@blamejs/blamejs-shop 0.0.124 → 0.0.126

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.
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ /**
3
+ * Layer 0 — b.auth.jar.parse: RFC 9101 JWT-Secured Authorization
4
+ * Request (server side). Verifies the client-signed request object
5
+ * via verifyExternal (mandatory alg allowlist), pins iss + client_id
6
+ * + aud, refuses nested request / request_uri, and returns the
7
+ * authorization parameters. Request objects are signed inline with a
8
+ * classical key (RS256) to mirror a real OAuth client.
9
+ */
10
+
11
+ var helpers = require("../helpers");
12
+ var b = helpers.b;
13
+ var check = helpers.check;
14
+ var nodeCrypto = require("node:crypto");
15
+
16
+ function _b64url(buf) {
17
+ return Buffer.from(buf).toString("base64").replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_");
18
+ }
19
+ function _signRs256(privateKey, header, payload) {
20
+ var input = _b64url(JSON.stringify(header)) + "." + _b64url(JSON.stringify(payload));
21
+ var sig = nodeCrypto.sign("sha256", Buffer.from(input, "ascii"),
22
+ { key: privateKey, padding: nodeCrypto.constants.RSA_PKCS1_PADDING });
23
+ return input + "." + _b64url(sig);
24
+ }
25
+ function _rsaPair() {
26
+ return nodeCrypto.generateKeyPairSync("rsa", {
27
+ modulusLength: 2048,
28
+ publicKeyEncoding: { type: "spki", format: "jwk" },
29
+ privateKeyEncoding: { type: "pkcs8", format: "pem" },
30
+ });
31
+ }
32
+ function _nowSec() { return Math.floor(Date.now() / 1000); }
33
+
34
+ var KEYS = _rsaPair();
35
+ var JWK = Object.assign({}, KEYS.publicKey, { kid: "c1", use: "sig", alg: "RS256" });
36
+ var AS = "https://as.example.com";
37
+ var CLIENT = "s6BhdRkqt3";
38
+
39
+ function _requestObject(extraClaims) {
40
+ var payload = Object.assign({
41
+ iss: CLIENT,
42
+ aud: AS,
43
+ client_id: CLIENT,
44
+ response_type: "code",
45
+ redirect_uri: "https://app.example.com/cb",
46
+ scope: "openid profile",
47
+ state: "xyz-state",
48
+ nonce: "n-0S6_WzA2Mj",
49
+ iat: _nowSec(),
50
+ exp: _nowSec() + 120,
51
+ }, extraClaims || {});
52
+ return _signRs256(KEYS.privateKey, { alg: "RS256", typ: "oauth-authz-req+jwt", kid: "c1" }, payload);
53
+ }
54
+
55
+ function _parseOpts(over) {
56
+ var o = { clientId: CLIENT, audience: AS, algorithms: ["RS256"], jwks: [JWK] };
57
+ if (over) { var k = Object.keys(over); for (var i = 0; i < k.length; i++) o[k[i]] = over[k[i]]; }
58
+ return o;
59
+ }
60
+
61
+ async function testRoundTrip() {
62
+ var jar = _requestObject();
63
+ var out = await b.auth.jar.parse(jar, _parseOpts());
64
+ check("parse: returns authorization params", out.params.response_type === "code" && out.params.redirect_uri === "https://app.example.com/cb");
65
+ check("parse: preserves state + nonce + scope", out.params.state === "xyz-state" && out.params.nonce === "n-0S6_WzA2Mj" && out.params.scope === "openid profile");
66
+ check("parse: strips JWT envelope claims from params", out.params.iss === undefined && out.params.aud === undefined && out.params.exp === undefined && out.params.iat === undefined);
67
+ check("parse: full claims still available", out.claims.iss === CLIENT && out.claims.aud === AS);
68
+ }
69
+
70
+ async function testAntiNesting() {
71
+ var withUri = _requestObject({ request_uri: "https://evil.example.com/ro" });
72
+ var e1 = null;
73
+ try { await b.auth.jar.parse(withUri, _parseOpts()); } catch (e) { e1 = e; }
74
+ check("parse: nested request_uri refused (RFC 9101 §6.3)", e1 && e1.code === "auth-jar/nested-request");
75
+ var withReq = _requestObject({ request: "ey.another.jwt" });
76
+ var e2 = null;
77
+ try { await b.auth.jar.parse(withReq, _parseOpts()); } catch (e) { e2 = e; }
78
+ check("parse: nested request refused", e2 && e2.code === "auth-jar/nested-request");
79
+ }
80
+
81
+ async function testClientIdBinding() {
82
+ // iss matches clientId, but the client_id claim differs → mismatch.
83
+ var mismatched = _requestObject({ client_id: "different-client" });
84
+ var e1 = null;
85
+ try { await b.auth.jar.parse(mismatched, _parseOpts()); } catch (e) { e1 = e; }
86
+ check("parse: client_id claim mismatch refused", e1 && e1.code === "auth-jar/client-id-mismatch");
87
+
88
+ // iss itself differs from expected clientId → verifyExternal issuer pin throws.
89
+ var wrongIss = _signRs256(KEYS.privateKey, { alg: "RS256", typ: "oauth-authz-req+jwt", kid: "c1" },
90
+ { iss: "attacker-client", aud: AS, client_id: "attacker-client", response_type: "code",
91
+ iat: _nowSec(), exp: _nowSec() + 120 });
92
+ var e2 = null;
93
+ try { await b.auth.jar.parse(wrongIss, _parseOpts()); } catch (e) { e2 = e; }
94
+ check("parse: iss not matching expected client refused (verifyExternal issuer pin)", e2 !== null);
95
+
96
+ // Codex P2 on PR #182 — a request object that OMITS client_id must
97
+ // be refused (RFC 9101 §5.2 requires it in the signed object), not
98
+ // waved through on the strength of an outer query-param client_id.
99
+ var noClientId = _signRs256(KEYS.privateKey, { alg: "RS256", typ: "oauth-authz-req+jwt", kid: "c1" },
100
+ { iss: CLIENT, aud: AS, response_type: "code", redirect_uri: "https://app/cb",
101
+ iat: _nowSec(), exp: _nowSec() + 120 });
102
+ var e3 = null;
103
+ try { await b.auth.jar.parse(noClientId, _parseOpts()); } catch (e) { e3 = e; }
104
+ check("parse: missing client_id claim refused (RFC 9101 §5.2)", e3 && e3.code === "auth-jar/missing-client-id");
105
+ }
106
+
107
+ async function testAlgConfusionDelegated() {
108
+ var jar = _requestObject();
109
+ // Valid RS256 JAR, but the AS only accepts HS256 → verifyExternal refuses the HMAC alg.
110
+ var e1 = null;
111
+ try { await b.auth.jar.parse(jar, _parseOpts({ algorithms: ["HS256"] })); } catch (e) { e1 = e; }
112
+ check("parse: HMAC in the allowlist refused (alg-confusion defense delegated)", e1 && /refused-alg/.test(e1.code || ""));
113
+ // Audience mismatch → verifyExternal aud pin throws.
114
+ var e2 = null;
115
+ try { await b.auth.jar.parse(jar, _parseOpts({ audience: "https://other-as.example.com" })); } catch (e) { e2 = e; }
116
+ check("parse: audience mismatch refused", e2 !== null);
117
+ }
118
+
119
+ async function testValidation() {
120
+ var bads = [
121
+ [function () { return b.auth.jar.parse("", _parseOpts()); }, "auth-jar/no-jar"],
122
+ [function () { return b.auth.jar.parse(_requestObject(), { audience: AS, algorithms: ["RS256"], jwks: [JWK] }); }, "auth-jar/bad-client-id"],
123
+ [function () { return b.auth.jar.parse(_requestObject(), { clientId: CLIENT, algorithms: ["RS256"], jwks: [JWK] }); }, "auth-jar/bad-audience"],
124
+ ];
125
+ var ok = true;
126
+ for (var i = 0; i < bads.length; i++) {
127
+ var caught = null;
128
+ try { await bads[i][0](); } catch (e) { caught = e; }
129
+ if (!caught || caught.code !== bads[i][1]) { ok = false; check("validation case " + i + " expected " + bads[i][1] + " got " + (caught && caught.code), false); }
130
+ }
131
+ check("parse: malformed args throw the right codes", ok);
132
+ // Missing algorithms → verifyExternal requires it (no defaults).
133
+ var noAlg = null;
134
+ try { await b.auth.jar.parse(_requestObject(), { clientId: CLIENT, audience: AS, jwks: [JWK] }); } catch (e) { noAlg = e; }
135
+ check("parse: missing algorithms refused (verifyExternal — no alg defaults)", noAlg !== null);
136
+ }
137
+
138
+ async function run() {
139
+ await testRoundTrip();
140
+ await testAntiNesting();
141
+ await testClientIdBinding();
142
+ await testAlgConfusionDelegated();
143
+ await testValidation();
144
+ }
145
+
146
+ module.exports = { run: run };
147
+
148
+ if (require.main === module) {
149
+ run().then(
150
+ function () { console.log("[auth-jar] OK — " + helpers.getChecks() + " checks passed"); },
151
+ function (e) { console.error("FAIL:", e && e.stack || e); process.exit(1); }
152
+ );
153
+ }
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ /**
3
+ * Layer 0 — bundleAdapterStorage.keyRotation: whole-repository
4
+ * envelope rotation (composes rewrapAllBundles) + post-rotation
5
+ * read-back under the new key (composes verifyAllBundles), so a
6
+ * rotation that corrupts a bundle surfaces immediately rather than at
7
+ * restore time.
8
+ */
9
+
10
+ var fs = require("node:fs");
11
+ var path = require("node:path");
12
+ var os = require("node:os");
13
+ var b = require("../../index");
14
+ var helpers = require("../helpers");
15
+ var check = helpers.check;
16
+
17
+ function _mk(prefix) { return fs.mkdtempSync(path.join(os.tmpdir(), prefix)); }
18
+ function _rm(d) { try { fs.rmSync(d, { recursive: true, force: true }); } catch (_e) { /* ignore */ } }
19
+
20
+ async function testKeyRotationRecipient() {
21
+ var oldPair = b.crypto.generateEncryptionKeyPair();
22
+ var newPair = b.crypto.generateEncryptionKeyPair();
23
+ var src = _mk("kr-src-");
24
+ var dest = _mk("kr-dest-");
25
+ try {
26
+ fs.writeFileSync(path.join(src, "a"), "payload", { mode: 0o600 });
27
+ var storage = b.backup.bundleAdapterStorage({
28
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: dest }),
29
+ format: "tar.gz",
30
+ cryptoStrategy: "recipient",
31
+ recipient: oldPair,
32
+ audit: false,
33
+ });
34
+ var ids = ["2026-05-24T09-00-00-000Z-aa000001", "2026-05-24T09-15-00-000Z-aa000002"];
35
+ for (var i = 0; i < ids.length; i += 1) await storage.writeBundle(ids[i], src);
36
+
37
+ var report = await storage.keyRotation({ newRecipient: newPair });
38
+ check("keyRotation: rotated every bundle", report.total === 2 && report.rotated === 2 && report.failed === 0);
39
+ check("keyRotation: post-rotation verify read every bundle under the new key",
40
+ report.verified === 2 && report.verifyFailed === 0);
41
+ check("keyRotation: carries a rotationId + rotatedAt", /^rotation-/.test(report.rotationId) && typeof report.rotatedAt === "string");
42
+
43
+ // Independent confirmation: a fresh storage under the NEW key reads all bundles.
44
+ var fresh = b.backup.bundleAdapterStorage({
45
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: dest }),
46
+ format: "tar.gz",
47
+ cryptoStrategy: "recipient",
48
+ recipient: newPair,
49
+ audit: false,
50
+ });
51
+ var v = await fresh.verifyAllBundles();
52
+ check("keyRotation: rotation landed — new-key storage verifies all", v.ok === 2 && v.failed === 0);
53
+ } finally { _rm(src); _rm(dest); }
54
+ }
55
+
56
+ async function testKeyRotationPassphrase() {
57
+ var oldPass = b.crypto.generateBytes(32).toString("hex");
58
+ var newPass = b.crypto.generateBytes(32).toString("hex");
59
+ var src = _mk("kr-pp-src-");
60
+ var dest = _mk("kr-pp-dest-");
61
+ try {
62
+ fs.writeFileSync(path.join(src, "a"), "payload", { mode: 0o600 });
63
+ var storage = b.backup.bundleAdapterStorage({
64
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: dest }),
65
+ format: "tar.gz",
66
+ cryptoStrategy: "passphrase",
67
+ passphrase: oldPass,
68
+ audit: false,
69
+ });
70
+ await storage.writeBundle("2026-05-24T11-00-00-000Z-bb000001", src);
71
+ var report = await storage.keyRotation({ oldPassphrase: oldPass, newPassphrase: newPass });
72
+ check("keyRotation: passphrase rotation rotated + verified",
73
+ report.rotated === 1 && report.failed === 0 && report.verified === 1 && report.verifyFailed === 0);
74
+ } finally { _rm(src); _rm(dest); }
75
+ }
76
+
77
+ async function testKeyRotationVerifyOptOut() {
78
+ var oldPair = b.crypto.generateEncryptionKeyPair();
79
+ var newPair = b.crypto.generateEncryptionKeyPair();
80
+ var src = _mk("kr-nov-src-");
81
+ var dest = _mk("kr-nov-dest-");
82
+ try {
83
+ fs.writeFileSync(path.join(src, "a"), "payload", { mode: 0o600 });
84
+ var storage = b.backup.bundleAdapterStorage({
85
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: dest }),
86
+ format: "tar.gz",
87
+ cryptoStrategy: "recipient",
88
+ recipient: oldPair,
89
+ audit: false,
90
+ });
91
+ await storage.writeBundle("2026-05-24T12-00-00-000Z-cc000001", src);
92
+ var report = await storage.keyRotation({ newRecipient: newPair, verify: false });
93
+ check("keyRotation: verify:false skips read-back (verified null)", report.rotated === 1 && report.verified === null && report.verifyFailed === 0);
94
+ } finally { _rm(src); _rm(dest); }
95
+ }
96
+
97
+ async function testKeyRotationRefusals() {
98
+ var dest = _mk("kr-ref-dest-");
99
+ try {
100
+ // cryptoStrategy "none" — nothing to rotate.
101
+ var plain = b.backup.bundleAdapterStorage({
102
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: dest }), audit: false,
103
+ });
104
+ var none = null;
105
+ try { await plain.keyRotation({ newRecipient: b.crypto.generateEncryptionKeyPair() }); } catch (e) { none = e; }
106
+ check("keyRotation: refuses on cryptoStrategy none", none && none.code === "backup/no-envelope-to-rewrap");
107
+
108
+ var rec = b.backup.bundleAdapterStorage({
109
+ adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: dest }),
110
+ cryptoStrategy: "recipient",
111
+ recipient: b.crypto.generateEncryptionKeyPair(),
112
+ audit: false,
113
+ });
114
+ // Missing newRecipient.
115
+ var noNew = null;
116
+ try { await rec.keyRotation({}); } catch (e) { noNew = e; }
117
+ check("keyRotation: refuses without newRecipient", noNew && noNew.code === "backup/no-recipient");
118
+
119
+ // dualWrap deferred-with-condition.
120
+ var dual = null;
121
+ try { await rec.keyRotation({ newRecipient: b.crypto.generateEncryptionKeyPair(), dualWrap: true }); } catch (e) { dual = e; }
122
+ check("keyRotation: dualWrap refused (deferred — needs multi-recipient envelopes)",
123
+ dual && dual.code === "backup/dual-wrap-unsupported");
124
+ } finally { _rm(dest); }
125
+ }
126
+
127
+ async function run() {
128
+ await testKeyRotationRecipient();
129
+ await testKeyRotationPassphrase();
130
+ await testKeyRotationVerifyOptOut();
131
+ await testKeyRotationRefusals();
132
+ }
133
+
134
+ module.exports = { run: run };
135
+
136
+ if (require.main === module) {
137
+ run().then(
138
+ function () { console.log("[backup-key-rotation] OK — " + helpers.getChecks() + " checks passed"); },
139
+ function (e) { console.error("FAIL:", e && e.stack || e); process.exit(1); }
140
+ );
141
+ }
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ /**
3
+ * Layer 0 — b.cbor bounded deterministic CBOR codec (RFC 8949).
4
+ * Encoder validated against RFC 8949 Appendix A vectors + §4.2
5
+ * deterministic encoding; decoder validated against the bounded
6
+ * refusals (depth / size / indefinite-length / reserved-ai / tag /
7
+ * duplicate-key / trailing-byte / non-canonical).
8
+ */
9
+
10
+ var b = require("../../index");
11
+ var helpers = require("../helpers");
12
+ var check = helpers.check;
13
+ var cbor = b.cbor;
14
+
15
+ function _hex(buf) { return Buffer.from(buf).toString("hex"); }
16
+
17
+ function testSurface() {
18
+ // Reference every export through the public b.cbor.* path (the
19
+ // coverage gate matches the dotted form).
20
+ check("b.cbor.encode exposed", typeof b.cbor.encode === "function");
21
+ check("b.cbor.decode exposed", typeof b.cbor.decode === "function");
22
+ check("b.cbor.Tag exposed", typeof b.cbor.Tag === "function");
23
+ check("b.cbor.CborError exposed", typeof b.cbor.CborError === "function");
24
+ var rt = b.cbor.decode(b.cbor.encode(new b.cbor.Tag(0, "x")), { allowedTags: [0] });
25
+ check("b.cbor round-trips a tag via the public path", rt instanceof b.cbor.Tag && rt.value === "x");
26
+ var err = null;
27
+ try { b.cbor.decode(Buffer.from([0x9f, 0x01, 0xff])); } catch (e) { err = e; }
28
+ check("b.cbor.CborError is thrown on bad input", err instanceof b.cbor.CborError);
29
+ }
30
+
31
+ function testAppendixAVectors() {
32
+ // RFC 8949 Appendix A.
33
+ var vectors = [
34
+ [0, "00"], [1, "01"], [10, "0a"], [23, "17"], [24, "1818"], [100, "1864"],
35
+ [1000, "1903e8"], [-1, "20"], [-100, "3863"], [1000000, "1a000f4240"],
36
+ [false, "f4"], [true, "f5"], [null, "f6"],
37
+ ["", "60"], ["a", "6161"], ["IETF", "6449455446"], ["ü", "62c3bc"],
38
+ [[], "80"], [[1, 2, 3], "83010203"], [[1, [2, 3], [4, 5]], "8301820203820405"],
39
+ ];
40
+ var ok = true;
41
+ for (var i = 0; i < vectors.length; i++) {
42
+ var got = _hex(cbor.encode(vectors[i][0]));
43
+ if (got !== vectors[i][1]) { ok = false; check("vector " + JSON.stringify(vectors[i][0]) + " → " + vectors[i][1] + " (got " + got + ")", false); }
44
+ }
45
+ check("encode: matches RFC 8949 Appendix A integer/string/array vectors", ok);
46
+ check("encode: bytes h'01020304' → 4401020304", _hex(cbor.encode(Buffer.from([1, 2, 3, 4]))) === "4401020304");
47
+ // Preferred float serialization (§4.2.1): shortest width that
48
+ // round-trips. 1.5 fits float16; an integer-valued float is encoded
49
+ // as an integer (deterministic encoding prefers the shortest form).
50
+ check("encode: float 1.5 → f93e00 (preferred half)", _hex(cbor.encode(1.5)) === "f93e00");
51
+ check("encode: 100000 → integer, not float", _hex(cbor.encode(100000)) === "1a000186a0");
52
+ check("encode: 3.4 → float64 (not half/float32 representable)", _hex(cbor.encode(3.4)) === "fb400b333333333333");
53
+ check("encode: map {1:2,3:4} (int keys) → a201020304", _hex(cbor.encode(new Map([[1, 2], [3, 4]]))) === "a201020304");
54
+ check("encode: nested {a:1,b:[2,3]} → a26161016162820203", _hex(cbor.encode({ a: 1, b: [2, 3] })) === "a26161016162820203");
55
+ }
56
+
57
+ function testDeterministicEncoding() {
58
+ // §4.2 — map keys sorted by encoded-key bytes regardless of order.
59
+ check("deterministic: map key order is normalized", _hex(cbor.encode({ b: 2, a: 1 })) === _hex(cbor.encode({ a: 1, b: 2 })));
60
+ check("deterministic: shortest-form integer head", _hex(cbor.encode(24)) === "1818" && _hex(cbor.encode(23)) === "17");
61
+ // Duplicate key on encode (a Map can hold structurally-equal encoded keys only via distinct JS keys — guard the explicit case).
62
+ var dup = null;
63
+ try { cbor.encode(new Map([["a", 1]])); } catch (e) { dup = e; }
64
+ check("deterministic: well-formed map encodes", dup === null);
65
+ }
66
+
67
+ function testRoundTrip() {
68
+ var value = { id: 7, tags: ["x", "y"], meta: new Map([[1, "alg"], [2, Buffer.from([0xab])]]), ok: true, n: null };
69
+ var decoded = cbor.decode(cbor.encode(value));
70
+ check("round-trip: top-level map decodes to Map", decoded instanceof Map);
71
+ check("round-trip: scalar + array + nested preserved",
72
+ decoded.get("id") === 7 && decoded.get("tags")[1] === "y" && decoded.get("ok") === true && decoded.get("n") === null);
73
+ check("round-trip: nested map int keys preserved", decoded.get("meta") instanceof Map && decoded.get("meta").get(1) === "alg");
74
+ check("round-trip: byte string preserved", Buffer.isBuffer(decoded.get("meta").get(2)) && decoded.get("meta").get(2)[0] === 0xab);
75
+ // negative + float + float16 decode
76
+ check("round-trip: negative int", cbor.decode(cbor.encode(-100)) === -100);
77
+ check("round-trip: float64", cbor.decode(cbor.encode(3.14159)) === 3.14159);
78
+ check("decode: float16 (0xf93e00 = 1.5)", cbor.decode(Buffer.from([0xf9, 0x3e, 0x00])) === 1.5);
79
+ // Preferred-width round-trips: each chooses the shortest exact form.
80
+ [1.5, -2.5, 0.5, 3.4, 1e300, 5.960464477539063e-8].forEach(function (n) {
81
+ check("preferred-float round-trip " + n, cbor.decode(cbor.encode(n)) === n);
82
+ });
83
+ // A canonically float16-encoded value passes requireDeterministic
84
+ // (the preferred-serialization fix — float64 emission would falsely
85
+ // reject it).
86
+ check("requireDeterministic: float16-canonical input accepted", cbor.decode(cbor.encode(1.5), { requireDeterministic: true }) === 1.5);
87
+ }
88
+
89
+ function testInvalidUtf8() {
90
+ // CBOR text strings must be valid UTF-8 (§3.1) — malformed bytes are
91
+ // refused, not silently replaced with U+FFFD.
92
+ var bad = null;
93
+ try { cbor.decode(Buffer.from([0x63, 0xff, 0xff, 0xff])); } catch (e) { bad = e; } // text(3) + invalid bytes
94
+ check("decode: invalid UTF-8 text string refused", bad && bad.code === "cbor/invalid-utf8");
95
+ check("decode: valid multibyte UTF-8 preserved", cbor.decode(cbor.encode("héllo ☃")) === "héllo ☃");
96
+ }
97
+
98
+ function testTags() {
99
+ var enc = cbor.encode(new cbor.Tag(42, "answer"));
100
+ check("encode: tagged value", _hex(enc) === "d82a66616e73776572");
101
+ var refused = null;
102
+ try { cbor.decode(enc); } catch (e) { refused = e; }
103
+ check("decode: tag refused unless allowlisted", refused && refused.code === "cbor/tag-refused");
104
+ var t = cbor.decode(enc, { allowedTags: [42] });
105
+ check("decode: allowlisted tag returns Tag", t instanceof cbor.Tag && t.tag === 42 && t.value === "answer");
106
+ }
107
+
108
+ function testBoundedRefusals() {
109
+ var cases = [
110
+ ["indefinite array", Buffer.from([0x9f, 0x01, 0xff]), {}, "cbor/indefinite-refused"],
111
+ ["reserved ai-28", Buffer.from([0x1c]), {}, "cbor/reserved-ai"],
112
+ ["duplicate map key", Buffer.from([0xa2, 0x01, 0x02, 0x01, 0x03]), {}, "cbor/duplicate-key"],
113
+ ["trailing bytes", Buffer.from([0x01, 0x02]), {}, "cbor/trailing-bytes"],
114
+ ["truncated head", Buffer.from([0x18]), {}, "cbor/truncated"],
115
+ ["length bomb (no data)", Buffer.from([0x9a, 0xff, 0xff, 0xff, 0xff]), {}, "cbor/truncated"],
116
+ ["bad simple value (major 7, ai 28)", Buffer.from([0xfc]), {}, "cbor/bad-simple"],
117
+ ];
118
+ var ok = true;
119
+ for (var i = 0; i < cases.length; i++) {
120
+ var caught = null;
121
+ try { cbor.decode(cases[i][1], cases[i][2]); } catch (e) { caught = e; }
122
+ if (!caught || caught.code !== cases[i][3]) { ok = false; check(cases[i][0] + " expected " + cases[i][3] + " got " + (caught && caught.code), false); }
123
+ }
124
+ check("decode: bounded refusals fire with the right codes", ok);
125
+
126
+ var depth = null;
127
+ try { cbor.decode(cbor.encode([[[[[1]]]]]), { maxDepth: 2 }); } catch (e) { depth = e; }
128
+ check("decode: maxDepth refuses over-deep nesting", depth && depth.code === "cbor/max-depth");
129
+
130
+ var big = null;
131
+ try { cbor.decode(cbor.encode([1, 2, 3, 4, 5]), { maxBytes: 2 }); } catch (e) { big = e; }
132
+ check("decode: maxBytes refuses oversize input", big && big.code === "cbor/too-large");
133
+ }
134
+
135
+ function testRequireDeterministic() {
136
+ // Long-form encoding of 1 (0x1801) is valid CBOR but non-canonical.
137
+ var nonCanon = null;
138
+ try { cbor.decode(Buffer.from([0x18, 0x01]), { requireDeterministic: true }); } catch (e) { nonCanon = e; }
139
+ check("requireDeterministic: non-canonical long-form refused", nonCanon && nonCanon.code === "cbor/not-deterministic");
140
+ // A canonical encoding round-trips through the determinism check.
141
+ var d = cbor.decode(cbor.encode({ a: 1, b: 2 }), { requireDeterministic: true });
142
+ check("requireDeterministic: canonical input accepted", d.get("a") === 1 && d.get("b") === 2);
143
+ // Lenient decode (default) accepts the long form.
144
+ check("decode: non-canonical accepted without requireDeterministic", cbor.decode(Buffer.from([0x18, 0x01])) === 1);
145
+ }
146
+
147
+ function testInputValidation() {
148
+ var e1 = null;
149
+ try { cbor.decode("not a buffer"); } catch (e) { e1 = e; }
150
+ check("decode: non-buffer input refused", e1 && e1.code === "cbor/bad-input");
151
+ var e2 = null;
152
+ try { cbor.encode(function () {}); } catch (e) { e2 = e; }
153
+ check("encode: unencodable value refused", e2 && e2.code === "cbor/unencodable");
154
+ var e3 = null;
155
+ try { cbor.encode(NaN); } catch (e) { e3 = e; }
156
+ check("encode: NaN refused by default", e3 && e3.code === "cbor/non-finite");
157
+ check("encode: NaN emitted under allowNonFinite", Buffer.isBuffer(cbor.encode(NaN, { allowNonFinite: true })));
158
+ }
159
+
160
+ function run() {
161
+ testSurface();
162
+ testAppendixAVectors();
163
+ testDeterministicEncoding();
164
+ testRoundTrip();
165
+ testInvalidUtf8();
166
+ testTags();
167
+ testBoundedRefusals();
168
+ testRequireDeterministic();
169
+ testInputValidation();
170
+ }
171
+
172
+ module.exports = { run: run };
173
+
174
+ if (require.main === module) {
175
+ run();
176
+ console.log("[cbor] OK — " + helpers.getChecks() + " checks passed");
177
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/blamejs-shop",
3
- "version": "0.0.124",
3
+ "version": "0.0.126",
4
4
  "description": "Open-source framework built on blamejs. Vendored stack, zero npm runtime deps, PQC-first crypto, security-on by default.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {