@blamejs/blamejs-shop 0.5.19 → 0.5.20

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.
Files changed (110) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/admin.js +35 -40
  3. package/lib/asset-manifest.json +1 -1
  4. package/lib/externaldb-d1.js +31 -21
  5. package/lib/payment.js +103 -58
  6. package/lib/referrals.js +10 -6
  7. package/lib/security-middleware.js +39 -12
  8. package/lib/site-redirects.js +44 -121
  9. package/lib/storefront.js +19 -21
  10. package/lib/vendor/MANIFEST.json +107 -97
  11. package/lib/vendor/blamejs/CHANGELOG.md +180 -0
  12. package/lib/vendor/blamejs/NOTICE +14 -10
  13. package/lib/vendor/blamejs/README.md +17 -5
  14. package/lib/vendor/blamejs/index.js +2 -0
  15. package/lib/vendor/blamejs/lib/acme.js +9 -9
  16. package/lib/vendor/blamejs/lib/api-snapshot.js +35 -16
  17. package/lib/vendor/blamejs/lib/app-shutdown.js +1 -1
  18. package/lib/vendor/blamejs/lib/archive-adapters.js +1 -1
  19. package/lib/vendor/blamejs/lib/archive.js +13 -24
  20. package/lib/vendor/blamejs/lib/auth/access-lock.js +2 -1
  21. package/lib/vendor/blamejs/lib/auth/bot-challenge.js +3 -6
  22. package/lib/vendor/blamejs/lib/auth/ciba.js +32 -3
  23. package/lib/vendor/blamejs/lib/auth/oauth.js +65 -8
  24. package/lib/vendor/blamejs/lib/auth/password.js +1 -1
  25. package/lib/vendor/blamejs/lib/auth/saml.js +21 -3
  26. package/lib/vendor/blamejs/lib/auth-bot-challenge.js +3 -3
  27. package/lib/vendor/blamejs/lib/backup/index.js +5 -5
  28. package/lib/vendor/blamejs/lib/case-fold-classes.js +491 -0
  29. package/lib/vendor/blamejs/lib/codepoint-class.js +131 -0
  30. package/lib/vendor/blamejs/lib/constants.js +79 -0
  31. package/lib/vendor/blamejs/lib/db-declare-view.js +8 -2
  32. package/lib/vendor/blamejs/lib/error-page.js +20 -1
  33. package/lib/vendor/blamejs/lib/external-db.js +5 -1
  34. package/lib/vendor/blamejs/lib/flag-evaluation-context.js +24 -6
  35. package/lib/vendor/blamejs/lib/flag.js +28 -2
  36. package/lib/vendor/blamejs/lib/framework-schema.js +14 -3
  37. package/lib/vendor/blamejs/lib/guard-regex.js +2345 -89
  38. package/lib/vendor/blamejs/lib/http-client.js +217 -40
  39. package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
  40. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +3 -2
  41. package/lib/vendor/blamejs/lib/mail-dav.js +26 -26
  42. package/lib/vendor/blamejs/lib/mail-deploy.js +10 -10
  43. package/lib/vendor/blamejs/lib/mail-scan.js +3 -0
  44. package/lib/vendor/blamejs/lib/mail-store.js +7 -1
  45. package/lib/vendor/blamejs/lib/mail.js +5 -1
  46. package/lib/vendor/blamejs/lib/middleware/age-gate.js +3 -2
  47. package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +1 -1
  48. package/lib/vendor/blamejs/lib/middleware/assetlinks.js +2 -1
  49. package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +3 -2
  50. package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +2 -1
  51. package/lib/vendor/blamejs/lib/middleware/compression.js +1 -1
  52. package/lib/vendor/blamejs/lib/middleware/cors.js +1 -1
  53. package/lib/vendor/blamejs/lib/middleware/csp-report.js +5 -5
  54. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +2 -1
  55. package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +2 -2
  56. package/lib/vendor/blamejs/lib/middleware/deny-response.js +2 -1
  57. package/lib/vendor/blamejs/lib/middleware/dpop.js +2 -2
  58. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +2 -1
  59. package/lib/vendor/blamejs/lib/middleware/flag-context.js +17 -0
  60. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +10 -8
  61. package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +3 -2
  62. package/lib/vendor/blamejs/lib/middleware/require-aal.js +3 -2
  63. package/lib/vendor/blamejs/lib/middleware/require-auth.js +4 -3
  64. package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +4 -3
  65. package/lib/vendor/blamejs/lib/middleware/require-content-type.js +3 -2
  66. package/lib/vendor/blamejs/lib/middleware/require-methods.js +3 -2
  67. package/lib/vendor/blamejs/lib/middleware/require-mtls.js +3 -2
  68. package/lib/vendor/blamejs/lib/middleware/security-txt.js +2 -1
  69. package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +2 -1
  70. package/lib/vendor/blamejs/lib/network-dns-resolver.js +1 -1
  71. package/lib/vendor/blamejs/lib/network-dns.js +3 -3
  72. package/lib/vendor/blamejs/lib/network-nts.js +35 -14
  73. package/lib/vendor/blamejs/lib/network-proxy.js +42 -4
  74. package/lib/vendor/blamejs/lib/network-smtp-policy.js +1 -1
  75. package/lib/vendor/blamejs/lib/network-tls.js +341 -11
  76. package/lib/vendor/blamejs/lib/nist-crosswalk.js +2 -2
  77. package/lib/vendor/blamejs/lib/ntp-check.js +30 -19
  78. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +1 -1
  79. package/lib/vendor/blamejs/lib/object-store/gcs.js +1 -1
  80. package/lib/vendor/blamejs/lib/object-store/http-put.js +2 -1
  81. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -5
  82. package/lib/vendor/blamejs/lib/object-store/sigv4.js +2 -2
  83. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +4 -2
  84. package/lib/vendor/blamejs/lib/openapi.js +1 -1
  85. package/lib/vendor/blamejs/lib/pqc-agent.js +4 -7
  86. package/lib/vendor/blamejs/lib/problem-details.js +2 -1
  87. package/lib/vendor/blamejs/lib/redis-client.js +12 -1
  88. package/lib/vendor/blamejs/lib/regex-linear.js +1349 -0
  89. package/lib/vendor/blamejs/lib/render.js +531 -7
  90. package/lib/vendor/blamejs/lib/request-helpers.js +181 -5
  91. package/lib/vendor/blamejs/lib/router.js +37 -13
  92. package/lib/vendor/blamejs/lib/safe-async.js +142 -0
  93. package/lib/vendor/blamejs/lib/safe-icap.js +3 -0
  94. package/lib/vendor/blamejs/lib/safe-sql.js +15 -3
  95. package/lib/vendor/blamejs/lib/self-update.js +2 -2
  96. package/lib/vendor/blamejs/lib/testing.js +54 -7
  97. package/lib/vendor/blamejs/lib/validate-opts.js +56 -0
  98. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +62 -25
  99. package/lib/vendor/blamejs/lib/vendor/blamejs-pki.cjs +2004 -142
  100. package/lib/vendor/blamejs/lib/vendor/browser/noble-ciphers.mjs +727 -0
  101. package/lib/vendor/blamejs/lib/vendor/browser/noble-hashes.mjs +1070 -0
  102. package/lib/vendor/blamejs/lib/vendor/browser/noble-post-quantum.mjs +1090 -0
  103. package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +510 -227
  104. package/lib/vendor/blamejs/lib/webhook-hmac.js +19 -2
  105. package/lib/vendor/blamejs/lib/webhook.js +1 -1
  106. package/lib/vendor/blamejs/lib/ws-client.js +24 -2
  107. package/lib/vendor/blamejs/package.json +1 -1
  108. package/lib/vendor/blamejs/sbom.cdx.json +6 -6
  109. package/lib/webhook-receiver.js +43 -73
  110. package/package.json +1 -1
