Skip to content

Commit

Permalink
Upgraded and refactored Sanitizing. Much less crap should get through…
Browse files Browse the repository at this point in the history
… now!

Conflicts:
	app/assets/javascripts/discourse/components/syntax_highlighting.js
  • Loading branch information
eviltrout committed Oct 15, 2013
1 parent e0e79ca commit 5281b7f
Show file tree
Hide file tree
Showing 16 changed files with 175 additions and 174 deletions.
95 changes: 61 additions & 34 deletions app/assets/javascripts/defer/html-sanitizer-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@
// 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
Expand Down Expand Up @@ -88,7 +83,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
Expand Down Expand Up @@ -159,7 +154,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;
Expand Down Expand Up @@ -743,9 +738,14 @@ 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 Wed Feb 20 13:32:22 EST 2013
// Autogenerated at Fri Oct 11 16:16:32 EDT 2013
// @overrides window
// @provides html4
var html4 = {};
Expand All @@ -765,6 +765,7 @@ html4.atype = {
'FRAME_TARGET': 10,
'MEDIA_QUERY': 13
};
html4[ 'atype' ] = html4.atype;
html4.ATTRIBS = {
'*::class': 9,
'*::dir': 0,
Expand All @@ -780,6 +781,7 @@ html4.ATTRIBS = {
'*::onchange': 2,
'*::onclick': 2,
'*::ondblclick': 2,
'*::onerror': 2,
'*::onfocus': 2,
'*::onkeydown': 2,
'*::onkeypress': 2,
Expand Down Expand Up @@ -825,6 +827,7 @@ html4.ATTRIBS = {
'audio::mediagroup': 5,
'audio::muted': 0,
'audio::preload': 0,
'audio::src': 1,
'bdo::dir': 0,
'blockquote::cite': 1,
'br::clear': 0,
Expand Down Expand Up @@ -1066,8 +1069,10 @@ 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,
Expand All @@ -1079,6 +1084,7 @@ html4.eflags = {
'STYLE': 128,
'VIRTUALIZED': 256
};
html4[ 'eflags' ] = html4.eflags;
html4.ELEMENTS = {
'a': 0,
'abbr': 0,
Expand Down Expand Up @@ -1202,6 +1208,7 @@ html4.ELEMENTS = {
'video': 0,
'wbr': 2
};
html4[ 'ELEMENTS' ] = html4.ELEMENTS;
html4.ELEMENT_DOM_INTERFACES = {
'a': 'HTMLAnchorElement',
'abbr': 'HTMLElement',
Expand Down Expand Up @@ -1325,14 +1332,17 @@ 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,
Expand All @@ -1341,16 +1351,20 @@ html4.URIEFFECTS = {
'input::src': 1,
'ins::cite': 0,
'q::cite': 0,
'video::poster': 1
'video::poster': 1,
'video::src': 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,
Expand All @@ -1359,8 +1373,15 @@ html4.LOADERTYPES = {
'input::src': 1,
'ins::cite': 2,
'q::cite': 2,
'video::poster': 1
'video::poster': 1,
'video::src': 2
};
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");
Expand Down Expand Up @@ -1397,7 +1418,7 @@ html4.LOADERTYPES = {
*/

// The Turkish i seems to be a non-issue, but abort in case it is.
// if ('I'.toLowerCase() !== 'i') { throw 'I/i problem'; } # Sam ... screwing up in turkish browsers seems a silly idea
if ('I'.toLowerCase() !== 'i') { throw 'I/i problem'; }

/**
* \@namespace
Expand All @@ -1407,9 +1428,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!
Expand Down Expand Up @@ -1439,7 +1460,8 @@ 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.
*
Expand Down Expand Up @@ -1608,7 +1630,7 @@ var html = (function(html4) {
var splitWillCapture = ('a,b'.split(/(,)/).length === 3);

// bitmask for tags with special parsing, like <script> and <textarea>
var EFLAGS_TEXT = html4.eflags.CDATA | html4.eflags.RCDATA;
var EFLAGS_TEXT = html4.eflags['CDATA'] | html4.eflags['RCDATA'];

/**
* Given a SAX-like event handler, produce a function that feeds those
Expand Down Expand Up @@ -1714,7 +1736,7 @@ var html = (function(html4) {
}
break;
case '<\/':
if (m = /^([-\w:]+)[^\'\"]*/.exec(next)) {
if ((m = /^([-\w:]+)[^\'\"]*/.exec(next))) {
if (m[0].length === next.length && parts[pos + 1] === '>') {
// fast case, no attribute parsing needed
pos += 2;
Expand Down Expand Up @@ -1875,7 +1897,7 @@ var html = (function(html4) {
var parts = [];
var lastPos = 0;
var m;
while ((m = re.exec(str)) != null) {
while ((m = re.exec(str)) !== null) {
parts.push(str.substring(lastPos, m.index));
parts.push(m[0]);
lastPos = m.index + m[0].length;
Expand Down Expand Up @@ -2085,7 +2107,7 @@ var html = (function(html4) {
for (var i = 0, n = attribs.length; i < n; i += 2) {
var attribName = attribs[i],
value = attribs[i + 1];
if (value != null && value !== void 0) {
if (value !== null && value !== void 0) {
out.push(' ', attribName, '="', escapeAttrib(value), '"');
}
}
Expand Down Expand Up @@ -2241,7 +2263,7 @@ var html = (function(html4) {
html4.ATTRIBS.hasOwnProperty(attribKey))) {
atype = html4.ATTRIBS[attribKey];
}
if (atype != null) {
if (atype !== null) {
switch (atype) {
case html4.atype['NONE']: break;
case html4.atype['SCRIPT']:
Expand All @@ -2262,14 +2284,10 @@ var html = (function(html4) {
parseCssDeclarations(
value,
{
declaration: function (property, tokens) {
'declaration': function (property, tokens) {
var normProp = property.toLowerCase();
var schema = cssSchema[normProp];
if (!schema) {
return;
}
sanitizeCssProperty(
normProp, schema, tokens,
normProp, tokens,
opt_naiveUriRewriter
? function (url) {
return safeUri(
Expand All @@ -2281,7 +2299,10 @@ var html = (function(html4) {
}, opt_naiveUriRewriter);
}
: null);
sanitizedDeclarations.push(property + ': ' + tokens.join(' '));
if (tokens.length) {
sanitizedDeclarations.push(
normProp + ': ' + tokens.join(' '));
}
}
});
value = sanitizedDeclarations.length > 0 ?
Expand Down Expand Up @@ -2318,7 +2339,7 @@ var html = (function(html4) {
if (value && '#' === value.charAt(0)) {
value = value.substring(1); // remove the leading '#'
value = opt_nmTokenPolicy ? opt_nmTokenPolicy(value) : value;
if (value != null && value !== void 0) {
if (value !== null && value !== void 0) {
value = '#' + value; // restore the leading '#'
}
} else {
Expand All @@ -2336,9 +2357,11 @@ var html = (function(html4) {
break;
}
} else {
value = null;
if (opt_logger) {
log(opt_logger, tagName, attribName, oldValue, value);
if (!/^data\-/.test(attribName)) {
value = null;
if (opt_logger) {
log(opt_logger, tagName, attribName, oldValue, value);
}
}
}
attribs[i + 1] = value;
Expand Down Expand Up @@ -2418,7 +2441,11 @@ var html = (function(html4) {
return html;
})(html4);

var html_sanitize = html['sanitize'];

return function(s){return html.sanitize(s, function(uri){return uri;})};
})();

// Exports for Closure compiler. Note this file is also cajoled
// for domado and run in an environment without 'window'
if (typeof window !== 'undefined') {
window['html'] = html;
window['html_sanitize'] = html_sanitize;
}
57 changes: 55 additions & 2 deletions app/assets/javascripts/discourse/components/markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@
**/
Discourse.Markdown = {

validClasses: {},

/**
Whitelists classes for sanitization
@method whiteListClass
@param {String} val The value to whitelist. Can supply more than one argument
**/
whiteListClass: function() {
var args = Array.prototype.slice.call(arguments),
validClasses = Discourse.Markdown.validClasses;

args.forEach(function (a) {
validClasses[a] = true;
});
},

/**
Convert a raw string to a cooked markdown string.
Expand Down Expand Up @@ -85,6 +102,41 @@ Discourse.Markdown = {
return new Markdown.Editor(markdownConverter, undefined, editorOptions);
},

/**
Checks to see if a URL is allowed in the cooked content
@method urlAllowed
@param {String} url Url to check
@return {String} url to insert in the cooked content
**/
urlAllowed: function (url) {
if(/^https?:\/\//.test(url)) { return url; }
if(/^\/\/?[\w\.\-]+/.test(url)) { return url; }
},

/**
Checks to see if a name, class or id is allowed in the cooked content
@method nameIdClassAllowed
@param {String} val The name, class or id to check
@return {String} val the transformed name class or id
**/
nameIdClassAllowed: function(val) {
if (Discourse.Markdown.validClasses[val]) { return val; }
},

/**
Sanitize text using the sanitizer
@method sanitize
@param {String} text The text to sanitize
@return {String} text The sanitized text
**/
sanitize: function(text) {
if (!window.html_sanitize) return "";
return window.html_sanitize(text, Discourse.Markdown.urlAllowed, Discourse.Markdown.nameIdClassAllowed);
},

/**
Creates a Markdown.Converter that we we can use for formatting
Expand All @@ -101,8 +153,7 @@ Discourse.Markdown = {
if (!text) return "";

if (opts.sanitize) {
if (!window.sanitizeHtml) return "";
text = window.sanitizeHtml(text);
text = Discourse.Markdown.sanitize(text);
}

return text;
Expand All @@ -112,3 +163,5 @@ Discourse.Markdown = {

};
RSVP.EventTarget.mixin(Discourse.Markdown);

Discourse.Markdown.whiteListClass("attachment");
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ Discourse.SyntaxHighlighting = {
@param {jQuery.selector} $elem The element we want to apply our highlighting to
**/
apply: function($elem) {
return $('pre code[class]', $elem).each(function(i, e) {
$('pre code[class]', $elem).each(function(i, e) {
return $LAB.script("/javascripts/highlight-handlebars.pack.js").wait(function() {
return hljs.highlightBlock(e);
});
});
}
};


Loading

0 comments on commit 5281b7f

Please sign in to comment.