@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.
- package/CHANGELOG.md +2 -0
- package/lib/admin.js +35 -40
- package/lib/asset-manifest.json +1 -1
- package/lib/externaldb-d1.js +31 -21
- package/lib/payment.js +103 -58
- package/lib/referrals.js +10 -6
- package/lib/security-middleware.js +39 -12
- package/lib/site-redirects.js +44 -121
- package/lib/storefront.js +19 -21
- package/lib/vendor/MANIFEST.json +107 -97
- package/lib/vendor/blamejs/CHANGELOG.md +180 -0
- package/lib/vendor/blamejs/NOTICE +14 -10
- package/lib/vendor/blamejs/README.md +17 -5
- package/lib/vendor/blamejs/index.js +2 -0
- package/lib/vendor/blamejs/lib/acme.js +9 -9
- package/lib/vendor/blamejs/lib/api-snapshot.js +35 -16
- package/lib/vendor/blamejs/lib/app-shutdown.js +1 -1
- package/lib/vendor/blamejs/lib/archive-adapters.js +1 -1
- package/lib/vendor/blamejs/lib/archive.js +13 -24
- package/lib/vendor/blamejs/lib/auth/access-lock.js +2 -1
- package/lib/vendor/blamejs/lib/auth/bot-challenge.js +3 -6
- package/lib/vendor/blamejs/lib/auth/ciba.js +32 -3
- package/lib/vendor/blamejs/lib/auth/oauth.js +65 -8
- package/lib/vendor/blamejs/lib/auth/password.js +1 -1
- package/lib/vendor/blamejs/lib/auth/saml.js +21 -3
- package/lib/vendor/blamejs/lib/auth-bot-challenge.js +3 -3
- package/lib/vendor/blamejs/lib/backup/index.js +5 -5
- package/lib/vendor/blamejs/lib/case-fold-classes.js +491 -0
- package/lib/vendor/blamejs/lib/codepoint-class.js +131 -0
- package/lib/vendor/blamejs/lib/constants.js +79 -0
- package/lib/vendor/blamejs/lib/db-declare-view.js +8 -2
- package/lib/vendor/blamejs/lib/error-page.js +20 -1
- package/lib/vendor/blamejs/lib/external-db.js +5 -1
- package/lib/vendor/blamejs/lib/flag-evaluation-context.js +24 -6
- package/lib/vendor/blamejs/lib/flag.js +28 -2
- package/lib/vendor/blamejs/lib/framework-schema.js +14 -3
- package/lib/vendor/blamejs/lib/guard-regex.js +2345 -89
- package/lib/vendor/blamejs/lib/http-client.js +217 -40
- package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +3 -2
- package/lib/vendor/blamejs/lib/mail-dav.js +26 -26
- package/lib/vendor/blamejs/lib/mail-deploy.js +10 -10
- package/lib/vendor/blamejs/lib/mail-scan.js +3 -0
- package/lib/vendor/blamejs/lib/mail-store.js +7 -1
- package/lib/vendor/blamejs/lib/mail.js +5 -1
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/assetlinks.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/compression.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/cors.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/csp-report.js +5 -5
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +2 -2
- package/lib/vendor/blamejs/lib/middleware/deny-response.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/dpop.js +2 -2
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/flag-context.js +17 -0
- package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +10 -8
- package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/require-aal.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/require-auth.js +4 -3
- package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +4 -3
- package/lib/vendor/blamejs/lib/middleware/require-content-type.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/require-methods.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/require-mtls.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/security-txt.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +2 -1
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +1 -1
- package/lib/vendor/blamejs/lib/network-dns.js +3 -3
- package/lib/vendor/blamejs/lib/network-nts.js +35 -14
- package/lib/vendor/blamejs/lib/network-proxy.js +42 -4
- package/lib/vendor/blamejs/lib/network-smtp-policy.js +1 -1
- package/lib/vendor/blamejs/lib/network-tls.js +341 -11
- package/lib/vendor/blamejs/lib/nist-crosswalk.js +2 -2
- package/lib/vendor/blamejs/lib/ntp-check.js +30 -19
- package/lib/vendor/blamejs/lib/object-store/azure-blob.js +1 -1
- package/lib/vendor/blamejs/lib/object-store/gcs.js +1 -1
- package/lib/vendor/blamejs/lib/object-store/http-put.js +2 -1
- package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -5
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +2 -2
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +4 -2
- package/lib/vendor/blamejs/lib/openapi.js +1 -1
- package/lib/vendor/blamejs/lib/pqc-agent.js +4 -7
- package/lib/vendor/blamejs/lib/problem-details.js +2 -1
- package/lib/vendor/blamejs/lib/redis-client.js +12 -1
- package/lib/vendor/blamejs/lib/regex-linear.js +1349 -0
- package/lib/vendor/blamejs/lib/render.js +531 -7
- package/lib/vendor/blamejs/lib/request-helpers.js +181 -5
- package/lib/vendor/blamejs/lib/router.js +37 -13
- package/lib/vendor/blamejs/lib/safe-async.js +142 -0
- package/lib/vendor/blamejs/lib/safe-icap.js +3 -0
- package/lib/vendor/blamejs/lib/safe-sql.js +15 -3
- package/lib/vendor/blamejs/lib/self-update.js +2 -2
- package/lib/vendor/blamejs/lib/testing.js +54 -7
- package/lib/vendor/blamejs/lib/validate-opts.js +56 -0
- package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +62 -25
- package/lib/vendor/blamejs/lib/vendor/blamejs-pki.cjs +2004 -142
- package/lib/vendor/blamejs/lib/vendor/browser/noble-ciphers.mjs +727 -0
- package/lib/vendor/blamejs/lib/vendor/browser/noble-hashes.mjs +1070 -0
- package/lib/vendor/blamejs/lib/vendor/browser/noble-post-quantum.mjs +1090 -0
- package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +510 -227
- package/lib/vendor/blamejs/lib/webhook-hmac.js +19 -2
- package/lib/vendor/blamejs/lib/webhook.js +1 -1
- package/lib/vendor/blamejs/lib/ws-client.js +24 -2
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/sbom.cdx.json +6 -6
- package/lib/webhook-receiver.js +43 -73
- package/package.json +1 -1
|
@@ -94,6 +94,7 @@ function _requireNonEmptyString(val, name) {
|
|
|
94
94
|
* sigField: string, // default: "v1"
|
|
95
95
|
* alg: string, // default: "hmac-sha256" (also "hmac-sha512")
|
|
96
96
|
* toleranceSec: number, // default: 300 (5 minutes)
|
|
97
|
+
* now: number, // epoch ms for the replay window; default: Date.now()
|
|
97
98
|
*
|
|
98
99
|
* @example
|
|
99
100
|
* var v = b.webhookHmac.verify({
|
|
@@ -107,7 +108,8 @@ function verify(opts) {
|
|
|
107
108
|
opts = validateOpts.requireObject(opts, "webhookHmac.verify",
|
|
108
109
|
WebhookHmacError, "webhook-hmac/bad-opts");
|
|
109
110
|
validateOpts(opts,
|
|
110
|
-
["header", "rawBody", "secret", "profile", "tsField", "sigField", "alg", "toleranceSec"
|
|
111
|
+
["header", "rawBody", "secret", "profile", "tsField", "sigField", "alg", "toleranceSec",
|
|
112
|
+
"now"],
|
|
111
113
|
"webhookHmac.verify");
|
|
112
114
|
|
|
113
115
|
// Resolve profile → field/alg defaults; explicit opts win.
|
|
@@ -141,6 +143,21 @@ function verify(opts) {
|
|
|
141
143
|
WebhookHmacError, "webhook-hmac/bad-tolerance");
|
|
142
144
|
var tolerance = typeof opts.toleranceSec === "number" ? opts.toleranceSec : DEFAULT_TOLERANCE_SEC;
|
|
143
145
|
|
|
146
|
+
// Replay window measured against an injectable clock (epoch milliseconds,
|
|
147
|
+
// the shape b.cwt.verify already takes), defaulting to wall time. A caller
|
|
148
|
+
// that owns its own time source -- a receiver built around an injected
|
|
149
|
+
// clock, a forensic replay of a captured delivery, a deterministic
|
|
150
|
+
// simulation -- otherwise has to abandon this primitive and rebuild the
|
|
151
|
+
// scheme by hand, since its window check and this one disagree the moment
|
|
152
|
+
// the injected clock is not now.
|
|
153
|
+
//
|
|
154
|
+
// An injected clock rather than a skip-the-check flag: the replay defense
|
|
155
|
+
// stays inside the primitive, and omitting the option falls back to wall
|
|
156
|
+
// time, so forgetting it fails closed instead of silently accepting an
|
|
157
|
+
// arbitrarily old delivery.
|
|
158
|
+
numericBounds.requirePositiveFiniteIntIfPresent(opts.now, "now",
|
|
159
|
+
WebhookHmacError, "webhook-hmac/bad-now");
|
|
160
|
+
|
|
144
161
|
// Parse "t=<ts>,v1=<sig>,v1=<rotated>" — comma-separated k=v. Collect the ts
|
|
145
162
|
// and EVERY sigField value; ignore any other version keys.
|
|
146
163
|
var tsRaw = null;
|
|
@@ -169,7 +186,7 @@ function verify(opts) {
|
|
|
169
186
|
throw new WebhookHmacError("webhook-hmac/bad-timestamp",
|
|
170
187
|
"verify: '" + tsField + "' is not a positive integer");
|
|
171
188
|
}
|
|
172
|
-
var nowSec = Math.floor(Date.now() / 1000);
|
|
189
|
+
var nowSec = Math.floor((typeof opts.now === "number" ? opts.now : Date.now()) / 1000);
|
|
173
190
|
var skew = Math.abs(nowSec - ts);
|
|
174
191
|
if (skew > tolerance) {
|
|
175
192
|
throw new WebhookHmacError("webhook-hmac/timestamp-skew",
|
|
@@ -485,7 +485,7 @@ function signer(opts) {
|
|
|
485
485
|
}, retryOpts);
|
|
486
486
|
var statusCode = (res && (res.statusCode || res.status)) || 0;
|
|
487
487
|
_emitEvent("webhook.send", 1, {
|
|
488
|
-
outcome: statusCode
|
|
488
|
+
outcome: C.HTTP.success(statusCode) ? "success" : "failure",
|
|
489
489
|
status: statusCode,
|
|
490
490
|
host: hostLabel,
|
|
491
491
|
});
|
|
@@ -381,7 +381,23 @@ class WsClient extends EventEmitter {
|
|
|
381
381
|
(parsed.protocol === "wss:" ? 443 : 80); // TLS / HTTP default port
|
|
382
382
|
var host = parsed.hostname;
|
|
383
383
|
|
|
384
|
-
|
|
384
|
+
// Filled in on the wss:// path below with the options the dial actually
|
|
385
|
+
// used. dialTlsOpts is merged OVER the shared posture, so a caller that
|
|
386
|
+
// narrowed ecdhCurve or moved minVersion negotiated on something the
|
|
387
|
+
// shared object does not describe, and diagnosing against the shared one
|
|
388
|
+
// would answer for a connection that was never made.
|
|
389
|
+
var effectiveTls = null;
|
|
390
|
+
|
|
391
|
+
function _onError(err) {
|
|
392
|
+
// A wss:// handshake refused by the posture arrives as a bare OpenSSL
|
|
393
|
+
// alert; name the cause before it reaches the caller's handler.
|
|
394
|
+
networkTls().annotateOutboundFailure(err, {
|
|
395
|
+
host: host,
|
|
396
|
+
port: port,
|
|
397
|
+
tlsOpts: effectiveTls || {},
|
|
398
|
+
});
|
|
399
|
+
self._handleSocketError(err);
|
|
400
|
+
}
|
|
385
401
|
|
|
386
402
|
// Pin the connect to the SSRF-validated IPs returned by
|
|
387
403
|
// ssrfGuard.checkUrl — closes the DNS-rebinding TOCTOU window where
|
|
@@ -413,6 +429,12 @@ class WsClient extends EventEmitter {
|
|
|
413
429
|
port: port,
|
|
414
430
|
rejectUnauthorized: true,
|
|
415
431
|
}, networkTls().outboundPosture(), dialTlsOpts || {});
|
|
432
|
+
// The posture advertises RFC 8879 certificate compression, which is a
|
|
433
|
+
// TLS 1.3 extension. A caller who capped this dial lower asked for none
|
|
434
|
+
// of it, and Node refuses the whole options object rather than ignoring
|
|
435
|
+
// an extension it cannot use.
|
|
436
|
+
networkTls()._stripUnreachableCertCompression(tlsOpts, dialTlsOpts);
|
|
437
|
+
effectiveTls = tlsOpts;
|
|
416
438
|
// RFC 6066 §3: the TLS SNI ServerName MUST be a hostname, never an IP
|
|
417
439
|
// literal — Node throws ERR_INVALID_ARG_VALUE when servername is an IP,
|
|
418
440
|
// which made wss:// to any IP-literal target unusable. Send SNI only for
|
|
@@ -541,7 +563,7 @@ class WsClient extends EventEmitter {
|
|
|
541
563
|
return;
|
|
542
564
|
}
|
|
543
565
|
var status = parseInt(match[1], 10);
|
|
544
|
-
if (status !==
|
|
566
|
+
if (status !== C.HTTP.STATUS.SWITCHING_PROTOCOLS) { // HTTP 101
|
|
545
567
|
// Body bytes after the header section are the server's
|
|
546
568
|
// explanation. Surface them on the error so callers can branch
|
|
547
569
|
// on the status code and inspect the body without re-parsing
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.5",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:885de67e-71f9-4512-83e7-3538ecfd9d88",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-08-
|
|
8
|
+
"timestamp": "2026-08-10T21:28:58.997Z",
|
|
9
9
|
"lifecycles": [
|
|
10
10
|
{
|
|
11
11
|
"phase": "build"
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
}
|
|
20
20
|
],
|
|
21
21
|
"component": {
|
|
22
|
-
"bom-ref": "@blamejs/core@0.18.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.18.21",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.18.
|
|
25
|
+
"version": "0.18.21",
|
|
26
26
|
"scope": "required",
|
|
27
27
|
"author": "blamejs contributors",
|
|
28
28
|
"description": "The Node framework that owns its stack.",
|
|
29
|
-
"purl": "pkg:npm/%40blamejs/core@0.18.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.18.21",
|
|
30
30
|
"properties": [],
|
|
31
31
|
"externalReferences": [
|
|
32
32
|
{
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"components": [],
|
|
55
55
|
"dependencies": [
|
|
56
56
|
{
|
|
57
|
-
"ref": "@blamejs/core@0.18.
|
|
57
|
+
"ref": "@blamejs/core@0.18.21",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|
package/lib/webhook-receiver.js
CHANGED
|
@@ -44,12 +44,14 @@
|
|
|
44
44
|
* - `b.crypto.namespaceHash` — secret-at-rest fingerprint.
|
|
45
45
|
* - `b.crypto.sha3Hash` — body fingerprint for audit.
|
|
46
46
|
* - `b.crypto.generateBytes` — secret plaintext draw.
|
|
47
|
-
* - `b.crypto.timingSafeEqual` — constant-time hex compare on
|
|
48
|
-
* secret-hash
|
|
49
|
-
* - `b.
|
|
50
|
-
*
|
|
51
|
-
* (
|
|
52
|
-
* the
|
|
47
|
+
* - `b.crypto.timingSafeEqual` — constant-time hex compare on the
|
|
48
|
+
* secret-hash match.
|
|
49
|
+
* - `b.webhookHmac.verify` — the whole `t=<ts>,v1=<hex>` scheme:
|
|
50
|
+
* HMAC-SHA-256 over `<timestamp>.<raw-body>`,
|
|
51
|
+
* the replay window (on this receiver's
|
|
52
|
+
* injected clock and the source row's
|
|
53
|
+
* tolerance), and a constant-time compare
|
|
54
|
+
* across every signature the header carries.
|
|
53
55
|
* - `b.uuid.v7` — row ids.
|
|
54
56
|
*
|
|
55
57
|
* Surface:
|
|
@@ -305,34 +307,6 @@ function _hashSecret(canonical) {
|
|
|
305
307
|
return b.crypto.namespaceHash(SECRET_NAMESPACE, canonical);
|
|
306
308
|
}
|
|
307
309
|
|
|
308
|
-
// Extract the v1 hex tag from a `t=<ts>,v1=<hex>` Stripe-shape header
|
|
309
|
-
// produced by b.webhook.sign. We pin to this composition rather than
|
|
310
|
-
// reach for node:crypto so the receiver inherits whatever HMAC-SHA-256
|
|
311
|
-
// hardening lives in the vendored blamejs surface.
|
|
312
|
-
function _hmacSha256Hex(secretPlaintext, timestampSeconds, bodyString) {
|
|
313
|
-
var header = b.webhook.sign({
|
|
314
|
-
alg: "hmac-sha256-stripe",
|
|
315
|
-
secret: secretPlaintext,
|
|
316
|
-
body: bodyString,
|
|
317
|
-
timestamp: timestampSeconds,
|
|
318
|
-
});
|
|
319
|
-
// Header shape is `t=<ts>,v1=<hex>` — the marker is the only place
|
|
320
|
-
// ",v1=" appears so a literal indexOf is the canonical parse.
|
|
321
|
-
var marker = ",v1=";
|
|
322
|
-
var i = header.indexOf(marker);
|
|
323
|
-
if (i < 0) {
|
|
324
|
-
// Defensive: a future blamejs version that changes the shape
|
|
325
|
-
// would slip past silently if we returned an empty string. Throw
|
|
326
|
-
// loudly so the operator notices at deploy time, not at the
|
|
327
|
-
// first inbound webhook.
|
|
328
|
-
throw new Error(
|
|
329
|
-
"webhookReceiver: b.webhook.sign returned an unexpected header shape " +
|
|
330
|
-
"(no ',v1=' marker) — vendored blamejs may need a refresh"
|
|
331
|
-
);
|
|
332
|
-
}
|
|
333
|
-
return header.slice(i + marker.length);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
310
|
// ---- factory ------------------------------------------------------------
|
|
337
311
|
|
|
338
312
|
function create(opts) {
|
|
@@ -610,40 +584,9 @@ function create(opts) {
|
|
|
610
584
|
timestamp_out_of_window: false,
|
|
611
585
|
};
|
|
612
586
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
ok: false,
|
|
617
|
-
event_id: null,
|
|
618
|
-
replay: false,
|
|
619
|
-
signature_invalid: true,
|
|
620
|
-
timestamp_out_of_window: false,
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
// Replay-window check. The third-party's timestamp must land
|
|
625
|
-
// within ±replay_window_seconds of the receiver's current
|
|
626
|
-
// wall-clock. We accept future-skewed timestamps inside the
|
|
627
|
-
// window (a peer with a slightly fast clock shouldn't reject)
|
|
628
|
-
// but not arbitrarily-future timestamps that would let an
|
|
629
|
-
// attacker bypass replay protection by stamping a fresh ts.
|
|
630
|
-
var windowSec = Number(sourceRow.replay_window_seconds);
|
|
631
|
-
var nowSec = Math.floor(nowMs / 1000);
|
|
632
|
-
var ageSec = Math.abs(nowSec - timestampSeconds);
|
|
633
|
-
if (ageSec > windowSec) {
|
|
634
|
-
return {
|
|
635
|
-
ok: false,
|
|
636
|
-
event_id: null,
|
|
637
|
-
replay: false,
|
|
638
|
-
signature_invalid: false,
|
|
639
|
-
timestamp_out_of_window: true,
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// Signature validation. The third-party signs the literal
|
|
644
|
-
// `<timestamp>.<body>` string with HMAC-SHA-256 under the
|
|
645
|
-
// secret. We recompute via b.webhook.sign and constant-time-
|
|
646
|
-
// compare the supplied hex against the expected hex.
|
|
587
|
+
// The signature must be exactly the hex digest before it is composed
|
|
588
|
+
// into the header below — a value carrying a comma or an `=` would
|
|
589
|
+
// otherwise add fields the parser reads as its own.
|
|
647
590
|
var supplied = input.signature_header.trim().toLowerCase();
|
|
648
591
|
if (!SIGNATURE_HEX_RE.test(supplied)) {
|
|
649
592
|
return {
|
|
@@ -654,15 +597,42 @@ function create(opts) {
|
|
|
654
597
|
timestamp_out_of_window: false,
|
|
655
598
|
};
|
|
656
599
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
600
|
+
|
|
601
|
+
// Signature + replay window, both from b.webhookHmac. It owns this exact
|
|
602
|
+
// scheme — `t=<ts>,v1=<hex>` over `<timestamp>.<raw-body>` — including
|
|
603
|
+
// the strict-integer timestamp, the skew window, a constant-time compare
|
|
604
|
+
// and multi-signature support for a rotated secret. This receiver takes
|
|
605
|
+
// its clock from the operator (opts.now) and its window from the source
|
|
606
|
+
// row, so both are passed in; the primitive gained the clock argument in
|
|
607
|
+
// 0.18.18, which is what made composing it possible at all.
|
|
608
|
+
//
|
|
609
|
+
// The body goes in as BYTES. Signing a UTF-8 string rebuild of it
|
|
610
|
+
// replaces anything that is not valid UTF-8 with U+FFFD, taking the
|
|
611
|
+
// digest over different bytes than the sender signed and rejecting a
|
|
612
|
+
// correctly-signed delivery. The timestamp goes in as the raw header
|
|
613
|
+
// text rather than a reparsed integer for the same reason.
|
|
614
|
+
var windowSec = Number(sourceRow.replay_window_seconds);
|
|
615
|
+
try {
|
|
616
|
+
b.webhookHmac.verify({
|
|
617
|
+
header: "t=" + tsStr + ",v1=" + supplied,
|
|
618
|
+
rawBody: bodyBytes,
|
|
619
|
+
secret: matched.plaintext,
|
|
620
|
+
profile: "stripe",
|
|
621
|
+
toleranceSec: windowSec,
|
|
622
|
+
now: nowMs,
|
|
623
|
+
});
|
|
624
|
+
} catch (e) {
|
|
625
|
+
// Out-of-window and bad-signature are distinct outcomes to an operator
|
|
626
|
+
// reading the delivery log: one is a clock or a replay, the other is a
|
|
627
|
+
// wrong secret. Every other refusal is a malformed header, which is
|
|
628
|
+
// not a signature the receiver can accept.
|
|
629
|
+
var skew = e && e.code === "webhook-hmac/timestamp-skew";
|
|
660
630
|
return {
|
|
661
631
|
ok: false,
|
|
662
632
|
event_id: null,
|
|
663
633
|
replay: false,
|
|
664
|
-
signature_invalid:
|
|
665
|
-
timestamp_out_of_window:
|
|
634
|
+
signature_invalid: !skew,
|
|
635
|
+
timestamp_out_of_window: skew,
|
|
666
636
|
};
|
|
667
637
|
}
|
|
668
638
|
|
package/package.json
CHANGED