@blamejs/core 0.14.26 → 0.15.0
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 +6 -0
- package/README.md +2 -2
- package/index.js +4 -0
- package/lib/agent-envelope-mac.js +104 -0
- package/lib/agent-event-bus.js +105 -4
- package/lib/agent-posture-chain.js +8 -42
- package/lib/ai-content-detect.js +9 -10
- package/lib/api-key.js +107 -74
- package/lib/atomic-file.js +62 -4
- package/lib/audit-chain.js +47 -11
- package/lib/audit-sign.js +77 -2
- package/lib/audit-tools.js +79 -51
- package/lib/audit.js +249 -123
- package/lib/auth/openid-federation.js +108 -47
- package/lib/backup/index.js +13 -10
- package/lib/break-glass.js +202 -144
- package/lib/cache.js +174 -105
- package/lib/chain-writer.js +38 -16
- package/lib/cli.js +19 -14
- package/lib/cluster-provider-db.js +130 -104
- package/lib/cluster-storage.js +119 -22
- package/lib/cluster.js +119 -71
- package/lib/compliance.js +169 -4
- package/lib/consent.js +73 -24
- package/lib/constants.js +16 -11
- package/lib/crypto-field.js +474 -92
- package/lib/db-declare-row-policy.js +35 -22
- package/lib/db-file-lifecycle.js +3 -2
- package/lib/db-query.js +497 -255
- package/lib/db-schema.js +209 -44
- package/lib/db.js +176 -95
- package/lib/error-page.js +14 -1
- package/lib/external-db-migrate.js +229 -139
- package/lib/external-db.js +25 -15
- package/lib/file-upload.js +52 -7
- package/lib/framework-error.js +14 -1
- package/lib/framework-files.js +73 -0
- package/lib/framework-schema.js +695 -394
- package/lib/gate-contract.js +649 -1
- package/lib/guard-agent-registry.js +26 -44
- package/lib/guard-all.js +1 -0
- package/lib/guard-auth.js +42 -112
- package/lib/guard-cidr.js +33 -154
- package/lib/guard-csv.js +46 -113
- package/lib/guard-domain.js +34 -157
- package/lib/guard-dsn.js +27 -43
- package/lib/guard-email.js +47 -69
- package/lib/guard-envelope.js +19 -32
- package/lib/guard-event-bus-payload.js +24 -42
- package/lib/guard-event-bus-topic.js +25 -43
- package/lib/guard-filename.js +42 -106
- package/lib/guard-graphql.js +42 -123
- package/lib/guard-html.js +53 -108
- package/lib/guard-idempotency-key.js +24 -42
- package/lib/guard-image.js +46 -103
- package/lib/guard-imap-command.js +18 -32
- package/lib/guard-jmap.js +16 -30
- package/lib/guard-json.js +38 -108
- package/lib/guard-jsonpath.js +38 -171
- package/lib/guard-jwt.js +49 -179
- package/lib/guard-list-id.js +25 -41
- package/lib/guard-list-unsubscribe.js +27 -43
- package/lib/guard-mail-compose.js +24 -42
- package/lib/guard-mail-move.js +26 -44
- package/lib/guard-mail-query.js +28 -46
- package/lib/guard-mail-reply.js +24 -42
- package/lib/guard-mail-sieve.js +24 -42
- package/lib/guard-managesieve-command.js +17 -31
- package/lib/guard-markdown.js +37 -104
- package/lib/guard-message-id.js +26 -45
- package/lib/guard-mime.js +39 -151
- package/lib/guard-oauth.js +54 -135
- package/lib/guard-pdf.js +45 -101
- package/lib/guard-pop3-command.js +21 -31
- package/lib/guard-posture-chain.js +24 -42
- package/lib/guard-regex.js +33 -107
- package/lib/guard-saga-config.js +24 -42
- package/lib/guard-shell.js +42 -172
- package/lib/guard-smtp-command.js +48 -54
- package/lib/guard-snapshot-envelope.js +24 -42
- package/lib/guard-sql.js +1491 -0
- package/lib/guard-stream-args.js +24 -43
- package/lib/guard-svg.js +47 -65
- package/lib/guard-template.js +35 -172
- package/lib/guard-tenant-id.js +26 -45
- package/lib/guard-time.js +32 -154
- package/lib/guard-trace-context.js +25 -44
- package/lib/guard-uuid.js +32 -153
- package/lib/guard-xml.js +38 -113
- package/lib/guard-yaml.js +51 -163
- package/lib/http-client.js +37 -9
- package/lib/inbox.js +120 -107
- package/lib/legal-hold.js +107 -50
- package/lib/log-stream-cloudwatch.js +47 -31
- package/lib/log-stream-otlp.js +32 -18
- package/lib/mail-crypto-smime.js +2 -6
- package/lib/mail-greylist.js +2 -6
- package/lib/mail-helo.js +2 -6
- package/lib/mail-journal.js +85 -64
- package/lib/mail-rbl.js +2 -6
- package/lib/mail-scan.js +2 -6
- package/lib/mail-server-jmap.js +117 -12
- package/lib/mail-spam-score.js +2 -6
- package/lib/mail-store.js +287 -154
- package/lib/middleware/body-parser.js +71 -25
- package/lib/middleware/csrf-protect.js +19 -8
- package/lib/middleware/fetch-metadata.js +17 -7
- package/lib/middleware/idempotency-key.js +54 -38
- package/lib/middleware/rate-limit.js +102 -32
- package/lib/middleware/security-headers.js +21 -5
- package/lib/migrations.js +108 -66
- package/lib/network-heartbeat.js +7 -0
- package/lib/nonce-store.js +31 -9
- package/lib/object-store/azure-blob-bucket-ops.js +9 -4
- package/lib/object-store/azure-blob.js +57 -3
- package/lib/object-store/sigv4.js +10 -0
- package/lib/observability.js +87 -0
- package/lib/otel-export.js +25 -1
- package/lib/outbox.js +136 -82
- package/lib/parsers/safe-xml.js +47 -7
- package/lib/pqc-agent.js +44 -0
- package/lib/pubsub-cluster.js +42 -20
- package/lib/queue-local.js +202 -139
- package/lib/queue-redis.js +9 -1
- package/lib/queue-sqs.js +6 -0
- package/lib/redact.js +68 -11
- package/lib/redis-client.js +160 -31
- package/lib/retention.js +82 -39
- package/lib/router.js +212 -5
- package/lib/safe-dns.js +29 -45
- package/lib/safe-ical.js +18 -33
- package/lib/safe-icap.js +27 -43
- package/lib/safe-sieve.js +21 -40
- package/lib/safe-sql.js +124 -3
- package/lib/safe-vcard.js +18 -33
- package/lib/scheduler.js +35 -12
- package/lib/seeders.js +122 -74
- package/lib/session-stores.js +42 -14
- package/lib/session.js +109 -72
- package/lib/sql.js +3885 -0
- package/lib/ssrf-guard.js +51 -4
- package/lib/static.js +177 -34
- package/lib/subject.js +55 -17
- package/lib/vault/index.js +3 -2
- package/lib/vault/passphrase-ops.js +3 -2
- package/lib/vault/rotate.js +104 -64
- package/lib/vendor-data.js +2 -0
- package/lib/websocket.js +35 -5
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/guard-shell.js
CHANGED
|
@@ -342,181 +342,51 @@ function sanitize(input, opts) {
|
|
|
342
342
|
// Shell args can't be repaired — sanitize either passes through
|
|
343
343
|
// valid input or throws.
|
|
344
344
|
var issues = _detectIssues(input, opts);
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
"guardShell.sanitize: " + issues[i].snippet);
|
|
349
|
-
}
|
|
350
|
-
}
|
|
345
|
+
gateContract.throwOnRefusalSeverity(issues, {
|
|
346
|
+
errorClass: GuardShellError, codePrefix: "shell",
|
|
347
|
+
});
|
|
351
348
|
return input;
|
|
352
349
|
}
|
|
353
350
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
* Build a `b.gateContract` gate that screens `ctx.identifier` (or
|
|
363
|
-
* `ctx.arg`) before each spawn. Action chain: `serve` (no issues)
|
|
364
|
-
* → `audit-only` (warn-only) → `refuse` (any `critical` or `high`).
|
|
365
|
-
* No `sanitize` action — shell args cannot be repaired. Compose
|
|
366
|
-
* with `b.processSpawn` so each argv slot is gated before reaching
|
|
367
|
-
* the OS (the spawn primitive itself enforces `shell: false`; the
|
|
368
|
-
* gate enforces metacharacter cleanliness).
|
|
369
|
-
*
|
|
370
|
-
* @opts
|
|
371
|
-
* profile: "strict"|"balanced"|"permissive",
|
|
372
|
-
* compliancePosture: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
373
|
-
* name: string, // override gate name in audit emissions
|
|
374
|
-
* posixMetaPolicy: "reject"|"audit"|"allow",
|
|
375
|
-
* cmdMetaPolicy: "reject"|"audit"|"allow",
|
|
376
|
-
* dollarSubstPolicy: "reject"|"audit"|"allow",
|
|
377
|
-
* processSubstPolicy:"reject"|"audit"|"allow",
|
|
378
|
-
* backtickPolicy: "reject"|"audit"|"allow",
|
|
379
|
-
* newlinePolicy: "reject"|"audit"|"allow",
|
|
380
|
-
* argHyphenPolicy: "reject"|"audit"|"allow",
|
|
381
|
-
* maxBytes: number,
|
|
382
|
-
*
|
|
383
|
-
* @example
|
|
384
|
-
* var gate = b.guardShell.gate({ profile: "strict" });
|
|
385
|
-
*
|
|
386
|
-
* // Hostile arg — gate refuses before spawn.
|
|
387
|
-
* gate({ identifier: "safe; rm -rf /" }).then(function (rv) {
|
|
388
|
-
* rv.ok; // → false
|
|
389
|
-
* rv.action; // → "refuse"
|
|
390
|
-
* });
|
|
391
|
-
*
|
|
392
|
-
* // Benign arg — gate serves.
|
|
393
|
-
* gate({ identifier: "safe-arg-value" }).then(function (rv) {
|
|
394
|
-
* rv.action; // → "serve"
|
|
395
|
-
* });
|
|
396
|
-
*/
|
|
397
|
-
function gate(opts) {
|
|
398
|
-
opts = _resolveOpts(opts);
|
|
399
|
-
return gateContract.buildGuardGate(
|
|
400
|
-
opts.name || "guardShell:" + (opts.profile || "default"),
|
|
401
|
-
opts,
|
|
402
|
-
async function (ctx) {
|
|
403
|
-
var arg = ctx && (ctx.identifier || ctx.arg);
|
|
404
|
-
if (arg === undefined || arg === null) return { ok: true, action: "serve" };
|
|
405
|
-
var rv = validate(arg, opts);
|
|
406
|
-
if (rv.issues.length === 0) return { ok: true, action: "serve" };
|
|
407
|
-
var hasCritical = rv.issues.some(function (i) {
|
|
408
|
-
return i.severity === "critical";
|
|
409
|
-
});
|
|
410
|
-
var hasHigh = rv.issues.some(function (i) {
|
|
411
|
-
return i.severity === "high";
|
|
412
|
-
});
|
|
413
|
-
if (!hasCritical && !hasHigh) {
|
|
414
|
-
return { ok: true, action: "audit-only", issues: rv.issues };
|
|
415
|
-
}
|
|
416
|
-
return { ok: false, action: "refuse", issues: rv.issues };
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* @primitive b.guardShell.buildProfile
|
|
422
|
-
* @signature b.guardShell.buildProfile(opts)
|
|
423
|
-
* @since 0.7.13
|
|
424
|
-
* @status stable
|
|
425
|
-
* @related b.guardShell.gate, b.guardShell.compliancePosture
|
|
426
|
-
*
|
|
427
|
-
* Compose a derived guardShell profile from one or more named bases
|
|
428
|
-
* plus inline overrides. `opts.extends` is a profile name
|
|
429
|
-
* (`"strict"` / `"balanced"` / `"permissive"`) or an array of
|
|
430
|
-
* names; later entries shadow earlier ones. Inline `opts` keys win
|
|
431
|
-
* last. Used to keep operator-defined profiles traceable to a
|
|
432
|
-
* baseline rather than re-typing every key.
|
|
433
|
-
*
|
|
434
|
-
* @opts
|
|
435
|
-
* extends: string|string[], // base profile name(s) to compose
|
|
436
|
-
* ...: any guardShell key, // inline override of resolved keys
|
|
437
|
-
*
|
|
438
|
-
* @example
|
|
439
|
-
* var custom = b.guardShell.buildProfile({
|
|
440
|
-
* extends: "balanced",
|
|
441
|
-
* argHyphenPolicy: "reject",
|
|
442
|
-
* });
|
|
443
|
-
* custom.argHyphenPolicy; // → "reject"
|
|
444
|
-
* custom.dollarSubstPolicy; // → "reject"
|
|
445
|
-
*/
|
|
446
|
-
var buildProfile = gateContract.makeProfileBuilder(PROFILES);
|
|
351
|
+
// The request-boundary gate is the gate-contract factory default: it reads
|
|
352
|
+
// `ctx.identifier` (or `ctx.arg`), runs `validate`, and maps severity to
|
|
353
|
+
// action — `serve` (no issue) / `audit-only` (info / warn) / `refuse` (any
|
|
354
|
+
// high / critical). No `sanitize` action — shell args cannot be repaired.
|
|
355
|
+
// Compose with `b.processSpawn` so each argv slot is gated before reaching
|
|
356
|
+
// the OS (the spawn primitive itself enforces `shell: false`; the gate
|
|
357
|
+
// enforces metacharacter cleanliness). Its wiki section renders from the
|
|
358
|
+
// single-sourced `@abiTemplate gate` block in gate-contract.js.
|
|
447
359
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
454
|
-
* @related b.guardShell.gate, b.guardShell.buildProfile
|
|
455
|
-
*
|
|
456
|
-
* Look up a compliance-posture overlay by name (`"hipaa"` /
|
|
457
|
-
* `"pci-dss"` / `"gdpr"` / `"soc2"`). Returns a shallow clone of
|
|
458
|
-
* the posture object — the caller may mutate freely. Throws
|
|
459
|
-
* `GuardShellError("shell.bad-posture")` on unknown name.
|
|
460
|
-
*
|
|
461
|
-
* @example
|
|
462
|
-
* var posture = b.guardShell.compliancePosture("hipaa");
|
|
463
|
-
* posture.posixMetaPolicy; // → "reject"
|
|
464
|
-
* posture.forensicSnippetBytes; // → 256
|
|
465
|
-
*/
|
|
466
|
-
function compliancePosture(name) {
|
|
467
|
-
return gateContract.lookupCompliancePosture(name, COMPLIANCE_POSTURES,
|
|
468
|
-
_err, "shell");
|
|
469
|
-
}
|
|
360
|
+
// buildProfile / compliancePosture / loadRulePack are assembled by
|
|
361
|
+
// gateContract.defineGuard below (makeProfileBuilder(PROFILES) /
|
|
362
|
+
// lookupCompliancePosture(_, COMPLIANCE_POSTURES) / makeRulePackLoader).
|
|
363
|
+
// Their wiki sections render from the single-sourced @abiTemplate blocks
|
|
364
|
+
// in gate-contract.js, instantiated per guard by the page generator.
|
|
470
365
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
* registry. The pack is identified by `pack.id` (non-empty string)
|
|
481
|
-
* and stored for later inspection / dispatch by gates that opt in
|
|
482
|
-
* via `opts.rulePackId`. Returns the pack object unchanged on
|
|
483
|
-
* success; throws `GuardShellError("shell.bad-opt")` when `pack`
|
|
484
|
-
* is missing or `pack.id` is not a non-empty string.
|
|
485
|
-
*
|
|
486
|
-
* @example
|
|
487
|
-
* var pack = b.guardShell.loadRulePack({
|
|
488
|
-
* id: "no-leading-dash",
|
|
489
|
-
* rules: [
|
|
490
|
-
* { id: "leading-dash", severity: "high",
|
|
491
|
-
* detect: function (arg) { return arg.charAt(0) === "-"; },
|
|
492
|
-
* reason: "argument starts with `-` flag prefix" },
|
|
493
|
-
* ],
|
|
494
|
-
* });
|
|
495
|
-
* pack.id; // → "no-leading-dash"
|
|
496
|
-
*/
|
|
497
|
-
var loadRulePack = _shellRulePacks.load;
|
|
366
|
+
// ---- adaptive integration-test fixtures (consumed by layer-5 host harness) ----
|
|
367
|
+
var INTEGRATION_FIXTURES = Object.freeze({
|
|
368
|
+
kind: "identifier",
|
|
369
|
+
benignBytes: Buffer.from("safe-arg-value", "utf8"),
|
|
370
|
+
hostileBytes: Buffer.from("safe; rm -rf /", "utf8"),
|
|
371
|
+
benignIdentifier: "safe-arg-value",
|
|
372
|
+
// Hostile: command-injection via metacharacter chain.
|
|
373
|
+
hostileIdentifier: "safe; rm -rf /",
|
|
374
|
+
});
|
|
498
375
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
validate:
|
|
513
|
-
sanitize:
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
compliancePosture: compliancePosture,
|
|
517
|
-
loadRulePack: loadRulePack,
|
|
518
|
-
PROFILES: PROFILES,
|
|
519
|
-
DEFAULTS: DEFAULTS,
|
|
520
|
-
COMPLIANCE_POSTURES: COMPLIANCE_POSTURES,
|
|
521
|
-
GuardShellError: GuardShellError,
|
|
522
|
-
};
|
|
376
|
+
// Assembled from the gate-contract guard factory: error class, registry
|
|
377
|
+
// exports (NAME / KIND / INTEGRATION_FIXTURES), buildProfile /
|
|
378
|
+
// compliancePosture / loadRulePack wiring, plus the per-guard inspection
|
|
379
|
+
// surface (validate / sanitize). The gate is the factory default chain,
|
|
380
|
+
// dispatched to `ctx.identifier` / `ctx.arg` via ctxFields.
|
|
381
|
+
module.exports = gateContract.defineGuard({
|
|
382
|
+
name: "shell",
|
|
383
|
+
kind: "identifier",
|
|
384
|
+
errorClass: GuardShellError,
|
|
385
|
+
profiles: PROFILES,
|
|
386
|
+
defaults: DEFAULTS,
|
|
387
|
+
postures: COMPLIANCE_POSTURES,
|
|
388
|
+
integrationFixtures: INTEGRATION_FIXTURES,
|
|
389
|
+
validate: validate,
|
|
390
|
+
sanitize: sanitize,
|
|
391
|
+
ctxFields: ["identifier", "arg"],
|
|
392
|
+
});
|
|
@@ -103,11 +103,15 @@ var PROFILES = Object.freeze({
|
|
|
103
103
|
permissive: { maxLineBytes: 4096, maxMailbox: 512, maxLocalPart: 64, maxDomain: 255, allowBareLf: true, allowSmtpUtf8: true }, // permissive cap for legacy peers
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
-
var COMPLIANCE_POSTURES =
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
var COMPLIANCE_POSTURES = gateContract.ALL_STRICT_POSTURES;
|
|
107
|
+
|
|
108
|
+
var _resolveProfile = gateContract.makeProfileResolver({
|
|
109
|
+
profiles: PROFILES,
|
|
110
|
+
postures: COMPLIANCE_POSTURES,
|
|
111
|
+
defaults: DEFAULT_PROFILE,
|
|
112
|
+
errorClass: GuardSmtpCommandError,
|
|
113
|
+
codePrefix: "guard-smtp-command",
|
|
114
|
+
byObject: true,
|
|
111
115
|
});
|
|
112
116
|
|
|
113
117
|
// Verbs we know — anything else is refused under strict, accepted as
|
|
@@ -237,21 +241,10 @@ function validate(line, opts) {
|
|
|
237
241
|
}
|
|
238
242
|
}
|
|
239
243
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
* @status stable
|
|
245
|
-
*
|
|
246
|
-
* Return the effective profile name for a compliance posture, or
|
|
247
|
-
* `null` for unknown posture names.
|
|
248
|
-
*
|
|
249
|
-
* @example
|
|
250
|
-
* b.guardSmtpCommand.compliancePosture("hipaa"); // → "strict"
|
|
251
|
-
*/
|
|
252
|
-
function compliancePosture(posture) {
|
|
253
|
-
return COMPLIANCE_POSTURES[posture] || null;
|
|
254
|
-
}
|
|
244
|
+
// compliancePosture is assembled by gateContract.defineParser below; its
|
|
245
|
+
// wiki section renders from the single-sourced @abiTemplate (defineParser)
|
|
246
|
+
// block in gate-contract.js, instantiated for this guard by the page
|
|
247
|
+
// generator.
|
|
255
248
|
|
|
256
249
|
function _validateGreeting(verb, rest, caps) {
|
|
257
250
|
if (rest.length === 0) {
|
|
@@ -420,18 +413,6 @@ function _parseAuthCommandSyntax(rest) {
|
|
|
420
413
|
};
|
|
421
414
|
}
|
|
422
415
|
|
|
423
|
-
function _resolveProfile(opts) {
|
|
424
|
-
if (opts.posture && COMPLIANCE_POSTURES[opts.posture]) {
|
|
425
|
-
return PROFILES[COMPLIANCE_POSTURES[opts.posture]];
|
|
426
|
-
}
|
|
427
|
-
var p = opts.profile || DEFAULT_PROFILE;
|
|
428
|
-
if (!PROFILES[p]) {
|
|
429
|
-
throw new GuardSmtpCommandError("guard-smtp-command/bad-profile",
|
|
430
|
-
"guardSmtpCommand: unknown profile '" + p + "'");
|
|
431
|
-
}
|
|
432
|
-
return PROFILES[p];
|
|
433
|
-
}
|
|
434
|
-
|
|
435
416
|
/**
|
|
436
417
|
* @primitive b.guardSmtpCommand.gate
|
|
437
418
|
* @signature b.guardSmtpCommand.gate(opts?)
|
|
@@ -569,25 +550,38 @@ function detectBodySmuggling(buf) {
|
|
|
569
550
|
return false;
|
|
570
551
|
}
|
|
571
552
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
553
|
+
var INTEGRATION_FIXTURES = Object.freeze({
|
|
554
|
+
kind: "identifier",
|
|
555
|
+
// Benign: standard EHLO greeting.
|
|
556
|
+
benignBytes: Buffer.from("EHLO mail.example.com", "ascii"),
|
|
557
|
+
// Hostile: CRLF smuggling attempt — bare CR inside a command line
|
|
558
|
+
// (CVE-2023-51764 / 51765 / 51766 class).
|
|
559
|
+
hostileBytes: Buffer.from("MAIL FROM:<a@b.com>\r\n.\r\nMAIL FROM:<evil@x.com>", "ascii"),
|
|
560
|
+
benignIdentifier: "EHLO mail.example.com",
|
|
561
|
+
hostileIdentifier: "MAIL FROM:<a@b.com>\r\n.\r\nMAIL FROM:<evil@x.com>",
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
// Assembled from the gate-contract parser factory: error class,
|
|
565
|
+
// compliancePosture wiring, PROFILES / COMPLIANCE_POSTURES, the `validate`
|
|
566
|
+
// entry, plus this guard's registry exports (NAME / KIND /
|
|
567
|
+
// INTEGRATION_FIXTURES), bespoke `gate`, `detectBodySmuggling`, and the
|
|
568
|
+
// KNOWN_VERBS table passed through verbatim. defineParser is the right
|
|
569
|
+
// shape here — the guard's four postures all resolve to `strict`
|
|
570
|
+
// (ALL_STRICT_POSTURES) and it carries no buildProfile / loadRulePack.
|
|
571
|
+
// The bespoke `gate` and `detectBodySmuggling` keep their own @primitive
|
|
572
|
+
// blocks; only the factory-generated compliancePosture block is removed.
|
|
573
|
+
module.exports = gateContract.defineParser({
|
|
574
|
+
name: "smtp-command",
|
|
575
|
+
entry: validate,
|
|
576
|
+
errorClass: GuardSmtpCommandError,
|
|
577
|
+
profiles: PROFILES,
|
|
578
|
+
postures: COMPLIANCE_POSTURES,
|
|
579
|
+
extra: {
|
|
580
|
+
NAME: "smtpCommand",
|
|
581
|
+
KIND: "identifier",
|
|
582
|
+
INTEGRATION_FIXTURES: INTEGRATION_FIXTURES,
|
|
583
|
+
gate: gate,
|
|
584
|
+
detectBodySmuggling: detectBodySmuggling,
|
|
585
|
+
KNOWN_VERBS: KNOWN_VERBS,
|
|
586
|
+
},
|
|
587
|
+
});
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
var { defineClass } = require("./framework-error");
|
|
32
|
+
var gateContract = require("./gate-contract");
|
|
32
33
|
|
|
33
34
|
var GuardSnapshotEnvelopeError = defineClass("GuardSnapshotEnvelopeError", { alwaysPermanent: true });
|
|
34
35
|
|
|
@@ -40,11 +41,14 @@ var PROFILES = Object.freeze({
|
|
|
40
41
|
permissive: { maxBytes: 1073741824, maxInFlight: 1048576 }, // 1 GiB
|
|
41
42
|
});
|
|
42
43
|
|
|
43
|
-
var COMPLIANCE_POSTURES =
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
var COMPLIANCE_POSTURES = gateContract.ALL_STRICT_POSTURES;
|
|
45
|
+
|
|
46
|
+
var _resolveProfile = gateContract.makeProfileResolver({
|
|
47
|
+
profiles: PROFILES,
|
|
48
|
+
postures: COMPLIANCE_POSTURES,
|
|
49
|
+
defaults: DEFAULT_PROFILE,
|
|
50
|
+
errorClass: GuardSnapshotEnvelopeError,
|
|
51
|
+
codePrefix: "snapshot-envelope",
|
|
48
52
|
});
|
|
49
53
|
|
|
50
54
|
/**
|
|
@@ -128,41 +132,19 @@ function validate(envelope, opts) {
|
|
|
128
132
|
return envelope;
|
|
129
133
|
}
|
|
130
134
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
* @status stable
|
|
136
|
-
*
|
|
137
|
-
* Return the effective profile for a given compliance posture name.
|
|
138
|
-
* Returns `null` for unknown posture names so operator typos surface
|
|
139
|
-
* here instead of silently falling through to the default profile.
|
|
140
|
-
*
|
|
141
|
-
* @example
|
|
142
|
-
* b.guardSnapshotEnvelope.compliancePosture("hipaa"); // returns "strict"
|
|
143
|
-
*/
|
|
144
|
-
function compliancePosture(posture) {
|
|
145
|
-
return COMPLIANCE_POSTURES[posture] || null;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function _resolveProfile(opts) {
|
|
149
|
-
if (opts.posture && COMPLIANCE_POSTURES[opts.posture]) {
|
|
150
|
-
return COMPLIANCE_POSTURES[opts.posture];
|
|
151
|
-
}
|
|
152
|
-
var p = opts.profile || DEFAULT_PROFILE;
|
|
153
|
-
if (!PROFILES[p]) {
|
|
154
|
-
throw new GuardSnapshotEnvelopeError("snapshot-envelope/bad-profile",
|
|
155
|
-
"guardSnapshotEnvelope: unknown profile '" + p + "'");
|
|
156
|
-
}
|
|
157
|
-
return p;
|
|
158
|
-
}
|
|
135
|
+
// compliancePosture is assembled by gateContract.defineParser below; its
|
|
136
|
+
// wiki section renders from the single-sourced @abiTemplate (defineParser)
|
|
137
|
+
// block in gate-contract.js, instantiated for this guard by the page
|
|
138
|
+
// generator.
|
|
159
139
|
|
|
160
|
-
module.exports = {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
140
|
+
module.exports = gateContract.defineParser({
|
|
141
|
+
name: "snapshot-envelope",
|
|
142
|
+
entry: validate,
|
|
143
|
+
errorClass: GuardSnapshotEnvelopeError,
|
|
144
|
+
profiles: PROFILES,
|
|
145
|
+
postures: COMPLIANCE_POSTURES,
|
|
146
|
+
extra: {
|
|
147
|
+
NAME: "snapshotEnvelope",
|
|
148
|
+
KIND: "snapshot-envelope",
|
|
149
|
+
},
|
|
150
|
+
});
|