@@ -240,18 +240,29 @@ function _epochMs(n, label) {
240
240
  return n;
241
241
  }
242
242
 
243
- // Refuse regex patterns that carry backreferences (`\1`..`\9`) or
244
- // lookahead/lookbehind (`(?=...)`, `(?!...)`, `(?<=...)`, `(?<!...)`).
245
- // These are the two regex-shape categories that drive catastrophic
246
- // backtracking under adversarial input. Operators wanting these
247
- // shapes register multiple `prefix` / `exact` rules instead — the
248
- // regex match_kind is for cheap path-translation, not arbitrary
249
- // pattern matching.
243
+ // Compile an operator's redirect pattern, anchored with `^` and `$` so
244
+ // `resolveForPath` answers an exact-path match rather than a substring one
245
+ // (`/foo` must not find `/foo/bar`).
250
246
  //
251
- // `_compileRegex` walks the source for the forbidden tokens BEFORE
252
- // handing it to RegExp(), then anchors the compiled pattern with `^`
253
- // and `$` so `resolveForPath` answers an exact-path match (not a
254
- // substring match a la `/foo` finding `/foo/bar`).
247
+ // The pattern is matched by b.regexLinear, which simulates every path through
248
+ // it one character at a time, so the work cannot grow faster than the subject
249
+ // times the pattern no matter what the operator wrote. That replaces the
250
+ // screen this used to run — a walker for backreferences and lookaround, then
251
+ // b.guardRegex for backtracking shapes.
252
+ //
253
+ // Screening was always an approximation in both directions: it refused
254
+ // patterns that were perfectly linear, and it could not promise to catch every
255
+ // shape that was not, so each shape it missed became another case to add. The
256
+ // patterns it existed to stop — `(a+)+`, `(a|a)*` — are now simply run: on two
257
+ // thousand characters they finish in about two milliseconds where the platform
258
+ // engine takes the better part of a minute. An operator gets their pattern
259
+ // accepted and the request path stays bounded, which is what the screen was
260
+ // trying and failing to deliver.
261
+ //
262
+ // Three constructs still cannot be simulated this way and are refused by name:
263
+ // a backreference, a lookaround, and a repetition whose body can match nothing.
264
+ // Each is mapped below into this module's TypeError envelope so a caller sees
265
+ // one error shape.
255
266
  function _compileRegex(source) {
256
267
  if (typeof source !== "string" || !source.length) {
257
268
  throw new TypeError("siteRedirects: source_path (regex) must be a non-empty string");
@@ -264,124 +275,36 @@ function _compileRegex(source) {
264
275
  if (CONTROL_BYTE_RE.test(source) || ZERO_WIDTH_RE.test(source)) {
265
276
  throw new TypeError("siteRedirects: regex source contains control / zero-width bytes");
266
277
  }
267
- // Backreferences: \1 .. \9 outside a character class. The walker
268
- // tracks character-class depth so `[\1]` (literal byte) doesn't
269
- // trip the gate, but `(.)\1` (a real backreference) does.
270
- var inClass = 0;
271
- for (var i = 0; i < source.length; i += 1) {
272
- var ch = source.charAt(i);
273
- if (ch === "\\" && i + 1 < source.length) {
274
- var nxt = source.charAt(i + 1);
275
- if (inClass === 0 && nxt >= "1" && nxt <= "9") {
276
- throw new TypeError(
277
- "siteRedirects: regex backreferences (\\1..\\9) refused — operators register " +
278
- "separate redirect rows for each variant instead"
279
- );
280
- }
281
- i += 1; // skip escaped char
282
- continue;
283
- }
284
- if (ch === "[") { inClass += 1; continue; }
285
- if (ch === "]" && inClass > 0) { inClass -= 1; continue; }
286
- if (inClass > 0) continue;
287
- if (ch === "(" && i + 2 < source.length && source.charAt(i + 1) === "?") {
288
- var third = source.charAt(i + 2);
289
- if (third === "=" || third === "!" || third === "<") {
290
- throw new TypeError(
291
- "siteRedirects: regex lookahead / lookbehind (`(?=`, `(?!`, `(?<=`, `(?<!`) refused " +
292
- "— catastrophic-backtracking surface; rewrite as `prefix` or split into multiple rows"
293
- );
294
- }
295
- }
296
- }
297
- // Build the anchored form. RegExp() throws SyntaxError on a
298
- // malformed source — re-shape that into the primitive's TypeError
299
- // envelope so callers can match on the consistent error shape.
300
278
  var anchored = "^(?:" + source + ")$";
301
- var compiled;
302
279
  try {
303
- compiled = new RegExp(anchored);
280
+ return b.regexLinear.compile(anchored);
304
281
  } catch (e) {
282
+ var code = (e && e.code) || "";
283
+ if (code === "regex/unsupported-backreference") {
284
+ throw new TypeError(
285
+ "siteRedirects: regex backreferences (\\1..\\9) refused — a backreference " +
286
+ "cannot be matched in linear time; register a separate redirect row for " +
287
+ "each variant instead"
288
+ );
289
+ }
290
+ if (code === "regex/unsupported-lookaround") {
291
+ throw new TypeError(
292
+ "siteRedirects: regex lookahead / lookbehind (`(?=`, `(?!`, `(?<=`, `(?<!`) " +
293
+ "refused — lookaround cannot be matched in linear time; rewrite as `prefix` " +
294
+ "or split into multiple rows"
295
+ );
296
+ }
297
+ if (code === "regex/nullable-repetition") {
298
+ throw new TypeError(
299
+ "siteRedirects: a repetition whose body can match nothing (`(a*)*`) is " +
300
+ "refused — it matches exactly what its body matches, so write that instead"
301
+ );
302
+ }
305
303
  throw new TypeError(
306
304
  "siteRedirects: regex source did not compile — " +
307
305
  (e && e.message ? e.message : "invalid pattern")
308
306
  );
309
307
  }
310
- // Extend the backreference / lookaround screen above with the last
311
- // catastrophic-backtracking class it doesn't cover: a nested unbounded
312
- // quantifier ((a+)+, (a*)*, (?:a+)+, (.+)+ …). This regex runs against the
313
- // request path in `resolveForPath`, so a super-linear pattern is a DoS on
314
- // every matching request. (The framework's b.guardRegex screen is not used
315
- // here because its text scan misreads the `?` in a `(?:…)` group prefix and
316
- // a bounded trailing `?` as quantifiers, rejecting linear patterns like
317
- // `/blog(?:/page/\d+)?` — filed upstream; this walker allows them.)
318
- if (_hasNestedUnboundedQuantifier(source)) {
319
- throw new TypeError(
320
- "siteRedirects: regex source rejected — nested unbounded quantifier " +
321
- "(catastrophic-backtracking / ReDoS) surface; rewrite as `prefix` / " +
322
- "`exact`, or split into multiple rows"
323
- );
324
- }
325
- return compiled;
326
- }
327
-
328
- // Detect the nested-unbounded-quantifier ReDoS class: a group whose body
329
- // contains an unbounded quantifier (`+`, `*`, `{n,}`) and is itself repeated
330
- // by an unbounded quantifier — `(a+)+`, `(a*)*`, `(?:a+)+`, `(.+)+`,
331
- // `((ab)+)+` at any depth. A single optional / linearly-repeated group
332
- // (`(?:foo)?`, `(?:bar)*`, `/products/.+`) is safe and MUST be allowed. The
333
- // walk mirrors the backreference/lookaround walk: char-by-char, honoring
334
- // escapes, character classes, and the `(?:` / `(?<name>` group prefixes whose
335
- // `?` is group syntax, not a quantifier. Lookaround is already refused before
336
- // this runs, so only `(?:` reaches here.
337
- function _hasNestedUnboundedQuantifier(source) {
338
- var stack = []; // open groups: { bodyUnbounded: bool }
339
- var inClass = false;
340
- var i = 0;
341
- var n = source.length;
342
- function outerUnboundedAt(idx) {
343
- var c = source.charAt(idx);
344
- if (c === "*" || c === "+") return true;
345
- if (c === "{") { return /^\{\d*,\}/.test(source.slice(idx)); } // {n,} — no upper bound
346
- return false;
347
- }
348
- while (i < n) {
349
- var ch = source.charAt(i);
350
- if (ch === "\\") { i += 2; continue; } // escaped atom
351
- if (inClass) { if (ch === "]") { inClass = false; } i += 1; continue; }
352
- if (ch === "[") { inClass = true; i += 1; continue; }
353
- if (ch === "(") {
354
- if (source.charAt(i + 1) === "?") { // group prefix — not a quantifier
355
- i += 2;
356
- if (source.charAt(i) === ":") { i += 1; }
357
- else if (source.charAt(i) === "<") { while (i < n && source.charAt(i) !== ">") { i += 1; } if (i < n) { i += 1; } }
358
- } else { i += 1; }
359
- stack.push({ bodyUnbounded: false });
360
- continue;
361
- }
362
- if (ch === ")") {
363
- var g = stack.pop() || { bodyUnbounded: false };
364
- var outer = outerUnboundedAt(i + 1);
365
- if (g.bodyUnbounded && outer) { return true; } // nested unbounded quantifier
366
- // A group repeated by an unbounded quantifier is itself an unbounded
367
- // atom for its parent.
368
- if (outer && stack.length) { stack[stack.length - 1].bodyUnbounded = true; }
369
- i += 1;
370
- continue;
371
- }
372
- if (ch === "*" || ch === "+") {
373
- if (stack.length) { stack[stack.length - 1].bodyUnbounded = true; }
374
- i += 1;
375
- continue;
376
- }
377
- if (ch === "{" && /^\{\d*,\}/.test(source.slice(i))) {
378
- if (stack.length) { stack[stack.length - 1].bodyUnbounded = true; }
379
- i += 1;
380
- continue;
381
- }
382
- i += 1;
383
- }
384
- return false;
385
308
  }
386
309
 
387
310
  // ---- row hydration ------------------------------------------------------
package/lib/storefront.js CHANGED
@@ -15928,28 +15928,26 @@ function mount(router, deps) {
15928
15928
  // is built from the validated UUID order id alone (hex + hyphens),
15929
15929
  // carrying no quote/CRLF that could break out of the header.
15930
15930
  var safeId = String(o.id).replace(/[^A-Za-z0-9._-]/g, "");
15931
- res.status(200);
15932
- if (res.setHeader) {
15933
- res.setHeader("content-type", "text/html; charset=utf-8");
15934
- res.setHeader("content-disposition", "attachment; filename=\"receipt-" + safeId + ".html\"");
15935
- res.setHeader("x-content-type-options", "nosniff");
15936
- // The receipt carries the buyer's name + address + line items —
15937
- // keep it out of any shared/proxy cache.
15938
- res.setHeader("cache-control", "no-store");
15939
- }
15940
15931
  // One chunk per batch as the source yields it — bounded memory
15941
- // regardless of document size. A response without an incremental
15942
- // write() (a JSON test stub) falls back to buffering.
15943
- if (typeof res.write === "function" && typeof res.end === "function") {
15944
- for await (var chunk of _streamReceiptDocument(doc)) {
15945
- if (chunk) res.write(chunk);
15946
- }
15947
- res.end();
15948
- } else {
15949
- var buffered = "";
15950
- for await (var c2 of _streamReceiptDocument(doc)) buffered += c2;
15951
- if (res.end) res.end(buffered); else res.send(buffered);
15952
- }
15932
+ // regardless of document size. render.stream awaits backpressure so a
15933
+ // slow client cannot queue the whole document in the socket buffer,
15934
+ // stops when the peer disconnects, and signals a mid-stream failure as
15935
+ // a broken transfer rather than ending a truncated body as a clean 200.
15936
+ //
15937
+ // Headers go in the call, not via setHeader beforehand: render.stream
15938
+ // writes its own defaults with the first chunk, and its default
15939
+ // Content-Type would replace one set earlier. Cache-Control is set
15940
+ // explicitly because the receipt carries the buyer's name, address and
15941
+ // line items and must stay out of any shared or proxy cache.
15942
+ await b.render.stream(res, _streamReceiptDocument(doc), {
15943
+ status: 200,
15944
+ headers: {
15945
+ "Content-Type": "text/html; charset=utf-8",
15946
+ "Content-Disposition": "attachment; filename=\"receipt-" + safeId + ".html\"",
15947
+ "X-Content-Type-Options": "nosniff",
15948
+ "Cache-Control": "no-store",
15949
+ },
15950
+ });
15953
15951
  });
15954
15952
  }
15955
15953