@blamejs/blamejs-shop 0.0.127 → 0.0.129
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/README.md +4 -0
- package/lib/storefront.js +235 -6
- package/lib/vendor/MANIFEST.json +3 -3
- package/lib/vendor/blamejs/CHANGELOG.md +14 -0
- package/lib/vendor/blamejs/README.md +7 -1
- package/lib/vendor/blamejs/SECURITY.md +3 -0
- package/lib/vendor/blamejs/api-snapshot.json +408 -2
- package/lib/vendor/blamejs/index.js +6 -0
- package/lib/vendor/blamejs/lib/cose.js +212 -4
- package/lib/vendor/blamejs/lib/cwt.js +244 -0
- package/lib/vendor/blamejs/lib/eat.js +240 -0
- package/lib/vendor/blamejs/lib/mdoc.js +305 -0
- package/lib/vendor/blamejs/lib/scitt.js +243 -0
- package/lib/vendor/blamejs/lib/tsa.js +688 -0
- package/lib/vendor/blamejs/lib/vc.js +328 -0
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.12.34.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.12.35.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.12.36.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.12.37.json +27 -0
- package/lib/vendor/blamejs/release-notes/v0.12.38.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.12.39.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.12.40.json +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +84 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/cwt.test.js +137 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/eat.test.js +111 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mdoc.test.js +230 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scitt.test.js +158 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +373 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +188 -0
- package/package.json +1 -1
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Layer 0 — b.vc (W3C Verifiable Credentials 2.0, VC-JOSE-COSE).
|
|
4
|
+
* Covers JOSE (compact JWS, vc+jwt) and COSE (COSE_Sign1, vc+cose)
|
|
5
|
+
* securing round-trips, the byte-exact credential payload (no injected
|
|
6
|
+
* JWT claims), VCDM structural validation, the validFrom / validUntil
|
|
7
|
+
* window, expected-issuer enforcement, the mandatory algorithm
|
|
8
|
+
* allowlist, and refusal of the JOSE `none` algorithm.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
var b = require("../../index");
|
|
12
|
+
var helpers = require("../helpers");
|
|
13
|
+
var check = helpers.check;
|
|
14
|
+
var nodeCrypto = require("node:crypto");
|
|
15
|
+
|
|
16
|
+
var EC = nodeCrypto.generateKeyPairSync("ec", { namedCurve: "P-256" });
|
|
17
|
+
var ED = nodeCrypto.generateKeyPairSync("ed25519");
|
|
18
|
+
|
|
19
|
+
// Sign an arbitrary header + payload as a compact JWS with the EC key —
|
|
20
|
+
// bypasses b.vc.issue's validation so the verify-side fail-closed paths
|
|
21
|
+
// (malformed validity, crit) can be exercised on a real signature.
|
|
22
|
+
function _rawJose(header, payloadObj) {
|
|
23
|
+
var h = Buffer.from(JSON.stringify(header), "utf8").toString("base64url");
|
|
24
|
+
var p = Buffer.from(JSON.stringify(payloadObj), "utf8").toString("base64url");
|
|
25
|
+
var signingInput = h + "." + p;
|
|
26
|
+
var sig = nodeCrypto.sign("sha256", Buffer.from(signingInput, "ascii"), { key: EC.privateKey, dsaEncoding: "ieee-p1363" });
|
|
27
|
+
return signingInput + "." + sig.toString("base64url");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function _cred(extra) {
|
|
31
|
+
return Object.assign({
|
|
32
|
+
"@context": ["https://www.w3.org/ns/credentials/v2"],
|
|
33
|
+
"type": ["VerifiableCredential", "ExampleDegree"],
|
|
34
|
+
"issuer": "did:example:issuer123",
|
|
35
|
+
"credentialSubject": { "id": "did:example:subject", "degree": "BS" },
|
|
36
|
+
}, extra || {});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function testSurface() {
|
|
40
|
+
check("b.vc.issue is a function", typeof b.vc.issue === "function");
|
|
41
|
+
check("b.vc.verify is a function", typeof b.vc.verify === "function");
|
|
42
|
+
check("b.vc.VCDM_V2_CONTEXT is the v2 context", b.vc.VCDM_V2_CONTEXT === "https://www.w3.org/ns/credentials/v2");
|
|
43
|
+
check("b.vc.JOSE_ALGS includes ES256 + EdDSA", !!b.vc.JOSE_ALGS.ES256 && !!b.vc.JOSE_ALGS.EdDSA);
|
|
44
|
+
check("b.vc.VcError is a class", typeof b.vc.VcError === "function");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function testJoseRoundTrip() {
|
|
48
|
+
var jws = await b.vc.issue(_cred(), { securing: "jose", alg: "ES256", privateKey: EC.privateKey, kid: "k1", cty: "vc" });
|
|
49
|
+
check("jose: compact JWS has 3 segments", typeof jws === "string" && jws.split(".").length === 3);
|
|
50
|
+
var header = JSON.parse(Buffer.from(jws.split(".")[0], "base64url").toString("utf8"));
|
|
51
|
+
check("jose: typ header is vc+jwt", header.typ === "vc+jwt");
|
|
52
|
+
check("jose: cty + kid headers present", header.cty === "vc" && header.kid === "k1");
|
|
53
|
+
var payload = JSON.parse(Buffer.from(jws.split(".")[1], "base64url").toString("utf8"));
|
|
54
|
+
check("jose: payload is the credential, no injected iat/vc claim", payload.iat === undefined && payload.vc === undefined && payload.issuer === "did:example:issuer123");
|
|
55
|
+
|
|
56
|
+
var out = await b.vc.verify(jws, { algorithms: ["ES256"], publicKey: EC.publicKey, expectedIssuer: "did:example:issuer123" });
|
|
57
|
+
check("jose verify: securing detected", out.securing === "jose");
|
|
58
|
+
check("jose verify: alg + issuer", out.alg === "ES256" && out.issuer === "did:example:issuer123");
|
|
59
|
+
check("jose verify: credential returned", out.credential.credentialSubject.degree === "BS");
|
|
60
|
+
|
|
61
|
+
// EdDSA
|
|
62
|
+
var jed = await b.vc.issue(_cred(), { securing: "jose", alg: "EdDSA", privateKey: ED.privateKey });
|
|
63
|
+
var jedv = await b.vc.verify(jed, { algorithms: ["EdDSA"], publicKey: ED.publicKey });
|
|
64
|
+
check("jose EdDSA: round-trips", jedv.issuer === "did:example:issuer123");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function testCoseRoundTrip() {
|
|
68
|
+
var token = await b.vc.issue(_cred(), { securing: "cose", alg: "ES256", privateKey: EC.privateKey });
|
|
69
|
+
check("cose: returns tagged COSE_Sign1 bytes", Buffer.isBuffer(token) && token[0] === 0xd2);
|
|
70
|
+
var out = await b.vc.verify(token, { algorithms: ["ES256"], publicKey: EC.publicKey, expectedIssuer: "did:example:issuer123" });
|
|
71
|
+
check("cose verify: securing detected", out.securing === "cose");
|
|
72
|
+
check("cose verify: credential returned", out.credential.type.indexOf("VerifiableCredential") !== -1);
|
|
73
|
+
|
|
74
|
+
// ML-DSA-87 PQC-forward (skip gracefully if the runtime lacks it).
|
|
75
|
+
var ml = null;
|
|
76
|
+
try { ml = nodeCrypto.generateKeyPairSync("ml-dsa-87"); } catch (_e) { ml = null; }
|
|
77
|
+
if (ml) {
|
|
78
|
+
var t2 = await b.vc.issue(_cred(), { securing: "cose", alg: "ML-DSA-87", privateKey: ml.privateKey });
|
|
79
|
+
var o2 = await b.vc.verify(t2, { algorithms: ["ML-DSA-87"], publicKey: ml.publicKey });
|
|
80
|
+
check("cose ML-DSA-87: round-trips", o2.issuer === "did:example:issuer123");
|
|
81
|
+
} else {
|
|
82
|
+
check("cose ML-DSA-87: runtime lacks it — classical path covers the contract", true);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function testRefusals() {
|
|
87
|
+
var jws = await b.vc.issue(_cred(), { securing: "jose", alg: "ES256", privateKey: EC.privateKey });
|
|
88
|
+
|
|
89
|
+
var e1 = null;
|
|
90
|
+
try { await b.vc.verify(jws, { algorithms: ["EdDSA"], publicKey: EC.publicKey }); } catch (e) { e1 = e; }
|
|
91
|
+
check("verify: alg outside allowlist refused", e1 && e1.code === "vc/alg-not-allowed");
|
|
92
|
+
|
|
93
|
+
// tampered payload
|
|
94
|
+
var parts = jws.split(".");
|
|
95
|
+
parts[1] = Buffer.from(JSON.stringify(_cred({ issuer: "did:evil" })), "utf8").toString("base64url");
|
|
96
|
+
var e2 = null;
|
|
97
|
+
try { await b.vc.verify(parts.join("."), { algorithms: ["ES256"], publicKey: EC.publicKey }); } catch (e) { e2 = e; }
|
|
98
|
+
check("verify: tampered payload refused", e2 && e2.code === "vc/bad-signature");
|
|
99
|
+
|
|
100
|
+
// alg none always refused
|
|
101
|
+
var noneTok = Buffer.from(JSON.stringify({ alg: "none", typ: "vc+jwt" }), "utf8").toString("base64url") +
|
|
102
|
+
"." + Buffer.from(JSON.stringify(_cred()), "utf8").toString("base64url") + ".";
|
|
103
|
+
var e3 = null;
|
|
104
|
+
try { await b.vc.verify(noneTok, { algorithms: ["ES256"], publicKey: EC.publicKey }); } catch (e) { e3 = e; }
|
|
105
|
+
check("verify: JOSE alg 'none' refused", e3 && e3.code === "vc/bad-alg");
|
|
106
|
+
|
|
107
|
+
// expectedIssuer mismatch
|
|
108
|
+
var e4 = null;
|
|
109
|
+
try { await b.vc.verify(jws, { algorithms: ["ES256"], publicKey: EC.publicKey, expectedIssuer: "did:other" }); } catch (e) { e4 = e; }
|
|
110
|
+
check("verify: expectedIssuer mismatch refused", e4 && e4.code === "vc/issuer-mismatch");
|
|
111
|
+
|
|
112
|
+
// invalid opts.at Date refused (lesson carried from b.tsa)
|
|
113
|
+
var e5 = null;
|
|
114
|
+
try { await b.vc.verify(jws, { algorithms: ["ES256"], publicKey: EC.publicKey, at: new Date("nope") }); } catch (e) { e5 = e; }
|
|
115
|
+
check("verify: invalid opts.at refused", e5 && e5.code === "vc/bad-at");
|
|
116
|
+
|
|
117
|
+
// crit-bypass defense: a critical header extension the verifier does
|
|
118
|
+
// not implement must be refused (the check precedes signature verify).
|
|
119
|
+
var critTok = _rawJose({ alg: "ES256", typ: "vc+jwt", crit: ["https://example/ext"] }, _cred());
|
|
120
|
+
var e6 = null;
|
|
121
|
+
try { await b.vc.verify(critTok, { algorithms: ["ES256"], publicKey: EC.publicKey }); } catch (e) { e6 = e; }
|
|
122
|
+
check("verify: JWS crit header refused", e6 && e6.code === "vc/crit-unsupported");
|
|
123
|
+
|
|
124
|
+
// A malformed validity field on a validly-signed credential fails
|
|
125
|
+
// closed at verify (not just at issue) — no silent skip.
|
|
126
|
+
var badValidityTok = _rawJose({ alg: "ES256", typ: "vc+jwt" }, _cred({ validUntil: "not-a-date" }));
|
|
127
|
+
var e7 = null;
|
|
128
|
+
try { await b.vc.verify(badValidityTok, { algorithms: ["ES256"], publicKey: EC.publicKey }); } catch (e) { e7 = e; }
|
|
129
|
+
check("verify: malformed validUntil refused (fail closed)", e7 && e7.code === "vc/bad-validity");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function testTemporalAndStructural() {
|
|
133
|
+
// validUntil in the past → expired
|
|
134
|
+
var je = await b.vc.issue(_cred({ validUntil: "2020-01-01T00:00:00Z" }), { securing: "jose", alg: "ES256", privateKey: EC.privateKey });
|
|
135
|
+
var e1 = null;
|
|
136
|
+
try { await b.vc.verify(je, { algorithms: ["ES256"], publicKey: EC.publicKey }); } catch (e) { e1 = e; }
|
|
137
|
+
check("verify: expired credential refused", e1 && e1.code === "vc/expired");
|
|
138
|
+
|
|
139
|
+
// validFrom in the future → not yet valid
|
|
140
|
+
var jf = await b.vc.issue(_cred({ validFrom: "2099-01-01T00:00:00Z" }), { securing: "jose", alg: "ES256", privateKey: EC.privateKey });
|
|
141
|
+
var e2 = null;
|
|
142
|
+
try { await b.vc.verify(jf, { algorithms: ["ES256"], publicKey: EC.publicKey }); } catch (e) { e2 = e; }
|
|
143
|
+
check("verify: not-yet-valid credential refused", e2 && e2.code === "vc/not-yet-valid");
|
|
144
|
+
|
|
145
|
+
// opts.at lets a verifier check validity at a chosen instant
|
|
146
|
+
var ok = await b.vc.verify(je, { algorithms: ["ES256"], publicKey: EC.publicKey, at: new Date("2019-06-01T00:00:00Z") });
|
|
147
|
+
check("verify: opts.at within window accepts", ok.issuer === "did:example:issuer123");
|
|
148
|
+
|
|
149
|
+
// issue refuses a malformed VCDM credential
|
|
150
|
+
var structural = [
|
|
151
|
+
["missing v2 context", { "@context": ["https://other"], type: ["VerifiableCredential"], issuer: "x", credentialSubject: {} }, "vc/bad-context"],
|
|
152
|
+
["missing VerifiableCredential type", { "@context": ["https://www.w3.org/ns/credentials/v2"], type: ["Foo"], issuer: "x", credentialSubject: {} }, "vc/bad-type"],
|
|
153
|
+
["missing issuer", { "@context": ["https://www.w3.org/ns/credentials/v2"], type: ["VerifiableCredential"], credentialSubject: {} }, "vc/no-issuer"],
|
|
154
|
+
["missing credentialSubject", { "@context": ["https://www.w3.org/ns/credentials/v2"], type: ["VerifiableCredential"], issuer: "x" }, "vc/no-subject"],
|
|
155
|
+
];
|
|
156
|
+
for (var i = 0; i < structural.length; i++) {
|
|
157
|
+
var err = null;
|
|
158
|
+
try { await b.vc.issue(structural[i][1], { securing: "jose", alg: "ES256", privateKey: EC.privateKey }); } catch (e) { err = e; }
|
|
159
|
+
check("issue refuses: " + structural[i][0], err && err.code === structural[i][2]);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// issue refuses a malformed validity datetime (structural, fail closed)
|
|
163
|
+
var em = null;
|
|
164
|
+
try { await b.vc.issue(_cred({ validFrom: "yesterday" }), { securing: "jose", alg: "ES256", privateKey: EC.privateKey }); } catch (e) { em = e; }
|
|
165
|
+
check("issue refuses malformed validFrom", em && em.code === "vc/bad-validity");
|
|
166
|
+
|
|
167
|
+
// issuer-as-object { id } is accepted
|
|
168
|
+
var jo = await b.vc.issue(_cred({ issuer: { id: "did:example:obj", name: "Acme" } }), { securing: "jose", alg: "ES256", privateKey: EC.privateKey });
|
|
169
|
+
var oo = await b.vc.verify(jo, { algorithms: ["ES256"], publicKey: EC.publicKey, expectedIssuer: "did:example:obj" });
|
|
170
|
+
check("verify: object issuer id extracted", oo.issuer === "did:example:obj");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function run() {
|
|
174
|
+
testSurface();
|
|
175
|
+
await testJoseRoundTrip();
|
|
176
|
+
await testCoseRoundTrip();
|
|
177
|
+
await testRefusals();
|
|
178
|
+
await testTemporalAndStructural();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
module.exports = { run: run };
|
|
182
|
+
|
|
183
|
+
if (require.main === module) {
|
|
184
|
+
run().then(
|
|
185
|
+
function () { console.log("[vc] OK — " + helpers.getChecks() + " checks passed"); },
|
|
186
|
+
function (e) { console.error("FAIL:", e && e.stack || e); process.exit(1); }
|
|
187
|
+
);
|
|
188
|
+
}
|
package/package.json
CHANGED