@blamejs/blamejs-shop 0.0.128 → 0.1.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/CHANGELOG.md +6 -0
- package/README.md +2 -0
- package/lib/admin.js +1 -2
- package/lib/affiliates.js +4 -3
- package/lib/analytics.js +3 -2
- package/lib/api-keys.js +1 -1
- package/lib/assembly-instructions.js +2 -1
- package/lib/auto-replenish.js +4 -3
- package/lib/backorder.js +2 -1
- package/lib/business-hours.js +8 -1
- package/lib/carrier-accounts.js +1 -1
- package/lib/carrier-rates.js +1 -1
- package/lib/cart-abandonment.js +3 -2
- package/lib/cart-bulk-ops.js +2 -1
- package/lib/cart-recovery.js +5 -4
- package/lib/cart.js +6 -2
- package/lib/catalog-drafts.js +1 -1
- package/lib/click-and-collect.js +3 -2
- package/lib/clickstream.js +4 -3
- package/lib/config.js +2 -1
- package/lib/cookie-consent.js +2 -1
- package/lib/credit-limits.js +2 -1
- package/lib/currency-display.js +2 -1
- package/lib/customer-activity.js +3 -2
- package/lib/customer-impersonation.js +3 -3
- package/lib/customer-merge.js +4 -3
- package/lib/customer-portal.js +4 -4
- package/lib/customer-risk-profile.js +2 -1
- package/lib/customer-segments.js +2 -1
- package/lib/customer-surveys.js +6 -3
- package/lib/delivery-estimate.js +2 -2
- package/lib/demand-forecast.js +2 -1
- package/lib/discount-analytics.js +2 -2
- package/lib/dunning.js +4 -1
- package/lib/email-warmup.js +6 -1
- package/lib/email.js +1 -8
- package/lib/error-log.js +3 -2
- package/lib/event-log.js +3 -2
- package/lib/fraud-screen.js +3 -1
- package/lib/fulfillment-sla.js +3 -1
- package/lib/index.js +11 -3
- package/lib/inventory-allocations.js +3 -0
- package/lib/inventory-snapshots.js +2 -1
- package/lib/invoice-renderer.js +2 -1
- package/lib/line-gift-wrap.js +6 -1
- package/lib/live-chat.js +2 -1
- package/lib/loyalty-redemption.js +2 -1
- package/lib/newsletter.js +6 -1
- package/lib/operator-activity-feed.js +4 -3
- package/lib/operator-sessions.js +7 -7
- package/lib/order-exchanges.js +1 -0
- package/lib/order-timeline.js +2 -1
- package/lib/payment-retries.js +2 -1
- package/lib/payment.js +5 -4
- package/lib/pixel-events.js +6 -5
- package/lib/preorder.js +2 -1
- package/lib/print-queue.js +2 -1
- package/lib/product-compare.js +2 -1
- package/lib/product-qa.js +2 -1
- package/lib/push-notifications.js +6 -5
- package/lib/recently-viewed.js +7 -2
- package/lib/recommendations.js +7 -2
- package/lib/referral-leaderboard.js +2 -1
- package/lib/refund-automation.js +1 -1
- package/lib/refund-policy.js +1 -1
- package/lib/reorder-reminders.js +2 -1
- package/lib/reorder-thresholds.js +2 -1
- package/lib/robots-config.js +1 -0
- package/lib/sales-reports.js +17 -14
- package/lib/sales-tax-filings.js +2 -1
- package/lib/save-for-later.js +2 -1
- package/lib/search-suggestions.js +1 -1
- package/lib/shipping-insurance.js +2 -1
- package/lib/shipping-labels.js +3 -2
- package/lib/shipping-zones.js +1 -0
- package/lib/shrinkage-report.js +9 -8
- package/lib/sms-dispatcher.js +6 -5
- package/lib/stock-alerts.js +1 -1
- package/lib/stock-receipts.js +2 -1
- package/lib/store-credit.js +2 -1
- package/lib/storefront-forms.js +1 -1
- package/lib/storefront.js +223 -141
- package/lib/subscription-analytics.js +7 -2
- package/lib/subscription-controls.js +9 -8
- package/lib/subscription-gifts.js +2 -1
- package/lib/subscriptions.js +2 -0
- package/lib/support-tickets.js +4 -4
- package/lib/tax-cert-renewals.js +2 -1
- package/lib/tax-remittance.js +2 -1
- package/lib/theme-assets.js +1 -1
- package/lib/vendor/MANIFEST.json +2 -2
- package/lib/vendor/blamejs/CHANGELOG.md +4 -0
- package/lib/vendor/blamejs/README.md +2 -0
- package/lib/vendor/blamejs/api-snapshot.json +122 -2
- package/lib/vendor/blamejs/index.js +2 -0
- package/lib/vendor/blamejs/lib/did.js +367 -0
- package/lib/vendor/blamejs/lib/mdoc.js +305 -0
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.12.40.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.12.41.json +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +27 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/did.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mdoc.test.js +230 -0
- package/lib/vendor-invoices.js +1 -1
- package/lib/webhook-receiver.js +8 -2
- package/lib/webhook-subscriptions.js +1 -1
- package/lib/webhooks.js +6 -5
- package/lib/winback-campaigns.js +2 -1
- package/lib/wishlist-alerts.js +2 -1
- package/lib/wishlist-digest.js +2 -1
- package/package.json +1 -1
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Layer 0 — b.mdoc (ISO 18013-5 mdoc / mDL issuer-data verification).
|
|
4
|
+
* A pure-node mock issuer builds an IssuerSigned structure (COSE_Sign1
|
|
5
|
+
* IssuerAuth over a Tag-24 MobileSecurityObject, with the signer cert in
|
|
6
|
+
* the x5chain header) so the verifier's full path is exercised: COSE
|
|
7
|
+
* signature, MSO validity window, per-element digest matching against
|
|
8
|
+
* the MSO, selective disclosure, and the tamper / expiry / docType /
|
|
9
|
+
* malformed-validity refusal paths. The trust core (COSE_Sign1 + CBOR)
|
|
10
|
+
* is the framework's tested b.cose / b.cbor substrate.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
var b = require("../../index");
|
|
14
|
+
var helpers = require("../helpers");
|
|
15
|
+
var check = helpers.check;
|
|
16
|
+
var asn1 = require("../../lib/asn1-der");
|
|
17
|
+
var cbor = b.cbor;
|
|
18
|
+
var nodeCrypto = require("node:crypto");
|
|
19
|
+
|
|
20
|
+
var NS = "org.iso.18013.5.1";
|
|
21
|
+
var DOCTYPE = "org.iso.18013.5.1.mDL";
|
|
22
|
+
|
|
23
|
+
function _algId(oid, withNull) {
|
|
24
|
+
return withNull ? asn1.writeSequence([asn1.writeOid(oid), asn1.writeNull()]) : asn1.writeSequence([asn1.writeOid(oid)]);
|
|
25
|
+
}
|
|
26
|
+
function _name(cn) {
|
|
27
|
+
return asn1.writeSequence([asn1.writeSet([asn1.writeSequence([asn1.writeOid("2.5.4.3"), asn1.writeUtf8String(cn)])])]);
|
|
28
|
+
}
|
|
29
|
+
function _utc(d) { return asn1.writeNode(0x17, Buffer.from(d.toISOString().replace(/[-:T]/g, "").slice(2, 14) + "Z", "ascii")); }
|
|
30
|
+
|
|
31
|
+
// Minimal self-signed EC cert (mdoc issuer-data verify reads the key,
|
|
32
|
+
// not an EKU). Returns { certDer, key, pem }.
|
|
33
|
+
function _makeCert(cn) {
|
|
34
|
+
var kp = nodeCrypto.generateKeyPairSync("ec", { namedCurve: "P-256" });
|
|
35
|
+
var spki = kp.publicKey.export({ type: "spki", format: "der" });
|
|
36
|
+
var sa = _algId("1.2.840.10045.4.3.2", false);
|
|
37
|
+
var nm = _name(cn || "mDL Issuer");
|
|
38
|
+
var now = Date.now();
|
|
39
|
+
var tbs = asn1.writeSequence([
|
|
40
|
+
asn1.writeContextExplicit(0, asn1.writeInteger(Buffer.from([2]))),
|
|
41
|
+
asn1.writeInteger(Buffer.from([0x2a])), sa, nm,
|
|
42
|
+
asn1.writeSequence([_utc(new Date(now - 86400000)), _utc(new Date(now + 86400000 * 3650))]),
|
|
43
|
+
nm, spki,
|
|
44
|
+
]);
|
|
45
|
+
var certDer = asn1.writeSequence([tbs, sa, asn1.writeBitString(nodeCrypto.sign("sha256", tbs, kp.privateKey), 0)]);
|
|
46
|
+
return { certDer: certDer, key: kp.privateKey, pem: new nodeCrypto.X509Certificate(certDer).toString() };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Build an IssuerSigned (CBOR bytes). opts: { elements, validFrom,
|
|
50
|
+
// validUntil, docType, digestAlg } — defaults are a valid mDL.
|
|
51
|
+
async function _makeMdoc(cert, opts) {
|
|
52
|
+
opts = opts || {};
|
|
53
|
+
var elements = opts.elements || [["family_name", "Doe"], ["age_over_18", true], ["given_name", "Jane"]];
|
|
54
|
+
var digestNode = opts.digestNode || "sha256";
|
|
55
|
+
var digestAlg = opts.digestAlg || "SHA-256";
|
|
56
|
+
var now = Date.now();
|
|
57
|
+
var items = [];
|
|
58
|
+
var digests = new Map();
|
|
59
|
+
elements.forEach(function (el, i) {
|
|
60
|
+
var inner = cbor.encode(new Map([
|
|
61
|
+
["digestID", i], ["random", nodeCrypto.randomBytes(32)],
|
|
62
|
+
["elementIdentifier", el[0]], ["elementValue", el[1]],
|
|
63
|
+
]));
|
|
64
|
+
items.push(new cbor.Tag(24, inner));
|
|
65
|
+
digests.set(i, nodeCrypto.createHash(digestNode).update(cbor.encode(new cbor.Tag(24, inner))).digest());
|
|
66
|
+
});
|
|
67
|
+
var validFromMs = opts.validFrom != null ? opts.validFrom : now - 86400000;
|
|
68
|
+
var validUntilMs = opts.validUntil != null ? opts.validUntil : now + 86400000 * 3650;
|
|
69
|
+
var validUntilTag = opts.validUntilRaw !== undefined ? opts.validUntilRaw : new cbor.Tag(0, new Date(validUntilMs).toISOString());
|
|
70
|
+
var mso = new Map([
|
|
71
|
+
["version", "1.0"], ["digestAlgorithm", digestAlg], ["docType", opts.docType || DOCTYPE],
|
|
72
|
+
["valueDigests", new Map([[NS, digests]])],
|
|
73
|
+
["validityInfo", new Map([
|
|
74
|
+
["signed", new cbor.Tag(0, new Date(now).toISOString())],
|
|
75
|
+
["validFrom", new cbor.Tag(0, new Date(validFromMs).toISOString())],
|
|
76
|
+
["validUntil", validUntilTag],
|
|
77
|
+
])],
|
|
78
|
+
]);
|
|
79
|
+
var payload = cbor.encode(new cbor.Tag(24, cbor.encode(mso)));
|
|
80
|
+
var signed = await b.cose.sign(payload, { alg: opts.alg || "ES256", privateKey: cert.key, unprotectedHeaders: { 33: cert.certDer } });
|
|
81
|
+
var issuerAuth = cbor.decode(signed, { allowedTags: [18, 24] }).value;
|
|
82
|
+
return cbor.encode(new Map([["nameSpaces", new Map([[NS, items]])], ["issuerAuth", issuerAuth]]));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function testSurface() {
|
|
86
|
+
check("b.mdoc.verifyIssuerSigned is a function", typeof b.mdoc.verifyIssuerSigned === "function");
|
|
87
|
+
check("b.mdoc.DIGEST_ALGS has SHA-256", b.mdoc.DIGEST_ALGS["SHA-256"] === "sha256");
|
|
88
|
+
check("b.mdoc.MdocError is a class", typeof b.mdoc.MdocError === "function");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function testRoundTrip() {
|
|
92
|
+
var cert = _makeCert();
|
|
93
|
+
var mdoc = await _makeMdoc(cert);
|
|
94
|
+
var out = await b.mdoc.verifyIssuerSigned(mdoc, { algorithms: ["ES256"], expectedDocType: DOCTYPE });
|
|
95
|
+
check("verify: docType", out.docType === DOCTYPE);
|
|
96
|
+
check("verify: alg reported", out.alg === "ES256");
|
|
97
|
+
check("verify: digestAlgorithm", out.digestAlgorithm === "SHA-256");
|
|
98
|
+
check("verify: disclosed elements extracted", out.namespaces[NS].family_name === "Doe" && out.namespaces[NS].age_over_18 === true && out.namespaces[NS].given_name === "Jane");
|
|
99
|
+
check("verify: validityInfo dates returned", out.validityInfo.validUntil instanceof Date);
|
|
100
|
+
check("verify: signerCert PEM returned", /BEGIN CERTIFICATE/.test(out.signerCert));
|
|
101
|
+
|
|
102
|
+
// chain verify against the self-signed issuer as anchor
|
|
103
|
+
var ok = await b.mdoc.verifyIssuerSigned(mdoc, { algorithms: ["ES256"], trustAnchorsPem: cert.pem });
|
|
104
|
+
check("verify: chain to issuer anchor (string)", ok.docType === DOCTYPE);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function testDigestAndSignatureRefusals() {
|
|
108
|
+
var cert = _makeCert();
|
|
109
|
+
var mdoc = await _makeMdoc(cert);
|
|
110
|
+
|
|
111
|
+
// Tamper a disclosed element's value: re-pack one IssuerSignedItem
|
|
112
|
+
// with a changed value but keep the MSO digest → digest mismatch.
|
|
113
|
+
var top = cbor.decode(mdoc, { allowedTags: [0, 1, 24, 1004] });
|
|
114
|
+
var items = top.get("nameSpaces").get(NS);
|
|
115
|
+
var inner0 = cbor.decode(items[0].value, { allowedTags: [0, 1, 24, 1004] });
|
|
116
|
+
inner0.set("elementValue", "Tampered");
|
|
117
|
+
items[0] = new cbor.Tag(24, cbor.encode(inner0));
|
|
118
|
+
var tampered = cbor.encode(top);
|
|
119
|
+
var e1 = null;
|
|
120
|
+
try { await b.mdoc.verifyIssuerSigned(tampered, { algorithms: ["ES256"] }); } catch (e) { e1 = e; }
|
|
121
|
+
check("verify: tampered element refused (digest-mismatch)", e1 && e1.code === "mdoc/digest-mismatch");
|
|
122
|
+
|
|
123
|
+
// Tamper the COSE signature deterministically (flip a byte in the
|
|
124
|
+
// issuerAuth signature element) → bad-signature.
|
|
125
|
+
var top2 = cbor.decode(mdoc, { allowedTags: [0, 1, 24, 1004] });
|
|
126
|
+
var ia = top2.get("issuerAuth");
|
|
127
|
+
ia[3] = Buffer.from(ia[3]); ia[3][0] ^= 0xff;
|
|
128
|
+
var bad = cbor.encode(top2);
|
|
129
|
+
var e2 = null;
|
|
130
|
+
try { await b.mdoc.verifyIssuerSigned(bad, { algorithms: ["ES256"] }); } catch (e) { e2 = e; }
|
|
131
|
+
check("verify: tampered COSE signature refused", e2 && e2.code === "cose/bad-signature");
|
|
132
|
+
|
|
133
|
+
// A malformed x5chain certificate surfaces a clean error (not raw OpenSSL).
|
|
134
|
+
var top3 = cbor.decode(mdoc, { allowedTags: [0, 1, 24, 1004] });
|
|
135
|
+
top3.get("issuerAuth")[1].set(33, Buffer.from([0x30, 0x03, 0x02, 0x01, 0x01]));
|
|
136
|
+
var e6 = null;
|
|
137
|
+
try { await b.mdoc.verifyIssuerSigned(cbor.encode(top3), { algorithms: ["ES256"] }); } catch (e) { e6 = e; }
|
|
138
|
+
check("verify: malformed x5chain cert refused cleanly", e6 && e6.code === "mdoc/bad-cert");
|
|
139
|
+
|
|
140
|
+
// alg outside allowlist
|
|
141
|
+
var e3 = null;
|
|
142
|
+
try { await b.mdoc.verifyIssuerSigned(mdoc, { algorithms: ["EdDSA"] }); } catch (e) { e3 = e; }
|
|
143
|
+
check("verify: alg outside allowlist refused", e3 && (e3.code === "cose/alg-not-allowed"));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function testValidityAndDocType() {
|
|
147
|
+
var cert = _makeCert();
|
|
148
|
+
|
|
149
|
+
// expired (valid window 10 days ago .. 1 day ago)
|
|
150
|
+
var expired = await _makeMdoc(cert, { validFrom: Date.now() - 86400000 * 10, validUntil: Date.now() - 86400000 });
|
|
151
|
+
var e1 = null;
|
|
152
|
+
try { await b.mdoc.verifyIssuerSigned(expired, { algorithms: ["ES256"] }); } catch (e) { e1 = e; }
|
|
153
|
+
check("verify: expired credential refused", e1 && e1.code === "mdoc/expired");
|
|
154
|
+
|
|
155
|
+
// not yet valid
|
|
156
|
+
var future = await _makeMdoc(cert, { validFrom: Date.now() + 86400000 * 30 });
|
|
157
|
+
var e2 = null;
|
|
158
|
+
try { await b.mdoc.verifyIssuerSigned(future, { algorithms: ["ES256"] }); } catch (e) { e2 = e; }
|
|
159
|
+
check("verify: not-yet-valid credential refused", e2 && e2.code === "mdoc/not-yet-valid");
|
|
160
|
+
|
|
161
|
+
// opts.at within window accepts an otherwise-expired credential
|
|
162
|
+
var ok = await b.mdoc.verifyIssuerSigned(expired, { algorithms: ["ES256"], at: new Date(Date.now() - 86400000 * 2) });
|
|
163
|
+
check("verify: opts.at within window accepts", ok.docType === DOCTYPE);
|
|
164
|
+
|
|
165
|
+
// docType mismatch
|
|
166
|
+
var e3 = null;
|
|
167
|
+
try { await b.mdoc.verifyIssuerSigned(await _makeMdoc(cert), { algorithms: ["ES256"], expectedDocType: "org.iso.18013.5.1.photoID" }); } catch (e) { e3 = e; }
|
|
168
|
+
check("verify: docType mismatch refused", e3 && e3.code === "mdoc/doctype-mismatch");
|
|
169
|
+
|
|
170
|
+
// malformed validUntil (a non-date) fails closed
|
|
171
|
+
var badValidity = await _makeMdoc(cert, { validUntilRaw: new cbor.Tag(0, "not-a-date") });
|
|
172
|
+
var e4 = null;
|
|
173
|
+
try { await b.mdoc.verifyIssuerSigned(badValidity, { algorithms: ["ES256"] }); } catch (e) { e4 = e; }
|
|
174
|
+
check("verify: malformed validUntil refused (fail closed)", e4 && e4.code === "mdoc/bad-validity");
|
|
175
|
+
|
|
176
|
+
// invalid opts.at refused (lesson carried from b.tsa / b.vc)
|
|
177
|
+
var e5 = null;
|
|
178
|
+
try { await b.mdoc.verifyIssuerSigned(await _makeMdoc(cert), { algorithms: ["ES256"], at: new Date("nope") }); } catch (e) { e5 = e; }
|
|
179
|
+
check("verify: invalid opts.at refused", e5 && e5.code === "mdoc/bad-at");
|
|
180
|
+
|
|
181
|
+
// Two signed IssuerSignedItems with the same elementIdentifier (each
|
|
182
|
+
// with a valid MSO digest) is ambiguous → fail closed, not last-wins.
|
|
183
|
+
var dup = await _makeMdoc(cert, { elements: [["family_name", "Doe"], ["family_name", "Roe"]] });
|
|
184
|
+
var e6 = null;
|
|
185
|
+
try { await b.mdoc.verifyIssuerSigned(dup, { algorithms: ["ES256"] }); } catch (e) { e6 = e; }
|
|
186
|
+
check("verify: duplicate elementIdentifier refused", e6 && e6.code === "mdoc/duplicate-element");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function testChainAndInputGuards() {
|
|
190
|
+
var cert = _makeCert();
|
|
191
|
+
var mdoc = await _makeMdoc(cert);
|
|
192
|
+
|
|
193
|
+
// unrelated anchor → untrusted
|
|
194
|
+
var other = _makeCert("Unrelated Root");
|
|
195
|
+
var e1 = null;
|
|
196
|
+
try { await b.mdoc.verifyIssuerSigned(mdoc, { algorithms: ["ES256"], trustAnchorsPem: [other.pem] }); } catch (e) { e1 = e; }
|
|
197
|
+
check("verify: unrelated anchor refused", e1 && e1.code === "mdoc/untrusted-chain");
|
|
198
|
+
|
|
199
|
+
// empty trust-anchor shape refused (no fail-open)
|
|
200
|
+
var e2 = null;
|
|
201
|
+
try { await b.mdoc.verifyIssuerSigned(mdoc, { algorithms: ["ES256"], trustAnchorsPem: [] }); } catch (e) { e2 = e; }
|
|
202
|
+
check("verify: empty trustAnchorsPem refused", e2 && e2.code === "mdoc/bad-trust-anchors");
|
|
203
|
+
|
|
204
|
+
// garbage input → not CBOR / malformed
|
|
205
|
+
var e3 = null;
|
|
206
|
+
try { await b.mdoc.verifyIssuerSigned(Buffer.from([0x00, 0x01]), { algorithms: ["ES256"] }); } catch (e) { e3 = e; }
|
|
207
|
+
check("verify: garbage input refused", e3 && (e3.code === "mdoc/malformed" || e3.code === "mdoc/bad-input" || /cbor/.test(e3.code || "")));
|
|
208
|
+
|
|
209
|
+
// missing algorithms
|
|
210
|
+
var e4 = null;
|
|
211
|
+
try { await b.mdoc.verifyIssuerSigned(mdoc, {}); } catch (e) { e4 = e; }
|
|
212
|
+
check("verify: missing algorithms refused", e4 && e4.code === "mdoc/algorithms-required");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function run() {
|
|
216
|
+
testSurface();
|
|
217
|
+
await testRoundTrip();
|
|
218
|
+
await testDigestAndSignatureRefusals();
|
|
219
|
+
await testValidityAndDocType();
|
|
220
|
+
await testChainAndInputGuards();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
module.exports = { run: run };
|
|
224
|
+
|
|
225
|
+
if (require.main === module) {
|
|
226
|
+
run().then(
|
|
227
|
+
function () { console.log("[mdoc] OK — " + helpers.getChecks() + " checks passed"); },
|
|
228
|
+
function (e) { console.error("FAIL:", e && e.stack || e); process.exit(1); }
|
|
229
|
+
);
|
|
230
|
+
}
|
package/lib/vendor-invoices.js
CHANGED
|
@@ -106,7 +106,7 @@ var INVOICE_STATUSES = Object.freeze([
|
|
|
106
106
|
|
|
107
107
|
var MAX_DUE_WITHIN_DAYS = 3650; // ~10 years — bound the predicate
|
|
108
108
|
|
|
109
|
-
var MS_PER_DAY =
|
|
109
|
+
var MS_PER_DAY = _b().constants.TIME.days(1);
|
|
110
110
|
|
|
111
111
|
// Aging buckets (days past due, inclusive at upper bound). `current`
|
|
112
112
|
// is anything with due_date >= as_of; the rest are the canonical
|
package/lib/webhook-receiver.js
CHANGED
|
@@ -76,16 +76,22 @@
|
|
|
76
76
|
* @related b.crypto, b.webhook, b.uuid
|
|
77
77
|
*/
|
|
78
78
|
|
|
79
|
+
// `_b()` is a hoisted function declaration (defined below), so resolving
|
|
80
|
+
// the framework constants here at module-eval is safe — the index entry
|
|
81
|
+
// point exposes `framework` before the require cascade.
|
|
82
|
+
var C = _b().constants;
|
|
83
|
+
|
|
79
84
|
var SECRET_NAMESPACE = "webhook-receiver-secret";
|
|
80
85
|
var SECRET_BYTE_LEN = 32;
|
|
81
86
|
// 32 bytes -> 43 chars of base64url (no padding).
|
|
82
87
|
var SECRET_PLAINTEXT_LEN = 43;
|
|
83
88
|
var SECRET_PLAINTEXT_RE = /^[A-Za-z0-9_\-]{43}$/;
|
|
84
89
|
|
|
85
|
-
var ROTATION_GRACE_MS =
|
|
90
|
+
var ROTATION_GRACE_MS = C.TIME.days(1);
|
|
86
91
|
|
|
87
92
|
var DEFAULT_REPLAY_WINDOW_SECONDS = 300; // 5 min — Stripe-shaped default
|
|
88
93
|
var MIN_REPLAY_WINDOW_SECONDS = 30; // floor — below this clock skew false-rejects
|
|
94
|
+
// allow:raw-time-literal — replay-window ceiling in SECONDS (24h); C.TIME returns ms
|
|
89
95
|
var MAX_REPLAY_WINDOW_SECONDS = 86400; // 24 h — anything larger is "no replay defense"
|
|
90
96
|
|
|
91
97
|
var DEFAULT_MAX_BODY_BYTES = 1024 * 1024; // 1 MiB
|
|
@@ -933,7 +939,7 @@ function create(opts) {
|
|
|
933
939
|
purgeOlderThan: async function (days) {
|
|
934
940
|
var d = _purgeDays(days);
|
|
935
941
|
var nowMs = _now();
|
|
936
|
-
var cutoff = nowMs - (d
|
|
942
|
+
var cutoff = nowMs - C.TIME.days(d);
|
|
937
943
|
var r = await query(
|
|
938
944
|
"DELETE FROM webhook_received_events " +
|
|
939
945
|
"WHERE received_at < ?1 " +
|
|
@@ -56,7 +56,7 @@ var MAX_EVENT_TYPES = 64;
|
|
|
56
56
|
var MAX_ENDPOINT_URL_LEN = 2048;
|
|
57
57
|
var SECRET_BYTES = 32;
|
|
58
58
|
var SECRET_NAMESPACE = "webhook-signing-secret";
|
|
59
|
-
var ROTATION_GRACE_MS =
|
|
59
|
+
var ROTATION_GRACE_MS = _b().constants.TIME.days(1);
|
|
60
60
|
|
|
61
61
|
var WILDCARD_EVENT = "*";
|
|
62
62
|
|
package/lib/webhooks.js
CHANGED
|
@@ -41,6 +41,7 @@ function _b() {
|
|
|
41
41
|
if (!bShop) bShop = require("./index");
|
|
42
42
|
return bShop.framework;
|
|
43
43
|
}
|
|
44
|
+
var C = _b().constants;
|
|
44
45
|
|
|
45
46
|
var KNOWN_EVENTS = Object.freeze([
|
|
46
47
|
"order.mark_paid",
|
|
@@ -75,7 +76,7 @@ var SECRET_BYTES = 32;
|
|
|
75
76
|
//
|
|
76
77
|
// After the fifth failed attempt the delivery moves to webhook_dlq
|
|
77
78
|
// for operator investigation — see `_moveToDlq` below.
|
|
78
|
-
var BACKOFF_SCHEDULE_S = Object.freeze([60, 300, 1800, 14400, 86400]);
|
|
79
|
+
var BACKOFF_SCHEDULE_S = Object.freeze([60, 300, 1800, 14400, 86400]); // allow:raw-time-literal — seconds values; C.TIME returns ms
|
|
79
80
|
var MAX_ATTEMPTS = 5;
|
|
80
81
|
|
|
81
82
|
// Window used by the per-endpoint rate-limit sliding count. One
|
|
@@ -83,7 +84,7 @@ var MAX_ATTEMPTS = 5;
|
|
|
83
84
|
// brick its own delivery feed (the window naturally slides forward),
|
|
84
85
|
// long enough that bursty fan-out from a single high-volume event
|
|
85
86
|
// doesn't trip the throttle on a healthy endpoint.
|
|
86
|
-
var RATE_WINDOW_MS =
|
|
87
|
+
var RATE_WINDOW_MS = C.TIME.minutes(1);
|
|
87
88
|
|
|
88
89
|
function _now() { return Date.now(); }
|
|
89
90
|
|
|
@@ -254,7 +255,7 @@ function create(opts) {
|
|
|
254
255
|
if (!willDlq) {
|
|
255
256
|
var idx = nextAttempts - 1;
|
|
256
257
|
if (idx < BACKOFF_SCHEDULE_S.length) {
|
|
257
|
-
nextRetryAt = ts + (BACKOFF_SCHEDULE_S[idx] * 1000);
|
|
258
|
+
nextRetryAt = ts + (BACKOFF_SCHEDULE_S[idx] * 1000); // allow:raw-time-literal — schedule entry is a runtime seconds value; *1000 converts to ms
|
|
258
259
|
}
|
|
259
260
|
}
|
|
260
261
|
await query(
|
|
@@ -507,12 +508,12 @@ function create(opts) {
|
|
|
507
508
|
}
|
|
508
509
|
var tolMs;
|
|
509
510
|
if (toleranceSeconds === undefined) {
|
|
510
|
-
tolMs =
|
|
511
|
+
tolMs = C.TIME.minutes(5);
|
|
511
512
|
} else {
|
|
512
513
|
if (typeof toleranceSeconds !== "number" || !isFinite(toleranceSeconds) || toleranceSeconds < 30) {
|
|
513
514
|
throw new TypeError("webhooks.verifyIncoming: toleranceSeconds must be >= 30");
|
|
514
515
|
}
|
|
515
|
-
tolMs = Math.floor(toleranceSeconds * 1000);
|
|
516
|
+
tolMs = Math.floor(toleranceSeconds * 1000); // allow:raw-time-literal — toleranceSeconds is a runtime seconds value; *1000 converts to ms
|
|
516
517
|
}
|
|
517
518
|
return await _b().webhook.verify({
|
|
518
519
|
alg: "hmac-sha256-stripe",
|
package/lib/winback-campaigns.js
CHANGED
|
@@ -102,6 +102,7 @@ function _b() {
|
|
|
102
102
|
if (!bShop) bShop = require("./index");
|
|
103
103
|
return bShop.framework;
|
|
104
104
|
}
|
|
105
|
+
var C = _b().constants;
|
|
105
106
|
|
|
106
107
|
// ---- constants ----------------------------------------------------------
|
|
107
108
|
|
|
@@ -109,7 +110,7 @@ var SLUG_RE = /^[a-z0-9][a-z0-9._-]{0,62}[a-z0-9]$|^[a-z0-9]$/;
|
|
|
109
110
|
var TEMPLATE_RE = /^[a-z0-9][a-z0-9._-]{0,126}[a-z0-9]$|^[a-z0-9]$/;
|
|
110
111
|
var MAX_REASON_LEN = 280;
|
|
111
112
|
var MAX_STEPS = 12;
|
|
112
|
-
var DAY_MS =
|
|
113
|
+
var DAY_MS = C.TIME.days(1);
|
|
113
114
|
|
|
114
115
|
var ENROLLMENT_STATUSES = Object.freeze([
|
|
115
116
|
"active",
|
package/lib/wishlist-alerts.js
CHANGED
|
@@ -93,6 +93,7 @@ function _b() {
|
|
|
93
93
|
if (!bShop) bShop = require("./index");
|
|
94
94
|
return bShop.framework;
|
|
95
95
|
}
|
|
96
|
+
var C = _b().constants;
|
|
96
97
|
|
|
97
98
|
// ---- constants ----------------------------------------------------------
|
|
98
99
|
|
|
@@ -115,7 +116,7 @@ var DEFAULT_BATCH_SIZE = 500;
|
|
|
115
116
|
var MAX_BATCH_SIZE = 5000;
|
|
116
117
|
var MAX_WEEKLY_CAP = 1000;
|
|
117
118
|
var MAX_BPS = 10000; // 100% — refuse strictly absurd thresholds
|
|
118
|
-
var MS_PER_DAY =
|
|
119
|
+
var MS_PER_DAY = C.TIME.days(1);
|
|
119
120
|
var MS_PER_WEEK = MS_PER_DAY * 7;
|
|
120
121
|
|
|
121
122
|
// Per-(customer, sku, policy) re-fire suppression window. A price drop
|
package/lib/wishlist-digest.js
CHANGED
|
@@ -115,6 +115,7 @@ function _b() {
|
|
|
115
115
|
if (!bShop) bShop = require("./index");
|
|
116
116
|
return bShop.framework;
|
|
117
117
|
}
|
|
118
|
+
var C = _b().constants;
|
|
118
119
|
|
|
119
120
|
// ---- constants ----------------------------------------------------------
|
|
120
121
|
|
|
@@ -130,7 +131,7 @@ var MAX_LIMIT = 500;
|
|
|
130
131
|
var DEFAULT_LIMIT = 50;
|
|
131
132
|
var MAX_DIGEST_LINES = 200;
|
|
132
133
|
|
|
133
|
-
var DAY_MS =
|
|
134
|
+
var DAY_MS = C.TIME.days(1);
|
|
134
135
|
|
|
135
136
|
// ---- html escape (local; vendored blamejs's _htmlEscape is private to
|
|
136
137
|
// the mail primitive). Same rules — five named entities, no tag/attr
|
package/package.json
CHANGED