@shgysk8zer0/polyfills 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/Document.js +1 -3
- package/README.md +1 -1
- package/all.js +1 -2
- package/all.min.js +14 -19
- package/all.min.js.map +1 -1
- package/array.js +13 -0
- package/deprecated/.gitkeep +0 -0
- package/element.js +119 -20
- package/iterator.js +39 -0
- package/package.json +6 -1
- package/popover.css +25 -0
- package/popover.js +118 -0
- package/rollup.config.js +3 -0
- package/sanitizer.js +1 -0
- package/assets/Sanitizer.js +0 -61
- package/assets/SanitizerConfig.js +0 -348
- package/assets/SanitizerConfigBase.js +0 -18
- package/assets/SanitizerConfigEdge.js +0 -335
- package/assets/SanitizerConfigW3C.js +0 -766
- package/assets/sanitizerUtils.js +0 -286
package/assets/sanitizerUtils.js
DELETED
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @copyright 2023 Chris Zuber <admin@kernvalley.us>
|
|
3
|
-
*/
|
|
4
|
-
import { SanitizerConfig as defaultConfig } from './SanitizerConfigW3C.js';
|
|
5
|
-
import { createPolicy } from './trust.js';
|
|
6
|
-
import { isObject, getType, callOnce } from './utility.js';
|
|
7
|
-
import { urls } from './attributes.js';
|
|
8
|
-
|
|
9
|
-
export const supported = () => 'Sanitizer' in globalThis;
|
|
10
|
-
export const nativeSupport = supported();
|
|
11
|
-
|
|
12
|
-
export const setHTML = function setHTML(el, input, opts = defaultConfig) {
|
|
13
|
-
const doc = safeParseHTML(input, opts);
|
|
14
|
-
el.replaceChildren(documentToFragment(doc));
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const allowProtocols = ['https:'];
|
|
18
|
-
|
|
19
|
-
if (! allowProtocols.includes(location.protocol)) {
|
|
20
|
-
allowProtocols.push(location.protocol);
|
|
21
|
-
}
|
|
22
|
-
const policyName = 'sanitizer-raw#html';
|
|
23
|
-
const getPolicy = callOnce(() => createPolicy(policyName, { createHTML: input => input }));
|
|
24
|
-
const createHTML = input => getPolicy().createHTML(input);
|
|
25
|
-
|
|
26
|
-
export function documentToFragment(doc) {
|
|
27
|
-
const frag = document.createDocumentFragment();
|
|
28
|
-
const clone = doc.cloneNode(true);
|
|
29
|
-
frag.append(...clone.head.childNodes, ...clone.body.childNodes);
|
|
30
|
-
return frag;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Helper function to adapt to changes in spec
|
|
35
|
-
*/
|
|
36
|
-
export function convertSanitizerConfig({
|
|
37
|
-
allowAttributes, allowComments, allowElements, allowCustomElements,
|
|
38
|
-
blockElements, dropAttributes, dropElements, allowUnknownMarkup, sanitizer,
|
|
39
|
-
} = {}, context) {
|
|
40
|
-
if (sanitizer instanceof Sanitizer) {
|
|
41
|
-
return convertSanitizerConfig(sanitizer.getConfiguration(), context);
|
|
42
|
-
} else {
|
|
43
|
-
switch (context) {
|
|
44
|
-
default:
|
|
45
|
-
if (typeof allowAttributes === 'undefined' && typeof dropAttributes === 'undefined') {
|
|
46
|
-
allowAttributes = defaultConfig.allowAttributes;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (typeof allowElements === 'undefined' && typeof dropElements === 'undefined') {
|
|
50
|
-
allowElements = defaultConfig.allowElements;
|
|
51
|
-
}
|
|
52
|
-
return {
|
|
53
|
-
allowAttributes, allowComments, allowElements, allowCustomElements,
|
|
54
|
-
blockElements, dropAttributes, dropElements, allowUnknownMarkup,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function convertToSanitizerConfig({
|
|
61
|
-
allowAttributes, allowComments, allowElements, allowCustomElements,
|
|
62
|
-
blockElements, dropAttributes, dropElements, allowUnknownMarkup,
|
|
63
|
-
} = {}) {
|
|
64
|
-
if (typeof allowAttributes === 'undefined' && typeof dropAttributes === 'undefined') {
|
|
65
|
-
allowAttributes = defaultConfig.allowAttributes;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (typeof allowElements === 'undefined' && typeof dropElements === 'undefined') {
|
|
69
|
-
allowElements = defaultConfig.allowElements;
|
|
70
|
-
}
|
|
71
|
-
return {
|
|
72
|
-
allowAttributes, allowComments, allowElements, allowCustomElements,
|
|
73
|
-
blockElements, dropAttributes, dropElements, allowUnknownMarkup,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function safeParseHTML(input, opts = defaultConfig) {
|
|
78
|
-
const doc = new DOMParser().parseFromString(createHTML(input), 'text/html');
|
|
79
|
-
// Not sure if this will be in spec, but it is necessary
|
|
80
|
-
if (Array.isArray(opts.allowElements) && ! opts.allowElements.includes('html') ) {
|
|
81
|
-
opts.allowElements = [...new Set([...opts.allowElements, 'html' ,'head', 'body'])];
|
|
82
|
-
}
|
|
83
|
-
return sanitizeNode(doc, opts);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function sanitize(input, opts = defaultConfig) {
|
|
87
|
-
if (! (input instanceof Node)) {
|
|
88
|
-
throw new TypeError('sanitize requires a Document or DocumentFragment');
|
|
89
|
-
} else if (input.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
90
|
-
return sanitizeNode(input, opts);
|
|
91
|
-
} else if (input.nodeType === Node.DOCUMENT_NODE) {
|
|
92
|
-
return sanitizeNode(documentToFragment(input), opts);
|
|
93
|
-
} else {
|
|
94
|
-
throw new TypeError('sanitize requires a Document or DocumentFragment');
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function sanitizeFor(tag, content, opts = defaultConfig) {
|
|
99
|
-
const el = document.createElement(tag);
|
|
100
|
-
const temp = document.createElement('template');
|
|
101
|
-
temp.innerHTML = createHTML(content);
|
|
102
|
-
el.append(sanitize(temp.content, opts));
|
|
103
|
-
return el;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export function sanitizeNode(root, opts = defaultConfig) {
|
|
107
|
-
try {
|
|
108
|
-
if (! (root instanceof Node)) {
|
|
109
|
-
throw new TypeError(`Expected a Node but got a ${getType(root)}.`);
|
|
110
|
-
} else if (! isObject(opts)) {
|
|
111
|
-
throw new TypeError(`Expected config to be an object but got ${getType(opts)}.`);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const {
|
|
115
|
-
allowElements, allowComments, allowAttributes, allowCustomElements,
|
|
116
|
-
blockElements, dropAttributes, dropElements, allowUnknownMarkup,
|
|
117
|
-
} = convertSanitizerConfig(opts);
|
|
118
|
-
|
|
119
|
-
const iter = document.createNodeIterator(
|
|
120
|
-
root,
|
|
121
|
-
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
let node = iter.root.nodeType === Node.ELEMENT_NODE
|
|
125
|
-
? iter.root
|
|
126
|
-
: iter.nextNode();
|
|
127
|
-
|
|
128
|
-
while (node instanceof Node) {
|
|
129
|
-
switch(node.nodeType) {
|
|
130
|
-
case Node.ELEMENT_NODE: {
|
|
131
|
-
if (
|
|
132
|
-
! allowUnknownMarkup
|
|
133
|
-
&& ( ! (node instanceof HTMLElement) || node instanceof HTMLUnknownElement)
|
|
134
|
-
) {
|
|
135
|
-
node.remove();
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const tag = node.tagName.toLowerCase();
|
|
140
|
-
|
|
141
|
-
if (Array.isArray(dropElements) && dropElements.includes(tag)) {
|
|
142
|
-
node.remove();
|
|
143
|
-
} else if (Array.isArray(blockElements) && blockElements.includes(tag)) {
|
|
144
|
-
if (node.hasChildNodes()) {
|
|
145
|
-
node.replaceWith(...node.childNodes);
|
|
146
|
-
} else {
|
|
147
|
-
node.remove();
|
|
148
|
-
}
|
|
149
|
-
} else if (tag.includes('-') && ! allowCustomElements) {
|
|
150
|
-
node.remove();
|
|
151
|
-
} else if (Array.isArray(allowElements) && ! allowElements.includes(tag)) {
|
|
152
|
-
node.remove();
|
|
153
|
-
} else {
|
|
154
|
-
if (node.hasAttributes()) {
|
|
155
|
-
node.getAttributeNames().forEach(name => {
|
|
156
|
-
const attr = node.getAttributeNode(name);
|
|
157
|
-
const { value } = attr;
|
|
158
|
-
|
|
159
|
-
if (
|
|
160
|
-
urls.includes(name)
|
|
161
|
-
&& ! allowProtocols.includes(new URL(value, document.baseURI).protocol)
|
|
162
|
-
) {
|
|
163
|
-
node.removeAttributeNode(attr);
|
|
164
|
-
} else if (isObject(dropAttributes)) {
|
|
165
|
-
if (
|
|
166
|
-
name in dropAttributes
|
|
167
|
-
&& ['*', tag].some(sel => dropAttributes[name].includes(sel))
|
|
168
|
-
) {
|
|
169
|
-
node.removeAttributeNode(attr);
|
|
170
|
-
}
|
|
171
|
-
} else if (isObject(allowAttributes)) {
|
|
172
|
-
if (
|
|
173
|
-
! (name in allowAttributes
|
|
174
|
-
&& ['*', tag].some(sel => allowAttributes[name].includes(sel)))
|
|
175
|
-
) {
|
|
176
|
-
node.removeAttributeNode(attr);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
break;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
case Node.COMMENT_NODE: {
|
|
187
|
-
if (! allowComments) {
|
|
188
|
-
node.remove();
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (node.localName === 'template') {
|
|
196
|
-
sanitizeNode(node.content, opts);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
node = iter.nextNode();
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return root;
|
|
203
|
-
} catch(err) {
|
|
204
|
-
console.error(err);
|
|
205
|
-
root.parentElement.removeChild(root);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export function getSantizerUtils(Sanitizer, defaultConfig) {
|
|
210
|
-
const polyfill = function polyfill() {
|
|
211
|
-
let polyfilled = false;
|
|
212
|
-
|
|
213
|
-
if (! supported()) {
|
|
214
|
-
globalThis.Sanitizer = Sanitizer;
|
|
215
|
-
polyfilled = true;
|
|
216
|
-
} else {
|
|
217
|
-
if (! (globalThis.Sanitizer.getDefaultConfiguration instanceof Function)) {
|
|
218
|
-
globalThis.Sanitizer.getDefaultConfiguration = function() {
|
|
219
|
-
return defaultConfig;
|
|
220
|
-
};
|
|
221
|
-
polyfilled = true;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (! (globalThis.Sanitizer.prototype.getConfiguration instanceof Function)) {
|
|
225
|
-
const configs = new WeakMap();
|
|
226
|
-
const SanitizerNative = globalThis.Sanitizer;
|
|
227
|
-
|
|
228
|
-
globalThis.Sanitizer = class Sanitizer extends SanitizerNative {
|
|
229
|
-
constructor({
|
|
230
|
-
allowAttributes, allowComments, allowElements, allowCustomElements,
|
|
231
|
-
blockElements, dropAttributes, dropElements, allowUnknownMarkup,
|
|
232
|
-
} = SanitizerNative.getDefaultConfiguration()) {
|
|
233
|
-
super({
|
|
234
|
-
allowAttributes, allowComments, allowElements, allowCustomElements,
|
|
235
|
-
blockElements, dropAttributes, dropElements, allowUnknownMarkup,
|
|
236
|
-
});
|
|
237
|
-
configs.set(this, {
|
|
238
|
-
allowAttributes, allowComments, allowElements, allowCustomElements,
|
|
239
|
-
blockElements, dropAttributes, dropElements, allowUnknownMarkup,
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
getConfiguration() {
|
|
244
|
-
return configs.get(this);
|
|
245
|
-
}
|
|
246
|
-
};
|
|
247
|
-
polyfilled = true;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (! (globalThis.Sanitizer.prototype.sanitize instanceof Function)) {
|
|
251
|
-
globalThis.Sanitizer.prototype.sanitize = function(input) {
|
|
252
|
-
if (! (input instanceof Node)) {
|
|
253
|
-
throw new TypeError('`Sanitizer.sanitize()` expects a `Node`');
|
|
254
|
-
} else if (! [Node.DOCUMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE].includes(input.nodeType)) {
|
|
255
|
-
throw new TypeError('Expected a Document or DocumentFragment in `Sanitizer.sanitize()`.');
|
|
256
|
-
} else {
|
|
257
|
-
return sanitize(input, this.getConfiguration());
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
polyfilled = true;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (! (globalThis.Sanitizer.prototype.sanitizeFor instanceof Function)) {
|
|
264
|
-
globalThis.Sanitizer.prototype.sanitizeFor = function(element, input) {
|
|
265
|
-
const el = document.createElement(element);
|
|
266
|
-
setHTML(el, input,this.getConfiguration());
|
|
267
|
-
return el;
|
|
268
|
-
};
|
|
269
|
-
polyfilled = true;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
if (! (Element.prototype.setHTML instanceof Function)) {
|
|
273
|
-
Element.prototype.setHTML = function(input, opts = defaultConfig) {
|
|
274
|
-
setHTML(this, input, opts);
|
|
275
|
-
};
|
|
276
|
-
polyfilled = true;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return polyfilled;
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
return { setHTML, polyfill };
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
export const trustPolicies = [policyName];
|