1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | const 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 |
|
17 |
|
18 |
|
19 |
|
20 | const documentFragment = document.createDocumentFragment();
|
21 | const workingDiv = document.createElement('div');
|
22 | documentFragment.appendChild(workingDiv);
|
23 | workingDiv.innerHTML = untrustedString;
|
24 | |
25 |
|
26 |
|
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 |
|
40 |
|
41 |
|
42 |
|
43 | const childElements = getElementChildren(element);
|
44 |
|
45 | for (let childIndex = 0; childIndex < childElements.length; childIndex++) {
|
46 | sanitizeElement(childElements[childIndex]);
|
47 | }
|
48 | }
|
49 | });
|
50 | |
51 |
|
52 |
|
53 |
|
54 |
|
55 | const dfChildren = getElementChildren(documentFragment);
|
56 |
|
57 | for (let childIndex = 0; childIndex < dfChildren.length; childIndex++) {
|
58 | sanitizeElement(dfChildren[childIndex]);
|
59 | }
|
60 |
|
61 | const fragmentDiv = document.createElement('div');
|
62 | fragmentDiv.appendChild(documentFragment);
|
63 |
|
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 |
|
74 |
|
75 |
|
76 |
|
77 | const sanitizeElement = (element) => {
|
78 |
|
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 |
|
86 | if (!allowedAttributes.includes(attributeName.toLowerCase())) {
|
87 | element.removeAttribute(attributeName);
|
88 | continue;
|
89 | }
|
90 |
|
91 |
|
92 | const attributeValue = attribute.value;
|
93 |
|
94 | if (attributeValue != null && attributeValue.toLowerCase().includes('javascript:')) {
|
95 | element.removeAttribute(attributeName);
|
96 | }
|
97 | }
|
98 | |
99 |
|
100 |
|
101 | const childElements = getElementChildren(element);
|
102 |
|
103 | for (let i = 0; i < childElements.length; i++) {
|
104 | sanitizeElement(childElements[i]);
|
105 | }
|
106 | };
|
107 |
|
108 |
|
109 |
|
110 |
|
111 | const getElementChildren = (el) => {
|
112 | return (el.children != null) ? el.children : el.childNodes;
|
113 | };
|
114 | const 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 | };
|
127 | const allowedAttributes = ['class', 'id', 'href', 'src', 'name', 'slot'];
|
128 | const blockedTags = ['script', 'style', 'iframe', 'meta', 'link', 'object', 'embed'];
|
129 | class IonicSafeString {
|
130 | constructor(value) {
|
131 | this.value = value;
|
132 | }
|
133 | }
|
134 |
|
135 | exports.IonicSafeString = IonicSafeString;
|
136 | exports.sanitizeDOMString = sanitizeDOMString;
|