Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Use google's caja html sanitizer

  • Loading branch information...
commit c8be81c2309161952a8457a9e1e926af7f15f226 1 parent f07b265
@isaacs isaacs authored
View
26 node_modules/sanitizer/README.rdoc
@@ -0,0 +1,26 @@
+== Installation
+
+npm install sanitizer
+
+
+== Require
+
+var sanitizer = require('sanitizer');
+
+
+== Use
+
+sanitizer.escape('your dirty string'); // Escapes HTML special characters in attribute values as HTML entities
+
+var yourParser = sanitizer.makeSaxParser(yourHandler); // Given a SAX-like event handler, produce a function that feeds those events and a parameter to the event handler.
+
+sanitizer.normalizeRCData('your dirty string'); // Escape entities in RCDATA that can be escaped without changing the meaning.
+
+sanitizer.sanitize('your dirty string'); // Strips unsafe tags and attributes from html.
+
+exports.unescapeEntities('your string'); // The plain text of a chunk of HTML CDATA which possibly containing.
+
+
+== More information
+
+http://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/plugin/html-sanitizer.js
View
22 node_modules/sanitizer/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "sanitizer",
+ "description": "Caja's HTML Sanitizer as a Node.js module",
+ "version": "0.0.15",
+ "author": {
+ "name": "Ben Smawfield",
+ "email": "bensmawfield@googlemail.com"
+ },
+ "homepage": "http://github.com/theSmaw/Caja-HTML-Sanitizer",
+ "bugs": {
+ "mail": "bensmawfield@googlemail.com",
+ "url": "http://github.com/theSmaw/Caja-HTML-Sanitizer/issues"
+ },
+ "main": "sanitizer.js",
+ "repository": {
+ "type": "git",
+ "url": "http://github.com/theSmaw/Caja-HTML-Sanitizer.git"
+ },
+ "readme": "== Installation\n\nnpm install sanitizer\n\n\n== Require\n\nvar sanitizer = require('sanitizer');\n\n\n== Use\n\nsanitizer.escape('your dirty string'); // Escapes HTML special characters in attribute values as HTML entities\n\nvar yourParser = sanitizer.makeSaxParser(yourHandler); // Given a SAX-like event handler, produce a function that feeds those events and a parameter to the event handler.\n\nsanitizer.normalizeRCData('your dirty string'); // Escape entities in RCDATA that can be escaped without changing the meaning.\n\nsanitizer.sanitize('your dirty string'); // Strips unsafe tags and attributes from html.\n\nexports.unescapeEntities('your string'); // The plain text of a chunk of HTML CDATA which possibly containing.\n\n\n== More information\n\nhttp://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/plugin/html-sanitizer.js",
+ "_id": "sanitizer@0.0.15",
+ "_from": "sanitizer"
+}
View
897 node_modules/sanitizer/sanitizer.js
@@ -0,0 +1,897 @@
+// Copyright (C) 2006 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// 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.
+
+/**
+ * @fileoverview
+ * An HTML sanitizer that can satisfy a variety of security policies.
+ *
+ * <p>
+ * The HTML sanitizer is built around a SAX parser and HTML element and
+ * attributes schemas.
+ *
+ * @author mikesamuel@gmail.com
+ * @requires html4
+ * @provides html, html_sanitize
+ */
+
+/**
+ * @namespace
+ */
+var html = (function () {
+ var lcase;
+ // The below may not be true on browsers in the Turkish locale.
+ if ('script' === 'SCRIPT'.toLowerCase()) {
+ lcase = function (s) { return s.toLowerCase(); };
+ } else {
+ /**
+ * {@updoc
+ * $ lcase('SCRIPT')
+ * # 'script'
+ * $ lcase('script')
+ * # 'script'
+ * }
+ */
+ lcase = function (s) {
+ return s.replace(
+ /[A-Z]/g,
+ function (ch) {
+ return String.fromCharCode(ch.charCodeAt(0) | 32);
+ });
+ };
+ }
+
+ var ENTITIES = {
+ lt : '<',
+ gt : '>',
+ amp : '&',
+ nbsp : '\240',
+ quot : '"',
+ apos : '\''
+ };
+
+ var decimalEscapeRe = /^#(\d+)$/;
+ var hexEscapeRe = /^#x([0-9A-Fa-f]+)$/;
+ /**
+ * Decodes an HTML entity.
+ *
+ * {@updoc
+ * $ lookupEntity('lt')
+ * # '<'
+ * $ lookupEntity('GT')
+ * # '>'
+ * $ lookupEntity('amp')
+ * # '&'
+ * $ lookupEntity('nbsp')
+ * # '\xA0'
+ * $ lookupEntity('apos')
+ * # "'"
+ * $ lookupEntity('quot')
+ * # '"'
+ * $ lookupEntity('#xa')
+ * # '\n'
+ * $ lookupEntity('#10')
+ * # '\n'
+ * $ lookupEntity('#x0a')
+ * # '\n'
+ * $ lookupEntity('#010')
+ * # '\n'
+ * $ lookupEntity('#x00A')
+ * # '\n'
+ * $ lookupEntity('Pi') // Known failure
+ * # '\u03A0'
+ * $ lookupEntity('pi') // Known failure
+ * # '\u03C0'
+ * }
+ *
+ * @param name the content between the '&' and the ';'.
+ * @return a single unicode code-point as a string.
+ */
+ function lookupEntity(name) {
+ name = lcase(name); // TODO: &pi; is different from &Pi;
+ if (ENTITIES.hasOwnProperty(name)) { return ENTITIES[name]; }
+ var m = name.match(decimalEscapeRe);
+ if (m) {
+ return String.fromCharCode(parseInt(m[1], 10));
+ } else if (!!(m = name.match(hexEscapeRe))) {
+ return String.fromCharCode(parseInt(m[1], 16));
+ }
+ return '';
+ }
+
+ function decodeOneEntity(_, name) {
+ return lookupEntity(name);
+ }
+
+ var nulRe = /\0/g;
+ function stripNULs(s) {
+ return s.replace(nulRe, '');
+ }
+
+ var entityRe = /&(#\d+|#x[0-9A-Fa-f]+|\w+);/g;
+ /**
+ * The plain text of a chunk of HTML CDATA which possibly containing.
+ *
+ * {@updoc
+ * $ unescapeEntities('')
+ * # ''
+ * $ unescapeEntities('hello World!')
+ * # 'hello World!'
+ * $ unescapeEntities('1 &lt; 2 &amp;&AMP; 4 &gt; 3&#10;')
+ * # '1 < 2 && 4 > 3\n'
+ * $ unescapeEntities('&lt;&lt <- unfinished entity&gt;')
+ * # '<&lt <- unfinished entity>'
+ * $ unescapeEntities('/foo?bar=baz&copy=true') // & often unescaped in URLS
+ * # '/foo?bar=baz&copy=true'
+ * $ unescapeEntities('pi=&pi;&#x3c0;, Pi=&Pi;\u03A0') // FIXME: known failure
+ * # 'pi=\u03C0\u03c0, Pi=\u03A0\u03A0'
+ * }
+ *
+ * @param s a chunk of HTML CDATA. It must not start or end inside an HTML
+ * entity.
+ */
+ function unescapeEntities(s) {
+ return s.replace(entityRe, decodeOneEntity);
+ }
+
+ var ampRe = /&/g;
+ var looseAmpRe = /&([^a-z#]|#(?:[^0-9x]|x(?:[^0-9a-f]|$)|$)|$)/gi;
+ var ltRe = /</g;
+ var gtRe = />/g;
+ var quotRe = /\"/g;
+ var eqRe = /\=/g; // Backslash required on JScript.net
+
+ /**
+ * Escapes HTML special characters in attribute values as HTML entities.
+ *
+ * {@updoc
+ * $ escapeAttrib('')
+ * # ''
+ * $ escapeAttrib('"<<&==&>>"') // Do not just escape the first occurrence.
+ * # '&#34;&lt;&lt;&amp;&#61;&#61;&amp;&gt;&gt;&#34;'
+ * $ escapeAttrib('Hello <World>!')
+ * # 'Hello &lt;World&gt;!'
+ * }
+ */
+ function escapeAttrib(s) {
+ // Escaping '=' defangs many UTF-7 and SGML short-tag attacks.
+ return s.replace(ampRe, '&amp;').replace(ltRe, '&lt;').replace(gtRe, '&gt;')
+ .replace(quotRe, '&#34;').replace(eqRe, '&#61;');
+ }
+
+ /**
+ * Escape entities in RCDATA that can be escaped without changing the meaning.
+ * {@updoc
+ * $ normalizeRCData('1 < 2 &&amp; 3 > 4 &amp;& 5 &lt; 7&8')
+ * # '1 &lt; 2 &amp;&amp; 3 &gt; 4 &amp;&amp; 5 &lt; 7&amp;8'
+ * }
+ */
+ function normalizeRCData(rcdata) {
+ return rcdata
+ .replace(looseAmpRe, '&amp;$1')
+ .replace(ltRe, '&lt;')
+ .replace(gtRe, '&gt;');
+ }
+
+
+ // TODO(mikesamuel): validate sanitizer regexs against the HTML5 grammar at
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html
+
+ /** token definitions. */
+ var INSIDE_TAG_TOKEN = new RegExp(
+ // Don't capture space.
+ '^\\s*(?:'
+ // Capture an attribute name in group 1, and value in group 3.
+ // We capture the fact that there was an attribute in group 2, since
+ // interpreters are inconsistent in whether a group that matches nothing
+ // is null, undefined, or the empty string.
+ + ('(?:'
+ + '([a-z][a-z-]*)' // attribute name
+ + ('(' // optionally followed
+ + '\\s*=\\s*'
+ + ('('
+ // A double quoted string.
+ + '\"[^\"]*\"'
+ // A single quoted string.
+ + '|\'[^\']*\''
+ // The positive lookahead is used to make sure that in
+ // <foo bar= baz=boo>, the value for bar is blank, not "baz=boo".
+ + '|(?=[a-z][a-z-]*\\s*=)'
+ // An unquoted value that is not an attribute name.
+ // We know it is not an attribute name because the previous
+ // zero-width match would've eliminated that possibility.
+ + '|[^>\"\'\\s]*'
+ + ')'
+ )
+ + ')'
+ ) + '?'
+ + ')'
+ )
+ // End of tag captured in group 3.
+ + '|(/?>)'
+ // Don't capture cruft
+ + '|.[^a-z\\s>]*)',
+ 'i');
+
+ var OUTSIDE_TAG_TOKEN = new RegExp(
+ '^(?:'
+ // Entity captured in group 1.
+ + '&(\\#[0-9]+|\\#[x][0-9a-f]+|\\w+);'
+ // Comment, doctypes, and processing instructions not captured.
+ + '|<\!--[\\s\\S]*?--\>|<!\\w[^>]*>|<\\?[^>*]*>'
+ // '/' captured in group 2 for close tags, and name captured in group 3.
+ + '|<(/)?([a-z][a-z0-9]*)'
+ // Text captured in group 4.
+ + '|([^<&>]+)'
+ // Cruft captured in group 5.
+ + '|([<&>]))',
+ 'i');
+
+ /**
+ * Given a SAX-like event handler, produce a function that feeds those
+ * events and a parameter to the event handler.
+ *
+ * The event handler has the form:{@code
+ * {
+ * // Name is an upper-case HTML tag name. Attribs is an array of
+ * // alternating upper-case attribute names, and attribute values. The
+ * // attribs array is reused by the parser. Param is the value passed to
+ * // the saxParser.
+ * startTag: function (name, attribs, param) { ... },
+ * endTag: function (name, param) { ... },
+ * pcdata: function (text, param) { ... },
+ * rcdata: function (text, param) { ... },
+ * cdata: function (text, param) { ... },
+ * startDoc: function (param) { ... },
+ * endDoc: function (param) { ... }
+ * }}
+ *
+ * @param {Object} handler a record containing event handlers.
+ * @return {Function} that takes a chunk of html and a parameter.
+ * The parameter is passed on to the handler methods.
+ */
+ function makeSaxParser(handler) {
+ return function parse(htmlText, param) {
+ htmlText = String(htmlText);
+ var htmlLower = null;
+
+ var inTag = false; // True iff we're currently processing a tag.
+ var attribs = []; // Accumulates attribute names and values.
+ var tagName = void 0; // The name of the tag currently being processed.
+ var eflags = void 0; // The element flags for the current tag.
+ var openTag = void 0; // True if the current tag is an open tag.
+
+ if (handler.startDoc) { handler.startDoc(param); }
+
+ while (htmlText) {
+ var m = htmlText.match(inTag ? INSIDE_TAG_TOKEN : OUTSIDE_TAG_TOKEN);
+ htmlText = htmlText.substring(m[0].length);
+
+ if (inTag) {
+ if (m[1]) { // attribute
+ // setAttribute with uppercase names doesn't work on IE6.
+ var attribName = lcase(m[1]);
+ var decodedValue;
+ if (m[2]) {
+ var encodedValue = m[3];
+ switch (encodedValue.charCodeAt(0)) { // Strip quotes
+ case 34: case 39:
+ encodedValue = encodedValue.substring(
+ 1, encodedValue.length - 1);
+ break;
+ }
+ decodedValue = unescapeEntities(stripNULs(encodedValue));
+ } else {
+ // Use name as value for valueless attribs, so
+ // <input type=checkbox checked>
+ // gets attributes ['type', 'checkbox', 'checked', 'checked']
+ decodedValue = attribName;
+ }
+ attribs.push(attribName, decodedValue);
+ } else if (m[4]) {
+ if (eflags !== void 0) { // False if not in whitelist.
+ if (openTag) {
+ if (handler.startTag) {
+ handler.startTag(tagName, attribs, param);
+ }
+ } else {
+ if (handler.endTag) {
+ handler.endTag(tagName, param);
+ }
+ }
+ }
+
+ if (openTag
+ && (eflags & (html4.eflags.CDATA | html4.eflags.RCDATA))) {
+ if (htmlLower === null) {
+ htmlLower = lcase(htmlText);
+ } else {
+ htmlLower = htmlLower.substring(
+ htmlLower.length - htmlText.length);
+ }
+ var dataEnd = htmlLower.indexOf('</' + tagName);
+ if (dataEnd < 0) { dataEnd = htmlText.length; }
+ if (eflags & html4.eflags.CDATA) {
+ if (handler.cdata) {
+ handler.cdata(htmlText.substring(0, dataEnd), param);
+ }
+ } else if (handler.rcdata) {
+ handler.rcdata(
+ normalizeRCData(htmlText.substring(0, dataEnd)), param);
+ }
+ htmlText = htmlText.substring(dataEnd);
+ }
+
+ tagName = eflags = openTag = void 0;
+ attribs.length = 0;
+ inTag = false;
+ }
+ } else {
+ if (m[1]) { // Entity
+ if (handler.pcdata) { handler.pcdata(m[0], param); }
+ } else if (m[3]) { // Tag
+ openTag = !m[2];
+ inTag = true;
+ tagName = lcase(m[3]);
+ eflags = html4.ELEMENTS.hasOwnProperty(tagName)
+ ? html4.ELEMENTS[tagName] : void 0;
+ } else if (m[4]) { // Text
+ if (handler.pcdata) { handler.pcdata(m[4], param); }
+ } else if (m[5]) { // Cruft
+ if (handler.pcdata) {
+ switch (m[5]) {
+ case '<': handler.pcdata('&lt;', param); break;
+ case '>': handler.pcdata('&gt;', param); break;
+ default: handler.pcdata('&amp;', param); break;
+ }
+ }
+ }
+ }
+ }
+
+ if (handler.endDoc) { handler.endDoc(param); }
+ };
+ }
+
+ return {
+ normalizeRCData: normalizeRCData,
+ escapeAttrib: escapeAttrib,
+ unescapeEntities: unescapeEntities,
+ makeSaxParser: makeSaxParser
+ };
+})();
+
+/**
+ * Returns a function that strips unsafe tags and attributes from html.
+ * @param {Function} sanitizeAttributes
+ * maps from (tagName, attribs[]) to null or a sanitized attribute array.
+ * The attribs array can be arbitrarily modified, but the same array
+ * instance is reused, so should not be held.
+ * @return {Function} from html to sanitized html
+ */
+html.makeHtmlSanitizer = function (sanitizeAttributes) {
+ var stack;
+ var ignoring;
+ return html.makeSaxParser({
+ startDoc: function (_) {
+ stack = [];
+ ignoring = false;
+ },
+ startTag: function (tagName, attribs, out) {
+ if (ignoring) { return; }
+ if (!html4.ELEMENTS.hasOwnProperty(tagName)) { return; }
+ var eflags = html4.ELEMENTS[tagName];
+ if (eflags & html4.eflags.FOLDABLE) {
+ return;
+ } else if (eflags & html4.eflags.UNSAFE) {
+ ignoring = !(eflags & html4.eflags.EMPTY);
+ return;
+ }
+ attribs = sanitizeAttributes(tagName, attribs);
+ // TODO(mikesamuel): relying on sanitizeAttributes not to
+ // insert unsafe attribute names.
+ if (attribs) {
+ if (!(eflags & html4.eflags.EMPTY)) {
+ stack.push(tagName);
+ }
+
+ out.push('<', tagName);
+ 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) {
+ out.push(' ', attribName, '="', html.escapeAttrib(value), '"');
+ }
+ }
+ out.push('>');
+ }
+ },
+ endTag: function (tagName, out) {
+ if (ignoring) {
+ ignoring = false;
+ return;
+ }
+ if (!html4.ELEMENTS.hasOwnProperty(tagName)) { return; }
+ var eflags = html4.ELEMENTS[tagName];
+ if (!(eflags & (html4.eflags.UNSAFE | html4.eflags.EMPTY
+ | html4.eflags.FOLDABLE))) {
+ var index;
+ if (eflags & html4.eflags.OPTIONAL_ENDTAG) {
+ for (index = stack.length; --index >= 0;) {
+ var stackEl = stack[index];
+ if (stackEl === tagName) { break; }
+ if (!(html4.ELEMENTS[stackEl] & html4.eflags.OPTIONAL_ENDTAG)) {
+ // Don't pop non optional end tags looking for a match.
+ return;
+ }
+ }
+ } else {
+ for (index = stack.length; --index >= 0;) {
+ if (stack[index] === tagName) { break; }
+ }
+ }
+ if (index < 0) { return; } // Not opened.
+ for (var i = stack.length; --i > index;) {
+ var stackEl = stack[i];
+ if (!(html4.ELEMENTS[stackEl] & html4.eflags.OPTIONAL_ENDTAG)) {
+ out.push('</', stackEl, '>');
+ }
+ }
+ stack.length = index;
+ out.push('</', tagName, '>');
+ }
+ },
+ pcdata: function (text, out) {
+ if (!ignoring) { out.push(text); }
+ },
+ rcdata: function (text, out) {
+ if (!ignoring) { out.push(text); }
+ },
+ cdata: function (text, out) {
+ if (!ignoring) { out.push(text); }
+ },
+ endDoc: function (out) {
+ for (var i = stack.length; --i >= 0;) {
+ out.push('</', stack[i], '>');
+ }
+ stack.length = 0;
+ }
+ });
+};
+
+
+/**
+ * Strips unsafe tags and attributes from html.
+ * @param {string} htmlText to sanitize
+ * @param {Function} opt_uriPolicy -- a transform to apply to uri/url attribute
+ * values.
+ * @param {Function} opt_nmTokenPolicy : string -> string? -- a transform to
+ * apply to names, ids, and classes.
+ * @return {string} html
+ */
+function html_sanitize(htmlText, opt_uriPolicy, opt_nmTokenPolicy) {
+ var out = [];
+ html.makeHtmlSanitizer(
+ function sanitizeAttribs(tagName, attribs) {
+ for (var i = 0; i < attribs.length; i += 2) {
+ var attribName = attribs[i];
+ var value = attribs[i + 1];
+ var atype = null, attribKey;
+ if ((attribKey = tagName + '::' + attribName,
+ html4.ATTRIBS.hasOwnProperty(attribKey))
+ || (attribKey = '*::' + attribName,
+ html4.ATTRIBS.hasOwnProperty(attribKey))) {
+ atype = html4.ATTRIBS[attribKey];
+ }
+ if (atype !== null) {
+ switch (atype) {
+ case html4.atype.NONE: break;
+ case html4.atype.SCRIPT:
+ case html4.atype.STYLE:
+ value = null;
+ break;
+ case html4.atype.ID:
+ case html4.atype.IDREF:
+ case html4.atype.IDREFS:
+ case html4.atype.GLOBAL_NAME:
+ case html4.atype.LOCAL_NAME:
+ case html4.atype.CLASSES:
+ value = opt_nmTokenPolicy ? opt_nmTokenPolicy(value) : value;
+ break;
+ case html4.atype.URI:
+ value = opt_uriPolicy && opt_uriPolicy(value);
+ break;
+ case html4.atype.URI_FRAGMENT:
+ if (value && '#' === value.charAt(0)) {
+ value = opt_nmTokenPolicy ? opt_nmTokenPolicy(value) : value;
+ if (value) { value = '#' + value; }
+ } else {
+ value = null;
+ }
+ break;
+ default:
+ value = null;
+ break;
+ }
+ } else {
+ value = null;
+ }
+ attribs[i + 1] = value;
+ }
+ return attribs;
+ })(htmlText, out);
+ return out.join('');
+}
+
+/* Copyright Google Inc.
+ * Licensed under the Apache Licence Version 2.0
+ * Autogenerated at Fri Aug 13 11:26:55 PDT 2010
+ * @provides html4
+ */
+var html4 = {};
+html4 .atype = {
+ 'NONE': 0,
+ 'URI': 1,
+ 'URI_FRAGMENT': 11,
+ 'SCRIPT': 2,
+ 'STYLE': 3,
+ 'ID': 4,
+ 'IDREF': 5,
+ 'IDREFS': 6,
+ 'GLOBAL_NAME': 7,
+ 'LOCAL_NAME': 8,
+ 'CLASSES': 9,
+ 'FRAME_TARGET': 10
+};
+html4 .ATTRIBS = {
+ '*::class': 9,
+ '*::dir': 0,
+ '*::id': 4,
+ '*::lang': 0,
+ '*::onclick': 2,
+ '*::ondblclick': 2,
+ '*::onkeydown': 2,
+ '*::onkeypress': 2,
+ '*::onkeyup': 2,
+ '*::onload': 2,
+ '*::onmousedown': 2,
+ '*::onmousemove': 2,
+ '*::onmouseout': 2,
+ '*::onmouseover': 2,
+ '*::onmouseup': 2,
+ '*::style': 3,
+ '*::title': 0,
+ 'a::accesskey': 0,
+ 'a::coords': 0,
+ 'a::href': 1,
+ 'a::hreflang': 0,
+ 'a::name': 7,
+ 'a::onblur': 2,
+ 'a::onfocus': 2,
+ 'a::rel': 0,
+ 'a::rev': 0,
+ 'a::shape': 0,
+ 'a::tabindex': 0,
+ 'a::target': 10,
+ 'a::type': 0,
+ 'area::accesskey': 0,
+ 'area::alt': 0,
+ 'area::coords': 0,
+ 'area::href': 1,
+ 'area::nohref': 0,
+ 'area::onblur': 2,
+ 'area::onfocus': 2,
+ 'area::shape': 0,
+ 'area::tabindex': 0,
+ 'area::target': 10,
+ 'bdo::dir': 0,
+ 'blockquote::cite': 1,
+ 'br::clear': 0,
+ 'button::accesskey': 0,
+ 'button::disabled': 0,
+ 'button::name': 8,
+ 'button::onblur': 2,
+ 'button::onfocus': 2,
+ 'button::tabindex': 0,
+ 'button::type': 0,
+ 'button::value': 0,
+ 'caption::align': 0,
+ 'col::align': 0,
+ 'col::char': 0,
+ 'col::charoff': 0,
+ 'col::span': 0,
+ 'col::valign': 0,
+ 'col::width': 0,
+ 'colgroup::align': 0,
+ 'colgroup::char': 0,
+ 'colgroup::charoff': 0,
+ 'colgroup::span': 0,
+ 'colgroup::valign': 0,
+ 'colgroup::width': 0,
+ 'del::cite': 1,
+ 'del::datetime': 0,
+ 'dir::compact': 0,
+ 'div::align': 0,
+ 'dl::compact': 0,
+ 'font::color': 0,
+ 'font::face': 0,
+ 'font::size': 0,
+ 'form::accept': 0,
+ 'form::action': 1,
+ 'form::autocomplete': 0,
+ 'form::enctype': 0,
+ 'form::method': 0,
+ 'form::name': 7,
+ 'form::onreset': 2,
+ 'form::onsubmit': 2,
+ 'form::target': 10,
+ 'h1::align': 0,
+ 'h2::align': 0,
+ 'h3::align': 0,
+ 'h4::align': 0,
+ 'h5::align': 0,
+ 'h6::align': 0,
+ 'hr::align': 0,
+ 'hr::noshade': 0,
+ 'hr::size': 0,
+ 'hr::width': 0,
+ 'iframe::align': 0,
+ 'iframe::frameborder': 0,
+ 'iframe::height': 0,
+ 'iframe::marginheight': 0,
+ 'iframe::marginwidth': 0,
+ 'iframe::width': 0,
+ 'img::align': 0,
+ 'img::alt': 0,
+ 'img::border': 0,
+ 'img::height': 0,
+ 'img::hspace': 0,
+ 'img::ismap': 0,
+ 'img::name': 7,
+ 'img::src': 1,
+ 'img::usemap': 11,
+ 'img::vspace': 0,
+ 'img::width': 0,
+ 'input::accept': 0,
+ 'input::accesskey': 0,
+ 'input::align': 0,
+ 'input::alt': 0,
+ 'input::autocomplete': 0,
+ 'input::checked': 0,
+ 'input::disabled': 0,
+ 'input::ismap': 0,
+ 'input::maxlength': 0,
+ 'input::name': 8,
+ 'input::onblur': 2,
+ 'input::onchange': 2,
+ 'input::onfocus': 2,
+ 'input::onselect': 2,
+ 'input::readonly': 0,
+ 'input::size': 0,
+ 'input::src': 1,
+ 'input::tabindex': 0,
+ 'input::type': 0,
+ 'input::usemap': 11,
+ 'input::value': 0,
+ 'ins::cite': 1,
+ 'ins::datetime': 0,
+ 'label::accesskey': 0,
+ 'label::for': 5,
+ 'label::onblur': 2,
+ 'label::onfocus': 2,
+ 'legend::accesskey': 0,
+ 'legend::align': 0,
+ 'li::type': 0,
+ 'li::value': 0,
+ 'map::name': 7,
+ 'menu::compact': 0,
+ 'ol::compact': 0,
+ 'ol::start': 0,
+ 'ol::type': 0,
+ 'optgroup::disabled': 0,
+ 'optgroup::label': 0,
+ 'option::disabled': 0,
+ 'option::label': 0,
+ 'option::selected': 0,
+ 'option::value': 0,
+ 'p::align': 0,
+ 'pre::width': 0,
+ 'q::cite': 1,
+ 'select::disabled': 0,
+ 'select::multiple': 0,
+ 'select::name': 8,
+ 'select::onblur': 2,
+ 'select::onchange': 2,
+ 'select::onfocus': 2,
+ 'select::size': 0,
+ 'select::tabindex': 0,
+ 'table::align': 0,
+ 'table::bgcolor': 0,
+ 'table::border': 0,
+ 'table::cellpadding': 0,
+ 'table::cellspacing': 0,
+ 'table::frame': 0,
+ 'table::rules': 0,
+ 'table::summary': 0,
+ 'table::width': 0,
+ 'tbody::align': 0,
+ 'tbody::char': 0,
+ 'tbody::charoff': 0,
+ 'tbody::valign': 0,
+ 'td::abbr': 0,
+ 'td::align': 0,
+ 'td::axis': 0,
+ 'td::bgcolor': 0,
+ 'td::char': 0,
+ 'td::charoff': 0,
+ 'td::colspan': 0,
+ 'td::headers': 6,
+ 'td::height': 0,
+ 'td::nowrap': 0,
+ 'td::rowspan': 0,
+ 'td::scope': 0,
+ 'td::valign': 0,
+ 'td::width': 0,
+ 'textarea::accesskey': 0,
+ 'textarea::cols': 0,
+ 'textarea::disabled': 0,
+ 'textarea::name': 8,
+ 'textarea::onblur': 2,
+ 'textarea::onchange': 2,
+ 'textarea::onfocus': 2,
+ 'textarea::onselect': 2,
+ 'textarea::readonly': 0,
+ 'textarea::rows': 0,
+ 'textarea::tabindex': 0,
+ 'tfoot::align': 0,
+ 'tfoot::char': 0,
+ 'tfoot::charoff': 0,
+ 'tfoot::valign': 0,
+ 'th::abbr': 0,
+ 'th::align': 0,
+ 'th::axis': 0,
+ 'th::bgcolor': 0,
+ 'th::char': 0,
+ 'th::charoff': 0,
+ 'th::colspan': 0,
+ 'th::headers': 6,
+ 'th::height': 0,
+ 'th::nowrap': 0,
+ 'th::rowspan': 0,
+ 'th::scope': 0,
+ 'th::valign': 0,
+ 'th::width': 0,
+ 'thead::align': 0,
+ 'thead::char': 0,
+ 'thead::charoff': 0,
+ 'thead::valign': 0,
+ 'tr::align': 0,
+ 'tr::bgcolor': 0,
+ 'tr::char': 0,
+ 'tr::charoff': 0,
+ 'tr::valign': 0,
+ 'ul::compact': 0,
+ 'ul::type': 0
+};
+html4 .eflags = {
+ 'OPTIONAL_ENDTAG': 1,
+ 'EMPTY': 2,
+ 'CDATA': 4,
+ 'RCDATA': 8,
+ 'UNSAFE': 16,
+ 'FOLDABLE': 32,
+ 'SCRIPT': 64,
+ 'STYLE': 128
+};
+html4 .ELEMENTS = {
+ 'a': 0,
+ 'abbr': 0,
+ 'acronym': 0,
+ 'address': 0,
+ 'applet': 16,
+ 'area': 2,
+ 'b': 0,
+ 'base': 18,
+ 'basefont': 18,
+ 'bdo': 0,
+ 'big': 0,
+ 'blockquote': 0,
+ 'body': 49,
+ 'br': 2,
+ 'button': 0,
+ 'caption': 0,
+ 'center': 0,
+ 'cite': 0,
+ 'code': 0,
+ 'col': 2,
+ 'colgroup': 1,
+ 'dd': 1,
+ 'del': 0,
+ 'dfn': 0,
+ 'dir': 0,
+ 'div': 0,
+ 'dl': 0,
+ 'dt': 1,
+ 'em': 0,
+ 'fieldset': 0,
+ 'font': 0,
+ 'form': 0,
+ 'frame': 18,
+ 'frameset': 16,
+ 'h1': 0,
+ 'h2': 0,
+ 'h3': 0,
+ 'h4': 0,
+ 'h5': 0,
+ 'h6': 0,
+ 'head': 49,
+ 'hr': 2,
+ 'html': 49,
+ 'i': 0,
+ 'iframe': 4,
+ 'img': 2,
+ 'input': 2,
+ 'ins': 0,
+ 'isindex': 18,
+ 'kbd': 0,
+ 'label': 0,
+ 'legend': 0,
+ 'li': 1,
+ 'link': 18,
+ 'map': 0,
+ 'menu': 0,
+ 'meta': 18,
+ 'noframes': 20,
+ 'noscript': 20,
+ 'object': 16,
+ 'ol': 0,
+ 'optgroup': 0,
+ 'option': 1,
+ 'p': 1,
+ 'param': 18,
+ 'pre': 0,
+ 'q': 0,
+ 's': 0,
+ 'samp': 0,
+ 'script': 84,
+ 'select': 0,
+ 'small': 0,
+ 'span': 0,
+ 'strike': 0,
+ 'strong': 0,
+ 'style': 148,
+ 'sub': 0,
+ 'sup': 0,
+ 'table': 0,
+ 'tbody': 1,
+ 'td': 1,
+ 'textarea': 8,
+ 'tfoot': 1,
+ 'th': 1,
+ 'thead': 1,
+ 'title': 24,
+ 'tr': 1,
+ 'tt': 0,
+ 'u': 0,
+ 'ul': 0,
+ 'var': 0
+};
+
+exports.escape = html.escapeAttrib;
+exports.makeSaxParser = html.makeSaxParser;
+exports.normalizeRCData = html.normalizeRCData;
+exports.sanitize = html_sanitize;
+exports.unescapeEntities = html.unescapeEntities;
View
3  package.json
@@ -30,7 +30,8 @@
"moment": "~1.6.2",
"canonical-host": "0",
"st": "0.0",
- "minimatch": "~0.2.6"
+ "minimatch": "~0.2.6",
+ "sanitizer": "0.0.15"
},
"engines": {
"node": ">=0.7.7"
Please sign in to comment.
Something went wrong with that request. Please try again.