From acb6179b30b0808386a1d2e65029cc9538b476bf Mon Sep 17 00:00:00 2001 From: William Boman Date: Thu, 28 Dec 2017 14:34:49 +0100 Subject: [PATCH] relay client's preferred language in link preview requests Closes #1440. --- src/plugins/irc-events/link.js | 22 ++++++++++++++++------ src/server.js | 12 ++++++++++++ test/plugins/link.js | 17 +++++++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/plugins/irc-events/link.js b/src/plugins/irc-events/link.js index 037b769b..950172f2 100644 --- a/src/plugins/irc-events/link.js +++ b/src/plugins/irc-events/link.js @@ -38,7 +38,7 @@ module.exports = function(client, chan, msg) { })).slice(0, 5); // Only preview the first 5 URLs in message to avoid abuse msg.previews.forEach((preview) => { - fetch(preview.link, function(res, err) { + fetch(preview.link, {language: client.language}, function(res, err) { if (err) { preview.type = "error"; preview.error = "message"; @@ -85,7 +85,7 @@ function parse(msg, preview, res, client) { // Verify that thumbnail pic exists and is under allowed size if (preview.thumb.length) { - fetch(escapeHeader(preview.thumb), (resThumb) => { + fetch(escapeHeader(preview.thumb), {language: client.language}, (resThumb) => { if (resThumb === null || !(/^image\/.+/.test(resThumb.type)) || resThumb.size > (Helper.config.prefetchMaxImageSize * 1024)) { @@ -198,7 +198,19 @@ function emitPreview(client, msg, preview) { }); } -function fetch(uri, cb) { +function getRequestHeaders(language) { + const headers = { + "User-Agent": "Mozilla/5.0 (compatible; The Lounge IRC Client; +https://github.com/thelounge/lounge)", + }; + + if (language !== null) { + headers["Accept-Language"] = language; + } + + return headers; +} + +function fetch(uri, {language}, cb) { let req; try { @@ -206,9 +218,7 @@ function fetch(uri, cb) { url: uri, maxRedirects: 5, timeout: 5000, - headers: { - "User-Agent": "Mozilla/5.0 (compatible; The Lounge IRC Client; +https://github.com/thelounge/lounge)", - }, + headers: getRequestHeaders(language), }); } catch (e) { return cb(null, e); diff --git a/src/server.js b/src/server.js index 22163cab..26e1956b 100644 --- a/src/server.js +++ b/src/server.js @@ -204,6 +204,17 @@ module.exports = function() { return server; }; +function getClientLanguage(socket) { + const acceptLanguage = socket.handshake.headers["accept-language"]; + + if (typeof acceptLanguage === "string" && /^[\x00-\x7F]{1,50}$/.test(acceptLanguage)) { + // only allow ASCII strings between 1-50 characters in length + return acceptLanguage; + } + + return null; +} + function getClientIp(socket) { let ip = socket.handshake.address; @@ -549,6 +560,7 @@ function performAuthentication(data) { socket.emit("configuration", getClientConfiguration()); client.ip = getClientIp(socket); + client.language = getClientLanguage(socket); // If webirc is enabled perform reverse dns lookup if (Helper.config.webirc === null) { diff --git a/test/plugins/link.js b/test/plugins/link.js index 65c8127f..1721477c 100644 --- a/test/plugins/link.js +++ b/test/plugins/link.js @@ -266,4 +266,21 @@ 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; + + app.get("/language-check", function(req, res) { + expect(req.headers["accept-language"]).to.equal(language); + res.send(); + done(); + }); + + const message = this.irc.createMessage({ + text: "http://localhost:9002/language-check", + }); + + link(this.irc, this.network.channels[0], message); + }); });