From 9949488273180e9151079d6e36988250436ec06f Mon Sep 17 00:00:00 2001 From: Charlie DeTar Date: Thu, 31 Mar 2016 16:19:44 -0600 Subject: [PATCH] Sanitize iframe before setting to event --- lib/unhangout-sockets.js | 8 ++++++-- lib/utils.js | 16 ++++++++++++++-- package.json | 2 +- test/test.sanitize-iframe.js | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 test/test.sanitize-iframe.js diff --git a/lib/unhangout-sockets.js b/lib/unhangout-sockets.js index e3395635..12053df1 100644 --- a/lib/unhangout-sockets.js +++ b/lib/unhangout-sockets.js @@ -412,12 +412,16 @@ _.extend(UnhangoutSocketManager.prototype, events.EventEmitter.prototype, { if (!("iframeCode" in args)) { return mgr.writeErr(socket, "insert-iframe", "Missing Iframe Code"); } + var iframeCode = utils.sanitizeIframe(args.iframeCode); + if (iframeCode === null) { + return mgr.writeErr(socket, "insert-iframe", "Invalid iframe code"); + } var event = this.getEvent(args.roomId); if (event && socket.user.isAdminOf(event)) { - event.set("iframeEmbedCode", args.iframeCode); + event.set("iframeEmbedCode", iframeCode); event.save(); mgr.writeAck(socket, "embed-iframe"); - event.logAnalytics({action: "embed-iframe", user: socket.user, iframeCode: args.iframeCode}); + event.logAnalytics({action: "embed-iframe", user: socket.user, iframeCode: iframeCode}); } else { return mgr.writeErr(socket, "embed-iframe", "Missing event or not admin"); } diff --git a/lib/utils.js b/lib/utils.js index 42de44df..1db5462a 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -3,8 +3,8 @@ var _ = require("underscore"), toobusy = require("toobusy"), options = require("./options"), logger = require("./logging").getLogger(), - cheerio = require("cheerio"); - + cheerio = require("cheerio"), + Promise = require("bluebird"); // Configure maximum latency in the event loop. See // https://github.com/lloyd/node-toobusy for more. toobusy.maxLag(options.MAX_EVENT_LOOP_LAG); @@ -137,6 +137,18 @@ module.exports = { logPolicy ); }, + /** + * Ensure that the given iframeCode consists of a single iframe tag and no + * extra junk. + */ + sanitizeIframe: function(iframeCode) { + var $ = cheerio.load(iframeCode); + var iframe = $("iframe").empty()[0]; + if (!iframe) { + return null; + } + return cheerio.html(iframe); + }, getEventSanitizationWarnings: function(event) { // Run caja-sanitizer on the raw HTML fields, using the `logPolicy` // to construct a list of risky issues. Then, iterate over these to diff --git a/package.json b/package.json index 7b710ab8..73c6a415 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "backbone": "1.1.2", "bluebird": "1.1.1", "caja-sanitizer": "*", - "cheerio": "0.13.1", + "cheerio": "0.20.0", "connect-redis": "1.4.7", "connect-slashes": "1.3.0", "deep-copy": "^1.0.0", diff --git a/test/test.sanitize-iframe.js b/test/test.sanitize-iframe.js new file mode 100644 index 00000000..d8d171b0 --- /dev/null +++ b/test/test.sanitize-iframe.js @@ -0,0 +1,34 @@ +var expect = require("chai").expect; +var sanitizeIframe = require("../lib/utils").sanitizeIframe; + +/* + * Rather than doing a full test of caja-sanitizer, just make sure that the + * basics are wired up right and that our custom policy functions work. + */ +describe("SANITIZE IFRAME", function() { + it("Passes through clean iframe code", function() { + var code = ''; + expect(sanitizeIframe(code)).to.equal(code); + }); + + it("Removes trailing tags", function() { + var code = ""; + expect(sanitizeIframe(code)).to.equal(''); + }); + it("Removes leading tags", function() { + var code = "

This is nonsense

"; + expect(sanitizeIframe(code)).to.equal(''); + }); + it("Removes inner html", function() { + var code = ""; + expect(sanitizeIframe(code)).to.equal(''); + }); + it("Returns null for no iframes", function() { + var code = "

wat

"; + expect(sanitizeIframe(code)).to.be.null; + }); + it("Returns null for seriously busted markup", function() { + var code = "