@blamejs/blamejs-shop 0.4.56 → 0.4.58
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/lib/affiliates.js +35 -4
- package/lib/api-keys.js +17 -2
- package/lib/asset-manifest.json +1 -1
- package/lib/backorder.js +21 -4
- package/lib/click-and-collect.js +11 -2
- package/lib/credit-limits.js +132 -84
- package/lib/vendor/MANIFEST.json +426 -366
- package/lib/vendor/blamejs/.github/codeql/codeql-config.yml +25 -0
- package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +1 -1
- package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +1 -1
- package/lib/vendor/blamejs/.github/workflows/ci.yml +13 -13
- package/lib/vendor/blamejs/.github/workflows/codeql.yml +8 -7
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +2 -2
- package/lib/vendor/blamejs/.github/workflows/release-container.yml +4 -4
- package/lib/vendor/blamejs/.github/workflows/scorecard.yml +1 -1
- package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
- package/lib/vendor/blamejs/CHANGELOG.md +2 -0
- package/lib/vendor/blamejs/api-snapshot.json +1381 -4
- package/lib/vendor/blamejs/eslint.config.mjs +1 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +4 -1
- package/lib/vendor/blamejs/examples/wiki/lib/symbol-index.js +5 -2
- package/lib/vendor/blamejs/examples/wiki/routes/pages.js +4 -1
- package/lib/vendor/blamejs/fuzz/guard-text.fuzz.js +20 -0
- package/lib/vendor/blamejs/index.js +2 -0
- package/lib/vendor/blamejs/lib/a2a-tasks.js +7 -23
- package/lib/vendor/blamejs/lib/acme.js +6 -5
- package/lib/vendor/blamejs/lib/agent-event-bus.js +5 -4
- package/lib/vendor/blamejs/lib/agent-idempotency.js +2 -5
- package/lib/vendor/blamejs/lib/agent-orchestrator.js +2 -5
- package/lib/vendor/blamejs/lib/agent-saga.js +3 -5
- package/lib/vendor/blamejs/lib/agent-tenant.js +2 -5
- package/lib/vendor/blamejs/lib/ai-adverse-decision.js +2 -15
- package/lib/vendor/blamejs/lib/ai-capability.js +1 -6
- package/lib/vendor/blamejs/lib/ai-dp.js +1 -5
- package/lib/vendor/blamejs/lib/ai-input.js +2 -2
- package/lib/vendor/blamejs/lib/ai-pref.js +3 -8
- package/lib/vendor/blamejs/lib/ai-quota.js +3 -14
- package/lib/vendor/blamejs/lib/api-key.js +37 -28
- package/lib/vendor/blamejs/lib/archive-adapters.js +2 -4
- package/lib/vendor/blamejs/lib/archive-entry-policy.js +32 -0
- package/lib/vendor/blamejs/lib/archive-read.js +5 -17
- package/lib/vendor/blamejs/lib/archive-tar-read.js +5 -16
- package/lib/vendor/blamejs/lib/archive.js +2 -10
- package/lib/vendor/blamejs/lib/arg-parser.js +7 -6
- package/lib/vendor/blamejs/lib/asyncapi-traits.js +2 -6
- package/lib/vendor/blamejs/lib/atomic-file.js +108 -31
- package/lib/vendor/blamejs/lib/audit-chain.js +133 -53
- package/lib/vendor/blamejs/lib/audit-daily-review.js +24 -14
- package/lib/vendor/blamejs/lib/audit-emit.js +82 -0
- package/lib/vendor/blamejs/lib/audit-sign.js +257 -0
- package/lib/vendor/blamejs/lib/audit.js +84 -0
- package/lib/vendor/blamejs/lib/auth/access-lock.js +5 -27
- package/lib/vendor/blamejs/lib/auth/dpop.js +23 -35
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +9 -15
- package/lib/vendor/blamejs/lib/auth/jwt-external.js +26 -8
- package/lib/vendor/blamejs/lib/auth/jwt.js +13 -15
- package/lib/vendor/blamejs/lib/auth/lockout.js +6 -25
- package/lib/vendor/blamejs/lib/auth/oauth.js +67 -45
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +55 -32
- package/lib/vendor/blamejs/lib/auth/oid4vp.js +3 -2
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +6 -6
- package/lib/vendor/blamejs/lib/auth/passkey.js +3 -3
- package/lib/vendor/blamejs/lib/auth/password.js +7 -1
- package/lib/vendor/blamejs/lib/auth/saml.js +37 -27
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +2 -14
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-issuer.js +2 -14
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +1 -1
- package/lib/vendor/blamejs/lib/auth/status-list.js +7 -7
- package/lib/vendor/blamejs/lib/auth/step-up.js +6 -12
- package/lib/vendor/blamejs/lib/auth-bot-challenge.js +6 -37
- package/lib/vendor/blamejs/lib/backup/bundle.js +11 -18
- package/lib/vendor/blamejs/lib/backup/index.js +14 -47
- package/lib/vendor/blamejs/lib/bounded-map.js +112 -1
- package/lib/vendor/blamejs/lib/breach-deadline.js +1 -11
- package/lib/vendor/blamejs/lib/cache.js +7 -18
- package/lib/vendor/blamejs/lib/cbor.js +2 -1
- package/lib/vendor/blamejs/lib/cdn-cache-control.js +8 -9
- package/lib/vendor/blamejs/lib/cert.js +3 -10
- package/lib/vendor/blamejs/lib/chain-writer.js +162 -47
- package/lib/vendor/blamejs/lib/cli.js +5 -1
- package/lib/vendor/blamejs/lib/client-hints.js +7 -9
- package/lib/vendor/blamejs/lib/cloud-events.js +40 -31
- package/lib/vendor/blamejs/lib/cluster-storage.js +2 -38
- package/lib/vendor/blamejs/lib/cms-codec.js +2 -1
- package/lib/vendor/blamejs/lib/codepoint-class.js +67 -1
- package/lib/vendor/blamejs/lib/compliance-ai-act-logging.js +1 -6
- package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +2 -4
- package/lib/vendor/blamejs/lib/compliance-eaa.js +1 -11
- package/lib/vendor/blamejs/lib/compliance-sanctions-fetcher.js +21 -28
- package/lib/vendor/blamejs/lib/compliance-sanctions.js +2 -14
- package/lib/vendor/blamejs/lib/compliance.js +2 -9
- package/lib/vendor/blamejs/lib/config-drift.js +2 -12
- package/lib/vendor/blamejs/lib/content-digest.js +10 -8
- package/lib/vendor/blamejs/lib/cookies.js +5 -11
- package/lib/vendor/blamejs/lib/cose.js +19 -11
- package/lib/vendor/blamejs/lib/cra-report.js +1 -11
- package/lib/vendor/blamejs/lib/crypto-field.js +5 -10
- package/lib/vendor/blamejs/lib/crypto.js +120 -3
- package/lib/vendor/blamejs/lib/csp.js +235 -3
- package/lib/vendor/blamejs/lib/daemon.js +42 -41
- package/lib/vendor/blamejs/lib/data-act.js +19 -9
- package/lib/vendor/blamejs/lib/db-query.js +6 -40
- package/lib/vendor/blamejs/lib/db.js +34 -12
- package/lib/vendor/blamejs/lib/dbsc.js +5 -6
- package/lib/vendor/blamejs/lib/ddl-change-control.js +18 -14
- package/lib/vendor/blamejs/lib/deprecate.js +4 -5
- package/lib/vendor/blamejs/lib/did.js +6 -2
- package/lib/vendor/blamejs/lib/dsr.js +8 -12
- package/lib/vendor/blamejs/lib/external-db-migrate.js +21 -22
- package/lib/vendor/blamejs/lib/external-db.js +14 -26
- package/lib/vendor/blamejs/lib/fda-21cfr11.js +12 -8
- package/lib/vendor/blamejs/lib/fdx.js +22 -18
- package/lib/vendor/blamejs/lib/file-upload.js +80 -66
- package/lib/vendor/blamejs/lib/flag-evaluation-context.js +5 -8
- package/lib/vendor/blamejs/lib/framework-error.js +12 -0
- package/lib/vendor/blamejs/lib/framework-schema.js +19 -0
- package/lib/vendor/blamejs/lib/fsm.js +7 -12
- package/lib/vendor/blamejs/lib/gate-contract.js +869 -38
- package/lib/vendor/blamejs/lib/gdpr-ropa.js +4 -13
- package/lib/vendor/blamejs/lib/graphql-federation.js +1 -1
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +2 -1
- package/lib/vendor/blamejs/lib/guard-all.js +1 -0
- package/lib/vendor/blamejs/lib/guard-archive.js +9 -30
- package/lib/vendor/blamejs/lib/guard-auth.js +23 -80
- package/lib/vendor/blamejs/lib/guard-cidr.js +20 -96
- package/lib/vendor/blamejs/lib/guard-csv.js +135 -196
- package/lib/vendor/blamejs/lib/guard-domain.js +23 -106
- package/lib/vendor/blamejs/lib/guard-dsn.js +16 -13
- package/lib/vendor/blamejs/lib/guard-email.js +46 -53
- package/lib/vendor/blamejs/lib/guard-envelope.js +1 -1
- package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +2 -1
- package/lib/vendor/blamejs/lib/guard-filename.js +12 -60
- package/lib/vendor/blamejs/lib/guard-graphql.js +28 -75
- package/lib/vendor/blamejs/lib/guard-html-wcag.js +15 -2
- package/lib/vendor/blamejs/lib/guard-html.js +65 -117
- package/lib/vendor/blamejs/lib/guard-idempotency-key.js +2 -1
- package/lib/vendor/blamejs/lib/guard-image.js +280 -77
- package/lib/vendor/blamejs/lib/guard-imap-command.js +8 -9
- package/lib/vendor/blamejs/lib/guard-json.js +87 -103
- package/lib/vendor/blamejs/lib/guard-jsonpath.js +20 -88
- package/lib/vendor/blamejs/lib/guard-jwt.js +32 -114
- package/lib/vendor/blamejs/lib/guard-list-id.js +2 -7
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -7
- package/lib/vendor/blamejs/lib/guard-mail-compose.js +5 -6
- package/lib/vendor/blamejs/lib/guard-mail-move.js +2 -1
- package/lib/vendor/blamejs/lib/guard-mail-query.js +5 -3
- package/lib/vendor/blamejs/lib/guard-mail-sieve.js +6 -7
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +5 -4
- package/lib/vendor/blamejs/lib/guard-markdown.js +76 -110
- package/lib/vendor/blamejs/lib/guard-message-id.js +5 -6
- package/lib/vendor/blamejs/lib/guard-mime.js +20 -99
- package/lib/vendor/blamejs/lib/guard-oauth.js +19 -73
- package/lib/vendor/blamejs/lib/guard-pdf.js +65 -72
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +12 -13
- package/lib/vendor/blamejs/lib/guard-posture-chain.js +2 -1
- package/lib/vendor/blamejs/lib/guard-regex.js +24 -99
- package/lib/vendor/blamejs/lib/guard-saga-config.js +2 -1
- package/lib/vendor/blamejs/lib/guard-shell.js +22 -87
- package/lib/vendor/blamejs/lib/guard-smtp-command.js +8 -11
- package/lib/vendor/blamejs/lib/guard-sql.js +15 -13
- package/lib/vendor/blamejs/lib/guard-stream-args.js +2 -1
- package/lib/vendor/blamejs/lib/guard-svg.js +95 -140
- package/lib/vendor/blamejs/lib/guard-template.js +23 -80
- package/lib/vendor/blamejs/lib/guard-tenant-id.js +2 -1
- package/lib/vendor/blamejs/lib/guard-text.js +592 -0
- package/lib/vendor/blamejs/lib/guard-time.js +27 -95
- package/lib/vendor/blamejs/lib/guard-uuid.js +21 -93
- package/lib/vendor/blamejs/lib/guard-xml.js +76 -106
- package/lib/vendor/blamejs/lib/guard-yaml.js +24 -60
- package/lib/vendor/blamejs/lib/http-client-cache.js +5 -12
- package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +2 -4
- package/lib/vendor/blamejs/lib/http-client.js +8 -21
- package/lib/vendor/blamejs/lib/http-message-signature.js +3 -2
- package/lib/vendor/blamejs/lib/i18n-messageformat.js +5 -7
- package/lib/vendor/blamejs/lib/i18n.js +83 -26
- package/lib/vendor/blamejs/lib/inbox.js +8 -8
- package/lib/vendor/blamejs/lib/incident-report.js +3 -21
- package/lib/vendor/blamejs/lib/ip-utils.js +49 -6
- package/lib/vendor/blamejs/lib/jobs.js +3 -2
- package/lib/vendor/blamejs/lib/keychain.js +6 -18
- package/lib/vendor/blamejs/lib/legal-hold.js +6 -15
- package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +44 -112
- package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +17 -14
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +16 -80
- package/lib/vendor/blamejs/lib/log-stream-webhook.js +20 -92
- package/lib/vendor/blamejs/lib/mail-arc-sign.js +8 -3
- package/lib/vendor/blamejs/lib/mail-arf.js +3 -2
- package/lib/vendor/blamejs/lib/mail-auth.js +40 -66
- package/lib/vendor/blamejs/lib/mail-bimi.js +19 -39
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +3 -2
- package/lib/vendor/blamejs/lib/mail-dav.js +8 -35
- package/lib/vendor/blamejs/lib/mail-deploy.js +6 -9
- package/lib/vendor/blamejs/lib/mail-dkim.js +19 -38
- package/lib/vendor/blamejs/lib/mail-greylist.js +15 -26
- package/lib/vendor/blamejs/lib/mail-helo.js +2 -3
- package/lib/vendor/blamejs/lib/mail-journal.js +2 -1
- package/lib/vendor/blamejs/lib/mail-mdn.js +4 -3
- package/lib/vendor/blamejs/lib/mail-rbl.js +5 -8
- package/lib/vendor/blamejs/lib/mail-scan.js +2 -2
- package/lib/vendor/blamejs/lib/mail-send-deliver.js +33 -20
- package/lib/vendor/blamejs/lib/mail-server-imap.js +32 -87
- package/lib/vendor/blamejs/lib/mail-server-jmap.js +35 -51
- package/lib/vendor/blamejs/lib/mail-server-managesieve.js +29 -83
- package/lib/vendor/blamejs/lib/mail-server-mx.js +33 -74
- package/lib/vendor/blamejs/lib/mail-server-net.js +177 -0
- package/lib/vendor/blamejs/lib/mail-server-pop3.js +30 -83
- package/lib/vendor/blamejs/lib/mail-server-rate-limit.js +30 -6
- package/lib/vendor/blamejs/lib/mail-server-submission.js +34 -73
- package/lib/vendor/blamejs/lib/mail-server-tls.js +89 -0
- package/lib/vendor/blamejs/lib/mail-spam-score.js +7 -8
- package/lib/vendor/blamejs/lib/mail-store.js +3 -2
- package/lib/vendor/blamejs/lib/mail.js +6 -11
- package/lib/vendor/blamejs/lib/markup-escape.js +31 -0
- package/lib/vendor/blamejs/lib/markup-tokenizer.js +54 -0
- package/lib/vendor/blamejs/lib/mcp-tool-registry.js +26 -23
- package/lib/vendor/blamejs/lib/mcp.js +1 -1
- package/lib/vendor/blamejs/lib/mdoc.js +11 -12
- package/lib/vendor/blamejs/lib/metrics.js +32 -30
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +3 -23
- package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +11 -22
- package/lib/vendor/blamejs/lib/middleware/assetlinks.js +2 -7
- package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +31 -48
- package/lib/vendor/blamejs/lib/middleware/bot-disclose.js +7 -10
- package/lib/vendor/blamejs/lib/middleware/bot-guard.js +2 -10
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +13 -2
- package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +6 -26
- package/lib/vendor/blamejs/lib/middleware/deny-response.js +19 -1
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +7 -0
- package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +4 -20
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +20 -28
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/security-headers.js +9 -1
- package/lib/vendor/blamejs/lib/middleware/security-txt.js +2 -6
- package/lib/vendor/blamejs/lib/middleware/tus-upload.js +12 -27
- package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +2 -7
- package/lib/vendor/blamejs/lib/migrations.js +4 -13
- package/lib/vendor/blamejs/lib/mime-parse.js +34 -17
- package/lib/vendor/blamejs/lib/module-loader.js +44 -0
- package/lib/vendor/blamejs/lib/money.js +105 -0
- package/lib/vendor/blamejs/lib/mtls-ca.js +116 -36
- package/lib/vendor/blamejs/lib/network-byte-quota.js +4 -18
- package/lib/vendor/blamejs/lib/network-dane.js +8 -6
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +97 -6
- package/lib/vendor/blamejs/lib/network-dnssec.js +16 -16
- package/lib/vendor/blamejs/lib/network-heartbeat.js +3 -2
- package/lib/vendor/blamejs/lib/network-smtp-policy.js +29 -41
- package/lib/vendor/blamejs/lib/network-tls.js +40 -42
- package/lib/vendor/blamejs/lib/nis2-report.js +1 -11
- package/lib/vendor/blamejs/lib/nonce-store.js +81 -3
- package/lib/vendor/blamejs/lib/numeric-bounds.js +22 -8
- package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +2 -6
- package/lib/vendor/blamejs/lib/object-store/azure-blob.js +5 -45
- package/lib/vendor/blamejs/lib/object-store/gcs.js +8 -71
- package/lib/vendor/blamejs/lib/object-store/http-put.js +1 -5
- package/lib/vendor/blamejs/lib/object-store/http-request.js +128 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +2 -1
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +9 -77
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -25
- package/lib/vendor/blamejs/lib/observability.js +95 -0
- package/lib/vendor/blamejs/lib/openapi-paths-builder.js +7 -3
- package/lib/vendor/blamejs/lib/otel-export.js +7 -10
- package/lib/vendor/blamejs/lib/outbox.js +43 -37
- package/lib/vendor/blamejs/lib/pagination.js +11 -15
- package/lib/vendor/blamejs/lib/parsers/safe-env.js +5 -4
- package/lib/vendor/blamejs/lib/parsers/safe-ini.js +10 -4
- package/lib/vendor/blamejs/lib/parsers/safe-toml.js +11 -9
- package/lib/vendor/blamejs/lib/parsers/safe-xml.js +2 -2
- package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +7 -6
- package/lib/vendor/blamejs/lib/pick.js +63 -5
- package/lib/vendor/blamejs/lib/pipl-cn.js +69 -59
- package/lib/vendor/blamejs/lib/privacy-pass.js +8 -6
- package/lib/vendor/blamejs/lib/problem-details.js +2 -5
- package/lib/vendor/blamejs/lib/pubsub.js +4 -8
- package/lib/vendor/blamejs/lib/redact.js +2 -1
- package/lib/vendor/blamejs/lib/render.js +4 -2
- package/lib/vendor/blamejs/lib/request-helpers.js +133 -6
- package/lib/vendor/blamejs/lib/restore.js +5 -22
- package/lib/vendor/blamejs/lib/retention.js +3 -5
- package/lib/vendor/blamejs/lib/safe-async.js +457 -0
- package/lib/vendor/blamejs/lib/safe-buffer.js +137 -6
- package/lib/vendor/blamejs/lib/safe-decompress.js +2 -1
- package/lib/vendor/blamejs/lib/safe-dns.js +2 -1
- package/lib/vendor/blamejs/lib/safe-ical.js +12 -26
- package/lib/vendor/blamejs/lib/safe-json.js +7 -8
- package/lib/vendor/blamejs/lib/safe-jsonpath.js +6 -5
- package/lib/vendor/blamejs/lib/safe-mime.js +25 -29
- package/lib/vendor/blamejs/lib/safe-redirect.js +2 -5
- package/lib/vendor/blamejs/lib/safe-schema.js +7 -6
- package/lib/vendor/blamejs/lib/safe-sql.js +126 -0
- package/lib/vendor/blamejs/lib/safe-vcard.js +12 -26
- package/lib/vendor/blamejs/lib/sandbox-worker.js +9 -2
- package/lib/vendor/blamejs/lib/sandbox.js +3 -2
- package/lib/vendor/blamejs/lib/scheduler.js +5 -12
- package/lib/vendor/blamejs/lib/sec-cyber.js +82 -37
- package/lib/vendor/blamejs/lib/seeders.js +4 -11
- package/lib/vendor/blamejs/lib/self-update.js +92 -69
- package/lib/vendor/blamejs/lib/session-device-binding.js +112 -66
- package/lib/vendor/blamejs/lib/session.js +194 -6
- package/lib/vendor/blamejs/lib/sql.js +225 -78
- package/lib/vendor/blamejs/lib/sse.js +6 -10
- package/lib/vendor/blamejs/lib/static.js +136 -98
- package/lib/vendor/blamejs/lib/storage.js +4 -2
- package/lib/vendor/blamejs/lib/structured-fields.js +275 -16
- package/lib/vendor/blamejs/lib/tenant-quota.js +2 -20
- package/lib/vendor/blamejs/lib/tsa.js +11 -15
- package/lib/vendor/blamejs/lib/validate-opts.js +154 -8
- package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +30 -48
- package/lib/vendor/blamejs/lib/vault-aad.js +3 -2
- package/lib/vendor/blamejs/lib/vc.js +2 -7
- package/lib/vendor/blamejs/lib/vex.js +35 -13
- package/lib/vendor/blamejs/lib/web-push-vapid.js +23 -20
- package/lib/vendor/blamejs/lib/webhook-dispatcher.js +706 -0
- package/lib/vendor/blamejs/lib/webhook.js +43 -18
- package/lib/vendor/blamejs/lib/websocket-channels.js +9 -7
- package/lib/vendor/blamejs/lib/websocket.js +7 -3
- package/lib/vendor/blamejs/lib/worm.js +2 -3
- package/lib/vendor/blamejs/lib/ws-client.js +8 -10
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.15.13.json +81 -0
- package/lib/vendor/blamejs/scripts/check-changelog-extract.js +1 -1
- package/lib/vendor/blamejs/test/00-primitives.js +136 -7
- package/lib/vendor/blamejs/test/10-state.js +9 -3
- package/lib/vendor/blamejs/test/30-chain.js +40 -0
- package/lib/vendor/blamejs/test/helpers/check.js +18 -0
- package/lib/vendor/blamejs/test/helpers/db.js +4 -0
- package/lib/vendor/blamejs/test/helpers/index.js +1 -0
- package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +2 -1
- package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +2 -1
- package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +8 -1
- package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +1 -1
- package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +2 -1
- package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +269 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-fd-read.test.js +149 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-framework-namespaces.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +88 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-use-store.test.js +55 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-object-store-adapter.test.js +2 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/bot-guard.test.js +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/bounded-map.test.js +129 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/chain-writer-multichain.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-api-key.test.js +12 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +2788 -3214
- package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-base64url.test.js +63 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +2 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-builder.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-nonce.test.js +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +2 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-resolve-opts.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +9 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract-content-gate.test.js +290 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +84 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-email.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +23 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-gate-disposition-coverage.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +60 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +184 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +54 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +10 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +45 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +101 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-text.test.js +365 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-xml.test.js +35 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-yaml.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +20 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-arf.test.js +10 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +39 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-greylist.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-tls.test.js +39 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mime-parse.test.js +106 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/money.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-revocation.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-release.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-memory-getorinsert.test.js +100 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +88 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-loops.test.js +278 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +37 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-jsonpath.test.js +14 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +19 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +2 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/session-valid-from.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +100 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/validate-opts-shape.test.js +235 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +374 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +75 -8
- package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +3 -3
- package/package.json +1 -1
|
@@ -14,7 +14,9 @@ var C = require("./constants");
|
|
|
14
14
|
var lazyRequire = require("./lazy-require");
|
|
15
15
|
var safeBuffer = require("./safe-buffer");
|
|
16
16
|
var archiveTar = require("./archive-tar");
|
|
17
|
+
var archiveEntryPolicy = require("./archive-entry-policy");
|
|
17
18
|
var atomicFile = require("./atomic-file");
|
|
19
|
+
var auditEmit = require("./audit-emit");
|
|
18
20
|
|
|
19
21
|
var TarError = archiveTar.TarError;
|
|
20
22
|
var _parseHeader = archiveTar._parseHeader;
|
|
@@ -45,29 +47,16 @@ var DEFAULT_BOMB_POLICY = Object.freeze({
|
|
|
45
47
|
maxExpansionRatio: 100, // tar has no compression-ratio concept, but keep field for orchestrator policy parity
|
|
46
48
|
});
|
|
47
49
|
|
|
48
|
-
var DEFAULT_ENTRY_TYPE_POLICY =
|
|
49
|
-
symlinks: false,
|
|
50
|
-
hardlinks: false,
|
|
51
|
-
devices: false,
|
|
52
|
-
fifos: false,
|
|
53
|
-
sockets: false,
|
|
54
|
-
});
|
|
50
|
+
var DEFAULT_ENTRY_TYPE_POLICY = archiveEntryPolicy.DEFAULT_ENTRY_TYPE_POLICY;
|
|
55
51
|
|
|
56
52
|
function _normalizeBombPolicy(p) {
|
|
57
53
|
if (!p) return DEFAULT_BOMB_POLICY;
|
|
58
54
|
return Object.freeze(Object.assign({}, DEFAULT_BOMB_POLICY, p));
|
|
59
55
|
}
|
|
60
56
|
|
|
61
|
-
|
|
62
|
-
if (!p) return DEFAULT_ENTRY_TYPE_POLICY;
|
|
63
|
-
return Object.freeze(Object.assign({}, DEFAULT_ENTRY_TYPE_POLICY, p));
|
|
64
|
-
}
|
|
57
|
+
var _normalizeEntryTypePolicy = archiveEntryPolicy.normalize;
|
|
65
58
|
|
|
66
|
-
|
|
67
|
-
if (!opts || !opts.audit || typeof opts.audit.safeEmit !== "function") return;
|
|
68
|
-
try { opts.audit.safeEmit({ action: action, outcome: outcome, metadata: metadata }); }
|
|
69
|
-
catch (_e) { /* drop-silent */ }
|
|
70
|
-
}
|
|
59
|
+
var _emitAudit = auditEmit.emitToSink; // operator-sink audit emit (opts.audit)
|
|
71
60
|
|
|
72
61
|
function _isZeroBlock(buf) {
|
|
73
62
|
for (var i = 0; i < BLOCK_SIZE; i += 1) {
|
|
@@ -58,6 +58,7 @@ var nodeStream = require("node:stream");
|
|
|
58
58
|
var streamPromises = require("node:stream/promises");
|
|
59
59
|
var C = require("./constants");
|
|
60
60
|
var { defineClass } = require("./framework-error");
|
|
61
|
+
var auditEmit = require("./audit-emit");
|
|
61
62
|
|
|
62
63
|
var ArchiveError = defineClass("ArchiveError", { alwaysPermanent: true });
|
|
63
64
|
|
|
@@ -481,16 +482,7 @@ function zip() {
|
|
|
481
482
|
return buf.length;
|
|
482
483
|
}
|
|
483
484
|
|
|
484
|
-
|
|
485
|
-
if (!opts || !opts.audit || typeof opts.audit.safeEmit !== "function") return;
|
|
486
|
-
try {
|
|
487
|
-
opts.audit.safeEmit({
|
|
488
|
-
action: action,
|
|
489
|
-
outcome: outcome,
|
|
490
|
-
metadata: metadata,
|
|
491
|
-
});
|
|
492
|
-
} catch (_e) { /* drop-silent — audit sinks must never crash the producer */ }
|
|
493
|
-
}
|
|
485
|
+
var _emitAudit = auditEmit.emitToSink; // operator-sink audit emit (opts.audit)
|
|
494
486
|
|
|
495
487
|
function _writeChunk(writable, chunk) {
|
|
496
488
|
return new Promise(function (resolve, reject) {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
38
|
var { defineClass } = require("./framework-error");
|
|
39
|
+
var pick = require("./pick");
|
|
39
40
|
|
|
40
41
|
var ArgParserError = defineClass("ArgParserError", { alwaysPermanent: true });
|
|
41
42
|
|
|
@@ -44,8 +45,8 @@ var SUPPORTED_TYPES = ["string", "number", "boolean", "list"];
|
|
|
44
45
|
// Names operators can never use for a flag. Prototype-pollution defense:
|
|
45
46
|
// even though the parser internally uses Object.create(null), downstream
|
|
46
47
|
// callers spreading parsed.flags into a normal object would otherwise
|
|
47
|
-
// overwrite the prototype.
|
|
48
|
-
|
|
48
|
+
// overwrite the prototype. The forbidden-name set is the framework's one
|
|
49
|
+
// prototype-pollution key guard — pick.isPoisonedKey.
|
|
49
50
|
|
|
50
51
|
function _isPlainNonEmpty(s) {
|
|
51
52
|
return typeof s === "string" && s.length > 0;
|
|
@@ -56,7 +57,7 @@ function _validateFlagName(name) {
|
|
|
56
57
|
throw new ArgParserError("arg-parser/flag-name-invalid",
|
|
57
58
|
"flag name must be a non-empty string");
|
|
58
59
|
}
|
|
59
|
-
if (
|
|
60
|
+
if (pick.isPoisonedKey(name)) {
|
|
60
61
|
throw new ArgParserError("arg-parser/flag-name-forbidden",
|
|
61
62
|
"flag name '" + name + "' is reserved");
|
|
62
63
|
}
|
|
@@ -298,7 +299,7 @@ function _consumeFlags(index, tokens) {
|
|
|
298
299
|
|
|
299
300
|
if (tok.indexOf("--") === 0) {
|
|
300
301
|
var rest = tok.slice(2);
|
|
301
|
-
if (
|
|
302
|
+
if (pick.isPoisonedKey(rest.split("=")[0])) {
|
|
302
303
|
throw new ArgParserError("arg-parser/argv-forbidden-name",
|
|
303
304
|
"flag '--" + rest.split("=")[0] + "' is reserved");
|
|
304
305
|
}
|
|
@@ -672,14 +673,14 @@ function parseRaw(argv) {
|
|
|
672
673
|
} else {
|
|
673
674
|
val = true;
|
|
674
675
|
}
|
|
675
|
-
if (
|
|
676
|
+
if (pick.isPoisonedKey(name)) {
|
|
676
677
|
throw new ArgParserError("arg-parser/argv-forbidden-name",
|
|
677
678
|
"flag '--" + name + "' is reserved");
|
|
678
679
|
}
|
|
679
680
|
flags[name] = val;
|
|
680
681
|
} else if (tok.indexOf("-") === 0 && tok.length === 2) {
|
|
681
682
|
var s = tok.slice(1);
|
|
682
|
-
if (
|
|
683
|
+
if (pick.isPoisonedKey(s)) {
|
|
683
684
|
throw new ArgParserError("arg-parser/argv-forbidden-name",
|
|
684
685
|
"flag '-" + s + "' is reserved");
|
|
685
686
|
}
|
|
@@ -109,12 +109,8 @@ function _mergeKey(key, base, overlay) {
|
|
|
109
109
|
if (typeof base === "object" && typeof overlay === "object" &&
|
|
110
110
|
!Array.isArray(base) && !Array.isArray(overlay)) {
|
|
111
111
|
var out = {};
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
for (var k2 in overlay) {
|
|
116
|
-
if (Object.prototype.hasOwnProperty.call(overlay, k2)) out[k2] = overlay[k2];
|
|
117
|
-
}
|
|
112
|
+
validateOpts.assignOwnEnumerable(out, base);
|
|
113
|
+
validateOpts.assignOwnEnumerable(out, overlay);
|
|
118
114
|
return out;
|
|
119
115
|
}
|
|
120
116
|
return overlay; // scalar overrides
|
|
@@ -703,39 +703,88 @@ function _validateMaxBytes(maxBytes) {
|
|
|
703
703
|
}
|
|
704
704
|
}
|
|
705
705
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
706
|
+
/**
|
|
707
|
+
* @primitive b.atomicFile.fdSafeReadSync
|
|
708
|
+
* @signature b.atomicFile.fdSafeReadSync(filepath, opts?)
|
|
709
|
+
* @since 0.15.13
|
|
710
|
+
* @status stable
|
|
711
|
+
* @related b.atomicFile.readSync, b.atomicFile.read
|
|
712
|
+
*
|
|
713
|
+
* TOCTOU-safe synchronous file read (CWE-367 / js/file-system-race). Opens
|
|
714
|
+
* the path read-only, then binds every subsequent measurement — size,
|
|
715
|
+
* content, integrity — to the inode the fd holds open, so an attacker who
|
|
716
|
+
* swaps the file between stat and read can't change which bytes come back.
|
|
717
|
+
* The optional guards layer on top of that core: a byte cap (`maxBytes`),
|
|
718
|
+
* symlink refusal + inode-equality (`refuseSymlink` / `inodeCheck` — the
|
|
719
|
+
* strongest defense, for operator-writable source paths), an integrity
|
|
720
|
+
* hash (`expectedHash`, SHA3-512), and a short-read policy (throw, or
|
|
721
|
+
* slice when `allowShortRead`). Each caller maps a failure KIND to its own
|
|
722
|
+
* typed error via `errorFor`, so the message / code / audit posture stays
|
|
723
|
+
* per-domain; the default raises an `AtomicFileError`.
|
|
724
|
+
*
|
|
725
|
+
* @opts
|
|
726
|
+
* mode: number, // open mode (default 0o600; inert under O_RDONLY)
|
|
727
|
+
* maxBytes: number, // refuse a file larger than this (default: no cap)
|
|
728
|
+
* refuseSymlink: boolean, // lstat + refuse a symlink source (default: false)
|
|
729
|
+
* inodeCheck: boolean, // refuse if the fd inode != the lstat inode (needs refuseSymlink)
|
|
730
|
+
* expectedHash: string, // SHA3-512 the content must match (default: none)
|
|
731
|
+
* encoding: string, // decode to a string (default: return a Buffer)
|
|
732
|
+
* allowShortRead: boolean, // slice to the bytes read instead of throwing (default: false)
|
|
733
|
+
* errorFor: Function, // (kind, detail) => Error|undefined; kinds: enoent / symlink / too-large / toctou / short-read / integrity
|
|
734
|
+
*
|
|
735
|
+
* @example
|
|
736
|
+
* var cfg = b.atomicFile.fdSafeReadSync("/etc/app/config.json", {
|
|
737
|
+
* maxBytes: b.constants.BYTES.mib(1),
|
|
738
|
+
* encoding: "utf8",
|
|
739
|
+
* });
|
|
740
|
+
*/
|
|
741
|
+
function fdSafeReadSync(filepath, opts) {
|
|
742
|
+
opts = opts || {};
|
|
743
|
+
var errorFor = opts.errorFor || function (kind, detail) {
|
|
744
|
+
return new AtomicFileError((detail && detail.message) || ("atomic-file: " + kind), "atomic-file/" + kind);
|
|
745
|
+
};
|
|
746
|
+
if (opts.maxBytes !== undefined) _validateMaxBytes(opts.maxBytes);
|
|
747
|
+
var mode = opts.mode === undefined ? 0o600 : opts.mode;
|
|
748
|
+
// refuseSymlink: lstat the path first and refuse a symlink source —
|
|
749
|
+
// the strongest TOCTOU posture (open() would follow the link). The
|
|
750
|
+
// fd's inode is re-checked against this lstat's inode below.
|
|
751
|
+
var lstat = null;
|
|
752
|
+
if (opts.refuseSymlink) {
|
|
753
|
+
lstat = nodeFs.lstatSync(filepath);
|
|
754
|
+
if (lstat.isSymbolicLink()) throw errorFor("symlink", { path: filepath });
|
|
755
|
+
if (opts.maxBytes !== undefined && lstat.size > opts.maxBytes) {
|
|
756
|
+
throw errorFor("too-large", { size: lstat.size, max: opts.maxBytes });
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
// The third argument pins an owner-only mode (0o600 default). The flag
|
|
760
|
+
// is read-only ("r" → O_RDONLY, no O_CREAT) so the mode is inert on
|
|
761
|
+
// disk, but specifying it keeps this open out of the insecure-temp-file
|
|
762
|
+
// class (CWE-377). ENOENT surfaces from open() rather than a pre-check;
|
|
763
|
+
// a caller's errorFor("enoent") may translate it, else it rethrows raw.
|
|
720
764
|
var fd;
|
|
721
765
|
try {
|
|
722
|
-
fd = nodeFs.openSync(filepath, "r",
|
|
766
|
+
fd = nodeFs.openSync(filepath, "r", mode);
|
|
723
767
|
} catch (openErr) {
|
|
724
768
|
if (openErr && openErr.code === "ENOENT") {
|
|
725
|
-
var
|
|
726
|
-
|
|
727
|
-
throw e;
|
|
769
|
+
var typed = errorFor("enoent", { path: filepath, cause: openErr });
|
|
770
|
+
if (typed) throw typed;
|
|
728
771
|
}
|
|
729
772
|
throw openErr;
|
|
730
773
|
}
|
|
731
774
|
var buf;
|
|
732
775
|
try {
|
|
733
776
|
var fstat = nodeFs.fstatSync(fd);
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
777
|
+
// inodeCheck: the fd must point at the same inode lstat saw — any
|
|
778
|
+
// swap between lstat and open is a TOCTOU and is refused. A file that
|
|
779
|
+
// GREW past the cap between lstat and open is the same class of swap,
|
|
780
|
+
// so under inodeCheck a post-open over-cap is reported as toctou; a
|
|
781
|
+
// plain (no-inodeCheck) reader reports an over-cap as too-large.
|
|
782
|
+
if (lstat && opts.inodeCheck) {
|
|
783
|
+
if (fstat.ino !== lstat.ino || (opts.maxBytes !== undefined && fstat.size > opts.maxBytes)) {
|
|
784
|
+
throw errorFor("toctou", { path: filepath });
|
|
785
|
+
}
|
|
786
|
+
} else if (opts.maxBytes !== undefined && fstat.size > opts.maxBytes) {
|
|
787
|
+
throw errorFor("too-large", { size: fstat.size, max: opts.maxBytes });
|
|
739
788
|
}
|
|
740
789
|
buf = Buffer.alloc(fstat.size);
|
|
741
790
|
var read = 0;
|
|
@@ -745,10 +794,8 @@ function _readSyncCore(filepath, opts) {
|
|
|
745
794
|
read += n;
|
|
746
795
|
}
|
|
747
796
|
if (read !== fstat.size) {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
"atomic-file/short-read"
|
|
751
|
-
);
|
|
797
|
+
if (opts.allowShortRead) { buf = buf.slice(0, read); }
|
|
798
|
+
else { throw errorFor("short-read", { read: read, size: fstat.size }); }
|
|
752
799
|
}
|
|
753
800
|
} finally {
|
|
754
801
|
try { nodeFs.closeSync(fd); } catch (_c) { /* close best-effort */ }
|
|
@@ -756,15 +803,44 @@ function _readSyncCore(filepath, opts) {
|
|
|
756
803
|
if (opts.expectedHash) {
|
|
757
804
|
var actual = sha3Hash(buf);
|
|
758
805
|
if (actual !== opts.expectedHash) {
|
|
759
|
-
throw
|
|
760
|
-
"integrity check failed: expected " + opts.expectedHash + " got " + actual,
|
|
761
|
-
"atomic-file/integrity"
|
|
762
|
-
);
|
|
806
|
+
throw errorFor("integrity", { expected: opts.expectedHash, actual: actual });
|
|
763
807
|
}
|
|
764
808
|
}
|
|
765
809
|
return opts.encoding ? buf.toString(opts.encoding) : buf;
|
|
766
810
|
}
|
|
767
811
|
|
|
812
|
+
// Atomic-file's own reads route through fdSafeReadSync with an errorFor
|
|
813
|
+
// that reproduces this module's exact codes + messages (a pure refactor).
|
|
814
|
+
function _readSyncCore(filepath, opts) {
|
|
815
|
+
return fdSafeReadSync(filepath, {
|
|
816
|
+
mode: 0o600,
|
|
817
|
+
maxBytes: opts.maxBytes,
|
|
818
|
+
expectedHash: opts.expectedHash,
|
|
819
|
+
encoding: opts.encoding,
|
|
820
|
+
errorFor: function (kind, detail) {
|
|
821
|
+
if (kind === "enoent") {
|
|
822
|
+
var e = new AtomicFileError("file not found: " + filepath, "atomic-file/not-found");
|
|
823
|
+
e.code = "ENOENT";
|
|
824
|
+
return e;
|
|
825
|
+
}
|
|
826
|
+
if (kind === "too-large") {
|
|
827
|
+
return new AtomicFileError(
|
|
828
|
+
"file size " + detail.size + " > maxBytes " + detail.max, "atomic-file/too-large");
|
|
829
|
+
}
|
|
830
|
+
if (kind === "short-read") {
|
|
831
|
+
return new AtomicFileError(
|
|
832
|
+
"short read: " + detail.read + " of " + detail.size + " bytes", "atomic-file/short-read");
|
|
833
|
+
}
|
|
834
|
+
if (kind === "integrity") {
|
|
835
|
+
return new AtomicFileError(
|
|
836
|
+
"integrity check failed: expected " + detail.expected + " got " + detail.actual,
|
|
837
|
+
"atomic-file/integrity");
|
|
838
|
+
}
|
|
839
|
+
return new AtomicFileError("atomic-file: " + kind, "atomic-file/" + kind);
|
|
840
|
+
},
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
|
|
768
844
|
/**
|
|
769
845
|
* @primitive b.atomicFile.writeJson
|
|
770
846
|
* @signature b.atomicFile.writeJson(filepath, value, opts)
|
|
@@ -1066,6 +1142,7 @@ module.exports = {
|
|
|
1066
1142
|
writeSync: writeSync,
|
|
1067
1143
|
read: read,
|
|
1068
1144
|
readSync: readSync,
|
|
1145
|
+
fdSafeReadSync: fdSafeReadSync,
|
|
1069
1146
|
writeJson: writeJson,
|
|
1070
1147
|
readJson: readJson,
|
|
1071
1148
|
copy: copy,
|
|
@@ -38,6 +38,7 @@ var C = require("./constants");
|
|
|
38
38
|
var clusterStorage = require("./cluster-storage");
|
|
39
39
|
var frameworkSchema = require("./framework-schema");
|
|
40
40
|
var sql = require("./sql");
|
|
41
|
+
var safeSql = require("./safe-sql");
|
|
41
42
|
var { sha3Hash } = require("./crypto");
|
|
42
43
|
|
|
43
44
|
// b.sql opts for the chain read SQL these primitives compose. The reader
|
|
@@ -135,7 +136,7 @@ function computeRowHash(prevHash, rowFields, nonce) {
|
|
|
135
136
|
|
|
136
137
|
/**
|
|
137
138
|
* @primitive b.auditChain.getChainTip
|
|
138
|
-
* @signature b.auditChain.getChainTip(queryOneAsync, tableName)
|
|
139
|
+
* @signature b.auditChain.getChainTip(queryOneAsync, tableName, opts?)
|
|
139
140
|
* @since 0.4.0
|
|
140
141
|
* @related b.auditChain.verifyChain, b.auditChain.computeRowHash
|
|
141
142
|
*
|
|
@@ -146,6 +147,14 @@ function computeRowHash(prevHash, rowFields, nonce) {
|
|
|
146
147
|
* drivers can use any await-able query function of the shape
|
|
147
148
|
* `async (sql, params?) -> row | null`.
|
|
148
149
|
*
|
|
150
|
+
* Pass `{ chainKey, keyValue }` to scope the tip to one partition of a
|
|
151
|
+
* multi-chain table (one chain per account / device / tenant) — the tip read
|
|
152
|
+
* filters `WHERE <chainKey> = ?` with the value bound, never interpolated.
|
|
153
|
+
*
|
|
154
|
+
* @opts
|
|
155
|
+
* chainKey: string, // partition column for a multi-chain table
|
|
156
|
+
* keyValue: any, // the partition value to scope the tip to (bound)
|
|
157
|
+
*
|
|
149
158
|
* @example
|
|
150
159
|
* async function queryOne(sql) {
|
|
151
160
|
* var rows = await myDriver.query(sql);
|
|
@@ -154,16 +163,22 @@ function computeRowHash(prevHash, rowFields, nonce) {
|
|
|
154
163
|
* var tip = await b.auditChain.getChainTip(queryOne, "audit_log");
|
|
155
164
|
* // → { prevHash: "<128-char hex>", counter: 4217 }
|
|
156
165
|
*/
|
|
157
|
-
async function getChainTip(queryOneAsync, tableName) {
|
|
166
|
+
async function getChainTip(queryOneAsync, tableName, opts) {
|
|
167
|
+
opts = opts || {};
|
|
158
168
|
// Emit a BARE logical table name — the operator-supplied reader routes
|
|
159
169
|
// through clusterStorage, which rewrites bare framework names to the
|
|
160
170
|
// configured-prefix form and placeholderizes. b.sql quotes the camelCase
|
|
161
|
-
// columns + runs the output validator.
|
|
162
|
-
|
|
171
|
+
// columns + runs the output validator. A chainKey scopes the tip to one
|
|
172
|
+
// partition; the key value binds as a ? placeholder.
|
|
173
|
+
var q = sql.select(tableName, _sqlOpts())
|
|
163
174
|
.columns(["rowHash", "monotonicCounter"])
|
|
164
175
|
.orderBy("monotonicCounter", "desc")
|
|
165
|
-
.limit(1)
|
|
166
|
-
|
|
176
|
+
.limit(1);
|
|
177
|
+
if (opts.chainKey) {
|
|
178
|
+
safeSql.validateIdentifier(opts.chainKey);
|
|
179
|
+
q = q.where(opts.chainKey, opts.keyValue);
|
|
180
|
+
}
|
|
181
|
+
var built = q.toSql();
|
|
167
182
|
var row = await queryOneAsync(built.sql, built.params);
|
|
168
183
|
if (!row) return { prevHash: ZERO_HASH, counter: 0 };
|
|
169
184
|
// Normalize driver shape (Postgres returns BIGINT monotonicCounter as a
|
|
@@ -192,60 +207,30 @@ async function getChainTip(queryOneAsync, tableName) {
|
|
|
192
207
|
* after a successful archive and lets the chain math survive deletion
|
|
193
208
|
* of historical rows without the archive bundle as source of truth.
|
|
194
209
|
*
|
|
210
|
+
* Pass `{ chainKey }` to verify a MULTI-chain table partitioned by a key
|
|
211
|
+
* column (one chain per account / device / tenant): each key's sub-chain is
|
|
212
|
+
* walked independently from `ZERO_HASH`, and the first break in any key returns
|
|
213
|
+
* `{ ok:false, chainKey, breakAt, ... }`. Under `chainKey`, `maxRows` is
|
|
214
|
+
* per-sub-chain and `maxChains` bounds the partition fan-out, failing closed
|
|
215
|
+
* when exceeded. The `audit_log` purge-anchor logic is single-chain-only and
|
|
216
|
+
* is skipped when a `chainKey` is given.
|
|
217
|
+
*
|
|
195
218
|
* @opts
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
219
|
+
* maxRows: number, // stop after N rows per (sub-)chain (default: walk every row)
|
|
220
|
+
* chainKey: string, // partition column — verify each sub-chain independently
|
|
221
|
+
* maxChains: number, // max partitions to verify under chainKey (default 100000; fails closed)
|
|
199
222
|
*
|
|
200
223
|
* @example
|
|
201
224
|
* async function queryAll(sql) { return await myDriver.query(sql); }
|
|
202
225
|
* var result = await b.auditChain.verifyChain(queryAll, "audit_log", {});
|
|
203
226
|
* // → { ok: true, table: "audit_log", rowsVerified: 4217, lastHash: "<hex>" }
|
|
204
227
|
*/
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
var anchor;
|
|
212
|
-
try {
|
|
213
|
-
// External-only table whose LOGICAL name IS the `_blamejs_`-prefixed
|
|
214
|
-
// name (self-mapped in LOCAL_TO_EXTERNAL), passed bare so the reader's
|
|
215
|
-
// clusterStorage rewrites it; the 'audit' scope binds as a ? param.
|
|
216
|
-
// allow:hand-rolled-sql — bare logical key.
|
|
217
|
-
var anchorBuilt = sql.select("_blamejs_audit_purge_anchor", _sqlOpts()) // allow:hand-rolled-sql
|
|
218
|
-
.columns(["lastPurgedCounter", "lastPurgedRowHash"])
|
|
219
|
-
.where("scope", "audit")
|
|
220
|
-
.toSql();
|
|
221
|
-
anchor = await queryAllAsync(anchorBuilt.sql, anchorBuilt.params);
|
|
222
|
-
} catch (_e) {
|
|
223
|
-
// Anchor table may not exist on a deployment that has never been
|
|
224
|
-
// through a purge. Treat as no anchor.
|
|
225
|
-
anchor = [];
|
|
226
|
-
}
|
|
227
|
-
if (Array.isArray(anchor) && anchor.length > 0) {
|
|
228
|
-
prevHash = anchor[0].lastPurgedRowHash;
|
|
229
|
-
skipBeforeCounter = Number(anchor[0].lastPurgedCounter);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
var rowsBuilt = sql.select(tableName, _sqlOpts())
|
|
234
|
-
.orderBy("monotonicCounter", "asc")
|
|
235
|
-
.toSql();
|
|
236
|
-
var rows = await queryAllAsync(rowsBuilt.sql, rowsBuilt.params);
|
|
237
|
-
// Normalize driver shape before hashing: node-postgres returns BIGINT
|
|
238
|
-
// columns (recordedAt / monotonicCounter) as strings, which would hash
|
|
239
|
-
// differently from the numbers the chain-writer signed — the chain only
|
|
240
|
-
// verified on SQLite without this. coerceRow makes the recompute
|
|
241
|
-
// type-stable across backends (no-op on already-numeric SQLite rows).
|
|
242
|
-
rows = frameworkSchema.coerceRows(rows);
|
|
243
|
-
if (skipBeforeCounter > 0) {
|
|
244
|
-
rows = rows.filter(function (r) {
|
|
245
|
-
return Number(r.monotonicCounter) > skipBeforeCounter;
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
|
|
228
|
+
// Walk one (sub-)chain forward from startPrevHash, recomputing each row's
|
|
229
|
+
// hash. Returns the same { ok, table, rowsVerified, lastHash | breakAt... }
|
|
230
|
+
// shape verifyChain documents. Shared by the single-chain path and each
|
|
231
|
+
// per-key partition.
|
|
232
|
+
function _walkRows(rows, tableName, startPrevHash, opts) {
|
|
233
|
+
var prevHash = startPrevHash;
|
|
249
234
|
if (rows.length === 0) {
|
|
250
235
|
return { ok: true, table: tableName, rowsVerified: 0, lastHash: prevHash };
|
|
251
236
|
}
|
|
@@ -293,6 +278,101 @@ async function verifyChain(queryAllAsync, tableName, opts) {
|
|
|
293
278
|
return { ok: true, table: tableName, rowsVerified: rows.length, lastHash: prevHash };
|
|
294
279
|
}
|
|
295
280
|
|
|
281
|
+
async function verifyChain(queryAllAsync, tableName, opts) {
|
|
282
|
+
opts = opts || {};
|
|
283
|
+
|
|
284
|
+
// Multi-chain table: verify each partition independently. Each key's
|
|
285
|
+
// sub-chain anchors at ZERO_HASH and is walked in monotonic-counter order;
|
|
286
|
+
// the first break in ANY key returns { ok:false, chainKey, ... }. maxRows is
|
|
287
|
+
// per-sub-chain; maxChains bounds the partition fan-out (fails closed when
|
|
288
|
+
// exceeded). The audit_log purge-anchor logic is single-chain-only, so it is
|
|
289
|
+
// skipped under a chainKey.
|
|
290
|
+
if (opts.chainKey) {
|
|
291
|
+
safeSql.validateIdentifier(opts.chainKey);
|
|
292
|
+
var keysBuilt = sql.select(tableName, _sqlOpts())
|
|
293
|
+
.distinct()
|
|
294
|
+
.columns([opts.chainKey])
|
|
295
|
+
.orderBy(opts.chainKey, "asc")
|
|
296
|
+
.toSql();
|
|
297
|
+
// coerce so a Postgres INTEGER/BIGINT chainKey is type-stable in the
|
|
298
|
+
// reported break-shape and the per-key WHERE bind, matching SQLite.
|
|
299
|
+
var keyRows = frameworkSchema.coerceRows(await queryAllAsync(keysBuilt.sql, keysBuilt.params));
|
|
300
|
+
var maxChains = (typeof opts.maxChains === "number" && opts.maxChains > 0) ? opts.maxChains : 100000; // allow:numeric-opt-Infinity — partition fan-out cap; non-number / <=0 falls back to the default
|
|
301
|
+
if (keyRows.length > maxChains) {
|
|
302
|
+
return {
|
|
303
|
+
ok: false,
|
|
304
|
+
table: tableName,
|
|
305
|
+
rowsVerified: 0,
|
|
306
|
+
reason: "too many chains: " + keyRows.length + " partitions exceeds maxChains " + maxChains,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
var totalVerified = 0;
|
|
310
|
+
var lastHashByKey = {};
|
|
311
|
+
for (var ki = 0; ki < keyRows.length; ki++) {
|
|
312
|
+
var keyValue = keyRows[ki][opts.chainKey];
|
|
313
|
+
var rowsBuiltK = sql.select(tableName, _sqlOpts())
|
|
314
|
+
.where(opts.chainKey, keyValue)
|
|
315
|
+
.orderBy("monotonicCounter", "asc")
|
|
316
|
+
.toSql();
|
|
317
|
+
var rowsK = frameworkSchema.coerceRows(await queryAllAsync(rowsBuiltK.sql, rowsBuiltK.params));
|
|
318
|
+
var resK = _walkRows(rowsK, tableName, ZERO_HASH, opts);
|
|
319
|
+
if (!resK.ok) { resK.chainKey = keyValue; return resK; }
|
|
320
|
+
totalVerified += resK.rowsVerified;
|
|
321
|
+
lastHashByKey[String(keyValue)] = resK.lastHash;
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
ok: true,
|
|
325
|
+
table: tableName,
|
|
326
|
+
rowsVerified: totalVerified,
|
|
327
|
+
chains: keyRows.length,
|
|
328
|
+
lastHashByKey: lastHashByKey,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
var prevHash = ZERO_HASH;
|
|
333
|
+
var skipBeforeCounter = 0;
|
|
334
|
+
if (tableName === "audit_log") {
|
|
335
|
+
var anchor;
|
|
336
|
+
try {
|
|
337
|
+
// External-only table whose LOGICAL name IS the `_blamejs_`-prefixed
|
|
338
|
+
// name (self-mapped in LOCAL_TO_EXTERNAL), passed bare so the reader's
|
|
339
|
+
// clusterStorage rewrites it; the 'audit' scope binds as a ? param.
|
|
340
|
+
// allow:hand-rolled-sql — bare logical key.
|
|
341
|
+
var anchorBuilt = sql.select("_blamejs_audit_purge_anchor", _sqlOpts()) // allow:hand-rolled-sql
|
|
342
|
+
.columns(["lastPurgedCounter", "lastPurgedRowHash"])
|
|
343
|
+
.where("scope", "audit")
|
|
344
|
+
.toSql();
|
|
345
|
+
anchor = await queryAllAsync(anchorBuilt.sql, anchorBuilt.params);
|
|
346
|
+
} catch (_e) {
|
|
347
|
+
// Anchor table may not exist on a deployment that has never been
|
|
348
|
+
// through a purge. Treat as no anchor.
|
|
349
|
+
anchor = [];
|
|
350
|
+
}
|
|
351
|
+
if (Array.isArray(anchor) && anchor.length > 0) {
|
|
352
|
+
prevHash = anchor[0].lastPurgedRowHash;
|
|
353
|
+
skipBeforeCounter = Number(anchor[0].lastPurgedCounter);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
var rowsBuilt = sql.select(tableName, _sqlOpts())
|
|
358
|
+
.orderBy("monotonicCounter", "asc")
|
|
359
|
+
.toSql();
|
|
360
|
+
var rows = await queryAllAsync(rowsBuilt.sql, rowsBuilt.params);
|
|
361
|
+
// Normalize driver shape before hashing: node-postgres returns BIGINT
|
|
362
|
+
// columns (recordedAt / monotonicCounter) as strings, which would hash
|
|
363
|
+
// differently from the numbers the chain-writer signed — the chain only
|
|
364
|
+
// verified on SQLite without this. coerceRow makes the recompute
|
|
365
|
+
// type-stable across backends (no-op on already-numeric SQLite rows).
|
|
366
|
+
rows = frameworkSchema.coerceRows(rows);
|
|
367
|
+
if (skipBeforeCounter > 0) {
|
|
368
|
+
rows = rows.filter(function (r) {
|
|
369
|
+
return Number(r.monotonicCounter) > skipBeforeCounter;
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return _walkRows(rows, tableName, prevHash, opts);
|
|
374
|
+
}
|
|
375
|
+
|
|
296
376
|
module.exports = {
|
|
297
377
|
ZERO_HASH: ZERO_HASH,
|
|
298
378
|
canonicalize: canonicalize,
|
|
@@ -164,20 +164,30 @@ function create(opts) {
|
|
|
164
164
|
throw _err("auditDailyReview/audit-query-missing",
|
|
165
165
|
"auditDailyReview.create: opts.audit.query must be a function");
|
|
166
166
|
}
|
|
167
|
-
validateOpts.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
167
|
+
validateOpts.shape(opts, {
|
|
168
|
+
audit: { methods: ["query", "safeEmit"] },
|
|
169
|
+
notify: { rule: "optional-function", code: "auditDailyReview/bad-notify" },
|
|
170
|
+
classify: { rule: "optional-function", code: "auditDailyReview/bad-classify" },
|
|
171
|
+
now: { rule: "optional-function", code: "auditDailyReview/bad-now" },
|
|
172
|
+
posture: { rule: "optional-string", code: "auditDailyReview/bad-posture" },
|
|
173
|
+
cron: { rule: "optional-string", code: "auditDailyReview/bad-cron" },
|
|
174
|
+
severityThreshold: { rule: "optional-string", code: "auditDailyReview/bad-severity" },
|
|
175
|
+
queryLimit: { rule: "optional-positive-int", code: "auditDailyReview/bad-querylimit" },
|
|
176
|
+
historyLimit: { rule: "optional-positive-int", code: "auditDailyReview/bad-historylimit" },
|
|
177
|
+
// lookbackHours — positive finite number (hours, not bytes). Bespoke
|
|
178
|
+
// check preserves the auditDailyReview/bad-lookback code the message
|
|
179
|
+
// below depends on; a positive-int token would reject fractional hours.
|
|
180
|
+
lookbackHours: function (value, label) {
|
|
181
|
+
if (value === undefined || value === null) return;
|
|
182
|
+
if (typeof value !== "number" || !isFinite(value) || value <= 0) {
|
|
183
|
+
throw _err("auditDailyReview/bad-lookback",
|
|
184
|
+
"auditDailyReview.create: lookbackHours must be a positive finite number");
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
}, "auditDailyReview", AuditDailyReviewError, "auditDailyReview/bad-opts",
|
|
188
|
+
// scheduler is forwarded to the b.scheduler instance at start() and not
|
|
189
|
+
// validated locally at create-time (start() requires it on its own).
|
|
190
|
+
{ allow: ["scheduler"] });
|
|
181
191
|
|
|
182
192
|
// lookbackHours — default 24 per PCI DSS 4.0 daily cadence. Caller can
|
|
183
193
|
// pass weekly / monthly via larger numbers.
|