@blamejs/core 0.13.42 → 0.13.44
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/LTS-CALENDAR.md +6 -2
- package/lib/a2a.js +11 -11
- package/lib/agent-snapshot.js +1 -1
- package/lib/ai-capability.js +20 -20
- package/lib/ai-content-detect.js +4 -3
- package/lib/ai-dp.js +17 -17
- package/lib/ai-input.js +3 -3
- package/lib/ai-pref.js +9 -9
- package/lib/ai-quota.js +17 -17
- package/lib/archive-read.js +10 -7
- package/lib/arg-parser.js +38 -38
- package/lib/audit-sign.js +4 -4
- package/lib/auth/acr-vocabulary.js +4 -4
- package/lib/auth/auth-time-tracker.js +1 -1
- package/lib/auth/elevation-grant.js +10 -10
- package/lib/auth/step-up-policy.js +12 -12
- package/lib/auth/step-up.js +15 -15
- package/lib/boot-gates.js +6 -6
- package/lib/break-glass.js +1 -1
- package/lib/budr.js +6 -6
- package/lib/cms-codec.js +10 -9
- package/lib/content-credentials.js +13 -13
- package/lib/dark-patterns.js +15 -15
- package/lib/ddl-change-control.js +37 -37
- package/lib/dr-runbook.js +7 -7
- package/lib/fapi2.js +9 -9
- package/lib/fdx.js +7 -7
- package/lib/graphql-federation.js +2 -2
- package/lib/iab-mspa.js +5 -5
- package/lib/iab-tcf.js +18 -18
- package/lib/mail-crypto-smime.js +10 -6
- package/lib/mcp.js +13 -13
- package/lib/middleware/require-step-up.js +3 -3
- package/lib/mtls-ca.js +2 -2
- package/lib/safe-archive.js +8 -7
- package/lib/sec-cyber.js +3 -3
- package/lib/sse.js +14 -14
- package/lib/tcpa-10dlc.js +5 -5
- package/lib/tenant-quota.js +18 -18
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/auth/step-up.js
CHANGED
|
@@ -87,11 +87,11 @@ function _quote(value) {
|
|
|
87
87
|
for (var i = 0; i < value.length; i += 1) {
|
|
88
88
|
var code = value.charCodeAt(i);
|
|
89
89
|
if (code < 32 || code === 127) { // allow:raw-byte-literal — ASCII control codepoints
|
|
90
|
-
throw new AuthError("auth-
|
|
90
|
+
throw new AuthError("auth-step-up/bad-challenge",
|
|
91
91
|
"challenge value contains control character at index " + i);
|
|
92
92
|
}
|
|
93
93
|
if (value.charAt(i) === '"' || value.charAt(i) === "\\") {
|
|
94
|
-
throw new AuthError("auth-
|
|
94
|
+
throw new AuthError("auth-step-up/bad-challenge",
|
|
95
95
|
"challenge value contains illegal character " +
|
|
96
96
|
JSON.stringify(value.charAt(i)) + " at index " + i);
|
|
97
97
|
}
|
|
@@ -101,7 +101,7 @@ function _quote(value) {
|
|
|
101
101
|
|
|
102
102
|
function _validateRequirement(requirement, label) {
|
|
103
103
|
if (!requirement || typeof requirement !== "object") {
|
|
104
|
-
throw new AuthError("auth-
|
|
104
|
+
throw new AuthError("auth-step-up/bad-requirement",
|
|
105
105
|
label + ": requirement must be an object — got " +
|
|
106
106
|
JSON.stringify(requirement));
|
|
107
107
|
}
|
|
@@ -111,39 +111,39 @@ function _validateRequirement(requirement, label) {
|
|
|
111
111
|
], label);
|
|
112
112
|
if (requirement.acr != null) {
|
|
113
113
|
validateOpts.requireNonEmptyString(requirement.acr,
|
|
114
|
-
label + ": acr", AuthError, "auth-
|
|
114
|
+
label + ": acr", AuthError, "auth-step-up/bad-acr");
|
|
115
115
|
}
|
|
116
116
|
if (requirement.acrValues != null) {
|
|
117
117
|
if (!Array.isArray(requirement.acrValues) || requirement.acrValues.length === 0) {
|
|
118
|
-
throw new AuthError("auth-
|
|
118
|
+
throw new AuthError("auth-step-up/bad-acr",
|
|
119
119
|
label + ": acrValues must be a non-empty string array");
|
|
120
120
|
}
|
|
121
121
|
for (var i = 0; i < requirement.acrValues.length; i += 1) {
|
|
122
122
|
validateOpts.requireNonEmptyString(requirement.acrValues[i],
|
|
123
|
-
label + ": acrValues[" + i + "]", AuthError, "auth-
|
|
123
|
+
label + ": acrValues[" + i + "]", AuthError, "auth-step-up/bad-acr");
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
if (requirement.maxAge != null) {
|
|
127
127
|
if (typeof requirement.maxAge !== "number" || !isFinite(requirement.maxAge) ||
|
|
128
128
|
requirement.maxAge < 0) {
|
|
129
|
-
throw new AuthError("auth-
|
|
129
|
+
throw new AuthError("auth-step-up/bad-max-age",
|
|
130
130
|
label + ": maxAge must be a finite number >= 0 — got " +
|
|
131
131
|
JSON.stringify(requirement.maxAge));
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
if (requirement.requiredAmr != null) {
|
|
135
135
|
if (!Array.isArray(requirement.requiredAmr)) {
|
|
136
|
-
throw new AuthError("auth-
|
|
136
|
+
throw new AuthError("auth-step-up/bad-amr",
|
|
137
137
|
label + ": requiredAmr must be a string array");
|
|
138
138
|
}
|
|
139
139
|
for (var j = 0; j < requirement.requiredAmr.length; j += 1) {
|
|
140
140
|
validateOpts.requireNonEmptyString(requirement.requiredAmr[j],
|
|
141
|
-
label + ": requiredAmr[" + j + "]", AuthError, "auth-
|
|
141
|
+
label + ": requiredAmr[" + j + "]", AuthError, "auth-step-up/bad-amr");
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
if (requirement.phishingResistant != null &&
|
|
145
145
|
typeof requirement.phishingResistant !== "boolean") {
|
|
146
|
-
throw new AuthError("auth-
|
|
146
|
+
throw new AuthError("auth-step-up/bad-requirement",
|
|
147
147
|
label + ": phishingResistant must be boolean — got " +
|
|
148
148
|
JSON.stringify(requirement.phishingResistant));
|
|
149
149
|
}
|
|
@@ -274,29 +274,29 @@ function buildChallenge(opts) {
|
|
|
274
274
|
// Hot-path callers wrap this in try/catch.
|
|
275
275
|
function parseAuthorizationDetails(value) {
|
|
276
276
|
if (typeof value !== "string") {
|
|
277
|
-
throw new AuthError("auth-
|
|
277
|
+
throw new AuthError("auth-step-up/bad-rar",
|
|
278
278
|
"parseAuthorizationDetails: value must be a JSON string — got " +
|
|
279
279
|
typeof value);
|
|
280
280
|
}
|
|
281
281
|
var parsed;
|
|
282
282
|
try { parsed = safeJson.parse(value, { maxBytes: C.BYTES.kib(64) }); }
|
|
283
283
|
catch (e) {
|
|
284
|
-
throw new AuthError("auth-
|
|
284
|
+
throw new AuthError("auth-step-up/bad-rar",
|
|
285
285
|
"parseAuthorizationDetails: invalid JSON — " + e.message);
|
|
286
286
|
}
|
|
287
287
|
if (!Array.isArray(parsed)) {
|
|
288
|
-
throw new AuthError("auth-
|
|
288
|
+
throw new AuthError("auth-step-up/bad-rar",
|
|
289
289
|
"parseAuthorizationDetails: value must be a JSON array — got " +
|
|
290
290
|
typeof parsed);
|
|
291
291
|
}
|
|
292
292
|
for (var i = 0; i < parsed.length; i += 1) {
|
|
293
293
|
var entry = parsed[i];
|
|
294
294
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
295
|
-
throw new AuthError("auth-
|
|
295
|
+
throw new AuthError("auth-step-up/bad-rar",
|
|
296
296
|
"parseAuthorizationDetails[" + i + "]: must be an object");
|
|
297
297
|
}
|
|
298
298
|
if (typeof entry.type !== "string" || entry.type.length === 0) {
|
|
299
|
-
throw new AuthError("auth-
|
|
299
|
+
throw new AuthError("auth-step-up/bad-rar",
|
|
300
300
|
"parseAuthorizationDetails[" + i + "]: missing required 'type' field");
|
|
301
301
|
}
|
|
302
302
|
}
|
package/lib/boot-gates.js
CHANGED
|
@@ -66,7 +66,7 @@ var DEFAULT_EXIT_CODE = 1;
|
|
|
66
66
|
async function run(gates, opts) {
|
|
67
67
|
opts = opts || {};
|
|
68
68
|
if (!Array.isArray(gates) || gates.length === 0) {
|
|
69
|
-
throw new BootGatesError("
|
|
69
|
+
throw new BootGatesError("boot-gates/bad-input",
|
|
70
70
|
"b.bootGates.run: gates must be a non-empty array");
|
|
71
71
|
}
|
|
72
72
|
var log = typeof opts.log === "function" ? opts.log : function (msg) {
|
|
@@ -82,7 +82,7 @@ async function run(gates, opts) {
|
|
|
82
82
|
// throw rather than terminating the process — operators that wire
|
|
83
83
|
// bootGates from their daemon main() pass `exit: process.exit.bind(process)`.
|
|
84
84
|
var exit = typeof opts.exit === "function" ? opts.exit : function (code) {
|
|
85
|
-
var e = new BootGatesError("
|
|
85
|
+
var e = new BootGatesError("boot-gates/no-exit-wired",
|
|
86
86
|
"b.bootGates.run: gate failed (exitCode=" + code + ") but no opts.exit handler was supplied; " +
|
|
87
87
|
"operators wire opts.exit to process.exit.bind(process) in their daemon main()");
|
|
88
88
|
e.exitCode = code;
|
|
@@ -96,26 +96,26 @@ async function run(gates, opts) {
|
|
|
96
96
|
var gate = gates[i];
|
|
97
97
|
if (!gate || typeof gate.name !== "string" || gate.name.length === 0 ||
|
|
98
98
|
typeof gate.fn !== "function") {
|
|
99
|
-
throw new BootGatesError("
|
|
99
|
+
throw new BootGatesError("boot-gates/bad-gate",
|
|
100
100
|
"b.bootGates.run: gates[" + i + "] must be { name: string, fn: function }");
|
|
101
101
|
}
|
|
102
102
|
var timeoutMs = gate.timeoutMs || DEFAULT_GATE_TIMEOUT_MS;
|
|
103
103
|
if (typeof timeoutMs !== "number" || !isFinite(timeoutMs) || timeoutMs < 1) {
|
|
104
|
-
throw new BootGatesError("
|
|
104
|
+
throw new BootGatesError("boot-gates/bad-timeout",
|
|
105
105
|
"b.bootGates.run: gates[" + i + "].timeoutMs must be a positive finite number");
|
|
106
106
|
}
|
|
107
107
|
var gateT0 = Date.now();
|
|
108
108
|
var failure = null;
|
|
109
109
|
try {
|
|
110
110
|
await safeAsync.withTimeout(Promise.resolve().then(gate.fn), timeoutMs,
|
|
111
|
-
new BootGatesError("
|
|
111
|
+
new BootGatesError("boot-gates/timeout",
|
|
112
112
|
"b.bootGates.run: gate '" + gate.name + "' exceeded " + timeoutMs + "ms"));
|
|
113
113
|
} catch (err) {
|
|
114
114
|
failure = err;
|
|
115
115
|
}
|
|
116
116
|
if (overallTimeoutMs !== undefined &&
|
|
117
117
|
Date.now() - t0 > overallTimeoutMs && failure === null) {
|
|
118
|
-
failure = new BootGatesError("
|
|
118
|
+
failure = new BootGatesError("boot-gates/overall-timeout",
|
|
119
119
|
"b.bootGates.run: overall budget " + overallTimeoutMs + "ms exceeded after gate '" +
|
|
120
120
|
gate.name + "'");
|
|
121
121
|
}
|
package/lib/break-glass.js
CHANGED
|
@@ -523,7 +523,7 @@ function _validatePolicySet(table, opts) {
|
|
|
523
523
|
"' not in allowed factors [" + ALLOWED_FACTORS.join(",") + "]");
|
|
524
524
|
}
|
|
525
525
|
}
|
|
526
|
-
// Model B (cryptographic mode)
|
|
526
|
+
// Model B (cryptographic mode). When enabled,
|
|
527
527
|
// glass-locked columns must be encrypted with `b.breakGlass.encryptCell`
|
|
528
528
|
// at write time (the framework can't auto-encrypt at write because
|
|
529
529
|
// policy-set may post-date existing data; operators run the migration
|
package/lib/budr.js
CHANGED
|
@@ -78,31 +78,31 @@ var declarations = new Map();
|
|
|
78
78
|
*/
|
|
79
79
|
function declare(opts) {
|
|
80
80
|
if (!opts || typeof opts !== "object") {
|
|
81
|
-
throw BudrError.factory("
|
|
81
|
+
throw BudrError.factory("budr/bad-opts", "budr.declare: opts required");
|
|
82
82
|
}
|
|
83
83
|
if (typeof opts.service !== "string" || opts.service.length === 0 ||
|
|
84
84
|
opts.service.length > SERVICE_MAX || !SERVICE_RE.test(opts.service)) {
|
|
85
|
-
throw BudrError.factory("
|
|
85
|
+
throw BudrError.factory("budr/bad-service",
|
|
86
86
|
"budr.declare: service must match " + SERVICE_RE);
|
|
87
87
|
}
|
|
88
88
|
numericBounds.requirePositiveFiniteIntIfPresent(opts.rtoMs, "budr.declare: rtoMs", BudrError, "BAD_RTO");
|
|
89
89
|
numericBounds.requirePositiveFiniteIntIfPresent(opts.rpoMs, "budr.declare: rpoMs", BudrError, "BAD_RPO");
|
|
90
90
|
if (typeof opts.rtoMs !== "number" || typeof opts.rpoMs !== "number") {
|
|
91
|
-
throw BudrError.factory("
|
|
91
|
+
throw BudrError.factory("budr/bad-targets",
|
|
92
92
|
"budr.declare: rtoMs and rpoMs are required positive integer milliseconds");
|
|
93
93
|
}
|
|
94
94
|
if (opts.tier !== undefined && TIERS.indexOf(opts.tier) === -1) {
|
|
95
|
-
throw BudrError.factory("
|
|
95
|
+
throw BudrError.factory("budr/bad-tier",
|
|
96
96
|
"budr.declare: tier must be one of " + TIERS.join(", "));
|
|
97
97
|
}
|
|
98
98
|
if (opts.criticality !== undefined && CRITICALITIES.indexOf(opts.criticality) === -1) {
|
|
99
|
-
throw BudrError.factory("
|
|
99
|
+
throw BudrError.factory("budr/bad-criticality",
|
|
100
100
|
"budr.declare: criticality must be one of " + CRITICALITIES.join(", "));
|
|
101
101
|
}
|
|
102
102
|
validateOpts.optionalNonEmptyString(opts.owner,
|
|
103
103
|
"budr.declare: owner", BudrError, "BAD_OWNER");
|
|
104
104
|
if (opts.citations !== undefined && !Array.isArray(opts.citations)) {
|
|
105
|
-
throw BudrError.factory("
|
|
105
|
+
throw BudrError.factory("budr/bad-citations",
|
|
106
106
|
"budr.declare: citations must be an array of strings");
|
|
107
107
|
}
|
|
108
108
|
|
package/lib/cms-codec.js
CHANGED
|
@@ -42,15 +42,16 @@
|
|
|
42
42
|
* refuses EnvelopedData and accepts only the §5083 ContentInfo
|
|
43
43
|
* OID. Cheap escape hatch: operators on such a peer compose
|
|
44
44
|
* `b.asn1Der` directly to rewrap an EnvelopedData blob into an
|
|
45
|
-
* AuthEnvelopedData ContentInfo.
|
|
46
|
-
*
|
|
47
|
-
*
|
|
45
|
+
* AuthEnvelopedData ContentInfo. A built-in encode path is deferred
|
|
46
|
+
* until an interop case requires a peer that refuses EnvelopedData;
|
|
47
|
+
* the `b.asn1Der` rewrap covers the gap until then.
|
|
48
48
|
* - **`b.cms.decode` parse-tree of inner SignedData / EnvelopedData**
|
|
49
|
-
* beyond the ContentInfo wrapper.
|
|
49
|
+
* beyond the ContentInfo wrapper. `b.cms.decode` returns the inner
|
|
50
50
|
* SEQUENCE bytes as `content` (an asn1-der node); callers that
|
|
51
|
-
* need fielded access walk it via `b.asn1Der.readSequence`.
|
|
52
|
-
* fielded decoders
|
|
53
|
-
*
|
|
51
|
+
* need fielded access walk it via `b.asn1Der.readSequence`. Built-in
|
|
52
|
+
* fielded decoders are deferred until they're actually consumed by a
|
|
53
|
+
* shipping primitive; the `b.asn1Der.readSequence` walk is the escape
|
|
54
|
+
* hatch until then.
|
|
54
55
|
*
|
|
55
56
|
* Refusal posture:
|
|
56
57
|
*
|
|
@@ -302,8 +303,8 @@ function encodeEnvelopedData(opts) {
|
|
|
302
303
|
* string (e.g. `"1.2.840.113549.1.7.2"` for SignedData) and
|
|
303
304
|
* `content` is the inner asn1-der node (SignedData / EnvelopedData /
|
|
304
305
|
* other) — operators walk it via `b.asn1Der.readSequence`. Fielded
|
|
305
|
-
* decoders for SignedData / EnvelopedData
|
|
306
|
-
*
|
|
306
|
+
* decoders for SignedData / EnvelopedData are deferred; the
|
|
307
|
+
* `b.asn1Der.readSequence` walk is the escape hatch until then.
|
|
307
308
|
*
|
|
308
309
|
* Refuses input past `opts.maxBytes` (default 64 MiB), top-level
|
|
309
310
|
* non-SEQUENCE shapes, missing OID + [0] EXPLICIT child pair.
|
|
@@ -48,7 +48,7 @@ var REQUIRED_FIELDS = ["provider", "system", "systemVersion", "contentId"];
|
|
|
48
48
|
|
|
49
49
|
function _validateBuildOpts(opts) {
|
|
50
50
|
if (!opts || typeof opts !== "object") {
|
|
51
|
-
throw ContentCredentialsError.factory("
|
|
51
|
+
throw ContentCredentialsError.factory("content-credentials/bad-opts",
|
|
52
52
|
"contentCredentials.build: opts required");
|
|
53
53
|
}
|
|
54
54
|
for (var i = 0; i < REQUIRED_FIELDS.length; i += 1) {
|
|
@@ -57,32 +57,32 @@ function _validateBuildOpts(opts) {
|
|
|
57
57
|
"contentCredentials.build: " + f, ContentCredentialsError, "MISSING_" + f.toUpperCase());
|
|
58
58
|
}
|
|
59
59
|
if (opts.provider.length > STR_LEN_MAX) {
|
|
60
|
-
throw ContentCredentialsError.factory("
|
|
60
|
+
throw ContentCredentialsError.factory("content-credentials/bad-provider",
|
|
61
61
|
"provider exceeds " + STR_LEN_MAX + " chars");
|
|
62
62
|
}
|
|
63
63
|
if (opts.system.length > ID_LEN_MAX || !ID_RE.test(opts.system)) {
|
|
64
|
-
throw ContentCredentialsError.factory("
|
|
64
|
+
throw ContentCredentialsError.factory("content-credentials/bad-system",
|
|
65
65
|
"system must match " + ID_RE);
|
|
66
66
|
}
|
|
67
67
|
if (opts.systemVersion.length > 64 || !SEMVER_RE.test(opts.systemVersion)) { // allow:raw-byte-literal — semver length cap, not bytes
|
|
68
|
-
throw ContentCredentialsError.factory("
|
|
68
|
+
throw ContentCredentialsError.factory("content-credentials/bad-version",
|
|
69
69
|
"systemVersion must be semver");
|
|
70
70
|
}
|
|
71
71
|
if (opts.contentId.length > ID_LEN_MAX || !ID_RE.test(opts.contentId)) {
|
|
72
|
-
throw ContentCredentialsError.factory("
|
|
72
|
+
throw ContentCredentialsError.factory("content-credentials/bad-content-id",
|
|
73
73
|
"contentId must match " + ID_RE);
|
|
74
74
|
}
|
|
75
75
|
if (opts.contentType !== undefined) {
|
|
76
76
|
if (typeof opts.contentType !== "string" || opts.contentType.length === 0 ||
|
|
77
77
|
opts.contentType.length > ID_LEN_MAX || !/^[a-zA-Z]+\/[A-Za-z0-9._+-]+$/.test(opts.contentType)) {
|
|
78
|
-
throw ContentCredentialsError.factory("
|
|
78
|
+
throw ContentCredentialsError.factory("content-credentials/bad-content-type",
|
|
79
79
|
"contentType must be a valid IANA media type");
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
if (opts.contentSha3 !== undefined) {
|
|
83
83
|
if (typeof opts.contentSha3 !== "string" || opts.contentSha3.length !== SHA3_HEX_LEN ||
|
|
84
84
|
!/^[a-f0-9]+$/i.test(opts.contentSha3)) {
|
|
85
|
-
throw ContentCredentialsError.factory("
|
|
85
|
+
throw ContentCredentialsError.factory("content-credentials/bad-content-hash",
|
|
86
86
|
"contentSha3 must be lowercase hex SHA3-512 (" + SHA3_HEX_LEN + " chars)");
|
|
87
87
|
}
|
|
88
88
|
}
|
|
@@ -229,7 +229,7 @@ function required(opts) {
|
|
|
229
229
|
function sign(manifest, opts) {
|
|
230
230
|
opts = opts || {};
|
|
231
231
|
if (!manifest || typeof manifest !== "object") {
|
|
232
|
-
throw ContentCredentialsError.factory("
|
|
232
|
+
throw ContentCredentialsError.factory("content-credentials/bad-manifest",
|
|
233
233
|
"contentCredentials.sign: manifest required");
|
|
234
234
|
}
|
|
235
235
|
validateOpts.requireNonEmptyString(opts.privateKeyPem,
|
|
@@ -368,7 +368,7 @@ function _cborUint(n) {
|
|
|
368
368
|
if (n < 256) return Buffer.from([0x18, n]); // allow:raw-byte-literal — CBOR threshold
|
|
369
369
|
if (n < 65536) return Buffer.from([0x19, (n >> 8) & 0xFF, n & 0xFF]); // allow:raw-byte-literal — CBOR threshold
|
|
370
370
|
if (n < 4294967296) return Buffer.from([0x1A, (n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF]); // allow:raw-byte-literal — CBOR threshold
|
|
371
|
-
throw ContentCredentialsError.factory("
|
|
371
|
+
throw ContentCredentialsError.factory("content-credentials/cbor-overflow", "cbor uint too large: " + n);
|
|
372
372
|
}
|
|
373
373
|
|
|
374
374
|
function _cborNint(n) {
|
|
@@ -397,13 +397,13 @@ function _cborArrayHeader(n) {
|
|
|
397
397
|
if (n < 24) return Buffer.from([0x80 | n]); // allow:raw-byte-literal — CBOR threshold
|
|
398
398
|
if (n < 256) return Buffer.from([0x98, n]); // allow:raw-byte-literal — CBOR threshold
|
|
399
399
|
if (n < 65536) return Buffer.from([0x99, (n >> 8) & 0xFF, n & 0xFF]); // allow:raw-byte-literal — CBOR threshold
|
|
400
|
-
throw ContentCredentialsError.factory("
|
|
400
|
+
throw ContentCredentialsError.factory("content-credentials/cbor-overflow", "cbor array too large: " + n);
|
|
401
401
|
}
|
|
402
402
|
|
|
403
403
|
function _cborMapHeader(n) {
|
|
404
404
|
if (n < 24) return Buffer.from([0xA0 | n]); // allow:raw-byte-literal — CBOR threshold
|
|
405
405
|
if (n < 256) return Buffer.from([0xB8, n]); // allow:raw-byte-literal — CBOR threshold
|
|
406
|
-
throw ContentCredentialsError.factory("
|
|
406
|
+
throw ContentCredentialsError.factory("content-credentials/cbor-overflow", "cbor map too large: " + n);
|
|
407
407
|
}
|
|
408
408
|
|
|
409
409
|
function _cborTag(tag) {
|
|
@@ -454,14 +454,14 @@ function _cborTag(tag) {
|
|
|
454
454
|
function signCose(manifest, opts) {
|
|
455
455
|
opts = opts || {};
|
|
456
456
|
if (!manifest || typeof manifest !== "object") {
|
|
457
|
-
throw ContentCredentialsError.factory("
|
|
457
|
+
throw ContentCredentialsError.factory("content-credentials/bad-manifest",
|
|
458
458
|
"contentCredentials.signCose: manifest required");
|
|
459
459
|
}
|
|
460
460
|
validateOpts.requireNonEmptyString(opts.privateKeyPem,
|
|
461
461
|
"contentCredentials.signCose: privateKeyPem", ContentCredentialsError, "BAD_KEY");
|
|
462
462
|
var algName = (opts.alg || "ml-dsa-87").toLowerCase();
|
|
463
463
|
if (!(algName in COSE_ALGS)) {
|
|
464
|
-
throw ContentCredentialsError.factory("
|
|
464
|
+
throw ContentCredentialsError.factory("content-credentials/bad-alg",
|
|
465
465
|
"contentCredentials.signCose: alg '" + algName +
|
|
466
466
|
"' not in COSE alg registry. Known: " + Object.keys(COSE_ALGS).join(", "));
|
|
467
467
|
}
|
package/lib/dark-patterns.js
CHANGED
|
@@ -64,47 +64,47 @@ var POSTURES = {
|
|
|
64
64
|
|
|
65
65
|
function _validateFlowOpts(opts, label, errorClass) {
|
|
66
66
|
if (!opts || typeof opts !== "object") {
|
|
67
|
-
throw errorClass.factory("
|
|
67
|
+
throw errorClass.factory("dark-patterns/bad-opts",
|
|
68
68
|
"darkPatterns.record" + label + ": opts required");
|
|
69
69
|
}
|
|
70
70
|
if (CHANNELS.indexOf(opts.channel) === -1) {
|
|
71
|
-
throw errorClass.factory("
|
|
71
|
+
throw errorClass.factory("dark-patterns/bad-channel",
|
|
72
72
|
"darkPatterns: channel must be one of " + CHANNELS.join(","));
|
|
73
73
|
}
|
|
74
74
|
if (typeof opts.clickCount !== "number" || !isFinite(opts.clickCount) ||
|
|
75
75
|
opts.clickCount < 1 || opts.clickCount > 50 ||
|
|
76
76
|
Math.floor(opts.clickCount) !== opts.clickCount) {
|
|
77
|
-
throw errorClass.factory("
|
|
77
|
+
throw errorClass.factory("dark-patterns/bad-clicks",
|
|
78
78
|
"darkPatterns: clickCount must be integer 1..50");
|
|
79
79
|
}
|
|
80
80
|
if (!opts.cta || typeof opts.cta !== "object") {
|
|
81
|
-
throw errorClass.factory("
|
|
81
|
+
throw errorClass.factory("dark-patterns/bad-cta",
|
|
82
82
|
"darkPatterns: cta object required (text, fontWeight, contrastRatio)");
|
|
83
83
|
}
|
|
84
84
|
if (typeof opts.cta.text !== "string" || opts.cta.text.length === 0 ||
|
|
85
85
|
opts.cta.text.length > STR_LEN_MAX) {
|
|
86
|
-
throw errorClass.factory("
|
|
86
|
+
throw errorClass.factory("dark-patterns/bad-cta-text",
|
|
87
87
|
"darkPatterns: cta.text must be 1-256 char string");
|
|
88
88
|
}
|
|
89
89
|
if (typeof opts.cta.fontWeight !== "number" || opts.cta.fontWeight < 100 ||
|
|
90
90
|
opts.cta.fontWeight > FONT_WEIGHT_MAX) {
|
|
91
|
-
throw errorClass.factory("
|
|
91
|
+
throw errorClass.factory("dark-patterns/bad-font-weight",
|
|
92
92
|
"darkPatterns: cta.fontWeight must be 100..1000");
|
|
93
93
|
}
|
|
94
94
|
if (typeof opts.cta.contrastRatio !== "number" ||
|
|
95
95
|
opts.cta.contrastRatio < 1 || opts.cta.contrastRatio > 21) {
|
|
96
|
-
throw errorClass.factory("
|
|
96
|
+
throw errorClass.factory("dark-patterns/bad-contrast",
|
|
97
97
|
"darkPatterns: cta.contrastRatio must be 1..21");
|
|
98
98
|
}
|
|
99
99
|
if (typeof opts.confirmations !== "number" ||
|
|
100
100
|
opts.confirmations < 0 || opts.confirmations > 10 ||
|
|
101
101
|
Math.floor(opts.confirmations) !== opts.confirmations) {
|
|
102
|
-
throw errorClass.factory("
|
|
102
|
+
throw errorClass.factory("dark-patterns/bad-confirmations",
|
|
103
103
|
"darkPatterns: confirmations must be integer 0..10");
|
|
104
104
|
}
|
|
105
105
|
if (typeof opts.resourceId !== "string" || opts.resourceId.length === 0 ||
|
|
106
106
|
opts.resourceId.length > STR_LEN_MAX) {
|
|
107
|
-
throw errorClass.factory("
|
|
107
|
+
throw errorClass.factory("dark-patterns/bad-resource-id",
|
|
108
108
|
"darkPatterns: resourceId must be 1-256 char string");
|
|
109
109
|
}
|
|
110
110
|
}
|
|
@@ -252,21 +252,21 @@ function assertParity(signup, cancel, opts) {
|
|
|
252
252
|
opts = opts || {};
|
|
253
253
|
var errorClass = opts.errorClass || DarkPatternsError;
|
|
254
254
|
if (!signup || signup.kind !== "signup") {
|
|
255
|
-
throw errorClass.factory("
|
|
255
|
+
throw errorClass.factory("dark-patterns/bad-signup-flow",
|
|
256
256
|
"darkPatterns.assertParity: signup must be a recorded signup flow");
|
|
257
257
|
}
|
|
258
258
|
if (!cancel || cancel.kind !== "cancel") {
|
|
259
|
-
throw errorClass.factory("
|
|
259
|
+
throw errorClass.factory("dark-patterns/bad-cancel-flow",
|
|
260
260
|
"darkPatterns.assertParity: cancel must be a recorded cancel flow");
|
|
261
261
|
}
|
|
262
262
|
if (signup.resourceId !== cancel.resourceId) {
|
|
263
|
-
throw errorClass.factory("
|
|
263
|
+
throw errorClass.factory("dark-patterns/resource-mismatch",
|
|
264
264
|
"darkPatterns.assertParity: resourceId differs between flows");
|
|
265
265
|
}
|
|
266
266
|
var postureName = opts.posture || "ftc-2024";
|
|
267
267
|
var posture = POSTURES[postureName];
|
|
268
268
|
if (!posture) {
|
|
269
|
-
throw errorClass.factory("
|
|
269
|
+
throw errorClass.factory("dark-patterns/bad-posture",
|
|
270
270
|
"darkPatterns.assertParity: unknown posture " + postureName);
|
|
271
271
|
}
|
|
272
272
|
|
|
@@ -427,11 +427,11 @@ function middleware(opts) {
|
|
|
427
427
|
opts = opts || {};
|
|
428
428
|
var errorClass = opts.errorClass || DarkPatternsError;
|
|
429
429
|
if (typeof opts.lookupAttestation !== "function") {
|
|
430
|
-
throw errorClass.factory("
|
|
430
|
+
throw errorClass.factory("dark-patterns/bad-opts",
|
|
431
431
|
"darkPatterns.middleware: lookupAttestation function required");
|
|
432
432
|
}
|
|
433
433
|
if (typeof opts.resourceIdFromReq !== "function") {
|
|
434
|
-
throw errorClass.factory("
|
|
434
|
+
throw errorClass.factory("dark-patterns/bad-opts",
|
|
435
435
|
"darkPatterns.middleware: resourceIdFromReq function required");
|
|
436
436
|
}
|
|
437
437
|
|