@blamejs/blamejs-shop 0.0.129 → 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 +4 -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 +93 -112
- 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 +2 -0
- package/lib/vendor/blamejs/README.md +1 -0
- package/lib/vendor/blamejs/api-snapshot.json +92 -2
- package/lib/vendor/blamejs/index.js +1 -0
- package/lib/vendor/blamejs/lib/did.js +367 -0
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.12.41.json +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +9 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/did.test.js +147 -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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"frameworkVersion": "0.12.
|
|
4
|
-
"createdAt": "2026-05-
|
|
3
|
+
"frameworkVersion": "0.12.41",
|
|
4
|
+
"createdAt": "2026-05-25T05:05:33.017Z",
|
|
5
5
|
"exports": {
|
|
6
6
|
"a2a": {
|
|
7
7
|
"type": "object",
|
|
@@ -14411,6 +14411,96 @@
|
|
|
14411
14411
|
}
|
|
14412
14412
|
}
|
|
14413
14413
|
},
|
|
14414
|
+
"did": {
|
|
14415
|
+
"type": "object",
|
|
14416
|
+
"members": {
|
|
14417
|
+
"DidError": {
|
|
14418
|
+
"type": "function",
|
|
14419
|
+
"arity": 4
|
|
14420
|
+
},
|
|
14421
|
+
"MULTICODEC": {
|
|
14422
|
+
"type": "object",
|
|
14423
|
+
"members": {
|
|
14424
|
+
"231": {
|
|
14425
|
+
"type": "object",
|
|
14426
|
+
"members": {
|
|
14427
|
+
"curveOid": {
|
|
14428
|
+
"type": "primitive",
|
|
14429
|
+
"valueType": "string"
|
|
14430
|
+
},
|
|
14431
|
+
"kind": {
|
|
14432
|
+
"type": "primitive",
|
|
14433
|
+
"valueType": "string"
|
|
14434
|
+
},
|
|
14435
|
+
"name": {
|
|
14436
|
+
"type": "primitive",
|
|
14437
|
+
"valueType": "string"
|
|
14438
|
+
}
|
|
14439
|
+
}
|
|
14440
|
+
},
|
|
14441
|
+
"237": {
|
|
14442
|
+
"type": "object",
|
|
14443
|
+
"members": {
|
|
14444
|
+
"kind": {
|
|
14445
|
+
"type": "primitive",
|
|
14446
|
+
"valueType": "string"
|
|
14447
|
+
},
|
|
14448
|
+
"name": {
|
|
14449
|
+
"type": "primitive",
|
|
14450
|
+
"valueType": "string"
|
|
14451
|
+
}
|
|
14452
|
+
}
|
|
14453
|
+
},
|
|
14454
|
+
"4608": {
|
|
14455
|
+
"type": "object",
|
|
14456
|
+
"members": {
|
|
14457
|
+
"curveOid": {
|
|
14458
|
+
"type": "primitive",
|
|
14459
|
+
"valueType": "string"
|
|
14460
|
+
},
|
|
14461
|
+
"kind": {
|
|
14462
|
+
"type": "primitive",
|
|
14463
|
+
"valueType": "string"
|
|
14464
|
+
},
|
|
14465
|
+
"name": {
|
|
14466
|
+
"type": "primitive",
|
|
14467
|
+
"valueType": "string"
|
|
14468
|
+
}
|
|
14469
|
+
}
|
|
14470
|
+
},
|
|
14471
|
+
"4609": {
|
|
14472
|
+
"type": "object",
|
|
14473
|
+
"members": {
|
|
14474
|
+
"curveOid": {
|
|
14475
|
+
"type": "primitive",
|
|
14476
|
+
"valueType": "string"
|
|
14477
|
+
},
|
|
14478
|
+
"kind": {
|
|
14479
|
+
"type": "primitive",
|
|
14480
|
+
"valueType": "string"
|
|
14481
|
+
},
|
|
14482
|
+
"name": {
|
|
14483
|
+
"type": "primitive",
|
|
14484
|
+
"valueType": "string"
|
|
14485
|
+
}
|
|
14486
|
+
}
|
|
14487
|
+
}
|
|
14488
|
+
}
|
|
14489
|
+
},
|
|
14490
|
+
"keyToDid": {
|
|
14491
|
+
"type": "function",
|
|
14492
|
+
"arity": 1
|
|
14493
|
+
},
|
|
14494
|
+
"parse": {
|
|
14495
|
+
"type": "function",
|
|
14496
|
+
"arity": 1
|
|
14497
|
+
},
|
|
14498
|
+
"resolve": {
|
|
14499
|
+
"type": "function",
|
|
14500
|
+
"arity": 2
|
|
14501
|
+
}
|
|
14502
|
+
}
|
|
14503
|
+
},
|
|
14414
14504
|
"dora": {
|
|
14415
14505
|
"type": "object",
|
|
14416
14506
|
"members": {
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @module b.did
|
|
4
|
+
* @nav Crypto
|
|
5
|
+
* @title Decentralized Identifiers (DID)
|
|
6
|
+
*
|
|
7
|
+
* @intro
|
|
8
|
+
* Resolve W3C Decentralized Identifiers (DID Core 1.0, a W3C
|
|
9
|
+
* Recommendation) to verification keys — the missing link that lets a
|
|
10
|
+
* credential's issuer be named by a DID rather than a raw key. Resolve
|
|
11
|
+
* the issuer DID of a <code>b.vc</code> / <code>b.mdoc</code> /
|
|
12
|
+
* <code>b.scitt</code> credential to a <code>node:crypto</code>
|
|
13
|
+
* KeyObject, then hand that key to the verifier.
|
|
14
|
+
*
|
|
15
|
+
* Two methods are supported. <strong>did:key</strong> encodes a public
|
|
16
|
+
* key directly in the identifier (multicodec + base58btc multibase),
|
|
17
|
+
* so resolution is deterministic and offline — Ed25519, P-256, P-384,
|
|
18
|
+
* and secp256k1 keys round-trip. <strong>did:web</strong> places the
|
|
19
|
+
* DID document at an HTTPS URL derived from the identifier; the network
|
|
20
|
+
* fetch is the operator's to make (the same operator-supplied-input
|
|
21
|
+
* stance as the rest of the framework), and <code>resolve</code> takes
|
|
22
|
+
* the fetched document and extracts its verification methods.
|
|
23
|
+
*
|
|
24
|
+
* <code>b.did.keyToDid(publicKey)</code> produces a did:key from a
|
|
25
|
+
* KeyObject (an issuer naming itself); <code>b.did.parse(did)</code>
|
|
26
|
+
* splits the identifier (and, for did:web, returns the HTTPS URL to
|
|
27
|
+
* fetch); <code>b.did.resolve(did, opts)</code> returns the DID
|
|
28
|
+
* document and its verification methods as KeyObjects. Verification
|
|
29
|
+
* methods expressed as <code>publicKeyMultibase</code> or
|
|
30
|
+
* <code>publicKeyJwk</code> are both understood.
|
|
31
|
+
*
|
|
32
|
+
* <strong>Maturity.</strong> DID Core 1.0 is a Recommendation, but the
|
|
33
|
+
* method specs are deployed-stable rather than Recommendations:
|
|
34
|
+
* did:key is a W3C CCG report and did:web is a registered DID method
|
|
35
|
+
* (mandated by the EU Digital Identity Wallet). They are widely
|
|
36
|
+
* deployed and interoperable today; pin the dependency deliberately.
|
|
37
|
+
*
|
|
38
|
+
* @card
|
|
39
|
+
* W3C DID resolution (did:key + did:web) → verification KeyObjects for
|
|
40
|
+
* the credential verifiers. did:key is deterministic + offline
|
|
41
|
+
* (Ed25519 / P-256 / P-384 / secp256k1); did:web parses an
|
|
42
|
+
* operator-fetched DID document. Composes node:crypto; no new dep.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
var nodeCrypto = require("node:crypto");
|
|
46
|
+
var validateOpts = require("./validate-opts");
|
|
47
|
+
var { defineClass } = require("./framework-error");
|
|
48
|
+
|
|
49
|
+
var DidError = defineClass("DidError", { alwaysPermanent: true });
|
|
50
|
+
|
|
51
|
+
var B58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
52
|
+
var B58_MAP = (function () {
|
|
53
|
+
var m = {};
|
|
54
|
+
for (var i = 0; i < B58_ALPHABET.length; i += 1) m[B58_ALPHABET[i]] = i;
|
|
55
|
+
return m;
|
|
56
|
+
})();
|
|
57
|
+
var MAX_MULTIBASE_CHARS = 1024; // allow:raw-byte-literal — bounded did:key multibase length (DoS cap)
|
|
58
|
+
|
|
59
|
+
// multicodec public-key codes (unsigned-varint) → curve descriptor.
|
|
60
|
+
// keyLen is the multicodec payload: Ed25519 raw 32; EC compressed point.
|
|
61
|
+
var MULTICODEC = {
|
|
62
|
+
0xed: { name: "Ed25519", kind: "okp" }, // ed25519-pub
|
|
63
|
+
0x1200: { name: "P-256", kind: "ec", curveOid: "1.2.840.10045.3.1.7" }, // allow:raw-byte-literal allow:raw-time-literal — p256-pub multicodec code + OID dotted-form
|
|
64
|
+
0x1201: { name: "P-384", kind: "ec", curveOid: "1.3.132.0.34" }, // allow:raw-byte-literal — p384-pub multicodec code
|
|
65
|
+
0xe7: { name: "secp256k1", kind: "ec", curveOid: "1.3.132.0.10" }, // secp256k1-pub
|
|
66
|
+
};
|
|
67
|
+
var NAME_TO_CODE = {};
|
|
68
|
+
Object.keys(MULTICODEC).forEach(function (c) { NAME_TO_CODE[MULTICODEC[c].name] = Number(c); });
|
|
69
|
+
|
|
70
|
+
// ---- base58btc (bounded) ----
|
|
71
|
+
|
|
72
|
+
function _b58decode(str) {
|
|
73
|
+
if (str.length > MAX_MULTIBASE_CHARS) {
|
|
74
|
+
throw new DidError("did/too-long", "did: multibase value exceeds the " + MAX_MULTIBASE_CHARS + "-char cap");
|
|
75
|
+
}
|
|
76
|
+
var bytes = [0];
|
|
77
|
+
for (var i = 0; i < str.length; i += 1) {
|
|
78
|
+
var v = B58_MAP[str[i]];
|
|
79
|
+
if (v === undefined) throw new DidError("did/bad-base58", "did: invalid base58btc character '" + str[i] + "'");
|
|
80
|
+
var carry = v;
|
|
81
|
+
for (var j = 0; j < bytes.length; j += 1) {
|
|
82
|
+
carry += bytes[j] * 58;
|
|
83
|
+
bytes[j] = carry & 0xff;
|
|
84
|
+
carry >>= 8; // allow:raw-byte-literal — base-256 carry
|
|
85
|
+
}
|
|
86
|
+
while (carry > 0) { bytes.push(carry & 0xff); carry >>= 8; } // allow:raw-byte-literal — base-256 carry
|
|
87
|
+
}
|
|
88
|
+
// Leading '1's are leading zero bytes.
|
|
89
|
+
for (var k = 0; k < str.length && str[k] === "1"; k += 1) bytes.push(0);
|
|
90
|
+
return Buffer.from(bytes.reverse());
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function _b58encode(buf) {
|
|
94
|
+
var digits = [0];
|
|
95
|
+
for (var i = 0; i < buf.length; i += 1) {
|
|
96
|
+
var carry = buf[i];
|
|
97
|
+
for (var j = 0; j < digits.length; j += 1) {
|
|
98
|
+
carry += digits[j] << 8; // allow:raw-byte-literal — base-256 shift
|
|
99
|
+
digits[j] = carry % 58;
|
|
100
|
+
carry = (carry / 58) | 0;
|
|
101
|
+
}
|
|
102
|
+
while (carry > 0) { digits.push(carry % 58); carry = (carry / 58) | 0; }
|
|
103
|
+
}
|
|
104
|
+
var out = "";
|
|
105
|
+
for (var z = 0; z < buf.length && buf[z] === 0; z += 1) out += "1";
|
|
106
|
+
for (var d = digits.length - 1; d >= 0; d -= 1) out += B58_ALPHABET[digits[d]];
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Read an unsigned LEB128 varint (multicodec code). Bounded to 4 bytes.
|
|
111
|
+
function _readVarint(buf) {
|
|
112
|
+
var value = 0, shift = 0, len = 0;
|
|
113
|
+
for (var i = 0; i < buf.length && i < 4; i += 1) { // allow:raw-byte-literal — multicodec varint ≤ 4 bytes
|
|
114
|
+
var b = buf[i];
|
|
115
|
+
value |= (b & 0x7f) << shift;
|
|
116
|
+
len += 1;
|
|
117
|
+
if ((b & 0x80) === 0) return { value: value >>> 0, length: len };
|
|
118
|
+
shift += 7; // allow:raw-byte-literal — 7 bits per varint byte
|
|
119
|
+
}
|
|
120
|
+
throw new DidError("did/bad-multicodec", "did: multicodec varint did not terminate");
|
|
121
|
+
}
|
|
122
|
+
function _encodeVarint(code) {
|
|
123
|
+
var out = [];
|
|
124
|
+
var n = code;
|
|
125
|
+
do { var b = n & 0x7f; n >>>= 7; if (n > 0) b |= 0x80; out.push(b); } while (n > 0); // allow:raw-byte-literal — LEB128 7-bit groups
|
|
126
|
+
return Buffer.from(out);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ---- key <-> bytes ----
|
|
130
|
+
|
|
131
|
+
var ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex"); // RFC 8410 Ed25519 SubjectPublicKeyInfo header
|
|
132
|
+
|
|
133
|
+
function _keyObjectFromMulticodec(code, keyBytes) {
|
|
134
|
+
var desc = MULTICODEC[code];
|
|
135
|
+
if (!desc) throw new DidError("did/unsupported-key", "did: unsupported multicodec key code 0x" + code.toString(16)); // allow:raw-byte-literal — hex radix
|
|
136
|
+
if (desc.kind === "okp") {
|
|
137
|
+
if (keyBytes.length !== 32) { // allow:raw-byte-literal — Ed25519 public key is 32 bytes
|
|
138
|
+
throw new DidError("did/bad-key", "did: Ed25519 key must be 32 bytes (got " + keyBytes.length + ")");
|
|
139
|
+
}
|
|
140
|
+
return nodeCrypto.createPublicKey({ key: Buffer.concat([ED25519_SPKI_PREFIX, keyBytes]), format: "der", type: "spki" });
|
|
141
|
+
}
|
|
142
|
+
// EC: keyBytes is a compressed point (0x02/0x03 + X). Build an SPKI and
|
|
143
|
+
// let node decompress.
|
|
144
|
+
if (keyBytes.length < 2 || (keyBytes[0] !== 0x02 && keyBytes[0] !== 0x03)) {
|
|
145
|
+
throw new DidError("did/bad-key", "did: EC key must be a compressed point (0x02/0x03 prefix)");
|
|
146
|
+
}
|
|
147
|
+
var algid = _ecAlgId(desc.curveOid);
|
|
148
|
+
var bitstr = Buffer.concat([Buffer.from([0x03, keyBytes.length + 1, 0x00]), keyBytes]);
|
|
149
|
+
var body = Buffer.concat([algid, bitstr]);
|
|
150
|
+
var spki = Buffer.concat([Buffer.from([0x30, body.length]), body]); // allow:raw-byte-literal — SEQUENCE tag; single-byte DER length holds for these curves
|
|
151
|
+
try { return nodeCrypto.createPublicKey({ key: spki, format: "der", type: "spki" }); }
|
|
152
|
+
catch (e) { throw new DidError("did/bad-key", "did: could not import EC key: " + ((e && e.message) || e)); }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// AlgorithmIdentifier SEQUENCE { id-ecPublicKey, namedCurve OID }.
|
|
156
|
+
function _ecAlgId(curveOid) {
|
|
157
|
+
var idEcPublicKey = Buffer.from("06072a8648ce3d0201", "hex"); // allow:raw-byte-literal allow:raw-time-literal — DER OID for id-ecPublicKey
|
|
158
|
+
var curve = _oidDer(curveOid);
|
|
159
|
+
var inner = Buffer.concat([idEcPublicKey, curve]);
|
|
160
|
+
return Buffer.concat([Buffer.from([0x30, inner.length]), inner]);
|
|
161
|
+
}
|
|
162
|
+
function _oidDer(dotted) {
|
|
163
|
+
var parts = dotted.split(".").map(Number);
|
|
164
|
+
var bytes = [parts[0] * 40 + parts[1]]; // allow:raw-byte-literal — X.690 first-arc encoding
|
|
165
|
+
for (var i = 2; i < parts.length; i += 1) {
|
|
166
|
+
var arc = parts[i], stack = [];
|
|
167
|
+
do { stack.unshift(arc & 0x7f); arc >>>= 7; } while (arc > 0); // allow:raw-byte-literal — base-128 OID arc
|
|
168
|
+
for (var j = 0; j < stack.length - 1; j += 1) stack[j] |= 0x80; // allow:raw-byte-literal — continuation bit
|
|
169
|
+
bytes = bytes.concat(stack);
|
|
170
|
+
}
|
|
171
|
+
return Buffer.concat([Buffer.from([0x06, bytes.length]), Buffer.from(bytes)]);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Compressed point + curve name from an EC KeyObject's JWK.
|
|
175
|
+
function _compressedPoint(jwk) {
|
|
176
|
+
var x = Buffer.from(jwk.x, "base64url");
|
|
177
|
+
var y = Buffer.from(jwk.y, "base64url");
|
|
178
|
+
return Buffer.concat([Buffer.from([(y[y.length - 1] & 1) ? 0x03 : 0x02]), x]);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @primitive b.did.parse
|
|
183
|
+
* @signature b.did.parse(did)
|
|
184
|
+
* @since 0.12.41
|
|
185
|
+
* @status experimental
|
|
186
|
+
* @related b.did.resolve, b.did.keyToDid
|
|
187
|
+
*
|
|
188
|
+
* Split a DID string into its method and method-specific id. For
|
|
189
|
+
* <code>did:web</code> the HTTPS URL of the DID document is also
|
|
190
|
+
* returned (host[:port][:path] → <code>https://host/path/did.json</code>,
|
|
191
|
+
* or <code>/.well-known/did.json</code> with no path).
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* b.did.parse("did:web:example.com:issuers:42");
|
|
195
|
+
* // → { method: "web", id: "example.com:issuers:42", url: "https://example.com/issuers/42/did.json" }
|
|
196
|
+
*/
|
|
197
|
+
function parse(did) {
|
|
198
|
+
if (typeof did !== "string" || did.indexOf("did:") !== 0) {
|
|
199
|
+
throw new DidError("did/bad-did", "did.parse: not a DID (must start with 'did:')");
|
|
200
|
+
}
|
|
201
|
+
var rest = did.slice(4);
|
|
202
|
+
var colon = rest.indexOf(":");
|
|
203
|
+
if (colon <= 0) throw new DidError("did/bad-did", "did.parse: DID is missing a method-specific id");
|
|
204
|
+
var method = rest.slice(0, colon);
|
|
205
|
+
var id = rest.slice(colon + 1);
|
|
206
|
+
var out = { method: method, id: id };
|
|
207
|
+
if (method === "web") out.url = _didWebUrl(id);
|
|
208
|
+
return out;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function _didWebUrl(id) {
|
|
212
|
+
// did-method-web §read: ':' separates segments (→ '/'); only the host
|
|
213
|
+
// may carry a percent-encoded port (%3A → ':'). Path segments are kept
|
|
214
|
+
// verbatim — NOT percent-decoded — so an escaped reserved char (e.g.
|
|
215
|
+
// %3F) stays path data rather than becoming URL control syntax, and a
|
|
216
|
+
// malformed escape never throws a raw URIError.
|
|
217
|
+
var segs = id.split(":");
|
|
218
|
+
var host = segs[0].replace(/%3[Aa]/g, ":");
|
|
219
|
+
if (!host) throw new DidError("did/bad-did", "did:web: missing host");
|
|
220
|
+
var path = segs.slice(1);
|
|
221
|
+
var base = "https://" + host;
|
|
222
|
+
return path.length ? base + "/" + path.join("/") + "/did.json" : base + "/.well-known/did.json";
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* @primitive b.did.keyToDid
|
|
227
|
+
* @signature b.did.keyToDid(publicKey)
|
|
228
|
+
* @since 0.12.41
|
|
229
|
+
* @status experimental
|
|
230
|
+
* @related b.did.resolve
|
|
231
|
+
*
|
|
232
|
+
* Encode a public key (a <code>node:crypto</code> KeyObject or PEM) as a
|
|
233
|
+
* <code>did:key</code> — the inverse of resolution, for an issuer that
|
|
234
|
+
* names itself by its key. Ed25519, P-256, P-384, and secp256k1 are
|
|
235
|
+
* supported.
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* var did = b.did.keyToDid(issuerPublicKey); // → "did:key:z6Mk…"
|
|
239
|
+
*/
|
|
240
|
+
function keyToDid(publicKey) {
|
|
241
|
+
var key = (publicKey && typeof publicKey === "object" && publicKey.asymmetricKeyType)
|
|
242
|
+
? publicKey : nodeCrypto.createPublicKey(publicKey);
|
|
243
|
+
var jwk = key.export({ format: "jwk" });
|
|
244
|
+
var code, payload;
|
|
245
|
+
if (jwk.kty === "OKP" && jwk.crv === "Ed25519") {
|
|
246
|
+
code = NAME_TO_CODE["Ed25519"];
|
|
247
|
+
payload = Buffer.from(jwk.x, "base64url");
|
|
248
|
+
} else if (jwk.kty === "EC") {
|
|
249
|
+
var name = jwk.crv === "P-256" ? "P-256" : jwk.crv === "P-384" ? "P-384" : jwk.crv === "secp256k1" ? "secp256k1" : null;
|
|
250
|
+
if (!name) throw new DidError("did/unsupported-key", "did.keyToDid: unsupported EC curve '" + jwk.crv + "'");
|
|
251
|
+
code = NAME_TO_CODE[name];
|
|
252
|
+
payload = _compressedPoint(jwk);
|
|
253
|
+
} else {
|
|
254
|
+
throw new DidError("did/unsupported-key", "did.keyToDid: unsupported key type '" + jwk.kty + "/" + jwk.crv + "'");
|
|
255
|
+
}
|
|
256
|
+
return "did:key:z" + _b58encode(Buffer.concat([_encodeVarint(code), payload]));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* @primitive b.did.resolve
|
|
261
|
+
* @signature b.did.resolve(did, opts?)
|
|
262
|
+
* @since 0.12.41
|
|
263
|
+
* @status experimental
|
|
264
|
+
* @compliance soc2
|
|
265
|
+
* @related b.did.parse, b.vc.verify, b.mdoc.verifyIssuerSigned
|
|
266
|
+
*
|
|
267
|
+
* Resolve a DID to its document and verification methods (each with a
|
|
268
|
+
* <code>node:crypto</code> public KeyObject ready for a verifier).
|
|
269
|
+
* <code>did:key</code> resolves deterministically and offline.
|
|
270
|
+
* <code>did:web</code> requires the operator to supply the fetched DID
|
|
271
|
+
* document as <code>opts.document</code> (the network fetch is the
|
|
272
|
+
* operator's; the URL to fetch is on <code>b.did.parse(did).url</code>).
|
|
273
|
+
*
|
|
274
|
+
* @opts
|
|
275
|
+
* {
|
|
276
|
+
* document: object, // did:web — the fetched did.json (required for did:web)
|
|
277
|
+
* }
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* var r = b.did.resolve("did:key:z6Mk…");
|
|
281
|
+
* var key = r.verificationMethods[0].publicKey; // → KeyObject for b.vc.verify / b.mdoc / b.scitt
|
|
282
|
+
*/
|
|
283
|
+
function resolve(did, opts) {
|
|
284
|
+
opts = opts || {};
|
|
285
|
+
validateOpts.requireObject(opts, "did.resolve", DidError);
|
|
286
|
+
validateOpts(opts, ["document"], "did.resolve");
|
|
287
|
+
var parsed = parse(did);
|
|
288
|
+
|
|
289
|
+
if (parsed.method === "key") {
|
|
290
|
+
if (parsed.id[0] !== "z") {
|
|
291
|
+
throw new DidError("did/bad-did", "did:key: method-specific id must be base58btc multibase (start with 'z')");
|
|
292
|
+
}
|
|
293
|
+
var raw = _b58decode(parsed.id.slice(1));
|
|
294
|
+
var vh = _readVarint(raw);
|
|
295
|
+
var key = _keyObjectFromMulticodec(vh.value, raw.slice(vh.length));
|
|
296
|
+
var vmId = did + "#" + parsed.id;
|
|
297
|
+
var vm = { id: vmId, controller: did, type: MULTICODEC[vh.value].name, publicKey: key };
|
|
298
|
+
var doc = {
|
|
299
|
+
"@context": ["https://www.w3.org/ns/did/v1"],
|
|
300
|
+
id: did,
|
|
301
|
+
verificationMethod: [{ id: vmId, controller: did, type: "Multikey", publicKeyMultibase: parsed.id }],
|
|
302
|
+
assertionMethod: [vmId], authentication: [vmId],
|
|
303
|
+
};
|
|
304
|
+
return { didDocument: doc, verificationMethods: [vm] };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (parsed.method === "web") {
|
|
308
|
+
if (!opts.document || typeof opts.document !== "object") {
|
|
309
|
+
throw new DidError("did/document-required",
|
|
310
|
+
"did:web: the DID document must be fetched by the operator and passed as opts.document (GET " + parsed.url + ")");
|
|
311
|
+
}
|
|
312
|
+
var docW = opts.document;
|
|
313
|
+
if (docW.id !== did) {
|
|
314
|
+
throw new DidError("did/document-mismatch", "did:web: document id '" + docW.id + "' does not match the requested DID");
|
|
315
|
+
}
|
|
316
|
+
return { didDocument: docW, verificationMethods: _extractVerificationMethods(docW) };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
throw new DidError("did/unsupported-method", "did.resolve: unsupported DID method '" + parsed.method + "' (did:key and did:web only)");
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Import a publicKeyJwk after allowlisting its kty/crv — a DID document
|
|
323
|
+
// is untrusted input, so an unexpected key type (RSA / oct / unknown
|
|
324
|
+
// curve) is refused before it reaches node:crypto rather than blindly
|
|
325
|
+
// imported (the DID-context equivalent of the JWT alg/kty cross-check;
|
|
326
|
+
// there is no single verification `alg` in a DID document).
|
|
327
|
+
function _jwkToKey(jwk) {
|
|
328
|
+
var ok = (jwk.kty === "OKP" && jwk.crv === "Ed25519") ||
|
|
329
|
+
(jwk.kty === "EC" && (jwk.crv === "P-256" || jwk.crv === "P-384" || jwk.crv === "secp256k1"));
|
|
330
|
+
if (!ok) {
|
|
331
|
+
throw new DidError("did/unsupported-key",
|
|
332
|
+
"did: verificationMethod publicKeyJwk has unsupported kty/crv (" + jwk.kty + "/" + jwk.crv + ")");
|
|
333
|
+
}
|
|
334
|
+
try { return nodeCrypto.createPublicKey({ key: jwk, format: "jwk" }); }
|
|
335
|
+
catch (e) { throw new DidError("did/bad-key", "did: verificationMethod publicKeyJwk is invalid: " + ((e && e.message) || e)); }
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Extract verification methods from a DID document → KeyObjects.
|
|
339
|
+
function _extractVerificationMethods(doc) {
|
|
340
|
+
var vms = Array.isArray(doc.verificationMethod) ? doc.verificationMethod : [];
|
|
341
|
+
var out = [];
|
|
342
|
+
for (var i = 0; i < vms.length; i += 1) {
|
|
343
|
+
var vm = vms[i];
|
|
344
|
+
if (!vm || typeof vm !== "object") continue;
|
|
345
|
+
var key = null;
|
|
346
|
+
if (typeof vm.publicKeyMultibase === "string" && vm.publicKeyMultibase[0] === "z") {
|
|
347
|
+
var raw = _b58decode(vm.publicKeyMultibase.slice(1));
|
|
348
|
+
var vh = _readVarint(raw);
|
|
349
|
+
key = _keyObjectFromMulticodec(vh.value, raw.slice(vh.length));
|
|
350
|
+
} else if (vm.publicKeyJwk && typeof vm.publicKeyJwk === "object") {
|
|
351
|
+
key = _jwkToKey(vm.publicKeyJwk);
|
|
352
|
+
} else {
|
|
353
|
+
continue; // unknown key encoding — skip rather than guess
|
|
354
|
+
}
|
|
355
|
+
out.push({ id: vm.id, controller: vm.controller, type: vm.type, publicKey: key });
|
|
356
|
+
}
|
|
357
|
+
if (!out.length) throw new DidError("did/no-keys", "did: document has no resolvable verification methods");
|
|
358
|
+
return out;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
module.exports = {
|
|
362
|
+
parse: parse,
|
|
363
|
+
keyToDid: keyToDid,
|
|
364
|
+
resolve: resolve,
|
|
365
|
+
MULTICODEC: MULTICODEC,
|
|
366
|
+
DidError: DidError,
|
|
367
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../scripts/release-notes-schema.json",
|
|
3
|
+
"version": "0.12.41",
|
|
4
|
+
"date": "2026-05-24",
|
|
5
|
+
"headline": "`b.did` — W3C DID resolution (did:key + did:web) feeding the credential verifiers",
|
|
6
|
+
"summary": "Resolve W3C Decentralized Identifiers (DID Core 1.0) to verification keys — the link that lets a credential's issuer be named by a DID rather than a raw key. Resolve the issuer DID of a b.vc / b.mdoc / b.scitt credential to a node:crypto KeyObject and hand it to the verifier. did:key encodes the public key in the identifier (multicodec + base58btc), so resolution is deterministic and offline — Ed25519, P-256, P-384, and secp256k1 round-trip; did:web places the DID document at an HTTPS URL derived from the identifier, with the network fetch left to the operator (the framework parses the operator-fetched document and extracts its verification methods, as publicKeyMultibase or publicKeyJwk). b.did.keyToDid encodes a KeyObject as a did:key (an issuer naming itself), b.did.parse splits the identifier (and returns the did:web URL to fetch), and b.did.resolve returns the document and verification keys. DID Core 1.0 is a W3C Recommendation; the method specs (did:key W3C CCG report, did:web DID method registry — EUDI-mandated) are deployed-stable. Composes node:crypto; no new runtime dependency.",
|
|
7
|
+
"sections": [
|
|
8
|
+
{
|
|
9
|
+
"heading": "Added",
|
|
10
|
+
"items": [
|
|
11
|
+
{
|
|
12
|
+
"title": "`b.did.resolve(did, opts?)` / `b.did.keyToDid(publicKey)` / `b.did.parse(did)`",
|
|
13
|
+
"body": "`resolve` returns `{ didDocument, verificationMethods: [{ id, controller, type, publicKey }] }` with each `publicKey` a `node:crypto` KeyObject ready for `b.vc.verify` / `b.mdoc.verifyIssuerSigned` / `b.scitt.verifyStatement`. did:key resolves deterministically and offline (base58btc + multicodec → Ed25519 raw key or EC compressed point, rebuilt via SPKI); did:web requires the operator to pass the fetched DID document as `opts.document` (the URL to GET is on `b.did.parse(did).url`) and the document `id` must match the requested DID. A publicKeyJwk in a DID document is imported only after its `kty`/`crv` is allowlisted (Ed25519 / P-256 / P-384 / secp256k1) — an unexpected key type from an untrusted document is refused, not blindly imported. `keyToDid` encodes an Ed25519 / P-256 / P-384 / secp256k1 KeyObject as a did:key; `parse` derives the did:web HTTPS URL (`host[:port][:path]` → `https://host/path/did.json`, or `/.well-known/did.json`). Unknown methods, malformed base58, unsupported multicodec codes, and unsupported key types are each refused."
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -6215,8 +6215,16 @@ var KNOWN_ANTIPATTERNS = [
|
|
|
6215
6215
|
// jwtExternal._assertAlgKtyMatch BEFORE createPublicKey on
|
|
6216
6216
|
// the browser-supplied DBSC binding JWK.
|
|
6217
6217
|
"lib/dbsc.js",
|
|
6218
|
+
// did.js — _jwkToKey allowlists the JWK's kty/crv (OKP/Ed25519 or
|
|
6219
|
+
// EC/P-256/P-384/secp256k1) and refuses any other type BEFORE
|
|
6220
|
+
// createPublicKey, which is the DID-context equivalent of the
|
|
6221
|
+
// alg/kty cross-check: a DID document carries verification keys,
|
|
6222
|
+
// not a verification alg (the consuming verifier — b.vc / b.mdoc —
|
|
6223
|
+
// supplies the alg allowlist), so there is no `alg` to pass to
|
|
6224
|
+
// _assertAlgKtyMatch; the kty/crv allowlist is the confusion guard.
|
|
6225
|
+
"lib/did.js",
|
|
6218
6226
|
],
|
|
6219
|
-
reason: "CVE-2026-22817 — every JWT verifier that resolves a JWK BY ATTACKER-CONTROLLED HEADER (kid / x5t) must cross-check the declared alg against the JWK's kty (and crv for EC) BEFORE handing the key to node:crypto.verify. Imports that skip the check are exactly the confused-deputy shape (RS256→HS256 family). The shared helper `jwtExternal._assertAlgKtyMatch(alg, jwk)` is the single point of enforcement; new code routes through it. Allowlist entries are sign-side / pinned-cert paths where the JWK is not attacker-supplied.",
|
|
6227
|
+
reason: "CVE-2026-22817 — every JWT verifier that resolves a JWK BY ATTACKER-CONTROLLED HEADER (kid / x5t) must cross-check the declared alg against the JWK's kty (and crv for EC) BEFORE handing the key to node:crypto.verify. Imports that skip the check are exactly the confused-deputy shape (RS256→HS256 family). The shared helper `jwtExternal._assertAlgKtyMatch(alg, jwk)` is the single point of enforcement; new code routes through it. Allowlist entries are sign-side / pinned-cert paths where the JWK is not attacker-supplied, or (did.js) where a kty/crv allowlist stands in for alg/kty because the format carries no verification alg.",
|
|
6220
6228
|
},
|
|
6221
6229
|
{
|
|
6222
6230
|
// CVE-2026-23552 — cross-realm JWT acceptance via non-CT iss
|