Move IRC object and validation to network model

This commit is contained in:
Pavel Djundik 2018-03-15 10:37:05 +02:00
parent b08b23d59e
commit 682d3070e9
3 changed files with 156 additions and 97 deletions

View File

@ -2,12 +2,10 @@
const _ = require("lodash");
const colors = require("chalk");
const pkg = require("../package.json");
const Chan = require("./models/chan");
const crypto = require("crypto");
const Msg = require("./models/msg");
const Network = require("./models/network");
const ircFramework = require("irc-framework");
const Helper = require("./helper");
const UAParser = require("ua-parser-js");
const MessageStorage = require("./plugins/sqlite");
@ -140,8 +138,6 @@ Client.prototype.find = function(channelId) {
Client.prototype.connect = function(args) {
const client = this;
const nick = args.nick || "thelounge";
let webirc = null;
let channels = [];
if (args.channels) {
@ -176,105 +172,33 @@ Client.prototype.connect = function(args) {
});
}
args.ip = args.ip || (client.config && client.config.ip) || client.ip;
args.hostname = args.hostname || (client.config && client.config.hostname) || client.hostname;
const network = new Network({
uuid: args.uuid,
name: args.name || (Helper.config.displayNetwork ? "" : Helper.config.defaults.name) || "",
host: args.host || "",
port: parseInt(args.port, 10) || (args.tls ? 6697 : 6667),
name: String(args.name || (Helper.config.displayNetwork ? "" : Helper.config.defaults.name) || ""),
host: String(args.host || ""),
port: parseInt(args.port, 10),
tls: !!args.tls,
rejectUnauthorized: !!args.rejectUnauthorized,
password: args.password,
username: args.username || nick.replace(/[^a-zA-Z0-9]/g, ""),
realname: args.realname || "The Lounge User",
commands: args.commands,
ip: args.ip,
hostname: args.hostname,
password: String(args.password || ""),
nick: String(args.nick || ""),
username: String(args.username || ""),
realname: String(args.realname || ""),
commands: args.commands || [],
ip: args.ip || (client.config && client.config.ip) || client.ip,
hostname: args.hostname || (client.config && client.config.hostname) || client.hostname,
channels: channels,
});
network.setNick(nick);
client.networks.push(network);
client.emit("network", {
networks: [network.getFilteredClone(this.lastActiveChannel, -1)],
});
if (Helper.config.lockNetwork) {
// This check is needed to prevent invalid user configurations
if (!Helper.config.public && args.host && args.host.length > 0 && args.host !== Helper.config.defaults.host) {
network.channels[0].pushMessage(client, new Msg({
type: Msg.Type.ERROR,
text: "Hostname you specified is not allowed.",
}), true);
if (!network.validate(client)) {
return;
}
network.host = Helper.config.defaults.host;
network.port = Helper.config.defaults.port;
network.tls = Helper.config.defaults.tls;
network.rejectUnauthorized = Helper.config.defaults.rejectUnauthorized;
}
if (network.host.length === 0) {
network.channels[0].pushMessage(client, new Msg({
type: Msg.Type.ERROR,
text: "You must specify a hostname to connect.",
}), true);
return;
}
if (Helper.config.webirc && network.host in Helper.config.webirc) {
if (!args.hostname) {
args.hostname = args.ip;
}
if (args.ip) {
if (Helper.config.webirc[network.host] instanceof Function) {
webirc = Helper.config.webirc[network.host](client, args);
} else {
webirc = {
password: Helper.config.webirc[network.host],
username: pkg.name,
address: args.ip,
hostname: args.hostname,
};
}
} else {
log.warn("Cannot find a valid WEBIRC configuration for " + nick
+ "!" + network.username + "@" + network.host);
}
}
network.irc = new ircFramework.Client({
version: false, // We handle it ourselves
host: network.host,
port: network.port,
nick: nick,
username: Helper.config.useHexIp ? Helper.ip2hex(args.ip) : network.username,
gecos: network.realname,
password: network.password,
tls: network.tls,
outgoing_addr: Helper.config.bind,
rejectUnauthorized: network.rejectUnauthorized,
enable_chghost: true,
enable_echomessage: true,
auto_reconnect: true,
auto_reconnect_wait: 10000 + Math.floor(Math.random() * 1000), // If multiple users are connected to the same network, randomize their reconnections a little
auto_reconnect_max_retries: 360, // At least one hour (plus timeouts) worth of reconnections
webirc: webirc,
});
network.irc.requestCap([
"znc.in/self-message", // Legacy echo-message for ZNC
]);
// Request only new messages from ZNC if we have sqlite logging enabled
// See http://wiki.znc.in/Playback
if (client.config.log && Helper.config.messageStorage.includes("sqlite")) {
network.irc.requestCap("znc.in/playback");
}
network.createIrcFramework(client);
events.forEach((plugin) => {
require(`./plugins/irc-events/${plugin}`).apply(client, [

View File

@ -2,7 +2,10 @@
const _ = require("lodash");
const uuidv4 = require("uuid/v4");
const IrcFramework = require("irc-framework");
const Chan = require("./chan");
const Msg = require("./msg");
const Helper = require("../helper");
module.exports = Network;
@ -59,6 +62,108 @@ function Network(attr) {
);
}
Network.prototype.validate = function(client) {
this.setNick(String(this.nick || "thelounge").replace(" ", "_"));
if (!this.username) {
this.username = this.nick.replace(/[^a-zA-Z0-9]/g, "");
}
if (!this.realname) {
this.realname = "The Lounge User";
}
if (!this.port) {
this.port = this.tls ? 6697 : 6667;
}
if (Helper.config.lockNetwork) {
// This check is needed to prevent invalid user configurations
if (!Helper.config.public && this.host && this.host.length > 0 && this.host !== Helper.config.defaults.host) {
this.channels[0].pushMessage(client, new Msg({
type: Msg.Type.ERROR,
text: "Hostname you specified is not allowed.",
}), true);
return false;
}
this.host = Helper.config.defaults.host;
this.port = Helper.config.defaults.port;
this.tls = Helper.config.defaults.tls;
this.rejectUnauthorized = Helper.config.defaults.rejectUnauthorized;
}
if (this.host.length === 0) {
this.channels[0].pushMessage(client, new Msg({
type: Msg.Type.ERROR,
text: "You must specify a hostname to connect.",
}), true);
return false;
}
return true;
};
Network.prototype.createIrcFramework = function(client) {
this.irc = new IrcFramework.Client({
version: false, // We handle it ourselves
host: this.host,
port: this.port,
nick: this.nick,
username: Helper.config.useHexIp ? Helper.ip2hex(this.ip) : this.username,
gecos: this.realname,
password: this.password,
tls: this.tls,
outgoing_addr: Helper.config.bind,
rejectUnauthorized: this.rejectUnauthorized,
enable_chghost: true,
enable_echomessage: true,
auto_reconnect: true,
auto_reconnect_wait: 10000 + Math.floor(Math.random() * 1000), // If multiple users are connected to the same network, randomize their reconnections a little
auto_reconnect_max_retries: 360, // At least one hour (plus timeouts) worth of reconnections
webirc: this.createWebIrc(client),
});
this.irc.requestCap([
"znc.in/self-message", // Legacy echo-message for ZNC
]);
// Request only new messages from ZNC if we have sqlite logging enabled
// See http://wiki.znc.in/Playback
if (client.config.log && Helper.config.messageStorage.includes("sqlite")) {
this.irc.requestCap("znc.in/playback");
}
};
Network.prototype.createWebIrc = function(client) {
if (!Helper.config.webirc || !(this.host in Helper.config.webirc)) {
return null;
}
if (!this.ip) {
log.warn(`Cannot find a valid WEBIRC configuration for ${this.nick}!${this.username}@${this.host}`);
return null;
}
if (!this.hostname) {
this.hostname = this.ip;
}
if (Helper.config.webirc[this.host] instanceof Function) {
return Helper.config.webirc[this.host](client, this);
}
return {
password: Helper.config.webirc[this.host],
username: "thelounge",
address: this.ip,
hostname: this.hostname,
};
};
Network.prototype.destroy = function() {
this.channels.forEach((channel) => channel.destroy());
};

View File

@ -307,11 +307,40 @@ function initializeClient(socket, client, token, lastMessage) {
data.ip = null;
data.hostname = null;
data.uuid = null;
data.commands = null;
client.connect(data);
}
});
socket.on("network:get", (data) => {
if (typeof data !== "string") {
return;
}
const network = _.find(client.networks, {uuid: data});
if (!network) {
return;
}
socket.emit("network:info", getClientConfiguration(network.export()));
});
socket.on("network:edit", (data) => {
if (typeof data !== "object") {
return;
}
const network = _.find(client.networks, {uuid: data.uuid});
if (!network) {
return;
}
network.edit(client, data);
});
if (!Helper.config.public && !Helper.config.ldap.enable) {
socket.on("change-password", (data) => {
if (typeof data === "object") {
@ -541,27 +570,22 @@ function initializeClient(socket, client, token, lastMessage) {
}
}
function getClientConfiguration() {
function getClientConfiguration(network) {
const config = _.pick(Helper.config, [
"public",
"lockNetwork",
"displayNetwork",
"useHexIp",
"themes",
"prefetch",
]);
config.ldapEnabled = Helper.config.ldap.enable;
config.version = pkg.version;
config.gitCommit = Helper.getGitCommit();
config.themes = themes.getAll();
config.defaultTheme = Helper.config.theme;
if (config.displayNetwork) {
config.defaults = _.clone(Helper.config.defaults);
config.defaults = _.clone(network || Helper.config.defaults);
} else {
// Only send defaults that are visible on the client
config.defaults = _.pick(Helper.config.defaults, [
config.defaults = _.pick(network || Helper.config.defaults, [
"nick",
"username",
"password",
@ -570,7 +594,13 @@ function getClientConfiguration() {
]);
}
if (!network) {
config.version = pkg.version;
config.gitCommit = Helper.getGitCommit();
config.themes = themes.getAll();
config.defaultTheme = Helper.config.theme;
config.defaults.nick = config.defaults.nick.replace(/%/g, () => Math.floor(Math.random() * 10));
}
return config;
}