diff --git a/app/assets/javascripts/defer/html-sanitizer-bundle.js b/app/assets/javascripts/defer/html-sanitizer-bundle.js index ccdebf3a92b..363a5ce402a 100644 --- a/app/assets/javascripts/defer/html-sanitizer-bundle.js +++ b/app/assets/javascripts/defer/html-sanitizer-bundle.js @@ -11,6 +11,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// +// Sam: made some modifications to pass jshint and protect against global namespace pollution + + +window.sanitizeHtml = (function() { /** * @fileoverview @@ -83,7 +88,7 @@ function encodeIfExists(unescapedPart) { return encodeURIComponent(unescapedPart); } return null; -}; +} /** * if unescapedPart is non null, then escapes any characters in it that aren't * valid characters in a url and also escapes any special characters that @@ -154,7 +159,7 @@ var EXTRA_PARENT_PATHS_RE = /^(?:\.\.\/)*(?:\.\.$)?/; * } */ function collapse_dots(path) { - if (path === null) { return null; } + if (path == null) { return null; } var p = normPath(path); // Only /../ left to flatten var r = PARENT_DIRECTORY_HANDLER_RE; @@ -738,14 +743,9 @@ URI.utils = { return URI; })(); -// Exports for closure compiler. -if (typeof window !== 'undefined') { - window['URI'] = URI; -} -; // Copyright Google Inc. // Licensed under the Apache Licence Version 2.0 -// Autogenerated at Fri Oct 11 16:16:32 EDT 2013 +// Autogenerated at Wed Feb 20 13:32:22 EST 2013 // @overrides window // @provides html4 var html4 = {}; @@ -765,7 +765,6 @@ html4.atype = { 'FRAME_TARGET': 10, 'MEDIA_QUERY': 13 }; -html4[ 'atype' ] = html4.atype; html4.ATTRIBS = { '*::class': 9, '*::dir': 0, @@ -781,7 +780,6 @@ html4.ATTRIBS = { '*::onchange': 2, '*::onclick': 2, '*::ondblclick': 2, - '*::onerror': 2, '*::onfocus': 2, '*::onkeydown': 2, '*::onkeypress': 2, @@ -827,7 +825,6 @@ html4.ATTRIBS = { 'audio::mediagroup': 5, 'audio::muted': 0, 'audio::preload': 0, - 'audio::src': 1, 'bdo::dir': 0, 'blockquote::cite': 1, 'br::clear': 0, @@ -1069,10 +1066,8 @@ html4.ATTRIBS = { 'video::muted': 0, 'video::poster': 1, 'video::preload': 0, - 'video::src': 1, 'video::width': 0 }; -html4[ 'ATTRIBS' ] = html4.ATTRIBS; html4.eflags = { 'OPTIONAL_ENDTAG': 1, 'EMPTY': 2, @@ -1084,7 +1079,6 @@ html4.eflags = { 'STYLE': 128, 'VIRTUALIZED': 256 }; -html4[ 'eflags' ] = html4.eflags; html4.ELEMENTS = { 'a': 0, 'abbr': 0, @@ -1208,7 +1202,6 @@ html4.ELEMENTS = { 'video': 0, 'wbr': 2 }; -html4[ 'ELEMENTS' ] = html4.ELEMENTS; html4.ELEMENT_DOM_INTERFACES = { 'a': 'HTMLAnchorElement', 'abbr': 'HTMLElement', @@ -1332,17 +1325,14 @@ html4.ELEMENT_DOM_INTERFACES = { 'video': 'HTMLVideoElement', 'wbr': 'HTMLElement' }; -html4[ 'ELEMENT_DOM_INTERFACES' ] = html4.ELEMENT_DOM_INTERFACES; html4.ueffects = { 'NOT_LOADED': 0, 'SAME_DOCUMENT': 1, 'NEW_DOCUMENT': 2 }; -html4[ 'ueffects' ] = html4.ueffects; html4.URIEFFECTS = { 'a::href': 2, 'area::href': 2, - 'audio::src': 1, 'blockquote::cite': 0, 'command::icon': 1, 'del::cite': 0, @@ -1351,20 +1341,16 @@ html4.URIEFFECTS = { 'input::src': 1, 'ins::cite': 0, 'q::cite': 0, - 'video::poster': 1, - 'video::src': 1 + 'video::poster': 1 }; -html4[ 'URIEFFECTS' ] = html4.URIEFFECTS; html4.ltypes = { 'UNSANDBOXED': 2, 'SANDBOXED': 1, 'DATA': 0 }; -html4[ 'ltypes' ] = html4.ltypes; html4.LOADERTYPES = { 'a::href': 2, 'area::href': 2, - 'audio::src': 2, 'blockquote::cite': 2, 'command::icon': 1, 'del::cite': 2, @@ -1373,15 +1359,8 @@ html4.LOADERTYPES = { 'input::src': 1, 'ins::cite': 2, 'q::cite': 2, - 'video::poster': 1, - 'video::src': 2 + 'video::poster': 1 }; -html4[ 'LOADERTYPES' ] = html4.LOADERTYPES; -// export for Closure Compiler -if (typeof window !== 'undefined') { - window['html4'] = html4; -} -; // Copyright (C) 2006 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -1418,7 +1397,7 @@ if (typeof window !== 'undefined') { */ // The Turkish i seems to be a non-issue, but abort in case it is. -if ('I'.toLowerCase() !== 'i') { throw 'I/i problem'; } +// if ('I'.toLowerCase() !== 'i') { throw 'I/i problem'; } # Sam ... screwing up in turkish browsers seems a silly idea /** * \@namespace @@ -1428,9 +1407,9 @@ var html = (function(html4) { // For closure compiler var parseCssDeclarations, sanitizeCssProperty, cssSchema; if ('undefined' !== typeof window) { - parseCssDeclarations = window['parseCssDeclarations']; - sanitizeCssProperty = window['sanitizeCssProperty']; - cssSchema = window['cssSchema']; + parseCssDeclarations = window.parseCssDeclarations; + sanitizeCssProperty = window.sanitizeCssProperty; + cssSchema = window.cssSchema; } // The keys of this object must be 'quoted' or JSCompiler will mangle them! @@ -1460,8 +1439,7 @@ var html = (function(html4) { // TODO(kpreid): This retrieval is a kludge and leads to silent loss of // functionality if the document isn't available. var entityLookupElement = - ('undefined' !== typeof window && window['document']) - ? window['document'].createElement('textarea') : null; + ('undefined' !== typeof window && window.document) ? window.document.createElement('textarea') : null; /** * Decodes an HTML entity. * @@ -1630,7 +1608,7 @@ var html = (function(html4) { var splitWillCapture = ('a,b'.split(/(,)/).length === 3); // bitmask for tags with special parsing, like ").should match_html "
" + PrettyText.cook("").should match_html "alert(42)" end it 'should allow for @mentions to have punctuation' do diff --git a/test/javascripts/components/bbcode_test.js b/test/javascripts/components/bbcode_test.js index 1fb59dca108..d0b4c118fb1 100644 --- a/test/javascripts/components/bbcode_test.js +++ b/test/javascripts/components/bbcode_test.js @@ -27,6 +27,13 @@ test('lists', function() { format("[ol][li]option one[/li][/ol]", "hello
hello
hello
hello
hello
", "it sanitizes while cooking"); cooked("disney reddit", @@ -307,15 +305,3 @@ test("URLs in BBCode tags", function() { "named links are properly parsed"); }); - -test("urlAllowed", function() { - var allowed = function(url, msg) { - equal(Discourse.Markdown.urlAllowed(url), url, msg); - }; - - allowed("/foo/bar.html", "allows relative urls"); - allowed("http://eviltrout.com/evil/trout", "allows full urls"); - allowed("https://eviltrout.com/evil/trout", "allows https urls"); - allowed("//eviltrout.com/evil/trout", "allows protocol relative urls"); - -}); diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js index 37cf2bb550b..94a3597f7af 100644 --- a/test/javascripts/test_helper.js +++ b/test/javascripts/test_helper.js @@ -25,6 +25,7 @@ //= require LAB.js //= require Markdown.Converter.js //= require Markdown.Editor.js +//= require Markdown.Sanitizer.js //= require better_markdown.js //= require bootbox.js //= require bootstrap-alert.js diff --git a/vendor/assets/javascripts/Markdown.Sanitizer.js b/vendor/assets/javascripts/Markdown.Sanitizer.js new file mode 100644 index 00000000000..c3283e590f7 --- /dev/null +++ b/vendor/assets/javascripts/Markdown.Sanitizer.js @@ -0,0 +1,108 @@ +(function () { + var output, Converter; + if (typeof exports === "object" && typeof require === "function") { // we're in a CommonJS (e.g. Node.js) module + output = exports; + Converter = require("./Markdown.Converter").Converter; + } else { + output = window.Markdown; + Converter = output.Converter; + } + + output.getSanitizingConverter = function () { + var converter = new Converter(); + converter.hooks.chain("postConversion", sanitizeHtml); + converter.hooks.chain("postConversion", balanceTags); + return converter; + } + + function sanitizeHtml(html) { + return html.replace(/<[^>]*>?/gi, sanitizeTag); + } + + // (tags that can be opened/closed) | (tags that stand alone) + var basic_tag_whitelist = /^(<\/?(b|blockquote|code|del|dd|dl|dt|em|h1|h2|h3|i|kbd|li|ol|p|pre|s|sup|sub|strong|strike|ul)>|<(br|hr)\s?\/?>)$/i; + // | + var a_white = /^(]+")?\s?>|<\/a>)$/i; + + //