@blamejs/core 0.8.42 → 0.8.49
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 +93 -0
- package/README.md +10 -10
- package/index.js +52 -0
- package/lib/a2a.js +159 -34
- package/lib/acme.js +762 -0
- package/lib/ai-pref.js +166 -43
- package/lib/api-key.js +108 -47
- package/lib/api-snapshot.js +157 -40
- package/lib/app-shutdown.js +113 -77
- package/lib/archive.js +337 -40
- package/lib/arg-parser.js +697 -0
- package/lib/asyncapi.js +99 -55
- package/lib/atomic-file.js +465 -104
- package/lib/audit-chain.js +123 -34
- package/lib/audit-daily-review.js +389 -0
- package/lib/audit-sign.js +302 -56
- package/lib/audit-tools.js +412 -63
- package/lib/audit.js +656 -35
- package/lib/auth/jwt-external.js +17 -0
- package/lib/auth/oauth.js +7 -0
- package/lib/auth-bot-challenge.js +505 -0
- package/lib/auth-header.js +92 -25
- package/lib/backup/bundle.js +26 -0
- package/lib/backup/index.js +512 -89
- package/lib/backup/manifest.js +168 -7
- package/lib/break-glass.js +415 -39
- package/lib/budr.js +103 -30
- package/lib/bundler.js +86 -66
- package/lib/cache.js +192 -72
- package/lib/chain-writer.js +65 -40
- package/lib/circuit-breaker.js +56 -33
- package/lib/cli-helpers.js +106 -75
- package/lib/cli.js +6 -30
- package/lib/cloud-events.js +99 -32
- package/lib/cluster-storage.js +162 -37
- package/lib/cluster.js +340 -49
- package/lib/codepoint-class.js +66 -0
- package/lib/compliance.js +424 -24
- package/lib/config-drift.js +111 -46
- package/lib/config.js +94 -40
- package/lib/consent.js +165 -18
- package/lib/constants.js +1 -0
- package/lib/content-credentials.js +153 -48
- package/lib/cookies.js +154 -62
- package/lib/credential-hash.js +133 -61
- package/lib/crypto-field.js +702 -18
- package/lib/crypto-hpke.js +256 -0
- package/lib/crypto.js +744 -22
- package/lib/csv.js +178 -35
- package/lib/daemon.js +456 -0
- package/lib/dark-patterns.js +186 -55
- package/lib/db-query.js +79 -2
- package/lib/db.js +1431 -60
- package/lib/ddl-change-control.js +523 -0
- package/lib/deprecate.js +195 -40
- package/lib/dev.js +82 -39
- package/lib/dora.js +67 -48
- package/lib/dr-runbook.js +368 -0
- package/lib/dsr.js +142 -11
- package/lib/dual-control.js +91 -56
- package/lib/events.js +120 -41
- package/lib/external-db-migrate.js +192 -2
- package/lib/external-db.js +795 -50
- package/lib/fapi2.js +122 -1
- package/lib/fda-21cfr11.js +395 -0
- package/lib/fdx.js +132 -2
- package/lib/file-type.js +87 -0
- package/lib/file-upload.js +93 -0
- package/lib/flag.js +82 -20
- package/lib/forms.js +132 -29
- package/lib/framework-error.js +169 -0
- package/lib/framework-schema.js +163 -35
- package/lib/gate-contract.js +849 -175
- package/lib/graphql-federation.js +68 -7
- package/lib/guard-all.js +172 -55
- package/lib/guard-archive.js +286 -124
- package/lib/guard-auth.js +194 -21
- package/lib/guard-cidr.js +190 -28
- package/lib/guard-csv.js +397 -51
- package/lib/guard-domain.js +213 -91
- package/lib/guard-email.js +236 -29
- package/lib/guard-filename.js +307 -75
- package/lib/guard-graphql.js +263 -30
- package/lib/guard-html.js +310 -116
- package/lib/guard-image.js +243 -30
- package/lib/guard-json.js +260 -54
- package/lib/guard-jsonpath.js +235 -23
- package/lib/guard-jwt.js +284 -30
- package/lib/guard-markdown.js +204 -22
- package/lib/guard-mime.js +190 -26
- package/lib/guard-oauth.js +277 -28
- package/lib/guard-pdf.js +251 -27
- package/lib/guard-regex.js +226 -18
- package/lib/guard-shell.js +229 -26
- package/lib/guard-svg.js +177 -10
- package/lib/guard-template.js +232 -21
- package/lib/guard-time.js +195 -29
- package/lib/guard-uuid.js +189 -30
- package/lib/guard-xml.js +259 -36
- package/lib/guard-yaml.js +241 -44
- package/lib/honeytoken.js +63 -27
- package/lib/html-balance.js +83 -0
- package/lib/http-client.js +486 -59
- package/lib/http-message-signature.js +582 -0
- package/lib/i18n.js +102 -49
- package/lib/iab-mspa.js +112 -32
- package/lib/iab-tcf.js +107 -2
- package/lib/inbox.js +90 -52
- package/lib/keychain.js +865 -0
- package/lib/legal-hold.js +374 -0
- package/lib/local-db-thin.js +320 -0
- package/lib/log-stream.js +281 -51
- package/lib/log.js +184 -86
- package/lib/mail-bounce.js +107 -62
- package/lib/mail.js +295 -58
- package/lib/mcp.js +108 -27
- package/lib/metrics.js +98 -89
- package/lib/middleware/age-gate.js +36 -0
- package/lib/middleware/ai-act-disclosure.js +37 -0
- package/lib/middleware/api-encrypt.js +45 -0
- package/lib/middleware/assetlinks.js +40 -0
- package/lib/middleware/asyncapi-serve.js +35 -0
- package/lib/middleware/attach-user.js +40 -0
- package/lib/middleware/bearer-auth.js +40 -0
- package/lib/middleware/body-parser.js +230 -0
- package/lib/middleware/bot-disclose.js +34 -0
- package/lib/middleware/bot-guard.js +39 -0
- package/lib/middleware/compression.js +37 -0
- package/lib/middleware/cookies.js +32 -0
- package/lib/middleware/cors.js +40 -0
- package/lib/middleware/csp-nonce.js +40 -0
- package/lib/middleware/csp-report.js +34 -0
- package/lib/middleware/csrf-protect.js +43 -0
- package/lib/middleware/daily-byte-quota.js +53 -85
- package/lib/middleware/db-role-for.js +40 -0
- package/lib/middleware/dpop.js +40 -0
- package/lib/middleware/error-handler.js +37 -14
- package/lib/middleware/fetch-metadata.js +39 -0
- package/lib/middleware/flag-context.js +34 -0
- package/lib/middleware/gpc.js +33 -0
- package/lib/middleware/headers.js +35 -0
- package/lib/middleware/health.js +46 -0
- package/lib/middleware/host-allowlist.js +30 -0
- package/lib/middleware/network-allowlist.js +38 -0
- package/lib/middleware/openapi-serve.js +34 -0
- package/lib/middleware/rate-limit.js +160 -18
- package/lib/middleware/request-id.js +36 -18
- package/lib/middleware/request-log.js +37 -0
- package/lib/middleware/require-aal.js +29 -0
- package/lib/middleware/require-auth.js +32 -0
- package/lib/middleware/require-bound-key.js +41 -0
- package/lib/middleware/require-content-type.js +32 -0
- package/lib/middleware/require-methods.js +27 -0
- package/lib/middleware/require-mtls.js +33 -0
- package/lib/middleware/require-step-up.js +37 -0
- package/lib/middleware/security-headers.js +44 -0
- package/lib/middleware/security-txt.js +38 -0
- package/lib/middleware/span-http-server.js +37 -0
- package/lib/middleware/sse.js +36 -0
- package/lib/middleware/trace-log-correlation.js +33 -0
- package/lib/middleware/trace-propagate.js +32 -0
- package/lib/middleware/tus-upload.js +90 -0
- package/lib/middleware/web-app-manifest.js +53 -0
- package/lib/mtls-ca.js +100 -70
- package/lib/network-byte-quota.js +308 -0
- package/lib/network-heartbeat.js +135 -0
- package/lib/network-tls.js +534 -4
- package/lib/network.js +103 -0
- package/lib/notify.js +114 -43
- package/lib/ntp-check.js +192 -51
- package/lib/observability.js +145 -47
- package/lib/openapi.js +90 -44
- package/lib/outbox.js +99 -1
- package/lib/pagination.js +168 -86
- package/lib/parsers/index.js +16 -5
- package/lib/permissions.js +93 -40
- package/lib/pqc-agent.js +84 -8
- package/lib/pqc-software.js +94 -60
- package/lib/process-spawn.js +95 -21
- package/lib/pubsub.js +96 -66
- package/lib/queue.js +375 -54
- package/lib/redact.js +793 -21
- package/lib/render.js +139 -47
- package/lib/request-helpers.js +485 -121
- package/lib/restore-bundle.js +142 -39
- package/lib/restore-rollback.js +136 -45
- package/lib/retention.js +178 -50
- package/lib/retry.js +116 -33
- package/lib/router.js +475 -23
- package/lib/safe-async.js +543 -94
- package/lib/safe-buffer.js +337 -41
- package/lib/safe-json.js +467 -62
- package/lib/safe-jsonpath.js +285 -0
- package/lib/safe-schema.js +631 -87
- package/lib/safe-sql.js +221 -59
- package/lib/safe-url.js +278 -46
- package/lib/sandbox-worker.js +135 -0
- package/lib/sandbox.js +358 -0
- package/lib/scheduler.js +135 -70
- package/lib/self-update.js +647 -0
- package/lib/session-device-binding.js +431 -0
- package/lib/session.js +259 -49
- package/lib/slug.js +138 -26
- package/lib/ssrf-guard.js +316 -56
- package/lib/storage.js +433 -70
- package/lib/subject.js +405 -23
- package/lib/template.js +148 -8
- package/lib/tenant-quota.js +545 -0
- package/lib/testing.js +440 -53
- package/lib/time.js +291 -23
- package/lib/tls-exporter.js +239 -0
- package/lib/tracing.js +90 -74
- package/lib/uuid.js +97 -22
- package/lib/vault/index.js +284 -22
- package/lib/vault/seal-pem-file.js +66 -0
- package/lib/watcher.js +368 -0
- package/lib/webhook.js +196 -63
- package/lib/websocket.js +393 -68
- package/lib/wiki-concepts.js +338 -0
- package/lib/worker-pool.js +464 -0
- package/package.json +3 -3
- package/sbom.cyclonedx.json +7 -7
package/lib/guard-json.js
CHANGED
|
@@ -1,70 +1,73 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* @module b.guardJson
|
|
4
|
+
* @nav Guards
|
|
5
|
+
* @title Guard Json
|
|
4
6
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
11
|
-
* - CVE-2025-13465 Lodash prototype-chain path traversal
|
|
12
|
-
* - CVE-2025-25014 Kibana prototype pollution → RCE
|
|
13
|
-
* - CVE-2024-38984 json-override prototype pollution
|
|
14
|
-
* - CVE-2022-42743 deep-parse-json prototype pollution
|
|
15
|
-
* - GHSA-9c47-m6qq-7p4h JSON5 prototype pollution via parse method
|
|
7
|
+
* @intro
|
|
8
|
+
* JSON content-safety guard — defends against the threat catalog
|
|
9
|
+
* operators face when accepting JSON sourced from user input.
|
|
10
|
+
* `b.safeJson.parse` enforces baseline depth + size caps; this
|
|
11
|
+
* module layers prototype-pollution / depth-bomb / key-count /
|
|
12
|
+
* duplicate-key / unicode threat detection on top.
|
|
16
13
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
14
|
+
* Prototype-pollution defense: keys `__proto__` / `constructor` /
|
|
15
|
+
* `prototype` anywhere in the tree are detected at the SOURCE level
|
|
16
|
+
* (before any parser sees them). After `JSON.parse` normalizes the
|
|
17
|
+
* input, `__proto__` routes through the prototype setter and is
|
|
18
|
+
* invisible to `Object.keys()`, so a post-parse tree walk misses
|
|
19
|
+
* the pollution shape — the source-text scan catches it. CVE
|
|
20
|
+
* coverage spans the 2025-2026 deserialization + prototype-
|
|
21
|
+
* pollution wave: CVE-2025-55182 React Server Functions RCE,
|
|
22
|
+
* CVE-2025-57820 / CVE-2026-30226 Svelte devalue, CVE-2026-35209
|
|
23
|
+
* defu, CVE-2026-28794 @orpc/client, CVE-2025-13465 Lodash path
|
|
24
|
+
* traversal, CVE-2025-25014 Kibana, CVE-2024-38984 json-override,
|
|
25
|
+
* CVE-2022-42743 deep-parse-json, GHSA-9c47-m6qq-7p4h JSON5.
|
|
20
26
|
*
|
|
21
|
-
*
|
|
27
|
+
* Depth + breadth caps: `maxDepth` / `maxKeysPerObject` /
|
|
28
|
+
* `maxArrayLength` / `maxStringLength` / `maxTotalNodes` refuse
|
|
29
|
+
* key-count bombs (10^6 keys per object) and stack-exhaustion
|
|
30
|
+
* nesting attacks under strict.
|
|
22
31
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
32
|
+
* Duplicate-key smuggling: RFC 8259 says keys SHOULD be unique;
|
|
33
|
+
* `JSON.parse` silently last-wins. A two-validator pipeline that
|
|
34
|
+
* inspects the first occurrence and trusts the parser's last-wins
|
|
35
|
+
* value is the smuggling shape; this guard rescans the source for
|
|
36
|
+
* identical quoted keys at the same `{ ... }` nesting level.
|
|
26
37
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
38
|
+
* JSON5 / JSONC quirks (single-line `//` + block C-style
|
|
39
|
+
* comments, trailing commas, NaN / Infinity / -Infinity, hex
|
|
40
|
+
* literals, single-quoted keys) — RFC 8259 forbids these but
|
|
41
|
+
* lenient parsers accept; the guard flags them at the source so
|
|
42
|
+
* operators can refuse hostile inputs regardless of which parser
|
|
43
|
+
* is downstream.
|
|
31
44
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
45
|
+
* Numeric precision loss: integers above `Number.MAX_SAFE_INTEGER`
|
|
46
|
+
* (~9.007 x 10^15, 16 digits) silently lose precision when round-
|
|
47
|
+
* tripped through Number. Detected via raw-text scan for digit
|
|
48
|
+
* runs of 17+ characters.
|
|
34
49
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
50
|
+
* BOM injection (leading or mid-stream U+FEFF) and bidi / null /
|
|
51
|
+
* control / zero-width character threats route through the shared
|
|
52
|
+
* lib/codepoint-class catalog — the same detector backing the
|
|
53
|
+
* guard-csv / guard-html / guard-svg families.
|
|
37
54
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
55
|
+
* Top-level-key allowlist: when the operator opts in via
|
|
56
|
+
* `topLevelKeyAllowlist: ["alpha", "beta"]`, every other top-level
|
|
57
|
+
* key triggers a refused-shape issue. Useful for HTTP body schemas
|
|
58
|
+
* where unexpected keys signal malformed or hostile input.
|
|
42
59
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
60
|
+
* Profiles: `strict` / `balanced` / `permissive`. Compliance
|
|
61
|
+
* postures: `hipaa` / `pci-dss` / `gdpr` / `soc2`. Operators select
|
|
62
|
+
* via `{ profile: "strict" }` or `{ compliance: "hipaa" }`;
|
|
63
|
+
* postures overlay on top of the profile baseline.
|
|
45
64
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
65
|
+
* Source files MUST be pure ASCII; threat-detection regexes
|
|
66
|
+
* compose programmatically via lib/codepoint-class so the source
|
|
67
|
+
* never embeds the attack characters themselves.
|
|
48
68
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* 9. BOM injection — leading or mid-stream U+FEFF.
|
|
52
|
-
*
|
|
53
|
-
* 10. Bidi / null / control chars in string values — same codepoint
|
|
54
|
-
* catalog as guard-csv/html/svg via lib/codepoint-class.
|
|
55
|
-
*
|
|
56
|
-
* 11. Numeric precision loss — values above
|
|
57
|
-
* `Number.MAX_SAFE_INTEGER` silently lose precision when round-
|
|
58
|
-
* tripped through Number. Detected via raw-text scan for digit
|
|
59
|
-
* runs longer than safe-int width.
|
|
60
|
-
*
|
|
61
|
-
* 12. Total size cap (anti-DoS).
|
|
62
|
-
*
|
|
63
|
-
* 13. Top-level-key allowlist — strict profile requires the operator
|
|
64
|
-
* to declare allowed top-level keys; balanced/permissive skip.
|
|
65
|
-
*
|
|
66
|
-
* Source files MUST be pure ASCII per the codepoint-table programmatic
|
|
67
|
-
* regex pattern; threat-detection regexes use lib/codepoint-class.
|
|
69
|
+
* @card
|
|
70
|
+
* JSON content-safety guard — defends against the threat catalog operators face when accepting JSON sourced from user input.
|
|
68
71
|
*/
|
|
69
72
|
|
|
70
73
|
var codepointClass = require("./codepoint-class");
|
|
@@ -558,6 +561,61 @@ function _stripPollutionTree(value, opts, depth) {
|
|
|
558
561
|
|
|
559
562
|
// ---- Public surface ----
|
|
560
563
|
|
|
564
|
+
/**
|
|
565
|
+
* @primitive b.guardJson.validate
|
|
566
|
+
* @signature b.guardJson.validate(input, opts?)
|
|
567
|
+
* @since 0.7.13
|
|
568
|
+
* @status stable
|
|
569
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
570
|
+
* @related b.guardJson.parse, b.guardJson.gate, b.safeJson.parse
|
|
571
|
+
*
|
|
572
|
+
* Inspect `input` (string of JSON source) for the full guard-json
|
|
573
|
+
* threat catalog without committing to a parsed value. Returns
|
|
574
|
+
* `{ ok, issues, severities }` where `issues` is the aggregated
|
|
575
|
+
* detector output — every prototype-pollution key, depth/breadth
|
|
576
|
+
* cap hit, duplicate-key smuggle, JSON5-quirk match, BOM placement,
|
|
577
|
+
* unicode threat, and numeric-precision-loss candidate is reported
|
|
578
|
+
* with `kind` / `severity` / `ruleId` / `snippet`. Profile-driven
|
|
579
|
+
* (`strict` / `balanced` / `permissive`) and posture-driven
|
|
580
|
+
* (`hipaa` / `pci-dss` / `gdpr` / `soc2`).
|
|
581
|
+
*
|
|
582
|
+
* Detection runs in two passes: a raw-source scan (BOM placement,
|
|
583
|
+
* comments, NaN/Infinity, trailing commas, JSON5 quirks, source-
|
|
584
|
+
* level prototype-pollution keys, codepoint-class threats) followed
|
|
585
|
+
* by a parsed-tree walk (depth / breadth / array-length / string-
|
|
586
|
+
* length / node-count caps, duplicate-key rescan).
|
|
587
|
+
*
|
|
588
|
+
* @opts
|
|
589
|
+
* profile: "strict"|"balanced"|"permissive",
|
|
590
|
+
* compliance: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
591
|
+
* pollutionPolicy: "reject"|"strip"|"audit"|"allow",
|
|
592
|
+
* duplicateKeyPolicy: "reject"|"audit"|"allow",
|
|
593
|
+
* nanInfinityPolicy: "reject"|"audit"|"allow",
|
|
594
|
+
* commentPolicy: "reject"|"audit"|"allow",
|
|
595
|
+
* trailingCommaPolicy: "reject"|"audit"|"allow",
|
|
596
|
+
* json5SyntaxPolicy: "reject"|"audit"|"allow",
|
|
597
|
+
* bomPolicy: "reject"|"strip"|"allow",
|
|
598
|
+
* bidiPolicy: "reject"|"strip"|"audit"|"allow",
|
|
599
|
+
* controlPolicy: "reject"|"strip"|"allow",
|
|
600
|
+
* nullBytePolicy: "reject"|"strip"|"allow",
|
|
601
|
+
* zeroWidthPolicy: "reject"|"strip"|"audit"|"allow",
|
|
602
|
+
* numericPrecisionPolicy: "reject"|"audit"|"allow",
|
|
603
|
+
* requireTopLevelKeyAllowlist: boolean,
|
|
604
|
+
* topLevelKeyAllowlist: string[]|null,
|
|
605
|
+
* maxBytes: number, // total source byte cap
|
|
606
|
+
* maxDepth: number, // recursion depth cap
|
|
607
|
+
* maxKeysPerObject: number, // breadth cap per object
|
|
608
|
+
* maxArrayLength: number, // array length cap
|
|
609
|
+
* maxStringLength: number, // string length cap
|
|
610
|
+
* maxTotalNodes: number, // total node count cap
|
|
611
|
+
*
|
|
612
|
+
* @example
|
|
613
|
+
* var rv = b.guardJson.validate('{"__proto__":{"polluted":true}}', {
|
|
614
|
+
* profile: "strict",
|
|
615
|
+
* });
|
|
616
|
+
* rv.ok; // → false
|
|
617
|
+
* rv.issues.some(function (i) { return i.kind === "prototype-pollution-key"; }); // → true
|
|
618
|
+
*/
|
|
561
619
|
function validate(input, opts) {
|
|
562
620
|
opts = _resolveOpts(opts);
|
|
563
621
|
numericBounds.requireAllPositiveFiniteIntIfPresent(opts,
|
|
@@ -574,6 +632,48 @@ function validate(input, opts) {
|
|
|
574
632
|
return gateContract.aggregateIssues(_detectIssues(input, opts));
|
|
575
633
|
}
|
|
576
634
|
|
|
635
|
+
/**
|
|
636
|
+
* @primitive b.guardJson.parse
|
|
637
|
+
* @signature b.guardJson.parse(input, opts?)
|
|
638
|
+
* @since 0.7.13
|
|
639
|
+
* @status stable
|
|
640
|
+
* @related b.guardJson.validate, b.guardJson.gate, b.safeJson.parse
|
|
641
|
+
*
|
|
642
|
+
* Parse `input` (string of JSON source) into a JavaScript value
|
|
643
|
+
* after the guard-json threat catalog clears. Refuses on prototype-
|
|
644
|
+
* pollution keys when `pollutionPolicy === "reject"`, refuses on any
|
|
645
|
+
* critical raw-source pre-parse threat, refuses on parse failure,
|
|
646
|
+
* and otherwise routes through `b.safeJson.parse` with the configured
|
|
647
|
+
* `maxBytes` / `maxDepth` caps. Strip policies (`bomPolicy: "strip"`,
|
|
648
|
+
* `controlPolicy: "strip"`, `zeroWidthPolicy: "strip"`) silently
|
|
649
|
+
* remove the offending characters from the source before parsing.
|
|
650
|
+
*
|
|
651
|
+
* Pollution keys (`__proto__` / `constructor` / `prototype`) are
|
|
652
|
+
* normally invisible to `Object.keys()` after `JSON.parse` because
|
|
653
|
+
* they route through prototype setters; the parse path passes
|
|
654
|
+
* `allowProto: true` to `b.safeJson.parse` only when policy is
|
|
655
|
+
* `audit` / `allow`, ensuring strip / reject paths produce a tree
|
|
656
|
+
* with no pollution-key residue.
|
|
657
|
+
*
|
|
658
|
+
* Throws `GuardJsonError` on refusal — the error code matches the
|
|
659
|
+
* triggering rule (`json.prototype-pollution`, `json.parse`, etc.).
|
|
660
|
+
*
|
|
661
|
+
* @opts
|
|
662
|
+
* profile: "strict"|"balanced"|"permissive",
|
|
663
|
+
* compliance: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
664
|
+
* pollutionPolicy: "reject"|"strip"|"audit"|"allow",
|
|
665
|
+
* bomPolicy: "reject"|"strip"|"allow",
|
|
666
|
+
* controlPolicy: "reject"|"strip"|"allow",
|
|
667
|
+
* zeroWidthPolicy: "reject"|"strip"|"audit"|"allow",
|
|
668
|
+
* maxBytes: number, maxDepth: number,
|
|
669
|
+
*
|
|
670
|
+
* @example
|
|
671
|
+
* var safe = b.guardJson.parse('{"name":"alice","age":30}', {
|
|
672
|
+
* profile: "strict",
|
|
673
|
+
* });
|
|
674
|
+
* safe.name; // → "alice"
|
|
675
|
+
* safe.age; // → 30
|
|
676
|
+
*/
|
|
577
677
|
function parse(input, opts) {
|
|
578
678
|
opts = _resolveOpts(opts);
|
|
579
679
|
if (typeof input !== "string") {
|
|
@@ -643,6 +743,42 @@ function _policyKeyForRuleId(ruleId) {
|
|
|
643
743
|
return map[ruleId] || null;
|
|
644
744
|
}
|
|
645
745
|
|
|
746
|
+
/**
|
|
747
|
+
* @primitive b.guardJson.gate
|
|
748
|
+
* @signature b.guardJson.gate(opts?)
|
|
749
|
+
* @since 0.7.13
|
|
750
|
+
* @status stable
|
|
751
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
752
|
+
* @related b.guardJson.validate, b.guardJson.parse, b.staticServe.create, b.fileUpload.create
|
|
753
|
+
*
|
|
754
|
+
* Build a `b.gateContract` gate suitable for plugging into
|
|
755
|
+
* `b.staticServe({ contentSafety: { ".json": gate } })`,
|
|
756
|
+
* `b.fileUpload({ contentSafety: { "application/json": gate } })`,
|
|
757
|
+
* or any host primitive that consumes the gate-contract shape.
|
|
758
|
+
* Action chain on validation: `serve` (no issues) → `audit-only`
|
|
759
|
+
* (warn-only issues) → `sanitize` (high/critical but every reject-
|
|
760
|
+
* policy is off — re-parse + re-emit a cleaned tree via
|
|
761
|
+
* `JSON.stringify`) → `refuse` (critical/high under any reject
|
|
762
|
+
* policy, or sanitize threw).
|
|
763
|
+
*
|
|
764
|
+
* Sanitize-eligibility requires every policy in the reject set
|
|
765
|
+
* (`pollutionPolicy` / `duplicateKeyPolicy` / `nanInfinityPolicy` /
|
|
766
|
+
* `commentPolicy` / `trailingCommaPolicy` / `json5SyntaxPolicy` /
|
|
767
|
+
* `bomPolicy` / `bidiPolicy` / `controlPolicy` / `nullBytePolicy`)
|
|
768
|
+
* to be off; under strict every one is `"reject"` so the gate jumps
|
|
769
|
+
* straight from `audit-only` to `refuse`.
|
|
770
|
+
*
|
|
771
|
+
* @opts
|
|
772
|
+
* profile: "strict"|"balanced"|"permissive",
|
|
773
|
+
* compliance: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
774
|
+
* name: string, // gate identity for audit / observability
|
|
775
|
+
*
|
|
776
|
+
* @example
|
|
777
|
+
* var jsonGate = b.guardJson.gate({ profile: "strict" });
|
|
778
|
+
* var hostile = Buffer.from('{"__proto__":{"x":1}}', "utf8");
|
|
779
|
+
* var verdict = await jsonGate.check({ bytes: hostile });
|
|
780
|
+
* verdict.action; // → "refuse"
|
|
781
|
+
*/
|
|
646
782
|
function gate(opts) {
|
|
647
783
|
opts = _resolveOpts(opts);
|
|
648
784
|
return gateContract.buildGuardGate(
|
|
@@ -684,13 +820,83 @@ function gate(opts) {
|
|
|
684
820
|
});
|
|
685
821
|
}
|
|
686
822
|
|
|
823
|
+
/**
|
|
824
|
+
* @primitive b.guardJson.buildProfile
|
|
825
|
+
* @signature b.guardJson.buildProfile(opts)
|
|
826
|
+
* @since 0.7.13
|
|
827
|
+
* @status stable
|
|
828
|
+
* @related b.guardJson.gate, b.guardJson.compliancePosture
|
|
829
|
+
*
|
|
830
|
+
* Compose a derived profile from one or more named bases plus
|
|
831
|
+
* inline overrides. `opts.extends` is a profile name (`"strict"` /
|
|
832
|
+
* `"balanced"` / `"permissive"`) or an array of names; later entries
|
|
833
|
+
* shadow earlier ones. Inline `opts` keys win last. Used to keep
|
|
834
|
+
* operator-defined profiles traceable to a baseline rather than re-
|
|
835
|
+
* typing every key.
|
|
836
|
+
*
|
|
837
|
+
* @opts
|
|
838
|
+
* extends: string|string[], // base profile name(s) to compose
|
|
839
|
+
* ...: any guard-json key, // inline override of resolved keys
|
|
840
|
+
*
|
|
841
|
+
* @example
|
|
842
|
+
* var custom = b.guardJson.buildProfile({
|
|
843
|
+
* extends: "balanced",
|
|
844
|
+
* pollutionPolicy: "reject",
|
|
845
|
+
* maxDepth: 16,
|
|
846
|
+
* });
|
|
847
|
+
* custom.pollutionPolicy; // → "reject"
|
|
848
|
+
* custom.maxDepth; // → 16
|
|
849
|
+
*/
|
|
687
850
|
var buildProfile = gateContract.makeProfileBuilder(PROFILES);
|
|
688
851
|
|
|
852
|
+
/**
|
|
853
|
+
* @primitive b.guardJson.compliancePosture
|
|
854
|
+
* @signature b.guardJson.compliancePosture(name)
|
|
855
|
+
* @since 0.7.13
|
|
856
|
+
* @status stable
|
|
857
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
858
|
+
* @related b.guardJson.gate, b.guardJson.buildProfile
|
|
859
|
+
*
|
|
860
|
+
* Look up a compliance-posture overlay by name (`"hipaa"` /
|
|
861
|
+
* `"pci-dss"` / `"gdpr"` / `"soc2"`). Returns a shallow clone of the
|
|
862
|
+
* posture object — the caller may mutate freely. Throws
|
|
863
|
+
* `GuardJsonError("json.bad-posture")` on unknown name.
|
|
864
|
+
*
|
|
865
|
+
* @example
|
|
866
|
+
* var posture = b.guardJson.compliancePosture("hipaa");
|
|
867
|
+
* posture.pollutionPolicy; // → "reject"
|
|
868
|
+
* posture.forensicSnippetBytes; // → 256
|
|
869
|
+
*/
|
|
689
870
|
function compliancePosture(name) {
|
|
690
871
|
return gateContract.lookupCompliancePosture(name, COMPLIANCE_POSTURES, _err, "json");
|
|
691
872
|
}
|
|
692
873
|
|
|
693
874
|
var _jsonRulePacks = gateContract.makeRulePackLoader(GuardJsonError, "json");
|
|
875
|
+
/**
|
|
876
|
+
* @primitive b.guardJson.loadRulePack
|
|
877
|
+
* @signature b.guardJson.loadRulePack(pack)
|
|
878
|
+
* @since 0.7.13
|
|
879
|
+
* @status stable
|
|
880
|
+
* @related b.guardJson.gate
|
|
881
|
+
*
|
|
882
|
+
* Register an operator-supplied rule pack with the guard-json
|
|
883
|
+
* registry. The pack is identified by `pack.id` (non-empty string)
|
|
884
|
+
* and stored for later inspection / dispatch by gates that opt in
|
|
885
|
+
* via `opts.rulePackId`. Returns the pack object unchanged on
|
|
886
|
+
* success; throws `GuardJsonError("json.bad-opt")` when `pack` is
|
|
887
|
+
* missing or `pack.id` is not a non-empty string.
|
|
888
|
+
*
|
|
889
|
+
* @example
|
|
890
|
+
* var pack = b.guardJson.loadRulePack({
|
|
891
|
+
* id: "tenant-keys",
|
|
892
|
+
* rules: [
|
|
893
|
+
* { id: "tenant-id-shape", severity: "high",
|
|
894
|
+
* detect: function (tree) { return !tree || typeof tree.tenantId !== "string"; },
|
|
895
|
+
* reason: "tenantId must be a string at top level" },
|
|
896
|
+
* ],
|
|
897
|
+
* });
|
|
898
|
+
* pack.id; // → "tenant-keys"
|
|
899
|
+
*/
|
|
694
900
|
var loadRulePack = _jsonRulePacks.load;
|
|
695
901
|
|
|
696
902
|
module.exports = {
|
package/lib/guard-jsonpath.js
CHANGED
|
@@ -1,30 +1,53 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* @module b.guardJsonpath
|
|
4
|
+
* @nav Guards
|
|
5
|
+
* @title Guard Jsonpath
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* @intro
|
|
8
|
+
* JSONPath content-safety guard — refuses user-supplied JSONPath
|
|
9
|
+
* query strings that exhibit dynamic-code-execution shapes BEFORE
|
|
10
|
+
* they reach a JSONPath evaluator. Many JSONPath implementations
|
|
11
|
+
* (the original Stefan Goessner reference and several JS forks)
|
|
12
|
+
* route filter / script expressions through `eval`-class
|
|
13
|
+
* dispatch, turning a query path into an RCE primitive; this
|
|
14
|
+
* primitive screens the path so a hostile query can't escape into
|
|
15
|
+
* code execution. KIND=`identifier`; the gate consumes
|
|
16
|
+
* `ctx.identifier` (or `ctx.jsonpath`) and refuses on hostile
|
|
17
|
+
* shapes. Targets the RFC 9535 compliant subset — filter / script
|
|
18
|
+
* expressions with code-execution semantics are rejected at every
|
|
19
|
+
* profile.
|
|
12
20
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* -
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
21
|
+
* Threat catalog: filter expression `?(...)` (dynamic-code-
|
|
22
|
+
* execution class in legacy implementations — refused
|
|
23
|
+
* universally); script expression shape `(@.x)` (RFC 9535
|
|
24
|
+
* undefined but several implementations alias it to filter);
|
|
25
|
+
* JS-source hints (the path contains substrings that only appear
|
|
26
|
+
* in a code-injection attempt — dynamic-code-exec keyword,
|
|
27
|
+
* constructor invocation keyword, function-declaration keyword,
|
|
28
|
+
* arrow-function arrow, or statement-separator semicolon);
|
|
29
|
+
* recursive-descent depth bomb (`..[*]` repeated past
|
|
30
|
+
* `maxRecursiveDescents`); 3+ consecutive `[` parser-DoS shape;
|
|
31
|
+
* per-pattern byte cap; BIDI override / zero-width / C0 control /
|
|
32
|
+
* null-byte universal refuse.
|
|
33
|
+
*
|
|
34
|
+
* Profiles: `strict` / `balanced` / `permissive`. Compliance
|
|
35
|
+
* postures: `hipaa` / `pci-dss` / `gdpr` / `soc2`. Operators
|
|
36
|
+
* select via `{ profile: "strict" }` or
|
|
37
|
+
* `{ compliance: "hipaa" }`; postures overlay on top of the
|
|
38
|
+
* profile baseline. Filter / script / dynamic-hint refusal holds
|
|
39
|
+
* at every profile — the RCE class is never an operator opt-in.
|
|
40
|
+
*
|
|
41
|
+
* JSONPath strings can't be repaired safely — `sanitize` either
|
|
42
|
+
* passes through clean input or throws `GuardJsonpathError`; the
|
|
43
|
+
* gate returns `serve` / `audit-only` / `refuse` (no `sanitize`
|
|
44
|
+
* action). The source file's hint catalog is composed from
|
|
45
|
+
* substring fragments so the file itself stays free of the
|
|
46
|
+
* literal keywords (the codebase-patterns gate flags them
|
|
47
|
+
* otherwise).
|
|
48
|
+
*
|
|
49
|
+
* @card
|
|
50
|
+
* JSONPath content-safety guard — refuses user-supplied JSONPath query strings that exhibit dynamic-code-execution shapes BEFORE they reach a JSONPath evaluator.
|
|
28
51
|
*/
|
|
29
52
|
|
|
30
53
|
var codepointClass = require("./codepoint-class");
|
|
@@ -217,6 +240,46 @@ function _detectIssues(input, opts) {
|
|
|
217
240
|
return issues;
|
|
218
241
|
}
|
|
219
242
|
|
|
243
|
+
/**
|
|
244
|
+
* @primitive b.guardJsonpath.validate
|
|
245
|
+
* @signature b.guardJsonpath.validate(input, opts)
|
|
246
|
+
* @since 0.7.13
|
|
247
|
+
* @status stable
|
|
248
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
249
|
+
* @related b.guardJsonpath.gate, b.guardJsonpath.sanitize
|
|
250
|
+
*
|
|
251
|
+
* Inspect a user-supplied JSONPath string and return an aggregated
|
|
252
|
+
* issue list. Pure inspection — never throws on hostile paths;
|
|
253
|
+
* caller decides what to do with the issues. The `ok` flag is
|
|
254
|
+
* `true` only when zero `critical` / `high` issues fire. Throws
|
|
255
|
+
* `GuardJsonpathError("jsonpath.bad-opt")` when a numeric opt is
|
|
256
|
+
* non-finite / negative (config-time mistake by the operator).
|
|
257
|
+
*
|
|
258
|
+
* @opts
|
|
259
|
+
* profile: "strict"|"balanced"|"permissive",
|
|
260
|
+
* compliance: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
261
|
+
* bidiPolicy: "reject"|"audit"|"allow",
|
|
262
|
+
* controlPolicy: "reject"|"audit"|"allow",
|
|
263
|
+
* nullBytePolicy: "reject"|"audit"|"allow",
|
|
264
|
+
* zeroWidthPolicy: "reject"|"strip"|"audit"|"allow",
|
|
265
|
+
* filterExprPolicy: "reject"|"audit"|"allow",
|
|
266
|
+
* scriptExprPolicy: "reject"|"audit"|"allow",
|
|
267
|
+
* dynamicHintPolicy: "reject"|"audit"|"allow",
|
|
268
|
+
* bracketNestingPolicy: "reject"|"audit"|"allow",
|
|
269
|
+
* recursiveDescentPolicy: "reject"|"audit"|"allow",
|
|
270
|
+
* maxRecursiveDescents: number,
|
|
271
|
+
* maxPatternBytes: number,
|
|
272
|
+
* maxBytes: number,
|
|
273
|
+
* maxRuntimeMs: number,
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* var clean = b.guardJsonpath.validate("$.users[*].name", { profile: "strict" });
|
|
277
|
+
* clean.ok; // → true
|
|
278
|
+
*
|
|
279
|
+
* var hostile = b.guardJsonpath.validate("$..[?(@.x)]", { profile: "strict" });
|
|
280
|
+
* hostile.ok; // → false
|
|
281
|
+
* hostile.issues.some(function (i) { return i.kind === "filter-expression"; }); // → true
|
|
282
|
+
*/
|
|
220
283
|
function validate(input, opts) {
|
|
221
284
|
opts = _resolveOpts(opts);
|
|
222
285
|
numericBounds.requireAllPositiveFiniteIntIfPresent(opts,
|
|
@@ -225,6 +288,45 @@ function validate(input, opts) {
|
|
|
225
288
|
return gateContract.aggregateIssues(_detectIssues(input, opts));
|
|
226
289
|
}
|
|
227
290
|
|
|
291
|
+
/**
|
|
292
|
+
* @primitive b.guardJsonpath.sanitize
|
|
293
|
+
* @signature b.guardJsonpath.sanitize(input, opts)
|
|
294
|
+
* @since 0.7.13
|
|
295
|
+
* @status stable
|
|
296
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
297
|
+
* @related b.guardJsonpath.validate, b.guardJsonpath.gate
|
|
298
|
+
*
|
|
299
|
+
* Pass-through-or-throw. JSONPath expressions cannot be safely
|
|
300
|
+
* repaired (stripping a `?(` from a filter silently changes query
|
|
301
|
+
* semantics); this primitive returns the input unchanged when no
|
|
302
|
+
* `critical` or `high` issue fires, otherwise throws
|
|
303
|
+
* `GuardJsonpathError` with the offending rule id (e.g.
|
|
304
|
+
* `jsonpath.filter-expression`, `jsonpath.dynamic-hint`,
|
|
305
|
+
* `jsonpath.script-expression`). Operators that need a "best-
|
|
306
|
+
* effort cleanup" semantic should reject the path at the boundary
|
|
307
|
+
* instead.
|
|
308
|
+
*
|
|
309
|
+
* @opts
|
|
310
|
+
* profile: "strict"|"balanced"|"permissive",
|
|
311
|
+
* compliance: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
312
|
+
* filterExprPolicy: "reject"|"audit"|"allow",
|
|
313
|
+
* scriptExprPolicy: "reject"|"audit"|"allow",
|
|
314
|
+
* dynamicHintPolicy: "reject"|"audit"|"allow",
|
|
315
|
+
* bracketNestingPolicy: "reject"|"audit"|"allow",
|
|
316
|
+
* recursiveDescentPolicy: "reject"|"audit"|"allow",
|
|
317
|
+
* maxRecursiveDescents: number,
|
|
318
|
+
* maxPatternBytes: number,
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* var safe = b.guardJsonpath.sanitize("$.users[*].name", { profile: "strict" });
|
|
322
|
+
* safe; // → "$.users[*].name"
|
|
323
|
+
*
|
|
324
|
+
* try {
|
|
325
|
+
* b.guardJsonpath.sanitize("$..[?(@.x)]", { profile: "strict" });
|
|
326
|
+
* } catch (e) {
|
|
327
|
+
* e.code; // → "jsonpath.filter-expression"
|
|
328
|
+
* }
|
|
329
|
+
*/
|
|
228
330
|
function sanitize(input, opts) {
|
|
229
331
|
opts = _resolveOpts(opts);
|
|
230
332
|
if (typeof input !== "string") {
|
|
@@ -240,6 +342,46 @@ function sanitize(input, opts) {
|
|
|
240
342
|
return input;
|
|
241
343
|
}
|
|
242
344
|
|
|
345
|
+
/**
|
|
346
|
+
* @primitive b.guardJsonpath.gate
|
|
347
|
+
* @signature b.guardJsonpath.gate(opts)
|
|
348
|
+
* @since 0.7.13
|
|
349
|
+
* @status stable
|
|
350
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
351
|
+
* @related b.guardJsonpath.validate, b.guardJsonpath.sanitize
|
|
352
|
+
*
|
|
353
|
+
* Build a `b.gateContract` gate that screens `ctx.identifier` (or
|
|
354
|
+
* `ctx.jsonpath`) before the path reaches a JSONPath evaluator.
|
|
355
|
+
* Action chain: `serve` (no issues) → `audit-only` (warn-only) →
|
|
356
|
+
* `refuse` (any `critical` or `high`). No `sanitize` action —
|
|
357
|
+
* JSONPath strings cannot be repaired. Compose into query
|
|
358
|
+
* endpoints / search filters / data-export flows so operator-fed
|
|
359
|
+
* paths hit the guard before any evaluator dispatch.
|
|
360
|
+
*
|
|
361
|
+
* @opts
|
|
362
|
+
* profile: "strict"|"balanced"|"permissive",
|
|
363
|
+
* compliance: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
364
|
+
* name: string, // override gate name in audit emissions
|
|
365
|
+
* filterExprPolicy: "reject"|"audit"|"allow",
|
|
366
|
+
* scriptExprPolicy: "reject"|"audit"|"allow",
|
|
367
|
+
* dynamicHintPolicy: "reject"|"audit"|"allow",
|
|
368
|
+
* bracketNestingPolicy: "reject"|"audit"|"allow",
|
|
369
|
+
* recursiveDescentPolicy: "reject"|"audit"|"allow",
|
|
370
|
+
* maxRecursiveDescents: number,
|
|
371
|
+
* maxPatternBytes: number,
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* var gate = b.guardJsonpath.gate({ profile: "strict" });
|
|
375
|
+
*
|
|
376
|
+
* gate({ identifier: "$..[?(@.x)]" }).then(function (rv) {
|
|
377
|
+
* rv.ok; // → false
|
|
378
|
+
* rv.action; // → "refuse"
|
|
379
|
+
* });
|
|
380
|
+
*
|
|
381
|
+
* gate({ identifier: "$.users[*].name" }).then(function (rv) {
|
|
382
|
+
* rv.action; // → "serve"
|
|
383
|
+
* });
|
|
384
|
+
*/
|
|
243
385
|
function gate(opts) {
|
|
244
386
|
opts = _resolveOpts(opts);
|
|
245
387
|
return gateContract.buildGuardGate(
|
|
@@ -265,14 +407,84 @@ function gate(opts) {
|
|
|
265
407
|
});
|
|
266
408
|
}
|
|
267
409
|
|
|
410
|
+
/**
|
|
411
|
+
* @primitive b.guardJsonpath.buildProfile
|
|
412
|
+
* @signature b.guardJsonpath.buildProfile(opts)
|
|
413
|
+
* @since 0.7.13
|
|
414
|
+
* @status stable
|
|
415
|
+
* @related b.guardJsonpath.gate, b.guardJsonpath.compliancePosture
|
|
416
|
+
*
|
|
417
|
+
* Compose a derived guardJsonpath profile from one or more named
|
|
418
|
+
* bases plus inline overrides. `opts.extends` is a profile name
|
|
419
|
+
* (`"strict"` / `"balanced"` / `"permissive"`) or an array of
|
|
420
|
+
* names; later entries shadow earlier ones. Inline `opts` keys win
|
|
421
|
+
* last. Used to keep operator-defined profiles traceable to a
|
|
422
|
+
* baseline rather than re-typing every key.
|
|
423
|
+
*
|
|
424
|
+
* @opts
|
|
425
|
+
* extends: string|string[], // base profile name(s) to compose
|
|
426
|
+
* ...: any guardJsonpath key, // inline override of resolved keys
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* var custom = b.guardJsonpath.buildProfile({
|
|
430
|
+
* extends: "balanced",
|
|
431
|
+
* maxRecursiveDescents: 1,
|
|
432
|
+
* recursiveDescentPolicy: "reject",
|
|
433
|
+
* });
|
|
434
|
+
* custom.maxRecursiveDescents; // → 1
|
|
435
|
+
* custom.filterExprPolicy; // → "reject"
|
|
436
|
+
*/
|
|
268
437
|
var buildProfile = gateContract.makeProfileBuilder(PROFILES);
|
|
269
438
|
|
|
439
|
+
/**
|
|
440
|
+
* @primitive b.guardJsonpath.compliancePosture
|
|
441
|
+
* @signature b.guardJsonpath.compliancePosture(name)
|
|
442
|
+
* @since 0.7.13
|
|
443
|
+
* @status stable
|
|
444
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
445
|
+
* @related b.guardJsonpath.gate, b.guardJsonpath.buildProfile
|
|
446
|
+
*
|
|
447
|
+
* Look up a compliance-posture overlay by name (`"hipaa"` /
|
|
448
|
+
* `"pci-dss"` / `"gdpr"` / `"soc2"`). Returns a shallow clone of
|
|
449
|
+
* the posture object — the caller may mutate freely. Throws
|
|
450
|
+
* `GuardJsonpathError("jsonpath.bad-posture")` on unknown name.
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* var posture = b.guardJsonpath.compliancePosture("hipaa");
|
|
454
|
+
* posture.filterExprPolicy; // → "reject"
|
|
455
|
+
* posture.forensicSnippetBytes; // → 256
|
|
456
|
+
*/
|
|
270
457
|
function compliancePosture(name) {
|
|
271
458
|
return gateContract.lookupCompliancePosture(name, COMPLIANCE_POSTURES,
|
|
272
459
|
_err, "jsonpath");
|
|
273
460
|
}
|
|
274
461
|
|
|
275
462
|
var _jpRulePacks = gateContract.makeRulePackLoader(GuardJsonpathError, "jsonpath");
|
|
463
|
+
/**
|
|
464
|
+
* @primitive b.guardJsonpath.loadRulePack
|
|
465
|
+
* @signature b.guardJsonpath.loadRulePack(pack)
|
|
466
|
+
* @since 0.7.13
|
|
467
|
+
* @status stable
|
|
468
|
+
* @related b.guardJsonpath.gate
|
|
469
|
+
*
|
|
470
|
+
* Register an operator-supplied rule pack with the guardJsonpath
|
|
471
|
+
* registry. The pack is identified by `pack.id` (non-empty string)
|
|
472
|
+
* and stored for later inspection / dispatch by gates that opt in
|
|
473
|
+
* via `opts.rulePackId`. Returns the pack object unchanged on
|
|
474
|
+
* success; throws `GuardJsonpathError("jsonpath.bad-opt")` when
|
|
475
|
+
* `pack` is missing or `pack.id` is not a non-empty string.
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* var pack = b.guardJsonpath.loadRulePack({
|
|
479
|
+
* id: "no-wildcards",
|
|
480
|
+
* rules: [
|
|
481
|
+
* { id: "wildcard", severity: "high",
|
|
482
|
+
* detect: function (path) { return path.indexOf("[*]") !== -1; },
|
|
483
|
+
* reason: "wildcard index forbidden in this context" },
|
|
484
|
+
* ],
|
|
485
|
+
* });
|
|
486
|
+
* pack.id; // → "no-wildcards"
|
|
487
|
+
*/
|
|
276
488
|
var loadRulePack = _jpRulePacks.load;
|
|
277
489
|
|
|
278
490
|
module.exports = {
|