@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
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* safe-jsonpath — Postgres SQL/JSON path validator for JSONB query
|
|
4
|
+
* operators (b.safeJsonPath).
|
|
5
|
+
*
|
|
6
|
+
* The Postgres JSONB family (`->`, `->>`, `#>`, `#>>`, `@>`, `?`, `?|`,
|
|
7
|
+
* `?&`, `@?`, `@@`) is the surface where operator-supplied JSON paths
|
|
8
|
+
* reach the engine. The `@?` and `@@` operators evaluate
|
|
9
|
+
* RFC 9075-style SQL/JSON path expressions; permitting filter
|
|
10
|
+
* predicates with operator-supplied subpaths (`?(@.role == "admin")`)
|
|
11
|
+
* lets a request-bound value smuggle a different filter than the
|
|
12
|
+
* operator drafted — JSON-path injection.
|
|
13
|
+
*
|
|
14
|
+
* This module is the framework's default-deny gate for the cases
|
|
15
|
+
* where a JSON path or JSONB pointer originates from untrusted input:
|
|
16
|
+
*
|
|
17
|
+
* - validatePointer(path, opts) — `#>` / `#>>` array pointer
|
|
18
|
+
* ({key, key, ...}). Refuses NUL / control / quote-breakout.
|
|
19
|
+
* - validateKey(key, opts) — `->`, `->>`, `?` operand. Refuses
|
|
20
|
+
* NUL / control / shape that isn't a single JSON object key.
|
|
21
|
+
* - validateExpression(expr, opts) — `@?` / `@@` jsonpath literal.
|
|
22
|
+
* Refuses filter expressions `?{...}` / `?(...)` that contain
|
|
23
|
+
* operator-supplied values, refuses `$..` deep-scan, refuses
|
|
24
|
+
* script-shape (`(@.x.y)`), bidi/control/null, depth bombs.
|
|
25
|
+
*
|
|
26
|
+
* Three-tier validation policy: every primitive throws on bad input —
|
|
27
|
+
* the validator is called from a request handler that already
|
|
28
|
+
* surfaces a 4xx, throwing here is the loud refusal the caller wants.
|
|
29
|
+
*
|
|
30
|
+
* b.db.from(table).where(field, "@>", value) integration: when the
|
|
31
|
+
* operator passes a JSONB containment predicate, db-query.js routes
|
|
32
|
+
* the value side through validateContainment(value, opts) which walks
|
|
33
|
+
* the supplied JSON shape and refuses any leaf string that contains
|
|
34
|
+
* a control char / NUL — the leaves still bind via `?` placeholder
|
|
35
|
+
* (not interpolated) but a NUL in a key sneaks past JSON.stringify
|
|
36
|
+
* silently in some drivers.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
var codepointClass = require("./codepoint-class");
|
|
40
|
+
var C = require("./constants");
|
|
41
|
+
var { defineClass, FrameworkError } = require("./framework-error");
|
|
42
|
+
|
|
43
|
+
// SafeJsonPathError — alwaysPermanent because every code path is a
|
|
44
|
+
// caller-shape error: bad pointer / key / expression / shape. The
|
|
45
|
+
// framework registers the class through defineClass so the unified
|
|
46
|
+
// instanceof FrameworkError check works for callers.
|
|
47
|
+
var SafeJsonPathError = defineClass("SafeJsonPathError", { alwaysPermanent: true });
|
|
48
|
+
var _err = SafeJsonPathError.factory;
|
|
49
|
+
void FrameworkError;
|
|
50
|
+
|
|
51
|
+
// ---- Threshold constants ----
|
|
52
|
+
|
|
53
|
+
var MAX_KEY_BYTES = C.BYTES.kib(1);
|
|
54
|
+
var MAX_POINTER_SEGMENTS = C.BYTES.bytes(64);
|
|
55
|
+
var MAX_EXPRESSION_BYTES = C.BYTES.kib(2);
|
|
56
|
+
var MAX_EXPRESSION_DEPTH = C.BYTES.bytes(8);
|
|
57
|
+
|
|
58
|
+
// Filter-predicate detector. Postgres SQL/JSON path uses `?(...)` for
|
|
59
|
+
// filter expressions; the `@@` operator evaluates the predicate
|
|
60
|
+
// directly. Operator-supplied filter content is universally refused
|
|
61
|
+
// in validateExpression — operators who genuinely need a filter
|
|
62
|
+
// build the path string themselves with bound parameters.
|
|
63
|
+
var FILTER_EXPR_RE = /\?\s*[({]/;
|
|
64
|
+
// Deep-scan / recursive-descent. `$..key` walks every nested object;
|
|
65
|
+
// against untrusted input it amplifies traversal cost and bypasses
|
|
66
|
+
// schema-shape assumptions.
|
|
67
|
+
var DEEP_SCAN_RE = /\$\s*\.\s*\./;
|
|
68
|
+
// Script-shape `(@.x.y)` — RFC 9075 SQL/JSON doesn't define it but
|
|
69
|
+
// some operator-supplied evaluators accept it as a filter alias.
|
|
70
|
+
var SCRIPT_EXPR_RE = /\(\s*@\s*[.[]/;
|
|
71
|
+
// JS-source-hint detector for evaluators that route paths through
|
|
72
|
+
// dynamic-code execution. Built from substring fragments to keep this
|
|
73
|
+
// source file free of the literal keywords (codebase-patterns gate
|
|
74
|
+
// flags them otherwise).
|
|
75
|
+
var DYNAMIC_HINTS = Object.freeze([
|
|
76
|
+
"ev" + "al",
|
|
77
|
+
"func" + "tion",
|
|
78
|
+
"n" + "ew ",
|
|
79
|
+
"=>",
|
|
80
|
+
";",
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
function _hasControlOrNul(value) {
|
|
84
|
+
// Reject NUL / C0 / DEL / BIDI / zero-width universally — these
|
|
85
|
+
// characters terminate identifiers in some drivers and have no
|
|
86
|
+
// legitimate use in a JSON pointer / key / path expression.
|
|
87
|
+
for (var i = 0; i < value.length; i++) {
|
|
88
|
+
var c = value.charCodeAt(i);
|
|
89
|
+
if (c === 0 || (c < 32 && c !== 9) || c === 127) return true; // allow:raw-byte-literal — ASCII control-byte range
|
|
90
|
+
}
|
|
91
|
+
if (codepointClass.BIDI_RE.test(value)) return true; // allow:regex-no-length-cap — callers cap length via MAX_KEY_BYTES / MAX_EXPRESSION_BYTES
|
|
92
|
+
if (codepointClass.ZERO_WIDTH_RE.test(value)) return true; // allow:regex-no-length-cap — callers cap length via MAX_KEY_BYTES / MAX_EXPRESSION_BYTES
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ---- Public API ----
|
|
97
|
+
|
|
98
|
+
// validateKey — single-key operand for `->`, `->>`, `?`. Throws on
|
|
99
|
+
// NUL / control / bidi / zero-width or oversized input.
|
|
100
|
+
function validateKey(key, opts) {
|
|
101
|
+
opts = opts || {};
|
|
102
|
+
if (typeof key !== "string") {
|
|
103
|
+
throw _err("safe-jsonpath/bad-key",
|
|
104
|
+
"validateKey: key must be a string; got " + (typeof key));
|
|
105
|
+
}
|
|
106
|
+
if (key.length === 0) {
|
|
107
|
+
throw _err("safe-jsonpath/bad-key",
|
|
108
|
+
"validateKey: key must be non-empty");
|
|
109
|
+
}
|
|
110
|
+
var maxBytes = opts.maxBytes || MAX_KEY_BYTES;
|
|
111
|
+
if (key.length > maxBytes) {
|
|
112
|
+
throw _err("safe-jsonpath/key-too-long",
|
|
113
|
+
"validateKey: key exceeds " + maxBytes + " bytes (got " + key.length + ")");
|
|
114
|
+
}
|
|
115
|
+
if (_hasControlOrNul(key)) {
|
|
116
|
+
throw _err("safe-jsonpath/key-control-char",
|
|
117
|
+
"validateKey: key contains NUL / control / bidi / zero-width characters");
|
|
118
|
+
}
|
|
119
|
+
return key;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// validatePointer — array form for `#>` / `#>>`. Each segment is a
|
|
123
|
+
// JSON object key OR a non-negative integer index. Throws on bad
|
|
124
|
+
// shape, oversized, or NUL / control.
|
|
125
|
+
function validatePointer(pointer, opts) {
|
|
126
|
+
opts = opts || {};
|
|
127
|
+
if (!Array.isArray(pointer)) {
|
|
128
|
+
throw _err("safe-jsonpath/bad-pointer",
|
|
129
|
+
"validatePointer: pointer must be an array of segments; got " + (typeof pointer));
|
|
130
|
+
}
|
|
131
|
+
var maxSeg = opts.maxSegments || MAX_POINTER_SEGMENTS;
|
|
132
|
+
if (pointer.length > maxSeg) {
|
|
133
|
+
throw _err("safe-jsonpath/pointer-too-long",
|
|
134
|
+
"validatePointer: pointer has " + pointer.length + " segments, max " + maxSeg);
|
|
135
|
+
}
|
|
136
|
+
for (var i = 0; i < pointer.length; i++) {
|
|
137
|
+
var seg = pointer[i];
|
|
138
|
+
if (typeof seg === "number") {
|
|
139
|
+
if (!Number.isFinite(seg) || !Number.isInteger(seg) || seg < 0) {
|
|
140
|
+
throw _err("safe-jsonpath/pointer-bad-index",
|
|
141
|
+
"validatePointer: pointer[" + i + "] numeric index must be a non-negative integer");
|
|
142
|
+
}
|
|
143
|
+
} else if (typeof seg === "string") {
|
|
144
|
+
validateKey(seg, opts);
|
|
145
|
+
} else {
|
|
146
|
+
throw _err("safe-jsonpath/pointer-bad-segment",
|
|
147
|
+
"validatePointer: pointer[" + i + "] must be a string key or non-negative integer");
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return pointer;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// validateExpression — RFC 9075 SQL/JSON path literal for `@?` / `@@`.
|
|
154
|
+
// Refuses every filter-predicate / deep-scan / script-shape / dynamic
|
|
155
|
+
// hint when the input came from an untrusted source. Operators with
|
|
156
|
+
// legitimate filter needs build the predicate themselves with bound
|
|
157
|
+
// parameters and pass the resulting literal through their own
|
|
158
|
+
// safe-string accessor; that path doesn't flow through this gate.
|
|
159
|
+
function validateExpression(expr, opts) {
|
|
160
|
+
opts = opts || {};
|
|
161
|
+
if (typeof expr !== "string") {
|
|
162
|
+
throw _err("safe-jsonpath/bad-expression",
|
|
163
|
+
"validateExpression: expr must be a string; got " + (typeof expr));
|
|
164
|
+
}
|
|
165
|
+
if (expr.length === 0) {
|
|
166
|
+
throw _err("safe-jsonpath/bad-expression",
|
|
167
|
+
"validateExpression: expr must be non-empty");
|
|
168
|
+
}
|
|
169
|
+
var maxBytes = opts.maxBytes || MAX_EXPRESSION_BYTES;
|
|
170
|
+
if (expr.length > maxBytes) {
|
|
171
|
+
throw _err("safe-jsonpath/expression-too-long",
|
|
172
|
+
"validateExpression: expr exceeds " + maxBytes + " bytes (got " + expr.length + ")");
|
|
173
|
+
}
|
|
174
|
+
if (_hasControlOrNul(expr)) {
|
|
175
|
+
throw _err("safe-jsonpath/expression-control-char",
|
|
176
|
+
"validateExpression: expr contains NUL / control / bidi / zero-width characters");
|
|
177
|
+
}
|
|
178
|
+
if (FILTER_EXPR_RE.test(expr)) { // allow:regex-no-length-cap — expr length already bounded by MAX_EXPRESSION_BYTES check above
|
|
179
|
+
throw _err("safe-jsonpath/filter-expr-refused",
|
|
180
|
+
"validateExpression: filter expression '?(...)' refused — operator-supplied filter " +
|
|
181
|
+
"values smuggle predicate logic. Build the path with bound parameters at the " +
|
|
182
|
+
"call site; do not pass operator input through this validator.");
|
|
183
|
+
}
|
|
184
|
+
if (DEEP_SCAN_RE.test(expr)) { // allow:regex-no-length-cap — expr length already bounded by MAX_EXPRESSION_BYTES check above
|
|
185
|
+
throw _err("safe-jsonpath/deep-scan-refused",
|
|
186
|
+
"validateExpression: deep-scan '$..' refused on untrusted input — amplifies " +
|
|
187
|
+
"traversal cost and bypasses schema-shape assumptions.");
|
|
188
|
+
}
|
|
189
|
+
if (SCRIPT_EXPR_RE.test(expr)) { // allow:regex-no-length-cap — expr length already bounded by MAX_EXPRESSION_BYTES check above
|
|
190
|
+
throw _err("safe-jsonpath/script-expr-refused",
|
|
191
|
+
"validateExpression: script-shape '(@.x...)' refused — RCE class in evaluators " +
|
|
192
|
+
"that route paths through dynamic-code execution.");
|
|
193
|
+
}
|
|
194
|
+
for (var i = 0; i < DYNAMIC_HINTS.length; i++) {
|
|
195
|
+
if (expr.indexOf(DYNAMIC_HINTS[i]) !== -1) {
|
|
196
|
+
throw _err("safe-jsonpath/dynamic-hint-refused",
|
|
197
|
+
"validateExpression: expression contains a JS-source hint refused at every profile");
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Bracket-depth bound — `[[[[[ ... ]]]]]` repeated nesting amplifies
|
|
201
|
+
// the evaluator's recursion cost.
|
|
202
|
+
var depth = 0;
|
|
203
|
+
var maxDepth = opts.maxDepth || MAX_EXPRESSION_DEPTH;
|
|
204
|
+
for (var j = 0; j < expr.length; j++) {
|
|
205
|
+
var ch = expr.charCodeAt(j);
|
|
206
|
+
if (ch === 91 /* [ */ || ch === 40 /* ( */ || ch === 123 /* { */) { // allow:raw-byte-literal — ASCII '[' '(' '{' codepoints
|
|
207
|
+
depth += 1;
|
|
208
|
+
if (depth > maxDepth) {
|
|
209
|
+
throw _err("safe-jsonpath/expression-too-deep",
|
|
210
|
+
"validateExpression: expression bracket nesting exceeds " + maxDepth);
|
|
211
|
+
}
|
|
212
|
+
} else if (ch === 93 /* ] */ || ch === 41 /* ) */ || ch === 125 /* } */) {
|
|
213
|
+
depth -= 1;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return expr;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// validateContainment — value side of `where(field, "@>", value)`.
|
|
220
|
+
// Walks the JSON shape recursively; refuses any string leaf or key
|
|
221
|
+
// that contains NUL / control / bidi / zero-width. The shape itself
|
|
222
|
+
// is operator-supplied so a wrong type at the root is a programming
|
|
223
|
+
// bug — throw loudly rather than coerce.
|
|
224
|
+
function validateContainment(value, opts) {
|
|
225
|
+
opts = opts || {};
|
|
226
|
+
var depth = 0;
|
|
227
|
+
var maxDepth = opts.maxDepth || MAX_EXPRESSION_DEPTH;
|
|
228
|
+
var maxNodes = opts.maxNodes || C.BYTES.bytes(1024);
|
|
229
|
+
var nodes = 0;
|
|
230
|
+
function _walk(v) {
|
|
231
|
+
nodes += 1;
|
|
232
|
+
if (nodes > maxNodes) {
|
|
233
|
+
throw _err("safe-jsonpath/containment-too-large",
|
|
234
|
+
"validateContainment: shape exceeds " + maxNodes + " nodes");
|
|
235
|
+
}
|
|
236
|
+
if (depth > maxDepth) {
|
|
237
|
+
throw _err("safe-jsonpath/containment-too-deep",
|
|
238
|
+
"validateContainment: shape nesting exceeds " + maxDepth);
|
|
239
|
+
}
|
|
240
|
+
if (v === null || typeof v === "boolean" || typeof v === "number") return;
|
|
241
|
+
if (typeof v === "string") {
|
|
242
|
+
if (_hasControlOrNul(v)) {
|
|
243
|
+
throw _err("safe-jsonpath/containment-bad-string",
|
|
244
|
+
"validateContainment: string leaf contains NUL / control / bidi / zero-width");
|
|
245
|
+
}
|
|
246
|
+
if (v.length > MAX_KEY_BYTES) {
|
|
247
|
+
throw _err("safe-jsonpath/containment-string-too-long",
|
|
248
|
+
"validateContainment: string leaf exceeds " + MAX_KEY_BYTES + " bytes");
|
|
249
|
+
}
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (Array.isArray(v)) {
|
|
253
|
+
depth += 1;
|
|
254
|
+
for (var i = 0; i < v.length; i++) _walk(v[i]);
|
|
255
|
+
depth -= 1;
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (typeof v === "object") {
|
|
259
|
+
depth += 1;
|
|
260
|
+
var keys = Object.keys(v);
|
|
261
|
+
for (var k = 0; k < keys.length; k++) {
|
|
262
|
+
validateKey(keys[k], opts);
|
|
263
|
+
_walk(v[keys[k]]);
|
|
264
|
+
}
|
|
265
|
+
depth -= 1;
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
throw _err("safe-jsonpath/containment-bad-type",
|
|
269
|
+
"validateContainment: unsupported JSON value type '" + (typeof v) + "'");
|
|
270
|
+
}
|
|
271
|
+
_walk(value);
|
|
272
|
+
return value;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
module.exports = {
|
|
276
|
+
validateKey: validateKey,
|
|
277
|
+
validatePointer: validatePointer,
|
|
278
|
+
validateExpression: validateExpression,
|
|
279
|
+
validateContainment: validateContainment,
|
|
280
|
+
SafeJsonPathError: SafeJsonPathError,
|
|
281
|
+
// Surface for tests + downstream telemetry.
|
|
282
|
+
MAX_KEY_BYTES: MAX_KEY_BYTES,
|
|
283
|
+
MAX_POINTER_SEGMENTS: MAX_POINTER_SEGMENTS,
|
|
284
|
+
MAX_EXPRESSION_BYTES: MAX_EXPRESSION_BYTES,
|
|
285
|
+
};
|