@zeropress/build-core 0.6.8 → 0.6.11
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/package.json
CHANGED
|
@@ -329,18 +329,22 @@ function sanitizeHtml(html) {
|
|
|
329
329
|
'ul', 'ol', 'li',
|
|
330
330
|
'blockquote', 'aside',
|
|
331
331
|
'figure', 'figcaption', 'picture', 'source',
|
|
332
|
+
'video', 'audio', 'track',
|
|
332
333
|
'table', 'thead', 'tbody', 'tr', 'th', 'td',
|
|
333
334
|
'div', 'span', 'nav',
|
|
334
335
|
'iframe', 'input',
|
|
335
336
|
]);
|
|
336
337
|
|
|
337
338
|
const allowedAttributes = {
|
|
338
|
-
a: new Set(['href', 'title', 'class', 'id']),
|
|
339
|
+
a: new Set(['href', 'title', 'class', 'id', 'target', 'rel']),
|
|
339
340
|
aside: new Set(['role', 'class', 'id']),
|
|
340
341
|
img: new Set(['src', 'srcset', 'sizes', 'alt', 'title', 'class', 'id', 'width', 'height', 'loading', 'decoding']),
|
|
341
|
-
iframe: new Set(['src', 'width', 'height', 'frameborder', 'allowfullscreen', 'class']),
|
|
342
|
+
iframe: new Set(['src', 'width', 'height', 'frameborder', 'allowfullscreen', 'class', 'title']),
|
|
342
343
|
input: new Set(['type', 'checked', 'disabled', 'class', 'id', 'aria-label']),
|
|
343
344
|
source: new Set(['src', 'srcset', 'sizes', 'type', 'media', 'width', 'height', 'class', 'id']),
|
|
345
|
+
video: new Set(['src', 'controls', 'controlslist', 'autoplay', 'loop', 'muted', 'playsinline', 'poster', 'preload', 'width', 'height', 'class', 'id', 'title']),
|
|
346
|
+
audio: new Set(['src', 'controls', 'controlslist', 'autoplay', 'loop', 'muted', 'preload', 'class', 'id', 'title']),
|
|
347
|
+
track: new Set(['src', 'kind', 'srclang', 'label', 'default', 'class', 'id']),
|
|
344
348
|
'*': new Set(['class', 'id']),
|
|
345
349
|
};
|
|
346
350
|
|
|
@@ -364,6 +368,8 @@ function sanitizeHtml(html) {
|
|
|
364
368
|
const tagAllowedAttributes = allowedAttributes[normalizedTag] || new Set();
|
|
365
369
|
const globalAllowedAttributes = allowedAttributes['*'];
|
|
366
370
|
const filteredAttributes = [];
|
|
371
|
+
let anchorTarget = '';
|
|
372
|
+
let anchorRel = '';
|
|
367
373
|
|
|
368
374
|
if (attributeString) {
|
|
369
375
|
const attributePattern = /([a-zA-Z][a-zA-Z0-9-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|(\S+)))?/g;
|
|
@@ -377,7 +383,25 @@ function sanitizeHtml(html) {
|
|
|
377
383
|
continue;
|
|
378
384
|
}
|
|
379
385
|
|
|
380
|
-
if ((attributeName === 'href' || attributeName === 'src') && !safeUriPattern.test(attributeValue)) {
|
|
386
|
+
if ((attributeName === 'href' || attributeName === 'src' || attributeName === 'poster') && !safeUriPattern.test(attributeValue)) {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (normalizedTag === 'a' && attributeName === 'target') {
|
|
391
|
+
const target = sanitizeAnchorTarget(attributeValue);
|
|
392
|
+
if (!target) {
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
anchorTarget = target;
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (normalizedTag === 'a' && attributeName === 'rel') {
|
|
400
|
+
const rel = sanitizeRelList(attributeValue);
|
|
401
|
+
if (!rel) {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
anchorRel = rel;
|
|
381
405
|
continue;
|
|
382
406
|
}
|
|
383
407
|
|
|
@@ -385,6 +409,15 @@ function sanitizeHtml(html) {
|
|
|
385
409
|
continue;
|
|
386
410
|
}
|
|
387
411
|
|
|
412
|
+
if (attributeName === 'controlslist') {
|
|
413
|
+
const controlsList = sanitizeControlsList(attributeValue);
|
|
414
|
+
if (!controlsList) {
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
filteredAttributes.push(`${attributeName}="${controlsList}"`);
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
|
|
388
421
|
if (normalizedTag === 'input' && attributeName === 'type' && attributeValue !== 'checkbox') {
|
|
389
422
|
continue;
|
|
390
423
|
}
|
|
@@ -393,7 +426,19 @@ function sanitizeHtml(html) {
|
|
|
393
426
|
}
|
|
394
427
|
}
|
|
395
428
|
|
|
396
|
-
|
|
429
|
+
if (normalizedTag === 'a') {
|
|
430
|
+
if (anchorTarget) {
|
|
431
|
+
filteredAttributes.push(`target="${anchorTarget}"`);
|
|
432
|
+
}
|
|
433
|
+
if (anchorTarget === '_blank') {
|
|
434
|
+
anchorRel = ensureBlankTargetRel(anchorRel);
|
|
435
|
+
}
|
|
436
|
+
if (anchorRel) {
|
|
437
|
+
filteredAttributes.push(`rel="${anchorRel}"`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const isSelfClosing = match.endsWith('/>') || normalizedTag === 'br' || normalizedTag === 'hr' || normalizedTag === 'img' || normalizedTag === 'input' || normalizedTag === 'source' || normalizedTag === 'track';
|
|
397
442
|
const attributeSuffix = filteredAttributes.length > 0 ? ` ${filteredAttributes.join(' ')}` : '';
|
|
398
443
|
return isSelfClosing ? `<${normalizedTag}${attributeSuffix} />` : `<${normalizedTag}${attributeSuffix}>`;
|
|
399
444
|
});
|
|
@@ -410,6 +455,52 @@ function sanitizeHtml(html) {
|
|
|
410
455
|
.join('');
|
|
411
456
|
}
|
|
412
457
|
|
|
458
|
+
function sanitizeAnchorTarget(value) {
|
|
459
|
+
const normalized = String(value).trim().toLowerCase();
|
|
460
|
+
return normalized === '_blank' ? '_blank' : '';
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function sanitizeRelList(value) {
|
|
464
|
+
const allowedTokens = new Set(['noopener', 'noreferrer', 'nofollow', 'ugc', 'sponsored', 'external']);
|
|
465
|
+
const tokens = String(value)
|
|
466
|
+
.toLowerCase()
|
|
467
|
+
.split(/\s+/)
|
|
468
|
+
.filter((token, index, allTokens) => (
|
|
469
|
+
allowedTokens.has(token)
|
|
470
|
+
&& allTokens.indexOf(token) === index
|
|
471
|
+
));
|
|
472
|
+
|
|
473
|
+
return tokens.join(' ');
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function ensureBlankTargetRel(value) {
|
|
477
|
+
const tokens = String(value)
|
|
478
|
+
.toLowerCase()
|
|
479
|
+
.split(/\s+/)
|
|
480
|
+
.filter(Boolean);
|
|
481
|
+
|
|
482
|
+
for (const requiredToken of ['noopener', 'noreferrer']) {
|
|
483
|
+
if (!tokens.includes(requiredToken)) {
|
|
484
|
+
tokens.push(requiredToken);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
return tokens.join(' ');
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function sanitizeControlsList(value) {
|
|
492
|
+
const allowedTokens = new Set(['nodownload', 'nofullscreen', 'noremoteplayback']);
|
|
493
|
+
const tokens = String(value)
|
|
494
|
+
.toLowerCase()
|
|
495
|
+
.split(/\s+/)
|
|
496
|
+
.filter((token, index, allTokens) => (
|
|
497
|
+
allowedTokens.has(token)
|
|
498
|
+
&& allTokens.indexOf(token) === index
|
|
499
|
+
));
|
|
500
|
+
|
|
501
|
+
return tokens.join(' ');
|
|
502
|
+
}
|
|
503
|
+
|
|
413
504
|
function isSafeSrcset(value, safeUriPattern) {
|
|
414
505
|
const candidates = String(value)
|
|
415
506
|
.split(',')
|