@blamejs/core 0.6.12 → 0.6.20
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 +8 -0
- package/NOTICE +16 -0
- package/README.md +9 -8
- package/index.js +12 -0
- package/lib/api-key.js +2 -3
- package/lib/audit.js +4 -0
- package/lib/auth/password.js +449 -4
- package/lib/cache.js +3 -7
- package/lib/cli.js +598 -4
- package/lib/config-drift.js +309 -0
- package/lib/crypto-field.js +37 -0
- package/lib/crypto.js +8 -0
- package/lib/db.js +17 -2
- package/lib/dual-control.js +475 -0
- package/lib/file-type.js +265 -0
- package/lib/http-client.js +77 -0
- package/lib/internal-sha1-hibp.js +34 -0
- package/lib/middleware/csp-nonce.js +7 -4
- package/lib/middleware/index.js +2 -0
- package/lib/middleware/network-allowlist.js +199 -0
- package/lib/network-dns.js +469 -0
- package/lib/network-heartbeat.js +290 -0
- package/lib/network-nts.js +552 -0
- package/lib/network-proxy.js +246 -0
- package/lib/network-tls.js +326 -0
- package/lib/network.js +233 -0
- package/lib/notify.js +2 -3
- package/lib/ntp-check.js +50 -4
- package/lib/numeric-checks.js +40 -0
- package/lib/object-store/azure-blob.js +16 -42
- package/lib/permissions.js +223 -9
- package/lib/pqc-agent.js +4 -4
- package/lib/queue.js +5 -5
- package/lib/restore.js +5 -3
- package/lib/retention.js +439 -0
- package/lib/retry.js +3 -6
- package/lib/security-assert.js +368 -0
- package/lib/session.js +138 -8
- package/lib/slug.js +2 -3
- package/lib/ssrf-guard.js +9 -0
- package/lib/testing.js +3 -7
- package/lib/vendor/MANIFEST.json +12 -0
- package/lib/vendor/common-passwords-top-10000.txt +10000 -0
- package/lib/webhook.js +3 -6
- package/package.json +3 -2
- package/sbom.cyclonedx.json +61 -0
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,14 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.6.x
|
|
10
10
|
|
|
11
|
+
- **0.6.20** (2026-05-02) — CI / packaging fix-up. The npm-publish workflow's "Attach SBOM as release asset" step started failing with HTTP 422 ("Cannot upload assets to an immutable release") because the operator's manual `gh release create` had already been published when the workflow ran. Two changes: (1) `sbom.cyclonedx.json` is now bundled into the npm tarball (`files` block in package.json), so `npm install @blamejs/core && cat node_modules/@blamejs/core/sbom.cyclonedx.json` is the canonical SBOM access path. The prepack guard's known-allowed list covers the just-in-time generation. (2) The workflow's GH-release-attach step is now non-fatal: it tries to upload, logs a warning if the release is immutable, and lets the publish proceed regardless. The npm tarball is the load-bearing artifact; the GitHub release attachment was only ever supplementary. `.gitignore` adds `sbom.cyclonedx.json` so a stray local `npm sbom` doesn't pollute the repo.
|
|
12
|
+
- **0.6.19** (2026-05-02) — closes the critical + high gaps surfaced by the v0.6.18 audit. **Critical**: `b.network.ntp.nts.querySingle` now actually verifies the server reply with the s2cKey — extracts the AUTHENTICATOR_AND_ENC extension, AEAD-decrypts with AAD = bytes-before-authenticator, fails closed (`nts/auth-failed` / `nts/no-authenticator`) when verification fails. Server-supplied new cookies in the encrypted plaintext are appended to the cookie pool and the consumed cookie popped (real RFC 8915 cookie rotation). Previously the function returned `authenticated: true` while only checking the unique-identifier echo — any MITM that mirrored the request's 32-byte unique field could spoof timestamps. **High**: `azure-blob.presignedUploadPolicy` now throws `PRESIGN_NOT_SUPPORTED` instead of silently returning a SAS PUT URL when operators asked for POST policy semantics — Azure SAS has no body-size cap and the previous shape was a misleading mismatch (operator error message points at presignedUploadUrl + post-upload HEAD as the alternative). `b.auth.password.policy` now ships the SecLists top-10000 common-password list bundled (CC-BY-3.0, `lib/vendor/common-passwords-top-10000.txt`), loaded lazily on first `policy.check()` call; `password` / `dragon` / `qwerty` / etc. now reject with `policy/forbidden-common`; `useBundledCommon: false` per-policy bypasses if operator ships their own list. `b.network.tls` adds `removeCa(fingerprint256)` / `removeCaByLabel(label)` / `clearAll()` / `purgeExpired()` / `expiringSoon(windowMs)` so operators can rotate corp DPI CAs without process restart; every removal audits with subject + fingerprint + reason. `b.network.dns.setResultOrder("ipv6first")` now flips the order on the DoH / DoT dual-stack fallback paths too (was only sorting OS-resolver results). `b.network.dns.resolve4` / `resolve6` / `resolveAaaa` now use real DNS-protocol queries (`dns.promises.resolve4` / `_dohLookup` / `_dotLookup`) instead of aliasing `lookup()` — operator semantics now match Node's standard library (skips `/etc/hosts`, mDNS). `b.network.socket.setDefaultLinger` removed from the silent no-op path; now throws `socket/linger-not-supported` with operator guidance to use `socket.destroy()` (abort) vs `socket.end()` (graceful) since Node's public `net.Socket` has no `setLinger()`. **Internal**: every `new XxxError(...)` call across `lib/network*.js` was passing args in the wrong order (message-then-code instead of code-then-message), making `e.code` return human messages and `e.message` return slash-codes — operators relying on `e.code` for error handling got the wrong field. All 50+ throws fixed across `lib/network.js` / `network-dns.js` / `network-proxy.js` / `network-tls.js` / `network-heartbeat.js` / `network-nts.js`. **CI**: `.gitleaks.toml` adds `test/smoke.js` to the path allowlist and pins the historical commit + fingerprint that tripped the jwt rule on a `REDACTED` placeholder; `npm-publish.yml` job permissions bumped from `contents: read` to `contents: write` so `gh release upload sbom.cyclonedx.json` no longer 403s.
|
|
13
|
+
- **0.6.18** (2026-05-02) — `b.network` primitive — single namespace for runtime-configurable network behaviour. `b.network.ntp` adds tunable warn / fatal drift thresholds, env-var bindings (`BLAMEJS_NTP_SERVERS` / `BLAMEJS_NTP_TIMEOUT_MS` / `BLAMEJS_NTP_DRIFT_WARN_MS` / `BLAMEJS_NTP_DRIFT_FATAL_MS`), and authenticated-time support: `b.network.ntp.nts.query(opts)` performs an NTS-KE handshake (RFC 8915) over TLS 1.3 with the framework's PQC-hybrid group preference, extracts C2S / S2C keys via the standardized TLS exporter, and authenticates NTPv4 packets with AES-SIV-CMAC-256 (mandatory-to-implement, in-house) or AEAD-CHACHA20-POLY1305 — no extra vendored deps. `b.network.dns` exposes operator-pinned resolvers, IPv4 / IPv6 / dual-stack family selection, ipv4first / verbatim / ipv6first ordering, DNS lookup timeout (Node's native `dns.lookup` has none), in-memory positive + negative cache, and DoH / DoT (cloudflare / google / quad9 / custom URL) — `b.ssrfGuard` and `b.httpClient` route through it when configured. `b.network.proxy` honours `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY` / `ALL_PROXY` (lower- and upper-case) with CIDR + suffix + wildcard `NO_PROXY` matching, basic-auth via `BLAMEJS_PROXY_AUTH`, CONNECT tunnels for HTTPS through HTTP proxies; `b.httpClient` picks up the agent automatically. `b.network.tls` is a runtime-overridable trust store: `addCa(pemOrPath)` / `addCaBundle(path)` / `useSystemTrust()` / `getTrustStore()` for deep-packet-inspection deploys behind Zscaler / Netskope / corporate Squid + custom CA — Node's `NODE_EXTRA_CA_CERTS` only works at boot; this primitive accepts adds at any time and `b.pqcAgent` picks them up immediately. Every `addCa` audits with subject + issuer + fingerprint256 + validity + isSelfSigned. `b.security.assertProduction({ allowDpiTrust })` refuses to boot in production with installed CAs unless explicitly allowed. `b.network.heartbeat` adds application-level liveness probes for upstream services (HTTP / TCP / NTP probe types, healthy → degraded → down state machine with consecutive-failure threshold, audit on state change, observability counters per probe). `b.network.socket` gives operator-tunable defaults for `TCP_NODELAY` / `SO_KEEPALIVE` / `SO_LINGER`. `b.network.bootFromEnv()` reads every supported env var at startup and applies in the right order so configuration takes effect before the first outbound socket; the wiki app's docker-compose configs ship every knob with a default-empty value (production overlay tightens DNS lookup timeout + cache TTL + `NTP_STRICT=1` + `SOCKET_NO_DELAY=1`). `.gitleaks.toml` was previously gitignored by the deny-all-dotfiles allowlist; it is now allowlisted so CI's secret-scan job loads the framework's allowlist and stops failing on `.gitleaks.toml: no such file or directory`. New wiki page `/network-config` documents all six sub-primitives.
|
|
14
|
+
- **0.6.17** (2026-05-02) — six new CLI subcommands wrapping the v0.6.14 primitives so operators can drive them from runbooks / cron / one-off ops: `blamejs security assert` (boot the framework + run `b.security.assertProduction()` against the live posture; aggregates failures with their codes, exit 1 on any failure), `blamejs config-drift inspect/verify` (read the signed sidecar without rebooting; `verify` returns exit 1 on tamper or missing), `blamejs file-type detect <file>` (magic-byte content classification with `--allowlist` for upload debugging — pure utility, no boot), `blamejs password check --plaintext "..."` (test `b.auth.password.policy` with `--profile pci-4.0` / `nist-aal2` / `hipaa-aal2`, `--breach-check` for HIBP, `--email` / `--username` context — pure utility), `blamejs erase --table X --row-id Y --confirm` (one-off cryptographic erasure for GDPR Art. 17 — replaces sealed columns + derived hashes with NULL + audits via `system.erase`), `blamejs retention preview/run` (ad-hoc rule from CLI flags: `--table` + `--age-field` + `--ttl-ms` + `--action`, with `preview` for dry-run reporting). Also: per-subcommand `--help` now reaches each handler's USAGE block (the previous main() dispatch short-circuited every `<sub> --help` to top-level help); fix applies to all existing subcommands too (`api-key --help`, `vault --help`, etc.). The `b.dualControl` primitive is intentionally NOT in the CLI surface — its grants live in an operator-supplied `b.cache` instance the CLI can't bind to without operator wiring; admins approve / revoke from the operator's app instead. Hadolint action pinned to `@master` (the published `@v3` floating tag doesn't exist; the maintainer ships only patch tags + master).
|
|
15
|
+
- **0.6.16** (2026-05-02) — CI secret-scan job switched from `gitleaks/gitleaks-action` (which started requiring a paid `GITLEAKS_LICENSE` for organization repositories, breaking the v0.6.14 publish workflow) to a direct install of the OSS gitleaks binary (Apache-2.0); resolves the latest release at job time so new ruleset improvements ship automatically. Same forward-track posture applied to other CI tools where pinning would silently miss security improvements: `aquasecurity/trivy-action` swapped from `@v0.36.0` to `@master`, `hadolint/hadolint-action` from `@v3.3.0` to the floating `@v3` major tag, `ludeeus/action-shellcheck` from `@2.0.0` to `@master`, ESLint runner from `eslint@10` to `eslint@latest` in both `ci.yml` and `npm-publish.yml`. Vendored crypto libraries (@noble/ciphers, @simplewebauthn/server, argon2, peculiar-pki) verified at latest upstream — no bundle refresh needed. No framework code changes; npm publish workflow unblocked for v0.6.14 / v0.6.15 / this release.
|
|
16
|
+
- **0.6.15** (2026-05-02) — wiki sidebar nav: every concern group is now a `<details>` section starting collapsed; the section containing the current page is rendered with `open` server-side so the operator's current location is always visible. Custom CSS-only disclosure glyph (▸ → ▾ via rotation) — works under the wiki's strict CSP without inline JS. Wiki app gains three new env knobs that ship with the docker-compose configs out of the box: `WIKI_TRUST_PROXY` (cookie Secure-flag detection through TLS terminator; pre-existing in v0.6.12 lib code, now in docker-compose with documentation), `WIKI_ADMIN_ALLOWED_CIDRS` / `WIKI_ADMIN_DENIED_CIDRS` (in-process CIDR fence on `/admin` paths via `b.middleware.networkAllowlist`), `WIKI_REQUIRE_PROD_ASSERTS` (boot-time `b.security.assertProduction()` gate that refuses to boot when production posture is incomplete). The production overlay (`docker-compose.prod.yml`) defaults the latter two on (TRUST_PROXY=1 since Caddy terminates TLS, REQUIRE_PROD_ASSERTS=1 so a misconfigured prod deploy fails fast); the dev overlay defaults them off.
|
|
17
|
+
- **0.6.14** (2026-05-02) — new operator-facing primitives, each shipping the v1-defensible compliance surface: `b.security.assertProduction(opts)` boot-time policy engine (vault / dbAtRest / auditSigning posture, NTP strict, Node minimum major, TLS minimum version, required + forbidden env vars, NODE_ENV pinning, dataDir POSIX-mode check, CORS-allow-all detection, operator-supplied extra asserts); `b.permissions.policy(scope, predicate)` ABAC layer that evaluates per-scope predicates after RBAC passes (single + requireAll + requireAny modes); `b.permissions` role-spec `requireMfa` / `mfaWindowMs` AND per-route MFA enforcement; `b.session` IP/UA fingerprint capture + drift detection with operator-supplied scorer for anomaly scoring (strict modes: `requireFingerprintMatch` AND `maxAnomalyScore`); `b.auth.password.policy(opts)` with NIST 800-63B / PCI-DSS 4.0 / HIPAA-AAL2 named profiles, length / common / context / dictionary / complexity (categories + min-run + min-sequence) rules, HIBP k-anonymity breach check (SHA-1 lives in `lib/internal-sha1-hibp.js`, NOT exported on `b.crypto`), rotation (`shouldRotate`) and history-reuse (`reuseProhibited`); `b.dualControl.create(opts)` two-person-rule with m-of-n quorum, cooling-off lock between approval and consume, approver-role gate, requester cancellation, minimum reason length, notification hook; `b.retention.create(opts)` with multi-stage rules (warn → archive → erase), legal-hold per-row exemption, dry-run `preview()`, soft-delete vs hard-delete vs erase, cross-table cascade, per-rule concurrency lock; `b.configDrift.create(opts)` with multi-baseline support, critical-keys severity classification, ignore-keys allowlist, signed sidecar via SLH-DSA + diff vs prev snapshot; `b.fileType.detect/.assertOneOf` magic-byte content classification (image / document / archive / executable / etc.); `b.middleware.networkAllowlist({ paths, allowedCidrs, deniedCidrs })` deny-then-allow CIDR fence; `b.httpClient.request({ allowedHosts })` with exact / suffix / wildcard / per-method entries and audit emit on disallowed; `b.cryptoField.eraseRow(table, row)` cryptographic-erasure helper for sealed columns + derived hashes. CI gains gitleaks secret scan + CycloneDX SBOM via `npm sbom` (no vendoring). README + SECURITY operator-checklist updated end to end for the new surface; wiki gains alerting-rule reference table for the framework's emitted events. Backwards-compatible — every new opt is opt-in.
|
|
18
|
+
- **0.6.13** (2026-05-02) — wiki primitive-section docs catch up to the v0.6.12 surface (`safeUrl.parse` allowUserinfo, `session.touch` extendBy ceiling, `queue.consume` rateLimit validation, `mail.transports.console` redactBcc, `logStream` webhook-sink onDrop, `backup.create` requireFlush, `restore.create` maxPulledBytes / maxPulledFiles); restore default cap stated as `C.BYTES.gib(4)` instead of a raw byte literal; numeric-check predicates (`isPositiveInt`, `isFiniteNonNegative`, `isPositiveFinite`) consolidated into `lib/numeric-checks.js` — were duplicated across api-key, cache, notify, queue, restore, retry, slug, testing, webhook; api-snapshot.json refreshed
|
|
11
19
|
- **0.6.12** (2026-05-02) — `b.safeUrl.parse` now rejects URLs with `user:pass@` userinfo by default (opt in per-call via `allowUserinfo: true`); `b.session.touch({ extendBy })` enforces the same `MAX_TTL_MS` ceiling as `create` / `rotate`; `b.queue.consume({ rateLimit })` rejects negative / zero / `NaN` / `Infinity` / fractional `max`; `b.middleware.requireAuth` no longer treats request `Content-Type: application/json` as a JSON-preference signal (only `Accept` and `X-Requested-With` count); `b.backup.create({ requireFlush: true })` opt-in fails the backup if pre-flush fails instead of producing a stale snapshot; `b.restore.create({ maxPulledBytes, maxPulledFiles })` preflight bounds bundle footprint before and after pull (defaults 4 GiB / 100K files); `b.mail.transports.console({ redactBcc: true })` opt-in prints recipient count instead of addresses; `b.logStream.transports.webhook({ onDrop })` callback fires on overflow + retry-exhausted batch drops. Wiki: admin login wired through `b.auth.lockout` (exponential-backoff after bad-cred attempts) and cookie `Secure` flag now routes through `b.requestHelpers.requestProtocol` with `WIKI_TRUST_PROXY` opt-in instead of trusting raw `x-forwarded-proto`. Wiki README documents the trust model for editable page bodies and the sanitization pattern operators should adopt before expanding the editor surface.
|
|
12
20
|
- **0.6.11** (2026-05-01) — wiki example-execution validator: fixture init no longer reaches across module realms (unblocks the npm-publish workflow's wiki-e2e gate, which `npm install --install-links` copies the framework into the wiki's node_modules — two distinct singletons before this fix)
|
|
13
21
|
- **0.6.10** (2026-05-01) — README / SECURITY / CONTRIBUTING / wiki: removed stale version stamps and an inaccurate vendored-dep list; SECURITY now points at `lib/vendor/MANIFEST.json` for the authoritative vendor list; supported-versions table no longer pins to a specific minor; wiki archive example names the digest variable correctly (was `sha256`, output is SHA3-512 hex)
|
package/NOTICE
CHANGED
|
@@ -57,3 +57,19 @@ Used for: Pure-JS mTLS CA. Self-signed CA generation (ECDSA P-384, SHA-384),
|
|
|
57
57
|
asn1js, pvtsutils, pvutils, and the @peculiar/asn1-* schema
|
|
58
58
|
chain).
|
|
59
59
|
--------------------------------------------------------------------------------
|
|
60
|
+
Component: SecLists — 10k-most-common.txt
|
|
61
|
+
Version: master snapshot (bundled 2026-05-02)
|
|
62
|
+
Source: https://github.com/danielmiessler/SecLists
|
|
63
|
+
https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10k-most-common.txt
|
|
64
|
+
License: CC-BY-3.0
|
|
65
|
+
Copyright: Copyright (c) Daniel Miessler and SecLists contributors
|
|
66
|
+
Used for: Top-10000 most-common (breach-derived) passwords. Loaded by
|
|
67
|
+
b.auth.password.policy() to satisfy NIST 800-63B §5.1.1.2's
|
|
68
|
+
"previously breached, dictionary, repetitive/sequential,
|
|
69
|
+
context-specific" check. Operators with deeper enforcement
|
|
70
|
+
(HIBP downloads, NCSC 100k) layer on top via opts.forbidCommon
|
|
71
|
+
— the bundled set is additive. Bundled at lib/vendor/
|
|
72
|
+
common-passwords-top-10000.txt; thank you to the SecLists
|
|
73
|
+
project maintainers for keeping a curated, freely-redistributable
|
|
74
|
+
baseline.
|
|
75
|
+
--------------------------------------------------------------------------------
|
package/README.md
CHANGED
|
@@ -42,15 +42,15 @@ var b = require("@blamejs/core");
|
|
|
42
42
|
The framework bundles the surface a typical Node app reaches for. Every primitive listed is callable today; nothing is a stub.
|
|
43
43
|
|
|
44
44
|
- **Data layer** — SQLite with sealed-by-default columns (`b.db`), migrations, seeders, atomic-file writes; bring-your-own external Postgres / MySQL / etc. with pool tuning + role-aware connect + read-replica routing (`b.externalDb`); declarative role-narrowed views and Postgres row-level-security migrations (`b.db.declareView`, `b.db.declareRowPolicy`); S3 / R2 / B2 / GCS / Azure object store with multipart upload + SSE + bucket ops (`b.storage`, `b.objectStore`); durable queue with priority + cron + flows (`b.queue`, `b.jobs`); cluster-shared cache (`b.cache`).
|
|
45
|
-
- **Identity & access** — passwords (Argon2id), passkeys (WebAuthn), TOTP, JWT (PQ-default), OAuth, sessions, brute-force lockout (`b.auth.*`, `b.session`); RBAC
|
|
46
|
-
- **Crypto** — envelope-versioned PQC at rest (ML-KEM-1024 + P-384 hybrid, XChaCha20-Poly1305, SHAKE256), vault sealing, field-level crypto, signed webhooks (SLH-DSA-SHAKE-256f), ECIES API encryption (`b.crypto`, `b.vault`, `b.webhook`); pure-JS mTLS CA, PQC TLS gates inbound + outbound (`b.mtlsCa`, `b.pqcGate`, `b.pqcAgent`).
|
|
47
|
-
- **HTTP** — router with schema-validated routes + OpenAPI publication; full middleware stack (CSRF, CORS, rate-limit, security headers, CSP nonce, body parser, compression, SSE, request log, request-time DB role binding via `b.middleware.dbRoleFor`) wired by `createApp`; HTTP/1.1 + HTTP/2 outbound client with SSRF gate, redirects, multipart, interceptors, progress, encrypted cookie jar (`b.httpClient`, `b.ssrfGuard`, `b.safeUrl`).
|
|
48
|
-
- **Defensive parsers** — `b.safeJson`, `b.safeBuffer`, `b.safeSql`, `b.safeSchema`, `b.parsers` (XML / TOML / YAML / .env), `b.config` (schema-validated env).
|
|
45
|
+
- **Identity & access** — passwords (Argon2id) + policy primitive (NIST 800-63B / PCI-DSS 4.0 / HIPAA-AAL2 profiles, HaveIBeenPwned k-anonymity breach check, length / context / dictionary / complexity rules, rotation + history) (`b.auth.password`); passkeys (WebAuthn), TOTP, JWT (PQ-default), OAuth, sessions with optional IP / UA fingerprint drift detection + anomaly scoring, brute-force lockout (`b.auth.*`, `b.session`); RBAC + optional per-role DB binding + role-spec `requireMfa` + per-route MFA freshness window + ABAC predicate registry (`b.permissions`); API keys with rotation (`b.apiKey`); break-glass column gates with second-factor + audit (`b.breakGlass`); two-person-rule approval workflow with m-of-n quorum + cooling-off lock + approver-role gate + cancellation (`b.dualControl`).
|
|
46
|
+
- **Crypto** — envelope-versioned PQC at rest (ML-KEM-1024 + P-384 hybrid, XChaCha20-Poly1305, SHAKE256), vault sealing, field-level crypto + cryptographic erasure (`b.cryptoField.eraseRow`), signed webhooks (SLH-DSA-SHAKE-256f), ECIES API encryption (`b.crypto`, `b.vault`, `b.webhook`); pure-JS mTLS CA, PQC TLS gates inbound + outbound (`b.mtlsCa`, `b.pqcGate`, `b.pqcAgent`).
|
|
47
|
+
- **HTTP** — router with schema-validated routes + OpenAPI publication; full middleware stack (CSRF, CORS, rate-limit, security headers, CSP nonce, body parser, compression, SSE, request log, request-time DB role binding via `b.middleware.dbRoleFor`, in-process CIDR fence via `b.middleware.networkAllowlist`) wired by `createApp`; HTTP/1.1 + HTTP/2 outbound client with SSRF gate, scheme + userinfo + per-host (wildcard / per-method) destination allowlist, redirects, multipart, interceptors, progress, encrypted cookie jar (`b.httpClient`, `b.ssrfGuard`, `b.safeUrl`); operator-tunable network configurability — env-driven NTP / NTS (RFC 8915 authenticated time), DNS with IPv6 / DoH / DoT / cache / lookup timeout, outbound HTTP proxy (`HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`), runtime DPI trust-store CA additions, application-level heartbeats, TCP socket defaults (`b.network`).
|
|
48
|
+
- **Defensive parsers** — `b.safeJson`, `b.safeBuffer`, `b.safeSql`, `b.safeSchema`, `b.parsers` (XML / TOML / YAML / .env), `b.config` (schema-validated env), `b.fileType` magic-byte content classification with deny-on-upload categories (image / document / archive / executable / etc.).
|
|
49
49
|
- **Communication** — WebSockets with channel/room fan-out across cluster replicas (`b.websocket`, `b.websocketChannels`); mail with multipart + attachments + DKIM + calendar invites + bounce intake (`b.mail`, `b.mailBounce`); generic notification dispatcher with operator-supplied transports (`b.notify`).
|
|
50
|
-
- **Observability** — tamper-evident audit chain with SLH-DSA-signed checkpoints, metrics, tracing (OTel pass-through when wired), PII redaction, log-stream sinks, OTLP/HTTP-JSON exporter for any OTel-compatible backend (`b.audit`, `b.metrics`, `b.tracing`, `b.redact`, `b.logStream`, `b.otelExport`).
|
|
50
|
+
- **Observability** — tamper-evident audit chain with SLH-DSA-signed checkpoints, metrics, tracing (OTel pass-through when wired), PII redaction, log-stream sinks, OTLP/HTTP-JSON exporter for any OTel-compatible backend (`b.audit`, `b.metrics`, `b.tracing`, `b.redact`, `b.logStream`, `b.otelExport`); operator-callable boot-time security policy assertions (`b.security.assertProduction`) and tamper-evident config-baseline drift detection signed with the audit-signing key (`b.configDrift`).
|
|
51
51
|
- **i18n** — CLDR plural rules, Accept-Language negotiation, Intl formatters, RTL (`b.i18n`).
|
|
52
52
|
- **Format helpers** — RFC 4180 CSV with Excel formula-injection prevention (`b.csv`), RFC 9562 UUID v4 + v7 (`b.uuid`), URL-safe slugs (`b.slug`), TZ-aware datetime (`b.time`), ZIP creation (`b.archive`), HMAC-signed cursor pagination (`b.pagination`), HTML form rendering + validation + CSRF (`b.forms`).
|
|
53
|
-
- **Production** — cluster leader election with fenced leases over Postgres/SQLite (`b.cluster`); cron + interval scheduler that runs exactly-once globally (`b.scheduler`); retry with full-jitter backoff + circuit breaker (`b.retry`); graceful shutdown (`b.appShutdown`); NTP boot check (`b.ntpCheck`); end-to-end-encrypted backup bundles (`b.backup`).
|
|
53
|
+
- **Production** — cluster leader election with fenced leases over Postgres/SQLite (`b.cluster`); cron + interval scheduler that runs exactly-once globally (`b.scheduler`); retry with full-jitter backoff + circuit breaker (`b.retry`); graceful shutdown (`b.appShutdown`); NTP boot check (`b.ntpCheck`); end-to-end-encrypted backup bundles with pre-flush fail-closed mode (`b.backup`); restore with pulled-bundle footprint preflight (`b.restore`); GDPR / PCI / HIPAA-shaped retention rules with multi-stage warn → archive → erase, legal-hold exemptions, dry-run preview, cross-table cascade (`b.retention`).
|
|
54
54
|
|
|
55
55
|
## Documentation
|
|
56
56
|
|
|
@@ -59,7 +59,7 @@ Full primitive-by-primitive docs live at [blamejs.com](https://blamejs.com), whi
|
|
|
59
59
|
- **Data** — [Database](https://blamejs.com/database) · [Object Store](https://blamejs.com/object-store) · [Queue & Cache](https://blamejs.com/queue-cache)
|
|
60
60
|
- **Identity** — [Authentication](https://blamejs.com/auth) · [Access Control](https://blamejs.com/access-control)
|
|
61
61
|
- **Crypto** — [Crypto & Vault](https://blamejs.com/crypto-vault) · [Network Crypto](https://blamejs.com/network-crypto)
|
|
62
|
-
- **HTTP** — [Routing](https://blamejs.com/routing) · [Middleware](https://blamejs.com/middleware) · [Outbound HTTP](https://blamejs.com/outbound-http)
|
|
62
|
+
- **HTTP** — [Routing](https://blamejs.com/routing) · [Middleware](https://blamejs.com/middleware) · [Outbound HTTP](https://blamejs.com/outbound-http) · [Network Configurability](https://blamejs.com/network-config)
|
|
63
63
|
- **Validation** — [Safe Parsers](https://blamejs.com/safe-parsers)
|
|
64
64
|
- **Communication** — [WebSockets](https://blamejs.com/websockets) · [Mail](https://blamejs.com/mail) · [Notifications](https://blamejs.com/notifications)
|
|
65
65
|
- **Tools** — [Observability](https://blamejs.com/observability) · [Testing](https://blamejs.com/testing) · [i18n & Locale](https://blamejs.com/i18n-locale) · [Format Helpers](https://blamejs.com/format-helpers)
|
|
@@ -106,9 +106,10 @@ All runtime dependencies are committed to the repo — no transitive npm install
|
|
|
106
106
|
| [`@simplewebauthn/server`](https://github.com/MasterKale/SimpleWebAuthn) | 13.3.0 | [Matthew Miller](https://github.com/MasterKale) | WebAuthn / passkey verification |
|
|
107
107
|
| [`argon2`](https://github.com/ranisalt/node-argon2) | 0.44.0 | [Ranieri Althoff](https://github.com/ranisalt) | Password hashing (native prebuilds, 8 platforms) |
|
|
108
108
|
| [`@peculiar/x509`](https://github.com/PeculiarVentures/x509) + [`pkijs`](https://github.com/PeculiarVentures/PKI.js) | 2.0.0 + 3.4.0 | [Peculiar Ventures](https://github.com/PeculiarVentures) | Pure-JS mTLS CA — ECDSA P-384 cert signing, PKCS#12 packaging (no openssl CLI) |
|
|
109
|
+
| [`SecLists` 10k-most-common.txt](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10k-most-common.txt) | master snapshot | [Daniel Miessler / SecLists contributors](https://github.com/danielmiessler/SecLists) (CC-BY-3.0) | Top-10000 common-password dictionary read by `b.auth.password.policy()` for the NIST 800-63B §5.1.1.2 "previously breached" check |
|
|
109
110
|
| [`prismjs`](https://prismjs.com/) | 1.30.0 | [Lea Verou + contributors](https://github.com/PrismJS/prism) | Syntax highlighting in the example wiki's code blocks (browser-side) |
|
|
110
111
|
|
|
111
|
-
These libraries are exceptional work — blamejs wouldn't exist without them. All are MIT licensed. Per-package version, license, and provenance live in two manifests: [`lib/vendor/MANIFEST.json`](lib/vendor/MANIFEST.json) for the framework's server-side bundles and [`examples/wiki/public/vendor/MANIFEST.json`](examples/wiki/public/vendor/MANIFEST.json) for the wiki app's browser-side bundle. The framework's [`NOTICE`](NOTICE) file carries the upstream attributions.
|
|
112
|
+
These libraries are exceptional work — blamejs wouldn't exist without them. All are MIT licensed (the SecLists password list is CC-BY-3.0). Per-package version, license, and provenance live in two manifests: [`lib/vendor/MANIFEST.json`](lib/vendor/MANIFEST.json) for the framework's server-side bundles and [`examples/wiki/public/vendor/MANIFEST.json`](examples/wiki/public/vendor/MANIFEST.json) for the wiki app's browser-side bundle. The framework's [`NOTICE`](NOTICE) file carries the upstream attributions.
|
|
112
113
|
|
|
113
114
|
## Why "blamejs"
|
|
114
115
|
|
package/index.js
CHANGED
|
@@ -159,6 +159,12 @@ var seeders = require("./lib/seeders");
|
|
|
159
159
|
var i18n = require("./lib/i18n");
|
|
160
160
|
var notify = require("./lib/notify");
|
|
161
161
|
var testing = require("./lib/testing");
|
|
162
|
+
var configDrift = require("./lib/config-drift");
|
|
163
|
+
var security = require("./lib/security-assert");
|
|
164
|
+
var fileType = require("./lib/file-type");
|
|
165
|
+
var dualControl = require("./lib/dual-control");
|
|
166
|
+
var retention = require("./lib/retention");
|
|
167
|
+
var network = require("./lib/network");
|
|
162
168
|
|
|
163
169
|
module.exports = {
|
|
164
170
|
crypto: crypto,
|
|
@@ -266,6 +272,12 @@ module.exports = {
|
|
|
266
272
|
i18n: i18n,
|
|
267
273
|
notify: notify,
|
|
268
274
|
testing: testing,
|
|
275
|
+
configDrift: configDrift,
|
|
276
|
+
security: security,
|
|
277
|
+
fileType: fileType,
|
|
278
|
+
dualControl: dualControl,
|
|
279
|
+
retention: retention,
|
|
280
|
+
network: network,
|
|
269
281
|
ntpCheck: ntpCheck,
|
|
270
282
|
version: constants.version,
|
|
271
283
|
};
|
package/lib/api-key.js
CHANGED
|
@@ -63,6 +63,7 @@ var cryptoField = require("./crypto-field");
|
|
|
63
63
|
var requestHelpers = require("./request-helpers");
|
|
64
64
|
var validateOpts = require("./validate-opts");
|
|
65
65
|
var C = require("./constants");
|
|
66
|
+
var numericChecks = require("./numeric-checks");
|
|
66
67
|
var { ApiKeyError } = require("./framework-error");
|
|
67
68
|
|
|
68
69
|
var observability = lazyRequire(function () { return require("./observability"); });
|
|
@@ -129,9 +130,7 @@ var DEFAULTS = Object.freeze({
|
|
|
129
130
|
|
|
130
131
|
// ---- Config-time validation helpers (throw on bad input) ----
|
|
131
132
|
|
|
132
|
-
|
|
133
|
-
return typeof n === "number" && isFinite(n) && n >= 1 && Math.floor(n) === n;
|
|
134
|
-
}
|
|
133
|
+
var _isPositiveInt = numericChecks.isPositiveInt;
|
|
135
134
|
|
|
136
135
|
function _validateIdentifier(name, value) {
|
|
137
136
|
if (typeof value !== "string" || value.length === 0) {
|
package/lib/audit.js
CHANGED
|
@@ -203,13 +203,17 @@ var FRAMEWORK_NAMESPACES = [
|
|
|
203
203
|
"backup", // b.backup
|
|
204
204
|
"breakglass", // b.breakGlass — column-policy / row-enforcement step-up auth (audit namespace lowercased per the validator's `namespace.verb` rule, same convention as b.apiKey → apikey.*)
|
|
205
205
|
"cache", // b.cache
|
|
206
|
+
"config", // b.configDrift (config.baseline.captured / config.drift.detected / config.baseline.tamper / config.baseline.unreadable)
|
|
206
207
|
"db", // b.db / b.middleware.dbRoleFor / b.externalDb.runAs
|
|
207
208
|
// (role-switching, RLS-shaped events)
|
|
208
209
|
"dkim", // b.mail.dkim (DKIM-Signature generation events)
|
|
210
|
+
"dual", // b.dualControl (dual.grant.requested / approved / denied / consumed / expired / self_approval_denied)
|
|
209
211
|
"mail", // b.mail (b.mail-bounce uses "system.mail.*")
|
|
212
|
+
"network", // b.middleware.networkAllowlist (network.gate.denied)
|
|
210
213
|
"notify", // b.notify
|
|
211
214
|
"permissions", // b.permissions
|
|
212
215
|
"restore", // b.restore
|
|
216
|
+
"retention", // b.retention (retention.rule.declared / sweep.started / row.processed / sweep.completed / sweep.failed)
|
|
213
217
|
"scheduler", // b.scheduler (lifecycle: scheduler.start / scheduler.stop;
|
|
214
218
|
// tick/task events use "system.scheduler.*")
|
|
215
219
|
"seeders", // b.seeders
|