@blamejs/core 0.18.8 → 0.18.10
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 +4 -0
- package/NOTICE +1 -1
- package/lib/db.js +15 -1
- package/lib/http-client.js +9 -12
- package/lib/vendor/MANIFEST.json +12 -12
- package/lib/vendor/blamejs-pki.cjs +464 -40
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,10 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.18.x
|
|
10
10
|
|
|
11
|
+
- v0.18.10 (2026-08-03) — **Encrypted-at-rest boot fails closed on a truncated db.enc instead of silently starting fresh over it; broader SAML and database test coverage.** A database running encrypted at rest whose db.enc snapshot is truncated below a valid envelope (an interrupted external copy or backup restore, a full tmpfs, filesystem corruption) no longer boots onto a fresh empty database that the next flush would persist over the corrupt copy — it now fails closed so the operator can restore from backup. Alongside the fix, adversarial and edge branches of b.auth.saml and b.db come under explicit test, and the vendored @blamejs/pki toolkit is refreshed. **Changed:** *Verification- and edge-path tests for the SAML SP and database primitives* — b.auth.saml (the XML-signature Reference handling with no URI or no Transforms, a foreign-namespace Conditions element failing closed to no-audience-restriction, RSA-OAEP SHA-384/SHA-512 key transport with AES-128-GCM assertion decryption, ed25519 sign/verify dispatch, and the single-logout build/parse paths) and b.db (encrypted-boot key and envelope fallbacks, the truncated-snapshot refusal above, flush-to-disk after close, the audit-chain rollback check against a non-empty log, and the boot-time NTP check thresholds) now have explicit tests for their boundary branches. · *Vendored @blamejs/pki refreshed to 0.3.29* — The vendored @blamejs/pki toolkit that backs the mutual-TLS CA engine (X.509 / CRL / PKCS#12 signing) is refreshed from 0.3.28 to 0.3.29. The upstream change is in that toolkit's ACME client and Retry-After parser, which the CA engine does not call, so there is no behaviour change to the certificate-authority surface — this is a supply-chain currency refresh. **Fixed:** *Encrypted boot fails closed on a truncated db.enc rather than starting fresh over it* — When a database is encrypted at rest and its durable db.enc snapshot exists but is too short to be a valid AEAD envelope — a truncation from an interrupted external copy or backup restore, a full tmpfs, or filesystem corruption — boot silently opened a fresh empty database. The next flush or close then persisted that empty database over the corrupt-but-present snapshot, masking the corruption and destroying the operator's chance to recover. Boot now fails closed with db/enc-truncated; restore db.enc from backup, or remove it to intentionally start empty. A valid snapshot is always written atomically and is never this short, so no healthy deployment is affected. **Detectors:** *Truncated db.enc must fail closed, not start fresh* — A source guard keeps the encrypted-boot path throwing on an under-length db.enc rather than returning to open a fresh database — so a truncated durable snapshot can never again be silently overwritten by the next flush.
|
|
12
|
+
|
|
13
|
+
- v0.18.9 (2026-08-02) — **Broader error- and edge-path test coverage for the CLI, mail, and HTTP-client primitives.** Error, edge, and fallback branches of b.cli, b.mail, and b.httpClient are now under explicit test. No behaviour changes: exercising every path confirmed each already behaves per its documented contract. One dead internal parameter on the HTTP-client cache path — never supplied by any caller — was removed. **Changed:** *Error- and edge-path tests for the CLI, mail, and HTTP-client primitives* — b.cli (the api-snapshot capture/compare load-error paths and the restore-apply round trip), b.mail (reverse-DNS forward-confirmation and failure fallbacks, SMTP UTF-8 and binary-MIME detection on edge inputs, AUTH LOGIN with an empty password, and audit-emit failures being swallowed without masking the delivery outcome), and b.httpClient (the HTTPS-connect failure classification and the HTTP/2 synchronous-request-throw path) now have explicit tests for their boundary branches. Behaviour is unchanged.
|
|
14
|
+
|
|
11
15
|
- v0.18.8 (2026-08-02) — **SSRF-safe local-transport HTTP, timestamped-HMAC webhook verification, the OAuth client-credentials grant, trusted-proxy identity headers, and a public keyed-HMAC primitive; plus a fix for a filterless overflow update that could rewrite every row.** Five general-purpose primitives land: talking HTTP to a co-located daemon over a socket the SSRF gate cannot protect, verifying the single-header timestamped-HMAC webhook scheme, the machine-to-machine OAuth client_credentials grant with a cached auto-renewing token manager, and peer-gated trust of a reverse proxy's identity headers. b.crypto.hmac exposes the framework's keyed HMAC (SHA3-512 by default; weaker digests available explicitly for external-scheme interop) and replaces b.crypto.hmacSha3. Separately, an update() on a collection whose field lives in the overflow store, called with no filter, no longer slips past the unconditional-write guard and silently rewrites every row. **Added:** *b.localHttp — SSRF-safe HTTP over a local transport* — b.localHttp.create({ socketPath }) and b.localHttp.request() speak HTTP to a co-located daemon over a Unix domain socket, a Windows named pipe, or a loopback TCP peer with a bearer token — the transports an SSRF gate cannot protect, because there is no network host to steer. It deliberately does not route through b.httpClient (DNS + the SSRF gate): a socket-path request cannot be pointed at an arbitrary IP, so that surface is exactly what it exists to bypass safely. It refuses any non-loopback TCP host, never forwards Origin or Referer to the daemon, bounds the response body, and sets the caller's Host header verbatim. Use it for a local control-plane API — a sidecar's endpoint, a container-runtime socket, a metrics port. · *b.webhookHmac.verify — timestamped-HMAC webhook verification* — Verifies the single-header timestamped-HMAC webhook scheme — t=<unix-seconds>,v1=<hmac-hex> signed over <timestamp>.<raw-body> — used by Stripe, Tailscale, and others. It refuses a timestamp outside the tolerance window (replay defense), checks every v1 value so a rotated signing secret verifies with no downtime, compares in constant time, and ignores signature versions it does not recognize. Pass the exact bytes received, not a parsed-then-re-serialized JSON body, or the HMAC will not reproduce. This is distinct from b.standardWebhooks, which verifies the three-header StandardWebhooks scheme. · *b.auth.oauth.clientCredentials + clientCredentialsManager — the client_credentials grant* — The RFC 6749 §4.4 client_credentials grant for machine-to-machine authentication with no user present: clientCredentials() POSTs grant_type=client_credentials and returns the access token — never a refresh token, per the RFC. It authenticates with the client id/secret via client_secret_post (default) or client_secret_basic (tokenEndpointAuthMethod), sends no scope unless you supply one (the authorization-code scope default is not applied to a machine-to-machine request), and a client_credentials-only client needs no redirectUri at create. clientCredentialsManager() wraps it in an in-memory cache that fetches on first use, re-fetches a configurable window before expiry, collapses concurrent callers onto one in-flight request, and — throughout a 429 backoff window (honoring the server's Retry-After when present) — serves the still-valid cached token or fails fast without another network call, rather than hammering the authorization server. The client's tokenEndpointAuthMethod (client_secret_post / client_secret_basic) applies uniformly to every token-endpoint request, not just this grant. · *b.requestHelpers.trustedIdentityHeaders — peer-gated proxy identity headers* — Resolves an identity-injecting reverse proxy's header family — Cloudflare Access Cf-Access-*, oauth2-proxy X-Forwarded-User, Tailscale Serve Tailscale-User-*, or any custom mapping — under the same trusted-proxy peer-gate as b.requestHelpers.trustedClientIp. It is the identity-header mirror of the X-Forwarded-For discipline: the family is trusted only when the immediate socket peer is a configured trusted proxy; from any other peer the headers are stripped from req.headers so downstream code cannot read a forged identity. With no gate configured it fails closed and always strips. A naive trust of these headers is a full impersonation bypass; this closes it by construction rather than opening a second, looser trust path. · *b.crypto.hmac — a public keyed-HMAC primitive* — b.crypto.hmac(key, data, algorithm = "sha3-512") exposes the framework's keyed HMAC with a PQC-first SHA3-512 default. Weaker digests (sha256, sha384, sha512, sha3-256, sha3-384) are available by naming them explicitly, for interop with an external scheme that pins one — a provider's SHA-256 webhook signature, for example; SHA-1 and MD5 are refused. Key and data accept a Buffer or a string; the result is a lowercase hex digest. **Removed:** *b.crypto.hmacSha3 (folded into b.crypto.hmac)* — b.crypto.hmacSha3 is removed. b.crypto.hmac already defaults to SHA3-512, so replace b.crypto.hmacSha3(key, data) with b.crypto.hmac(key, data) — the same algorithm and the same output. **Fixed:** *A filterless update on an overflow-backed collection no longer rewrites every row* — An update() on a collection whose target field lives in the overflow (JSON) store, called with no filter conditions — an empty or absent query — slipped past the unconditional-write guard that protects real-column updates and silently rewrote every row: the internal per-row writes each carry a WHERE by row id, so the guard never saw a match-everything update. Such an update is now refused with the same "call where(...) first" error as a real-column update. Provide an explicit filter for the rows you intend to change. **Detectors:** *Overflow-store update re-asserts the unconditional-write refusal* — A source guard keeps the overflow-store update path re-checking, on its read query, that a filter is present — so a filterless overflow update cannot regress to silently rewriting every row.
|
|
12
16
|
|
|
13
17
|
- v0.18.7 (2026-08-02) — **STARTTLS idle-timeout no longer injects plaintext into the encrypted channel; broader mail-server test coverage.** A STARTTLS upgrade on the POP3 / IMAP / ManageSieve / SMTP-submission / MX servers left the pre-upgrade plain-socket idle-timeout handler armed, so a post-handshake idle wrote a plaintext timeout reply into the now-encrypted stream (the peer saw a TLS decode error / reset). The shared socket-upgrade path now strips that handler so the idle timeout is delivered encrypted. Alongside the fix, error and edge branches of b.mail.server.pop3, b.mail.server.imap, and b.mail.auth are now under test. Except for the fix, behaviour is unchanged. **Changed:** *Error- and edge-path tests for the POP3, IMAP, and mail-authentication primitives* — b.mail.server.pop3 (the STLS upgrade and post-handshake idle timeout, pipelined-command draining, AUTH / APOP / USER-PASS branches, and store-fallback and tenant-refusal shapes), b.mail.server.imap (APPEND / CATENATE literal handling, command-dispatch and guard-error branches, and the LOGIN / NOTIFY paths), and b.mail.auth (SPF macro expansion and record parsing, iprev forward-confirm, and dual-CIDR a/mx parsing) now have explicit tests for their boundary paths. **Security:** *STARTTLS idle timeout is delivered over the encrypted channel, not injected as plaintext* — The POP3, IMAP, ManageSieve, SMTP-submission, and MX servers arm a plain-socket idle timer whose handler writes a plaintext idle-timeout reply and closes the connection. After a STARTTLS upgrade the shared socket-upgrade path stripped only the plain socket's data listeners, so that plaintext handler survived the wrap and, on a post-handshake idle, injected cleartext into the now-encrypted stream — the peer observed a TLS decode error or connection reset instead of a clean encrypted timeout reply. The upgrade path now strips the plain socket's timeout listeners and disarms its idle timer, so the upgraded TLS socket owns the idle timeout and replies over the encrypted channel. **Detectors:** *STARTTLS upgrade strips the plaintext idle-timeout handler* — A source guard keeps the shared socket-upgrade path stripping the plain socket's timeout listeners alongside its data listeners, so a plaintext idle-timeout reply cannot survive into the encrypted channel.
|
package/NOTICE
CHANGED
|
@@ -60,7 +60,7 @@ Used for: WebAuthn / passkey registration + authentication response
|
|
|
60
60
|
server.cjs).
|
|
61
61
|
--------------------------------------------------------------------------------
|
|
62
62
|
Component: @blamejs/pki
|
|
63
|
-
Version: 0.3.
|
|
63
|
+
Version: 0.3.29
|
|
64
64
|
Source: https://github.com/blamejs/pki
|
|
65
65
|
License: Apache-2.0
|
|
66
66
|
Copyright: Copyright (c) blamejs contributors
|
package/lib/db.js
CHANGED
|
@@ -817,7 +817,21 @@ function decryptToTmp() {
|
|
|
817
817
|
// a symlink-mounted volume (k8s PVC). db.enc is AEAD-verified downstream, so
|
|
818
818
|
// the cap is the OOM-before-cap defense (was an uncapped read).
|
|
819
819
|
var packed = atomicFile.fdSafeReadSync(encPath, { maxBytes: C.BYTES.gib(2) });
|
|
820
|
-
|
|
820
|
+
// The minimum valid AEAD envelope is a 1-byte version + a 24-byte nonce +
|
|
821
|
+
// a 16-byte tag (41 bytes) — the same floor decryptPacked itself enforces.
|
|
822
|
+
// db.enc EXISTS here (guarded at entry) and a valid snapshot is written
|
|
823
|
+
// atomically (temp + rename), so anything shorter is a truncated / corrupt
|
|
824
|
+
// durable copy, never a clean state.
|
|
825
|
+
if (packed.length < 1 + C.BYTES.bytes(24) + C.BYTES.bytes(16)) {
|
|
826
|
+
// Fail loudly rather than open a fresh DB: starting fresh here lets the
|
|
827
|
+
// next flush/close persist an empty database over the corrupt-but-present
|
|
828
|
+
// snapshot, masking the corruption and destroying the operator's chance to
|
|
829
|
+
// restore from backup.
|
|
830
|
+
throw _dbErr("db/enc-truncated",
|
|
831
|
+
"FATAL: db.enc exists but is only " + packed.length + " byte(s) — too short to be " +
|
|
832
|
+
"a valid encrypted snapshot; refusing to start a fresh database over a corrupt durable " +
|
|
833
|
+
"copy (restore db.enc from backup, or remove it to intentionally start empty)");
|
|
834
|
+
}
|
|
821
835
|
// AAD binds the envelope to this deployment's data dir so two
|
|
822
836
|
// installs sharing the same operator passphrase can't swap each
|
|
823
837
|
// other's db.enc files. Backwards-compat: if the AAD-bound decrypt
|
package/lib/http-client.js
CHANGED
|
@@ -1080,19 +1080,16 @@ function _runWithCache(opts, maxRedirects, runAfter) {
|
|
|
1080
1080
|
try { got = cache._lookup(method, opts.url, requestHeaders); }
|
|
1081
1081
|
catch (_e) { got = null; }
|
|
1082
1082
|
|
|
1083
|
-
function _doNetwork(
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
headers: Object.assign({}, opts.headers || {}, extraReqHeaders),
|
|
1088
|
-
});
|
|
1089
|
-
}
|
|
1083
|
+
function _doNetwork() {
|
|
1084
|
+
// Conditional revalidation headers (If-None-Match / If-Modified-Since)
|
|
1085
|
+
// are built and applied on the separate _revalidate path, so a cache
|
|
1086
|
+
// miss / malformed-entry refetch issues the request opts verbatim.
|
|
1090
1087
|
if (maxRedirects === null || maxRedirects === 0) {
|
|
1091
|
-
return _requestSingle(
|
|
1092
|
-
return { finalOpts:
|
|
1088
|
+
return _requestSingle(opts).then(function (res) {
|
|
1089
|
+
return { finalOpts: opts, res: res };
|
|
1093
1090
|
});
|
|
1094
1091
|
}
|
|
1095
|
-
return _requestWithRedirects(
|
|
1092
|
+
return _requestWithRedirects(opts, maxRedirects);
|
|
1096
1093
|
}
|
|
1097
1094
|
|
|
1098
1095
|
// 2. Miss → network → maybe store.
|
|
@@ -1101,7 +1098,7 @@ function _runWithCache(opts, maxRedirects, runAfter) {
|
|
|
1101
1098
|
catch (_e) { /* drop-silent */ }
|
|
1102
1099
|
try { cache._obsEvent("httpclient.cache.miss", 1, { method: method }); }
|
|
1103
1100
|
catch (_e) { /* drop-silent */ }
|
|
1104
|
-
return _doNetwork(
|
|
1101
|
+
return _doNetwork().then(function (boxed) {
|
|
1105
1102
|
_maybeStore(cache, method, opts.url, requestHeaders, boxed.res);
|
|
1106
1103
|
return runAfter(boxed.finalOpts, _withCacheHeaders(boxed.res, "MISS", undefined, cache.statusHeader));
|
|
1107
1104
|
});
|
|
@@ -1115,7 +1112,7 @@ function _runWithCache(opts, maxRedirects, runAfter) {
|
|
|
1115
1112
|
// Malformed entry — drop it, treat as miss.
|
|
1116
1113
|
try { cache.invalidate(method, opts.url, requestHeaders); }
|
|
1117
1114
|
catch (_e2) { /* drop-silent */ }
|
|
1118
|
-
return _doNetwork(
|
|
1115
|
+
return _doNetwork().then(function (boxed) {
|
|
1119
1116
|
_maybeStore(cache, method, opts.url, requestHeaders, boxed.res);
|
|
1120
1117
|
return runAfter(boxed.finalOpts, _withCacheHeaders(boxed.res, "MISS", undefined, cache.statusHeader));
|
|
1121
1118
|
});
|
package/lib/vendor/MANIFEST.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"hashes": {
|
|
19
19
|
"server": "sha256:2b30a26f728c5349f4c4b47834f862a4f77393b1224fc12b22abe3ce2cfab78f"
|
|
20
20
|
},
|
|
21
|
-
"refreshedAt": "2026-08-
|
|
21
|
+
"refreshedAt": "2026-08-03T19:33:52.595Z"
|
|
22
22
|
},
|
|
23
23
|
"@noble/curves": {
|
|
24
24
|
"version": "2.2.0",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"hashes": {
|
|
41
41
|
"server": "sha256:2880c288b1285ef51d356d057bee6f0c8a00de36638cf47b47617e8c1faf10d5"
|
|
42
42
|
},
|
|
43
|
-
"refreshedAt": "2026-08-
|
|
43
|
+
"refreshedAt": "2026-08-03T19:33:52.595Z"
|
|
44
44
|
},
|
|
45
45
|
"@noble/post-quantum": {
|
|
46
46
|
"version": "0.6.1",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"hashes": {
|
|
72
72
|
"server": "sha256:f9c94094b3c10fe73dac5343289da582454ea6053494fab2bf66099d9103d6c3"
|
|
73
73
|
},
|
|
74
|
-
"refreshedAt": "2026-08-
|
|
74
|
+
"refreshedAt": "2026-08-03T19:33:52.595Z"
|
|
75
75
|
},
|
|
76
76
|
"@simplewebauthn/server": {
|
|
77
77
|
"version": "13.3.2",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"hashes": {
|
|
95
95
|
"server": "sha256:e83195dc9f189385da9c856ef38843f4466f93ea8f3d7fc2efcb1e1b18da6f20"
|
|
96
96
|
},
|
|
97
|
-
"refreshedAt": "2026-08-
|
|
97
|
+
"refreshedAt": "2026-08-03T19:33:52.595Z"
|
|
98
98
|
},
|
|
99
99
|
"SecLists-common-passwords-top-10000": {
|
|
100
100
|
"version": "10k-most-common (master)",
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
},
|
|
115
115
|
"runtime_artifact": "lib/vendor/common-passwords-top-10000.data.js",
|
|
116
116
|
"integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)",
|
|
117
|
-
"refreshedAt": "2026-08-
|
|
117
|
+
"refreshedAt": "2026-08-03T19:33:52.595Z"
|
|
118
118
|
},
|
|
119
119
|
"bimi-trust-anchors": {
|
|
120
120
|
"version": "operator-managed",
|
|
@@ -139,7 +139,7 @@
|
|
|
139
139
|
},
|
|
140
140
|
"runtime_artifact": "lib/vendor/bimi-trust-anchors.data.js",
|
|
141
141
|
"integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)",
|
|
142
|
-
"refreshedAt": "2026-08-
|
|
142
|
+
"refreshedAt": "2026-08-03T19:33:52.595Z"
|
|
143
143
|
},
|
|
144
144
|
"publicsuffix-list": {
|
|
145
145
|
"version": "master",
|
|
@@ -159,10 +159,10 @@
|
|
|
159
159
|
},
|
|
160
160
|
"runtime_artifact": "lib/vendor/public-suffix-list.data.js",
|
|
161
161
|
"integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)",
|
|
162
|
-
"refreshedAt": "2026-08-
|
|
162
|
+
"refreshedAt": "2026-08-03T19:33:52.595Z"
|
|
163
163
|
},
|
|
164
164
|
"@blamejs/pki": {
|
|
165
|
-
"version": "0.3.
|
|
165
|
+
"version": "0.3.29",
|
|
166
166
|
"license": "Apache-2.0",
|
|
167
167
|
"author": "blamejs",
|
|
168
168
|
"source": "https://github.com/blamejs/pki",
|
|
@@ -182,12 +182,12 @@
|
|
|
182
182
|
"server": "lib/vendor/blamejs-pki.cjs"
|
|
183
183
|
},
|
|
184
184
|
"bundler": "esbuild --format=cjs --platform=node --external:crypto --external:node:crypto",
|
|
185
|
-
"bundledAt": "2026-08-
|
|
186
|
-
"cpe": "cpe:2.3:a:blamejs:pki:0.3.
|
|
185
|
+
"bundledAt": "2026-08-03T00:00:00Z",
|
|
186
|
+
"cpe": "cpe:2.3:a:blamejs:pki:0.3.29:*:*:*:*:node.js:*:*",
|
|
187
187
|
"hashes": {
|
|
188
|
-
"server": "sha256:
|
|
188
|
+
"server": "sha256:8eb19192bcc9e9660b5fe72376d27de33a1c2c3b44ba18b1b3aeb9f0d95ed2bf"
|
|
189
189
|
},
|
|
190
|
-
"refreshedAt": "2026-08-
|
|
190
|
+
"refreshedAt": "2026-08-03T19:33:52.595Z"
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @blamejs/pki v0.3.
|
|
1
|
+
// @blamejs/pki v0.3.29 — vendored (Apache-2.0). Zero-dep pure CJS.
|
|
2
2
|
// https://github.com/blamejs/pki Exports: x509, crl, pkcs12, key, webcrypto, schema, csr, cms, ...
|
|
3
3
|
// Backs lib/mtls-engine-default.js (PQC-capable CA + PKCS#12 engine).
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -137,7 +137,7 @@ var require_package = __commonJS({
|
|
|
137
137
|
"node_modules/@blamejs/pki/package.json"(exports2, module2) {
|
|
138
138
|
module2.exports = {
|
|
139
139
|
name: "@blamejs/pki",
|
|
140
|
-
version: "0.3.
|
|
140
|
+
version: "0.3.29",
|
|
141
141
|
description: "Pure-JavaScript PKI toolkit that owns its stack \u2014 X.509, ASN.1/DER, CMS, PQC-first.",
|
|
142
142
|
license: "Apache-2.0",
|
|
143
143
|
author: "blamejs contributors",
|
|
@@ -15762,16 +15762,33 @@ var require_http_retry_after = __commonJS({
|
|
|
15762
15762
|
var out = { retryAfterSeconds: null, retryAfterDate: null };
|
|
15763
15763
|
if (/^\d+$/.test(raStr)) {
|
|
15764
15764
|
var n = parseInt(raStr, 10);
|
|
15765
|
-
if (
|
|
15765
|
+
if (typeof opts.cap === "number" && n > opts.cap) {
|
|
15766
|
+
out.retryAfterSeconds = opts.cap;
|
|
15767
|
+
return out;
|
|
15768
|
+
}
|
|
15769
|
+
if (!Number.isSafeInteger(n) || n > MAX_RETRY_AFTER_SECONDS) {
|
|
15770
|
+
if (opts.lenient) return out;
|
|
15771
|
+
throw _fail(opts, "the Retry-After delay is out of the supported range (0.." + MAX_RETRY_AFTER_SECONDS + " seconds)");
|
|
15772
|
+
}
|
|
15766
15773
|
out.retryAfterSeconds = n;
|
|
15767
15774
|
return out;
|
|
15768
15775
|
}
|
|
15769
15776
|
var when = httpDateMs(raStr, opts.now);
|
|
15770
|
-
if (isNaN(when))
|
|
15777
|
+
if (isNaN(when)) {
|
|
15778
|
+
if (opts.lenient) return out;
|
|
15779
|
+
throw _fail(opts, "a Retry-After must be delay-seconds or a valid HTTP-date (RFC 7231 sec. 7.1.1.1/7.1.3), got " + JSON.stringify(raStr));
|
|
15780
|
+
}
|
|
15771
15781
|
out.retryAfterDate = when;
|
|
15772
15782
|
if (typeof opts.now === "number" && isFinite(opts.now)) {
|
|
15773
15783
|
var d = Math.max(0, Math.ceil((when - opts.now) / constants.TIME.seconds(1)));
|
|
15774
|
-
if (
|
|
15784
|
+
if (typeof opts.cap === "number" && d > opts.cap) {
|
|
15785
|
+
out.retryAfterSeconds = opts.cap;
|
|
15786
|
+
return out;
|
|
15787
|
+
}
|
|
15788
|
+
if (d > MAX_RETRY_AFTER_SECONDS) {
|
|
15789
|
+
if (opts.lenient) return out;
|
|
15790
|
+
throw _fail(opts, "the Retry-After date is beyond the supported horizon (" + MAX_RETRY_AFTER_SECONDS + " seconds)");
|
|
15791
|
+
}
|
|
15775
15792
|
out.retryAfterSeconds = d;
|
|
15776
15793
|
}
|
|
15777
15794
|
return out;
|
|
@@ -26567,7 +26584,8 @@ var require_acme = __commonJS({
|
|
|
26567
26584
|
var pkix = require_schema_pkix();
|
|
26568
26585
|
var constants = require_constants();
|
|
26569
26586
|
var rfc3339 = require_rfc3339();
|
|
26570
|
-
var
|
|
26587
|
+
var webcrypto = require_webcrypto().webcrypto;
|
|
26588
|
+
var subtle = webcrypto.subtle;
|
|
26571
26589
|
var frameworkError = require_framework_error();
|
|
26572
26590
|
var httpTransport = require_http_transport();
|
|
26573
26591
|
var retryAfter = require_http_retry_after();
|
|
@@ -26586,6 +26604,13 @@ var require_acme = __commonJS({
|
|
|
26586
26604
|
function _isRfc3339(v) {
|
|
26587
26605
|
return rfc3339.isValid(v);
|
|
26588
26606
|
}
|
|
26607
|
+
var _RANDOM_DENOM = Math.pow(2, 48);
|
|
26608
|
+
function _defaultRandom() {
|
|
26609
|
+
return Buffer.from(webcrypto.getRandomValues(new Uint8Array(6))).readUIntBE(0, 6) / _RANDOM_DENOM;
|
|
26610
|
+
}
|
|
26611
|
+
var RENEWAL_RETRY_MIN_SECONDS = 60;
|
|
26612
|
+
var RENEWAL_RETRY_MAX_SECONDS = constants.TIME.days(1) / constants.TIME.seconds(1);
|
|
26613
|
+
var RENEWAL_RETRY_DEFAULT_SECONDS = constants.TIME.hours(6) / constants.TIME.seconds(1);
|
|
26589
26614
|
function _isUrl(v) {
|
|
26590
26615
|
if (!_isString(v) || !/^https?:\/\/[^\s]+$/.test(v)) return false;
|
|
26591
26616
|
var u;
|
|
@@ -26646,7 +26671,12 @@ var require_acme = __commonJS({
|
|
|
26646
26671
|
{ name: "expires", type: "rfc3339", requiredWhen: function(o) {
|
|
26647
26672
|
return o.status === "valid";
|
|
26648
26673
|
} },
|
|
26649
|
-
|
|
26674
|
+
// challenges is required (the key is present) but MAY be empty for an already-"valid" authorization the CA
|
|
26675
|
+
// granted out of band (RFC 8555 sec. 7.1.4 / 7.4.1 -- no challenge was validated); a pending/other authz still
|
|
26676
|
+
// needs at least the one challenge the client fulfills.
|
|
26677
|
+
{ name: "challenges", type: "array", required: true, minItems: function(o) {
|
|
26678
|
+
return o.status === "valid" ? 0 : 1;
|
|
26679
|
+
}, elemType: "challenge" },
|
|
26650
26680
|
{ name: "wildcard", type: "boolean" }
|
|
26651
26681
|
],
|
|
26652
26682
|
challenge: [
|
|
@@ -26666,7 +26696,7 @@ var require_acme = __commonJS({
|
|
|
26666
26696
|
{ name: "explanationURL", type: "url" }
|
|
26667
26697
|
]
|
|
26668
26698
|
};
|
|
26669
|
-
function _checkType(kind, field, value) {
|
|
26699
|
+
function _checkType(kind, field, value, obj) {
|
|
26670
26700
|
switch (field.type) {
|
|
26671
26701
|
case "string":
|
|
26672
26702
|
if (!_isString(value)) return "must be a string";
|
|
@@ -26692,7 +26722,8 @@ var require_acme = __commonJS({
|
|
|
26692
26722
|
break;
|
|
26693
26723
|
case "array":
|
|
26694
26724
|
if (!Array.isArray(value)) return "must be an array";
|
|
26695
|
-
|
|
26725
|
+
var minItems = typeof field.minItems === "function" ? field.minItems(obj) : field.minItems;
|
|
26726
|
+
if (minItems && value.length < minItems) return "must have at least " + minItems + " element(s)";
|
|
26696
26727
|
for (var i = 0; i < value.length; i++) {
|
|
26697
26728
|
if (field.elemType === "url" && !_isUrl(value[i])) return "element " + i + " must be a URL string";
|
|
26698
26729
|
if (field.elemType === "contact" && !_isUriString(value[i])) return "element " + i + " must be a URI string";
|
|
@@ -26724,20 +26755,22 @@ var require_acme = __commonJS({
|
|
|
26724
26755
|
if (field.enum && field.enum.indexOf(obj[field.name]) === -1) {
|
|
26725
26756
|
throw E("acme/bad-status", "the " + kind + " " + field.name + " " + JSON.stringify(obj[field.name]) + " is not a recognized value");
|
|
26726
26757
|
}
|
|
26727
|
-
var err = _checkType(kind, field, obj[field.name]);
|
|
26758
|
+
var err = _checkType(kind, field, obj[field.name], obj);
|
|
26728
26759
|
if (err) throw E("acme/bad-" + _codeSlug(kind), "the " + kind + " field " + JSON.stringify(field.name) + " " + err);
|
|
26729
26760
|
}
|
|
26730
26761
|
return obj;
|
|
26731
26762
|
}
|
|
26732
26763
|
function _validateIdentifier(id) {
|
|
26733
|
-
if (!_isObject(id)
|
|
26734
|
-
|
|
26735
|
-
|
|
26736
|
-
|
|
26737
|
-
|
|
26738
|
-
|
|
26764
|
+
if (!_isObject(id)) throw E("acme/bad-identifier", "an identifier must be { type, value } strings");
|
|
26765
|
+
var type = id.type, value = id.value;
|
|
26766
|
+
if (!_isString(type) || !_isString(value)) throw E("acme/bad-identifier", "an identifier must be { type, value } strings");
|
|
26767
|
+
if (type === "dns") {
|
|
26768
|
+
if (value.indexOf("*.") === 0) throw E("acme/bad-identifier", "a wildcard *. value is not permitted in an authorization identifier (RFC 8555 sec. 7.1.4)");
|
|
26769
|
+
_assertDnsName(value);
|
|
26770
|
+
} else if (type === "ip") {
|
|
26771
|
+
_assertIpAddress(value);
|
|
26739
26772
|
}
|
|
26740
|
-
return
|
|
26773
|
+
return { type, value };
|
|
26741
26774
|
}
|
|
26742
26775
|
function _assertDnsName(name) {
|
|
26743
26776
|
if (!_isString(name)) throw E("acme/bad-identifier", "a dns identifier value must be a string");
|
|
@@ -27010,9 +27043,11 @@ var require_acme = __commonJS({
|
|
|
27010
27043
|
return jose.sign({ protected: { alg, kid: o.kid, url: o.url }, payload: _payloadBuf(o.accountJwk), key, profile: "eab-inner" });
|
|
27011
27044
|
}
|
|
27012
27045
|
function _validateOrderIdentifier(id) {
|
|
27013
|
-
if (!_isObject(id)
|
|
27014
|
-
|
|
27015
|
-
|
|
27046
|
+
if (!_isObject(id)) throw E("acme/bad-identifier", "an order identifier must be { type, value } strings");
|
|
27047
|
+
var type = id.type, value = id.value;
|
|
27048
|
+
if (!_isString(type) || !_isString(value)) throw E("acme/bad-identifier", "an order identifier must be { type, value } strings");
|
|
27049
|
+
if (type === "dns") {
|
|
27050
|
+
var v = value;
|
|
27016
27051
|
if (v.indexOf("*.") === 0) {
|
|
27017
27052
|
v = v.slice(2);
|
|
27018
27053
|
if (v.indexOf("*") !== -1) throw E("acme/bad-identifier", "a wildcard order identifier permits exactly one leading *. label (RFC 8555 sec. 7.1.3)");
|
|
@@ -27020,16 +27055,15 @@ var require_acme = __commonJS({
|
|
|
27020
27055
|
throw E("acme/bad-identifier", "a wildcard must be a single leading *. label (RFC 8555 sec. 7.1.3)");
|
|
27021
27056
|
}
|
|
27022
27057
|
_assertDnsName(v);
|
|
27023
|
-
} else if (
|
|
27024
|
-
if (
|
|
27025
|
-
_assertIpAddress(
|
|
27058
|
+
} else if (type === "ip") {
|
|
27059
|
+
if (value.indexOf("*") !== -1) throw E("acme/bad-identifier", "an ip identifier has no wildcard form (RFC 8738)");
|
|
27060
|
+
_assertIpAddress(value);
|
|
27026
27061
|
}
|
|
27027
|
-
return
|
|
27062
|
+
return { type, value };
|
|
27028
27063
|
}
|
|
27029
27064
|
function newOrder(o) {
|
|
27030
27065
|
if (!_isObject(o) || !Array.isArray(o.identifiers) || o.identifiers.length === 0) throw E("acme/bad-order", "newOrder requires a non-empty identifiers array (RFC 8555 sec. 7.4)");
|
|
27031
|
-
o.identifiers.
|
|
27032
|
-
var payload = { identifiers: o.identifiers };
|
|
27066
|
+
var payload = { identifiers: o.identifiers.map(_validateOrderIdentifier) };
|
|
27033
27067
|
if (o.notBefore !== void 0) {
|
|
27034
27068
|
if (!_isRfc3339(o.notBefore)) throw E("acme/bad-order", "notBefore must be an RFC 3339 date-time");
|
|
27035
27069
|
payload.notBefore = o.notBefore;
|
|
@@ -27044,6 +27078,10 @@ var require_acme = __commonJS({
|
|
|
27044
27078
|
}
|
|
27045
27079
|
return _signOuter({ key: o.key, alg: o.alg, nonce: o.nonce, url: o.url, kid: o.kid }, payload);
|
|
27046
27080
|
}
|
|
27081
|
+
function newAuthz(o) {
|
|
27082
|
+
if (!_isObject(o) || !_isObject(o.identifier)) throw E("acme/bad-identifier", "newAuthz requires a single identifier object (RFC 8555 sec. 7.4.1)");
|
|
27083
|
+
return _signOuter({ key: o.key, alg: o.alg, nonce: o.nonce, url: o.url, kid: o.kid }, { identifier: _validateIdentifier(o.identifier) });
|
|
27084
|
+
}
|
|
27047
27085
|
async function _jwkToSpki(jwk) {
|
|
27048
27086
|
var importAlg;
|
|
27049
27087
|
if (jwk.kty === "EC") importAlg = { name: "ECDSA", namedCurve: jwk.crv };
|
|
@@ -27227,10 +27265,21 @@ var require_acme = __commonJS({
|
|
|
27227
27265
|
throw E("acme/bad-url", "the ACME URL did not parse: " + s, e);
|
|
27228
27266
|
}
|
|
27229
27267
|
if (url.protocol !== "https:") throw E("acme/insecure-url", "ACME requires https (RFC 8555 sec. 6.1), got " + url.protocol + " for " + s);
|
|
27268
|
+
if (((/^[A-Za-z][A-Za-z0-9+.-]*:\/\/([^/?#]*)/.exec(s) || [])[1] || "").indexOf("@") !== -1) throw E("acme/bad-url", "an ACME URL must not contain userinfo: " + JSON.stringify(s));
|
|
27230
27269
|
if (/[\s\\]/.test(s)) throw E("acme/bad-url", "an ACME URL must not contain whitespace or a backslash: " + JSON.stringify(s));
|
|
27270
|
+
if (_uriStructurallyInvalid(s)) throw E("acme/bad-url", "an ACME URL authority is not canonical (the transport would repair it): " + JSON.stringify(s));
|
|
27271
|
+
var _auth = /^[A-Za-z][A-Za-z0-9+.-]*:\/\/([^/?#]*)/.exec(s);
|
|
27272
|
+
if (_auth) {
|
|
27273
|
+
var _hp = _auth[1].slice(_auth[1].lastIndexOf("@") + 1);
|
|
27274
|
+
var _rawHost = _hp.charAt(0) === "[" ? _hp.slice(0, _hp.indexOf("]") + 1) : _hp.split(":")[0];
|
|
27275
|
+
if (_rawHost.toLowerCase() !== url.hostname) throw E("acme/bad-url", "an ACME URL host is not canonical (the transport would rewrite it): " + JSON.stringify(s));
|
|
27276
|
+
}
|
|
27231
27277
|
var rawPath = s.replace(/^[a-z]+:\/\/[^/?#]*/i, "").split(/[?#]/)[0];
|
|
27232
27278
|
if (rawPath !== url.pathname) throw E("acme/bad-url", "an ACME URL path is not canonical (the transport would normalize it): " + JSON.stringify(s));
|
|
27233
|
-
|
|
27279
|
+
var qi = s.indexOf("?");
|
|
27280
|
+
var rawQuery = qi === -1 ? "" : s.slice(qi).split("#")[0];
|
|
27281
|
+
if (rawQuery !== url.search) throw E("acme/bad-url", "an ACME URL query is not canonical (the transport would normalize it): " + JSON.stringify(s));
|
|
27282
|
+
if (s.indexOf("#") !== -1) throw E("acme/bad-url", "an ACME URL must not contain a fragment: " + JSON.stringify(s));
|
|
27234
27283
|
return s;
|
|
27235
27284
|
}
|
|
27236
27285
|
function _resolveLocation(loc, base) {
|
|
@@ -27241,13 +27290,18 @@ var require_acme = __commonJS({
|
|
|
27241
27290
|
isAbsolute = false;
|
|
27242
27291
|
}
|
|
27243
27292
|
if (isAbsolute) return _clientUrl(loc);
|
|
27244
|
-
var
|
|
27293
|
+
var u;
|
|
27245
27294
|
try {
|
|
27246
|
-
|
|
27295
|
+
u = new URL(loc, base);
|
|
27247
27296
|
} catch (e) {
|
|
27248
27297
|
throw E("acme/bad-url", "the Location header did not resolve to a valid URL: " + JSON.stringify(loc), e);
|
|
27249
27298
|
}
|
|
27250
|
-
|
|
27299
|
+
if (_queryRepaired(loc, u)) throw E("acme/bad-url", "a relative Link/Location query is not canonical (resolution re-encoded it): " + JSON.stringify(loc));
|
|
27300
|
+
return _clientUrl(u.href);
|
|
27301
|
+
}
|
|
27302
|
+
function _queryRepaired(rawRef, resolvedUrl) {
|
|
27303
|
+
var qi = rawRef.indexOf("?");
|
|
27304
|
+
return qi !== -1 && rawRef.slice(qi).split("#")[0] !== resolvedUrl.search;
|
|
27251
27305
|
}
|
|
27252
27306
|
var _defaultSleep = require_sleep().sleep;
|
|
27253
27307
|
function _clientTls(o) {
|
|
@@ -27275,6 +27329,252 @@ var require_acme = __commonJS({
|
|
|
27275
27329
|
if (!out.length) throw E("acme/bad-certificate-chain", "the certificate download carried no PEM certificate (RFC 8555 sec. 7.4.2)");
|
|
27276
27330
|
return out;
|
|
27277
27331
|
}
|
|
27332
|
+
var LINK_HEADER_MAX_BYTES = constants.BYTES.kib(8);
|
|
27333
|
+
var DEFAULT_MAX_ALTERNATES = 8;
|
|
27334
|
+
var LINK_TOKEN = /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/;
|
|
27335
|
+
function _trimOWS(s) {
|
|
27336
|
+
return s.replace(/^[ \t]+/, "").replace(/[ \t]+$/, "");
|
|
27337
|
+
}
|
|
27338
|
+
function _validRelType(t) {
|
|
27339
|
+
if (/^[A-Za-z][A-Za-z0-9.-]*$/.test(t)) return true;
|
|
27340
|
+
if (LINK_URI_BADCHAR.test(t)) return false;
|
|
27341
|
+
return _validAbsoluteUri(t);
|
|
27342
|
+
}
|
|
27343
|
+
function _validAbsoluteUri(t) {
|
|
27344
|
+
return /^[A-Za-z][A-Za-z0-9+.-]*:/.test(t) && !LINK_URI_BADPCT.test(t) && !_uriStructurallyInvalid(t);
|
|
27345
|
+
}
|
|
27346
|
+
function _multiFragment(uri) {
|
|
27347
|
+
return uri.split("#").length > 2;
|
|
27348
|
+
}
|
|
27349
|
+
function _authorityMultiAt(uri) {
|
|
27350
|
+
var m = /^(?:[A-Za-z][A-Za-z0-9+.-]*:)?\/\/([^/?#]*)/.exec(uri);
|
|
27351
|
+
return !!m && m[1].split("@").length > 2;
|
|
27352
|
+
}
|
|
27353
|
+
function _hasEmptyAuthority(uri) {
|
|
27354
|
+
var m = /^([A-Za-z][A-Za-z0-9+.-]*:)?\/\/([^/?#]*)/.exec(uri);
|
|
27355
|
+
if (!m) return false;
|
|
27356
|
+
var scheme = m[1] ? m[1].slice(0, -1).toLowerCase() : "";
|
|
27357
|
+
if (scheme !== "" && scheme !== "http" && scheme !== "https" && scheme !== "ws" && scheme !== "wss" && scheme !== "ftp") return false;
|
|
27358
|
+
var host = m[2].slice(m[2].lastIndexOf("@") + 1);
|
|
27359
|
+
if (host.charAt(0) !== "[") {
|
|
27360
|
+
var ci = host.indexOf(":");
|
|
27361
|
+
if (ci !== -1) host = host.slice(0, ci);
|
|
27362
|
+
}
|
|
27363
|
+
return host === "";
|
|
27364
|
+
}
|
|
27365
|
+
function _bracketsOnlyInAuthority(uri) {
|
|
27366
|
+
if (uri.indexOf("[") === -1 && uri.indexOf("]") === -1) return true;
|
|
27367
|
+
var m = /^(?:[A-Za-z][A-Za-z0-9+.-]*:)?\/\/(?:[^/?#@[\]]*@)?\[[^[\]]*\]/.exec(uri);
|
|
27368
|
+
if (!m) return false;
|
|
27369
|
+
var rest = uri.slice(m[0].length);
|
|
27370
|
+
if (rest.indexOf("[") !== -1 || rest.indexOf("]") !== -1) return false;
|
|
27371
|
+
var afterHost = rest.split(/[/?#]/)[0];
|
|
27372
|
+
return afterHost === "" || /^:[0-9]*$/.test(afterHost);
|
|
27373
|
+
}
|
|
27374
|
+
function _relFirstSegHasColon(uri) {
|
|
27375
|
+
if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(uri) || uri.indexOf("//") === 0) return false;
|
|
27376
|
+
return uri.split(/[/?#]/)[0].indexOf(":") !== -1;
|
|
27377
|
+
}
|
|
27378
|
+
function _badPort(uri) {
|
|
27379
|
+
var m = /^(?:[A-Za-z][A-Za-z0-9+.-]*:)?\/\/(?:[^/?#@]*@)?(?:\[[^\]]*\]|[^/?#:]*)(:[^/?#]*)?/.exec(uri);
|
|
27380
|
+
return !!(m && m[1] && !/^:[0-9]*$/.test(m[1]));
|
|
27381
|
+
}
|
|
27382
|
+
function _badIpLiteral(uri) {
|
|
27383
|
+
var m = /^(?:[A-Za-z][A-Za-z0-9+.-]*:)?\/\/(?:[^/?#@]*@)?\[([^\]]*)\]/.exec(uri);
|
|
27384
|
+
if (!m) return false;
|
|
27385
|
+
if (/^[vV][0-9A-Fa-f]+\.[A-Za-z0-9._~!$&'()*+,;=:-]+$/.test(m[1])) return false;
|
|
27386
|
+
return !URL.canParse("http://[" + m[1] + "]/");
|
|
27387
|
+
}
|
|
27388
|
+
function _uriStructurallyInvalid(uri) {
|
|
27389
|
+
return !_bracketsOnlyInAuthority(uri) || _hasEmptyAuthority(uri) || _authorityMultiAt(uri) || _multiFragment(uri) || _relFirstSegHasColon(uri) || _badPort(uri) || _badIpLiteral(uri);
|
|
27390
|
+
}
|
|
27391
|
+
function _dedupKey(href) {
|
|
27392
|
+
return href.replace(/%[0-9A-Fa-f]{2}/g, function(m) {
|
|
27393
|
+
var c = String.fromCharCode(parseInt(m.slice(1), 16));
|
|
27394
|
+
return /[A-Za-z0-9._~-]/.test(c) ? c : "%" + m.slice(1).toUpperCase();
|
|
27395
|
+
});
|
|
27396
|
+
}
|
|
27397
|
+
var LINK_QUOTED_INTERIOR = /^(?:[^"\\]|\\.)*$/;
|
|
27398
|
+
var LINK_URI_BADCHAR = /[^A-Za-z0-9._~:/?#[\]@!$&'()*+,;=%-]/;
|
|
27399
|
+
var LINK_URI_BADPCT = /%(?![0-9A-Fa-f]{2})/;
|
|
27400
|
+
function _hasEncodedDotSegment(uri) {
|
|
27401
|
+
var segs = uri.split(/[?#]/)[0].split("/");
|
|
27402
|
+
for (var _si = 0; _si < segs.length; _si++) {
|
|
27403
|
+
if (!/%2e/i.test(segs[_si])) continue;
|
|
27404
|
+
var dec = segs[_si].replace(/%2e/ig, ".");
|
|
27405
|
+
if (dec === "." || dec === "..") return true;
|
|
27406
|
+
}
|
|
27407
|
+
return false;
|
|
27408
|
+
}
|
|
27409
|
+
function _linkUriInvalid(uri) {
|
|
27410
|
+
return LINK_URI_BADCHAR.test(uri) || LINK_URI_BADPCT.test(uri) || _hasEncodedDotSegment(uri) || _uriStructurallyInvalid(uri);
|
|
27411
|
+
}
|
|
27412
|
+
function _hasCtlOctet(s) {
|
|
27413
|
+
for (var _ci = 0; _ci < s.length; _ci++) {
|
|
27414
|
+
var _cc = s.charCodeAt(_ci);
|
|
27415
|
+
if (_cc === 127 || _cc < 32 && _cc !== 9) return true;
|
|
27416
|
+
}
|
|
27417
|
+
return false;
|
|
27418
|
+
}
|
|
27419
|
+
function _splitLinkValues(s) {
|
|
27420
|
+
var out = [], start = 0, inAngle = false, inQuote = false;
|
|
27421
|
+
for (var i = 0; i < s.length; i++) {
|
|
27422
|
+
var ch = s.charAt(i);
|
|
27423
|
+
if (inQuote) {
|
|
27424
|
+
if (ch === "\\") {
|
|
27425
|
+
i++;
|
|
27426
|
+
continue;
|
|
27427
|
+
}
|
|
27428
|
+
if (ch === '"') inQuote = false;
|
|
27429
|
+
continue;
|
|
27430
|
+
}
|
|
27431
|
+
if (ch === '"') {
|
|
27432
|
+
inQuote = true;
|
|
27433
|
+
continue;
|
|
27434
|
+
}
|
|
27435
|
+
if (ch === "<") inAngle = true;
|
|
27436
|
+
else if (ch === ">") inAngle = false;
|
|
27437
|
+
else if (ch === "," && !inAngle) {
|
|
27438
|
+
out.push(s.slice(start, i));
|
|
27439
|
+
start = i + 1;
|
|
27440
|
+
}
|
|
27441
|
+
}
|
|
27442
|
+
if (inQuote || inAngle) throw E("acme/bad-link", "the Link header has an unterminated quote or angle bracket (RFC 8288)");
|
|
27443
|
+
out.push(s.slice(start));
|
|
27444
|
+
return out;
|
|
27445
|
+
}
|
|
27446
|
+
function _splitLinkParams(rest) {
|
|
27447
|
+
var parts = [], start = 0, inQuote = false;
|
|
27448
|
+
for (var i = 0; i < rest.length; i++) {
|
|
27449
|
+
var ch = rest.charAt(i);
|
|
27450
|
+
if (inQuote) {
|
|
27451
|
+
if (ch === "\\") {
|
|
27452
|
+
i++;
|
|
27453
|
+
continue;
|
|
27454
|
+
}
|
|
27455
|
+
if (ch === '"') inQuote = false;
|
|
27456
|
+
continue;
|
|
27457
|
+
}
|
|
27458
|
+
if (ch === '"') inQuote = true;
|
|
27459
|
+
else if (ch === ";") {
|
|
27460
|
+
parts.push(rest.slice(start, i));
|
|
27461
|
+
start = i + 1;
|
|
27462
|
+
}
|
|
27463
|
+
}
|
|
27464
|
+
parts.push(rest.slice(start));
|
|
27465
|
+
var out = [];
|
|
27466
|
+
for (var j = 0; j < parts.length; j++) {
|
|
27467
|
+
var p = _trimOWS(parts[j]);
|
|
27468
|
+
if (p === "") {
|
|
27469
|
+
if (j === 0) continue;
|
|
27470
|
+
throw E("acme/bad-link", "an empty Link parameter (a ';' with no parameter) is malformed (RFC 8288): " + JSON.stringify(rest));
|
|
27471
|
+
}
|
|
27472
|
+
var eq = p.indexOf("=");
|
|
27473
|
+
var name = (eq === -1 ? p : _trimOWS(p.slice(0, eq))).toLowerCase();
|
|
27474
|
+
if (!LINK_TOKEN.test(name)) throw E("acme/bad-link", "a Link parameter name must be a token (RFC 8288 / RFC 7230): " + JSON.stringify(p));
|
|
27475
|
+
if (eq === -1) {
|
|
27476
|
+
out.push({ name, value: "", hasValue: false });
|
|
27477
|
+
continue;
|
|
27478
|
+
}
|
|
27479
|
+
var v = _trimOWS(p.slice(eq + 1));
|
|
27480
|
+
if (v.length >= 2 && v.charAt(0) === '"' && v.charAt(v.length - 1) === '"') {
|
|
27481
|
+
var inner = v.slice(1, -1);
|
|
27482
|
+
if (!LINK_QUOTED_INTERIOR.test(inner)) throw E("acme/bad-link", "a quoted Link parameter value is malformed (an unescaped quote or dangling backslash, RFC 7230): " + JSON.stringify(p));
|
|
27483
|
+
v = inner.replace(/\\(.)/g, "$1");
|
|
27484
|
+
} else if (!LINK_TOKEN.test(v)) {
|
|
27485
|
+
throw E("acme/bad-link", "an unquoted Link parameter value must be a non-empty token (RFC 8288 / RFC 7230): " + JSON.stringify(p));
|
|
27486
|
+
}
|
|
27487
|
+
out.push({ name, value: v, hasValue: true });
|
|
27488
|
+
}
|
|
27489
|
+
return out;
|
|
27490
|
+
}
|
|
27491
|
+
function _relHasAlternate(rel) {
|
|
27492
|
+
var toks = String(rel).split(" ");
|
|
27493
|
+
for (var i = 0; i < toks.length; i++) {
|
|
27494
|
+
if (toks[i].toLowerCase() === "alternate") return true;
|
|
27495
|
+
}
|
|
27496
|
+
return false;
|
|
27497
|
+
}
|
|
27498
|
+
function _parseLinkValue(raw) {
|
|
27499
|
+
var s = _trimOWS(raw);
|
|
27500
|
+
if (s === "") return null;
|
|
27501
|
+
var gt = s.indexOf(">");
|
|
27502
|
+
if (s.charAt(0) !== "<" || gt === -1) throw E("acme/bad-link", "a Link value must be <URI-Reference> with parameters (RFC 8288): " + JSON.stringify(raw));
|
|
27503
|
+
var rest = s.slice(gt + 1).replace(/^[ \t]+/, "");
|
|
27504
|
+
if (rest !== "" && rest.charAt(0) !== ";") throw E("acme/bad-link", "a Link value's parameters must be introduced by ';' (RFC 8288): " + JSON.stringify(raw));
|
|
27505
|
+
var uri = s.slice(1, gt);
|
|
27506
|
+
if (_linkUriInvalid(uri)) throw E("acme/bad-link", "a Link URI-Reference contains a character, percent-escape, or encoded dot-segment not permitted by RFC 3986: " + JSON.stringify(raw));
|
|
27507
|
+
var params = _splitLinkParams(rest), rel = "", relSeen = false, anchor = null, anchorSeen = false;
|
|
27508
|
+
for (var i = 0; i < params.length; i++) {
|
|
27509
|
+
if (params[i].name === "rel" && !relSeen) {
|
|
27510
|
+
rel = params[i].value;
|
|
27511
|
+
relSeen = true;
|
|
27512
|
+
} else if (params[i].name === "anchor") {
|
|
27513
|
+
if (anchorSeen) throw E("acme/bad-link", "a Link value must not carry more than one anchor parameter (RFC 8288 sec. 3.2, ambiguous context): " + JSON.stringify(raw));
|
|
27514
|
+
anchorSeen = true;
|
|
27515
|
+
if (!params[i].hasValue) throw E("acme/bad-link", "a Link anchor parameter requires a URI value (RFC 8288 sec. 3.2): " + JSON.stringify(raw));
|
|
27516
|
+
anchor = params[i].value;
|
|
27517
|
+
}
|
|
27518
|
+
}
|
|
27519
|
+
return { uri, rel, anchor, relSeen };
|
|
27520
|
+
}
|
|
27521
|
+
function _parseLinkAlternates(headers, base) {
|
|
27522
|
+
var raw = null;
|
|
27523
|
+
for (var k in headers) {
|
|
27524
|
+
if (Object.prototype.hasOwnProperty.call(headers, k) && k.toLowerCase() === "link") {
|
|
27525
|
+
raw = headers[k];
|
|
27526
|
+
break;
|
|
27527
|
+
}
|
|
27528
|
+
}
|
|
27529
|
+
if (raw == null) return [];
|
|
27530
|
+
var baseUrl = new URL(base), baseOrigin = baseUrl.origin, baseHref = baseUrl.href;
|
|
27531
|
+
var fields = Array.isArray(raw) ? raw : [raw], out = [], seen = /* @__PURE__ */ Object.create(null), totalBytes = 0;
|
|
27532
|
+
seen[_dedupKey(baseHref)] = true;
|
|
27533
|
+
for (var fi = 0; fi < fields.length; fi++) {
|
|
27534
|
+
var field = String(fields[fi]);
|
|
27535
|
+
totalBytes += field.length + 1;
|
|
27536
|
+
if (totalBytes > LINK_HEADER_MAX_BYTES) throw E("acme/bad-link", "the Link header(s) exceed the " + LINK_HEADER_MAX_BYTES + "-byte aggregate cap (RFC 8288, CWE-770)");
|
|
27537
|
+
if (_hasCtlOctet(field)) throw E("acme/bad-link", "a Link header must not contain control octets (RFC 9110 field-value)");
|
|
27538
|
+
var values = _splitLinkValues(field);
|
|
27539
|
+
for (var vi = 0; vi < values.length; vi++) {
|
|
27540
|
+
var lv = _parseLinkValue(values[vi]);
|
|
27541
|
+
if (lv === null) continue;
|
|
27542
|
+
if (lv.relSeen && lv.rel === "") throw E("acme/bad-link", "a Link rel parameter must name at least one relation-type (RFC 8288 sec. 3.3)");
|
|
27543
|
+
if (lv.rel !== "" && (lv.rel.charAt(0) === " " || lv.rel.charAt(lv.rel.length - 1) === " ")) throw E("acme/bad-link", "a Link rel value has a leading or trailing space (RFC 8288 sec. 3.3): " + JSON.stringify(lv.rel));
|
|
27544
|
+
var relToks = lv.rel === "" ? [] : lv.rel.split(" ");
|
|
27545
|
+
for (var ri = 0; ri < relToks.length; ri++) {
|
|
27546
|
+
if (relToks[ri] !== "" && !_validRelType(relToks[ri])) throw E("acme/bad-link", "a Link rel value contains a token that is not a valid relation-type (RFC 8288 sec. 3.3): " + JSON.stringify(lv.rel));
|
|
27547
|
+
}
|
|
27548
|
+
if (!_relHasAlternate(lv.rel)) continue;
|
|
27549
|
+
if (lv.anchor != null) {
|
|
27550
|
+
if (_linkUriInvalid(lv.anchor)) continue;
|
|
27551
|
+
var au;
|
|
27552
|
+
try {
|
|
27553
|
+
au = new URL(lv.anchor, base);
|
|
27554
|
+
} catch (_ae) {
|
|
27555
|
+
continue;
|
|
27556
|
+
}
|
|
27557
|
+
if (_queryRepaired(lv.anchor, au)) continue;
|
|
27558
|
+
if (au.href !== baseHref) continue;
|
|
27559
|
+
}
|
|
27560
|
+
var resolved;
|
|
27561
|
+
try {
|
|
27562
|
+
resolved = _resolveLocation(lv.uri, base);
|
|
27563
|
+
} catch (e) {
|
|
27564
|
+
if (e && e.code === "acme/insecure-url") throw E("acme/bad-link", 'a rel="alternate" Link target is not an https URL: ' + JSON.stringify(lv.uri), e);
|
|
27565
|
+
continue;
|
|
27566
|
+
}
|
|
27567
|
+
var parsed = new URL(resolved);
|
|
27568
|
+
if (parsed.origin !== baseOrigin) throw E("acme/bad-link", `a rel="alternate" Link target is not on the certificate download's origin (SSRF guard): ` + JSON.stringify(lv.uri));
|
|
27569
|
+
var key = _dedupKey(parsed.href);
|
|
27570
|
+
if (!seen[key]) {
|
|
27571
|
+
seen[key] = true;
|
|
27572
|
+
out.push(resolved);
|
|
27573
|
+
}
|
|
27574
|
+
}
|
|
27575
|
+
}
|
|
27576
|
+
return out;
|
|
27577
|
+
}
|
|
27278
27578
|
function client(directoryUrl, opts) {
|
|
27279
27579
|
opts = opts || {};
|
|
27280
27580
|
if (!opts.accountKey) throw E("acme/bad-input", "client requires opts.accountKey (the account private key)");
|
|
@@ -27479,6 +27779,21 @@ var require_acme = __commonJS({
|
|
|
27479
27779
|
});
|
|
27480
27780
|
});
|
|
27481
27781
|
}
|
|
27782
|
+
function _newAuthz(identifier) {
|
|
27783
|
+
return Promise.resolve().then(function() {
|
|
27784
|
+
var canon = _validateIdentifier(identifier);
|
|
27785
|
+
return _resource("newAuthz").then(function(url) {
|
|
27786
|
+
return _post(url, newAuthz, { identifier: canon }, "kid", void 0, [200, 201]).then(function(res) {
|
|
27787
|
+
var loc = res.headers["location"];
|
|
27788
|
+
if (!_isString(loc)) throw E("acme/no-authorization-url", "newAuthz did not return an authorization URL in a Location header (RFC 8555 sec. 7.4.1)");
|
|
27789
|
+
var authz = validate("authorization", _json(res));
|
|
27790
|
+
if (!authz.identifier || authz.identifier.type !== canon.type || authz.identifier.value !== canon.value || authz.wildcard === true) throw E("acme/identifier-mismatch", "the returned authorization does not match the requested identifier (RFC 8555 sec. 7.4.1)");
|
|
27791
|
+
if (authz.status !== "pending" && authz.status !== "valid") throw E("acme/unexpected-authorization-status", "newAuthz returned an authorization that is neither pending nor already valid (status " + JSON.stringify(authz.status) + "); RFC 8555 sec. 7.4.1");
|
|
27792
|
+
return { authorization: authz, url: _resolveLocation(loc, url) };
|
|
27793
|
+
});
|
|
27794
|
+
});
|
|
27795
|
+
});
|
|
27796
|
+
}
|
|
27482
27797
|
function _getOrder(url) {
|
|
27483
27798
|
return _postAsGet(_clientUrl(url)).then(function(res) {
|
|
27484
27799
|
return validate("order", _json(res));
|
|
@@ -27547,13 +27862,53 @@ var require_acme = __commonJS({
|
|
|
27547
27862
|
function _pollAuthorization(url, budget) {
|
|
27548
27863
|
return _poll("authorization", url, budget);
|
|
27549
27864
|
}
|
|
27550
|
-
function
|
|
27551
|
-
|
|
27552
|
-
|
|
27553
|
-
|
|
27554
|
-
|
|
27555
|
-
|
|
27556
|
-
|
|
27865
|
+
function _readCertChain(res) {
|
|
27866
|
+
var ctToken = String(res.headers["content-type"] || "").split(";")[0].trim().toLowerCase();
|
|
27867
|
+
if (ctToken !== "application/pem-certificate-chain") throw E("acme/bad-certificate-chain", "the certificate download returned an unexpected media type " + JSON.stringify(ctToken) + " (expected application/pem-certificate-chain, RFC 8555 sec. 7.4.2)");
|
|
27868
|
+
var chain = _splitPemChain(_bodyText(res));
|
|
27869
|
+
return { certificate: chain[0], chain: chain.slice(1), certificates: chain };
|
|
27870
|
+
}
|
|
27871
|
+
function _fetchCertChain(url) {
|
|
27872
|
+
return _post(url, postAsGet, null, "kid", "application/pem-certificate-chain").then(_readCertChain);
|
|
27873
|
+
}
|
|
27874
|
+
function _downloadCertificate(url, opts2) {
|
|
27875
|
+
opts2 = opts2 || {};
|
|
27876
|
+
return Promise.resolve().then(function() {
|
|
27877
|
+
var select = opts2.selectChain;
|
|
27878
|
+
if (select !== void 0 && typeof select !== "function") throw E("acme/bad-input", "downloadCertificate opts.selectChain must be a function");
|
|
27879
|
+
var maxAlt = guard.limits.cap(opts2.maxAlternates, "maxAlternates", DEFAULT_MAX_ALTERNATES, { E, code: "acme/bad-input", min: 0, max: 64 });
|
|
27880
|
+
var dlUrl = _clientUrl(url);
|
|
27881
|
+
return _post(dlUrl, postAsGet, null, "kid", "application/pem-certificate-chain").then(function(res) {
|
|
27882
|
+
var primary = _readCertChain(res);
|
|
27883
|
+
var alternates = [], linkError = null;
|
|
27884
|
+
try {
|
|
27885
|
+
alternates = _parseLinkAlternates(res.headers, dlUrl);
|
|
27886
|
+
} catch (e) {
|
|
27887
|
+
linkError = e;
|
|
27888
|
+
}
|
|
27889
|
+
function result(cand) {
|
|
27890
|
+
return { certificate: cand.certificate, chain: cand.chain, certificates: cand.certificates, alternates };
|
|
27891
|
+
}
|
|
27892
|
+
if (!select) return result(primary);
|
|
27893
|
+
return Promise.resolve(select(primary)).then(function(primaryMatch) {
|
|
27894
|
+
if (primaryMatch) return result(primary);
|
|
27895
|
+
if (linkError) throw linkError;
|
|
27896
|
+
var leaf = primary.certificate, toFetch = alternates.slice(0, maxAlt), overBudget = alternates.length > maxAlt, idx = 0;
|
|
27897
|
+
function next() {
|
|
27898
|
+
if (idx >= toFetch.length) {
|
|
27899
|
+
if (overBudget) throw E("acme/too-many-alternates", "no acceptable chain within the maxAlternates=" + maxAlt + " fetch budget (RFC 8555 sec. 7.4.2, CWE-770)");
|
|
27900
|
+
throw E("acme/no-matching-chain", "no downloaded chain satisfied selectChain (RFC 8555 sec. 7.4.2)");
|
|
27901
|
+
}
|
|
27902
|
+
return _fetchCertChain(toFetch[idx++]).then(function(cand) {
|
|
27903
|
+
if (!cand.certificate.equals(leaf)) throw E("acme/bad-alternate", "an alternate chain did not start with the same end-entity certificate (RFC 8555 sec. 7.4.2)");
|
|
27904
|
+
return Promise.resolve(select(cand)).then(function(m) {
|
|
27905
|
+
return m ? result(cand) : next();
|
|
27906
|
+
});
|
|
27907
|
+
});
|
|
27908
|
+
}
|
|
27909
|
+
return next();
|
|
27910
|
+
});
|
|
27911
|
+
});
|
|
27557
27912
|
});
|
|
27558
27913
|
}
|
|
27559
27914
|
function _revokeCert(o) {
|
|
@@ -27607,10 +27962,19 @@ var require_acme = __commonJS({
|
|
|
27607
27962
|
});
|
|
27608
27963
|
});
|
|
27609
27964
|
}
|
|
27610
|
-
function _renewalInfo(certDer) {
|
|
27965
|
+
function _renewalInfo(certDer, clockFn, retryAfterCapSeconds) {
|
|
27611
27966
|
if (!Buffer.isBuffer(certDer)) throw E("acme/bad-input", "renewalInfo requires a DER certificate Buffer");
|
|
27967
|
+
var _rawClk = typeof clockFn === "function" ? clockFn : clock;
|
|
27968
|
+
function clk() {
|
|
27969
|
+
var t = _rawClk();
|
|
27970
|
+
if (typeof t !== "number" || !isFinite(t)) throw E("acme/bad-input", "the renewalInfo clock returned a non-finite value");
|
|
27971
|
+
return t;
|
|
27972
|
+
}
|
|
27973
|
+
var notAfterMs = x509.parse(certDer).validity.notAfter.getTime();
|
|
27974
|
+
if (clk() > notAfterMs) throw E("acme/certificate-expired", "the certificate is already past its notAfter; a client MUST NOT check RenewalInfo after it has expired (RFC 9773 sec. 4.3)");
|
|
27612
27975
|
var certId = ariCertId(certDer);
|
|
27613
27976
|
return _resource("renewalInfo").then(function(base) {
|
|
27977
|
+
if (clk() > notAfterMs) throw E("acme/certificate-expired", "the certificate expired before the RenewalInfo request could be issued; a client MUST NOT check RenewalInfo after expiry (RFC 9773 sec. 4.3)");
|
|
27614
27978
|
var u = new URL(base);
|
|
27615
27979
|
u.pathname = u.pathname.replace(/\/+$/, "") + "/" + certId;
|
|
27616
27980
|
var url = _clientUrl(u.href);
|
|
@@ -27619,15 +27983,73 @@ var require_acme = __commonJS({
|
|
|
27619
27983
|
var obj = validateRenewalInfo(_json(res));
|
|
27620
27984
|
var ra = res.headers["retry-after"];
|
|
27621
27985
|
var retryAfterSeconds = null;
|
|
27622
|
-
if (typeof ra === "string" && ra.trim() !== "")
|
|
27986
|
+
if (typeof ra === "string" && ra.trim() !== "") {
|
|
27987
|
+
var raOpts = { now: clk(), E, code: "acme/bad-retry-after" };
|
|
27988
|
+
if (typeof retryAfterCapSeconds === "number") {
|
|
27989
|
+
raOpts.cap = retryAfterCapSeconds;
|
|
27990
|
+
raOpts.lenient = true;
|
|
27991
|
+
}
|
|
27992
|
+
retryAfterSeconds = retryAfter.parse(ra, raOpts).retryAfterSeconds;
|
|
27993
|
+
}
|
|
27623
27994
|
return { renewalInfo: obj, retryAfterSeconds };
|
|
27624
27995
|
});
|
|
27625
27996
|
});
|
|
27626
27997
|
}
|
|
27998
|
+
function _renewalWindow(certDer, o) {
|
|
27999
|
+
o = o || {};
|
|
28000
|
+
return Promise.resolve().then(function() {
|
|
28001
|
+
if (!Buffer.isBuffer(certDer)) throw E("acme/bad-input", "renewalWindow requires a DER certificate Buffer");
|
|
28002
|
+
if (o.random !== void 0 && typeof o.random !== "function") throw E("acme/bad-input", "renewalWindow opts.random must be a function returning a number in [0, 1]");
|
|
28003
|
+
if (o.clock !== void 0 && typeof o.clock !== "function") throw E("acme/bad-input", "renewalWindow opts.clock must be a function returning epoch milliseconds");
|
|
28004
|
+
if (o.replaced !== void 0 && typeof o.replaced !== "boolean") throw E("acme/bad-input", "renewalWindow opts.replaced must be a boolean");
|
|
28005
|
+
if (o.previous !== void 0 && !_isObject(o.previous)) throw E("acme/bad-input", "renewalWindow opts.previous must be a prior renewalWindow result object");
|
|
28006
|
+
var _clk = typeof o.clock === "function" ? o.clock : clock;
|
|
28007
|
+
function clk() {
|
|
28008
|
+
var t = _clk();
|
|
28009
|
+
if (typeof t !== "number" || !isFinite(t)) throw E("acme/bad-input", "the renewalWindow clock returned a non-finite value");
|
|
28010
|
+
return t;
|
|
28011
|
+
}
|
|
28012
|
+
var notAfter = x509.parse(certDer).validity.notAfter;
|
|
28013
|
+
var now = clk();
|
|
28014
|
+
if (now > notAfter.getTime()) throw E("acme/certificate-expired", "the certificate is already past its notAfter; there is nothing to renew (RFC 9773 sec. 4.3)");
|
|
28015
|
+
if (o.replaced === true) throw E("acme/certificate-replaced", "the caller asserts this certificate has already been replaced (RFC 9773 sec. 4.3)");
|
|
28016
|
+
return _renewalInfo(certDer, clk, RENEWAL_RETRY_MAX_SECONDS).then(function(ri) {
|
|
28017
|
+
var w = ri.renewalInfo.suggestedWindow;
|
|
28018
|
+
var startMs = Date.parse(w.start), endMs = Date.parse(w.end);
|
|
28019
|
+
var notAfterMs = notAfter.getTime();
|
|
28020
|
+
var effEnd = Math.min(endMs, notAfterMs), effStart = Math.min(startMs, effEnd);
|
|
28021
|
+
var pw = o.previous && _isObject(o.previous.suggestedWindow) ? o.previous.suggestedWindow : null;
|
|
28022
|
+
var selectedMs;
|
|
28023
|
+
if (pw && pw.start === w.start && pw.end === w.end && _isString(o.previous.selectedTime)) {
|
|
28024
|
+
var prevMs = Date.parse(o.previous.selectedTime);
|
|
28025
|
+
if (!isFinite(prevMs)) throw E("acme/bad-input", "renewalWindow opts.previous.selectedTime must be an RFC 3339 date-time");
|
|
28026
|
+
selectedMs = Math.max(effStart, Math.min(effEnd, prevMs));
|
|
28027
|
+
} else {
|
|
28028
|
+
var draw = o.random ? o.random() : _defaultRandom();
|
|
28029
|
+
if (typeof draw !== "number" || !(draw >= 0 && draw <= 1)) throw E("acme/bad-input", "renewalWindow opts.random must return a number in [0, 1]");
|
|
28030
|
+
selectedMs = Math.round(effStart + draw * (effEnd - effStart));
|
|
28031
|
+
}
|
|
28032
|
+
var retryAfterSeconds = ri.retryAfterSeconds == null ? RENEWAL_RETRY_DEFAULT_SECONDS : Math.max(RENEWAL_RETRY_MIN_SECONDS, Math.min(RENEWAL_RETRY_MAX_SECONDS, ri.retryAfterSeconds));
|
|
28033
|
+
return {
|
|
28034
|
+
suggestedWindow: w,
|
|
28035
|
+
selectedTime: new Date(selectedMs).toISOString(),
|
|
28036
|
+
// Decide renew-now against a FRESH clock read: the RenewalInfo GET may itself span the selected
|
|
28037
|
+
// instant, so the pre-fetch `now` (used above only for the expiry gate) could be stale here. Also
|
|
28038
|
+
// renew now when the SELECTED instant lands at or past notAfter -- whether the whole window opened
|
|
28039
|
+
// after expiry or a straddling window's draw hit the clamp endpoint, there is no margin left, so
|
|
28040
|
+
// waiting for the (clamped) time would leave the cert to expire unrenewed.
|
|
28041
|
+
renewNow: selectedMs <= clk() || selectedMs >= notAfterMs,
|
|
28042
|
+
retryAfterSeconds,
|
|
28043
|
+
explanationURL: _isString(ri.renewalInfo.explanationURL) ? ri.renewalInfo.explanationURL : null
|
|
28044
|
+
};
|
|
28045
|
+
});
|
|
28046
|
+
});
|
|
28047
|
+
}
|
|
27627
28048
|
return {
|
|
27628
28049
|
directory: _directory,
|
|
27629
28050
|
newAccount: _newAccount,
|
|
27630
28051
|
newOrder: _newOrder,
|
|
28052
|
+
newAuthz: _newAuthz,
|
|
27631
28053
|
getOrder: _getOrder,
|
|
27632
28054
|
getAuthorization: _getAuthorization,
|
|
27633
28055
|
getChallenge: _getChallenge,
|
|
@@ -27640,7 +28062,8 @@ var require_acme = __commonJS({
|
|
|
27640
28062
|
deactivateAccount: _deactivateAccount,
|
|
27641
28063
|
deactivateAuthorization: _deactivateAuthorization,
|
|
27642
28064
|
keyChange: _keyChange,
|
|
27643
|
-
renewalInfo: _renewalInfo
|
|
28065
|
+
renewalInfo: _renewalInfo,
|
|
28066
|
+
renewalWindow: _renewalWindow
|
|
27644
28067
|
};
|
|
27645
28068
|
}
|
|
27646
28069
|
module2.exports = {
|
|
@@ -27660,6 +28083,7 @@ var require_acme = __commonJS({
|
|
|
27660
28083
|
newAccount,
|
|
27661
28084
|
externalAccountBinding,
|
|
27662
28085
|
newOrder,
|
|
28086
|
+
newAuthz,
|
|
27663
28087
|
finalize,
|
|
27664
28088
|
challengeResponse,
|
|
27665
28089
|
deactivate,
|
package/package.json
CHANGED
package/sbom.cdx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.5",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:52e564cd-e4bc-440f-bd6c-a12a68c4102e",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-08-
|
|
8
|
+
"timestamp": "2026-08-03T20:26:23.786Z",
|
|
9
9
|
"lifecycles": [
|
|
10
10
|
{
|
|
11
11
|
"phase": "build"
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
}
|
|
20
20
|
],
|
|
21
21
|
"component": {
|
|
22
|
-
"bom-ref": "@blamejs/core@0.18.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.18.10",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.18.
|
|
25
|
+
"version": "0.18.10",
|
|
26
26
|
"scope": "required",
|
|
27
27
|
"author": "blamejs contributors",
|
|
28
28
|
"description": "The Node framework that owns its stack.",
|
|
29
|
-
"purl": "pkg:npm/%40blamejs/core@0.18.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.18.10",
|
|
30
30
|
"properties": [],
|
|
31
31
|
"externalReferences": [
|
|
32
32
|
{
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"components": [],
|
|
55
55
|
"dependencies": [
|
|
56
56
|
{
|
|
57
|
-
"ref": "@blamejs/core@0.18.
|
|
57
|
+
"ref": "@blamejs/core@0.18.10",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|