1/** 2 * Whitelist of tag names allowed in parseHtmlSubset. 3 * @type {[string]} 4 */ 5var allowedTags = ['A', 'B', 'STRONG']; 6 7/** 8 * Parse a very small subset of HTML. 9 * @param {string} s The string to parse. 10 * @throws {Error} In case of non supported markup. 11 * @return {DocumentFragment} A document fragment containing the DOM tree. 12 */ 13var allowedAttributes = { 14 'href': function(node, value) { 15 // Only allow a[href] starting with http:// and https:// 16 return node.tagName == 'A' && (value.indexOf('http://') == 0 || 17 value.indexOf('https://') == 0); 18 }, 19 'target': function(node, value) { 20 // Allow a[target] but reset the value to "". 21 if (node.tagName != 'A') 22 return false; 23 node.setAttribute('target', ''); 24 return true; 25 } 26} 27 28/** 29 * Parse a very small subset of HTML. This ensures that insecure HTML / 30 * javascript cannot be injected into the new tab page. 31 * @param {string} s The string to parse. 32 * @throws {Error} In case of non supported markup. 33 * @return {DocumentFragment} A document fragment containing the DOM tree. 34 */ 35function parseHtmlSubset(s) { 36 function walk(n, f) { 37 f(n); 38 for (var i = 0; i < n.childNodes.length; i++) { 39 walk(n.childNodes[i], f); 40 } 41 } 42 43 function assertElement(node) { 44 if (allowedTags.indexOf(node.tagName) == -1) 45 throw Error(node.tagName + ' is not supported'); 46 } 47 48 function assertAttribute(attrNode, node) { 49 var n = attrNode.nodeName; 50 var v = attrNode.nodeValue; 51 if (!allowedAttributes.hasOwnProperty(n) || !allowedAttributes[n](node, v)) 52 throw Error(node.tagName + '[' + n + '="' + v + '"] is not supported'); 53 } 54 55 var r = document.createRange(); 56 r.selectNode(document.body); 57 // This does not execute any scripts. 58 var df = r.createContextualFragment(s); 59 walk(df, function(node) { 60 switch (node.nodeType) { 61 case Node.ELEMENT_NODE: 62 assertElement(node); 63 var attrs = node.attributes; 64 for (var i = 0; i < attrs.length; i++) { 65 assertAttribute(attrs[i], node); 66 } 67 break; 68 69 case Node.COMMENT_NODE: 70 case Node.DOCUMENT_FRAGMENT_NODE: 71 case Node.TEXT_NODE: 72 break; 73 74 default: 75 throw Error('Node type ' + node.nodeType + ' is not supported'); 76 } 77 }); 78 return df; 79} 80