diff --git a/defaults/config.js b/defaults/config.js index 8f346923..264d1f5d 100644 --- a/defaults/config.js +++ b/defaults/config.js @@ -110,6 +110,18 @@ module.exports = { // This value is set to `false` by default. prefetch: false, + // ### `disableMediaPreview` + // + // When set to `true`, The Lounge will not preview media (images, video and + // audio) hosted on third-party sites. This ensures the client does not + // make any requests to external sites. If `prefetchStorage` is enabled, + // images proxied via the The Lounge will be previewed. + // + // This has no effect if `prefetch` is set to `false`. + // + // This value is set to `false` by default. + disableMediaPreview: false, + // ### `prefetchStorage` // When set to `true`, The Lounge will store and proxy prefetched images and diff --git a/src/plugins/irc-events/link.js b/src/plugins/irc-events/link.js index e7f4822e..f9cec533 100644 --- a/src/plugins/irc-events/link.js +++ b/src/plugins/irc-events/link.js @@ -84,11 +84,6 @@ function parseHtml(preview, res, client) { $('meta[property="og:description"]').attr("content") || $('meta[name="description"]').attr("content") || ""; - let thumb = - $('meta[property="og:image"]').attr("content") || - $('meta[name="twitter:image:src"]').attr("content") || - $('link[rel="image_src"]').attr("href") || - ""; if (preview.head.length) { preview.head = preview.head.substr(0, 100); @@ -98,6 +93,17 @@ function parseHtml(preview, res, client) { preview.body = preview.body.substr(0, 300); } + if (!Helper.config.prefetchStorage && Helper.config.disableMediaPreview) { + resolve(res); + return; + } + + let thumb = + $('meta[property="og:image"]').attr("content") || + $('meta[name="twitter:image:src"]').attr("content") || + $('link[rel="image_src"]').attr("href") || + ""; + // Make sure thumbnail is a valid and absolute url if (thumb.length) { thumb = normalizeURL(thumb, preview.link) || ""; @@ -127,6 +133,10 @@ function parseHtml(preview, res, client) { function parseHtmlMedia($, preview, client) { return new Promise((resolve, reject) => { + if (Helper.config.disableMediaPreview) { + reject(); + } + let foundMedia = false; ["video", "audio"].forEach((type) => { @@ -203,6 +213,10 @@ function parse(msg, chan, preview, res, client) { case "image/jpg": case "image/jpeg": case "image/webp": + if (!Helper.config.prefetchStorage && Helper.config.disableMediaPreview) { + return removePreview(msg, preview); + } + if (res.size > Helper.config.prefetchMaxImageSize * 1024) { preview.type = "error"; preview.error = "image-too-big"; @@ -228,6 +242,10 @@ function parse(msg, chan, preview, res, client) { break; } + if (Helper.config.disableMediaPreview) { + return removePreview(msg, preview); + } + preview.type = "audio"; preview.media = preview.link; preview.mediaType = res.type; @@ -241,6 +259,10 @@ function parse(msg, chan, preview, res, client) { break; } + if (Helper.config.disableMediaPreview) { + return removePreview(msg, preview); + } + preview.type = "video"; preview.media = preview.link; preview.mediaType = res.type; diff --git a/test/plugins/link.js b/test/plugins/link.js index 01dbe042..5b06ca94 100644 --- a/test/plugins/link.js +++ b/test/plugins/link.js @@ -222,6 +222,70 @@ Vivamus bibendum vulputate tincidunt. Sed vitae ligula felis.`; }); }); + describe("test disableMediaPreview", function () { + beforeEach(function (done) { + Helper.config.disableMediaPreview = true; + done(); + }); + afterEach(function (done) { + Helper.config.disableMediaPreview = false; + done(); + }); + it("should ignore og:image if disableMediaPreview", function (done) { + const port = this.port; + + app.get("/nonexistent-test-image.png", function () { + throw "Should not fetch image"; + }); + + app.get("/thumb", function (req, res) { + res.send( + "Google" + ); + }); + const message = this.irc.createMessage({ + text: "http://localhost:" + port + "/thumb", + }); + + link(this.irc, this.network.channels[0], message); + + this.irc.once("msg:preview", function (data) { + expect(data.preview.head).to.equal("Google"); + expect(data.preview.type).to.equal("link"); + expect(data.preview.thumb).to.equal(""); + done(); + }); + }); + it("should ignore og:video if disableMediaPreview", function (done) { + const port = this.port; + + app.get("/nonexistent-video.mpr", function () { + throw "Should not fetch video"; + }); + + app.get("/thumb", function (req, res) { + res.send( + "Google" + ); + }); + const message = this.irc.createMessage({ + text: "http://localhost:" + port + "/thumb", + }); + + link(this.irc, this.network.channels[0], message); + + this.irc.once("msg:preview", function (data) { + expect(data.preview.head).to.equal("Google"); + expect(data.preview.type).to.equal("link"); + done(); + }); + }); + }); + it("should find image_src", function (done) { const port = this.port; const message = this.irc.createMessage({