@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/parsers/safe-env.js
CHANGED
|
@@ -55,6 +55,8 @@
|
|
|
55
55
|
*/
|
|
56
56
|
|
|
57
57
|
var C = require("../constants");
|
|
58
|
+
var pick = require("../pick");
|
|
59
|
+
var boundedMap = require("../bounded-map");
|
|
58
60
|
var atomicFile = require("../atomic-file");
|
|
59
61
|
var lazyRequire = require("../lazy-require");
|
|
60
62
|
var numericBounds = require("../numeric-bounds");
|
|
@@ -96,7 +98,6 @@ var DEFAULTS = {
|
|
|
96
98
|
audit: true,
|
|
97
99
|
};
|
|
98
100
|
|
|
99
|
-
var POISONED_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
100
101
|
|
|
101
102
|
// ---- parse ----
|
|
102
103
|
|
|
@@ -153,7 +154,7 @@ function parse(input, opts) {
|
|
|
153
154
|
if (key.length === 0) {
|
|
154
155
|
throw new SafeEnvError("empty key", "env/empty-key", lineNumber);
|
|
155
156
|
}
|
|
156
|
-
if (
|
|
157
|
+
if (pick.isPoisonedKey(key)) {
|
|
157
158
|
throw new SafeEnvError("forbidden key '" + key + "'", "env/poisoned-key", lineNumber);
|
|
158
159
|
}
|
|
159
160
|
if (!keyShape.test(key)) {
|
|
@@ -162,9 +163,9 @@ function parse(input, opts) {
|
|
|
162
163
|
"env/bad-key-shape", lineNumber
|
|
163
164
|
);
|
|
164
165
|
}
|
|
165
|
-
|
|
166
|
+
boundedMap.requireAbsentMember(seen, key, function () {
|
|
166
167
|
throw new SafeEnvError("duplicate key '" + key + "'", "env/duplicate-key", lineNumber);
|
|
167
|
-
}
|
|
168
|
+
});
|
|
168
169
|
|
|
169
170
|
// Tab at start of value is almost always a paste accident
|
|
170
171
|
if (rest.charAt(0) === "\t") {
|
package/lib/parsers/safe-ini.js
CHANGED
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
38
|
var C = require("../constants");
|
|
39
|
+
var pick = require("../pick");
|
|
39
40
|
var numericBounds = require("../numeric-bounds");
|
|
40
41
|
var safeBuffer = require("../safe-buffer");
|
|
41
42
|
var { defineClass } = require("../framework-error");
|
|
@@ -51,7 +52,6 @@ var DEFAULT_MAX_SECTIONS = 500;
|
|
|
51
52
|
var DEFAULT_MAX_KEYS_SECTION = 1_000;
|
|
52
53
|
var DEFAULT_MAX_VALUE_BYTES = C.BYTES.kib(64);
|
|
53
54
|
|
|
54
|
-
var FORBIDDEN_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
55
55
|
|
|
56
56
|
var TRUE_VALUES = new Set(["true", "yes", "on"]);
|
|
57
57
|
var FALSE_VALUES = new Set(["false", "no", "off"]);
|
|
@@ -136,7 +136,7 @@ function _coerceValue(raw) {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
function _validateKey(name) {
|
|
139
|
-
if (
|
|
139
|
+
if (pick.isPoisonedKey(name)) {
|
|
140
140
|
throw _err("ini/forbidden-key", "key '" + name + "' is reserved (prototype pollution defense)");
|
|
141
141
|
}
|
|
142
142
|
}
|
|
@@ -155,7 +155,7 @@ function _ensureSection(root, sectionPath) {
|
|
|
155
155
|
}
|
|
156
156
|
node = existing;
|
|
157
157
|
} else {
|
|
158
|
-
var child =
|
|
158
|
+
var child = Object.create(null); // null-proto: see root (pollution-safe)
|
|
159
159
|
node[seg] = child;
|
|
160
160
|
node = child;
|
|
161
161
|
}
|
|
@@ -218,7 +218,13 @@ function parse(input, opts) {
|
|
|
218
218
|
"ini.parse: onDuplicate must be 'throw' | 'first' | 'last', got " + JSON.stringify(onDuplicate));
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
|
|
221
|
+
// Defense-in-depth against prototype pollution: every parsed node is a
|
|
222
|
+
// null-prototype object, so a key like __proto__ / constructor / prototype
|
|
223
|
+
// (already REFUSED by _validateKey → pick.isPoisonedKey before any write)
|
|
224
|
+
// could only ever land as an own property here, never reach Object.prototype.
|
|
225
|
+
// safe-ini's own reads use Object.prototype.hasOwnProperty.call(node, ...),
|
|
226
|
+
// so a null-proto tree is fully compatible.
|
|
227
|
+
var root = Object.create(null);
|
|
222
228
|
var currentSectionPath = [];
|
|
223
229
|
var currentSection = root;
|
|
224
230
|
var sectionCount = 0;
|
package/lib/parsers/safe-toml.js
CHANGED
|
@@ -45,6 +45,9 @@
|
|
|
45
45
|
*/
|
|
46
46
|
|
|
47
47
|
var C = require("../constants");
|
|
48
|
+
var pick = require("../pick");
|
|
49
|
+
var boundedMap = require("../bounded-map");
|
|
50
|
+
var codepointClass = require("../codepoint-class");
|
|
48
51
|
var numericBounds = require("../numeric-bounds");
|
|
49
52
|
var safeBuffer = require("../safe-buffer");
|
|
50
53
|
var { FrameworkError } = require("../framework-error");
|
|
@@ -76,7 +79,6 @@ var DEFAULTS = {
|
|
|
76
79
|
maxKeys: 50_000,
|
|
77
80
|
};
|
|
78
81
|
|
|
79
|
-
var POISONED_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
80
82
|
|
|
81
83
|
function parse(input, opts) {
|
|
82
84
|
opts = opts || {};
|
|
@@ -222,7 +224,7 @@ function parse(input, opts) {
|
|
|
222
224
|
|
|
223
225
|
function _parseDottedKey() {
|
|
224
226
|
var segments = [_parseSingleKeySegment()];
|
|
225
|
-
if (
|
|
227
|
+
if (pick.isPoisonedKey(segments[0])) {
|
|
226
228
|
throw _err("forbidden key '" + segments[0] + "'", "toml/poisoned-key");
|
|
227
229
|
}
|
|
228
230
|
while (true) {
|
|
@@ -231,7 +233,7 @@ function parse(input, opts) {
|
|
|
231
233
|
_advance();
|
|
232
234
|
_skipSpacesAndTabs();
|
|
233
235
|
var seg = _parseSingleKeySegment();
|
|
234
|
-
if (
|
|
236
|
+
if (pick.isPoisonedKey(seg)) {
|
|
235
237
|
throw _err("forbidden key '" + seg + "'", "toml/poisoned-key");
|
|
236
238
|
}
|
|
237
239
|
segments.push(seg);
|
|
@@ -305,7 +307,7 @@ function parse(input, opts) {
|
|
|
305
307
|
continue;
|
|
306
308
|
}
|
|
307
309
|
var cc = _peekCode();
|
|
308
|
-
if ((cc
|
|
310
|
+
if (codepointClass.isForbiddenControlChar(cc)) { // C0 (except TAB) + DEL refusal
|
|
309
311
|
throw _err("unescaped control char in string", "toml/bad-string");
|
|
310
312
|
}
|
|
311
313
|
_advance();
|
|
@@ -622,7 +624,7 @@ function parse(input, opts) {
|
|
|
622
624
|
var t = table;
|
|
623
625
|
for (var i = 0; i < segments.length - 1; i++) {
|
|
624
626
|
var seg = segments[i];
|
|
625
|
-
if (
|
|
627
|
+
if (pick.isPoisonedKey(seg)) throw _err("forbidden key segment", "toml/poisoned-key");
|
|
626
628
|
if (Object.prototype.hasOwnProperty.call(t, seg)) {
|
|
627
629
|
var sub = t[seg];
|
|
628
630
|
if (sub == null || typeof sub !== "object" || Array.isArray(sub)) {
|
|
@@ -639,7 +641,7 @@ function parse(input, opts) {
|
|
|
639
641
|
}
|
|
640
642
|
}
|
|
641
643
|
var last = segments[segments.length - 1];
|
|
642
|
-
if (
|
|
644
|
+
if (pick.isPoisonedKey(last)) throw _err("forbidden key segment", "toml/poisoned-key");
|
|
643
645
|
if (Object.prototype.hasOwnProperty.call(t, last)) {
|
|
644
646
|
throw _err("duplicate key '" + last + "'", "toml/duplicate-key");
|
|
645
647
|
}
|
|
@@ -665,7 +667,7 @@ function parse(input, opts) {
|
|
|
665
667
|
var t = root;
|
|
666
668
|
for (var i = 0; i < segments.length; i++) {
|
|
667
669
|
var seg = segments[i];
|
|
668
|
-
if (
|
|
670
|
+
if (pick.isPoisonedKey(seg)) throw _err("forbidden key segment", "toml/poisoned-key");
|
|
669
671
|
var isLast = (i === segments.length - 1);
|
|
670
672
|
if (Object.prototype.hasOwnProperty.call(t, seg)) {
|
|
671
673
|
var sub = t[seg];
|
|
@@ -699,9 +701,9 @@ function parse(input, opts) {
|
|
|
699
701
|
}
|
|
700
702
|
if (isLast && !isAoT) {
|
|
701
703
|
var fullPath = segments.slice(0, i + 1).join(".");
|
|
702
|
-
|
|
704
|
+
boundedMap.requireAbsentMember(definedTables, fullPath, function () {
|
|
703
705
|
throw _err("table '" + fullPath + "' defined twice", "toml/redefine");
|
|
704
|
-
}
|
|
706
|
+
});
|
|
705
707
|
definedTables.add(fullPath);
|
|
706
708
|
current = sub;
|
|
707
709
|
return;
|
package/lib/parsers/safe-xml.js
CHANGED
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
*/
|
|
49
49
|
|
|
50
50
|
var C = require("../constants");
|
|
51
|
+
var pick = require("../pick");
|
|
51
52
|
var numericBounds = require("../numeric-bounds");
|
|
52
53
|
var safeBuffer = require("../safe-buffer");
|
|
53
54
|
var { FrameworkError } = require("../framework-error");
|
|
@@ -93,7 +94,6 @@ var BUILT_IN_ENTITIES = { lt: "<", gt: ">", amp: "&", quot: "\"", apos: "'" };
|
|
|
93
94
|
// the result is always a clean key→value map. Mirrors the
|
|
94
95
|
// __proto__/constructor/prototype rejection the toml / yaml / ini
|
|
95
96
|
// parsers in this family already apply.
|
|
96
|
-
var FORBIDDEN_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
97
97
|
|
|
98
98
|
function _validateAndCap(name, value, defaultValue, ceiling) {
|
|
99
99
|
if (value === undefined) return defaultValue;
|
|
@@ -174,7 +174,7 @@ function parse(input, opts) {
|
|
|
174
174
|
}
|
|
175
175
|
out += String.fromCodePoint(code);
|
|
176
176
|
i = end + 1;
|
|
177
|
-
} else if (BUILT_IN_ENTITIES
|
|
177
|
+
} else if (Object.prototype.hasOwnProperty.call(BUILT_IN_ENTITIES, name)) {
|
|
178
178
|
out += BUILT_IN_ENTITIES[name];
|
|
179
179
|
i = end + 1;
|
|
180
180
|
} else {
|
|
@@ -199,7 +199,7 @@ function parse(input, opts) {
|
|
|
199
199
|
}
|
|
200
200
|
if (pos === start) throw _err("expected name", "xml/bad-name");
|
|
201
201
|
var parsed = input.substring(start, pos);
|
|
202
|
-
if (
|
|
202
|
+
if (pick.isPoisonedKey(parsed)) {
|
|
203
203
|
throw _err("element/attribute name '" + parsed +
|
|
204
204
|
"' is reserved (prototype-pollution defense)", "xml/forbidden-name");
|
|
205
205
|
}
|
package/lib/parsers/safe-yaml.js
CHANGED
|
@@ -53,6 +53,8 @@
|
|
|
53
53
|
*/
|
|
54
54
|
|
|
55
55
|
var C = require("../constants");
|
|
56
|
+
var pick = require("../pick");
|
|
57
|
+
var boundedMap = require("../bounded-map");
|
|
56
58
|
var numericBounds = require("../numeric-bounds");
|
|
57
59
|
var safeBuffer = require("../safe-buffer");
|
|
58
60
|
var { FrameworkError } = require("../framework-error");
|
|
@@ -85,7 +87,6 @@ var DEFAULTS = {
|
|
|
85
87
|
maxKeys: 50_000,
|
|
86
88
|
};
|
|
87
89
|
|
|
88
|
-
var POISONED_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
89
90
|
|
|
90
91
|
// YAML 1.2 core-schema scalar resolution. Order matters: null first
|
|
91
92
|
// (covers ~ and empty), then bool, then int (with base prefixes), then
|
|
@@ -333,7 +334,7 @@ function parse(input, opts) {
|
|
|
333
334
|
return _decodeSingleQuoted(raw, lineNumber, col);
|
|
334
335
|
}
|
|
335
336
|
var trimmed = safeBuffer.stripTrailingHspace(raw);
|
|
336
|
-
if (
|
|
337
|
+
if (pick.isPoisonedKey(trimmed)) {
|
|
337
338
|
throw new SafeYamlError("forbidden key '" + trimmed + "'",
|
|
338
339
|
"yaml/poisoned-key", lineNumber, col);
|
|
339
340
|
}
|
|
@@ -368,7 +369,7 @@ function parse(input, opts) {
|
|
|
368
369
|
throw new SafeYamlError("non-string mapping key not supported",
|
|
369
370
|
"yaml/bad-key", ln.lineNumber, ln.indent + 1);
|
|
370
371
|
}
|
|
371
|
-
if (
|
|
372
|
+
if (pick.isPoisonedKey(key)) {
|
|
372
373
|
throw new SafeYamlError("forbidden key '" + key + "'",
|
|
373
374
|
"yaml/poisoned-key", ln.lineNumber, ln.indent + 1);
|
|
374
375
|
}
|
|
@@ -376,10 +377,10 @@ function parse(input, opts) {
|
|
|
376
377
|
throw new SafeYamlError("merge key '<<' not supported (anchor-using feature)",
|
|
377
378
|
"yaml/merge-key-banned", ln.lineNumber, ln.indent + 1);
|
|
378
379
|
}
|
|
379
|
-
|
|
380
|
+
boundedMap.requireAbsentMember(seen, key, function () {
|
|
380
381
|
throw new SafeYamlError("duplicate mapping key '" + key + "'",
|
|
381
382
|
"yaml/duplicate-key", ln.lineNumber, ln.indent + 1);
|
|
382
|
-
}
|
|
383
|
+
});
|
|
383
384
|
seen.add(key);
|
|
384
385
|
_bumpKeys(ln.lineNumber);
|
|
385
386
|
|
|
@@ -563,7 +564,7 @@ function parse(input, opts) {
|
|
|
563
564
|
throw new SafeYamlError("non-string flow-mapping key",
|
|
564
565
|
"yaml/bad-key", lineNumber, col + p);
|
|
565
566
|
}
|
|
566
|
-
if (
|
|
567
|
+
if (pick.isPoisonedKey(key)) {
|
|
567
568
|
throw new SafeYamlError("forbidden key '" + key + "'",
|
|
568
569
|
"yaml/poisoned-key", lineNumber, col + p);
|
|
569
570
|
}
|
|
@@ -770,9 +771,27 @@ function parse(input, opts) {
|
|
|
770
771
|
}
|
|
771
772
|
|
|
772
773
|
function _stripEolComment(text) {
|
|
773
|
-
// Strip ` #...` comments (must be preceded by
|
|
774
|
-
|
|
775
|
-
|
|
774
|
+
// Strip ` #...` comments (a YAML end-of-line comment must be preceded by
|
|
775
|
+
// whitespace) via a single linear scan. The previous /^(.*?)(\s+#.*)?$/
|
|
776
|
+
// backtracks polynomially on a long inline-whitespace run with no '#'
|
|
777
|
+
// (each position re-tries `\s+#`) — a ReDoS lever on attacker-supplied
|
|
778
|
+
// YAML. This finds the first whitespace-preceded '#' and cuts the
|
|
779
|
+
// preceding whitespace run, identical output without the catastrophic
|
|
780
|
+
// backtracking.
|
|
781
|
+
for (var i = 1; i < text.length; i++) {
|
|
782
|
+
if (text.charCodeAt(i) !== 0x23 /* # */) continue;
|
|
783
|
+
var prev = text.charCodeAt(i - 1);
|
|
784
|
+
// inline whitespace: space / tab / vtab / formfeed / CR
|
|
785
|
+
if (prev !== 0x20 && prev !== 0x09 && prev !== 0x0b && prev !== 0x0c && prev !== 0x0d) continue;
|
|
786
|
+
var end = i;
|
|
787
|
+
while (end > 0) {
|
|
788
|
+
var c = text.charCodeAt(end - 1);
|
|
789
|
+
if (c === 0x20 || c === 0x09 || c === 0x0b || c === 0x0c || c === 0x0d) end--;
|
|
790
|
+
else break;
|
|
791
|
+
}
|
|
792
|
+
return safeBuffer.stripTrailingHspace(text.slice(0, end));
|
|
793
|
+
}
|
|
794
|
+
return safeBuffer.stripTrailingHspace(text);
|
|
776
795
|
}
|
|
777
796
|
|
|
778
797
|
// ---- Block scalars (| literal, > folded) ----
|
package/lib/pick.js
CHANGED
|
@@ -28,7 +28,59 @@
|
|
|
28
28
|
* ]);
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
// CORE_POISONED_KEYS — the JavaScript-language prototype-pollution VECTORS: the
|
|
32
|
+
// property names that, used as an assignment target on a plain object, reach
|
|
33
|
+
// Object.prototype ("__proto__" directly; "constructor"."prototype"
|
|
34
|
+
// transitively). This is a LANGUAGE INVARIANT, not an operator policy and not
|
|
35
|
+
// an app-specific name like a table/column — "which keys pollute the JS
|
|
36
|
+
// prototype" is fixed by the runtime, so the core is a fixed list by design.
|
|
37
|
+
// It is also add-ONLY (below): removing any one would open a pollution hole, so
|
|
38
|
+
// the safe default can only ever get stricter, never weaker.
|
|
39
|
+
var CORE_POISONED_KEYS = ["__proto__", "constructor", "prototype"];
|
|
40
|
+
var POISONED_KEY_SET = new Set(CORE_POISONED_KEYS);
|
|
41
|
+
|
|
42
|
+
// registerPoisonedKeys(keys) — defense-in-depth EXTENSION hook (CWE-1321). An
|
|
43
|
+
// operator at boot, or a framework module, may ADD further dangerous property
|
|
44
|
+
// names to block everywhere isPoisonedKey is consulted — the accessor methods
|
|
45
|
+
// "__defineGetter__" / "__defineSetter__" / "__lookupGetter__" /
|
|
46
|
+
// "__lookupSetter__", or an app's own reserved keys. Add-ONLY by design: the
|
|
47
|
+
// core vectors can never be removed, so this knob can only tighten the
|
|
48
|
+
// framework-wide pollution defense, never weaken it.
|
|
49
|
+
function registerPoisonedKeys(keys) {
|
|
50
|
+
if (!Array.isArray(keys)) {
|
|
51
|
+
throw new TypeError("pick.registerPoisonedKeys: keys must be an array of strings, got " + (typeof keys));
|
|
52
|
+
}
|
|
53
|
+
for (var i = 0; i < keys.length; i += 1) {
|
|
54
|
+
if (typeof keys[i] !== "string" || keys[i].length === 0) {
|
|
55
|
+
throw new TypeError("pick.registerPoisonedKeys: every key must be a non-empty string");
|
|
56
|
+
}
|
|
57
|
+
POISONED_KEY_SET.add(keys[i]);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// isPoisonedKey(key) — the framework's single prototype-pollution key predicate.
|
|
62
|
+
// Every parser, decoder, and middleware that builds an object from untrusted
|
|
63
|
+
// keys routes its guard through this, so the dangerous-key set lives in ONE
|
|
64
|
+
// place rather than being re-declared (a Set per file) or re-spelled (a literal
|
|
65
|
+
// `k === "__proto__" || k === "constructor" || k === "prototype"`) at each
|
|
66
|
+
// site — where one stale copy is a pollution hole. Consults the core vectors
|
|
67
|
+
// plus any operator-registered extensions. Non-string keys are never poisoned
|
|
68
|
+
// (a Map/Symbol key can't name an Object.prototype slot via assignment).
|
|
69
|
+
function isPoisonedKey(key) {
|
|
70
|
+
return typeof key === "string" && POISONED_KEY_SET.has(key);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// assertSafeKey(key, onPoisoned) — throw-guard form for callers that REJECT a
|
|
74
|
+
// poisoned key (strict parsers, schema validators) rather than silently skip
|
|
75
|
+
// it. When key is poisoned, invokes onPoisoned(key) (the caller throws its own
|
|
76
|
+
// typed error from it) and returns the result; otherwise returns undefined.
|
|
77
|
+
function assertSafeKey(key, onPoisoned) {
|
|
78
|
+
if (typeof onPoisoned !== "function") {
|
|
79
|
+
throw new TypeError("pick.assertSafeKey: onPoisoned must be a function, got " + (typeof onPoisoned));
|
|
80
|
+
}
|
|
81
|
+
if (isPoisonedKey(key)) return onPoisoned(key);
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
32
84
|
|
|
33
85
|
function _isPlainObject(o) {
|
|
34
86
|
return o !== null && typeof o === "object" && !Array.isArray(o) &&
|
|
@@ -43,11 +95,11 @@ function _normalizeAllowList(list) {
|
|
|
43
95
|
for (var i = 0; i < list.length; i += 1) {
|
|
44
96
|
var entry = list[i];
|
|
45
97
|
if (typeof entry === "string") {
|
|
46
|
-
if (
|
|
98
|
+
if (isPoisonedKey(entry)) continue;
|
|
47
99
|
out[entry] = true;
|
|
48
100
|
} else if (Array.isArray(entry) && entry.length === 2 &&
|
|
49
101
|
typeof entry[0] === "string" && Array.isArray(entry[1])) {
|
|
50
|
-
if (
|
|
102
|
+
if (isPoisonedKey(entry[0])) continue;
|
|
51
103
|
out[entry[0]] = _normalizeAllowList(entry[1]);
|
|
52
104
|
} else {
|
|
53
105
|
throw new TypeError(
|
|
@@ -66,7 +118,7 @@ function _pickInner(input, normalized, onUnknown, path) {
|
|
|
66
118
|
var keys = Object.keys(input);
|
|
67
119
|
for (var i = 0; i < keys.length; i += 1) {
|
|
68
120
|
var k = keys[i];
|
|
69
|
-
if (
|
|
121
|
+
if (isPoisonedKey(k)) continue;
|
|
70
122
|
if (!Object.prototype.hasOwnProperty.call(normalized, k)) {
|
|
71
123
|
if (onUnknown === "throw") {
|
|
72
124
|
throw new TypeError(
|
|
@@ -102,4 +154,10 @@ function pick(input, allowList, opts) {
|
|
|
102
154
|
|
|
103
155
|
module.exports = pick;
|
|
104
156
|
module.exports.pick = pick;
|
|
105
|
-
|
|
157
|
+
// POISONED_KEYS — the frozen CORE vectors (a stable snapshot for callers that
|
|
158
|
+
// need the canonical list). The live predicate isPoisonedKey() also honors
|
|
159
|
+
// operator-registered extensions; this export is the immutable language core.
|
|
160
|
+
module.exports.POISONED_KEYS = Object.freeze(CORE_POISONED_KEYS.slice());
|
|
161
|
+
module.exports.isPoisonedKey = isPoisonedKey;
|
|
162
|
+
module.exports.assertSafeKey = assertSafeKey;
|
|
163
|
+
module.exports.registerPoisonedKeys = registerPoisonedKeys;
|
package/lib/pipl-cn.js
CHANGED
|
@@ -159,43 +159,50 @@ function _requireRecordedAt(value, label) {
|
|
|
159
159
|
function sccFilingAssessment(opts) {
|
|
160
160
|
validateOpts.requireObject(opts, "b.pipl.sccFilingAssessment: opts", PiplError, "pipl/bad-opts");
|
|
161
161
|
validateOpts(opts, SCC_ASSESSMENT_ALLOWED_KEYS, "b.pipl.sccFilingAssessment");
|
|
162
|
-
validateOpts.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
"b.pipl.sccFilingAssessment: opts.
|
|
166
|
-
|
|
167
|
-
|
|
162
|
+
validateOpts.shape(opts, {
|
|
163
|
+
assessmentId: { rule: "required-string", code: "pipl/bad-assessment-id", label: "b.pipl.sccFilingAssessment: opts.assessmentId" },
|
|
164
|
+
transferType: { rule: "required-string", code: "pipl/bad-transfer-type", label: "b.pipl.sccFilingAssessment: opts.transferType" },
|
|
165
|
+
recipientJurisdiction: { rule: "required-string", code: "pipl/bad-recipient", label: "b.pipl.sccFilingAssessment: opts.recipientJurisdiction" },
|
|
166
|
+
dataCategories: function (value) {
|
|
167
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
168
|
+
throw new PiplError("pipl/bad-data-categories",
|
|
169
|
+
"b.pipl.sccFilingAssessment: opts.dataCategories must be a non-empty array of strings");
|
|
170
|
+
}
|
|
171
|
+
validateOpts.optionalNonEmptyStringArray(value,
|
|
172
|
+
"b.pipl.sccFilingAssessment: opts.dataCategories", PiplError, "pipl/bad-data-categories");
|
|
173
|
+
},
|
|
174
|
+
legalBasis: function (value) {
|
|
175
|
+
if (LEGAL_BASES.indexOf(value) === -1) {
|
|
176
|
+
throw new PiplError("pipl/bad-legal-basis",
|
|
177
|
+
"b.pipl.sccFilingAssessment: opts.legalBasis must be one of " +
|
|
178
|
+
LEGAL_BASES.join(" | ") + " (PIPL Art. 38(1)) — got " + JSON.stringify(value));
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
volume: function (value) {
|
|
182
|
+
if (typeof value !== "number" || !isFinite(value) || value < 0) {
|
|
183
|
+
throw new PiplError("pipl/bad-volume",
|
|
184
|
+
"b.pipl.sccFilingAssessment: opts.volume must be a non-negative finite number (data-subject count)");
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
sensitivePI: function (value) {
|
|
188
|
+
if (typeof value !== "boolean") {
|
|
189
|
+
throw new PiplError("pipl/bad-sensitive-pi",
|
|
190
|
+
"b.pipl.sccFilingAssessment: opts.sensitivePI must be a boolean");
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
ciio: { rule: "optional-boolean", code: "pipl/bad-ciio", label: "b.pipl.sccFilingAssessment: opts.ciio" },
|
|
194
|
+
importantData: { rule: "optional-boolean", code: "pipl/bad-important-data", label: "b.pipl.sccFilingAssessment: opts.importantData" },
|
|
195
|
+
cumulativePI: { rule: "optional-non-negative", code: "pipl/bad-cumulative-pi", label: "b.pipl.sccFilingAssessment: opts.cumulativePI" },
|
|
196
|
+
cumulativeSensitivePI: { rule: "optional-non-negative", code: "pipl/bad-cumulative-sensitive-pi", label: "b.pipl.sccFilingAssessment: opts.cumulativeSensitivePI" },
|
|
197
|
+
recordedAt: function (value) {
|
|
198
|
+
_requireRecordedAt(value, "b.pipl.sccFilingAssessment: opts.recordedAt");
|
|
199
|
+
},
|
|
200
|
+
}, "b.pipl.sccFilingAssessment: opts", PiplError, "pipl/bad-opts", { allow: ["audit"] });
|
|
168
201
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
validateOpts.optionalNonEmptyStringArray(opts.dataCategories,
|
|
174
|
-
"b.pipl.sccFilingAssessment: opts.dataCategories", PiplError, "pipl/bad-data-categories");
|
|
175
|
-
|
|
176
|
-
if (LEGAL_BASES.indexOf(opts.legalBasis) === -1) {
|
|
177
|
-
throw new PiplError("pipl/bad-legal-basis",
|
|
178
|
-
"b.pipl.sccFilingAssessment: opts.legalBasis must be one of " +
|
|
179
|
-
LEGAL_BASES.join(" | ") + " (PIPL Art. 38(1)) — got " + JSON.stringify(opts.legalBasis));
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (typeof opts.volume !== "number" || !isFinite(opts.volume) || opts.volume < 0) {
|
|
183
|
-
throw new PiplError("pipl/bad-volume",
|
|
184
|
-
"b.pipl.sccFilingAssessment: opts.volume must be a non-negative finite number (data-subject count)");
|
|
185
|
-
}
|
|
186
|
-
if (typeof opts.sensitivePI !== "boolean") {
|
|
187
|
-
throw new PiplError("pipl/bad-sensitive-pi",
|
|
188
|
-
"b.pipl.sccFilingAssessment: opts.sensitivePI must be a boolean");
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
var ciio = opts.ciio === undefined ? false
|
|
192
|
-
: validateOpts.optionalBoolean(opts.ciio, "b.pipl.sccFilingAssessment: opts.ciio", PiplError, "pipl/bad-ciio");
|
|
193
|
-
var importantData = opts.importantData === undefined ? false
|
|
194
|
-
: validateOpts.optionalBoolean(opts.importantData, "b.pipl.sccFilingAssessment: opts.importantData", PiplError, "pipl/bad-important-data");
|
|
195
|
-
var cumulativePI = opts.cumulativePI === undefined ? 0
|
|
196
|
-
: validateOpts.optionalFiniteNonNegative(opts.cumulativePI, "b.pipl.sccFilingAssessment: opts.cumulativePI", PiplError, "pipl/bad-cumulative-pi");
|
|
197
|
-
var cumulativeSensitivePI = opts.cumulativeSensitivePI === undefined ? 0
|
|
198
|
-
: validateOpts.optionalFiniteNonNegative(opts.cumulativeSensitivePI, "b.pipl.sccFilingAssessment: opts.cumulativeSensitivePI", PiplError, "pipl/bad-cumulative-sensitive-pi");
|
|
202
|
+
var ciio = opts.ciio === undefined ? false : opts.ciio;
|
|
203
|
+
var importantData = opts.importantData === undefined ? false : opts.importantData;
|
|
204
|
+
var cumulativePI = opts.cumulativePI === undefined ? 0 : opts.cumulativePI;
|
|
205
|
+
var cumulativeSensitivePI = opts.cumulativeSensitivePI === undefined ? 0 : opts.cumulativeSensitivePI;
|
|
199
206
|
|
|
200
207
|
var recordedAt = _requireRecordedAt(opts.recordedAt, "b.pipl.sccFilingAssessment: opts.recordedAt");
|
|
201
208
|
// Resolve + shape-validate the audit sink at the entry-point tier (THROWS
|
|
@@ -306,30 +313,33 @@ function sccFilingAssessment(opts) {
|
|
|
306
313
|
function securityAssessmentCertificate(opts) {
|
|
307
314
|
validateOpts.requireObject(opts, "b.pipl.securityAssessmentCertificate: opts", PiplError, "pipl/bad-opts");
|
|
308
315
|
validateOpts(opts, SECURITY_CERT_ALLOWED_KEYS, "b.pipl.securityAssessmentCertificate");
|
|
309
|
-
validateOpts.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
"b.pipl.securityAssessmentCertificate: opts.
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
"b.pipl.securityAssessmentCertificate: opts.
|
|
316
|
+
validateOpts.shape(opts, {
|
|
317
|
+
certId: { rule: "required-string", code: "pipl/bad-cert-id", label: "b.pipl.securityAssessmentCertificate: opts.certId" },
|
|
318
|
+
assessmentScope: { rule: "required-string", code: "pipl/bad-scope", label: "b.pipl.securityAssessmentCertificate: opts.assessmentScope" },
|
|
319
|
+
dataExporter: { rule: "required-string", code: "pipl/bad-exporter", label: "b.pipl.securityAssessmentCertificate: opts.dataExporter" },
|
|
320
|
+
overseasRecipient: { rule: "required-string", code: "pipl/bad-recipient", label: "b.pipl.securityAssessmentCertificate: opts.overseasRecipient" },
|
|
321
|
+
riskRating: function (value) {
|
|
322
|
+
if (RISK_RATINGS.indexOf(value) === -1) {
|
|
323
|
+
throw new PiplError("pipl/bad-risk-rating",
|
|
324
|
+
"b.pipl.securityAssessmentCertificate: opts.riskRating must be one of " +
|
|
325
|
+
RISK_RATINGS.join(" | ") + " — got " + JSON.stringify(value));
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
safeguards: function (value) {
|
|
329
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
330
|
+
throw new PiplError("pipl/bad-safeguards",
|
|
331
|
+
"b.pipl.securityAssessmentCertificate: opts.safeguards must be a non-empty array of strings");
|
|
332
|
+
}
|
|
333
|
+
validateOpts.optionalNonEmptyStringArray(value,
|
|
334
|
+
"b.pipl.securityAssessmentCertificate: opts.safeguards", PiplError, "pipl/bad-safeguards");
|
|
335
|
+
},
|
|
336
|
+
filingRef: { rule: "optional-string", code: "pipl/bad-filing-ref", label: "b.pipl.securityAssessmentCertificate: opts.filingRef" },
|
|
337
|
+
recordedAt: function (value) {
|
|
338
|
+
_requireRecordedAt(value, "b.pipl.securityAssessmentCertificate: opts.recordedAt");
|
|
339
|
+
},
|
|
340
|
+
}, "b.pipl.securityAssessmentCertificate: opts", PiplError, "pipl/bad-opts", { allow: ["audit"] });
|
|
330
341
|
|
|
331
|
-
var filingRef =
|
|
332
|
-
"b.pipl.securityAssessmentCertificate: opts.filingRef", PiplError, "pipl/bad-filing-ref");
|
|
342
|
+
var filingRef = opts.filingRef;
|
|
333
343
|
|
|
334
344
|
var recordedAt = _requireRecordedAt(opts.recordedAt, "b.pipl.securityAssessmentCertificate: opts.recordedAt");
|
|
335
345
|
// Entry-point shape-validate the audit sink (THROWS) before the drop-silent
|
package/lib/privacy-pass.js
CHANGED
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
|
|
37
37
|
var nodeCrypto = require("node:crypto");
|
|
38
38
|
var bCrypto = require("./crypto");
|
|
39
|
+
var safeBuffer = require("./safe-buffer");
|
|
39
40
|
var validateOpts = require("./validate-opts");
|
|
40
41
|
var { defineClass } = require("./framework-error");
|
|
41
42
|
|
|
@@ -58,12 +59,13 @@ function _b64urlPadded(buf) {
|
|
|
58
59
|
return s;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
var _bytes = safeBuffer.makeByteCoercer({
|
|
63
|
+
errorClass: PrivacyPassError,
|
|
64
|
+
typeCode: "privacy-pass/bad-bytes",
|
|
65
|
+
messagePrefix: "privacyPass: ",
|
|
66
|
+
messageSuffix: " must be a Buffer / Uint8Array / base64 string",
|
|
67
|
+
encoding: "base64",
|
|
68
|
+
});
|
|
67
69
|
|
|
68
70
|
// Import the issuer public key and capture the SubjectPublicKeyInfo
|
|
69
71
|
// bytes used to derive token_key_id. When the caller supplies the
|
package/lib/problem-details.js
CHANGED
|
@@ -378,11 +378,8 @@ function fromError(err, opts2) {
|
|
|
378
378
|
* // res.statusCode: 400
|
|
379
379
|
*/
|
|
380
380
|
function respond(res, problem, req) {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
throw new ProblemDetailsError("problem-details/bad-res",
|
|
384
|
-
"respond: res must be an HTTP response object (setHeader + end)", true);
|
|
385
|
-
}
|
|
381
|
+
validateOpts.requireMethods(res, ["setHeader", "end"],
|
|
382
|
+
"respond: res (HTTP response object)", ProblemDetailsError, "problem-details/bad-res", true);
|
|
386
383
|
if (!problem || typeof problem !== "object" || Array.isArray(problem)) {
|
|
387
384
|
throw new ProblemDetailsError("problem-details/bad-problem",
|
|
388
385
|
"respond: problem must be a non-null object", true);
|
package/lib/pubsub.js
CHANGED
|
@@ -41,6 +41,7 @@ var C = require("./constants");
|
|
|
41
41
|
var lazyRequire = require("./lazy-require");
|
|
42
42
|
var safeJson = require("./safe-json");
|
|
43
43
|
var validateOpts = require("./validate-opts");
|
|
44
|
+
var boundedMap = require("./bounded-map");
|
|
44
45
|
var { defineClass } = require("./framework-error");
|
|
45
46
|
|
|
46
47
|
var audit = lazyRequire(function () { return require("./audit"); });
|
|
@@ -58,12 +59,8 @@ function _err(code, message) { return new PubsubError(code, message, true); }
|
|
|
58
59
|
function _resolveBackend(opts) {
|
|
59
60
|
var requested = opts.backend;
|
|
60
61
|
if (requested && typeof requested === "object") {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
typeof requested.stop !== "function") {
|
|
64
|
-
throw _err("BAD_BACKEND",
|
|
65
|
-
"pubsub: custom backend must implement { publishRemote, start, stop }");
|
|
66
|
-
}
|
|
62
|
+
validateOpts.requireMethods(requested, ["publishRemote", "start", "stop"],
|
|
63
|
+
"pubsub: custom backend", PubsubError, "BAD_BACKEND", true);
|
|
67
64
|
return Object.assign({ name: "custom" }, requested);
|
|
68
65
|
}
|
|
69
66
|
if (!requested || requested === "local") {
|
|
@@ -347,8 +344,7 @@ function create(opts) {
|
|
|
347
344
|
throw _err("BAD_OPT", "pubsub.subscribe: handler must be a function");
|
|
348
345
|
}
|
|
349
346
|
var rec = { channel: channel, handler: handler, isPattern: false };
|
|
350
|
-
var set =
|
|
351
|
-
if (!set) { set = new Set(); exactSubs.set(channel, set); }
|
|
347
|
+
var set = boundedMap.getOrInsert(exactSubs, channel, function () { return new Set(); });
|
|
352
348
|
set.add(rec);
|
|
353
349
|
// Remote subscribe is fire-and-forget from the caller's perspective;
|
|
354
350
|
// the redis backend awaits the SUBSCRIBE ack internally before its
|
package/lib/queue-local.js
CHANGED
|
@@ -406,7 +406,13 @@ function create(config) {
|
|
|
406
406
|
.where("_id", jobId)
|
|
407
407
|
.where("status", "inflight")
|
|
408
408
|
.toSql();
|
|
409
|
-
await store.execute(doneBuilt.sql, doneBuilt.params);
|
|
409
|
+
var doneRes = await store.execute(doneBuilt.sql, doneBuilt.params);
|
|
410
|
+
// Only run the post-completion side effects if THIS call actually flipped
|
|
411
|
+
// the row inflight→done. If the status guard matched 0 rows the job was
|
|
412
|
+
// already completed or re-leased to another worker (its lease expired and
|
|
413
|
+
// sweepExpired re-queued it) — a stale completer must NOT re-enqueue the
|
|
414
|
+
// cron repeat (duplicate firing) or release flow children twice.
|
|
415
|
+
if ((doneRes.rowCount || 0) === 0) return false;
|
|
410
416
|
|
|
411
417
|
// Repeat-in-queue: cron-recurring job re-enqueues itself for the
|
|
412
418
|
// next firing time. Failures (which take the fail() path) don't
|
|
@@ -513,9 +519,10 @@ function create(config) {
|
|
|
513
519
|
[nowMs + retryDelayMs])
|
|
514
520
|
.setRaw("finishedAt", "CASE WHEN " + attemptsLt + " THEN NULL ELSE ? END", [nowMs])
|
|
515
521
|
.where("_id", jobId)
|
|
522
|
+
.where("status", "inflight") // lease-ownership guard — a stale fail() must not clobber a job re-leased to another worker after this one's lease expired (mirrors complete()/extendLease)
|
|
516
523
|
.toSql();
|
|
517
|
-
await store.execute(failBuilt.sql, failBuilt.params);
|
|
518
|
-
return
|
|
524
|
+
var failRes = await store.execute(failBuilt.sql, failBuilt.params);
|
|
525
|
+
return (failRes.rowCount || 0) > 0;
|
|
519
526
|
}
|
|
520
527
|
|
|
521
528
|
async function sweepExpired() {
|