UNPKG

4.46 kBJavaScriptView Raw
1'use strict';
2
3/**
4 * Does a simple sanitization of all elements
5 * in an untrusted string
6 */
7const sanitizeDOMString = (untrustedString) => {
8 try {
9 if (untrustedString instanceof IonicSafeString) {
10 return untrustedString.value;
11 }
12 if (!isSanitizerEnabled() || typeof untrustedString !== 'string' || untrustedString === '') {
13 return untrustedString;
14 }
15 /**
16 * Create a document fragment
17 * separate from the main DOM,
18 * create a div to do our work in
19 */
20 const documentFragment = document.createDocumentFragment();
21 const workingDiv = document.createElement('div');
22 documentFragment.appendChild(workingDiv);
23 workingDiv.innerHTML = untrustedString;
24 /**
25 * Remove any elements
26 * that are blocked
27 */
28 blockedTags.forEach(blockedTag => {
29 const getElementsToRemove = documentFragment.querySelectorAll(blockedTag);
30 for (let elementIndex = getElementsToRemove.length - 1; elementIndex >= 0; elementIndex--) {
31 const element = getElementsToRemove[elementIndex];
32 if (element.parentNode) {
33 element.parentNode.removeChild(element);
34 }
35 else {
36 documentFragment.removeChild(element);
37 }
38 /**
39 * We still need to sanitize
40 * the children of this element
41 * as they are left behind
42 */
43 const childElements = getElementChildren(element);
44 /* tslint:disable-next-line */
45 for (let childIndex = 0; childIndex < childElements.length; childIndex++) {
46 sanitizeElement(childElements[childIndex]);
47 }
48 }
49 });
50 /**
51 * Go through remaining elements and remove
52 * non-allowed attribs
53 */
54 // IE does not support .children on document fragments, only .childNodes
55 const dfChildren = getElementChildren(documentFragment);
56 /* tslint:disable-next-line */
57 for (let childIndex = 0; childIndex < dfChildren.length; childIndex++) {
58 sanitizeElement(dfChildren[childIndex]);
59 }
60 // Append document fragment to div
61 const fragmentDiv = document.createElement('div');
62 fragmentDiv.appendChild(documentFragment);
63 // First child is always the div we did our work in
64 const getInnerDiv = fragmentDiv.querySelector('div');
65 return (getInnerDiv !== null) ? getInnerDiv.innerHTML : fragmentDiv.innerHTML;
66 }
67 catch (err) {
68 console.error(err);
69 return '';
70 }
71};
72/**
73 * Clean up current element based on allowed attributes
74 * and then recursively dig down into any child elements to
75 * clean those up as well
76 */
77const sanitizeElement = (element) => {
78 // IE uses childNodes, so ignore nodes that are not elements
79 if (element.nodeType && element.nodeType !== 1) {
80 return;
81 }
82 for (let i = element.attributes.length - 1; i >= 0; i--) {
83 const attribute = element.attributes.item(i);
84 const attributeName = attribute.name;
85 // remove non-allowed attribs
86 if (!allowedAttributes.includes(attributeName.toLowerCase())) {
87 element.removeAttribute(attributeName);
88 continue;
89 }
90 // clean up any allowed attribs
91 // that attempt to do any JS funny-business
92 const attributeValue = attribute.value;
93 /* tslint:disable-next-line */
94 if (attributeValue != null && attributeValue.toLowerCase().includes('javascript:')) {
95 element.removeAttribute(attributeName);
96 }
97 }
98 /**
99 * Sanitize any nested children
100 */
101 const childElements = getElementChildren(element);
102 /* tslint:disable-next-line */
103 for (let i = 0; i < childElements.length; i++) {
104 sanitizeElement(childElements[i]);
105 }
106};
107/**
108 * IE doesn't always support .children
109 * so we revert to .childNodes instead
110 */
111const getElementChildren = (el) => {
112 return (el.children != null) ? el.children : el.childNodes;
113};
114const isSanitizerEnabled = () => {
115 const win = window;
116 const config = win && win.Ionic && win.Ionic.config;
117 if (config) {
118 if (config.get) {
119 return config.get('sanitizerEnabled', true);
120 }
121 else {
122 return config.sanitizerEnabled === true || config.sanitizerEnabled === undefined;
123 }
124 }
125 return true;
126};
127const allowedAttributes = ['class', 'id', 'href', 'src', 'name', 'slot'];
128const blockedTags = ['script', 'style', 'iframe', 'meta', 'link', 'object', 'embed'];
129class IonicSafeString {
130 constructor(value) {
131 this.value = value;
132 }
133}
134
135exports.IonicSafeString = IonicSafeString;
136exports.sanitizeDOMString = sanitizeDOMString;