|
| 1 | +// Copyright (c) Jupyter Development Team. |
| 2 | +// Distributed under the terms of the Modified BSD License. |
| 3 | + |
| 4 | +define([ |
| 5 | + 'jquery', |
| 6 | + 'components/google-caja/html-css-sanitizer-minified', |
| 7 | +], function($, sanitize) { |
| 8 | + "use strict"; |
| 9 | + |
| 10 | + var noop = function (x) { return x; }; |
| 11 | + |
| 12 | + var caja; |
| 13 | + if (window && window.html) { |
| 14 | + caja = window.html; |
| 15 | + caja.html4 = window.html4; |
| 16 | + caja.sanitizeStylesheet = window.sanitizeStylesheet; |
| 17 | + } |
| 18 | + |
| 19 | + var sanitizeAttribs = function (tagName, attribs, opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger) { |
| 20 | + /** |
| 21 | + * add trusting data-attributes to the default sanitizeAttribs from caja |
| 22 | + * this function is mostly copied from the caja source |
| 23 | + */ |
| 24 | + var ATTRIBS = caja.html4.ATTRIBS; |
| 25 | + for (var i = 0; i < attribs.length; i += 2) { |
| 26 | + var attribName = attribs[i]; |
| 27 | + if (attribName.substr(0,5) == 'data-') { |
| 28 | + var attribKey = '*::' + attribName; |
| 29 | + if (!ATTRIBS.hasOwnProperty(attribKey)) { |
| 30 | + ATTRIBS[attribKey] = 0; |
| 31 | + } |
| 32 | + } |
| 33 | + } |
| 34 | + // Caja doesn't allow data uri for img::src, see |
| 35 | + // https://github.com/google/caja/issues/1558 |
| 36 | + // This is not a security issue for browser post ie6 though, so we |
| 37 | + // disable the check |
| 38 | + // https://www.owasp.org/index.php/Script_in_IMG_tags |
| 39 | + ATTRIBS['img::src'] = 0; |
| 40 | + return caja.sanitizeAttribs(tagName, attribs, opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger); |
| 41 | + }; |
| 42 | + |
| 43 | + var sanitize_css = function (css, tagPolicy) { |
| 44 | + /** |
| 45 | + * sanitize CSS |
| 46 | + * like sanitize_html, but for CSS |
| 47 | + * called by sanitize_stylesheets |
| 48 | + */ |
| 49 | + return caja.sanitizeStylesheet( |
| 50 | + window.location.pathname, |
| 51 | + css, |
| 52 | + { |
| 53 | + containerClass: null, |
| 54 | + idSuffix: '', |
| 55 | + tagPolicy: tagPolicy, |
| 56 | + virtualizeAttrName: noop |
| 57 | + }, |
| 58 | + noop |
| 59 | + ); |
| 60 | + }; |
| 61 | + |
| 62 | + var sanitize_stylesheets = function (html, tagPolicy) { |
| 63 | + /** |
| 64 | + * sanitize just the css in style tags in a block of html |
| 65 | + * called by sanitize_html, if allow_css is true |
| 66 | + */ |
| 67 | + var h = $("<div/>").append(html); |
| 68 | + var style_tags = h.find("style"); |
| 69 | + if (!style_tags.length) { |
| 70 | + // no style tags to sanitize |
| 71 | + return html; |
| 72 | + } |
| 73 | + style_tags.each(function(i, style) { |
| 74 | + style.innerHTML = sanitize_css(style.innerHTML, tagPolicy); |
| 75 | + }); |
| 76 | + return h.html(); |
| 77 | + }; |
| 78 | + |
| 79 | + var sanitize_html = function (html, allow_css) { |
| 80 | + /** |
| 81 | + * sanitize HTML |
| 82 | + * if allow_css is true (default: false), CSS is sanitized as well. |
| 83 | + * otherwise, CSS elements and attributes are simply removed. |
| 84 | + */ |
| 85 | + var html4 = caja.html4; |
| 86 | + |
| 87 | + if (allow_css) { |
| 88 | + // allow sanitization of style tags, |
| 89 | + // not just scrubbing |
| 90 | + html4.ELEMENTS.style &= ~html4.eflags.UNSAFE; |
| 91 | + html4.ATTRIBS.style = html4.atype.STYLE; |
| 92 | + } else { |
| 93 | + // scrub all CSS |
| 94 | + html4.ELEMENTS.style |= html4.eflags.UNSAFE; |
| 95 | + html4.ATTRIBS.style = html4.atype.SCRIPT; |
| 96 | + } |
| 97 | + |
| 98 | + var record_messages = function (msg, opts) { |
| 99 | + console.log("HTML Sanitizer", msg, opts); |
| 100 | + }; |
| 101 | + |
| 102 | + var policy = function (tagName, attribs) { |
| 103 | + if (!(html4.ELEMENTS[tagName] & html4.eflags.UNSAFE)) { |
| 104 | + return { |
| 105 | + 'attribs': sanitizeAttribs(tagName, attribs, |
| 106 | + noop, noop, record_messages) |
| 107 | + }; |
| 108 | + } else { |
| 109 | + record_messages(tagName + " removed", { |
| 110 | + change: "removed", |
| 111 | + tagName: tagName |
| 112 | + }); |
| 113 | + } |
| 114 | + }; |
| 115 | + |
| 116 | + var sanitized = caja.sanitizeWithPolicy(html, policy); |
| 117 | + |
| 118 | + if (allow_css) { |
| 119 | + // sanitize style tags as stylesheets |
| 120 | + sanitized = sanitize_stylesheets(sanitized, policy); |
| 121 | + } |
| 122 | + |
| 123 | + return sanitized; |
| 124 | + }; |
| 125 | + |
| 126 | + var sanitize_html_and_parse = function (html, allow_css) { |
| 127 | + /** |
| 128 | + * Sanitize HTML and parse it safely using jQuery. |
| 129 | + * |
| 130 | + * This disable's jQuery's html 'prefilter', which can make invalid |
| 131 | + * HTML valid after the sanitizer has checked it. |
| 132 | + * |
| 133 | + * Returns an array of DOM nodes. |
| 134 | + */ |
| 135 | + var sanitized_html = sanitize_html(html, allow_css); |
| 136 | + var prev_htmlPrefilter = $.htmlPrefilter; |
| 137 | + $.htmlPrefilter = function(html) {return html;}; // Don't modify HTML |
| 138 | + try { |
| 139 | + return $.parseHTML(sanitized_html); |
| 140 | + } finally { |
| 141 | + $.htmlPrefilter = prev_htmlPrefilter; // Set it back again |
| 142 | + } |
| 143 | + }; |
| 144 | + |
| 145 | + var security = { |
| 146 | + caja: caja, |
| 147 | + sanitize_html_and_parse: sanitize_html_and_parse, |
| 148 | + sanitize_html: sanitize_html |
| 149 | + }; |
| 150 | + |
| 151 | + return security; |
| 152 | +}); |
0 commit comments