From 54a4085b68a2285e13c2a66e7352128cfa313e3c Mon Sep 17 00:00:00 2001 From: Pavel Djundik Date: Tue, 16 Jul 2019 12:51:22 +0300 Subject: [PATCH] Store ip and language in a separate object in user file --- defaults/config.js | 20 ++++++++-------- src/client.js | 28 ++++------------------ src/clientManager.js | 1 + src/models/network.js | 34 +++++++++------------------ src/plugins/irc-events/connection.js | 2 +- src/plugins/irc-events/link.js | 6 ++--- src/server.js | 35 +++++++++++++++++++++------- test/models/network.js | 8 ++----- test/plugins/link.js | 8 +++---- test/util.js | 4 +++- 10 files changed, 66 insertions(+), 80 deletions(-) diff --git a/defaults/config.js b/defaults/config.js index 059ca16a..8498f844 100644 --- a/defaults/config.js +++ b/defaults/config.js @@ -298,23 +298,23 @@ module.exports = { // // ```json // webirc: { - // "irc.example.net": "password1", - // "irc.example.org": "passw0rd", + // "irc.example.net": "thisiswebircpassword1", + // "irc.example.org": "thisiswebircpassword2", // }, // ``` // // - **Advanced**: an object where keys are IRC hosts and values are functions - // that take three arguments (`client`, `args`, `trusted`) and return an - // object to be directly passed to `irc-framework`. For example: + // that take two arguments (`webircObj`, `network`) and return an + // object to be directly passed to `irc-framework`. `webircObj` contains the + // generated object which you can modify. For example: // // ```js // webirc: { - // "irc.example.net": (client, args, trusted) => ({ - // username: "thelounge", - // password: "password1", - // address: args.ip, - // hostname: `webirc/${args.hostname}` - // }), + // "irc.example.com": (webircObj, network) => { + // webircObj.password = "thisiswebircpassword"; + // webircObj.hostname = `webirc/${webircObj.hostname}`; + // return webircObj; + // }, // }, // ``` // diff --git a/src/client.js b/src/client.js index a0fc70e0..94c5da68 100644 --- a/src/client.js +++ b/src/client.js @@ -92,6 +92,10 @@ function Client(manager, name, config = {}) { client.config.clientSettings = {}; } + if (typeof client.config.browser !== "object") { + client.config.browser = {}; + } + client.compileCustomHighlights(); _.forOwn(client.config.sessions, (session) => { @@ -195,8 +199,6 @@ Client.prototype.connect = function(args) { 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, ignoreList: args.ignoreList ? args.ignoreList : [], }); @@ -547,7 +549,6 @@ Client.prototype.quit = function(signOut) { Client.prototype.clientAttach = function(socketId, token) { const client = this; - let save = false; if (client.awayMessage && _.size(client.attachedClients) === 0) { client.networks.forEach(function(network) { @@ -561,27 +562,6 @@ Client.prototype.clientAttach = function(socketId, token) { const openChannel = client.lastActiveChannel; client.attachedClients[socketId] = {token, openChannel}; - - // Update old networks to store ip and hostmask - client.networks.forEach((network) => { - if (!network.ip) { - save = true; - network.ip = (client.config && client.config.ip) || client.ip; - } - - if (!network.hostname) { - const hostmask = (client.config && client.config.hostname) || client.hostname; - - if (hostmask) { - save = true; - network.hostmask = hostmask; - } - } - }); - - if (save) { - client.save(); - } }; Client.prototype.clientDetach = function(socketId) { diff --git a/src/clientManager.js b/src/clientManager.js index 6077e315..4b2b3d98 100644 --- a/src/clientManager.js +++ b/src/clientManager.js @@ -118,6 +118,7 @@ ClientManager.prototype.addUser = function(name, password, enableLog) { networks: [], sessions: {}, clientSettings: {}, + browser: {}, }; try { diff --git a/src/models/network.js b/src/models/network.js index 11dee094..612f4aaf 100644 --- a/src/models/network.js +++ b/src/models/network.js @@ -1,7 +1,6 @@ "use strict"; const _ = require("lodash"); -const log = require("../log"); const uuidv4 = require("uuid/v4"); const IrcFramework = require("irc-framework"); const Chan = require("./chan"); @@ -36,8 +35,6 @@ function Network(attr) { username: "", realname: "", channels: [], - ip: null, - hostname: null, irc: null, serverOptions: { CHANTYPES: ["#", "&"], @@ -125,7 +122,7 @@ Network.prototype.createIrcFramework = function(client) { host: this.host, port: this.port, nick: this.nick, - username: Helper.config.useHexIp ? Helper.ip2hex(this.ip) : this.username, + username: Helper.config.useHexIp ? Helper.ip2hex(client.config.browser.ip) : this.username, gecos: this.realname, password: this.password, tls: this.tls, @@ -156,26 +153,19 @@ Network.prototype.createWebIrc = function(client) { 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 (typeof Helper.config.webirc[this.host] === "function") { - return Helper.config.webirc[this.host](client, this); - } - - return { + const webircObject = { password: Helper.config.webirc[this.host], username: "thelounge", - address: this.ip, - hostname: this.hostname, + address: client.config.browser.ip, + hostname: client.config.browser.hostname, }; + + if (typeof Helper.config.webirc[this.host] === "function") { + webircObject.password = null; + return Helper.config.webirc[this.host](webircObject, this); + } + + return webircObject; }; Network.prototype.edit = function(client, args) { @@ -348,8 +338,6 @@ Network.prototype.export = function() { "username", "realname", "commands", - "ip", - "hostname", "ignoreList", ]); diff --git a/src/plugins/irc-events/connection.js b/src/plugins/irc-events/connection.js index a05ce3dc..bc2f924a 100644 --- a/src/plugins/irc-events/connection.js +++ b/src/plugins/irc-events/connection.js @@ -79,7 +79,7 @@ module.exports = function(irc, network) { let ident = client.name || network.username; if (Helper.config.useHexIp) { - ident = Helper.ip2hex(network.ip); + ident = Helper.ip2hex(client.config.browser.ip); } identSocketId = client.manager.identHandler.addSocket(socket, ident); diff --git a/src/plugins/irc-events/link.js b/src/plugins/irc-events/link.js index 15a230a0..3614b336 100644 --- a/src/plugins/irc-events/link.js +++ b/src/plugins/irc-events/link.js @@ -63,7 +63,7 @@ module.exports = function(client, chan, msg) { fetch(url, { accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - language: client.language, + language: client.config.browser.language, }).then((res) => { parse(msg, chan, preview, res, client); }).catch((err) => { @@ -106,7 +106,7 @@ function parseHtml(preview, res, client) { // Verify that thumbnail pic exists and is under allowed size if (preview.thumb.length) { - fetch(preview.thumb, {language: client.language}).then((resThumb) => { + fetch(preview.thumb, {language: client.config.browser.language}).then((resThumb) => { if (resThumb === null || !(imageTypeRegex.test(resThumb.type)) || resThumb.size > (Helper.config.prefetchMaxImageSize * 1024)) { @@ -155,7 +155,7 @@ function parseHtmlMedia($, preview, client) { accept: type === "video" ? "video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5" : "audio/webm, audio/ogg, audio/wav, audio/*;q=0.9, application/ogg;q=0.7, video/*;q=0.6; */*;q=0.5", - language: client.language, + language: client.config.browser.language, }).then((resMedia) => { if (resMedia === null || !mediaTypeRegex.test(resMedia.type)) { return reject(); diff --git a/src/server.js b/src/server.js index 9b62a7ff..574a501c 100644 --- a/src/server.js +++ b/src/server.js @@ -235,7 +235,7 @@ function getClientIp(socket) { let ip = socket.handshake.address || "127.0.0.1"; if (Helper.config.reverseProxy) { - const forwarded = (socket.request.headers["x-forwarded-for"] || "").split(/\s*,\s*/).filter(Boolean); + const forwarded = (socket.handshake.headers["x-forwarded-for"] || "").split(/\s*,\s*/).filter(Boolean); if (forwarded.length && net.isIP(forwarded[0])) { ip = forwarded[0]; @@ -245,6 +245,16 @@ function getClientIp(socket) { return ip.replace(/^::ffff:/, ""); } +function getClientSecure(socket) { + let secure = socket.handshake.secure; + + if (Helper.config.reverseProxy && socket.handshake.headers["x-forwarded-proto"] === "https") { + secure = true; + } + + return secure; +} + function allRequests(req, res, next) { res.setHeader("X-Content-Type-Options", "nosniff"); return next(); @@ -329,8 +339,6 @@ function initializeClient(socket, client, token, lastMessage) { socket.on("network:new", (data) => { if (typeof data === "object") { // prevent people from overriding webirc settings - data.ip = null; - data.hostname = null; data.uuid = null; data.commands = null; data.ignoreList = null; @@ -657,21 +665,32 @@ function performAuthentication(data) { let client; let token = null; - const finalInit = () => initializeClient(socket, client, token, data.lastMessage || -1); + const finalInit = () => { + initializeClient(socket, client, token, data.lastMessage || -1); + + if (!Helper.config.public) { + client.manager.updateUser(client.name, { + browser: client.config.browser, + }); + } + }; const initClient = () => { socket.emit("configuration", getClientConfiguration()); - client.ip = getClientIp(socket); - client.language = getClientLanguage(socket); + client.config.browser = { + ip: getClientIp(socket), + isSecure: getClientSecure(socket), + language: getClientLanguage(socket), + }; // If webirc is enabled perform reverse dns lookup if (Helper.config.webirc === null) { return finalInit(); } - reverseDnsLookup(client.ip, (hostname) => { - client.hostname = hostname; + reverseDnsLookup(client.config.browser.ip, (hostname) => { + client.config.browser.hostname = hostname; finalInit(); }); diff --git a/test/models/network.js b/test/models/network.js index 14056b64..46725760 100644 --- a/test/models/network.js +++ b/test/models/network.js @@ -39,8 +39,6 @@ describe("Network", function() { realname: "", commands: [], nick: "chillin`", - ip: null, - hostname: null, channels: [ {name: "#thelounge", key: ""}, {name: "&foobar", key: ""}, @@ -127,8 +125,8 @@ describe("Network", function() { expect(saveCalled).to.be.true; expect(network.guid).to.not.equal("newGuid"); - expect(network.ip).to.be.null; - expect(network.hostname).to.be.null; + expect(network.ip).to.be.undefined; + expect(network.hostname).to.be.undefined; expect(network.name).to.equal("Lounge Test Network"); expect(network.channels[0].name).to.equal("Lounge Test Network"); @@ -226,8 +224,6 @@ describe("Network", function() { "channels", "commands", "host", - "hostname", - "ip", "name", "port", "realname", diff --git a/test/plugins/link.js b/test/plugins/link.js index f8adf9e2..74821f4f 100644 --- a/test/plugins/link.js +++ b/test/plugins/link.js @@ -287,7 +287,7 @@ describe("Link plugin", function() { it("should use client's preferred language as Accept-Language header", function(done) { const language = "sv,en-GB;q=0.9,en;q=0.8"; - this.irc.language = language; + this.irc.config.browser.language = language; app.get("/language-check", function(req, res) { expect(req.headers["accept-language"]).to.equal(language); @@ -449,7 +449,7 @@ describe("Link plugin", function() { let requests = 0; let responses = 0; - this.irc.language = "very nice language"; + this.irc.config.browser.language = "very nice language"; link(this.irc, this.network.channels[0], message); link(this.irc, this.network.channels[0], message); @@ -489,11 +489,11 @@ describe("Link plugin", function() { const requests = []; let responses = 0; - this.irc.language = "first language"; + this.irc.config.browser.language = "first language"; link(this.irc, this.network.channels[0], message); setTimeout(() => { - this.irc.language = "second language"; + this.irc.config.browser.language = "second language"; link(this.irc, this.network.channels[0], message); }, 100); diff --git a/test/util.js b/test/util.js index 1f433d4b..6222491b 100644 --- a/test/util.js +++ b/test/util.js @@ -8,7 +8,9 @@ const Network = require("../src/models/network"); const Chan = require("../src/models/chan"); function MockClient() { - this.user = {nick: "test-user"}; + this.config = { + browser: {}, + }; } util.inherits(MockClient, EventEmitter);