@blamejs/core 0.17.22 → 0.17.23
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/NOTICE +1 -1
- package/lib/audit-sign.js +10 -1
- package/lib/session.js +65 -18
- package/lib/vendor/MANIFEST.json +11 -11
- package/lib/vendor/public-suffix-list.dat +2 -6
- package/lib/vendor/public-suffix-list.data.js +2215 -2217
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,8 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.17.x
|
|
10
10
|
|
|
11
|
+
- v0.17.23 (2026-07-25) — **`b.session` refresh paths enforce the idle/absolute timeout floor, and a strict fingerprint policy without a request fails closed.** Two session-security fixes and one audit-signing robustness fix. b.session.rotate and b.session.updateData reset a session's activity clock but did not re-check the idle/absolute timeout floor that verify() and touch() enforce, so a session already past its idle timeout (default 30 min) -- which verify() would reject -- could be resurrected with a fresh idle window by rotating it or writing session data, defeating the idle timeout (OWASP ASVS 5.0 §3.3 / NIST SP 800-63B-4). Both now enforce the same floor and fail closed. Separately, verify() gated its strict fingerprint controls (requireFingerprintMatch / maxAnomalyScore) on a request being supplied, so passing the strict flag WITHOUT a req silently skipped the check and admitted the session from any device; a strict policy with no way to compute the device fingerprint now fails closed. Finally, b.auditSign.verify honored its documented never-throw contract only for well-formed keys -- a malformed publicKeyPem made it throw; it now returns false. **Changed:** *Vendored Public Suffix List refreshed to the current snapshot* — The bundled Public Suffix List that backs domain classification (registrable-domain and public-suffix checks across URL, cookie, and SSRF handling) is updated to the latest upstream publicsuffix.org snapshot, so newly delegated public suffixes and updated private-domain entries are recognized. **Fixed:** *b.auditSign.verify returns false on a malformed public key instead of throwing* — verify(payload, signature, publicKeyPem) documents that it never throws -- callers branch on the boolean, and a verifier-only consumer (b.backupManifest.verifyBytes) may pass an untrusted publicKeyPem taken from a signature block. A malformed / non-PEM key made node:crypto throw (ERR_OSSL_UNSUPPORTED) while building the key object, crashing such a caller instead of cleanly rejecting. verify() now catches that and returns false, honoring the contract. As a result, b.auditSign.reSignAll now treats an entry whose old key is unverifiable as skipped (unverifiable) rather than as an error. **Security:** *b.session.rotate and b.session.updateData enforce the idle/absolute timeout floor* — A session read path enforces two floors independent of the operator's ttl: an idle timeout (default 30 min) and an absolute timeout (default 12 h). verify() and touch() enforced them, but rotate() and updateData() only checked that the operator ttl had not elapsed while resetting lastActivity -- so a session past its idle floor (which verify() would expire and delete) could be revived with a fresh idle window by rotating it or writing to it. Both now route through the same floor check and fail closed (return null / false and best-effort delete) on breach, so no refresh path can resurrect a session verify() would reject. touch() also now emits the idle/absolute-expiry audit signal on breach, matching verify(). · *A strict fingerprint policy without a request now fails closed* — verify()'s strict device-binding controls -- requireFingerprintMatch: true and maxAnomalyScore -- were only applied when the caller also passed a req to compute the current device fingerprint. Setting a strict flag WITHOUT a req therefore skipped the binding check entirely and admitted the session unchecked from any device -- a fail-open of a control the operator asked to be strict. A strict policy with no req to compare against now fails closed (returns null), the same discipline already applied when the stored binding is unreadable or absent.
|
|
12
|
+
|
|
11
13
|
- v0.17.22 (2026-07-25) — **`b.network.tls.checkServerIdentity9525` parses subjectAltName quote-aware, closing a hostname-verification bypass.** The strict RFC 9525 identity verifier parsed Node's subjectAltName string with a naive comma split, ignoring the JSON-quoted encoding Node emits for a SAN value that itself contains separators (the CVE-2021-44531/44532 remediation). A certificate whose single dNSName is a quoted blob such as `DNS:"x, DNS:victim.com, y"` was broken into pieces by the split, smuggling a clean `victim.com` token the certificate never asserts -- so checkServerIdentity9525 ACCEPTED a host that Node's own tls.checkServerIdentity REJECTS (ERR_TLS_CERT_ALTNAME_INVALID). The verifier now splits SAN entries on commas outside quotes and JSON-decodes quoted spans, matching Node's splitEscapedAltNames, so it asserts only the certificate's actual dNSName / IP values and is at least as strict as the function it advertises replacing. This path gates peer identity in b.crypto.spkiPinVerifier. **Security:** *checkServerIdentity9525 no longer accepts a hostname smuggled through a quoted subjectAltName* — Node renders a subjectAltName value that contains commas or control characters as a JSON-quoted string, so a single dNSName whose value is `x, DNS:victim.com, y` appears in cert.subjectaltname as `DNS:"x, DNS:victim.com, y"`. The verifier's SAN parser split that raw string on every comma, turning one entry into several and extracting a `DNS:victim.com` token the certificate does not actually present -- a hostname-verification bypass, since a strict RFC 9525 drop-in must be no weaker than the Node function it replaces (which rejects this cert). The parser now mirrors Node's splitEscapedAltNames: it splits only on commas outside quotes and JSON-decodes quoted spans, so each parsed dNSName is exactly one GeneralName and a smuggled name can no longer match. Malformed SAN quoting fails closed (asserts no identifiers). Operators using b.network.tls.checkServerIdentity9525 (directly or via b.crypto.spkiPinVerifier) should upgrade.
|
|
12
14
|
|
|
13
15
|
- v0.17.21 (2026-07-25) — **`blamejs erase` treats only `--confirm true` as confirmation, so `--confirm false` no longer triggers the irreversible erase.** Three fixes to the blamejs command line. The `erase` subcommand (a cryptographic single-row erase) gated its irreversible action on a bare-truthiness check, so `--confirm false` -- a string -- counted as confirmation and the erase proceeded; the gate now accepts only `true` / "true", matching `audit purge`, and refuses anything else. A stray `-v` / `--version` token alongside a subcommand no longer short-circuits to the version print: `blamejs migrate up --db x -v` previously returned 0 after printing the version without running the migration, handing automation a false pass; the version flag is now honored only when it is the whole invocation. And `blamejs dev` now survives a crash of the watched child -- it stays up to hot-restart on the next file change instead of draining the event loop and exiting 0 -- and awaits the child's full termination on SIGINT/SIGTERM so a shutdown cannot orphan it. **Fixed:** *blamejs erase refuses --confirm false instead of performing the irreversible erase* — The erase subcommand confirmed its irreversible action with a bare-truthiness check, so the string `--confirm false` was treated as confirmation and the erase ran. Confirmation is now satisfied only by `--confirm true` (or the bare `--confirm`), matching the check `audit purge` already used; any other value -- including `false` -- is refused with a non-zero exit and no erase. A shared confirmation helper backs every destructive subcommand so the acknowledgement contract cannot drift between them. · *A stray -v / --version no longer turns a subcommand into a silent no-op* — The top-level version flag was evaluated before subcommand dispatch and returned 0 whenever `-v` / `--version` appeared anywhere in the arguments, so a consequential command such as `migrate up`, `seed run`, or `erase` alongside a stray `-v` printed the version and exited 0 without doing anything -- a false success for any script checking the exit code. The version flag is now honored only when the invocation carries no subcommand; otherwise the subcommand runs (or fails) as written. · *blamejs dev survives a watched-child crash and shuts the child down cleanly* — The dev supervisor held the event loop open with an unref'd timer, so when the watched child process crashed the supervisor drained the loop and exited 0 -- defeating crash-resilience (it should stay up and hot-restart on the next file change) and reporting success even though the app had crashed. It now holds a referenced heartbeat so a child crash leaves the supervisor running, and on SIGINT/SIGTERM it awaits the child's full termination (graceful signal, then escalation) before exiting, so a shutdown can no longer race ahead and orphan the child.
|
package/NOTICE
CHANGED
|
@@ -90,7 +90,7 @@ Used for: Top-10000 most-common (breach-derived) passwords. Loaded by
|
|
|
90
90
|
baseline.
|
|
91
91
|
--------------------------------------------------------------------------------
|
|
92
92
|
Component: publicsuffix-list (Mozilla Public Suffix List)
|
|
93
|
-
Version: master snapshot (bundled 2026-07-
|
|
93
|
+
Version: master snapshot (bundled 2026-07-25)
|
|
94
94
|
Source: https://publicsuffix.org/list/public_suffix_list.dat
|
|
95
95
|
License: MPL-2.0
|
|
96
96
|
Copyright: Copyright (c) Mozilla Foundation and Public Suffix List contributors
|
package/lib/audit-sign.js
CHANGED
|
@@ -528,7 +528,16 @@ function verify(payload, signature, publicKeyPem) {
|
|
|
528
528
|
var buf = Buffer.isBuffer(payload) ? payload : Buffer.from(String(payload), "utf8");
|
|
529
529
|
var sigBuf = Buffer.isBuffer(signature) ? signature : Buffer.from(signature);
|
|
530
530
|
var pub = publicKeyPem || keys.publicKey;
|
|
531
|
-
|
|
531
|
+
// Contract: never throw — the caller branches on the boolean. A malformed /
|
|
532
|
+
// unsupported publicKeyPem (node:crypto raises ERR_OSSL_UNSUPPORTED building
|
|
533
|
+
// the KeyObject) is a verification FAILURE, not an exception: a verifier-only
|
|
534
|
+
// consumer (e.g. b.backupManifest.verifyBytes) may feed an untrusted PEM from
|
|
535
|
+
// a signature block and must get `false`, not a crash.
|
|
536
|
+
try {
|
|
537
|
+
return nodeCrypto.verify(null, buf, pub, sigBuf);
|
|
538
|
+
} catch (_e) {
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
532
541
|
}
|
|
533
542
|
|
|
534
543
|
/**
|
package/lib/session.js
CHANGED
|
@@ -541,6 +541,24 @@ function _timeoutFloorBreach(row, nowMs, opts) {
|
|
|
541
541
|
return null;
|
|
542
542
|
}
|
|
543
543
|
|
|
544
|
+
// Enforce the idle/absolute floor on a read row and, on breach, emit the
|
|
545
|
+
// audit signal and best-effort delete (leader-only) — returning the breach so
|
|
546
|
+
// the caller fails closed. EVERY session read/refresh path (verify, touch,
|
|
547
|
+
// rotate, updateData) routes through this: the row's TTL being live
|
|
548
|
+
// (expiresAt >= now) is NOT enough, and a refresh must never resurrect a
|
|
549
|
+
// session verify() would expire. The row must carry createdAt + lastActivity.
|
|
550
|
+
async function _floorBreachAndCleanup(row, sidHash, nowMs, opts) {
|
|
551
|
+
var breach = _timeoutFloorBreach(row, nowMs, opts);
|
|
552
|
+
if (!breach) return null;
|
|
553
|
+
try {
|
|
554
|
+
audit.safeEmit({ action: breach.action, outcome: "success", metadata: breach.metadata });
|
|
555
|
+
} catch (_ignored) { /* audit best-effort */ }
|
|
556
|
+
if (cluster.isLeader()) {
|
|
557
|
+
try { await _deleteBySidHash(sidHash); } catch (_e) { /* best-effort */ }
|
|
558
|
+
}
|
|
559
|
+
return breach;
|
|
560
|
+
}
|
|
561
|
+
|
|
544
562
|
async function verify(token, verifyOpts) {
|
|
545
563
|
if (typeof token !== "string" || token.length === 0) return null;
|
|
546
564
|
verifyOpts = verifyOpts || {};
|
|
@@ -572,16 +590,7 @@ async function verify(token, verifyOpts) {
|
|
|
572
590
|
// SP 800-63B-4). These shorten the effective lifetime even when the
|
|
573
591
|
// operator picked a long ttlMs. Defaults: idle 30m, absolute 12h.
|
|
574
592
|
// Operator opt-out by passing 0 (disables that timeout).
|
|
575
|
-
|
|
576
|
-
if (floorBreach) {
|
|
577
|
-
try {
|
|
578
|
-
audit.safeEmit({ action: floorBreach.action, outcome: "success", metadata: floorBreach.metadata });
|
|
579
|
-
} catch (_ignored) { /* audit best-effort */ }
|
|
580
|
-
if (cluster.isLeader()) {
|
|
581
|
-
try { await _deleteBySidHash(sidHash); } catch (_e) { /* best-effort */ }
|
|
582
|
-
}
|
|
583
|
-
return null;
|
|
584
|
-
}
|
|
593
|
+
if (await _floorBreachAndCleanup(row, sidHash, nowMs, verifyOpts)) return null;
|
|
585
594
|
// Unseal sealed columns (userId, data) using the cryptoField pipeline
|
|
586
595
|
// so we return cleartext to the caller — same shape as the previous
|
|
587
596
|
// db().from(...).first() path delivered.
|
|
@@ -642,9 +651,24 @@ async function verify(token, verifyOpts) {
|
|
|
642
651
|
// than silently skip the gate. Treating "no binding to compare" as "the
|
|
643
652
|
// binding matches" is the fail-open this refuses: it admitted an unbound (or
|
|
644
653
|
// unreadable-binding) session from ANY device even under a strict policy.
|
|
645
|
-
var
|
|
646
|
-
|
|
647
|
-
|
|
654
|
+
var strictFlagRequested =
|
|
655
|
+
verifyOpts.requireFingerprintMatch === true ||
|
|
656
|
+
typeof verifyOpts.maxAnomalyScore === "number";
|
|
657
|
+
// A strict policy asserted WITHOUT a req cannot compute the current device
|
|
658
|
+
// fingerprint at all — a contradictory configuration that must ALSO fail
|
|
659
|
+
// CLOSED, never silently admit from any device (the same fail-open the
|
|
660
|
+
// no-stored-fingerprint branch below refuses).
|
|
661
|
+
if (strictFlagRequested && !verifyOpts.req) {
|
|
662
|
+
try {
|
|
663
|
+
audit.safeEmit({
|
|
664
|
+
action: "auth.session.binding_no_request",
|
|
665
|
+
outcome: "failure",
|
|
666
|
+
metadata: { hasUserId: !!unsealed.userId },
|
|
667
|
+
});
|
|
668
|
+
} catch (_ig) { /* audit best-effort */ }
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
var strictBindingRequested = strictFlagRequested && !!verifyOpts.req;
|
|
648
672
|
if (strictBindingRequested && !storedFingerprint) {
|
|
649
673
|
try {
|
|
650
674
|
audit.safeEmit({
|
|
@@ -944,10 +968,7 @@ async function touch(token, opts) {
|
|
|
944
968
|
.toSql();
|
|
945
969
|
var floorRow = await _currentStore().executeOne(floorSel.sql, floorSel.params);
|
|
946
970
|
if (!floorRow) return false;
|
|
947
|
-
if (
|
|
948
|
-
try { await _deleteBySidHash(sidHash); } catch (_e) { /* best-effort */ }
|
|
949
|
-
return false;
|
|
950
|
-
}
|
|
971
|
+
if (await _floorBreachAndCleanup(floorRow, sidHash, nowMs, opts)) return false;
|
|
951
972
|
// Two SQL paths so the SET list stays static (no dynamic column
|
|
952
973
|
// assembly) and matches the call shape clusterStorage expects.
|
|
953
974
|
// extendBy resets expiresAt relative to NOW, not relative to the
|
|
@@ -1008,8 +1029,18 @@ async function touch(token, opts) {
|
|
|
1008
1029
|
* reason?: string, // audit metadata ("login", "mfa", "role-change")
|
|
1009
1030
|
* req?: IncomingMessage, // re-key the device fingerprint to the new sid
|
|
1010
1031
|
* fingerprintFields?: Array<string|fn>, // default ["clientIp","userAgent","acceptLanguage"]
|
|
1032
|
+
* idleTimeoutMs?: number, // idle floor (default 30m; 0 disables)
|
|
1033
|
+
* absoluteTimeoutMs?: number, // absolute floor (default 12h; 0 disables)
|
|
1011
1034
|
* }
|
|
1012
1035
|
*
|
|
1036
|
+
* rotate() enforces the SAME idle/absolute timeout floor verify() does and
|
|
1037
|
+
* fails closed (returns null + deletes) on a session past it — a rotate must
|
|
1038
|
+
* never resurrect a session verify() would expire. Pass idleTimeoutMs /
|
|
1039
|
+
* absoluteTimeoutMs consistently with the values used at verify() (the policy
|
|
1040
|
+
* is per-call): a deployment that disables the idle floor via
|
|
1041
|
+
* verify(token, { idleTimeoutMs: 0 }) must pass the same here, or a
|
|
1042
|
+
* long-idle-but-valid session is purged on rotation.
|
|
1043
|
+
*
|
|
1013
1044
|
* @example
|
|
1014
1045
|
* var rotated = await b.session.rotate(req.cookies.sid, {
|
|
1015
1046
|
* ttlMs: b.constants.TIME.hours(8),
|
|
@@ -1050,12 +1081,15 @@ async function rotate(oldToken, opts) {
|
|
|
1050
1081
|
? opts.fingerprintFields : DEFAULT_FINGERPRINT_FIELDS;
|
|
1051
1082
|
var existingData = null;
|
|
1052
1083
|
var rotSelBuilt = sql.select(_sessionSqlTable(), _sessionSqlOpts())
|
|
1053
|
-
.columns(["data"])
|
|
1084
|
+
.columns(["data", "createdAt", "lastActivity"])
|
|
1054
1085
|
.where("sidHash", oldSidHash)
|
|
1055
1086
|
.where("expiresAt", ">=", nowMs)
|
|
1056
1087
|
.toSql();
|
|
1057
1088
|
var existingRow = await _currentStore().executeOne(rotSelBuilt.sql, rotSelBuilt.params);
|
|
1058
1089
|
if (!existingRow) return null; // unknown / expired old session
|
|
1090
|
+
// A rotate must not resurrect a session past its idle/absolute floor — the
|
|
1091
|
+
// TTL being live is not enough; enforce the same floor verify()/touch() do.
|
|
1092
|
+
if (await _floorBreachAndCleanup(existingRow, oldSidHash, nowMs, opts)) return null;
|
|
1059
1093
|
try {
|
|
1060
1094
|
var unsealedExisting = cryptoField.unsealRow(SESSION_TABLE, existingRow);
|
|
1061
1095
|
if (unsealedExisting.data) existingData = safeJson.parse(unsealedExisting.data);
|
|
@@ -1157,8 +1191,17 @@ async function rotate(oldToken, opts) {
|
|
|
1157
1191
|
* {
|
|
1158
1192
|
* merge?: boolean, // default false (full replace)
|
|
1159
1193
|
* touchLastActivity?: boolean, // default true
|
|
1194
|
+
* idleTimeoutMs?: number, // idle floor (default 30m; 0 disables)
|
|
1195
|
+
* absoluteTimeoutMs?: number, // absolute floor (default 12h; 0 disables)
|
|
1160
1196
|
* }
|
|
1161
1197
|
*
|
|
1198
|
+
* updateData() enforces the SAME idle/absolute timeout floor verify() does and
|
|
1199
|
+
* fails closed (returns false + deletes) on a session past it — a write must
|
|
1200
|
+
* not resurrect a session verify() would expire. The floor policy is per-call:
|
|
1201
|
+
* pass idleTimeoutMs / absoluteTimeoutMs consistently with the values used at
|
|
1202
|
+
* verify(), or a long-idle-but-valid session (e.g. one accepted under
|
|
1203
|
+
* verify(token, { idleTimeoutMs: 0 })) is purged on the next write.
|
|
1204
|
+
*
|
|
1162
1205
|
* @example
|
|
1163
1206
|
* // Replace the data payload entirely.
|
|
1164
1207
|
* await b.session.updateData(req.cookies.sid, { roles: ["admin"], theme: "dark" });
|
|
@@ -1194,6 +1237,10 @@ async function updateData(token, data, opts) {
|
|
|
1194
1237
|
.toSql();
|
|
1195
1238
|
var row = await _currentStore().executeOne(selBuilt.sql, selBuilt.params);
|
|
1196
1239
|
if (!row) return false;
|
|
1240
|
+
// A write must not resurrect a session past its idle/absolute floor (the
|
|
1241
|
+
// same floor verify()/touch() enforce) — resetting lastActivity on an
|
|
1242
|
+
// idle-expired-but-TTL-live session would defeat the idle timeout.
|
|
1243
|
+
if (await _floorBreachAndCleanup(row, sidHash, nowMs, opts)) return false;
|
|
1197
1244
|
|
|
1198
1245
|
// Recover the existing data + reserved fingerprint key (vault-
|
|
1199
1246
|
// sealed at rest). Operators that want a fresh fingerprint also
|
package/lib/vendor/MANIFEST.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"hashes": {
|
|
19
19
|
"server": "sha256:2b30a26f728c5349f4c4b47834f862a4f77393b1224fc12b22abe3ce2cfab78f"
|
|
20
20
|
},
|
|
21
|
-
"refreshedAt": "2026-07-
|
|
21
|
+
"refreshedAt": "2026-07-25T17:09:57.034Z"
|
|
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-07-
|
|
43
|
+
"refreshedAt": "2026-07-25T17:09:57.034Z"
|
|
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-07-
|
|
74
|
+
"refreshedAt": "2026-07-25T17:09:57.034Z"
|
|
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-07-
|
|
97
|
+
"refreshedAt": "2026-07-25T17:09:57.034Z"
|
|
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-07-
|
|
117
|
+
"refreshedAt": "2026-07-25T17:09:57.034Z"
|
|
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-07-
|
|
142
|
+
"refreshedAt": "2026-07-25T17:09:57.034Z"
|
|
143
143
|
},
|
|
144
144
|
"publicsuffix-list": {
|
|
145
145
|
"version": "master",
|
|
@@ -152,14 +152,14 @@
|
|
|
152
152
|
"data_js": "lib/vendor/public-suffix-list.data.js"
|
|
153
153
|
},
|
|
154
154
|
"bundler": "curl https://publicsuffix.org/list/public_suffix_list.dat",
|
|
155
|
-
"bundledAt": "2026-07-
|
|
155
|
+
"bundledAt": "2026-07-25T00:00:00Z",
|
|
156
156
|
"hashes": {
|
|
157
|
-
"server": "sha256:
|
|
158
|
-
"data_js": "sha256:
|
|
157
|
+
"server": "sha256:0240b3f1e8c90ecd4af5b94597afb5ba89997ad395f292f87318caefb7e10413",
|
|
158
|
+
"data_js": "sha256:7994e24e1865f197540a988783de567fe20fb29e7f6c3a5c142766bb0cfd9bfd"
|
|
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-07-
|
|
162
|
+
"refreshedAt": "2026-07-25T17:09:57.034Z"
|
|
163
163
|
},
|
|
164
164
|
"peculiar-pki": {
|
|
165
165
|
"version": "2.0.0+pkijs-3.4.0",
|
|
@@ -190,7 +190,7 @@
|
|
|
190
190
|
"hashes": {
|
|
191
191
|
"server": "sha256:2307ef65e070757ffb13442b377e45efb9fa1a10432d9b39618387720ab990ed"
|
|
192
192
|
},
|
|
193
|
-
"refreshedAt": "2026-07-
|
|
193
|
+
"refreshedAt": "2026-07-25T17:09:57.034Z"
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Please pull this list from, and only from https://publicsuffix.org/list/public_suffix_list.dat,
|
|
6
6
|
// rather than any other VCS sites. Pulling from any other URL is not guaranteed to be supported.
|
|
7
7
|
|
|
8
|
-
// VERSION: 2026-07-
|
|
9
|
-
// COMMIT:
|
|
8
|
+
// VERSION: 2026-07-25_14-20-03_UTC
|
|
9
|
+
// COMMIT: e1b8015c3b2f0f4f8c18659c2480fc1a22c07b20
|
|
10
10
|
|
|
11
11
|
// Instructions on pulling and using this list can be found at https://publicsuffix.org/list/.
|
|
12
12
|
|
|
@@ -11304,10 +11304,6 @@ ltd.ua
|
|
|
11304
11304
|
a2hosted.com
|
|
11305
11305
|
cpserver.com
|
|
11306
11306
|
|
|
11307
|
-
// Acorn Labs : https://acorn.io
|
|
11308
|
-
// Submitted by Craig Jellick <domains@acorn.io>
|
|
11309
|
-
*.on-acorn.io
|
|
11310
|
-
|
|
11311
11307
|
// ActiveTrail : https://www.activetrail.biz/
|
|
11312
11308
|
// Submitted by Ofer Kalaora <postmaster@activetrail.com>
|
|
11313
11309
|
activetrail.biz
|