@blamejs/core 0.15.12 → 0.15.14
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 +2 -0
- package/lib/a2a-tasks.js +45 -29
- package/lib/acme.js +6 -5
- package/lib/agent-event-bus.js +18 -4
- package/lib/agent-idempotency.js +7 -6
- package/lib/agent-orchestrator.js +2 -5
- package/lib/agent-saga.js +3 -5
- package/lib/agent-snapshot.js +32 -2
- package/lib/agent-tenant.js +2 -5
- package/lib/ai-adverse-decision.js +2 -15
- package/lib/ai-aedt-bias-audit.js +2 -1
- package/lib/ai-capability.js +1 -6
- package/lib/ai-content-detect.js +1 -3
- package/lib/ai-dp.js +1 -5
- package/lib/ai-frontier-protocol.js +1 -1
- package/lib/ai-input.js +2 -2
- package/lib/ai-model-manifest.js +1 -1
- package/lib/ai-output.js +16 -7
- package/lib/ai-pref.js +3 -8
- package/lib/ai-quota.js +3 -14
- package/lib/api-key.js +37 -28
- package/lib/api-snapshot.js +4 -1
- package/lib/app-shutdown.js +7 -1
- package/lib/archive-adapters.js +2 -4
- package/lib/archive-entry-policy.js +32 -0
- package/lib/archive-gz.js +9 -0
- package/lib/archive-read.js +14 -24
- package/lib/archive-tar-read.js +56 -24
- package/lib/archive.js +6 -12
- package/lib/arg-parser.js +7 -6
- package/lib/asn1-der.js +70 -22
- package/lib/asyncapi-traits.js +2 -6
- package/lib/atomic-file.js +312 -33
- package/lib/audit-chain.js +183 -54
- package/lib/audit-daily-review.js +36 -16
- package/lib/audit-emit.js +82 -0
- package/lib/audit-sign.js +258 -0
- package/lib/audit-tools.js +108 -23
- package/lib/audit.js +91 -2
- package/lib/auth/access-lock.js +7 -29
- package/lib/auth/bot-challenge.js +1 -1
- package/lib/auth/ciba.js +43 -4
- package/lib/auth/dpop.js +29 -36
- package/lib/auth/fido-mds3.js +14 -16
- package/lib/auth/jwt-external.js +26 -8
- package/lib/auth/jwt.js +15 -17
- package/lib/auth/lockout.js +24 -27
- package/lib/auth/oauth.js +67 -45
- package/lib/auth/oid4vci.js +55 -32
- package/lib/auth/oid4vp.js +3 -2
- package/lib/auth/openid-federation.js +6 -6
- package/lib/auth/passkey.js +4 -4
- package/lib/auth/password.js +8 -2
- package/lib/auth/saml.js +70 -40
- package/lib/auth/sd-jwt-vc-holder.js +2 -14
- package/lib/auth/sd-jwt-vc-issuer.js +2 -14
- package/lib/auth/sd-jwt-vc.js +25 -5
- package/lib/auth/status-list.js +21 -9
- package/lib/auth/step-up.js +15 -13
- package/lib/auth-bot-challenge.js +27 -39
- package/lib/backup/bundle.js +18 -20
- package/lib/backup/crypto.js +23 -8
- package/lib/backup/index.js +55 -67
- package/lib/backup/manifest.js +7 -1
- package/lib/bounded-map.js +112 -1
- package/lib/breach-deadline.js +1 -11
- package/lib/break-glass.js +41 -22
- package/lib/cache.js +7 -18
- package/lib/cbor.js +36 -12
- package/lib/cdn-cache-control.js +15 -12
- package/lib/cert.js +8 -13
- package/lib/chain-writer.js +162 -47
- package/lib/cli.js +10 -2
- package/lib/client-hints.js +7 -9
- package/lib/cloud-events.js +43 -33
- package/lib/cluster-storage.js +9 -41
- package/lib/cms-codec.js +2 -1
- package/lib/codepoint-class.js +84 -1
- package/lib/compliance-ai-act-logging.js +1 -6
- package/lib/compliance-ai-act-transparency.js +2 -4
- package/lib/compliance-eaa.js +2 -12
- package/lib/compliance-sanctions-fetcher.js +21 -28
- package/lib/compliance-sanctions.js +11 -21
- package/lib/compliance.js +3 -10
- package/lib/config-drift.js +24 -20
- package/lib/content-credentials.js +11 -8
- package/lib/content-digest.js +21 -12
- package/lib/cookies.js +15 -13
- package/lib/cose.js +39 -11
- package/lib/cra-report.js +1 -11
- package/lib/crdt.js +2 -1
- package/lib/crypto-field.js +34 -33
- package/lib/crypto.js +138 -7
- package/lib/csp.js +239 -3
- package/lib/daemon.js +46 -42
- package/lib/data-act.js +46 -13
- package/lib/db-file-lifecycle.js +14 -6
- package/lib/db-query.js +75 -49
- package/lib/db.js +66 -27
- package/lib/dbsc.js +5 -6
- package/lib/ddl-change-control.js +18 -14
- package/lib/deprecate.js +4 -5
- package/lib/did.js +6 -2
- package/lib/dora.js +43 -13
- package/lib/dr-runbook.js +1 -1
- package/lib/dsa.js +2 -1
- package/lib/dsr.js +30 -20
- package/lib/early-hints.js +19 -0
- package/lib/eat.js +5 -1
- package/lib/external-db-migrate.js +21 -22
- package/lib/external-db.js +74 -30
- package/lib/fda-21cfr11.js +42 -13
- package/lib/fdx.js +22 -18
- package/lib/file-upload.js +80 -66
- package/lib/flag-evaluation-context.js +5 -8
- package/lib/flag-providers.js +6 -2
- package/lib/forms.js +1 -1
- package/lib/framework-error.js +12 -0
- package/lib/framework-schema.js +19 -0
- package/lib/fsm.js +7 -12
- package/lib/gate-contract.js +911 -39
- package/lib/gdpr-ropa.js +22 -22
- package/lib/graphql-federation.js +18 -5
- package/lib/guard-agent-registry.js +2 -1
- package/lib/guard-all.js +3 -2
- package/lib/guard-archive.js +9 -30
- package/lib/guard-auth.js +23 -80
- package/lib/guard-cidr.js +20 -96
- package/lib/guard-csv.js +135 -196
- package/lib/guard-domain.js +23 -106
- package/lib/guard-dsn.js +17 -14
- package/lib/guard-email.js +46 -53
- package/lib/guard-envelope.js +2 -2
- package/lib/guard-event-bus-topic.js +2 -1
- package/lib/guard-filename.js +12 -60
- package/lib/guard-graphql.js +28 -75
- package/lib/guard-html-wcag.js +15 -2
- package/lib/guard-html.js +74 -128
- package/lib/guard-idempotency-key.js +2 -1
- package/lib/guard-image.js +280 -77
- package/lib/guard-imap-command.js +9 -10
- package/lib/guard-jmap.js +1 -1
- package/lib/guard-json.js +101 -109
- package/lib/guard-jsonpath.js +20 -88
- package/lib/guard-jwt.js +32 -114
- package/lib/guard-list-id.js +2 -7
- package/lib/guard-list-unsubscribe.js +2 -7
- package/lib/guard-mail-compose.js +5 -6
- package/lib/guard-mail-move.js +3 -2
- package/lib/guard-mail-query.js +5 -3
- package/lib/guard-mail-sieve.js +6 -7
- package/lib/guard-managesieve-command.js +6 -5
- package/lib/guard-markdown.js +76 -110
- package/lib/guard-message-id.js +5 -6
- package/lib/guard-mime.js +20 -99
- package/lib/guard-oauth.js +19 -73
- package/lib/guard-pdf.js +65 -72
- package/lib/guard-pop3-command.js +13 -14
- package/lib/guard-posture-chain.js +2 -1
- package/lib/guard-regex.js +24 -99
- package/lib/guard-saga-config.js +2 -1
- package/lib/guard-shell.js +22 -87
- package/lib/guard-smtp-command.js +9 -12
- package/lib/guard-sql.js +15 -13
- package/lib/guard-stream-args.js +2 -1
- package/lib/guard-svg.js +103 -149
- package/lib/guard-template.js +23 -80
- package/lib/guard-tenant-id.js +2 -1
- package/lib/guard-text.js +592 -0
- package/lib/guard-time.js +27 -95
- package/lib/guard-uuid.js +21 -93
- package/lib/guard-xml.js +76 -106
- package/lib/guard-yaml.js +24 -60
- package/lib/html-balance.js +7 -3
- package/lib/http-client-cache.js +5 -12
- package/lib/http-client-cookie-jar.js +35 -16
- package/lib/http-client.js +233 -74
- package/lib/http-message-signature.js +3 -2
- package/lib/i18n-messageformat.js +5 -7
- package/lib/i18n.js +83 -26
- package/lib/iab-tcf.js +3 -2
- package/lib/importmap-integrity.js +41 -1
- package/lib/inbox.js +8 -8
- package/lib/incident-report.js +12 -27
- package/lib/ip-utils.js +49 -6
- package/lib/jobs.js +3 -2
- package/lib/json-patch.js +1 -1
- package/lib/json-path.js +24 -3
- package/lib/jtd.js +2 -2
- package/lib/keychain.js +6 -18
- package/lib/legal-hold.js +30 -23
- package/lib/log-stream-cloudwatch.js +44 -112
- package/lib/log-stream-otlp-grpc.js +17 -14
- package/lib/log-stream-otlp.js +16 -80
- package/lib/log-stream-webhook.js +20 -92
- package/lib/log.js +2 -2
- package/lib/mail-agent.js +2 -2
- package/lib/mail-arc-sign.js +8 -3
- package/lib/mail-arf.js +4 -3
- package/lib/mail-auth.js +43 -69
- package/lib/mail-bimi.js +35 -55
- package/lib/mail-bounce.js +3 -3
- package/lib/mail-crypto-pgp.js +3 -2
- package/lib/mail-crypto-smime.js +71 -6
- package/lib/mail-dav.js +8 -35
- package/lib/mail-deploy.js +15 -14
- package/lib/mail-dkim.js +19 -38
- package/lib/mail-greylist.js +17 -30
- package/lib/mail-helo.js +4 -7
- package/lib/mail-journal.js +13 -9
- package/lib/mail-mdn.js +12 -7
- package/lib/mail-rbl.js +7 -12
- package/lib/mail-scan.js +5 -7
- package/lib/mail-send-deliver.js +33 -20
- package/lib/mail-server-imap.js +32 -87
- package/lib/mail-server-jmap.js +39 -52
- package/lib/mail-server-managesieve.js +29 -83
- package/lib/mail-server-mx.js +33 -74
- package/lib/mail-server-net.js +177 -0
- package/lib/mail-server-pop3.js +30 -83
- package/lib/mail-server-rate-limit.js +30 -6
- package/lib/mail-server-registry.js +1 -1
- package/lib/mail-server-submission.js +34 -73
- package/lib/mail-server-tls.js +98 -2
- package/lib/mail-spam-score.js +9 -12
- package/lib/mail-store-fts.js +1 -1
- package/lib/mail-store.js +3 -2
- package/lib/mail.js +28 -13
- package/lib/markup-escape.js +31 -0
- package/lib/markup-tokenizer.js +78 -0
- package/lib/mcp-tool-registry.js +26 -23
- package/lib/mcp.js +7 -5
- package/lib/mdoc.js +36 -14
- package/lib/metrics.js +46 -33
- package/lib/middleware/age-gate.js +3 -23
- package/lib/middleware/api-encrypt.js +13 -24
- package/lib/middleware/assetlinks.js +2 -7
- package/lib/middleware/bearer-auth.js +2 -1
- package/lib/middleware/body-parser.js +41 -52
- package/lib/middleware/bot-disclose.js +7 -10
- package/lib/middleware/bot-guard.js +28 -28
- package/lib/middleware/clear-site-data.js +5 -1
- package/lib/middleware/compression.js +9 -0
- package/lib/middleware/cors.js +32 -23
- package/lib/middleware/csrf-protect.js +73 -23
- package/lib/middleware/daily-byte-quota.js +12 -30
- package/lib/middleware/deny-response.js +19 -1
- package/lib/middleware/fetch-metadata.js +35 -4
- package/lib/middleware/idempotency-key.js +4 -20
- package/lib/middleware/network-allowlist.js +61 -30
- package/lib/middleware/rate-limit.js +45 -44
- package/lib/middleware/scim-server.js +5 -3
- package/lib/middleware/security-headers.js +33 -7
- package/lib/middleware/security-txt.js +2 -6
- package/lib/middleware/speculation-rules.js +6 -3
- package/lib/middleware/tus-upload.js +14 -29
- package/lib/middleware/web-app-manifest.js +2 -7
- package/lib/migrations.js +4 -13
- package/lib/mime-parse.js +34 -17
- package/lib/module-loader.js +44 -0
- package/lib/money.js +105 -0
- package/lib/mtls-ca.js +125 -41
- package/lib/network-byte-quota.js +4 -18
- package/lib/network-dane.js +8 -6
- package/lib/network-dns-resolver.js +98 -7
- package/lib/network-dns.js +9 -2
- package/lib/network-dnssec.js +18 -17
- package/lib/network-heartbeat.js +3 -2
- package/lib/network-smtp-policy.js +52 -46
- package/lib/network-tls.js +67 -47
- package/lib/network-tsig.js +2 -2
- package/lib/nis2-report.js +2 -12
- package/lib/nist-crosswalk.js +1 -1
- package/lib/nonce-store.js +81 -3
- package/lib/ntp-check.js +28 -0
- package/lib/numeric-bounds.js +31 -8
- package/lib/object-store/azure-blob-bucket-ops.js +2 -6
- package/lib/object-store/azure-blob.js +6 -47
- package/lib/object-store/gcs-bucket-ops.js +4 -2
- package/lib/object-store/gcs.js +14 -75
- package/lib/object-store/http-put.js +2 -7
- package/lib/object-store/http-request.js +157 -0
- package/lib/object-store/local.js +37 -17
- package/lib/object-store/sigv4-bucket-ops.js +2 -1
- package/lib/object-store/sigv4.js +10 -79
- package/lib/observability-otlp-exporter.js +29 -29
- package/lib/observability.js +95 -0
- package/lib/openapi-paths-builder.js +7 -3
- package/lib/otel-export.js +7 -10
- package/lib/outbox.js +54 -41
- package/lib/pagination.js +11 -15
- package/lib/parsers/safe-env.js +5 -4
- package/lib/parsers/safe-ini.js +10 -4
- package/lib/parsers/safe-toml.js +11 -9
- package/lib/parsers/safe-xml.js +3 -3
- package/lib/parsers/safe-yaml.js +28 -9
- package/lib/pick.js +63 -5
- package/lib/pipl-cn.js +69 -59
- package/lib/privacy-pass.js +8 -6
- package/lib/problem-details.js +2 -5
- package/lib/pubsub.js +4 -8
- package/lib/queue-local.js +10 -3
- package/lib/redact.js +9 -4
- package/lib/render.js +4 -2
- package/lib/request-helpers.js +334 -29
- package/lib/resource-access-lock.js +3 -3
- package/lib/restore-bundle.js +46 -18
- package/lib/restore-rollback.js +10 -4
- package/lib/restore.js +24 -22
- package/lib/retention.js +23 -9
- package/lib/router.js +17 -4
- package/lib/safe-async.js +457 -0
- package/lib/safe-buffer.js +137 -6
- package/lib/safe-decompress.js +2 -1
- package/lib/safe-dns.js +2 -1
- package/lib/safe-ical.js +14 -28
- package/lib/safe-icap.js +1 -1
- package/lib/safe-json.js +51 -8
- package/lib/safe-jsonpath.js +6 -5
- package/lib/safe-mime.js +25 -29
- package/lib/safe-redirect.js +2 -5
- package/lib/safe-schema.js +7 -6
- package/lib/safe-sieve.js +1 -1
- package/lib/safe-sql.js +126 -0
- package/lib/safe-vcard.js +13 -27
- package/lib/sandbox-worker.js +15 -2
- package/lib/sandbox.js +4 -3
- package/lib/scheduler.js +22 -13
- package/lib/sec-cyber.js +82 -37
- package/lib/seeders.js +4 -11
- package/lib/self-update-standalone-verifier.js +16 -0
- package/lib/self-update.js +92 -69
- package/lib/session-device-binding.js +112 -66
- package/lib/session.js +219 -7
- package/lib/sql.js +228 -81
- package/lib/sse.js +6 -10
- package/lib/static.js +201 -111
- package/lib/storage.js +4 -2
- package/lib/structured-fields.js +275 -16
- package/lib/template.js +7 -5
- package/lib/tenant-quota.js +53 -38
- package/lib/tsa.js +16 -17
- package/lib/validate-opts.js +154 -8
- package/lib/vault/index.js +5 -0
- package/lib/vault/passphrase-ops.js +22 -26
- package/lib/vault/passphrase-source.js +8 -3
- package/lib/vault/rotate.js +13 -18
- package/lib/vault/seal-pem-file.js +34 -49
- package/lib/vault-aad.js +3 -2
- package/lib/vc.js +3 -8
- package/lib/vendor/MANIFEST.json +10 -10
- package/lib/vendor/public-suffix-list.dat +23 -10
- package/lib/vendor/public-suffix-list.data.js +5498 -5494
- package/lib/vex.js +35 -13
- package/lib/web-push-vapid.js +23 -20
- package/lib/webhook-dispatcher.js +706 -0
- package/lib/webhook.js +59 -19
- package/lib/websocket-channels.js +9 -7
- package/lib/websocket.js +8 -4
- package/lib/worm.js +3 -4
- package/lib/ws-client.js +65 -56
- package/lib/x509-chain.js +44 -0
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/bounded-map.js
CHANGED
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
39
|
var numericBounds = require("./numeric-bounds");
|
|
40
|
+
var validateOpts = require("./validate-opts");
|
|
40
41
|
var { defineClass } = require("./framework-error");
|
|
41
42
|
|
|
42
43
|
var BoundedMapError = defineClass("BoundedMapError");
|
|
@@ -99,4 +100,114 @@ function boundedMap(opts) {
|
|
|
99
100
|
};
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
|
|
103
|
+
// getOrInsert(map, key, factory, opts?) — Map.prototype.getOrInsertComputed(key,
|
|
104
|
+
// factory) polyfill. The native method lands in Node 26 but the framework floor
|
|
105
|
+
// is 24.16, so the framework's request-keyed Maps hand-roll `var v = m.get(k);
|
|
106
|
+
// if (!v) { v = ...; m.set(k, v); }` everywhere. This is the ONE place that
|
|
107
|
+
// shape lives, so the floor-bump sweep swaps the body for the native method in
|
|
108
|
+
// a single edit instead of N call sites. Returns the existing value; otherwise
|
|
109
|
+
// computes factory(key), stores it, and returns it.
|
|
110
|
+
//
|
|
111
|
+
// Optional cardinality ceiling so a CAPPED caller (e.g. b.metrics' label
|
|
112
|
+
// cardinality cap) composes this rather than re-rolling the get-then-set with
|
|
113
|
+
// its own size guard: when `opts.maxSize` is a number and the key is absent at
|
|
114
|
+
// or above that size, the value is NOT stored and `opts.onFull(key)` (or
|
|
115
|
+
// undefined) is returned. Works on a plain Map or the boundedMap facade above.
|
|
116
|
+
function _assertMapLike(map, fnName) {
|
|
117
|
+
validateOpts.requireMethods(map, ["has", "get", "set"],
|
|
118
|
+
fnName + ": map (Map-like)", BoundedMapError, "bounded-map/bad-map");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function getOrInsert(map, key, factory, opts) {
|
|
122
|
+
_assertMapLike(map, "getOrInsert");
|
|
123
|
+
if (typeof factory !== "function") {
|
|
124
|
+
throw new BoundedMapError("bounded-map/bad-factory",
|
|
125
|
+
"getOrInsert: factory must be a function, got " + (typeof factory));
|
|
126
|
+
}
|
|
127
|
+
if (map.has(key)) return map.get(key);
|
|
128
|
+
if (opts && opts.maxSize !== undefined) {
|
|
129
|
+
// A bad maxSize silently breaks the ceiling (NaN/Infinity never cap →
|
|
130
|
+
// unbounded; negative always caps → never stores) — validate via the
|
|
131
|
+
// shared numeric-bounds / validate-opts assertions, never a hand-rolled
|
|
132
|
+
// typeof check.
|
|
133
|
+
numericBounds.requirePositiveFiniteIntIfPresent(opts.maxSize,
|
|
134
|
+
"getOrInsert: opts.maxSize", BoundedMapError, "bounded-map/bad-max-size");
|
|
135
|
+
validateOpts.optionalFunction(opts.onFull,
|
|
136
|
+
"getOrInsert: opts.onFull", BoundedMapError, "bounded-map/bad-on-full");
|
|
137
|
+
if (map.size >= opts.maxSize) {
|
|
138
|
+
return opts.onFull ? opts.onFull(key) : undefined;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
var value = factory(key);
|
|
142
|
+
map.set(key, value);
|
|
143
|
+
return value;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// requireAbsent / requirePresent complete the keyed-store guard family that
|
|
147
|
+
// getOrInsert opened. A framework registry (topics, jobs, metrics, RoPA
|
|
148
|
+
// activities, DSR tickets, …) keys a Map and guards every mutation by
|
|
149
|
+
// presence: a unique INSERT throws on a duplicate key, an UPDATE/lookup throws
|
|
150
|
+
// when the key is missing. That guard — `if (map.has(k)) throw <duplicate>` /
|
|
151
|
+
// `if (!map.has(k)) throw <not-found>` — recurred across ~18 registries, each
|
|
152
|
+
// re-rolling the check beside its own .set. Centralizing it makes the
|
|
153
|
+
// uniqueness/existence check impossible to forget (the primitive IS the check)
|
|
154
|
+
// while leaving the caller its own typed error and value shape.
|
|
155
|
+
|
|
156
|
+
// requireAbsent(map, key, onConflict) — uniqueness guard before an insert.
|
|
157
|
+
// When `key` is already present, invokes onConflict(key, existingValue)
|
|
158
|
+
// (callers throw their own typed duplicate error from it) and returns its
|
|
159
|
+
// result; otherwise returns undefined and the caller performs its insert.
|
|
160
|
+
function requireAbsent(map, key, onConflict) {
|
|
161
|
+
_assertMapLike(map, "requireAbsent");
|
|
162
|
+
if (typeof onConflict !== "function") {
|
|
163
|
+
throw new BoundedMapError("bounded-map/bad-on-conflict",
|
|
164
|
+
"requireAbsent: onConflict must be a function, got " + (typeof onConflict));
|
|
165
|
+
}
|
|
166
|
+
if (map.has(key)) return onConflict(key, map.get(key));
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// requirePresent(map, key, onMissing) — existence guard before an update or
|
|
171
|
+
// lookup. When `key` is absent, invokes onMissing(key) (callers throw their
|
|
172
|
+
// own typed not-found error) and returns its result; otherwise returns the
|
|
173
|
+
// existing value, so a must-exist lookup is a single call.
|
|
174
|
+
function requirePresent(map, key, onMissing) {
|
|
175
|
+
_assertMapLike(map, "requirePresent");
|
|
176
|
+
if (typeof onMissing !== "function") {
|
|
177
|
+
throw new BoundedMapError("bounded-map/bad-on-missing",
|
|
178
|
+
"requirePresent: onMissing must be a function, got " + (typeof onMissing));
|
|
179
|
+
}
|
|
180
|
+
if (!map.has(key)) return onMissing(key);
|
|
181
|
+
return map.get(key);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// requireAbsentMember(set, key, onConflict) — the Set sibling of requireAbsent.
|
|
185
|
+
// A value-LESS membership store (a Set tracking seen keys while parsing, or
|
|
186
|
+
// visited nodes during a recursive walk) rejects a re-occurrence:
|
|
187
|
+
// `if (set.has(key)) throw <duplicate|cycle>` before `set.add(key)`. Unlike
|
|
188
|
+
// requireAbsent (a keyed Map with values), the container has nothing to return,
|
|
189
|
+
// so only `.has` is required — a Set, or any { has } membership view. When the
|
|
190
|
+
// member is already present, invokes onConflict(key) (the caller throws its own
|
|
191
|
+
// typed duplicate / cycle error) and returns its result; otherwise returns
|
|
192
|
+
// undefined and the caller performs its `.add`.
|
|
193
|
+
function requireAbsentMember(set, key, onConflict) {
|
|
194
|
+
if (!set || typeof set.has !== "function") {
|
|
195
|
+
throw new BoundedMapError("bounded-map/bad-set",
|
|
196
|
+
"requireAbsentMember: set must be a Set-like { has }");
|
|
197
|
+
}
|
|
198
|
+
if (typeof onConflict !== "function") {
|
|
199
|
+
throw new BoundedMapError("bounded-map/bad-on-conflict",
|
|
200
|
+
"requireAbsentMember: onConflict must be a function, got " + (typeof onConflict));
|
|
201
|
+
}
|
|
202
|
+
if (set.has(key)) return onConflict(key);
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
module.exports = {
|
|
207
|
+
boundedMap: boundedMap,
|
|
208
|
+
BoundedMapError: BoundedMapError,
|
|
209
|
+
getOrInsert: getOrInsert,
|
|
210
|
+
requireAbsent: requireAbsent,
|
|
211
|
+
requirePresent: requirePresent,
|
|
212
|
+
requireAbsentMember: requireAbsentMember,
|
|
213
|
+
};
|
package/lib/breach-deadline.js
CHANGED
|
@@ -149,21 +149,11 @@ function forStates(states, detectedAtMs) {
|
|
|
149
149
|
// deadline registry and tracks per-state filing status.
|
|
150
150
|
function createReporter(opts) {
|
|
151
151
|
opts = opts || {};
|
|
152
|
-
var auditOn = opts.audit !== false;
|
|
153
152
|
var now = typeof opts.now === "function" ? opts.now : function () { return Date.now(); };
|
|
154
153
|
var seq = 0;
|
|
155
154
|
var breaches = new Map();
|
|
156
155
|
|
|
157
|
-
|
|
158
|
-
if (!auditOn) return;
|
|
159
|
-
try {
|
|
160
|
-
audit().safeEmit({
|
|
161
|
-
action: "breach.report." + action,
|
|
162
|
-
outcome: outcome,
|
|
163
|
-
metadata: metadata || {},
|
|
164
|
-
});
|
|
165
|
-
} catch (_e) { /* drop-silent */ }
|
|
166
|
-
}
|
|
156
|
+
var _emitAudit = audit().namespaced("breach.report", opts.audit);
|
|
167
157
|
|
|
168
158
|
function open(spec) {
|
|
169
159
|
if (!spec || typeof spec !== "object") {
|
package/lib/break-glass.js
CHANGED
|
@@ -120,10 +120,13 @@ function _appSqlOpts() { return { dialect: clusterStorage.dialect(), quoteName:
|
|
|
120
120
|
// Populated on first access per-table; invalidated on policy.set/delete.
|
|
121
121
|
var policyCache = new Map(); // table -> policy
|
|
122
122
|
var initialized = false;
|
|
123
|
-
// Framework-wide
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
|
|
123
|
+
// Framework-wide client-IP resolver (built at init). The grant row's `ip`
|
|
124
|
+
// field is a security control — a grant is pinned to the IP that minted it
|
|
125
|
+
// and re-checked on redeem. X-Forwarded-For is forgeable, so the binding is
|
|
126
|
+
// meaningful only when resolution is peer-gated: operators declare their
|
|
127
|
+
// reverse proxies via init({ trustedProxies }) or own resolution via
|
|
128
|
+
// init({ clientIpResolver }). Default resolves the socket address only.
|
|
129
|
+
var _ipResolver = requestHelpers.trustedClientIp();
|
|
127
130
|
|
|
128
131
|
// Factor lockout — wrap auth.lockout so a hostile actor brute-forcing
|
|
129
132
|
// TOTP codes against break-glass gets shut out after a few failures.
|
|
@@ -457,28 +460,45 @@ async function migrate(table, opts) {
|
|
|
457
460
|
* @related b.breakGlass.policy.set, b.breakGlass.grant
|
|
458
461
|
*
|
|
459
462
|
* One-shot boot wiring. Clears the in-memory policy cache, resets the
|
|
460
|
-
* factor-lockout counter, and records the
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
*
|
|
463
|
+
* factor-lockout counter, and records how the grant row's `ip` field is
|
|
464
|
+
* resolved. That IP is a security binding — the grant pins to it at mint
|
|
465
|
+
* and re-checks it on redeem — so resolution is peer-gated: declare your
|
|
466
|
+
* reverse proxies via `trustedProxies` (CIDRs; X-Forwarded-For honored
|
|
467
|
+
* only from a trusted peer) or own resolution via `clientIpResolver`. A
|
|
468
|
+
* bare `trustProxy` is refused — a forgeable pin is no pin. Operators call
|
|
469
|
+
* this once at boot, before any policy / grant / unseal call — every other
|
|
470
|
+
* primitive throws `breakglass/not-initialized` until init has run.
|
|
466
471
|
*
|
|
467
472
|
* @opts
|
|
468
|
-
*
|
|
473
|
+
* trustedProxies: string|string[], // CIDRs of your reverse proxies — peer-gates X-Forwarded-For
|
|
474
|
+
* clientIpResolver: function(req): string|null, // own grant-IP resolution
|
|
469
475
|
*
|
|
470
476
|
* @example
|
|
471
|
-
* b.breakGlass.init({
|
|
477
|
+
* b.breakGlass.init({ trustedProxies: ["10.0.0.0/8"] });
|
|
472
478
|
* // → undefined (init returns nothing; throws on bad opts)
|
|
473
479
|
*/
|
|
474
480
|
function init(opts) {
|
|
475
481
|
opts = opts || {};
|
|
476
|
-
validateOpts(opts, ["trustProxy"], "breakGlass.init");
|
|
482
|
+
validateOpts(opts, ["trustProxy", "trustedProxies", "clientIpResolver"], "breakGlass.init");
|
|
483
|
+
var resolver;
|
|
484
|
+
try {
|
|
485
|
+
resolver = requestHelpers.trustedClientIp({
|
|
486
|
+
trustedProxies: opts.trustedProxies,
|
|
487
|
+
clientIpResolver: opts.clientIpResolver,
|
|
488
|
+
});
|
|
489
|
+
} catch (e) {
|
|
490
|
+
throw new BreakGlassError("breakglass/bad-opt", e.message);
|
|
491
|
+
}
|
|
492
|
+
if ((opts.trustProxy === true || typeof opts.trustProxy === "number") && !resolver.peerGated) {
|
|
493
|
+
throw new BreakGlassError("breakglass/bad-opt",
|
|
494
|
+
"trustProxy is spoofable — a grant pinned to a forgeable X-Forwarded-For is no " +
|
|
495
|
+
"pin at all. Declare your reverse proxies via trustedProxies: [\"10.0.0.0/8\", …] " +
|
|
496
|
+
"or supply clientIpResolver(req).");
|
|
497
|
+
}
|
|
477
498
|
initialized = true;
|
|
478
499
|
policyCache.clear();
|
|
479
500
|
_factorLockout = null;
|
|
480
|
-
|
|
481
|
-
? opts.trustProxy : false;
|
|
501
|
+
_ipResolver = resolver;
|
|
482
502
|
}
|
|
483
503
|
|
|
484
504
|
function _resetForTest() {
|
|
@@ -490,7 +510,7 @@ function _resetForTest() {
|
|
|
490
510
|
}
|
|
491
511
|
_factorLockout = null;
|
|
492
512
|
_factorLockoutCache = null;
|
|
493
|
-
|
|
513
|
+
_ipResolver = requestHelpers.trustedClientIp();
|
|
494
514
|
}
|
|
495
515
|
|
|
496
516
|
function _requireInit() {
|
|
@@ -1119,11 +1139,10 @@ async function grant(opts) {
|
|
|
1119
1139
|
var nowMs = Date.now();
|
|
1120
1140
|
var grantId = "bg-" + generateToken(GRANT_ID_BYTES);
|
|
1121
1141
|
var sessionId = (opts.req && opts.req.session && opts.req.session.id) || null;
|
|
1122
|
-
//
|
|
1123
|
-
//
|
|
1124
|
-
//
|
|
1125
|
-
|
|
1126
|
-
var ipFromReq = requestHelpers.clientIp(opts.req, { trustProxy: _trustProxy });
|
|
1142
|
+
// Peer-gated client-IP resolution from init() (trustedProxies /
|
|
1143
|
+
// clientIpResolver). Without it, X-Forwarded-For is ignored as
|
|
1144
|
+
// attacker-forgeable and the grant pins to the socket remoteAddress only.
|
|
1145
|
+
var ipFromReq = _ipResolver.resolve(opts.req);
|
|
1127
1146
|
|
|
1128
1147
|
var grantRow = {
|
|
1129
1148
|
_id: grantId,
|
|
@@ -1218,7 +1237,7 @@ function _enforceGrantPins(policy, grantRow, redeemReq, actorFor) {
|
|
|
1218
1237
|
"captured at mint (fail-closed) — re-mint from a request whose client " +
|
|
1219
1238
|
"IP the framework can resolve", true);
|
|
1220
1239
|
}
|
|
1221
|
-
var redeemIp =
|
|
1240
|
+
var redeemIp = _ipResolver.resolve(redeemReq);
|
|
1222
1241
|
if (redeemIp !== grantRow.ip) {
|
|
1223
1242
|
audit.safeEmit({
|
|
1224
1243
|
action: "breakglass.unsealrow",
|
package/lib/cache.js
CHANGED
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
* LRU + TTL cache with operator-supplied namespacing, drop-silent key validation on hot-path observability, and pluggable backends that share semantics across single-process and clustered nodes.
|
|
71
71
|
*/
|
|
72
72
|
|
|
73
|
+
var boundedMap = require("./bounded-map");
|
|
73
74
|
var cacheRedis = require("./cache-redis");
|
|
74
75
|
var redisClient = require("./redis-client");
|
|
75
76
|
var clusterStorage = require("./cluster-storage");
|
|
@@ -179,16 +180,8 @@ function _defaultSizeOf(value) {
|
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
function _validateBackendObject(backend) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
throw _err("BAD_OPT", "cache.create: custom backend must be an object");
|
|
185
|
-
}
|
|
186
|
-
for (var i = 0; i < required.length; i++) {
|
|
187
|
-
if (typeof backend[required[i]] !== "function") {
|
|
188
|
-
throw _err("BAD_OPT", "cache.create: custom backend missing method '" + required[i] +
|
|
189
|
-
"' (required: " + required.join(", ") + ")");
|
|
190
|
-
}
|
|
191
|
-
}
|
|
183
|
+
validateOpts.requireMethods(backend, ["get", "set", "del", "clear", "size", "close"],
|
|
184
|
+
"cache.create: custom backend", CacheError, "BAD_OPT");
|
|
192
185
|
}
|
|
193
186
|
|
|
194
187
|
function _validateCreateOpts(opts) {
|
|
@@ -338,8 +331,7 @@ function _memoryBackend(cfg) {
|
|
|
338
331
|
totalBytes += bytes;
|
|
339
332
|
if (tags && tags.length > 0) {
|
|
340
333
|
for (var i = 0; i < tags.length; i++) {
|
|
341
|
-
var s =
|
|
342
|
-
if (!s) { s = new Set(); tagIndex.set(tags[i], s); }
|
|
334
|
+
var s = boundedMap.getOrInsert(tagIndex, tags[i], function () { return new Set(); });
|
|
343
335
|
s.add(key);
|
|
344
336
|
}
|
|
345
337
|
}
|
|
@@ -1028,12 +1020,9 @@ function create(opts) {
|
|
|
1028
1020
|
var operatorObs = opts.observability || null;
|
|
1029
1021
|
var clock = opts.clock || function () { return Date.now(); };
|
|
1030
1022
|
var invalidationPubsub = opts.invalidationPubsub || null;
|
|
1031
|
-
if (invalidationPubsub
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
typeof invalidationPubsub.unsubscribe !== "function")) {
|
|
1035
|
-
throw _err("BAD_OPT",
|
|
1036
|
-
"cache.create: invalidationPubsub must implement { publish, subscribe, unsubscribe } (b.pubsub.create instance)");
|
|
1023
|
+
if (invalidationPubsub) {
|
|
1024
|
+
validateOpts.requireMethods(invalidationPubsub, ["publish", "subscribe", "unsubscribe"],
|
|
1025
|
+
"cache.create: invalidationPubsub (b.pubsub.create instance)", CacheError, "BAD_OPT");
|
|
1037
1026
|
}
|
|
1038
1027
|
var invalidationChannel = "cache:" + namespace + ":invalidate";
|
|
1039
1028
|
var invalidationToken = null;
|
package/lib/cbor.js
CHANGED
|
@@ -54,10 +54,18 @@
|
|
|
54
54
|
*/
|
|
55
55
|
|
|
56
56
|
var C = require("./constants");
|
|
57
|
+
var safeBuffer = require("./safe-buffer");
|
|
58
|
+
var boundedMap = require("./bounded-map");
|
|
57
59
|
var { defineClass } = require("./framework-error");
|
|
58
60
|
|
|
59
61
|
var CborError = defineClass("CborError", { alwaysPermanent: true });
|
|
60
62
|
|
|
63
|
+
// Hoisted so the map-decode loop's per-key uniqueness guard doesn't allocate a
|
|
64
|
+
// closure per key (the decode hot path).
|
|
65
|
+
function _throwDuplicateKey() {
|
|
66
|
+
throw new CborError("cbor/duplicate-key", "cbor.decode: duplicate map key (RFC 8949 §5.6)");
|
|
67
|
+
}
|
|
68
|
+
|
|
61
69
|
var DEFAULT_MAX_DEPTH = 64; // nesting depth, not a size
|
|
62
70
|
var ABSOLUTE_MAX_DEPTH = 256; // nesting depth ceiling, not a size
|
|
63
71
|
var DEFAULT_MAX_BYTES = C.BYTES.mib(16);
|
|
@@ -126,6 +134,7 @@ function _encodeFloat(value) {
|
|
|
126
134
|
// exponent must fit the half range and the low 13 mantissa bits must
|
|
127
135
|
// be zero (half has a 10-bit mantissa vs float32's 23).
|
|
128
136
|
function _doubleToHalfBits(value) {
|
|
137
|
+
if (value === 0) return Object.is(value, -0) ? 0x8000 : 0x0000; // ±zero → half zero (sign-preserving); -0 must not fall to the subnormal path
|
|
129
138
|
var fbuf = Buffer.alloc(4);
|
|
130
139
|
fbuf.writeFloatBE(value, 0);
|
|
131
140
|
if (fbuf.readFloatBE(0) !== value) return -1; // not exact in float32 → not in float16
|
|
@@ -176,8 +185,10 @@ function _encodeValue(value, opts) {
|
|
|
176
185
|
// Exact integers within the safe range encode as CBOR integers;
|
|
177
186
|
// an integer-VALUED number beyond 2^53 (e.g. 1e300) has lost
|
|
178
187
|
// integer precision and is a float — encode it as a float (use a
|
|
179
|
-
// bigint for exact 64-bit CBOR integers).
|
|
180
|
-
|
|
188
|
+
// bigint for exact 64-bit CBOR integers). NEGATIVE ZERO is excluded:
|
|
189
|
+
// CBOR integers have no -0, so encoding -0 as the uint 0 would silently
|
|
190
|
+
// drop the sign; it falls through to the float branch (float16 -0.0).
|
|
191
|
+
if (Number.isInteger(value) && !Object.is(value, -0) && Math.abs(value) <= Number.MAX_SAFE_INTEGER) {
|
|
181
192
|
return value >= 0 ? _head(0, value) : _head(1, -1 - value);
|
|
182
193
|
}
|
|
183
194
|
if (!isFinite(value) && !opts.allowNonFinite) {
|
|
@@ -300,7 +311,7 @@ function decode(buffer, opts) {
|
|
|
300
311
|
}
|
|
301
312
|
var buf = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer);
|
|
302
313
|
var maxBytes = _capInt(opts.maxBytes, DEFAULT_MAX_BYTES, ABSOLUTE_MAX_BYTES);
|
|
303
|
-
if (buf
|
|
314
|
+
if (safeBuffer.byteLengthOf(buf) > maxBytes) {
|
|
304
315
|
throw new CborError("cbor/too-large",
|
|
305
316
|
"cbor.decode: input " + buf.length + " bytes exceeds maxBytes " + maxBytes);
|
|
306
317
|
}
|
|
@@ -336,7 +347,11 @@ function _need(state, n) {
|
|
|
336
347
|
|
|
337
348
|
function _readArgument(state, ai) {
|
|
338
349
|
// ai is the low-5-bits additional info. Returns the argument as a
|
|
339
|
-
// Number (or BigInt for 8-byte values beyond Number range).
|
|
350
|
+
// Number (or BigInt for 8-byte values beyond Number range). Non-minimal
|
|
351
|
+
// (non-canonical) heads are tolerated here by design — strict canonical
|
|
352
|
+
// enforcement is the opt-in `requireDeterministic` mode (round-trip compare);
|
|
353
|
+
// duplicate keys encoded non-minimally are caught value-based in the map
|
|
354
|
+
// decoder regardless of mode (RFC 8949 §5.6).
|
|
340
355
|
if (ai < CBOR_AI_1BYTE) return ai;
|
|
341
356
|
if (ai === CBOR_AI_1BYTE) { _need(state, 1); var v1 = state.buf[state.pos]; state.pos += 1; return v1; }
|
|
342
357
|
if (ai === 25) { _need(state, 2); var v2 = state.buf.readUInt16BE(state.pos); state.pos += 2; return v2; }
|
|
@@ -409,17 +424,26 @@ function _decodeItem(state, depth) {
|
|
|
409
424
|
case 5: { // map
|
|
410
425
|
var mlen = _lenOf(_readArgument(state, ai));
|
|
411
426
|
var m = new Map();
|
|
412
|
-
|
|
427
|
+
// O(1) duplicate-key detection (RFC 8949 §5.6) keyed on the CANONICAL
|
|
428
|
+
// re-encoding of each decoded key — not its raw input bytes. A per-key
|
|
429
|
+
// Buffer.compare scan over a `seen` array is O(n²), and cbor.decode runs on
|
|
430
|
+
// raw attacker bytes BEFORE any signature check on every COSE / CWT / EAT /
|
|
431
|
+
// mdoc verify path, so a large distinct-key map is an unauthenticated
|
|
432
|
+
// algorithmic-complexity DoS (CWE-407). Keying on the canonical encoding
|
|
433
|
+
// (rather than the input bytes) also closes the bypass where the SAME key
|
|
434
|
+
// value is sent twice with different (e.g. non-minimal) encodings to dodge
|
|
435
|
+
// a byte-wise dup check and silently last-value-win — both copies
|
|
436
|
+
// re-encode identically here and the duplicate is caught regardless of the
|
|
437
|
+
// requireDeterministic mode.
|
|
438
|
+
var seen = new Set();
|
|
413
439
|
for (var j = 0; j < mlen; j++) {
|
|
414
440
|
var keyStart = state.pos;
|
|
415
441
|
var key = _decodeItem(state, depth + 1);
|
|
416
|
-
var
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
seen.push(keyBytes);
|
|
442
|
+
var keyId;
|
|
443
|
+
try { keyId = encode(key).toString("latin1"); }
|
|
444
|
+
catch (_e) { keyId = "raw:" + state.buf.toString("latin1", keyStart, state.pos); }
|
|
445
|
+
boundedMap.requireAbsentMember(seen, keyId, _throwDuplicateKey);
|
|
446
|
+
seen.add(keyId);
|
|
423
447
|
var val = _decodeItem(state, depth + 1);
|
|
424
448
|
m.set(key, val);
|
|
425
449
|
}
|
package/lib/cdn-cache-control.js
CHANGED
|
@@ -336,20 +336,19 @@ function parse(headerValue) {
|
|
|
336
336
|
if (trimmed.length === 0) return null;
|
|
337
337
|
|
|
338
338
|
var out = { directives: {} };
|
|
339
|
-
var
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
var eq = raw.indexOf("=");
|
|
339
|
+
var kvps = structuredFields.parseKeyValuePieces(
|
|
340
|
+
structuredFields.splitTopLevel(trimmed, ","));
|
|
341
|
+
for (var p = 0; p < kvps.length; p += 1) {
|
|
342
|
+
var kvp = kvps[p];
|
|
344
343
|
var key, val, bare;
|
|
345
|
-
if (
|
|
346
|
-
key =
|
|
344
|
+
if (kvp.value === null) {
|
|
345
|
+
key = kvp.key;
|
|
347
346
|
val = "";
|
|
348
347
|
bare = true;
|
|
349
348
|
}
|
|
350
349
|
else {
|
|
351
|
-
key =
|
|
352
|
-
val =
|
|
350
|
+
key = kvp.key;
|
|
351
|
+
val = kvp.value.trim();
|
|
353
352
|
bare = false;
|
|
354
353
|
// Unquote sf-string per RFC 8941 §3.3.3 (defensive — operators
|
|
355
354
|
// routinely emit `s-maxage="3600"` even though the directive is
|
|
@@ -377,9 +376,13 @@ function parse(headerValue) {
|
|
|
377
376
|
}
|
|
378
377
|
continue;
|
|
379
378
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
379
|
+
// RFC 9111 delta-seconds is 1*DIGIT — Number() would also accept hex
|
|
380
|
+
// ("0x10"), exponential ("1e3"), and surrounding whitespace, which are
|
|
381
|
+
// not valid cache-directive values. Round-trip parseInt to require pure
|
|
382
|
+
// decimal digits.
|
|
383
|
+
var n = parseInt(val, 10);
|
|
384
|
+
if (Number.isFinite(n) && n >= 0 && String(n) === val) {
|
|
385
|
+
out[_camel(key)] = n;
|
|
383
386
|
}
|
|
384
387
|
continue;
|
|
385
388
|
}
|
package/lib/cert.js
CHANGED
|
@@ -100,10 +100,8 @@ function _createSealedDiskStorage(opts) {
|
|
|
100
100
|
CertError, "cert/bad-storage-root");
|
|
101
101
|
var rootDir = nodePath.resolve(opts.rootDir);
|
|
102
102
|
var vaultStore = opts.vault || vault().getDefaultStore();
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
"cert.storage: vault must expose seal(buf) + unseal(buf) — typically b.vault.getDefaultStore()");
|
|
106
|
-
}
|
|
103
|
+
validateOpts.requireMethods(vaultStore, ["seal", "unseal"],
|
|
104
|
+
"cert.storage: vault (typically b.vault.getDefaultStore())", CertError, "cert/bad-storage-vault");
|
|
107
105
|
|
|
108
106
|
function _ensureDir(dir) { atomicFile.ensureDir(dir); }
|
|
109
107
|
function _certDir(name) { return nodePath.join(rootDir, name); }
|
|
@@ -127,7 +125,9 @@ function _createSealedDiskStorage(opts) {
|
|
|
127
125
|
async readSealed(relPath) {
|
|
128
126
|
var p = nodePath.join(rootDir, relPath + ".sealed");
|
|
129
127
|
if (!nodeFs.existsSync(p)) return null;
|
|
130
|
-
|
|
128
|
+
// Cap + fd-bound (sealed cert/key envelope is well under 256 KiB). NO
|
|
129
|
+
// refuseSymlink: the sealed store may be operator-mounted.
|
|
130
|
+
var sealed = atomicFile.fdSafeReadSync(p, { maxBytes: C.BYTES.kib(256) });
|
|
131
131
|
var plain = vaultStore.unseal(sealed);
|
|
132
132
|
return Buffer.isBuffer(plain) ? plain : Buffer.from(plain);
|
|
133
133
|
},
|
|
@@ -141,7 +141,7 @@ function _createSealedDiskStorage(opts) {
|
|
|
141
141
|
async readMeta(certName) {
|
|
142
142
|
var p = nodePath.join(_certDir(certName), "meta.json");
|
|
143
143
|
if (!nodeFs.existsSync(p)) return null;
|
|
144
|
-
try { return safeJson.parse(
|
|
144
|
+
try { return safeJson.parse(atomicFile.fdSafeReadSync(p, { maxBytes: C.BYTES.kib(16), encoding: "utf8" }), { maxBytes: C.BYTES.kib(16) }); }
|
|
145
145
|
catch (e) {
|
|
146
146
|
// meta.json is a derived index (expiry + fingerprint), not a
|
|
147
147
|
// source of truth — the sealed cert is. A corrupt meta must not
|
|
@@ -411,12 +411,7 @@ function create(opts) {
|
|
|
411
411
|
var ocspTimer = null;
|
|
412
412
|
var stopped = false;
|
|
413
413
|
|
|
414
|
-
|
|
415
|
-
if (!auditEnabled) return;
|
|
416
|
-
try {
|
|
417
|
-
audit().safeEmit({ action: action, outcome: outcome, metadata: metadata || {} });
|
|
418
|
-
} catch (_e) { /* drop-silent — audit emission is hot-path */ }
|
|
419
|
-
}
|
|
414
|
+
var _emitAudit = audit().namespaced(null, { audit: auditEnabled });
|
|
420
415
|
|
|
421
416
|
function _bootAcme() {
|
|
422
417
|
if (acmeClient) return acmeClient;
|
|
@@ -436,7 +431,7 @@ function create(opts) {
|
|
|
436
431
|
function _loadOrGenerateAccountKey() {
|
|
437
432
|
// Read sealed account JWK; generate + persist if absent.
|
|
438
433
|
var sealedBuf = nodeFs.existsSync(nodePath.join(storage.rootDir, "account/jwk.json.sealed"))
|
|
439
|
-
?
|
|
434
|
+
? atomicFile.fdSafeReadSync(nodePath.join(storage.rootDir, "account/jwk.json.sealed"), { maxBytes: C.BYTES.kib(64) })
|
|
440
435
|
: null;
|
|
441
436
|
if (sealedBuf) {
|
|
442
437
|
var jwk;
|