@blamejs/blamejs-shop 0.2.9 → 0.2.11
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/asset-manifest.json +5 -5
- package/lib/storefront.js +231 -41
- package/lib/vendor/MANIFEST.json +3 -3
- package/lib/vendor/blamejs/CHANGELOG.md +6 -0
- package/lib/vendor/blamejs/README.md +2 -2
- package/lib/vendor/blamejs/api-snapshot.json +10 -2
- package/lib/vendor/blamejs/lib/agent-tenant.js +30 -0
- package/lib/vendor/blamejs/lib/archive-read.js +53 -40
- package/lib/vendor/blamejs/lib/archive-wrap.js +100 -32
- package/lib/vendor/blamejs/lib/cose.js +84 -0
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.13.20.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.13.21.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.13.22.json +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +46 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +50 -7
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +10 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +42 -0
- package/package.json +1 -1
|
@@ -82,13 +82,56 @@ async function testWrapRequiresRecipient() {
|
|
|
82
82
|
refused && /no-recipient/.test(refused.code || refused.message));
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
async function
|
|
86
|
-
var
|
|
85
|
+
async function testTenantStrategyRoundTrip() {
|
|
86
|
+
var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-aw-tenant-"));
|
|
87
87
|
try {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
await helpers.setupVaultOnly(tmpDir);
|
|
89
|
+
var src = Buffer.from("per-tenant sealed archive bytes ".repeat(40));
|
|
90
|
+
|
|
91
|
+
// wrap → unwrap round-trips for the same tenant, no key-pair managed.
|
|
92
|
+
var sealed = b.archive.wrap(src, { recipient: "tenant", tenantId: "alpha" });
|
|
93
|
+
check("archive.wrap tenant: BAWRP magic",
|
|
94
|
+
sealed.slice(0, 5).toString("ascii") === "BAWRP");
|
|
95
|
+
check("archive.wrap tenant: version byte is 0x02 (tenant)",
|
|
96
|
+
sealed[5] === 0x02);
|
|
97
|
+
var recovered = b.archive.unwrap(sealed, { recipient: "tenant", tenantId: "alpha" });
|
|
98
|
+
check("archive.wrap tenant: round-trips losslessly", recovered.equals(src));
|
|
99
|
+
// recipient may be omitted on unwrap (version byte selects the path).
|
|
100
|
+
var recovered2 = b.archive.unwrap(sealed, { tenantId: "alpha" });
|
|
101
|
+
check("archive.wrap tenant: unwrap works with tenantId alone", recovered2.equals(src));
|
|
102
|
+
|
|
103
|
+
// Cross-tenant isolation — a different tenant's derived key (and AAD)
|
|
104
|
+
// cannot open tenant alpha's envelope.
|
|
105
|
+
var crossErr = null;
|
|
106
|
+
try { b.archive.unwrap(sealed, { recipient: "tenant", tenantId: "beta" }); }
|
|
107
|
+
catch (e) { crossErr = e; }
|
|
108
|
+
check("archive.wrap tenant: another tenant cannot decrypt",
|
|
109
|
+
crossErr && /decrypt-failed/.test(crossErr.code || crossErr.message));
|
|
110
|
+
|
|
111
|
+
// Missing tenantId on wrap throws a clear config error.
|
|
112
|
+
var noIdErr = null;
|
|
113
|
+
try { b.archive.wrap(src, { recipient: "tenant" }); }
|
|
114
|
+
catch (e) { noIdErr = e; }
|
|
115
|
+
check("archive.wrap tenant: missing tenantId throws no-tenant-id",
|
|
116
|
+
noIdErr && /no-tenant-id/.test(noIdErr.code || noIdErr.message));
|
|
117
|
+
|
|
118
|
+
// Passing a key-pair recipient to a tenant envelope is refused.
|
|
119
|
+
var mismatchErr = null;
|
|
120
|
+
try { b.archive.unwrap(sealed, { recipient: { privateKey: "x", ecPrivateKey: "y" } }); }
|
|
121
|
+
catch (e) { mismatchErr = e; }
|
|
122
|
+
check("archive.wrap tenant: key-pair recipient on tenant envelope refused",
|
|
123
|
+
mismatchErr && /recipient-mismatch/.test(mismatchErr.code || mismatchErr.message));
|
|
124
|
+
|
|
125
|
+
// Determinism — re-wrapping the same bytes for the same tenant yields
|
|
126
|
+
// a DIFFERENT envelope (fresh nonce) that still opens to the same plaintext.
|
|
127
|
+
var sealed2 = b.archive.wrap(src, { recipient: "tenant", tenantId: "alpha" });
|
|
128
|
+
check("archive.wrap tenant: fresh nonce per wrap (envelopes differ)",
|
|
129
|
+
!sealed2.equals(sealed));
|
|
130
|
+
check("archive.wrap tenant: second envelope also round-trips",
|
|
131
|
+
b.archive.unwrap(sealed2, { tenantId: "alpha" }).equals(src));
|
|
132
|
+
} finally {
|
|
133
|
+
helpers.teardownVaultOnly(tmpDir);
|
|
134
|
+
}
|
|
92
135
|
}
|
|
93
136
|
|
|
94
137
|
async function testBackupRecipientRoundTrip() {
|
|
@@ -159,7 +202,7 @@ async function run() {
|
|
|
159
202
|
await testWrapRefusesWrongKey();
|
|
160
203
|
await testWrapRefusesPartialStaticRecipient();
|
|
161
204
|
await testWrapRequiresRecipient();
|
|
162
|
-
await
|
|
205
|
+
await testTenantStrategyRoundTrip();
|
|
163
206
|
await testBackupRecipientRoundTrip();
|
|
164
207
|
await testBackupRecipientStrategyRequiresKeys();
|
|
165
208
|
await testBackupRecipientDirectoryRefused();
|
|
@@ -2387,6 +2387,16 @@ async function testNoDuplicateCodeBlocks() {
|
|
|
2387
2387
|
],
|
|
2388
2388
|
reason: "v0.12.48 / v0.12.51 / v0.12.52 / v0.12.53 / v0.13.x — Buffer-coercion guard (`if (Buffer.isBuffer(x)) return x; if (x instanceof Uint8Array) return Buffer.from(x); ...`) repeats across byte-string-consuming primitives. The throw-on-unknown variants (cose / mdoc / dnssec / dane / tsa) each raise a MODULE-LOCAL typed error code naming the local argument; the JSON-fallback variants (eat._toBuf serializing a CBOR/EAT claims payload, worm._toBytes serializing a record to hash) instead JSON.stringify a non-bytes value. The duplicated prefix is the symptom; the cause is that JS can't throw a caller-namespaced ErrorClass (or choose the domain's serialization) without the local closure. Same documented exception as the v0.12.7 require-non-empty-string cluster — the per-domain error code / serialization is the divergence the dup detector can't see.",
|
|
2389
2389
|
},
|
|
2390
|
+
{
|
|
2391
|
+
mode: "family-subset",
|
|
2392
|
+
files: [
|
|
2393
|
+
"lib/cose.js:importKey",
|
|
2394
|
+
"lib/cose.js:exportKey",
|
|
2395
|
+
"lib/did.js:_jwkToKey",
|
|
2396
|
+
"lib/network-dnssec.js:_jwkKey",
|
|
2397
|
+
],
|
|
2398
|
+
reason: "v0.13.20 — EC/OKP JWK-coordinate handling (`kty` + `crv` switch over P-256/P-384/P-521 + Ed25519, base64url x/y, `createPublicKey({ format: 'jwk' })`) is coincidentally similar across three unrelated wire formats: cose.importKey/exportKey map a COSE_Key (RFC 9052 §7 — INTEGER crv ids -1/-2/-3 and labels) to/from a KeyObject; did._jwkToKey resolves a W3C DID verification method's JWK; network-dnssec._jwkKey reconstructs a DNSKEY's public key. The curve identifiers, the surrounding map shape, and the direction (import builds a key from a map, export emits a map from a key) all differ per spec — extracting a shared helper would couple three independent standards on a syntactic accident. The shingle is the JWK-coordinate idiom, not behaviour; same documented exception as the v0.12.40 signature-verify-preamble cluster.",
|
|
2399
|
+
},
|
|
2390
2400
|
{
|
|
2391
2401
|
mode: "family-subset",
|
|
2392
2402
|
files: [
|
|
@@ -247,6 +247,47 @@ async function testImportKey() {
|
|
|
247
247
|
check("importKey: secp256k1 refused (no ES256K binding)", secpBad && secpBad.code === "cose/unsupported-key");
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
+
async function testExportKey() {
|
|
251
|
+
// EC2 P-256 → COSE_Key bytes → decode → importKey round-trips, and
|
|
252
|
+
// the re-imported key verifies a COSE_Sign1 the original signed.
|
|
253
|
+
var bytes = b.cose.exportKey(EC.publicKey, { alg: "ES256", kid: "key-1" });
|
|
254
|
+
check("exportKey: returns CBOR bytes", Buffer.isBuffer(bytes));
|
|
255
|
+
var map = b.cbor.decode(bytes);
|
|
256
|
+
check("exportKey: kty=EC2 (2)", map.get(1) === 2);
|
|
257
|
+
check("exportKey: crv=P-256 (1)", map.get(-1) === 1);
|
|
258
|
+
check("exportKey: x matches the JWK", map.get(-2).toString("base64url") === EC.publicKey.export({ format: "jwk" }).x);
|
|
259
|
+
check("exportKey: alg label 3 = ES256 (-7)", map.get(3) === -7);
|
|
260
|
+
check("exportKey: kid label 2 = 'key-1'", Buffer.isBuffer(map.get(2)) && map.get(2).toString("utf8") === "key-1");
|
|
261
|
+
var reimported = b.cose.importKey(map);
|
|
262
|
+
var att = await b.cose.sign(Buffer.from("rt"), { alg: "ES256", privateKey: EC.privateKey });
|
|
263
|
+
check("exportKey → importKey: round-trips for verification",
|
|
264
|
+
(await b.cose.verify(att, { algorithms: ["ES256"], publicKey: reimported })).payload.toString() === "rt");
|
|
265
|
+
|
|
266
|
+
// OKP Ed25519 round-trip.
|
|
267
|
+
var edBytes = b.cose.exportKey(ED.publicKey);
|
|
268
|
+
var edMap = b.cbor.decode(edBytes);
|
|
269
|
+
check("exportKey: OKP kty=1 + crv Ed25519 (6)", edMap.get(1) === 1 && edMap.get(-1) === 6);
|
|
270
|
+
check("exportKey: OKP re-imports to ed25519",
|
|
271
|
+
b.cose.importKey(edMap).asymmetricKeyType === "ed25519");
|
|
272
|
+
|
|
273
|
+
// A private key exports its PUBLIC half (never the secret).
|
|
274
|
+
var fromPriv = b.cbor.decode(b.cose.exportKey(EC.privateKey));
|
|
275
|
+
check("exportKey: private key exports the public coordinates",
|
|
276
|
+
fromPriv.get(-2).toString("base64url") === EC.publicKey.export({ format: "jwk" }).x);
|
|
277
|
+
|
|
278
|
+
// Unsupported curve / key type / bad opts refused.
|
|
279
|
+
var k1 = nodeCrypto.generateKeyPairSync("ec", { namedCurve: "secp256k1" });
|
|
280
|
+
var secpBad = null;
|
|
281
|
+
try { b.cose.exportKey(k1.publicKey); } catch (e) { secpBad = e; }
|
|
282
|
+
check("exportKey: secp256k1 refused", secpBad && secpBad.code === "cose/unsupported-key");
|
|
283
|
+
var notKey = null;
|
|
284
|
+
try { b.cose.exportKey({ not: "a key" }); } catch (e) { notKey = e; }
|
|
285
|
+
check("exportKey: non-KeyObject refused", notKey && notKey.code === "cose/bad-key");
|
|
286
|
+
var badAlg = null;
|
|
287
|
+
try { b.cose.exportKey(EC.publicKey, { alg: "NOPE" }); } catch (e) { badAlg = e; }
|
|
288
|
+
check("exportKey: unknown alg refused", badAlg && badAlg.code === "cose/unknown-alg");
|
|
289
|
+
}
|
|
290
|
+
|
|
250
291
|
async function run() {
|
|
251
292
|
testSurface();
|
|
252
293
|
testEncrypt0();
|
|
@@ -258,6 +299,7 @@ async function run() {
|
|
|
258
299
|
await testValidation();
|
|
259
300
|
await testDetachedPayload();
|
|
260
301
|
await testImportKey();
|
|
302
|
+
await testExportKey();
|
|
261
303
|
testMac0();
|
|
262
304
|
}
|
|
263
305
|
|
package/package.json
CHANGED