@blamejs/core 0.14.1 → 0.14.2
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 +2 -0
- package/lib/_test/crypto-fixtures.js +3 -3
- package/lib/a2a-tasks.js +18 -18
- package/lib/a2a.js +4 -4
- package/lib/acme.js +3 -3
- package/lib/agent-idempotency.js +1 -1
- package/lib/agent-orchestrator.js +8 -8
- package/lib/agent-posture-chain.js +2 -2
- package/lib/agent-saga.js +1 -1
- package/lib/agent-snapshot.js +1 -1
- package/lib/agent-stream.js +1 -1
- package/lib/agent-tenant.js +1 -1
- package/lib/agent-trace.js +3 -3
- package/lib/ai-capability.js +1 -1
- package/lib/ai-dp.js +4 -4
- package/lib/ai-input.js +3 -3
- package/lib/ai-model-manifest.js +7 -7
- package/lib/ai-pref.js +3 -3
- package/lib/archive-gz.js +2 -2
- package/lib/archive-read.js +25 -25
- package/lib/archive-tar-read.js +2 -2
- package/lib/archive-tar.js +20 -20
- package/lib/archive-wrap.js +10 -10
- package/lib/argon2-builtin.js +1 -1
- package/lib/asn1-der.js +34 -34
- package/lib/atomic-file.js +2 -2
- package/lib/audit-daily-review.js +3 -3
- package/lib/audit-sign.js +5 -5
- package/lib/audit-tools.js +1 -1
- package/lib/audit.js +2 -2
- package/lib/auth/acr-vocabulary.js +2 -2
- package/lib/auth/bot-challenge.js +3 -3
- package/lib/auth/ciba.js +7 -7
- package/lib/auth/dpop.js +3 -3
- package/lib/auth/fido-mds3.js +8 -8
- package/lib/auth/jwt-external.js +5 -5
- package/lib/auth/oauth.js +2 -2
- package/lib/auth/oid4vci.js +9 -9
- package/lib/auth/oid4vp.js +2 -2
- package/lib/auth/openid-federation.js +2 -2
- package/lib/auth/passkey.js +3 -3
- package/lib/auth/saml.js +23 -23
- package/lib/auth/sd-jwt-vc-disclosure.js +1 -1
- package/lib/auth/sd-jwt-vc.js +4 -4
- package/lib/auth/status-list.js +10 -10
- package/lib/auth/step-up.js +1 -1
- package/lib/auth-bot-challenge.js +1 -1
- package/lib/backup/index.js +7 -7
- package/lib/base32.js +8 -8
- package/lib/budr.js +2 -2
- package/lib/cache-status.js +2 -2
- package/lib/calendar.js +23 -23
- package/lib/cbor.js +12 -12
- package/lib/cdn-cache-control.js +1 -1
- package/lib/cert.js +5 -5
- package/lib/cloud-events.js +5 -5
- package/lib/cms-codec.js +21 -21
- package/lib/codepoint-class.js +12 -12
- package/lib/compliance-sanctions-fuzzy.js +4 -4
- package/lib/compliance-sanctions.js +4 -4
- package/lib/compliance.js +29 -29
- package/lib/content-credentials.js +36 -36
- package/lib/cookies.js +1 -1
- package/lib/cose.js +13 -13
- package/lib/cra-report.js +1 -1
- package/lib/crdt.js +1 -1
- package/lib/crypto-field.js +2 -2
- package/lib/crypto-xwing.js +7 -7
- package/lib/crypto.js +6 -6
- package/lib/csp.js +2 -2
- package/lib/cwt.js +4 -4
- package/lib/dark-patterns.js +2 -2
- package/lib/data-act.js +2 -2
- package/lib/db-file-lifecycle.js +4 -4
- package/lib/db-query.js +1 -1
- package/lib/db.js +6 -6
- package/lib/dbsc.js +13 -13
- package/lib/did.js +17 -17
- package/lib/dora.js +4 -4
- package/lib/dsr.js +1 -1
- package/lib/early-hints.js +2 -2
- package/lib/eat.js +4 -4
- package/lib/external-db-migrate.js +1 -1
- package/lib/external-db.js +1 -1
- package/lib/flag-cache.js +1 -1
- package/lib/flag-evaluation-context.js +2 -2
- package/lib/graphql-federation.js +4 -4
- package/lib/guard-agent-registry.js +5 -5
- package/lib/guard-archive.js +24 -24
- package/lib/guard-cidr.js +33 -33
- package/lib/guard-csv.js +1 -1
- package/lib/guard-domain.js +10 -10
- package/lib/guard-dsn.js +4 -4
- package/lib/guard-email.js +19 -19
- package/lib/guard-event-bus-payload.js +4 -4
- package/lib/guard-event-bus-topic.js +6 -6
- package/lib/guard-filename.js +7 -7
- package/lib/guard-graphql.js +9 -9
- package/lib/guard-html-wcag-tagwalk.js +1 -1
- package/lib/guard-html-wcag.js +4 -4
- package/lib/guard-html.js +7 -7
- package/lib/guard-idempotency-key.js +6 -6
- package/lib/guard-image.js +4 -4
- package/lib/guard-imap-command.js +17 -17
- package/lib/guard-jmap.js +20 -20
- package/lib/guard-json.js +12 -12
- package/lib/guard-jsonpath.js +3 -3
- package/lib/guard-jwt.js +4 -4
- package/lib/guard-list-id.js +7 -7
- package/lib/guard-list-unsubscribe.js +8 -8
- package/lib/guard-mail-compose.js +4 -4
- package/lib/guard-mail-move.js +5 -5
- package/lib/guard-mail-query.js +3 -3
- package/lib/guard-mail-reply.js +3 -3
- package/lib/guard-mail-sieve.js +6 -6
- package/lib/guard-managesieve-command.js +25 -25
- package/lib/guard-markdown.js +31 -31
- package/lib/guard-message-id.js +5 -5
- package/lib/guard-mime.js +1 -1
- package/lib/guard-oauth.js +3 -3
- package/lib/guard-pdf.js +6 -6
- package/lib/guard-pop3-command.js +11 -11
- package/lib/guard-posture-chain.js +5 -5
- package/lib/guard-regex.js +10 -10
- package/lib/guard-saga-config.js +5 -5
- package/lib/guard-smtp-command.js +6 -6
- package/lib/guard-snapshot-envelope.js +3 -3
- package/lib/guard-stream-args.js +4 -4
- package/lib/guard-svg.js +11 -11
- package/lib/guard-tenant-id.js +5 -5
- package/lib/guard-time.js +15 -15
- package/lib/guard-trace-context.js +4 -4
- package/lib/guard-uuid.js +11 -11
- package/lib/guard-xml.js +12 -12
- package/lib/guard-yaml.js +16 -16
- package/lib/honeytoken.js +5 -5
- package/lib/http-client.js +1 -1
- package/lib/http-message-signature.js +2 -2
- package/lib/iab-mspa.js +3 -3
- package/lib/iab-tcf.js +70 -70
- package/lib/inbox.js +4 -4
- package/lib/ip-utils.js +15 -15
- package/lib/jose-jwe-experimental.js +2 -2
- package/lib/json-path.js +3 -3
- package/lib/json-schema.js +1 -1
- package/lib/jsonapi.js +3 -3
- package/lib/jtd.js +2 -2
- package/lib/link-header.js +1 -1
- package/lib/local-db-thin.js +1 -1
- package/lib/log.js +1 -1
- package/lib/lro.js +4 -4
- package/lib/mail-agent.js +1 -1
- package/lib/mail-arc-sign.js +6 -6
- package/lib/mail-auth.js +43 -43
- package/lib/mail-bimi.js +3 -3
- package/lib/mail-crypto-pgp.js +31 -31
- package/lib/mail-crypto-smime.js +5 -5
- package/lib/mail-dav.js +1 -1
- package/lib/mail-deploy.js +39 -39
- package/lib/mail-dkim.js +11 -11
- package/lib/mail-greylist.js +12 -12
- package/lib/mail-helo.js +1 -1
- package/lib/mail-journal.js +8 -8
- package/lib/mail-rbl.js +7 -7
- package/lib/mail-scan.js +7 -7
- package/lib/mail-send-deliver.js +2 -2
- package/lib/mail-server-imap.js +12 -12
- package/lib/mail-server-jmap.js +16 -16
- package/lib/mail-server-managesieve.js +4 -4
- package/lib/mail-server-mx.js +17 -17
- package/lib/mail-server-pop3.js +4 -4
- package/lib/mail-server-rate-limit.js +2 -2
- package/lib/mail-server-submission.js +21 -21
- package/lib/mail-sieve.js +2 -2
- package/lib/mail-spam-score.js +5 -5
- package/lib/mail-srs.js +12 -12
- package/lib/mail-store-fts.js +2 -2
- package/lib/mail-store.js +8 -8
- package/lib/mail-unsubscribe.js +4 -4
- package/lib/mail.js +4 -4
- package/lib/mcp-tool-registry.js +4 -4
- package/lib/mcp.js +8 -8
- package/lib/mdoc.js +2 -2
- package/lib/metrics.js +8 -8
- package/lib/middleware/age-gate.js +1 -1
- package/lib/middleware/api-encrypt.js +7 -7
- package/lib/middleware/assetlinks.js +2 -2
- package/lib/middleware/asyncapi-serve.js +2 -2
- package/lib/middleware/bearer-auth.js +5 -5
- package/lib/middleware/body-parser.js +5 -5
- package/lib/middleware/compose-pipeline.js +15 -15
- package/lib/middleware/csp-report.js +4 -4
- package/lib/middleware/daily-byte-quota.js +1 -1
- package/lib/middleware/dpop.js +1 -1
- package/lib/middleware/headers.js +2 -2
- package/lib/middleware/host-allowlist.js +1 -1
- package/lib/middleware/idempotency-key.js +12 -12
- package/lib/middleware/nel.js +1 -1
- package/lib/middleware/openapi-serve.js +2 -2
- package/lib/middleware/protected-resource-metadata.js +2 -2
- package/lib/middleware/require-aal.js +1 -1
- package/lib/middleware/require-bound-key.js +2 -2
- package/lib/middleware/require-content-type.js +1 -1
- package/lib/middleware/require-methods.js +1 -1
- package/lib/middleware/require-step-up.js +2 -2
- package/lib/middleware/scim-server.js +1 -1
- package/lib/middleware/security-txt.js +3 -3
- package/lib/middleware/tus-upload.js +12 -12
- package/lib/middleware/web-app-manifest.js +2 -2
- package/lib/network-byte-quota.js +1 -1
- package/lib/network-dns-resolver.js +23 -23
- package/lib/network-dns.js +29 -29
- package/lib/network-dnssec.js +33 -33
- package/lib/network-smtp-policy.js +10 -10
- package/lib/network-tls.js +87 -87
- package/lib/network-tsig.js +33 -33
- package/lib/nis2-report.js +1 -1
- package/lib/ntp-check.js +3 -3
- package/lib/observability-otlp-exporter.js +17 -17
- package/lib/observability-tracer.js +6 -6
- package/lib/observability.js +8 -8
- package/lib/openapi-yaml.js +1 -1
- package/lib/openapi.js +1 -1
- package/lib/outbox.js +6 -6
- package/lib/pqc-agent.js +4 -4
- package/lib/pqc-software.js +1 -1
- package/lib/privacy-pass.js +5 -5
- package/lib/problem-details.js +5 -5
- package/lib/promise-pool.js +1 -1
- package/lib/protobuf-encoder.js +1 -1
- package/lib/redact.js +2 -2
- package/lib/request-helpers.js +1 -1
- package/lib/router.js +10 -10
- package/lib/safe-async.js +2 -2
- package/lib/safe-dns.js +71 -71
- package/lib/safe-ical.js +19 -19
- package/lib/safe-icap.js +24 -24
- package/lib/safe-jsonpath.js +2 -2
- package/lib/safe-mime.js +10 -10
- package/lib/safe-mount-info.js +3 -3
- package/lib/safe-redirect.js +1 -1
- package/lib/safe-sieve.js +23 -23
- package/lib/safe-smtp.js +1 -1
- package/lib/safe-vcard.js +14 -14
- package/lib/sandbox.js +5 -5
- package/lib/sec-cyber.js +1 -1
- package/lib/self-update-standalone-verifier.js +3 -3
- package/lib/self-update.js +3 -3
- package/lib/server-timing.js +3 -3
- package/lib/session-device-binding.js +7 -7
- package/lib/session.js +8 -8
- package/lib/standard-webhooks.js +4 -4
- package/lib/storage.js +2 -2
- package/lib/stream-throttle.js +1 -1
- package/lib/structured-fields.js +15 -15
- package/lib/subject.js +1 -1
- package/lib/tcpa-10dlc.js +1 -1
- package/lib/tenant-quota.js +3 -3
- package/lib/test-harness.js +1 -1
- package/lib/tracing.js +1 -1
- package/lib/tsa.js +5 -5
- package/lib/uri-template.js +5 -5
- package/lib/vault/index.js +2 -2
- package/lib/vault/seal-pem-file.js +4 -4
- package/lib/vc.js +2 -2
- package/lib/vendor-data.js +1 -1
- package/lib/watcher.js +4 -4
- package/lib/web-push-vapid.js +21 -21
- package/lib/webhook.js +2 -2
- package/lib/websocket.js +3 -3
- package/lib/worker-pool.js +3 -3
- package/lib/ws-client.js +24 -24
- package/lib/xml-c14n.js +2 -2
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/mail-deploy.js
CHANGED
|
@@ -66,14 +66,14 @@ var TlsRptParseError = defineClass("TlsRptParseError", { alwaysPermanent: true }
|
|
|
66
66
|
var STS_MODES = Object.freeze({ enforce: 1, testing: 1, none: 1 });
|
|
67
67
|
|
|
68
68
|
function _domainOk(d) {
|
|
69
|
-
if (typeof d !== "string" || d.length === 0 || d.length > 253) return false; //
|
|
69
|
+
if (typeof d !== "string" || d.length === 0 || d.length > 253) return false; // RFC 1035 §2.3.4
|
|
70
70
|
// Bounded LDH check; we don't pull in b.guardDomain here because
|
|
71
71
|
// the helper is text-generation and the operator owns the value.
|
|
72
72
|
// Refuse C0 (covers CR / LF / NUL), DEL, and `"` outright —
|
|
73
73
|
// header-injection class + XML-attribute-injection class.
|
|
74
74
|
for (var i = 0; i < d.length; i++) {
|
|
75
75
|
var c = d.charCodeAt(i);
|
|
76
|
-
if (c < 0x20 || c === 0x7F || c === 0x22) return false; //
|
|
76
|
+
if (c < 0x20 || c === 0x7F || c === 0x22) return false; // refuse C0 / DEL / "
|
|
77
77
|
}
|
|
78
78
|
return true;
|
|
79
79
|
}
|
|
@@ -134,13 +134,13 @@ function mtaStsPublish(opts) {
|
|
|
134
134
|
throw new MailDeployError("mail-deploy/bad-mx",
|
|
135
135
|
"mtaStsPublish: opts.mxHosts must be a non-empty array");
|
|
136
136
|
}
|
|
137
|
-
if (opts.mxHosts.length > 64) { //
|
|
137
|
+
if (opts.mxHosts.length > 64) { // array cap
|
|
138
138
|
throw new MailDeployError("mail-deploy/bad-mx",
|
|
139
139
|
"mtaStsPublish: opts.mxHosts must contain at most 64 entries");
|
|
140
140
|
}
|
|
141
141
|
for (var i = 0; i < opts.mxHosts.length; i++) {
|
|
142
142
|
var m = opts.mxHosts[i];
|
|
143
|
-
if (typeof m !== "string" || m.length === 0 || m.length > 253) { //
|
|
143
|
+
if (typeof m !== "string" || m.length === 0 || m.length > 253) { // RFC 1035 cap
|
|
144
144
|
throw new MailDeployError("mail-deploy/bad-mx",
|
|
145
145
|
"mtaStsPublish: opts.mxHosts[" + i + "] invalid");
|
|
146
146
|
}
|
|
@@ -175,14 +175,14 @@ function mtaStsPublish(opts) {
|
|
|
175
175
|
// so peers can detect the change without re-fetching every fetch.
|
|
176
176
|
var policyId;
|
|
177
177
|
if (typeof opts.policyId === "string" && opts.policyId.length > 0) {
|
|
178
|
-
if (!/^[a-zA-Z0-9_-]{1,32}$/.test(opts.policyId)) { //
|
|
178
|
+
if (!/^[a-zA-Z0-9_-]{1,32}$/.test(opts.policyId)) { // RFC 8461 §3.1 token shape
|
|
179
179
|
throw new MailDeployError("mail-deploy/bad-policy-id",
|
|
180
180
|
"mtaStsPublish: opts.policyId must match [a-zA-Z0-9_-]{1,32}");
|
|
181
181
|
}
|
|
182
182
|
policyId = opts.policyId;
|
|
183
183
|
} else {
|
|
184
184
|
// ISO 8601 timestamp w/o punctuation = unique-by-second.
|
|
185
|
-
policyId = new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 16); //
|
|
185
|
+
policyId = new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 16); // yyyymmddhhmmssms
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
return {
|
|
@@ -229,7 +229,7 @@ function danePublish(opts) {
|
|
|
229
229
|
MailDeployError, "mail-deploy/bad-opts");
|
|
230
230
|
validateOpts.requireNonEmptyString(opts.certPem,
|
|
231
231
|
"b.mail.deploy.danePublish: opts.certPem", MailDeployError, "mail-deploy/bad-cert");
|
|
232
|
-
if (opts.certPem.length > 65536) { //
|
|
232
|
+
if (opts.certPem.length > 65536) { // sanity cap on PEM input
|
|
233
233
|
throw new MailDeployError("mail-deploy/bad-cert",
|
|
234
234
|
"danePublish: opts.certPem too large");
|
|
235
235
|
}
|
|
@@ -237,14 +237,14 @@ function danePublish(opts) {
|
|
|
237
237
|
throw new MailDeployError("mail-deploy/bad-mx-host",
|
|
238
238
|
"danePublish: opts.mxHost must be a valid hostname");
|
|
239
239
|
}
|
|
240
|
-
var port = opts.port === undefined ? 25 : opts.port; //
|
|
241
|
-
if (!numericBounds.isPositiveFiniteInt(port) || port > 65535) { //
|
|
240
|
+
var port = opts.port === undefined ? 25 : opts.port; // RFC 7672 §3.1 default port
|
|
241
|
+
if (!numericBounds.isPositiveFiniteInt(port) || port > 65535) { // IANA port range
|
|
242
242
|
throw new MailDeployError("mail-deploy/bad-port",
|
|
243
243
|
"danePublish: opts.port must be 1..65535");
|
|
244
244
|
}
|
|
245
|
-
var usage = opts.usage === undefined ? 3 : opts.usage; //
|
|
246
|
-
var selector = opts.selector === undefined ? 1 : opts.selector; //
|
|
247
|
-
var matchType = opts.matchType === undefined ? 1 : opts.matchType; //
|
|
245
|
+
var usage = opts.usage === undefined ? 3 : opts.usage; // DANE-EE
|
|
246
|
+
var selector = opts.selector === undefined ? 1 : opts.selector; // SPKI
|
|
247
|
+
var matchType = opts.matchType === undefined ? 1 : opts.matchType; // SHA-256
|
|
248
248
|
if ([0, 1, 2, 3].indexOf(usage) === -1) {
|
|
249
249
|
throw new MailDeployError("mail-deploy/bad-usage",
|
|
250
250
|
"danePublish: opts.usage must be 0|1|2|3 (RFC 6698 §2.1.1)");
|
|
@@ -330,7 +330,7 @@ function autoConfigXml(opts) {
|
|
|
330
330
|
}
|
|
331
331
|
var brand = typeof opts.displayName === "string" && opts.displayName.length > 0 ?
|
|
332
332
|
opts.displayName : opts.domain;
|
|
333
|
-
if (brand.length > 256) { //
|
|
333
|
+
if (brand.length > 256) { // DOM attr cap
|
|
334
334
|
throw new MailDeployError("mail-deploy/bad-displayName",
|
|
335
335
|
"autoConfigXml: opts.displayName too long");
|
|
336
336
|
}
|
|
@@ -347,7 +347,7 @@ function autoConfigXml(opts) {
|
|
|
347
347
|
throw new MailDeployError("mail-deploy/bad-host",
|
|
348
348
|
"autoConfigXml: opts." + protocol + ".host invalid");
|
|
349
349
|
}
|
|
350
|
-
if (!numericBounds.isPositiveFiniteInt(cfg.port) || cfg.port > 65535) { //
|
|
350
|
+
if (!numericBounds.isPositiveFiniteInt(cfg.port) || cfg.port > 65535) { // IANA port
|
|
351
351
|
throw new MailDeployError("mail-deploy/bad-port",
|
|
352
352
|
"autoConfigXml: opts." + protocol + ".port invalid");
|
|
353
353
|
}
|
|
@@ -368,14 +368,14 @@ function autoConfigXml(opts) {
|
|
|
368
368
|
// `jmapServer` per the Mozilla draft + Fastmail convention).
|
|
369
369
|
function _jmapServer(cfg) {
|
|
370
370
|
if (!cfg) return "";
|
|
371
|
-
if (typeof cfg.url !== "string" || cfg.url.length === 0 || cfg.url.length > 1024) { //
|
|
371
|
+
if (typeof cfg.url !== "string" || cfg.url.length === 0 || cfg.url.length > 1024) { // URL cap
|
|
372
372
|
throw new MailDeployError("mail-deploy/bad-jmap-url",
|
|
373
373
|
"autoConfigXml: opts.jmap.url must be a non-empty string");
|
|
374
374
|
}
|
|
375
375
|
// Refuse control bytes / quote in the URL.
|
|
376
376
|
for (var k = 0; k < cfg.url.length; k++) {
|
|
377
377
|
var c = cfg.url.charCodeAt(k);
|
|
378
|
-
if (c < 0x20 || c === 0x7F || c === 0x22) { //
|
|
378
|
+
if (c < 0x20 || c === 0x7F || c === 0x22) { // C0 / DEL / "
|
|
379
379
|
throw new MailDeployError("mail-deploy/bad-jmap-url",
|
|
380
380
|
"autoConfigXml: opts.jmap.url contains control byte");
|
|
381
381
|
}
|
|
@@ -437,14 +437,14 @@ function autoConfigXml(opts) {
|
|
|
437
437
|
function autoDiscoverXml(opts) {
|
|
438
438
|
validateOpts.requireObject(opts || {}, "b.mail.deploy.autoDiscoverXml",
|
|
439
439
|
MailDeployError, "mail-deploy/bad-opts");
|
|
440
|
-
if (typeof opts.email !== "string" || opts.email.length === 0 || opts.email.length > 254) { //
|
|
440
|
+
if (typeof opts.email !== "string" || opts.email.length === 0 || opts.email.length > 254) { // RFC 5321 cap
|
|
441
441
|
throw new MailDeployError("mail-deploy/bad-email",
|
|
442
442
|
"autoDiscoverXml: opts.email must be a non-empty string");
|
|
443
443
|
}
|
|
444
444
|
// Refuse CR / LF / NUL / control bytes in email (XML injection class).
|
|
445
445
|
for (var i = 0; i < opts.email.length; i++) {
|
|
446
446
|
var c = opts.email.charCodeAt(i);
|
|
447
|
-
if (c < 0x20 || c === 0x7F) { //
|
|
447
|
+
if (c < 0x20 || c === 0x7F) { // C0 / DEL
|
|
448
448
|
throw new MailDeployError("mail-deploy/bad-email",
|
|
449
449
|
"autoDiscoverXml: opts.email contains control byte");
|
|
450
450
|
}
|
|
@@ -455,7 +455,7 @@ function autoDiscoverXml(opts) {
|
|
|
455
455
|
throw new MailDeployError("mail-deploy/bad-host",
|
|
456
456
|
"autoDiscoverXml: opts." + kind.toLowerCase() + ".host invalid");
|
|
457
457
|
}
|
|
458
|
-
if (!numericBounds.isPositiveFiniteInt(cfg.port) || cfg.port > 65535) { //
|
|
458
|
+
if (!numericBounds.isPositiveFiniteInt(cfg.port) || cfg.port > 65535) { // IANA port
|
|
459
459
|
throw new MailDeployError("mail-deploy/bad-port",
|
|
460
460
|
"autoDiscoverXml: opts." + kind.toLowerCase() + ".port invalid");
|
|
461
461
|
}
|
|
@@ -530,13 +530,13 @@ function autoDiscoverXml(opts) {
|
|
|
530
530
|
// integer overflow) and the decompression-amplification class
|
|
531
531
|
// (CWE-409), plus the §5.2 community ceiling (receivers commonly cap
|
|
532
532
|
// at 10 MiB).
|
|
533
|
-
var TLSRPT_MAX_COMPRESSED_BYTES = C.BYTES.mib(4); //
|
|
534
|
-
var TLSRPT_MAX_DECOMPRESSED_BYTES = C.BYTES.mib(32); //
|
|
535
|
-
var TLSRPT_MAX_RATIO = 50; //
|
|
536
|
-
var TLSRPT_MAX_POLICIES = 1000; // allow:raw-
|
|
537
|
-
var TLSRPT_MAX_FAILURE_DETAILS = 10000; //
|
|
538
|
-
var TLSRPT_GZIP_MAGIC_0 = 0x1f; //
|
|
539
|
-
var TLSRPT_GZIP_MAGIC_1 = 0x8b; //
|
|
533
|
+
var TLSRPT_MAX_COMPRESSED_BYTES = C.BYTES.mib(4); // 4 MiB compressed cap per §5.2 community practice
|
|
534
|
+
var TLSRPT_MAX_DECOMPRESSED_BYTES = C.BYTES.mib(32); // 32 MiB decompressed cap (operators override via opts)
|
|
535
|
+
var TLSRPT_MAX_RATIO = 50; // 50:1 compression ratio refusal
|
|
536
|
+
var TLSRPT_MAX_POLICIES = 1000; // allow:raw-time-literal — RFC 8460 §4.4 policy-cardinality cap
|
|
537
|
+
var TLSRPT_MAX_FAILURE_DETAILS = 10000; // per-policy failure-details cap
|
|
538
|
+
var TLSRPT_GZIP_MAGIC_0 = 0x1f; // RFC 1952 gzip magic byte 0
|
|
539
|
+
var TLSRPT_GZIP_MAGIC_1 = 0x8b; // RFC 1952 gzip magic byte 1
|
|
540
540
|
|
|
541
541
|
// Valid RFC 8460 §4.4 result-type values for `failure-details[].result-type`.
|
|
542
542
|
var TLSRPT_RESULT_TYPES = Object.freeze({
|
|
@@ -658,8 +658,8 @@ function parseTlsRptReport(input, opts) {
|
|
|
658
658
|
try {
|
|
659
659
|
raw = guardJson().parse(bytes.toString("utf8"), {
|
|
660
660
|
maxBytes: maxDecompressed,
|
|
661
|
-
maxDepth: 32, //
|
|
662
|
-
maxKeys: 1000, //
|
|
661
|
+
maxDepth: 32, // JSON depth cap
|
|
662
|
+
maxKeys: 1000, // top-level key cap
|
|
663
663
|
});
|
|
664
664
|
} catch (_e) {
|
|
665
665
|
// Fall back to b.safeJson.parse if guardJson isn't available (in
|
|
@@ -946,7 +946,7 @@ function tlsRptIngestHttp(opts) {
|
|
|
946
946
|
|
|
947
947
|
return function tlsRptHandler(req, res) {
|
|
948
948
|
if (req.method !== "POST") {
|
|
949
|
-
res.writeHead(405, { "Allow": "POST", "Content-Type": "text/plain" }); // allow:raw-
|
|
949
|
+
res.writeHead(405, { "Allow": "POST", "Content-Type": "text/plain" }); // allow:raw-time-literal — RFC 8460 §5.4 status code
|
|
950
950
|
res.end("RFC 8460 §5.4 requires POST\n");
|
|
951
951
|
return;
|
|
952
952
|
}
|
|
@@ -958,7 +958,7 @@ function tlsRptIngestHttp(opts) {
|
|
|
958
958
|
});
|
|
959
959
|
if (onRefuse) try { onRefuse("mail-tlsrpt/bad-content-type", "unexpected content-type " + ctRoot, req); }
|
|
960
960
|
catch (_e) { /* drop-silent */ }
|
|
961
|
-
res.writeHead(415, { "Content-Type": "text/plain", "Accept": "application/tlsrpt+json, application/tlsrpt+gzip" }); // allow:raw-
|
|
961
|
+
res.writeHead(415, { "Content-Type": "text/plain", "Accept": "application/tlsrpt+json, application/tlsrpt+gzip" }); // allow:raw-time-literal — RFC 8460 §5.4 status code
|
|
962
962
|
res.end("RFC 8460 §6.4-6.5 media types required\n");
|
|
963
963
|
return;
|
|
964
964
|
}
|
|
@@ -975,7 +975,7 @@ function tlsRptIngestHttp(opts) {
|
|
|
975
975
|
_safeAuditEmit(opts.audit, "mail.tlsrpt.ingest_http", "denied", { reason: "unauthenticated" });
|
|
976
976
|
if (onRefuse) try { onRefuse("mail-tlsrpt/unauthenticated", "authenticate(req) returned falsy", req); }
|
|
977
977
|
catch (_e) { /* drop-silent */ }
|
|
978
|
-
res.writeHead(401, { "Content-Type": "text/plain", "Error-Type": "mail-tlsrpt/unauthenticated" }); // allow:raw-
|
|
978
|
+
res.writeHead(401, { "Content-Type": "text/plain", "Error-Type": "mail-tlsrpt/unauthenticated" }); // allow:raw-time-literal — RFC 8460 §5.4 status code
|
|
979
979
|
res.end("authentication required\n");
|
|
980
980
|
return;
|
|
981
981
|
}
|
|
@@ -986,7 +986,7 @@ function tlsRptIngestHttp(opts) {
|
|
|
986
986
|
});
|
|
987
987
|
if (onRefuse) try { onRefuse("mail-tlsrpt/auth-error", (err && err.message) || String(err), req); }
|
|
988
988
|
catch (_e) { /* drop-silent */ }
|
|
989
|
-
res.writeHead(500, { "Content-Type": "text/plain", "Error-Type": "mail-tlsrpt/auth-error" }); // allow:raw-
|
|
989
|
+
res.writeHead(500, { "Content-Type": "text/plain", "Error-Type": "mail-tlsrpt/auth-error" }); // allow:raw-time-literal — RFC 8460 §5.4 status code
|
|
990
990
|
res.end("authenticate hook threw\n");
|
|
991
991
|
});
|
|
992
992
|
return;
|
|
@@ -1012,7 +1012,7 @@ function tlsRptIngestHttp(opts) {
|
|
|
1012
1012
|
if (onRefuse) try { onRefuse("mail-tlsrpt/oversize-compressed", "body exceeded " + maxCompressed + " bytes", req); }
|
|
1013
1013
|
catch (_e) { /* drop-silent */ }
|
|
1014
1014
|
if (!res.headersSent) {
|
|
1015
|
-
res.writeHead(413, { "Content-Type": "text/plain" }); // allow:raw-
|
|
1015
|
+
res.writeHead(413, { "Content-Type": "text/plain" }); // allow:raw-time-literal — RFC 8460 §5.4 status code
|
|
1016
1016
|
res.end("RFC 8460 §5.4 — body exceeds " + maxCompressed + " bytes\n");
|
|
1017
1017
|
}
|
|
1018
1018
|
void e; // _e shadowed by lower scope; mark intent
|
|
@@ -1036,7 +1036,7 @@ function tlsRptIngestHttp(opts) {
|
|
|
1036
1036
|
: code === "mail-tlsrpt/gunzip-bomb" ? 413
|
|
1037
1037
|
: code === "mail-tlsrpt/ratio-bomb" ? 413
|
|
1038
1038
|
: code === "mail-tlsrpt/bad-content-type" ? 415
|
|
1039
|
-
: 400; // allow:raw-
|
|
1039
|
+
: 400; // allow:raw-time-literal — RFC 8460 §5.4 status code
|
|
1040
1040
|
res.writeHead(status, { "Content-Type": "text/plain", "Error-Type": code });
|
|
1041
1041
|
res.end("RFC 8460 §5.4 — refused: " + code + "\n");
|
|
1042
1042
|
return;
|
|
@@ -1048,7 +1048,7 @@ function tlsRptIngestHttp(opts) {
|
|
|
1048
1048
|
if (onRefuse) try { onRefuse("mail-tlsrpt/untrusted-reporter",
|
|
1049
1049
|
"reporter '" + report["organization-name"] + "' not in trustedReporters", req); }
|
|
1050
1050
|
catch (_e) { /* drop-silent */ }
|
|
1051
|
-
res.writeHead(403, { "Content-Type": "text/plain", "Error-Type": "mail-tlsrpt/untrusted-reporter" }); // allow:raw-
|
|
1051
|
+
res.writeHead(403, { "Content-Type": "text/plain", "Error-Type": "mail-tlsrpt/untrusted-reporter" }); // allow:raw-time-literal — RFC 8460 §5.4 status code
|
|
1052
1052
|
res.end("RFC 8460 §5.3-class: untrusted reporter\n");
|
|
1053
1053
|
return;
|
|
1054
1054
|
}
|
|
@@ -1069,12 +1069,12 @@ function tlsRptIngestHttp(opts) {
|
|
|
1069
1069
|
if (ret && typeof ret.then === "function") {
|
|
1070
1070
|
ret.then(function () {
|
|
1071
1071
|
if (!res.headersSent) {
|
|
1072
|
-
res.writeHead(201, { "Content-Type": "text/plain" }); // allow:raw-
|
|
1072
|
+
res.writeHead(201, { "Content-Type": "text/plain" }); // allow:raw-time-literal — RFC 8460 §5.4 status code
|
|
1073
1073
|
res.end("RFC 8460 §5.4 — accepted\n");
|
|
1074
1074
|
}
|
|
1075
1075
|
}, function (_e) {
|
|
1076
1076
|
if (!res.headersSent) {
|
|
1077
|
-
res.writeHead(500, { "Content-Type": "text/plain" }); //
|
|
1077
|
+
res.writeHead(500, { "Content-Type": "text/plain" }); // internal-error status
|
|
1078
1078
|
res.end("internal error processing report\n");
|
|
1079
1079
|
}
|
|
1080
1080
|
});
|
|
@@ -1082,7 +1082,7 @@ function tlsRptIngestHttp(opts) {
|
|
|
1082
1082
|
}
|
|
1083
1083
|
} catch (_e) { /* fall through to 201 — operator hook is best-effort */ }
|
|
1084
1084
|
}
|
|
1085
|
-
res.writeHead(201, { "Content-Type": "text/plain" }); // allow:raw-
|
|
1085
|
+
res.writeHead(201, { "Content-Type": "text/plain" }); // allow:raw-time-literal — RFC 8460 §5.4 status code
|
|
1086
1086
|
res.end("RFC 8460 §5.4 — accepted\n");
|
|
1087
1087
|
});
|
|
1088
1088
|
req.on("error", function () {
|
|
@@ -1090,7 +1090,7 @@ function tlsRptIngestHttp(opts) {
|
|
|
1090
1090
|
aborted = true;
|
|
1091
1091
|
_safeAuditEmit(opts.audit, "mail.tlsrpt.ingest_http", "denied", { reason: "req-error" });
|
|
1092
1092
|
if (!res.headersSent) {
|
|
1093
|
-
res.writeHead(400, { "Content-Type": "text/plain" }); // allow:raw-
|
|
1093
|
+
res.writeHead(400, { "Content-Type": "text/plain" }); // allow:raw-time-literal — RFC 8460 §5.4 status code
|
|
1094
1094
|
res.end("malformed request\n");
|
|
1095
1095
|
}
|
|
1096
1096
|
});
|
package/lib/mail-dkim.js
CHANGED
|
@@ -76,9 +76,9 @@ var DEFAULT_HEADERS = ["from", "to", "subject", "date", "message-id"];
|
|
|
76
76
|
// before bulk-sending) opt down via verify({ minRsaBits: 1024 }) per-call
|
|
77
77
|
// — the historical floor stays available for migration but the
|
|
78
78
|
// framework default refuses sub-2048 inbound.
|
|
79
|
-
var RSA_MIN_BITS = 2048; //
|
|
80
|
-
var RSA_WEAK_BITS = 2048; //
|
|
81
|
-
var RSA_LEGACY_MIN_BITS = 1024; //
|
|
79
|
+
var RSA_MIN_BITS = 2048; // RFC 8301bis + 2024 bulk-sender floor
|
|
80
|
+
var RSA_WEAK_BITS = 2048; // RFC 8301bis weak threshold (same as floor)
|
|
81
|
+
var RSA_LEGACY_MIN_BITS = 1024; // RFC 8301 historical floor, opt-in only
|
|
82
82
|
|
|
83
83
|
// ---- Canonicalization (RFC 6376 §3.4) ----
|
|
84
84
|
|
|
@@ -232,7 +232,7 @@ function create(opts) {
|
|
|
232
232
|
// keys). Each label is the LDH set; refuse leading/trailing dots and
|
|
233
233
|
// empty labels.
|
|
234
234
|
if (typeof opts.selector !== "string" ||
|
|
235
|
-
opts.selector.length === 0 || opts.selector.length > 253 || //
|
|
235
|
+
opts.selector.length === 0 || opts.selector.length > 253 || // DNS label length cap (RFC 1035)
|
|
236
236
|
!/^[a-z0-9_-]+(?:\.[a-z0-9_-]+)*$/i.test(opts.selector)) {
|
|
237
237
|
throw new DkimError("dkim/bad-selector",
|
|
238
238
|
"selector must be a non-empty LDH token, optionally dot-separated (e.g. 's1', '2024.s1') (RFC 6376 §3.1)");
|
|
@@ -524,12 +524,12 @@ var DKIM_KEY_CACHE_MAX_ENTRIES = 1024;
|
|
|
524
524
|
// permits multiple signatures but doesn't bound them; mainstream
|
|
525
525
|
// receivers cap at 5–8. Operators that legitimately accept more
|
|
526
526
|
// override via verify({ maxSignatures }).
|
|
527
|
-
var DKIM_MAX_SIGNATURES_PER_MESSAGE = 8; //
|
|
527
|
+
var DKIM_MAX_SIGNATURES_PER_MESSAGE = 8; // receiver-fan-out DoS bound
|
|
528
528
|
// Operator-supplied `maxSignatures` opt is range-checked against this
|
|
529
529
|
// ceiling. RFC 6376 §6.1 sets no upper bound; 16 is generous headroom
|
|
530
530
|
// for legitimate relay chains with hop signatures while keeping the
|
|
531
531
|
// verify-fan-out within a CPU-DoS envelope.
|
|
532
|
-
var DKIM_MAX_SIGNATURES_PER_MESSAGE_CEILING = 16; //
|
|
532
|
+
var DKIM_MAX_SIGNATURES_PER_MESSAGE_CEILING = 16; // operator-opt range ceiling
|
|
533
533
|
|
|
534
534
|
function _cacheGet(qname) {
|
|
535
535
|
var ent = DKIM_KEY_CACHE.get(qname);
|
|
@@ -579,7 +579,7 @@ async function _safeResolveTxt(qname, operatorLookup) {
|
|
|
579
579
|
var out = [];
|
|
580
580
|
for (var i = 0; i < r.rrs.length; i += 1) {
|
|
581
581
|
var rr = r.rrs[i];
|
|
582
|
-
if (rr && rr.type === 16) { //
|
|
582
|
+
if (rr && rr.type === 16) { // IANA DNS qtype TXT
|
|
583
583
|
out.push(Array.isArray(rr.decoded) ? rr.decoded : [String(rr.decoded)]);
|
|
584
584
|
}
|
|
585
585
|
}
|
|
@@ -599,8 +599,8 @@ function _pemFromB64KeyMaterial(b64) {
|
|
|
599
599
|
// accepts it.
|
|
600
600
|
var pem = "-----BEGIN PUBLIC KEY-----\n";
|
|
601
601
|
// 64-char wrap (PEM convention).
|
|
602
|
-
for (var i = 0; i < b64.length; i += 64) { //
|
|
603
|
-
pem += b64.slice(i, i + 64) + "\n"; //
|
|
602
|
+
for (var i = 0; i < b64.length; i += 64) { // PEM wrap width
|
|
603
|
+
pem += b64.slice(i, i + 64) + "\n"; // PEM wrap width
|
|
604
604
|
}
|
|
605
605
|
pem += "-----END PUBLIC KEY-----\n";
|
|
606
606
|
return pem;
|
|
@@ -1226,9 +1226,9 @@ function _bootstrapSingle(algorithm, domain, selector, rsaBits) {
|
|
|
1226
1226
|
// each capped at 255 octets. Long RSA p= values are split into multiple
|
|
1227
1227
|
// quoted strings so the zone file is valid.
|
|
1228
1228
|
function _wrapDnsTxt(value) {
|
|
1229
|
-
if (value.length <= 255) return '"' + value + '"'; //
|
|
1229
|
+
if (value.length <= 255) return '"' + value + '"'; // RFC 1035 character-string cap
|
|
1230
1230
|
var parts = [];
|
|
1231
|
-
for (var i = 0; i < value.length; i += 255) parts.push('"' + value.slice(i, i + 255) + '"'); //
|
|
1231
|
+
for (var i = 0; i < value.length; i += 255) parts.push('"' + value.slice(i, i + 255) + '"'); // RFC 1035 character-string cap
|
|
1232
1232
|
return parts.join(" ");
|
|
1233
1233
|
}
|
|
1234
1234
|
|
package/lib/mail-greylist.js
CHANGED
|
@@ -109,21 +109,21 @@ var MailGreylistError = defineClass("MailGreylistError", { alwaysPermanent: true
|
|
|
109
109
|
|
|
110
110
|
var DEFAULT_MIN_DELAY_MS = C.TIME.minutes(5);
|
|
111
111
|
var DEFAULT_WHITELIST_TTL = C.TIME.days(36);
|
|
112
|
-
var DEFAULT_MAX_ENTRIES = 1000000; //
|
|
113
|
-
var DEFAULT_IPV4_PREFIX = 24; //
|
|
114
|
-
var DEFAULT_IPV6_PREFIX = 64; //
|
|
112
|
+
var DEFAULT_MAX_ENTRIES = 1000000; // entry-count cap, not bytes
|
|
113
|
+
var DEFAULT_IPV4_PREFIX = 24; // RFC 6647 §4.4 IP-clustering granularity
|
|
114
|
+
var DEFAULT_IPV6_PREFIX = 64; // RFC 6647 §4.4 IPv6 IP-clustering granularity
|
|
115
115
|
var DEFAULT_PROFILE = "strict";
|
|
116
116
|
|
|
117
117
|
var PROFILES = Object.freeze({
|
|
118
118
|
// Strict: low delay, modest whitelist TTL. Catches snowshoe but
|
|
119
119
|
// retries from legitimate MTAs (which back off 5-15 min on tempfail)
|
|
120
120
|
// pass quickly.
|
|
121
|
-
strict: { minDelayMs: C.TIME.minutes(5), whitelistTtlMs: C.TIME.days(36), ipv4Prefix: 24, ipv6Prefix: 64 }, //
|
|
121
|
+
strict: { minDelayMs: C.TIME.minutes(5), whitelistTtlMs: C.TIME.days(36), ipv4Prefix: 24, ipv6Prefix: 64 }, // RFC 6647 §4.4 prefixes
|
|
122
122
|
// Balanced: minimum 1 min delay, shorter TTL for higher churn.
|
|
123
|
-
balanced: { minDelayMs: C.TIME.minutes(1), whitelistTtlMs: C.TIME.days(7), ipv4Prefix: 24, ipv6Prefix: 64 }, //
|
|
123
|
+
balanced: { minDelayMs: C.TIME.minutes(1), whitelistTtlMs: C.TIME.days(7), ipv4Prefix: 24, ipv6Prefix: 64 }, // RFC 6647 §4.4 prefixes
|
|
124
124
|
// Permissive: 30s delay, 30-day TTL. For operators that want
|
|
125
125
|
// greylisting present but minimally visible.
|
|
126
|
-
permissive: { minDelayMs: C.TIME.seconds(30), whitelistTtlMs: C.TIME.days(30), ipv4Prefix: 32, ipv6Prefix: 128 }, //
|
|
126
|
+
permissive: { minDelayMs: C.TIME.seconds(30), whitelistTtlMs: C.TIME.days(30), ipv4Prefix: 32, ipv6Prefix: 128 }, // RFC 6647 §4.4 prefixes
|
|
127
127
|
});
|
|
128
128
|
|
|
129
129
|
var COMPLIANCE_POSTURES = Object.freeze({
|
|
@@ -347,13 +347,13 @@ function _hashFingerprint(cidr, mailFrom, rcptTo) {
|
|
|
347
347
|
function _cidrKey(ip, ipv4Prefix, ipv6Prefix) {
|
|
348
348
|
if (IPV4_RE.test(ip)) {
|
|
349
349
|
var octets = ip.split(".").map(function (s) { return parseInt(s, 10); });
|
|
350
|
-
var prefix = Math.min(32, Math.max(0, ipv4Prefix)); //
|
|
350
|
+
var prefix = Math.min(32, Math.max(0, ipv4Prefix)); // IPv4 address bit width
|
|
351
351
|
// Apply prefix: zero out the host bits.
|
|
352
|
-
var int = (octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3]; //
|
|
353
|
-
var mask = prefix === 0 ? 0 : (~0 << (32 - prefix)) >>> 0; //
|
|
352
|
+
var int = (octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3]; // IPv4 byte shifts
|
|
353
|
+
var mask = prefix === 0 ? 0 : (~0 << (32 - prefix)) >>> 0; // IPv4 mask construction
|
|
354
354
|
var masked = (int & mask) >>> 0;
|
|
355
355
|
return [
|
|
356
|
-
(masked >>> 24) & 0xff, //
|
|
356
|
+
(masked >>> 24) & 0xff, // IPv4 byte extraction
|
|
357
357
|
(masked >>> 16) & 0xff,
|
|
358
358
|
(masked >>> 8) & 0xff,
|
|
359
359
|
masked & 0xff,
|
|
@@ -368,8 +368,8 @@ function _cidrKey(ip, ipv4Prefix, ipv6Prefix) {
|
|
|
368
368
|
"IP '" + ip + "' is not a parseable IPv6 address");
|
|
369
369
|
}
|
|
370
370
|
// expanded is 32 hex chars; mask to ipv6Prefix bits.
|
|
371
|
-
var prefixBits = Math.min(128, Math.max(0, ipv6Prefix)); //
|
|
372
|
-
var keepNibbles = Math.floor(prefixBits / 4); //
|
|
371
|
+
var prefixBits = Math.min(128, Math.max(0, ipv6Prefix)); // IPv6 address bit width
|
|
372
|
+
var keepNibbles = Math.floor(prefixBits / 4); // bits-per-hex-nibble
|
|
373
373
|
var keptHex = expanded.slice(0, keepNibbles);
|
|
374
374
|
return keptHex + "*/" + prefixBits;
|
|
375
375
|
}
|
package/lib/mail-helo.js
CHANGED
|
@@ -116,7 +116,7 @@ var LDH_LABEL_RE = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$/;
|
|
|
116
116
|
var ADDR_LIT_V4_RE = /^\[((?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})\]$/; // allow:regex-no-length-cap — anchored + per-octet repeat cap
|
|
117
117
|
var ADDR_LIT_V6_RE = /^\[IPv6:([0-9a-fA-F:.]+)\]$/; // allow:regex-no-length-cap — IPv6 textual bounded by overall maxBytes
|
|
118
118
|
|
|
119
|
-
var DEFAULT_MAX_BYTES = 255; //
|
|
119
|
+
var DEFAULT_MAX_BYTES = 255; // RFC 1035 §2.3.4 cap
|
|
120
120
|
var DEFAULT_PROFILE = "strict";
|
|
121
121
|
|
|
122
122
|
var PROFILES = Object.freeze({
|
package/lib/mail-journal.js
CHANGED
|
@@ -102,7 +102,7 @@ function _validateRegimes(regimes) {
|
|
|
102
102
|
"b.mail.journal.create: opts.regimes must be a non-empty array of regime names " +
|
|
103
103
|
"(known: " + Object.keys(REGIME_FLOOR_MS).join(", ") + ")");
|
|
104
104
|
}
|
|
105
|
-
if (regimes.length > 16) { //
|
|
105
|
+
if (regimes.length > 16) { // regime-list cap
|
|
106
106
|
throw new MailJournalError("mail-journal/bad-regimes",
|
|
107
107
|
"b.mail.journal.create: opts.regimes must contain at most 16 entries");
|
|
108
108
|
}
|
|
@@ -191,7 +191,7 @@ function create(opts) {
|
|
|
191
191
|
|
|
192
192
|
var namespace = typeof opts.namespace === "string" && opts.namespace.length > 0 ?
|
|
193
193
|
opts.namespace : "mail-journal";
|
|
194
|
-
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(namespace)) { //
|
|
194
|
+
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(namespace)) { // namespace token shape
|
|
195
195
|
throw new MailJournalError("mail-journal/bad-namespace",
|
|
196
196
|
"b.mail.journal.create: opts.namespace must match [a-zA-Z0-9_-]{1,64}");
|
|
197
197
|
}
|
|
@@ -250,7 +250,7 @@ function create(opts) {
|
|
|
250
250
|
}
|
|
251
251
|
validateOpts.requireNonEmptyString(req.actorId,
|
|
252
252
|
"mail.journal.record: opts.actorId", MailJournalError, "mail-journal/bad-actor");
|
|
253
|
-
if (typeof req.messageId !== "string" || req.messageId.length === 0 || req.messageId.length > 1024) { //
|
|
253
|
+
if (typeof req.messageId !== "string" || req.messageId.length === 0 || req.messageId.length > 1024) { // Message-Id cap
|
|
254
254
|
throw new MailJournalError("mail-journal/bad-message-id",
|
|
255
255
|
"mail.journal.record: opts.messageId must be a non-empty string");
|
|
256
256
|
}
|
|
@@ -258,13 +258,13 @@ function create(opts) {
|
|
|
258
258
|
throw new MailJournalError("mail-journal/bad-body",
|
|
259
259
|
"mail.journal.record: opts.bodyBytes must be a Buffer");
|
|
260
260
|
}
|
|
261
|
-
if (req.bodyBytes.length > C.BYTES.mib(256)) { //
|
|
261
|
+
if (req.bodyBytes.length > C.BYTES.mib(256)) { // per-message cap
|
|
262
262
|
throw new MailJournalError("mail-journal/too-large",
|
|
263
263
|
"mail.journal.record: message " + req.bodyBytes.length + " bytes exceeds 256 MiB cap");
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
var journalId = "j" + Date.now().toString(36) + "-" +
|
|
267
|
-
require("node:crypto").randomBytes(8).toString("hex"); //
|
|
267
|
+
require("node:crypto").randomBytes(8).toString("hex"); // 8-byte rand
|
|
268
268
|
var archivedAt = Date.now();
|
|
269
269
|
var sizeBytes = req.bodyBytes.length;
|
|
270
270
|
var storageKey = namespace + "/" + archivedAt + "/" + journalId + ".eml.sealed";
|
|
@@ -313,7 +313,7 @@ function create(opts) {
|
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
async function getById(journalId) {
|
|
316
|
-
if (typeof journalId !== "string" || journalId.length === 0 || journalId.length > 256) { //
|
|
316
|
+
if (typeof journalId !== "string" || journalId.length === 0 || journalId.length > 256) { // id cap
|
|
317
317
|
throw new MailJournalError("mail-journal/bad-id",
|
|
318
318
|
"mail.journal.getById: journalId must be a non-empty string");
|
|
319
319
|
}
|
|
@@ -362,7 +362,7 @@ function create(opts) {
|
|
|
362
362
|
clauses.push("actor_id = ?");
|
|
363
363
|
args.push(filter.actorId);
|
|
364
364
|
}
|
|
365
|
-
var limit = numericBounds.isPositiveFiniteInt(filter.limit) ? Math.min(filter.limit, 1000) : 100; //
|
|
365
|
+
var limit = numericBounds.isPositiveFiniteInt(filter.limit) ? Math.min(filter.limit, 1000) : 100; // list page cap
|
|
366
366
|
var where = clauses.length > 0 ? " WHERE " + clauses.join(" AND ") : "";
|
|
367
367
|
var sql = "SELECT journal_id, direction, actor_id, message_id, archived_at, " +
|
|
368
368
|
"size_bytes, regimes, floor_until, legal_hold, storage_key FROM " +
|
|
@@ -389,7 +389,7 @@ function create(opts) {
|
|
|
389
389
|
if (now === undefined) now = Date.now();
|
|
390
390
|
var rows = opts.db.runSql(
|
|
391
391
|
"SELECT journal_id, archived_at, floor_until, message_id, regimes FROM " +
|
|
392
|
-
qTable + " WHERE floor_until < ? AND legal_hold = 0 ORDER BY archived_at ASC LIMIT 1000;", //
|
|
392
|
+
qTable + " WHERE floor_until < ? AND legal_hold = 0 ORDER BY archived_at ASC LIMIT 1000;", // expiry-surface cap
|
|
393
393
|
[now]
|
|
394
394
|
);
|
|
395
395
|
_emit("mail.journal.expire_surface", "success", { count: rows ? rows.length : 0, now: now });
|
package/lib/mail-rbl.js
CHANGED
|
@@ -93,16 +93,16 @@ var MailRblError = defineClass("MailRblError", { alwaysPermanent: true });
|
|
|
93
93
|
|
|
94
94
|
var IPV4_RE = /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/; // allow:regex-no-length-cap — anchored + per-octet repeat-cap
|
|
95
95
|
var IPV6_HEX_RE = /^[0-9a-fA-F:]+$/; // allow:regex-no-length-cap — checked by length cap below
|
|
96
|
-
var IPV6_MAX_LEN = 39; //
|
|
96
|
+
var IPV6_MAX_LEN = 39; // max IPv6 textual length (8 groups × 4 hex + 7 colons)
|
|
97
97
|
|
|
98
98
|
var DEFAULT_TIMEOUT_MS = C.TIME.seconds(5);
|
|
99
|
-
var DEFAULT_CONCURRENCY = 8; //
|
|
99
|
+
var DEFAULT_CONCURRENCY = 8; // concurrent-query cap, not bytes
|
|
100
100
|
var DEFAULT_PROFILE = "strict";
|
|
101
101
|
|
|
102
102
|
var PROFILES = Object.freeze({
|
|
103
|
-
strict: { maxConcurrent: 8, perListTimeoutMs: C.TIME.seconds(5), maxListsPerQuery: 16 }, //
|
|
104
|
-
balanced: { maxConcurrent: 16, perListTimeoutMs: C.TIME.seconds(10), maxListsPerQuery: 32 }, //
|
|
105
|
-
permissive: { maxConcurrent: 32, perListTimeoutMs: C.TIME.seconds(20), maxListsPerQuery: 64 }, //
|
|
103
|
+
strict: { maxConcurrent: 8, perListTimeoutMs: C.TIME.seconds(5), maxListsPerQuery: 16 }, // list-count cap
|
|
104
|
+
balanced: { maxConcurrent: 16, perListTimeoutMs: C.TIME.seconds(10), maxListsPerQuery: 32 }, // list-count cap
|
|
105
|
+
permissive: { maxConcurrent: 32, perListTimeoutMs: C.TIME.seconds(20), maxListsPerQuery: 64 }, // list-count cap
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
var COMPLIANCE_POSTURES = Object.freeze({
|
|
@@ -328,7 +328,7 @@ function compliancePosture(posture) {
|
|
|
328
328
|
function _validateZoneNames(zones) {
|
|
329
329
|
for (var i = 0; i < zones.length; i += 1) {
|
|
330
330
|
var z = zones[i];
|
|
331
|
-
if (typeof z !== "string" || z.length === 0 || z.length > 253) { //
|
|
331
|
+
if (typeof z !== "string" || z.length === 0 || z.length > 253) { // RFC 1035 §2.3.4 total name cap
|
|
332
332
|
throw new MailRblError("mail-rbl/bad-zone",
|
|
333
333
|
"list zone '" + z + "' must be a non-empty string under 253 bytes");
|
|
334
334
|
}
|
|
@@ -340,7 +340,7 @@ function _validateZoneNames(zones) {
|
|
|
340
340
|
// if non-ASCII upstream).
|
|
341
341
|
for (var c = 0; c < z.length; c += 1) {
|
|
342
342
|
var cc = z.charCodeAt(c);
|
|
343
|
-
if (cc < 0x20 || cc === 0x7f || cc > 0x7e) { //
|
|
343
|
+
if (cc < 0x20 || cc === 0x7f || cc > 0x7e) { // RFC 1035 ASCII zone-name shape
|
|
344
344
|
throw new MailRblError("mail-rbl/bad-zone",
|
|
345
345
|
"list zone '" + z + "' contains non-ASCII or control chars");
|
|
346
346
|
}
|
package/lib/mail-scan.js
CHANGED
|
@@ -95,16 +95,16 @@ var DEFAULT_PROFILE = "strict";
|
|
|
95
95
|
var DEFAULT_PROTOCOL = "icap";
|
|
96
96
|
var DEFAULT_ICAP_SERVICE = "srv_clamav";
|
|
97
97
|
|
|
98
|
-
//
|
|
98
|
+
// ClamAV INSTREAM 4-byte length prefix.
|
|
99
99
|
var CLAMAV_LENGTH_PREFIX_BYTES = 4;
|
|
100
100
|
|
|
101
|
-
//
|
|
101
|
+
// ClamAV INSTREAM chunk size for streaming.
|
|
102
102
|
var CLAMAV_CHUNK_BYTES = 65536;
|
|
103
103
|
|
|
104
104
|
var PROFILES = Object.freeze({
|
|
105
|
-
strict: { timeoutMs: C.TIME.seconds(30), maxMessageBytes: C.BYTES.mib(25), maxResponseBytes: C.BYTES.mib(50) }, //
|
|
106
|
-
balanced: { timeoutMs: C.TIME.seconds(60), maxMessageBytes: C.BYTES.mib(50), maxResponseBytes: C.BYTES.mib(100) }, //
|
|
107
|
-
permissive: { timeoutMs: C.TIME.seconds(120), maxMessageBytes: C.BYTES.mib(150), maxResponseBytes: C.BYTES.mib(300) }, //
|
|
105
|
+
strict: { timeoutMs: C.TIME.seconds(30), maxMessageBytes: C.BYTES.mib(25), maxResponseBytes: C.BYTES.mib(50) }, // operator-facing default mailbox cap
|
|
106
|
+
balanced: { timeoutMs: C.TIME.seconds(60), maxMessageBytes: C.BYTES.mib(50), maxResponseBytes: C.BYTES.mib(100) }, // operator-facing default mailbox cap
|
|
107
|
+
permissive: { timeoutMs: C.TIME.seconds(120), maxMessageBytes: C.BYTES.mib(150), maxResponseBytes: C.BYTES.mib(300) }, // operator-facing default mailbox cap
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
var COMPLIANCE_POSTURES = Object.freeze({
|
|
@@ -165,7 +165,7 @@ function create(opts) {
|
|
|
165
165
|
|
|
166
166
|
validateOpts.requireNonEmptyString(opts.host, "mail.scan.create.host",
|
|
167
167
|
MailScanError, "mail-scan/bad-host");
|
|
168
|
-
if (!numericBounds.isPositiveFiniteInt(opts.port) || opts.port > 65535) { //
|
|
168
|
+
if (!numericBounds.isPositiveFiniteInt(opts.port) || opts.port > 65535) { // TCP port-number range cap
|
|
169
169
|
throw new MailScanError("mail-scan/bad-port",
|
|
170
170
|
"mail.scan.create.port must be a positive integer in [1,65535]; got " +
|
|
171
171
|
numericBounds.shape(opts.port));
|
|
@@ -329,7 +329,7 @@ function create(opts) {
|
|
|
329
329
|
// RFC 3507 §4.4.3 — body is chunked-transfer; we write a single
|
|
330
330
|
// chunk + terminator for simplicity. The wire format is the same
|
|
331
331
|
// as HTTP/1.1 chunked: `<hex-length>\r\n<bytes>\r\n0\r\n\r\n`.
|
|
332
|
-
var lenHex = messageBytes.length.toString(16); //
|
|
332
|
+
var lenHex = messageBytes.length.toString(16); // hex radix
|
|
333
333
|
sock.write(lenHex + "\r\n");
|
|
334
334
|
sock.write(messageBytes);
|
|
335
335
|
sock.write("\r\n0\r\n\r\n");
|
package/lib/mail-send-deliver.js
CHANGED
|
@@ -73,7 +73,7 @@ var audit = lazyRequire(function () { return require("./audit"); });
|
|
|
73
73
|
|
|
74
74
|
var DeliverError = defineClass("DeliverError");
|
|
75
75
|
|
|
76
|
-
var DEFAULT_PORT_SMTP = 25; //
|
|
76
|
+
var DEFAULT_PORT_SMTP = 25; // IANA SMTP port, not a byte literal
|
|
77
77
|
var DEFAULT_RETRY_BACKOFF_MS = Object.freeze([
|
|
78
78
|
C.TIME.minutes(1),
|
|
79
79
|
C.TIME.minutes(5),
|
|
@@ -83,7 +83,7 @@ var DEFAULT_RETRY_BACKOFF_MS = Object.freeze([
|
|
|
83
83
|
]);
|
|
84
84
|
var DEFAULT_MX_LOOKUP_TIMEOUT_MS = C.TIME.seconds(10);
|
|
85
85
|
var DEFAULT_PER_HOST_TIMEOUT_MS = C.TIME.seconds(60);
|
|
86
|
-
var MAX_RECIPIENTS_PER_CALL = 1000; //
|
|
86
|
+
var MAX_RECIPIENTS_PER_CALL = 1000; // manifest-size cap, not byte count
|
|
87
87
|
|
|
88
88
|
// ---- Outcome classifier ----
|
|
89
89
|
|