diff --git a/package.json b/package.json index 9bc52689..9b2e190f 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "irc-framework": "2.10.2", "ldapjs": "1.0.1", "lodash": "4.17.4", + "mime-types": "2.1.17", "moment": "2.20.1", "package-json": "4.0.1", "primer-tooltips": "1.5.1", diff --git a/src/plugins/irc-events/link.js b/src/plugins/irc-events/link.js index 45acaf84..7a8ed3a6 100644 --- a/src/plugins/irc-events/link.js +++ b/src/plugins/irc-events/link.js @@ -3,6 +3,7 @@ const cheerio = require("cheerio"); const request = require("request"); const url = require("url"); +const mime = require("mime-types"); const Helper = require("../../helper"); const cleanIrcMessage = require("../../../client/js/libs/handlebars/ircmessageparser/cleanIrcMessage"); const findLinks = require("../../../client/js/libs/handlebars/ircmessageparser/findLinks"); @@ -146,7 +147,22 @@ function handlePreview(client, msg, preview, res) { return emitPreview(client, msg, preview); } - storage.store(res.data, res.type.replace("image/", ""), (uri) => { + // Get the correct file extension for the provided content-type + // This is done to prevent user-input being stored in the file name (extension) + const extension = mime.extension(res.type); + + if (!extension) { + // For link previews, drop the thumbnail + // For other types, do not display preview at all + if (preview.type !== "link") { + return; + } + + preview.thumb = ""; + return emitPreview(client, msg, preview); + } + + storage.store(res.data, extension, (uri) => { preview.thumb = uri; emitPreview(client, msg, preview); diff --git a/test/plugins/storage.js b/test/plugins/storage.js index f8391f3f..05a1a304 100644 --- a/test/plugins/storage.js +++ b/test/plugins/storage.js @@ -15,11 +15,18 @@ describe("Image storage", function() { const correctImageHash = crypto.createHash("sha256").update(fs.readFileSync(testImagePath)).digest("hex"); const correctImageURL = `storage/${correctImageHash.substring(0, 2)}/${correctImageHash.substring(2, 4)}/${correctImageHash.substring(4)}.png`; + const testSvgPath = path.resolve(__dirname, "../../client/img/logo.svg"); + const correctSvgHash = crypto.createHash("sha256").update(fs.readFileSync(testSvgPath)).digest("hex"); + const correctSvgURL = `storage/${correctSvgHash.substring(0, 2)}/${correctSvgHash.substring(2, 4)}/${correctSvgHash.substring(4)}.svg`; + before(function(done) { this.app = util.createWebserver(); this.app.get("/real-test-image.png", function(req, res) { res.sendFile(testImagePath); }); + this.app.get("/logo.svg", function(req, res) { + res.sendFile(testSvgPath); + }); this.connection = this.app.listen(9003, done); }); @@ -67,4 +74,23 @@ describe("Image storage", function() { done(); }); }); + + it("should lookup correct extension type", function(done) { + const message = this.irc.createMessage({ + text: "http://localhost:9003/svg-preview", + }); + + this.app.get("/svg-preview", function(req, res) { + res.send("test title"); + }); + + link(this.irc, this.network.channels[0], message); + + this.irc.once("msg:preview", function(data) { + expect(data.preview.type).to.equal("link"); + expect(data.preview.link).to.equal("http://localhost:9003/svg-preview"); + expect(data.preview.thumb).to.equal(correctSvgURL); + done(); + }); + }); });