@blamejs/core 0.14.20 → 0.14.22
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/index.js +5 -1
- package/lib/auth/jar.js +190 -28
- package/lib/auth/jwt-external.js +213 -0
- package/lib/auth/oauth.js +115 -101
- package/lib/auth/oid4vci.js +124 -5
- package/lib/auth/oid4vp.js +14 -4
- package/lib/break-glass.js +1 -2
- package/lib/config.js +28 -31
- package/lib/dora.js +8 -5
- package/lib/dsr.js +2 -2
- package/lib/flag-evaluation-context.js +7 -0
- package/lib/guard-html-wcag-aria.js +4 -2
- package/lib/guard-html-wcag-forms.js +4 -2
- package/lib/guard-html-wcag-tables.js +4 -2
- package/lib/guard-html-wcag-tagwalk.js +20 -0
- package/lib/guard-html-wcag.js +1 -1
- package/lib/honeytoken.js +27 -20
- package/lib/http-client.js +3 -4
- package/lib/lro.js +3 -4
- package/lib/mail-deploy.js +1 -1
- package/lib/mail-send-deliver.js +13 -4
- package/lib/middleware/api-encrypt.js +140 -13
- package/lib/middleware/asyncapi-serve.js +3 -0
- package/lib/middleware/csp-report.js +13 -9
- package/lib/middleware/deny-response.js +2 -10
- package/lib/middleware/health.js +1 -4
- package/lib/middleware/openapi-serve.js +3 -0
- package/lib/middleware/scim-server.js +297 -19
- package/lib/middleware/security-txt.js +1 -2
- package/lib/middleware/trace-log-correlation.js +4 -8
- package/lib/network-smtp-policy.js +4 -4
- package/lib/object-store/sigv4-bucket-ops.js +11 -2
- package/lib/observability-tracer.js +1 -1
- package/lib/problem-details.js +56 -11
- package/lib/pubsub-cluster.js +16 -3
- package/lib/queue-sqs.js +20 -2
- package/lib/redis-client.js +32 -4
- package/lib/safe-redirect.js +16 -2
- package/lib/validate-opts.js +34 -0
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/queue-sqs.js
CHANGED
|
@@ -50,6 +50,7 @@ var httpClient = require("./http-client");
|
|
|
50
50
|
var cryptoField = require("./crypto-field");
|
|
51
51
|
var safeJson = require("./safe-json");
|
|
52
52
|
var safeUrl = require("./safe-url");
|
|
53
|
+
var validateOpts = require("./validate-opts");
|
|
53
54
|
var { generateToken } = require("./crypto");
|
|
54
55
|
var { QueueError } = require("./framework-error");
|
|
55
56
|
|
|
@@ -102,8 +103,25 @@ function create(opts) {
|
|
|
102
103
|
var accountId = opts.accountId ? String(opts.accountId) : null;
|
|
103
104
|
var timeoutMs = opts.timeoutMs;
|
|
104
105
|
var allowInternal = opts.allowInternal != null ? opts.allowInternal : null;
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
// Config-time: a typo (NaN-coercing string / negative / fractional)
|
|
107
|
+
// must surface at create, not silently fall back to the default and ship
|
|
108
|
+
// a mis-tuned lease loop. THROW on present-but-bad; absent keeps default.
|
|
109
|
+
validateOpts.optionalPositiveInt(opts.visibilityTimeoutSec,
|
|
110
|
+
"queue-sqs: visibilityTimeoutSec", QueueError, "INVALID_CONFIG");
|
|
111
|
+
// waitTimeSec=0 is the valid SQS short-poll sentinel (the default), so a
|
|
112
|
+
// positive-int check would wrongly reject it — allow non-negative integers.
|
|
113
|
+
if (opts.waitTimeSec !== undefined &&
|
|
114
|
+
(typeof opts.waitTimeSec !== "number" || !isFinite(opts.waitTimeSec) ||
|
|
115
|
+
opts.waitTimeSec < 0 || Math.floor(opts.waitTimeSec) !== opts.waitTimeSec)) {
|
|
116
|
+
throw _err("INVALID_CONFIG",
|
|
117
|
+
"queue-sqs: waitTimeSec must be a non-negative integer (0 = short-poll), got " +
|
|
118
|
+
(typeof opts.waitTimeSec === "number" ? String(opts.waitTimeSec) : typeof opts.waitTimeSec),
|
|
119
|
+
true);
|
|
120
|
+
}
|
|
121
|
+
var visibilityTimeoutSec = opts.visibilityTimeoutSec !== undefined
|
|
122
|
+
? opts.visibilityTimeoutSec : DEFAULT_VISIBILITY_TIMEOUT_SEC;
|
|
123
|
+
var waitTimeSec = opts.waitTimeSec !== undefined
|
|
124
|
+
? opts.waitTimeSec : DEFAULT_WAIT_TIME_SEC;
|
|
107
125
|
|
|
108
126
|
var queueUrlResolver = typeof opts.queueUrlByName === "function"
|
|
109
127
|
? opts.queueUrlByName
|
package/lib/redis-client.js
CHANGED
|
@@ -169,11 +169,36 @@ function create(opts) {
|
|
|
169
169
|
var useTls = opts.tls !== undefined ? !!opts.tls : parsed.tls;
|
|
170
170
|
var password = opts.password !== undefined ? opts.password : parsed.password;
|
|
171
171
|
var username = opts.username !== undefined ? opts.username : parsed.username;
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
// Config-time entry-point opts: a bad type must fail at create() rather
|
|
173
|
+
// than coerce-or-default silently. connectTimeoutMs:"abc" → NaN would
|
|
174
|
+
// otherwise fall through to the default; a negative timeout would sail
|
|
175
|
+
// into setTimeout; maxReconnectAttempts:"abc" → NaN would make the
|
|
176
|
+
// `>= 0` reconnect-cap check below false and SILENTLY disable the bound
|
|
177
|
+
// (unbounded reconnects). db and maxReconnectAttempts must allow 0
|
|
178
|
+
// (db 0 = no SELECT; maxReconnectAttempts 0 = give up immediately).
|
|
179
|
+
if (opts.db !== undefined &&
|
|
180
|
+
(typeof opts.db !== "number" || !Number.isInteger(opts.db) || opts.db < 0)) {
|
|
181
|
+
throw _err("BAD_OPTS",
|
|
182
|
+
"redis.create: opts.db must be a non-negative integer, got " +
|
|
183
|
+
(typeof opts.db === "number" ? String(opts.db) : typeof opts.db));
|
|
184
|
+
}
|
|
185
|
+
if (opts.maxReconnectAttempts !== undefined &&
|
|
186
|
+
(typeof opts.maxReconnectAttempts !== "number" ||
|
|
187
|
+
!Number.isInteger(opts.maxReconnectAttempts) || opts.maxReconnectAttempts < 0)) {
|
|
188
|
+
throw _err("BAD_OPTS",
|
|
189
|
+
"redis.create: opts.maxReconnectAttempts must be a non-negative integer, got " +
|
|
190
|
+
(typeof opts.maxReconnectAttempts === "number"
|
|
191
|
+
? String(opts.maxReconnectAttempts) : typeof opts.maxReconnectAttempts));
|
|
192
|
+
}
|
|
193
|
+
validateOpts.optionalPositiveInt(opts.connectTimeoutMs,
|
|
194
|
+
"redis.create: opts.connectTimeoutMs", RedisError, "BAD_OPTS");
|
|
195
|
+
validateOpts.optionalPositiveInt(opts.commandTimeoutMs,
|
|
196
|
+
"redis.create: opts.commandTimeoutMs", RedisError, "BAD_OPTS");
|
|
197
|
+
var db = opts.db !== undefined ? opts.db : parsed.db;
|
|
198
|
+
var connectTimeoutMs = opts.connectTimeoutMs !== undefined ? opts.connectTimeoutMs : 5000;
|
|
199
|
+
var commandTimeoutMs = opts.commandTimeoutMs !== undefined ? opts.commandTimeoutMs : 10000;
|
|
175
200
|
var maxReconnectAttempts = opts.maxReconnectAttempts === undefined ? 10
|
|
176
|
-
:
|
|
201
|
+
: opts.maxReconnectAttempts;
|
|
177
202
|
// TLS verification controls. Operators using rediss:// against private
|
|
178
203
|
// CAs (managed Redis services, on-prem clusters with internal PKI)
|
|
179
204
|
// pin the trust roots via opts.ca; rejectUnauthorized stays on by
|
|
@@ -470,6 +495,9 @@ function create(opts) {
|
|
|
470
495
|
pending: pending.length, backlog: backlog.length,
|
|
471
496
|
reconnect: reconnectAttempt,
|
|
472
497
|
host: host, port: port, db: db, tls: useTls,
|
|
498
|
+
connectTimeoutMs: connectTimeoutMs,
|
|
499
|
+
commandTimeoutMs: commandTimeoutMs,
|
|
500
|
+
maxReconnectAttempts: maxReconnectAttempts,
|
|
473
501
|
};
|
|
474
502
|
},
|
|
475
503
|
};
|
package/lib/safe-redirect.js
CHANGED
|
@@ -76,8 +76,21 @@ function resolve(rawTarget, opts) {
|
|
|
76
76
|
// Full URL — parse and check against allowlist.
|
|
77
77
|
var allowedOrigins = Array.isArray(opts.allowedOrigins) ? opts.allowedOrigins : null;
|
|
78
78
|
var allowedHosts = Array.isArray(opts.allowedHosts) ? opts.allowedHosts : null;
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
|
|
80
|
+
// The application's own origin (opts.base) is same-origin by
|
|
81
|
+
// definition, so a full URL pointing at it is safe even when the
|
|
82
|
+
// operator supplied no explicit allowedOrigins / allowedHosts. Derive
|
|
83
|
+
// the origin from base and treat it as an implicitly-allowed origin.
|
|
84
|
+
var baseOrigin = null;
|
|
85
|
+
if (typeof opts.base === "string" && opts.base.length > 0) {
|
|
86
|
+
try {
|
|
87
|
+
baseOrigin = safeUrl.parse(opts.base, { allowedProtocols: safeUrl.ALLOW_HTTP_TLS }).origin;
|
|
88
|
+
} catch (_e) { baseOrigin = null; }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!allowedOrigins && !allowedHosts && baseOrigin === null) {
|
|
92
|
+
// Operator gave no allowlist and no usable base — refuse all full
|
|
93
|
+
// URLs (the safe default).
|
|
81
94
|
return fallback;
|
|
82
95
|
}
|
|
83
96
|
|
|
@@ -85,6 +98,7 @@ function resolve(rawTarget, opts) {
|
|
|
85
98
|
try { parsed = safeUrl.parse(rawTarget, { allowedProtocols: safeUrl.ALLOW_HTTP_TLS }); }
|
|
86
99
|
catch (_e) { return fallback; }
|
|
87
100
|
|
|
101
|
+
if (baseOrigin !== null && parsed.origin === baseOrigin) return rawTarget;
|
|
88
102
|
if (allowedOrigins) {
|
|
89
103
|
for (var i = 0; i < allowedOrigins.length; i += 1) {
|
|
90
104
|
if (parsed.origin === allowedOrigins[i]) return rawTarget;
|
package/lib/validate-opts.js
CHANGED
|
@@ -393,6 +393,39 @@ function makeNamespacedEmitters(prefix, deps) {
|
|
|
393
393
|
return { audit: audit, metric: metric };
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
+
// assignOwnEnumerable — copy a source object's own enumerable keys onto a
|
|
397
|
+
// target, skipping the prototype-pollution sentinels (__proto__ /
|
|
398
|
+
// constructor / prototype) and any caller-named reserved keys. Several
|
|
399
|
+
// primitives that merge operator-supplied free-form fields onto a
|
|
400
|
+
// spec-built object (JOSE claim sets, JWS protected headers, attestation
|
|
401
|
+
// extra-claims) previously open-coded the identical
|
|
402
|
+
// `for (k of Object.keys(src)) { if (sentinel) continue; if (reserved)
|
|
403
|
+
// continue; dst[k] = src[k]; }` loop. Centralizing the proto-safe walk
|
|
404
|
+
// keeps the merge contract in one place. Reserved keys win — they are NOT
|
|
405
|
+
// overwritten — so the caller's spec-built fields can never be shadowed by
|
|
406
|
+
// a same-named operator key. Returns the target.
|
|
407
|
+
function assignOwnEnumerable(target, source, reservedKeys) {
|
|
408
|
+
if (!source || typeof source !== "object") return target;
|
|
409
|
+
var reserved = Object.create(null);
|
|
410
|
+
if (reservedKeys) for (var r = 0; r < reservedKeys.length; r += 1) reserved[reservedKeys[r]] = true;
|
|
411
|
+
var keys = Object.keys(source);
|
|
412
|
+
var entries = [];
|
|
413
|
+
for (var i = 0; i < keys.length; i += 1) {
|
|
414
|
+
var k = keys[i];
|
|
415
|
+
if (k === "__proto__" || k === "constructor" || k === "prototype") continue;
|
|
416
|
+
if (reserved[k]) continue;
|
|
417
|
+
entries.push([k, source[k]]);
|
|
418
|
+
}
|
|
419
|
+
// Staged through entries + Object.assign so the copy contains no
|
|
420
|
+
// computed-name property write at all: Object.fromEntries creates own
|
|
421
|
+
// data properties (it cannot walk the prototype chain), and the
|
|
422
|
+
// sentinel skip above means the staging object carries no
|
|
423
|
+
// __proto__/constructor/prototype key for Object.assign's [[Set]] to
|
|
424
|
+
// trip over. Same observable result as a key-by-key copy, with the
|
|
425
|
+
// arbitrary-property-write shape removed instead of merely guarded.
|
|
426
|
+
return Object.assign(target, Object.fromEntries(entries));
|
|
427
|
+
}
|
|
428
|
+
|
|
396
429
|
// observabilityShape — operator-supplied `opts.observability` must
|
|
397
430
|
// expose an `event` function. Parallel to auditShape; the n=1 catalog
|
|
398
431
|
// tracks both inline-shape regexes.
|
|
@@ -426,3 +459,4 @@ module.exports.requireMethods = requireMethods;
|
|
|
426
459
|
module.exports.applyDefaults = applyDefaults;
|
|
427
460
|
module.exports.makeAuditEmitter = makeAuditEmitter;
|
|
428
461
|
module.exports.makeNamespacedEmitters = makeNamespacedEmitters;
|
|
462
|
+
module.exports.assignOwnEnumerable = assignOwnEnumerable;
|
package/package.json
CHANGED
package/sbom.cdx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.5",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:6a454186-ef0a-43dd-8780-6900d4f1daf5",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-06-
|
|
8
|
+
"timestamp": "2026-06-05T17:23:40.587Z",
|
|
9
9
|
"lifecycles": [
|
|
10
10
|
{
|
|
11
11
|
"phase": "build"
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
}
|
|
20
20
|
],
|
|
21
21
|
"component": {
|
|
22
|
-
"bom-ref": "@blamejs/core@0.14.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.14.22",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.14.
|
|
25
|
+
"version": "0.14.22",
|
|
26
26
|
"scope": "required",
|
|
27
27
|
"author": "blamejs contributors",
|
|
28
28
|
"description": "The Node framework that owns its stack.",
|
|
29
|
-
"purl": "pkg:npm/%40blamejs/core@0.14.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.14.22",
|
|
30
30
|
"properties": [],
|
|
31
31
|
"externalReferences": [
|
|
32
32
|
{
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"components": [],
|
|
55
55
|
"dependencies": [
|
|
56
56
|
{
|
|
57
|
-
"ref": "@blamejs/core@0.14.
|
|
57
|
+
"ref": "@blamejs/core@0.14.22",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|