| /** |
| * Whitelist of tag names allowed in parseHtmlSubset. |
| * @type {[string]} |
| */ |
| var allowedTags = ['A', 'B', 'STRONG']; |
| |
| /** |
| * Parse a very small subset of HTML. |
| * @param {string} s The string to parse. |
| * @throws {Error} In case of non supported markup. |
| * @return {DocumentFragment} A document fragment containing the DOM tree. |
| */ |
| var allowedAttributes = { |
| 'href': function(node, value) { |
| // Only allow a[href] starting with http:// and https:// |
| return node.tagName == 'A' && (value.indexOf('http://') == 0 || |
| value.indexOf('https://') == 0); |
| }, |
| 'target': function(node, value) { |
| // Allow a[target] but reset the value to "". |
| if (node.tagName != 'A') |
| return false; |
| node.setAttribute('target', ''); |
| return true; |
| } |
| } |
| |
| /** |
| * Parse a very small subset of HTML. This ensures that insecure HTML / |
| * javascript cannot be injected into the new tab page. |
| * @param {string} s The string to parse. |
| * @throws {Error} In case of non supported markup. |
| * @return {DocumentFragment} A document fragment containing the DOM tree. |
| */ |
| function parseHtmlSubset(s) { |
| function walk(n, f) { |
| f(n); |
| for (var i = 0; i < n.childNodes.length; i++) { |
| walk(n.childNodes[i], f); |
| } |
| } |
| |
| function assertElement(node) { |
| if (allowedTags.indexOf(node.tagName) == -1) |
| throw Error(node.tagName + ' is not supported'); |
| } |
| |
| function assertAttribute(attrNode, node) { |
| var n = attrNode.nodeName; |
| var v = attrNode.nodeValue; |
| if (!allowedAttributes.hasOwnProperty(n) || !allowedAttributes[n](node, v)) |
| throw Error(node.tagName + '[' + n + '="' + v + '"] is not supported'); |
| } |
| |
| var r = document.createRange(); |
| r.selectNode(document.body); |
| // This does not execute any scripts. |
| var df = r.createContextualFragment(s); |
| walk(df, function(node) { |
| switch (node.nodeType) { |
| case Node.ELEMENT_NODE: |
| assertElement(node); |
| var attrs = node.attributes; |
| for (var i = 0; i < attrs.length; i++) { |
| assertAttribute(attrs[i], node); |
| } |
| break; |
| |
| case Node.COMMENT_NODE: |
| case Node.DOCUMENT_FRAGMENT_NODE: |
| case Node.TEXT_NODE: |
| break; |
| |
| default: |
| throw Error('Node type ' + node.nodeType + ' is not supported'); |
| } |
| }); |
| return df; |
| } |