@autumnsgrove/groveengine 0.6.1 → 0.6.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/dist/auth/jwt.d.ts +10 -4
- package/dist/auth/jwt.js +18 -4
- package/dist/auth/session.d.ts +22 -15
- package/dist/auth/session.js +35 -16
- package/dist/components/admin/GutterManager.svelte +81 -139
- package/dist/components/admin/GutterManager.svelte.d.ts +6 -6
- package/dist/components/admin/MarkdownEditor.svelte +80 -23
- package/dist/components/admin/MarkdownEditor.svelte.d.ts +14 -8
- package/dist/components/admin/composables/useAmbientSounds.svelte.d.ts +52 -2
- package/dist/components/admin/composables/useAmbientSounds.svelte.js +38 -4
- package/dist/components/admin/composables/useCommandPalette.svelte.d.ts +80 -10
- package/dist/components/admin/composables/useCommandPalette.svelte.js +45 -5
- package/dist/components/admin/composables/useDraftManager.svelte.d.ts +76 -14
- package/dist/components/admin/composables/useDraftManager.svelte.js +44 -10
- package/dist/components/admin/composables/useEditorTheme.svelte.d.ts +168 -2
- package/dist/components/admin/composables/useEditorTheme.svelte.js +40 -7
- package/dist/components/admin/composables/useSlashCommands.svelte.d.ts +94 -22
- package/dist/components/admin/composables/useSlashCommands.svelte.js +58 -9
- package/dist/components/admin/composables/useSnippets.svelte.d.ts +51 -2
- package/dist/components/admin/composables/useSnippets.svelte.js +35 -3
- package/dist/components/admin/composables/useWritingSession.svelte.d.ts +64 -6
- package/dist/components/admin/composables/useWritingSession.svelte.js +42 -5
- package/dist/components/custom/ContentWithGutter.svelte +53 -23
- package/dist/components/custom/ContentWithGutter.svelte.d.ts +6 -14
- package/dist/components/custom/GutterItem.svelte +1 -1
- package/dist/components/custom/LeftGutter.svelte +43 -13
- package/dist/components/custom/LeftGutter.svelte.d.ts +6 -6
- package/dist/config/ai-models.js +1 -1
- package/dist/groveauth/client.js +11 -11
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -2
- package/dist/server/logger.d.ts +74 -26
- package/dist/server/logger.js +133 -184
- package/dist/server/services/cache.js +1 -10
- package/dist/ui/components/charts/ActivityOverview.svelte +14 -3
- package/dist/ui/components/charts/ActivityOverview.svelte.d.ts +10 -7
- package/dist/ui/components/charts/RepoBreakdown.svelte +9 -3
- package/dist/ui/components/charts/RepoBreakdown.svelte.d.ts +12 -11
- package/dist/ui/components/charts/Sparkline.svelte +18 -7
- package/dist/ui/components/charts/Sparkline.svelte.d.ts +21 -2
- package/dist/ui/components/gallery/ImageGallery.svelte +12 -8
- package/dist/ui/components/gallery/ImageGallery.svelte.d.ts +2 -2
- package/dist/ui/components/gallery/Lightbox.svelte +5 -2
- package/dist/ui/components/gallery/ZoomableImage.svelte +8 -5
- package/dist/ui/components/primitives/accordion/index.d.ts +1 -1
- package/dist/ui/components/primitives/input/input.svelte.d.ts +1 -1
- package/dist/ui/components/primitives/tabs/index.d.ts +1 -1
- package/dist/ui/components/primitives/textarea/textarea.svelte.d.ts +1 -1
- package/dist/ui/components/ui/Button.svelte +5 -0
- package/dist/ui/components/ui/Button.svelte.d.ts +4 -1
- package/dist/ui/components/ui/Input.svelte +4 -0
- package/dist/ui/components/ui/Input.svelte.d.ts +3 -1
- package/dist/ui/components/ui/Logo.svelte +86 -0
- package/dist/ui/components/ui/Logo.svelte.d.ts +25 -0
- package/dist/ui/components/ui/LogoLoader.svelte +71 -0
- package/dist/ui/components/ui/LogoLoader.svelte.d.ts +9 -0
- package/dist/ui/components/ui/index.d.ts +2 -0
- package/dist/ui/components/ui/index.js +2 -0
- package/dist/ui/tailwind.preset.js +8 -8
- package/dist/utils/api.js +2 -1
- package/dist/utils/debounce.d.ts +4 -3
- package/dist/utils/debounce.js +10 -6
- package/dist/utils/gallery.d.ts +58 -32
- package/dist/utils/gallery.js +111 -129
- package/dist/utils/gutter.d.ts +47 -26
- package/dist/utils/gutter.js +116 -124
- package/dist/utils/imageProcessor.d.ts +66 -19
- package/dist/utils/imageProcessor.js +31 -10
- package/dist/utils/index.d.ts +11 -11
- package/dist/utils/index.js +4 -3
- package/dist/utils/json.js +1 -1
- package/dist/utils/markdown.d.ts +183 -103
- package/dist/utils/markdown.js +517 -678
- package/dist/utils/sanitize.d.ts +22 -12
- package/dist/utils/sanitize.js +268 -282
- package/dist/utils/validation.js +4 -3
- package/package.json +4 -3
package/dist/utils/sanitize.d.ts
CHANGED
|
@@ -1,25 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized sanitization utilities for XSS prevention
|
|
3
|
+
*
|
|
4
|
+
* Uses DOMPurify for client-side sanitization. On the server (SSR),
|
|
5
|
+
* content is passed through unsanitized since it will be sanitized
|
|
6
|
+
* when the page hydrates on the client.
|
|
7
|
+
*
|
|
8
|
+
* This approach avoids bundling jsdom (required by isomorphic-dompurify)
|
|
9
|
+
* which doesn't work in Cloudflare Workers.
|
|
10
|
+
*/
|
|
1
11
|
/**
|
|
2
12
|
* Sanitize HTML content to prevent XSS attacks
|
|
3
|
-
* @param
|
|
4
|
-
* @returns
|
|
13
|
+
* @param html - Raw HTML string to sanitize
|
|
14
|
+
* @returns Sanitized HTML safe for rendering
|
|
5
15
|
*/
|
|
6
|
-
export function sanitizeHTML(html: string): string;
|
|
16
|
+
export declare function sanitizeHTML(html: string): string;
|
|
7
17
|
/**
|
|
8
18
|
* Sanitize SVG content specifically (stricter rules for SVG)
|
|
9
|
-
* @param
|
|
10
|
-
* @returns
|
|
19
|
+
* @param svg - Raw SVG string to sanitize
|
|
20
|
+
* @returns Sanitized SVG safe for rendering
|
|
11
21
|
*/
|
|
12
|
-
export function sanitizeSVG(svg: string): string;
|
|
22
|
+
export declare function sanitizeSVG(svg: string): string;
|
|
13
23
|
/**
|
|
14
24
|
* Sanitize markdown-generated HTML with appropriate security rules
|
|
15
25
|
* This is a convenience wrapper for sanitizeHTML with markdown-specific settings
|
|
16
|
-
* @param
|
|
17
|
-
* @returns
|
|
26
|
+
* @param markdownHTML - HTML generated from markdown parsing
|
|
27
|
+
* @returns Sanitized HTML safe for rendering
|
|
18
28
|
*/
|
|
19
|
-
export function sanitizeMarkdown(markdownHTML: string): string;
|
|
29
|
+
export declare function sanitizeMarkdown(markdownHTML: string): string;
|
|
20
30
|
/**
|
|
21
31
|
* Sanitize URL to prevent dangerous protocols
|
|
22
|
-
* @param
|
|
23
|
-
* @returns
|
|
32
|
+
* @param url - URL to sanitize
|
|
33
|
+
* @returns Sanitized URL (returns empty string if dangerous)
|
|
24
34
|
*/
|
|
25
|
-
export function sanitizeURL(url: string): string;
|
|
35
|
+
export declare function sanitizeURL(url: string): string;
|
package/dist/utils/sanitize.js
CHANGED
|
@@ -8,309 +8,295 @@
|
|
|
8
8
|
* This approach avoids bundling jsdom (required by isomorphic-dompurify)
|
|
9
9
|
* which doesn't work in Cloudflare Workers.
|
|
10
10
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// Dynamically import DOMPurify only in browser
|
|
11
|
+
import { BROWSER } from "esm-env";
|
|
12
|
+
// DOMPurify instance - dynamically imported only in browser
|
|
15
13
|
let DOMPurify = null;
|
|
16
|
-
if (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
if (BROWSER) {
|
|
15
|
+
import("dompurify").then((module) => {
|
|
16
|
+
DOMPurify = module.default;
|
|
17
|
+
});
|
|
20
18
|
}
|
|
21
|
-
|
|
22
19
|
/**
|
|
23
20
|
* Sanitize HTML content to prevent XSS attacks
|
|
24
|
-
* @param
|
|
25
|
-
* @returns
|
|
21
|
+
* @param html - Raw HTML string to sanitize
|
|
22
|
+
* @returns Sanitized HTML safe for rendering
|
|
26
23
|
*/
|
|
27
24
|
export function sanitizeHTML(html) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return DOMPurify.sanitize(html, config);
|
|
25
|
+
if (!html || typeof html !== "string") {
|
|
26
|
+
return "";
|
|
27
|
+
}
|
|
28
|
+
// On server, pass through - will be sanitized on client hydration
|
|
29
|
+
if (!BROWSER || !DOMPurify) {
|
|
30
|
+
return html;
|
|
31
|
+
}
|
|
32
|
+
const config = {
|
|
33
|
+
FORBID_TAGS: [
|
|
34
|
+
"script",
|
|
35
|
+
"iframe",
|
|
36
|
+
"object",
|
|
37
|
+
"embed",
|
|
38
|
+
"link",
|
|
39
|
+
"style",
|
|
40
|
+
"form",
|
|
41
|
+
"input",
|
|
42
|
+
"button",
|
|
43
|
+
"base",
|
|
44
|
+
"meta",
|
|
45
|
+
],
|
|
46
|
+
FORBID_ATTR: [
|
|
47
|
+
"onerror",
|
|
48
|
+
"onload",
|
|
49
|
+
"onclick",
|
|
50
|
+
"onmouseover",
|
|
51
|
+
"onfocus",
|
|
52
|
+
"onblur",
|
|
53
|
+
"onchange",
|
|
54
|
+
"onsubmit",
|
|
55
|
+
"onmouseenter",
|
|
56
|
+
"onmouseleave",
|
|
57
|
+
"style",
|
|
58
|
+
],
|
|
59
|
+
ALLOWED_URI_REGEXP: /^(?:(?:https?|mailto|tel):|\/|#)/i,
|
|
60
|
+
ALLOW_DATA_ATTR: false,
|
|
61
|
+
KEEP_CONTENT: true,
|
|
62
|
+
SAFE_FOR_TEMPLATES: true,
|
|
63
|
+
RETURN_TRUSTED_TYPE: false,
|
|
64
|
+
};
|
|
65
|
+
return DOMPurify.sanitize(html, config);
|
|
71
66
|
}
|
|
72
|
-
|
|
73
67
|
/**
|
|
74
68
|
* Sanitize SVG content specifically (stricter rules for SVG)
|
|
75
|
-
* @param
|
|
76
|
-
* @returns
|
|
69
|
+
* @param svg - Raw SVG string to sanitize
|
|
70
|
+
* @returns Sanitized SVG safe for rendering
|
|
77
71
|
*/
|
|
78
72
|
export function sanitizeSVG(svg) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
});
|
|
73
|
+
if (!svg || typeof svg !== "string") {
|
|
74
|
+
return "";
|
|
75
|
+
}
|
|
76
|
+
// On server, pass through - will be sanitized on client hydration
|
|
77
|
+
if (!BROWSER || !DOMPurify) {
|
|
78
|
+
return svg;
|
|
79
|
+
}
|
|
80
|
+
return DOMPurify.sanitize(svg, {
|
|
81
|
+
USE_PROFILES: { svg: true, svgFilters: true },
|
|
82
|
+
ALLOWED_TAGS: [
|
|
83
|
+
"svg",
|
|
84
|
+
"g",
|
|
85
|
+
"path",
|
|
86
|
+
"circle",
|
|
87
|
+
"rect",
|
|
88
|
+
"line",
|
|
89
|
+
"polyline",
|
|
90
|
+
"polygon",
|
|
91
|
+
"ellipse",
|
|
92
|
+
"text",
|
|
93
|
+
"tspan",
|
|
94
|
+
"defs",
|
|
95
|
+
"marker",
|
|
96
|
+
"pattern",
|
|
97
|
+
"clipPath",
|
|
98
|
+
"mask",
|
|
99
|
+
"linearGradient",
|
|
100
|
+
"radialGradient",
|
|
101
|
+
"stop",
|
|
102
|
+
"use",
|
|
103
|
+
"symbol",
|
|
104
|
+
"title",
|
|
105
|
+
"desc",
|
|
106
|
+
],
|
|
107
|
+
ALLOWED_ATTR: [
|
|
108
|
+
"class",
|
|
109
|
+
"id",
|
|
110
|
+
"transform",
|
|
111
|
+
"fill",
|
|
112
|
+
"stroke",
|
|
113
|
+
"stroke-width",
|
|
114
|
+
"x",
|
|
115
|
+
"y",
|
|
116
|
+
"x1",
|
|
117
|
+
"y1",
|
|
118
|
+
"x2",
|
|
119
|
+
"y2",
|
|
120
|
+
"cx",
|
|
121
|
+
"cy",
|
|
122
|
+
"r",
|
|
123
|
+
"rx",
|
|
124
|
+
"ry",
|
|
125
|
+
"width",
|
|
126
|
+
"height",
|
|
127
|
+
"d",
|
|
128
|
+
"points",
|
|
129
|
+
"viewBox",
|
|
130
|
+
"xmlns",
|
|
131
|
+
"version",
|
|
132
|
+
"preserveAspectRatio",
|
|
133
|
+
"opacity",
|
|
134
|
+
"fill-opacity",
|
|
135
|
+
"stroke-opacity",
|
|
136
|
+
],
|
|
137
|
+
FORBID_TAGS: [
|
|
138
|
+
"script",
|
|
139
|
+
"iframe",
|
|
140
|
+
"object",
|
|
141
|
+
"embed",
|
|
142
|
+
"link",
|
|
143
|
+
"style",
|
|
144
|
+
"foreignObject",
|
|
145
|
+
"image",
|
|
146
|
+
"a",
|
|
147
|
+
],
|
|
148
|
+
FORBID_ATTR: [
|
|
149
|
+
"onerror",
|
|
150
|
+
"onload",
|
|
151
|
+
"onclick",
|
|
152
|
+
"onmouseover",
|
|
153
|
+
"onfocus",
|
|
154
|
+
"onblur",
|
|
155
|
+
"style",
|
|
156
|
+
"href",
|
|
157
|
+
"xlink:href",
|
|
158
|
+
],
|
|
159
|
+
KEEP_CONTENT: false,
|
|
160
|
+
SAFE_FOR_TEMPLATES: true,
|
|
161
|
+
RETURN_TRUSTED_TYPE: false,
|
|
162
|
+
});
|
|
170
163
|
}
|
|
171
|
-
|
|
172
164
|
/**
|
|
173
165
|
* Sanitize markdown-generated HTML with appropriate security rules
|
|
174
166
|
* This is a convenience wrapper for sanitizeHTML with markdown-specific settings
|
|
175
|
-
* @param
|
|
176
|
-
* @returns
|
|
167
|
+
* @param markdownHTML - HTML generated from markdown parsing
|
|
168
|
+
* @returns Sanitized HTML safe for rendering
|
|
177
169
|
*/
|
|
178
170
|
export function sanitizeMarkdown(markdownHTML) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
});
|
|
171
|
+
if (!markdownHTML || typeof markdownHTML !== "string") {
|
|
172
|
+
return "";
|
|
173
|
+
}
|
|
174
|
+
// On server, pass through - will be sanitized on client hydration
|
|
175
|
+
if (!BROWSER || !DOMPurify) {
|
|
176
|
+
return markdownHTML;
|
|
177
|
+
}
|
|
178
|
+
// For markdown, we allow a broader set of tags but still sanitize
|
|
179
|
+
return DOMPurify.sanitize(markdownHTML, {
|
|
180
|
+
ALLOWED_TAGS: [
|
|
181
|
+
"a",
|
|
182
|
+
"abbr",
|
|
183
|
+
"b",
|
|
184
|
+
"blockquote",
|
|
185
|
+
"br",
|
|
186
|
+
"code",
|
|
187
|
+
"dd",
|
|
188
|
+
"del",
|
|
189
|
+
"div",
|
|
190
|
+
"dl",
|
|
191
|
+
"dt",
|
|
192
|
+
"em",
|
|
193
|
+
"h1",
|
|
194
|
+
"h2",
|
|
195
|
+
"h3",
|
|
196
|
+
"h4",
|
|
197
|
+
"h5",
|
|
198
|
+
"h6",
|
|
199
|
+
"hr",
|
|
200
|
+
"i",
|
|
201
|
+
"img",
|
|
202
|
+
"ins",
|
|
203
|
+
"kbd",
|
|
204
|
+
"li",
|
|
205
|
+
"mark",
|
|
206
|
+
"ol",
|
|
207
|
+
"p",
|
|
208
|
+
"pre",
|
|
209
|
+
"q",
|
|
210
|
+
"s",
|
|
211
|
+
"samp",
|
|
212
|
+
"small",
|
|
213
|
+
"span",
|
|
214
|
+
"strong",
|
|
215
|
+
"sub",
|
|
216
|
+
"sup",
|
|
217
|
+
"table",
|
|
218
|
+
"tbody",
|
|
219
|
+
"td",
|
|
220
|
+
"tfoot",
|
|
221
|
+
"th",
|
|
222
|
+
"thead",
|
|
223
|
+
"tr",
|
|
224
|
+
"u",
|
|
225
|
+
"ul",
|
|
226
|
+
"var",
|
|
227
|
+
"input",
|
|
228
|
+
"label",
|
|
229
|
+
],
|
|
230
|
+
ALLOWED_ATTR: [
|
|
231
|
+
"href",
|
|
232
|
+
"src",
|
|
233
|
+
"alt",
|
|
234
|
+
"title",
|
|
235
|
+
"class",
|
|
236
|
+
"id",
|
|
237
|
+
"target",
|
|
238
|
+
"rel",
|
|
239
|
+
"width",
|
|
240
|
+
"height",
|
|
241
|
+
"align",
|
|
242
|
+
"type",
|
|
243
|
+
"checked",
|
|
244
|
+
"disabled",
|
|
245
|
+
],
|
|
246
|
+
FORBID_TAGS: [
|
|
247
|
+
"script",
|
|
248
|
+
"iframe",
|
|
249
|
+
"object",
|
|
250
|
+
"embed",
|
|
251
|
+
"link",
|
|
252
|
+
"style",
|
|
253
|
+
"form",
|
|
254
|
+
"button",
|
|
255
|
+
],
|
|
256
|
+
FORBID_ATTR: [
|
|
257
|
+
"onerror",
|
|
258
|
+
"onload",
|
|
259
|
+
"onclick",
|
|
260
|
+
"onmouseover",
|
|
261
|
+
"onfocus",
|
|
262
|
+
"onblur",
|
|
263
|
+
"onchange",
|
|
264
|
+
"onsubmit",
|
|
265
|
+
"style",
|
|
266
|
+
],
|
|
267
|
+
ALLOWED_URI_REGEXP: /^(?:(?:https?|mailto|tel):|\/|#)/i,
|
|
268
|
+
ALLOW_DATA_ATTR: false,
|
|
269
|
+
KEEP_CONTENT: true,
|
|
270
|
+
SAFE_FOR_TEMPLATES: true,
|
|
271
|
+
RETURN_TRUSTED_TYPE: false,
|
|
272
|
+
});
|
|
282
273
|
}
|
|
283
|
-
|
|
284
274
|
/**
|
|
285
275
|
* Sanitize URL to prevent dangerous protocols
|
|
286
|
-
* @param
|
|
287
|
-
* @returns
|
|
276
|
+
* @param url - URL to sanitize
|
|
277
|
+
* @returns Sanitized URL (returns empty string if dangerous)
|
|
288
278
|
*/
|
|
289
279
|
export function sanitizeURL(url) {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
if (dangerous.test(url)) {
|
|
302
|
-
return "";
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// Only allow safe protocols
|
|
306
|
-
const safe = /^(https?|mailto|tel):/i;
|
|
307
|
-
if (!safe.test(url)) {
|
|
308
|
-
// If no protocol, assume relative
|
|
309
|
-
if (!url.includes(":")) {
|
|
310
|
-
return url;
|
|
280
|
+
if (!url || typeof url !== "string") {
|
|
281
|
+
return "";
|
|
282
|
+
}
|
|
283
|
+
// Allow relative URLs
|
|
284
|
+
if (url.startsWith("/") || url.startsWith("./") || url.startsWith("../")) {
|
|
285
|
+
return url;
|
|
286
|
+
}
|
|
287
|
+
// Check for dangerous protocols
|
|
288
|
+
const dangerous = /^(javascript|data|vbscript|file|about):/i;
|
|
289
|
+
if (dangerous.test(url)) {
|
|
290
|
+
return "";
|
|
311
291
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
292
|
+
// Only allow safe protocols
|
|
293
|
+
const safe = /^(https?|mailto|tel):/i;
|
|
294
|
+
if (!safe.test(url)) {
|
|
295
|
+
// If no protocol, assume relative
|
|
296
|
+
if (!url.includes(":")) {
|
|
297
|
+
return url;
|
|
298
|
+
}
|
|
299
|
+
return "";
|
|
300
|
+
}
|
|
301
|
+
return url;
|
|
316
302
|
}
|
package/dist/utils/validation.js
CHANGED
|
@@ -26,12 +26,12 @@ const FILE_SIGNATURES = {
|
|
|
26
26
|
*/
|
|
27
27
|
export async function validateFileSignature(file, expectedType) {
|
|
28
28
|
const buffer = new Uint8Array(await file.arrayBuffer());
|
|
29
|
-
const signatures = FILE_SIGNATURES[expectedType];
|
|
29
|
+
const signatures = /** @type {number[][] | undefined} */ (FILE_SIGNATURES[/** @type {keyof typeof FILE_SIGNATURES} */ (expectedType)]);
|
|
30
30
|
|
|
31
31
|
if (!signatures) return false;
|
|
32
32
|
|
|
33
|
-
return signatures.some(sig =>
|
|
34
|
-
sig.every((byte, i) => buffer[i] === byte)
|
|
33
|
+
return signatures.some((/** @type {number[]} */ sig) =>
|
|
34
|
+
sig.every((/** @type {number} */ byte, /** @type {number} */ i) => buffer[i] === byte)
|
|
35
35
|
);
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -54,6 +54,7 @@ export function sanitizeObject(obj) {
|
|
|
54
54
|
));
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/** @type {Record<string, any>} */
|
|
57
58
|
const sanitized = {};
|
|
58
59
|
|
|
59
60
|
for (const [key, value] of Object.entries(obj)) {
|