html2canvas-pro 2.4.5 → 2.5.0
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/README.md +115 -13
- package/dist/html2canvas-pro.cjs +3058 -1607
- package/dist/html2canvas-pro.cjs.map +1 -1
- package/dist/html2canvas-pro.esm.js +3058 -1607
- package/dist/html2canvas-pro.esm.js.map +1 -1
- package/dist/html2canvas-pro.js +3055 -1604
- package/dist/html2canvas-pro.js.map +1 -1
- package/dist/html2canvas-pro.min.js +5 -5
- package/dist/types/core/cache-storage.d.ts +4 -1
- package/dist/types/core/context.d.ts +10 -1
- package/dist/types/core/render-element.d.ts +11 -0
- package/dist/types/core/util.d.ts +6 -0
- package/dist/types/css/index.d.ts +77 -46
- package/dist/types/css/parse.d.ts +15 -0
- package/dist/types/css/property-descriptors/accent-color.d.ts +5 -0
- package/dist/types/css/property-descriptors/backdrop-filter.d.ts +9 -0
- package/dist/types/css/property-descriptors/background-blend-mode.d.ts +16 -16
- package/dist/types/css/property-descriptors/border-image-width.d.ts +36 -0
- package/dist/types/css/property-descriptors/clip-path.d.ts +16 -2
- package/dist/types/css/property-descriptors/isolation.d.ts +6 -0
- package/dist/types/css/property-descriptors/mask.d.ts +25 -0
- package/dist/types/css/property-descriptors/mix-blend-mode.d.ts +16 -16
- package/dist/types/css/property-descriptors/outline.d.ts +15 -0
- package/dist/types/css/property-descriptors/text-emphasis.d.ts +22 -0
- package/dist/types/css/property-descriptors/text-shadow.d.ts +1 -1
- package/dist/types/css/property-descriptors/webkit-box-reflect.d.ts +19 -0
- package/dist/types/css/property-descriptors/webkit-text-fill-color.d.ts +9 -0
- package/dist/types/css/syntax/token-constants.d.ts +1 -1
- package/dist/types/css/types/color-math.d.ts +7 -1
- package/dist/types/css/types/color-spaces/a98.d.ts +2 -1
- package/dist/types/css/types/color-spaces/p3.d.ts +5 -4
- package/dist/types/css/types/color-spaces/pro-photo.d.ts +5 -4
- package/dist/types/css/types/color-spaces/rec2020.d.ts +5 -4
- package/dist/types/css/types/color-spaces/srgb.d.ts +5 -4
- package/dist/types/css/types/color-utilities.d.ts +11 -11
- package/dist/types/css/types/color.d.ts +1 -0
- package/dist/types/css/types/functions/conic-gradient.d.ts +11 -0
- package/dist/types/css/types/functions/image-set.d.ts +11 -0
- package/dist/types/css/types/functions/repeating-radial-gradient.d.ts +8 -0
- package/dist/types/css/types/image.d.ts +15 -2
- package/dist/types/css/types/safe-eval.d.ts +0 -6
- package/dist/types/dom/copy-css-styles.d.ts +8 -0
- package/dist/types/dom/document-cloner.d.ts +3 -13
- package/dist/types/dom/iframe-mount.d.ts +37 -0
- package/dist/types/dom/pseudo-content.d.ts +33 -0
- package/dist/types/dom/replaced-elements/iframe-element-container.d.ts +2 -2
- package/dist/types/options.d.ts +8 -2
- package/dist/types/render/canvas/background-renderer.d.ts +19 -0
- package/dist/types/render/canvas/border-image-renderer.d.ts +50 -1
- package/dist/types/render/canvas/canvas-renderer.d.ts +21 -15
- package/dist/types/render/canvas/mask-renderer.d.ts +36 -0
- package/dist/types/render/canvas/text-clip-renderer.d.ts +36 -0
- package/dist/types/render/canvas/text-renderer.d.ts +22 -0
- package/dist/types/render/stacking-context.d.ts +4 -1
- package/package.json +39 -40
- package/dist/lib/config.js +0 -49
- package/dist/lib/core/abort-helper.js +0 -20
- package/dist/lib/core/background-parser.js +0 -41
- package/dist/lib/core/bitwise.js +0 -5
- package/dist/lib/core/cache-storage.js +0 -283
- package/dist/lib/core/config-assembler.js +0 -88
- package/dist/lib/core/constants.js +0 -25
- package/dist/lib/core/context.js +0 -19
- package/dist/lib/core/debugger.js +0 -27
- package/dist/lib/core/features.js +0 -190
- package/dist/lib/core/logger.js +0 -56
- package/dist/lib/core/lru-map.js +0 -66
- package/dist/lib/core/origin-checker.js +0 -53
- package/dist/lib/core/performance-monitor.js +0 -185
- package/dist/lib/core/render-element.js +0 -131
- package/dist/lib/core/util.js +0 -4
- package/dist/lib/core/validator.js +0 -500
- package/dist/lib/css/grouped/background-styles.js +0 -36
- package/dist/lib/css/grouped/border-styles.js +0 -75
- package/dist/lib/css/grouped/font-styles.js +0 -93
- package/dist/lib/css/grouped/layout-styles.js +0 -127
- package/dist/lib/css/index.js +0 -339
- package/dist/lib/css/layout/bounds.js +0 -52
- package/dist/lib/css/layout/text.js +0 -133
- package/dist/lib/css/property-descriptor.js +0 -2
- package/dist/lib/css/property-descriptors/background-blend-mode.js +0 -41
- package/dist/lib/css/property-descriptors/background-clip.js +0 -25
- package/dist/lib/css/property-descriptors/background-color.js +0 -10
- package/dist/lib/css/property-descriptors/background-image.js +0 -24
- package/dist/lib/css/property-descriptors/background-origin.js +0 -23
- package/dist/lib/css/property-descriptors/background-position.js +0 -19
- package/dist/lib/css/property-descriptors/background-repeat.js +0 -33
- package/dist/lib/css/property-descriptors/background-size.js +0 -23
- package/dist/lib/css/property-descriptors/border-color.js +0 -14
- package/dist/lib/css/property-descriptors/border-image-repeat.js +0 -42
- package/dist/lib/css/property-descriptors/border-image-slice.js +0 -45
- package/dist/lib/css/property-descriptors/border-image-source.js +0 -22
- package/dist/lib/css/property-descriptors/border-radius.js +0 -15
- package/dist/lib/css/property-descriptors/border-style.js +0 -26
- package/dist/lib/css/property-descriptors/border-width.js +0 -20
- package/dist/lib/css/property-descriptors/box-decoration-break.js +0 -18
- package/dist/lib/css/property-descriptors/box-shadow.js +0 -54
- package/dist/lib/css/property-descriptors/clip-path.js +0 -189
- package/dist/lib/css/property-descriptors/color.js +0 -10
- package/dist/lib/css/property-descriptors/content.js +0 -19
- package/dist/lib/css/property-descriptors/counter-increment.js +0 -35
- package/dist/lib/css/property-descriptors/counter-reset.js +0 -18
- package/dist/lib/css/property-descriptors/direction.js +0 -18
- package/dist/lib/css/property-descriptors/display.js +0 -81
- package/dist/lib/css/property-descriptors/duration.js +0 -14
- package/dist/lib/css/property-descriptors/filter.js +0 -86
- package/dist/lib/css/property-descriptors/float.js +0 -22
- package/dist/lib/css/property-descriptors/font-family.js +0 -47
- package/dist/lib/css/property-descriptors/font-size.js +0 -10
- package/dist/lib/css/property-descriptors/font-style.js +0 -20
- package/dist/lib/css/property-descriptors/font-variant-ligatures.js +0 -34
- package/dist/lib/css/property-descriptors/font-variant.js +0 -13
- package/dist/lib/css/property-descriptors/font-weight.js +0 -25
- package/dist/lib/css/property-descriptors/image-rendering.js +0 -33
- package/dist/lib/css/property-descriptors/letter-spacing.js +0 -21
- package/dist/lib/css/property-descriptors/line-break.js +0 -23
- package/dist/lib/css/property-descriptors/line-height.js +0 -24
- package/dist/lib/css/property-descriptors/list-style-image.js +0 -17
- package/dist/lib/css/property-descriptors/list-style-position.js +0 -18
- package/dist/lib/css/property-descriptors/list-style-type.js +0 -122
- package/dist/lib/css/property-descriptors/margin.js +0 -13
- package/dist/lib/css/property-descriptors/mix-blend-mode.js +0 -31
- package/dist/lib/css/property-descriptors/object-fit.js +0 -28
- package/dist/lib/css/property-descriptors/object-position.js +0 -42
- package/dist/lib/css/property-descriptors/opacity.js +0 -16
- package/dist/lib/css/property-descriptors/overflow-wrap.js +0 -18
- package/dist/lib/css/property-descriptors/overflow.js +0 -27
- package/dist/lib/css/property-descriptors/padding.js +0 -14
- package/dist/lib/css/property-descriptors/paint-order.js +0 -33
- package/dist/lib/css/property-descriptors/position.js +0 -22
- package/dist/lib/css/property-descriptors/quotes.js +0 -41
- package/dist/lib/css/property-descriptors/rotate.js +0 -27
- package/dist/lib/css/property-descriptors/text-align.js +0 -21
- package/dist/lib/css/property-descriptors/text-decoration-color.js +0 -10
- package/dist/lib/css/property-descriptors/text-decoration-line.js +0 -28
- package/dist/lib/css/property-descriptors/text-decoration-style.js +0 -24
- package/dist/lib/css/property-descriptors/text-decoration-thickness.js +0 -26
- package/dist/lib/css/property-descriptors/text-overflow.js +0 -18
- package/dist/lib/css/property-descriptors/text-shadow.js +0 -46
- package/dist/lib/css/property-descriptors/text-transform.js +0 -20
- package/dist/lib/css/property-descriptors/text-underline-offset.js +0 -23
- package/dist/lib/css/property-descriptors/transform-origin.js +0 -24
- package/dist/lib/css/property-descriptors/transform.js +0 -57
- package/dist/lib/css/property-descriptors/visibility.js +0 -20
- package/dist/lib/css/property-descriptors/webkit-line-clamp.js +0 -26
- package/dist/lib/css/property-descriptors/webkit-text-stroke-color.js +0 -10
- package/dist/lib/css/property-descriptors/webkit-text-stroke-width.js +0 -16
- package/dist/lib/css/property-descriptors/white-space.js +0 -32
- package/dist/lib/css/property-descriptors/word-break.js +0 -26
- package/dist/lib/css/property-descriptors/writing-mode.js +0 -28
- package/dist/lib/css/property-descriptors/z-index.js +0 -19
- package/dist/lib/css/property-descriptors/zoom.js +0 -18
- package/dist/lib/css/syntax/parser.js +0 -141
- package/dist/lib/css/syntax/token-constants.js +0 -214
- package/dist/lib/css/syntax/token-singletons.js +0 -36
- package/dist/lib/css/syntax/token-types.js +0 -10
- package/dist/lib/css/syntax/tokenizer.js +0 -502
- package/dist/lib/css/type-descriptor.js +0 -2
- package/dist/lib/css/types/angle.js +0 -80
- package/dist/lib/css/types/color-math.js +0 -25
- package/dist/lib/css/types/color-spaces/a98.js +0 -78
- package/dist/lib/css/types/color-spaces/p3.js +0 -86
- package/dist/lib/css/types/color-spaces/pro-photo.js +0 -83
- package/dist/lib/css/types/color-spaces/rec2020.js +0 -85
- package/dist/lib/css/types/color-spaces/srgb.js +0 -79
- package/dist/lib/css/types/color-utilities.js +0 -342
- package/dist/lib/css/types/color.js +0 -400
- package/dist/lib/css/types/functions/-prefix-linear-gradient.js +0 -32
- package/dist/lib/css/types/functions/-prefix-radial-gradient.js +0 -83
- package/dist/lib/css/types/functions/-webkit-gradient.js +0 -59
- package/dist/lib/css/types/functions/counter.js +0 -367
- package/dist/lib/css/types/functions/gradient.js +0 -163
- package/dist/lib/css/types/functions/linear-gradient.js +0 -27
- package/dist/lib/css/types/functions/radial-gradient.js +0 -90
- package/dist/lib/css/types/functions/repeating-linear-gradient.js +0 -9
- package/dist/lib/css/types/image.js +0 -62
- package/dist/lib/css/types/index.js +0 -2
- package/dist/lib/css/types/length-percentage.js +0 -197
- package/dist/lib/css/types/length.js +0 -5
- package/dist/lib/css/types/safe-eval.js +0 -80
- package/dist/lib/css/types/time.js +0 -17
- package/dist/lib/dom/document-cloner.js +0 -618
- package/dist/lib/dom/dom-normalizer.js +0 -115
- package/dist/lib/dom/element-container.js +0 -71
- package/dist/lib/dom/elements/li-element-container.js +0 -11
- package/dist/lib/dom/elements/ol-element-container.js +0 -12
- package/dist/lib/dom/elements/select-element-container.js +0 -12
- package/dist/lib/dom/elements/textarea-element-container.js +0 -11
- package/dist/lib/dom/node-parser.js +0 -125
- package/dist/lib/dom/node-type-guards.js +0 -81
- package/dist/lib/dom/replaced-elements/canvas-element-container.js +0 -13
- package/dist/lib/dom/replaced-elements/iframe-element-container.js +0 -38
- package/dist/lib/dom/replaced-elements/image-element-container.js +0 -14
- package/dist/lib/dom/replaced-elements/index.js +0 -2
- package/dist/lib/dom/replaced-elements/input-element-container.js +0 -89
- package/dist/lib/dom/replaced-elements/svg-element-container.js +0 -57
- package/dist/lib/dom/slot-cloner.js +0 -176
- package/dist/lib/dom/text-container.js +0 -35
- package/dist/lib/index.js +0 -49
- package/dist/lib/options.js +0 -2
- package/dist/lib/render/background.js +0 -188
- package/dist/lib/render/bezier-curve.js +0 -34
- package/dist/lib/render/border.js +0 -104
- package/dist/lib/render/bound-curves.js +0 -188
- package/dist/lib/render/box-sizing.js +0 -20
- package/dist/lib/render/canvas/background-renderer.js +0 -338
- package/dist/lib/render/canvas/border-image-renderer.js +0 -153
- package/dist/lib/render/canvas/border-renderer.js +0 -184
- package/dist/lib/render/canvas/box-shadow-geometry.js +0 -52
- package/dist/lib/render/canvas/box-shadow-painter.js +0 -194
- package/dist/lib/render/canvas/box-shadow-transform.js +0 -42
- package/dist/lib/render/canvas/canvas-path.js +0 -25
- package/dist/lib/render/canvas/canvas-renderer.js +0 -610
- package/dist/lib/render/canvas/content-renderer.js +0 -270
- package/dist/lib/render/canvas/effects-renderer.js +0 -171
- package/dist/lib/render/canvas/filter-surface.js +0 -270
- package/dist/lib/render/canvas/font-utils.js +0 -46
- package/dist/lib/render/canvas/foreignobject-renderer.js +0 -38
- package/dist/lib/render/canvas/surface-bounds.js +0 -64
- package/dist/lib/render/canvas/text/text-decoration-renderer.js +0 -99
- package/dist/lib/render/canvas/text-renderer.js +0 -486
- package/dist/lib/render/effects.js +0 -231
- package/dist/lib/render/font-metrics.js +0 -53
- package/dist/lib/render/object-fit.js +0 -91
- package/dist/lib/render/path.js +0 -26
- package/dist/lib/render/renderer-interface.js +0 -2
- package/dist/lib/render/stacking-context.js +0 -341
- package/dist/lib/render/vector.js +0 -16
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.renderElement = void 0;
|
|
4
|
-
const bounds_1 = require("../css/layout/bounds");
|
|
5
|
-
const color_1 = require("../css/types/color");
|
|
6
|
-
const document_cloner_1 = require("../dom/document-cloner");
|
|
7
|
-
const node_type_guards_1 = require("../dom/node-type-guards");
|
|
8
|
-
const node_parser_1 = require("../dom/node-parser");
|
|
9
|
-
const canvas_renderer_1 = require("../render/canvas/canvas-renderer");
|
|
10
|
-
const foreignobject_renderer_1 = require("../render/canvas/foreignobject-renderer");
|
|
11
|
-
const context_1 = require("./context");
|
|
12
|
-
const validator_1 = require("./validator");
|
|
13
|
-
const performance_monitor_1 = require("./performance-monitor");
|
|
14
|
-
const abort_helper_1 = require("./abort-helper");
|
|
15
|
-
const config_assembler_1 = require("./config-assembler");
|
|
16
|
-
const background_parser_1 = require("./background-parser");
|
|
17
|
-
const renderElement = async (element, opts, config) => {
|
|
18
|
-
(0, config_assembler_1.coerceNumberOptions)(opts);
|
|
19
|
-
// Input validation (unless explicitly skipped)
|
|
20
|
-
if (!opts.skipValidation) {
|
|
21
|
-
const validator = opts.validator || (0, validator_1.createDefaultValidator)();
|
|
22
|
-
const elementValidation = validator.validateElement(element);
|
|
23
|
-
if (!elementValidation.valid) {
|
|
24
|
-
throw new Error(elementValidation.error);
|
|
25
|
-
}
|
|
26
|
-
const optionsValidation = validator.validateOptions(opts);
|
|
27
|
-
if (!optionsValidation.valid) {
|
|
28
|
-
throw new Error(`Invalid options: ${optionsValidation.error}`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (!element || typeof element !== 'object') {
|
|
32
|
-
throw new Error('Invalid element provided as first argument');
|
|
33
|
-
}
|
|
34
|
-
const ownerDocument = element.ownerDocument;
|
|
35
|
-
if (!ownerDocument) {
|
|
36
|
-
throw new Error(`Element is not attached to a Document`);
|
|
37
|
-
}
|
|
38
|
-
const defaultView = ownerDocument.defaultView;
|
|
39
|
-
if (!defaultView) {
|
|
40
|
-
throw new Error(`Document is not attached to a Window`);
|
|
41
|
-
}
|
|
42
|
-
const resourceOptions = (0, config_assembler_1.assembleResourceOptions)(opts);
|
|
43
|
-
const contextOptions = (0, config_assembler_1.assembleContextOptions)(opts, config, resourceOptions);
|
|
44
|
-
const windowOptions = (0, config_assembler_1.assembleWindowOptions)(opts, defaultView);
|
|
45
|
-
const windowBounds = new bounds_1.Bounds(windowOptions.scrollX, windowOptions.scrollY, windowOptions.windowWidth, windowOptions.windowHeight);
|
|
46
|
-
const context = new context_1.Context(contextOptions, windowBounds, config);
|
|
47
|
-
const performanceMonitoring = opts.enablePerformanceMonitoring ?? opts.logging ?? false;
|
|
48
|
-
const perfMonitor = new performance_monitor_1.PerformanceMonitor(context, performanceMonitoring);
|
|
49
|
-
perfMonitor.start('total', {
|
|
50
|
-
width: windowOptions.windowWidth,
|
|
51
|
-
height: windowOptions.windowHeight
|
|
52
|
-
});
|
|
53
|
-
const signal = opts.signal;
|
|
54
|
-
(0, abort_helper_1.throwIfAborted)(signal);
|
|
55
|
-
const foreignObjectRendering = opts.foreignObjectRendering ?? false;
|
|
56
|
-
const cloneOptions = (0, config_assembler_1.assembleCloneOptions)(opts, config, foreignObjectRendering);
|
|
57
|
-
context.logger.debug(`Starting document clone with size ${windowBounds.width}x${windowBounds.height} scrolled to ${-windowBounds.left},${-windowBounds.top}`);
|
|
58
|
-
perfMonitor.start('clone');
|
|
59
|
-
const documentCloner = new document_cloner_1.DocumentCloner(context, element, cloneOptions);
|
|
60
|
-
const clonedElement = documentCloner.clonedReferenceElement;
|
|
61
|
-
if (!clonedElement) {
|
|
62
|
-
throw new Error('Unable to find element in cloned iframe');
|
|
63
|
-
}
|
|
64
|
-
const container = await documentCloner.toIFrame(ownerDocument, windowBounds);
|
|
65
|
-
perfMonitor.end('clone');
|
|
66
|
-
if (signal?.aborted) {
|
|
67
|
-
if (opts.removeContainer ?? true) {
|
|
68
|
-
document_cloner_1.DocumentCloner.destroy(container);
|
|
69
|
-
}
|
|
70
|
-
(0, abort_helper_1.throwIfAborted)(signal);
|
|
71
|
-
}
|
|
72
|
-
const { width, height, left, top } = (0, node_type_guards_1.isBodyElement)(clonedElement) || (0, node_type_guards_1.isHTMLElement)(clonedElement)
|
|
73
|
-
? (0, bounds_1.parseDocumentSize)(clonedElement.ownerDocument)
|
|
74
|
-
: (0, bounds_1.parseBounds)(context, clonedElement);
|
|
75
|
-
const backgroundColor = (0, background_parser_1.parseBackgroundColor)(context, clonedElement, opts.backgroundColor);
|
|
76
|
-
const renderOptions = (0, config_assembler_1.assembleRenderOptions)(opts, backgroundColor, left, top, width, height, defaultView.devicePixelRatio ?? 1);
|
|
77
|
-
let canvas;
|
|
78
|
-
let root;
|
|
79
|
-
try {
|
|
80
|
-
if (foreignObjectRendering) {
|
|
81
|
-
context.logger.debug(`Document cloned, using foreign object rendering`);
|
|
82
|
-
perfMonitor.start('render-foreignobject');
|
|
83
|
-
const renderer = new foreignobject_renderer_1.ForeignObjectRenderer(context, renderOptions);
|
|
84
|
-
canvas = await renderer.render(clonedElement);
|
|
85
|
-
perfMonitor.end('render-foreignobject');
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
context.logger.debug(`Document cloned, element located at ${left},${top} with size ${width}x${height} using computed rendering`);
|
|
89
|
-
context.logger.debug(`Starting DOM parsing`);
|
|
90
|
-
perfMonitor.start('parse');
|
|
91
|
-
(0, abort_helper_1.throwIfAborted)(signal);
|
|
92
|
-
// Enter defer mode: collect all image URLs during parse without
|
|
93
|
-
// starting individual loads. This avoids serialised loading in
|
|
94
|
-
// DOM-traversal order.
|
|
95
|
-
context.cache.startDefer();
|
|
96
|
-
root = (0, node_parser_1.parseTree)(context, clonedElement);
|
|
97
|
-
perfMonitor.end('parse');
|
|
98
|
-
// Batch-preload all collected images in parallel before rendering.
|
|
99
|
-
perfMonitor.start('preload');
|
|
100
|
-
await context.cache.preloadAll();
|
|
101
|
-
perfMonitor.end('preload');
|
|
102
|
-
if (backgroundColor === root.styles.backgroundColor) {
|
|
103
|
-
root.styles.backgroundColor = color_1.COLORS.TRANSPARENT;
|
|
104
|
-
}
|
|
105
|
-
context.logger.debug(`Starting renderer for element at ${renderOptions.x},${renderOptions.y} with size ${renderOptions.width}x${renderOptions.height}`);
|
|
106
|
-
perfMonitor.start('render');
|
|
107
|
-
(0, abort_helper_1.throwIfAborted)(signal);
|
|
108
|
-
const renderer = new canvas_renderer_1.CanvasRenderer(context, renderOptions);
|
|
109
|
-
canvas = await renderer.render(root);
|
|
110
|
-
perfMonitor.end('render');
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
finally {
|
|
114
|
-
perfMonitor.start('cleanup');
|
|
115
|
-
try {
|
|
116
|
-
if (root)
|
|
117
|
-
root.restoreTree();
|
|
118
|
-
}
|
|
119
|
-
finally {
|
|
120
|
-
if (opts.removeContainer ?? true)
|
|
121
|
-
document_cloner_1.DocumentCloner.destroy(container);
|
|
122
|
-
perfMonitor.end('cleanup');
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
perfMonitor.end('total');
|
|
126
|
-
context.logger.debug(`Finished rendering`);
|
|
127
|
-
if (performanceMonitoring)
|
|
128
|
-
perfMonitor.logSummary();
|
|
129
|
-
return canvas;
|
|
130
|
-
};
|
|
131
|
-
exports.renderElement = renderElement;
|
package/dist/lib/core/util.js
DELETED
|
@@ -1,500 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Input Validator
|
|
4
|
-
*
|
|
5
|
-
* Provides validation and sanitization for user inputs to prevent security vulnerabilities
|
|
6
|
-
* including SSRF, XSS, and injection attacks.
|
|
7
|
-
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.Validator = void 0;
|
|
10
|
-
exports.createDefaultValidator = createDefaultValidator;
|
|
11
|
-
exports.createStrictValidator = createStrictValidator;
|
|
12
|
-
/**
|
|
13
|
-
* Input Validator
|
|
14
|
-
*
|
|
15
|
-
* Validates and sanitizes user inputs for security and correctness.
|
|
16
|
-
*/
|
|
17
|
-
class Validator {
|
|
18
|
-
constructor(config = {}) {
|
|
19
|
-
this.config = {
|
|
20
|
-
maxImageTimeout: 300000, // 5 minutes default
|
|
21
|
-
allowDataUrls: true,
|
|
22
|
-
...config
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Validate a URL
|
|
27
|
-
*
|
|
28
|
-
* @param url - URL to validate
|
|
29
|
-
* @param context - Context for validation (e.g., 'proxy', 'image')
|
|
30
|
-
* @returns Validation result
|
|
31
|
-
*/
|
|
32
|
-
validateUrl(url, context = 'general') {
|
|
33
|
-
if (!url || typeof url !== 'string') {
|
|
34
|
-
return {
|
|
35
|
-
valid: false,
|
|
36
|
-
error: 'URL must be a non-empty string'
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
// Check for data URLs
|
|
40
|
-
if (url.startsWith('data:')) {
|
|
41
|
-
if (!this.config.allowDataUrls) {
|
|
42
|
-
return {
|
|
43
|
-
valid: false,
|
|
44
|
-
error: 'Data URLs are not allowed'
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
return { valid: true, sanitized: url };
|
|
48
|
-
}
|
|
49
|
-
// Check for blob URLs
|
|
50
|
-
if (url.startsWith('blob:')) {
|
|
51
|
-
return { valid: true, sanitized: url };
|
|
52
|
-
}
|
|
53
|
-
// Validate URL format
|
|
54
|
-
try {
|
|
55
|
-
const parsedUrl = new URL(url);
|
|
56
|
-
// Only allow http and https protocols
|
|
57
|
-
if (!['http:', 'https:'].includes(parsedUrl.protocol)) {
|
|
58
|
-
return {
|
|
59
|
-
valid: false,
|
|
60
|
-
error: `Protocol ${parsedUrl.protocol} is not allowed. Only http and https are permitted.`
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
// For proxy URLs, check domain whitelist
|
|
64
|
-
if (context === 'proxy' && this.config.allowedProxyDomains && this.config.allowedProxyDomains.length > 0) {
|
|
65
|
-
const hostname = parsedUrl.hostname.toLowerCase();
|
|
66
|
-
const isAllowed = this.config.allowedProxyDomains.some((domain) => {
|
|
67
|
-
const normalizedDomain = domain.toLowerCase();
|
|
68
|
-
return hostname === normalizedDomain || hostname.endsWith('.' + normalizedDomain);
|
|
69
|
-
});
|
|
70
|
-
if (!isAllowed) {
|
|
71
|
-
return {
|
|
72
|
-
valid: false,
|
|
73
|
-
error: `Proxy domain ${parsedUrl.hostname} is not in the allowed list`
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
// Check for localhost/private IPs to prevent SSRF (skip when allowLocalhostProxy for dev/test)
|
|
78
|
-
if (context === 'proxy') {
|
|
79
|
-
if (!this.config.allowLocalhostProxy) {
|
|
80
|
-
const hostname = parsedUrl.hostname.toLowerCase();
|
|
81
|
-
// Check for localhost
|
|
82
|
-
if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1') {
|
|
83
|
-
return {
|
|
84
|
-
valid: false,
|
|
85
|
-
error: 'Localhost is not allowed for proxy URLs'
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
// For private IP ranges (simplified check)
|
|
89
|
-
if (this.isPrivateIP(hostname)) {
|
|
90
|
-
return {
|
|
91
|
-
valid: false,
|
|
92
|
-
error: 'Private IP addresses are not allowed for proxy URLs'
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
// For link-local addresses
|
|
96
|
-
if (hostname.startsWith('169.254.') || hostname.startsWith('fe80:')) {
|
|
97
|
-
return {
|
|
98
|
-
valid: false,
|
|
99
|
-
error: 'Link-local addresses are not allowed for proxy URLs'
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
// For proxy URLs, mark that runtime validation is recommended
|
|
104
|
-
// to prevent DNS rebinding attacks
|
|
105
|
-
return {
|
|
106
|
-
valid: true,
|
|
107
|
-
sanitized: url,
|
|
108
|
-
requiresRuntimeCheck: true
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
return { valid: true, sanitized: url };
|
|
112
|
-
}
|
|
113
|
-
catch (e) {
|
|
114
|
-
return {
|
|
115
|
-
valid: false,
|
|
116
|
-
error: `Invalid URL format: ${e instanceof Error ? e.message : 'Unknown error'}`
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Check if a hostname is a private IP address
|
|
122
|
-
*/
|
|
123
|
-
isPrivateIP(hostname) {
|
|
124
|
-
// IPv4 private ranges
|
|
125
|
-
const privateIPv4Patterns = [
|
|
126
|
-
/^0\./, // 0.0.0.0/8 (This network)
|
|
127
|
-
/^10\./, // 10.0.0.0/8 (Private)
|
|
128
|
-
/^100\.(6[4-9]|[7-9][0-9]|1[0-1][0-9]|12[0-7])\./, // 100.64.0.0/10 (CGNAT)
|
|
129
|
-
/^127\./, // 127.0.0.0/8 (Loopback)
|
|
130
|
-
/^169\.254\./, // 169.254.0.0/16 (Link-local)
|
|
131
|
-
/^172\.(1[6-9]|2[0-9]|3[0-1])\./, // 172.16.0.0/12 (Private)
|
|
132
|
-
/^192\.0\.0\./, // 192.0.0.0/24 (IETF Protocol Assignments)
|
|
133
|
-
/^192\.0\.2\./, // 192.0.2.0/24 (TEST-NET-1)
|
|
134
|
-
/^192\.168\./, // 192.168.0.0/16 (Private)
|
|
135
|
-
/^198\.(1[8-9])\./, // 198.18.0.0/15 (Network benchmark)
|
|
136
|
-
/^198\.51\.100\./, // 198.51.100.0/24 (TEST-NET-2)
|
|
137
|
-
/^203\.0\.113\./, // 203.0.113.0/24 (TEST-NET-3)
|
|
138
|
-
/^2(2[4-9]|3[0-9])\./, // 224.0.0.0/4 (Multicast)
|
|
139
|
-
/^24[0-9]\./, // 240.0.0.0/4 (Reserved)
|
|
140
|
-
/^255\.255\.255\.255$/ // 255.255.255.255/32 (Broadcast)
|
|
141
|
-
];
|
|
142
|
-
// Check IPv4
|
|
143
|
-
if (privateIPv4Patterns.some((pattern) => pattern.test(hostname))) {
|
|
144
|
-
return true;
|
|
145
|
-
}
|
|
146
|
-
// IPv6 private ranges and special addresses
|
|
147
|
-
if (hostname.includes(':')) {
|
|
148
|
-
return this.isPrivateIPv6(hostname);
|
|
149
|
-
}
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Check if an IPv6 address is private or special
|
|
154
|
-
* Handles compressed IPv6 addresses (e.g., ::1, fc00::1)
|
|
155
|
-
*/
|
|
156
|
-
isPrivateIPv6(hostname) {
|
|
157
|
-
const normalizedHost = hostname.toLowerCase().trim();
|
|
158
|
-
// Remove square brackets if present (e.g., [::1])
|
|
159
|
-
const addr = normalizedHost.replace(/^\[|\]$/g, '');
|
|
160
|
-
// Remove zone ID if present (e.g., fe80::1%eth0)
|
|
161
|
-
const addrWithoutZone = addr.split('%')[0];
|
|
162
|
-
// Loopback ::1 (also matches 0:0:0:0:0:0:0:1)
|
|
163
|
-
if (/^(0:){7}1$/.test(addrWithoutZone) || addrWithoutZone === '::1') {
|
|
164
|
-
return true;
|
|
165
|
-
}
|
|
166
|
-
// Unspecified address :: (also matches 0:0:0:0:0:0:0:0)
|
|
167
|
-
if (/^(0:){7}0$/.test(addrWithoutZone) || addrWithoutZone === '::') {
|
|
168
|
-
return true;
|
|
169
|
-
}
|
|
170
|
-
// Expand :: compression to check prefixes
|
|
171
|
-
// This handles cases like fc00::1, fe80::, etc.
|
|
172
|
-
const expandedAddr = this.expandIPv6(addrWithoutZone);
|
|
173
|
-
if (!expandedAddr) {
|
|
174
|
-
// If we can't expand it, fall back to prefix matching
|
|
175
|
-
return this.isPrivateIPv6Prefix(addrWithoutZone);
|
|
176
|
-
}
|
|
177
|
-
// fc00::/7 (Unique Local Address)
|
|
178
|
-
// Check if first byte is in range fc00-fdff
|
|
179
|
-
const firstByte = parseInt(expandedAddr.substring(0, 2), 16);
|
|
180
|
-
if (firstByte >= 0xfc && firstByte <= 0xfd) {
|
|
181
|
-
return true;
|
|
182
|
-
}
|
|
183
|
-
// fe80::/10 (Link-local)
|
|
184
|
-
// First 10 bits should be 1111 1110 10
|
|
185
|
-
if (firstByte === 0xfe) {
|
|
186
|
-
const secondByte = parseInt(expandedAddr.substring(2, 4), 16);
|
|
187
|
-
// Check if bits 11-12 are 10 (0x80-0xbf)
|
|
188
|
-
if (secondByte >= 0x80 && secondByte <= 0xbf) {
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
// ff00::/8 (Multicast)
|
|
193
|
-
if (firstByte === 0xff) {
|
|
194
|
-
return true;
|
|
195
|
-
}
|
|
196
|
-
return false;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Expand compressed IPv6 address to full form
|
|
200
|
-
* e.g., "::1" -> "0000:0000:0000:0000:0000:0000:0000:0001"
|
|
201
|
-
*/
|
|
202
|
-
expandIPv6(addr) {
|
|
203
|
-
try {
|
|
204
|
-
// Handle :: compression
|
|
205
|
-
if (addr.includes('::')) {
|
|
206
|
-
const parts = addr.split('::');
|
|
207
|
-
if (parts.length > 2) {
|
|
208
|
-
return null; // Invalid: more than one ::
|
|
209
|
-
}
|
|
210
|
-
const leftParts = parts[0] ? parts[0].split(':') : [];
|
|
211
|
-
const rightParts = parts[1] ? parts[1].split(':') : [];
|
|
212
|
-
const missingParts = 8 - leftParts.length - rightParts.length;
|
|
213
|
-
if (missingParts < 0) {
|
|
214
|
-
return null; // Invalid
|
|
215
|
-
}
|
|
216
|
-
const middleParts = Array(missingParts).fill('0000');
|
|
217
|
-
const allParts = [...leftParts, ...middleParts, ...rightParts];
|
|
218
|
-
return allParts.map((p) => p.padStart(4, '0')).join(':');
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
// No compression, just normalize
|
|
222
|
-
const parts = addr.split(':');
|
|
223
|
-
if (parts.length !== 8) {
|
|
224
|
-
return null; // Invalid
|
|
225
|
-
}
|
|
226
|
-
return parts.map((p) => p.padStart(4, '0')).join(':');
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
catch {
|
|
230
|
-
return null;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Fallback prefix matching for IPv6 when expansion fails
|
|
235
|
-
*/
|
|
236
|
-
isPrivateIPv6Prefix(addr) {
|
|
237
|
-
// fc00::/7 (Unique Local Address)
|
|
238
|
-
if (/^fc[0-9a-f]{0,2}:?/i.test(addr) || /^fd[0-9a-f]{0,2}:?/i.test(addr)) {
|
|
239
|
-
return true;
|
|
240
|
-
}
|
|
241
|
-
// fe80::/10 (Link-local)
|
|
242
|
-
if (/^fe[89ab][0-9a-f]:?/i.test(addr)) {
|
|
243
|
-
return true;
|
|
244
|
-
}
|
|
245
|
-
// ff00::/8 (Multicast)
|
|
246
|
-
if (/^ff[0-9a-f]{0,2}:?/i.test(addr)) {
|
|
247
|
-
return true;
|
|
248
|
-
}
|
|
249
|
-
return false;
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Validate CSP nonce
|
|
253
|
-
*
|
|
254
|
-
* @param nonce - CSP nonce to validate
|
|
255
|
-
* @returns Validation result
|
|
256
|
-
*/
|
|
257
|
-
validateCspNonce(nonce) {
|
|
258
|
-
if (!nonce || typeof nonce !== 'string') {
|
|
259
|
-
return {
|
|
260
|
-
valid: false,
|
|
261
|
-
error: 'CSP nonce must be a non-empty string'
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
// Basic format validation - nonce should be base64-like
|
|
265
|
-
// Typical format: base64 string, often 32+ characters
|
|
266
|
-
if (nonce.length < 16) {
|
|
267
|
-
return {
|
|
268
|
-
valid: false,
|
|
269
|
-
error: 'CSP nonce is too short (minimum 16 characters recommended)'
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
// Check for suspicious characters
|
|
273
|
-
if (!/^[A-Za-z0-9+/=_-]+$/.test(nonce)) {
|
|
274
|
-
return {
|
|
275
|
-
valid: false,
|
|
276
|
-
error: 'CSP nonce contains invalid characters'
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
return { valid: true, sanitized: nonce };
|
|
280
|
-
}
|
|
281
|
-
/**
|
|
282
|
-
* Validate image timeout
|
|
283
|
-
*
|
|
284
|
-
* @param timeout - Timeout in milliseconds
|
|
285
|
-
* @returns Validation result
|
|
286
|
-
*/
|
|
287
|
-
validateImageTimeout(timeout) {
|
|
288
|
-
if (typeof timeout !== 'number' || isNaN(timeout)) {
|
|
289
|
-
return {
|
|
290
|
-
valid: false,
|
|
291
|
-
error: 'Image timeout must be a number'
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
if (timeout < 0) {
|
|
295
|
-
return {
|
|
296
|
-
valid: false,
|
|
297
|
-
error: 'Image timeout cannot be negative'
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
if (this.config.maxImageTimeout && timeout > this.config.maxImageTimeout) {
|
|
301
|
-
return {
|
|
302
|
-
valid: false,
|
|
303
|
-
error: `Image timeout ${timeout}ms exceeds maximum allowed ${this.config.maxImageTimeout}ms`
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
return { valid: true, sanitized: timeout };
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* Validate window dimensions
|
|
310
|
-
*
|
|
311
|
-
* @param width - Window width
|
|
312
|
-
* @param height - Window height
|
|
313
|
-
* @returns Validation result
|
|
314
|
-
*/
|
|
315
|
-
validateDimensions(width, height) {
|
|
316
|
-
if (typeof width !== 'number' || typeof height !== 'number') {
|
|
317
|
-
return {
|
|
318
|
-
valid: false,
|
|
319
|
-
error: 'Dimensions must be numbers'
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
if (isNaN(width) || isNaN(height)) {
|
|
323
|
-
return {
|
|
324
|
-
valid: false,
|
|
325
|
-
error: 'Dimensions cannot be NaN'
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
if (width <= 0 || height <= 0) {
|
|
329
|
-
return {
|
|
330
|
-
valid: false,
|
|
331
|
-
error: 'Dimensions must be positive'
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
// Reasonable maximum to prevent memory issues
|
|
335
|
-
const MAX_DIMENSION = 32767; // Common canvas limit
|
|
336
|
-
if (width > MAX_DIMENSION || height > MAX_DIMENSION) {
|
|
337
|
-
return {
|
|
338
|
-
valid: false,
|
|
339
|
-
error: `Dimensions exceed maximum allowed (${MAX_DIMENSION}px)`
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
return { valid: true, sanitized: { width, height } };
|
|
343
|
-
}
|
|
344
|
-
/**
|
|
345
|
-
* Validate scale factor
|
|
346
|
-
*
|
|
347
|
-
* @param scale - Scale factor
|
|
348
|
-
* @returns Validation result
|
|
349
|
-
*/
|
|
350
|
-
validateScale(scale) {
|
|
351
|
-
if (typeof scale !== 'number' || isNaN(scale)) {
|
|
352
|
-
return {
|
|
353
|
-
valid: false,
|
|
354
|
-
error: 'Scale must be a number'
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
if (scale <= 0) {
|
|
358
|
-
return {
|
|
359
|
-
valid: false,
|
|
360
|
-
error: 'Scale must be positive'
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
// Reasonable scale limits
|
|
364
|
-
if (scale > 10) {
|
|
365
|
-
return {
|
|
366
|
-
valid: false,
|
|
367
|
-
error: 'Scale factor too large (maximum 10x)'
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
return { valid: true, sanitized: scale };
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* Validate HTML element
|
|
374
|
-
*
|
|
375
|
-
* @param element - Element to validate
|
|
376
|
-
* @returns Validation result
|
|
377
|
-
*/
|
|
378
|
-
validateElement(element) {
|
|
379
|
-
if (!element) {
|
|
380
|
-
return {
|
|
381
|
-
valid: false,
|
|
382
|
-
error: 'Element is required'
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
if (typeof element !== 'object') {
|
|
386
|
-
return {
|
|
387
|
-
valid: false,
|
|
388
|
-
error: 'Element must be an object'
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
// Accept real HTMLElement, or any element-like object with the minimal shape
|
|
392
|
-
// required by the implementation (ownerDocument + defaultView) for backward
|
|
393
|
-
// compatibility and test environments.
|
|
394
|
-
const el = element;
|
|
395
|
-
if (typeof HTMLElement !== 'undefined' && element instanceof HTMLElement) {
|
|
396
|
-
// Real DOM element
|
|
397
|
-
if (!element.ownerDocument) {
|
|
398
|
-
return { valid: false, error: 'Element must be attached to a document' };
|
|
399
|
-
}
|
|
400
|
-
return { valid: true };
|
|
401
|
-
}
|
|
402
|
-
// Duck-typing: accept object with ownerDocument and defaultView (minimal contract)
|
|
403
|
-
if (!el.ownerDocument) {
|
|
404
|
-
return {
|
|
405
|
-
valid: false,
|
|
406
|
-
error: 'Element must be attached to a document (ownerDocument required)'
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
if (!el.ownerDocument.defaultView) {
|
|
410
|
-
return {
|
|
411
|
-
valid: false,
|
|
412
|
-
error: 'Document must be attached to a window (ownerDocument.defaultView required)'
|
|
413
|
-
};
|
|
414
|
-
}
|
|
415
|
-
return { valid: true };
|
|
416
|
-
}
|
|
417
|
-
/**
|
|
418
|
-
* Validate entire options object
|
|
419
|
-
*
|
|
420
|
-
* @param options - Options to validate
|
|
421
|
-
* @returns Validation result with all errors
|
|
422
|
-
*/
|
|
423
|
-
validateOptions(options) {
|
|
424
|
-
const errors = [];
|
|
425
|
-
const proxyUrl = options.proxy;
|
|
426
|
-
if (proxyUrl !== undefined && proxyUrl !== null && typeof proxyUrl === 'string' && proxyUrl.length > 0) {
|
|
427
|
-
const proxyResult = this.validateUrl(proxyUrl, 'proxy');
|
|
428
|
-
if (!proxyResult.valid) {
|
|
429
|
-
errors.push(`Proxy: ${proxyResult.error}`);
|
|
430
|
-
}
|
|
431
|
-
// Note: Proxy URLs are marked with requiresRuntimeCheck to prevent DNS rebinding
|
|
432
|
-
// Consider implementing runtime IP validation in production environments
|
|
433
|
-
}
|
|
434
|
-
// Validate image timeout
|
|
435
|
-
if (options.imageTimeout !== undefined) {
|
|
436
|
-
const timeoutResult = this.validateImageTimeout(options.imageTimeout);
|
|
437
|
-
if (!timeoutResult.valid) {
|
|
438
|
-
errors.push(`Image timeout: ${timeoutResult.error}`);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
// Validate dimensions
|
|
442
|
-
if (options.width !== undefined || options.height !== undefined) {
|
|
443
|
-
const width = options.width ?? 800;
|
|
444
|
-
const height = options.height ?? 600;
|
|
445
|
-
const dimensionsResult = this.validateDimensions(width, height);
|
|
446
|
-
if (!dimensionsResult.valid) {
|
|
447
|
-
errors.push(`Dimensions: ${dimensionsResult.error}`);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
// Validate scale
|
|
451
|
-
if (options.scale !== undefined) {
|
|
452
|
-
const scaleResult = this.validateScale(options.scale);
|
|
453
|
-
if (!scaleResult.valid) {
|
|
454
|
-
errors.push(`Scale: ${scaleResult.error}`);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
// Validate CSP nonce
|
|
458
|
-
if (options.cspNonce !== undefined) {
|
|
459
|
-
const nonceResult = this.validateCspNonce(options.cspNonce);
|
|
460
|
-
if (!nonceResult.valid) {
|
|
461
|
-
errors.push(`CSP nonce: ${nonceResult.error}`);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
// Custom validation
|
|
465
|
-
if (this.config.customValidator) {
|
|
466
|
-
const customResult = this.config.customValidator(options, 'options');
|
|
467
|
-
if (!customResult.valid) {
|
|
468
|
-
errors.push(`Custom validation: ${customResult.error}`);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
if (errors.length > 0) {
|
|
472
|
-
return {
|
|
473
|
-
valid: false,
|
|
474
|
-
error: errors.join('; ')
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
return { valid: true };
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
exports.Validator = Validator;
|
|
481
|
-
/**
|
|
482
|
-
* Create a default validator instance
|
|
483
|
-
*/
|
|
484
|
-
function createDefaultValidator(config = {}) {
|
|
485
|
-
return new Validator({
|
|
486
|
-
allowDataUrls: true,
|
|
487
|
-
maxImageTimeout: 300000, // 5 minutes
|
|
488
|
-
...config
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
/**
|
|
492
|
-
* Create a strict validator with security-focused settings
|
|
493
|
-
*/
|
|
494
|
-
function createStrictValidator(allowedProxyDomains) {
|
|
495
|
-
return new Validator({
|
|
496
|
-
allowedProxyDomains,
|
|
497
|
-
allowDataUrls: false,
|
|
498
|
-
maxImageTimeout: 60000 // 1 minute
|
|
499
|
-
});
|
|
500
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BackgroundStyles = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* Read-only grouped accessor for background-related CSS properties.
|
|
6
|
-
*/
|
|
7
|
-
class BackgroundStyles {
|
|
8
|
-
constructor(styles) {
|
|
9
|
-
this.styles = styles;
|
|
10
|
-
}
|
|
11
|
-
get color() {
|
|
12
|
-
return this.styles.backgroundColor;
|
|
13
|
-
}
|
|
14
|
-
get image() {
|
|
15
|
-
return this.styles.backgroundImage;
|
|
16
|
-
}
|
|
17
|
-
get clip() {
|
|
18
|
-
return this.styles.backgroundClip;
|
|
19
|
-
}
|
|
20
|
-
get origin() {
|
|
21
|
-
return this.styles.backgroundOrigin;
|
|
22
|
-
}
|
|
23
|
-
get position() {
|
|
24
|
-
return this.styles.backgroundPosition;
|
|
25
|
-
}
|
|
26
|
-
get repeat() {
|
|
27
|
-
return this.styles.backgroundRepeat;
|
|
28
|
-
}
|
|
29
|
-
get size() {
|
|
30
|
-
return this.styles.backgroundSize;
|
|
31
|
-
}
|
|
32
|
-
get blendMode() {
|
|
33
|
-
return this.styles.backgroundBlendMode;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
exports.BackgroundStyles = BackgroundStyles;
|