pulse-js-framework 1.11.3 → 1.11.4
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/cli/analyze.js +21 -8
- package/cli/build.js +83 -56
- package/cli/dev.js +108 -94
- package/cli/docs-test.js +52 -33
- package/cli/index.js +81 -51
- package/cli/mobile.js +92 -40
- package/cli/release.js +64 -46
- package/cli/scaffold.js +14 -13
- package/compiler/lexer.js +55 -54
- package/compiler/parser/core.js +1 -0
- package/compiler/parser/state.js +6 -12
- package/compiler/parser/style.js +17 -20
- package/compiler/parser/view.js +1 -3
- package/compiler/preprocessor.js +124 -262
- package/compiler/sourcemap.js +10 -4
- package/compiler/transformer/expressions.js +122 -106
- package/compiler/transformer/index.js +2 -4
- package/compiler/transformer/style.js +74 -7
- package/compiler/transformer/view.js +86 -36
- package/loader/esbuild-plugin-server-components.js +209 -0
- package/loader/esbuild-plugin.js +41 -93
- package/loader/parcel-plugin.js +37 -97
- package/loader/rollup-plugin-server-components.js +30 -169
- package/loader/rollup-plugin.js +27 -78
- package/loader/shared.js +362 -0
- package/loader/swc-plugin.js +65 -82
- package/loader/vite-plugin-server-components.js +30 -171
- package/loader/vite-plugin.js +25 -10
- package/loader/webpack-loader-server-components.js +21 -134
- package/loader/webpack-loader.js +25 -80
- package/package.json +52 -12
- package/runtime/dom-selector.js +2 -1
- package/runtime/form.js +4 -3
- package/runtime/http.js +6 -1
- package/runtime/logger.js +44 -24
- package/runtime/router/utils.js +14 -7
- package/runtime/security.js +13 -1
- package/runtime/server-components/actions-server.js +23 -19
- package/runtime/server-components/error-sanitizer.js +18 -18
- package/runtime/server-components/security.js +41 -24
- package/runtime/ssr-preload.js +5 -3
- package/runtime/testing.js +759 -0
- package/runtime/utils.js +3 -2
- package/server/utils.js +15 -9
- package/sw/index.js +2 -0
- package/types/loaders.d.ts +1043 -0
- package/compiler/parser/_extract.js +0 -393
- package/loader/README.md +0 -509
|
@@ -26,24 +26,24 @@ const log = loggers.dom;
|
|
|
26
26
|
* Covers secrets, connection strings, file paths, env vars.
|
|
27
27
|
*/
|
|
28
28
|
const SENSITIVE_MESSAGE_PATTERNS = [
|
|
29
|
-
// Connection strings
|
|
30
|
-
/postgres:\/\/[
|
|
31
|
-
/mongodb(
|
|
32
|
-
/mysql:\/\/[
|
|
33
|
-
/redis:\/\/[
|
|
29
|
+
// Connection strings - bound quantifiers to prevent ReDoS on strings without '@'
|
|
30
|
+
/postgres:\/\/[^@\s]{1,256}@[^/\s]{1,256}/gi, // PostgreSQL
|
|
31
|
+
/mongodb(?:\+srv)?:\/\/[^@\s]{1,256}@[^/\s]{1,256}/gi, // MongoDB
|
|
32
|
+
/mysql:\/\/[^@\s]{1,256}@[^/\s]{1,256}/gi, // MySQL
|
|
33
|
+
/redis:\/\/[^@\s]{1,256}@[^/\s]{1,256}/gi, // Redis
|
|
34
34
|
|
|
35
|
-
// API keys and tokens (common formats)
|
|
36
|
-
/[a-zA-Z0-9_-]{20,}/g,
|
|
35
|
+
// API keys and tokens (common formats) - bounded
|
|
36
|
+
/[a-zA-Z0-9_-]{20,200}/g, // Generic long tokens
|
|
37
37
|
|
|
38
|
-
// Environment variable values (KEY=value patterns)
|
|
39
|
-
/\b[A-Z_]
|
|
38
|
+
// Environment variable values (KEY=value patterns) - bounded
|
|
39
|
+
/\b[A-Z_]{1,100}=[^\s]{1,500}/g,
|
|
40
40
|
|
|
41
|
-
// File paths (Unix and Windows)
|
|
42
|
-
/\/[a-zA-Z0-9_
|
|
43
|
-
/[A-Z]:\\[
|
|
41
|
+
// File paths (Unix and Windows) - non-overlapping segments, bounded
|
|
42
|
+
/\/[a-zA-Z0-9_-]{1,100}(?:\/[a-zA-Z0-9_-]{1,100}){0,20}\.[a-z]{1,6}/gi,
|
|
43
|
+
/[A-Z]:\\[a-zA-Z0-9_-]{1,100}(?:\\[a-zA-Z0-9_-]{1,100}){0,20}\.[a-z]{1,6}/gi,
|
|
44
44
|
|
|
45
|
-
// Email addresses
|
|
46
|
-
/\b[A-Za-z0-9._%+-]
|
|
45
|
+
// Email addresses - bounded segments to prevent ReDoS
|
|
46
|
+
/\b[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,253}\.[A-Za-z]{2,20}\b/g,
|
|
47
47
|
|
|
48
48
|
// IP addresses
|
|
49
49
|
/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g
|
|
@@ -152,11 +152,11 @@ export function sanitizeStackTrace(stack) {
|
|
|
152
152
|
// First, strip absolute paths to relative paths
|
|
153
153
|
let sanitizedLine = line;
|
|
154
154
|
|
|
155
|
-
// Replace absolute paths with relative (Unix)
|
|
156
|
-
sanitizedLine = sanitizedLine.replace(/\/[a-zA-Z0-9_
|
|
155
|
+
// Replace absolute paths with relative (Unix) - bounded segments to avoid ReDoS
|
|
156
|
+
sanitizedLine = sanitizedLine.replace(/\/[a-zA-Z0-9_-]{1,100}(?:\/[a-zA-Z0-9_-]{1,100}){0,30}\/([a-zA-Z0-9_.-]{1,100}\.(js|ts))/g, '$1');
|
|
157
157
|
|
|
158
|
-
// Replace absolute paths with relative (Windows)
|
|
159
|
-
sanitizedLine = sanitizedLine.replace(/[A-Z]:\\[
|
|
158
|
+
// Replace absolute paths with relative (Windows) - bounded segments to avoid ReDoS
|
|
159
|
+
sanitizedLine = sanitizedLine.replace(/[A-Z]:\\[a-zA-Z0-9_-]{1,100}(?:\\[a-zA-Z0-9_-]{1,100}){0,30}\\([a-zA-Z0-9_.-]{1,100}\.(js|ts))/g, '$1');
|
|
160
160
|
|
|
161
161
|
// NOW filter out internal/sensitive paths (after path conversion)
|
|
162
162
|
let shouldFilter = false;
|
|
@@ -66,10 +66,15 @@ const SECRET_PATTERNS = [
|
|
|
66
66
|
*/
|
|
67
67
|
const XSS_PATTERNS = {
|
|
68
68
|
scriptTag: /<script[\s>]/i,
|
|
69
|
-
|
|
69
|
+
// Use non-overlapping groups: match tag name chars then specifically 'on' + handler name
|
|
70
|
+
// Avoids ReDoS by limiting [^>] to {1,1000} and using non-greedy match
|
|
71
|
+
eventHandler: /<[^>]{1,1000}?\bon\w+\s*=/i,
|
|
70
72
|
javascriptProtocol: /javascript:/i,
|
|
71
73
|
vbscriptProtocol: /vbscript:/i,
|
|
72
|
-
|
|
74
|
+
// Match dangerous data: URIs - block data: with executable MIME types and SVG
|
|
75
|
+
dataProtocol: /data:\s*(?:text\/(?:html|javascript|xml)|image\/svg\+xml|application\/(?:javascript|x-javascript|ecmascript|xhtml\+xml|xml))/i,
|
|
76
|
+
// Catch-all for data: URIs not in allowlist (used in URL validation)
|
|
77
|
+
dataAny: /^\s*data\s*:/i
|
|
73
78
|
};
|
|
74
79
|
|
|
75
80
|
// ============================================================================
|
|
@@ -221,39 +226,51 @@ export function sanitizePropsForXSS(props, componentId) {
|
|
|
221
226
|
let sanitized = value;
|
|
222
227
|
let modified = false;
|
|
223
228
|
|
|
224
|
-
// Check for script tags
|
|
229
|
+
// Check for script tags - use loop to handle incomplete multi-character sanitization
|
|
225
230
|
if (XSS_PATTERNS.scriptTag.test(sanitized)) {
|
|
226
231
|
log.warn(`PSC: Script tag detected in prop '${path}' for '${componentId}'`);
|
|
227
|
-
|
|
232
|
+
// Loop until all <script patterns are removed (handles nested/overlapping)
|
|
233
|
+
let prev;
|
|
234
|
+
do {
|
|
235
|
+
prev = sanitized;
|
|
236
|
+
sanitized = sanitized.replace(/<script[\s>]/gi, '<script ');
|
|
237
|
+
} while (sanitized !== prev);
|
|
228
238
|
modified = true;
|
|
229
239
|
}
|
|
230
240
|
|
|
231
241
|
// Check for event handlers in HTML-like content
|
|
232
242
|
if (XSS_PATTERNS.eventHandler.test(sanitized)) {
|
|
233
243
|
log.warn(`PSC: Event handler detected in prop '${path}' for '${componentId}'`);
|
|
234
|
-
sanitized = sanitized.replace(
|
|
244
|
+
sanitized = sanitized.replace(/\bon\w{1,50}\s*=/gi, 'data-blocked-event=');
|
|
235
245
|
modified = true;
|
|
236
246
|
}
|
|
237
247
|
|
|
238
|
-
// Check for javascript:
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
248
|
+
// Check for dangerous URL protocols: javascript:, vbscript:, data:
|
|
249
|
+
// All three are checked together to ensure complete URL scheme validation.
|
|
250
|
+
{
|
|
251
|
+
const DANGEROUS_PROTOCOLS = /(?:javascript|vbscript|data)\s*:/i;
|
|
252
|
+
if (DANGEROUS_PROTOCOLS.test(sanitized)) {
|
|
253
|
+
// Block javascript: and vbscript: unconditionally
|
|
254
|
+
if (/javascript\s*:/i.test(sanitized)) {
|
|
255
|
+
log.warn(`PSC: javascript: protocol detected in prop '${path}' for '${componentId}'`);
|
|
256
|
+
sanitized = sanitized.replace(/javascript\s*:/gi, 'blocked:');
|
|
257
|
+
modified = true;
|
|
258
|
+
}
|
|
259
|
+
if (/vbscript\s*:/i.test(sanitized)) {
|
|
260
|
+
log.warn(`PSC: vbscript: protocol detected in prop '${path}' for '${componentId}'`);
|
|
261
|
+
sanitized = sanitized.replace(/vbscript\s*:/gi, 'blocked:');
|
|
262
|
+
modified = true;
|
|
263
|
+
}
|
|
264
|
+
// Block data: URIs except safe image/text types - neutralize to data:text/plain
|
|
265
|
+
if (/data\s*:/i.test(sanitized)) {
|
|
266
|
+
const SAFE_DATA = /data:\s*(?:text\/plain|image\/(?:png|jpe?g|gif|webp|bmp|ico))(?:[;,]|$)/i;
|
|
267
|
+
if (!SAFE_DATA.test(sanitized)) {
|
|
268
|
+
log.warn(`PSC: blocked data: URI in prop '${path}' for '${componentId}'`);
|
|
269
|
+
sanitized = sanitized.replace(/data\s*:[^\s)"']{0,500}/gi, 'data:text/plain');
|
|
270
|
+
modified = true;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
257
274
|
}
|
|
258
275
|
|
|
259
276
|
return sanitized;
|
package/runtime/ssr-preload.js
CHANGED
|
@@ -183,9 +183,11 @@ export function hintsToHTML(hints) {
|
|
|
183
183
|
if (!hints || hints.length === 0) return '';
|
|
184
184
|
|
|
185
185
|
return hints.map(hint => {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
// Escape all attribute values for safe use in HTML (& < > and double quotes)
|
|
187
|
+
const escapeAttr = (v) => escapeHTML(v).replace(/"/g, '"');
|
|
188
|
+
const parts = [`rel="${escapeAttr(hint.rel)}"`, `href="${escapeAttr(hint.href)}"`];
|
|
189
|
+
if (hint.as) parts.push(`as="${escapeAttr(hint.as)}"`);
|
|
190
|
+
if (hint.type) parts.push(`type="${escapeAttr(hint.type)}"`);
|
|
189
191
|
if (hint.crossorigin) parts.push('crossorigin');
|
|
190
192
|
return `<link ${parts.join(' ')}>`;
|
|
191
193
|
}).join('\n');
|