@blamejs/core 0.15.15 → 0.15.17
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/lib/atomic-file.js +66 -9
- package/lib/auth/fido-mds3.js +10 -0
- package/lib/auth/password.js +1 -0
- package/lib/auth/saml.js +11 -3
- package/lib/daemon.js +4 -1
- package/lib/external-db.js +131 -0
- package/lib/graphql-federation.js +25 -15
- package/lib/log-stream-cloudwatch.js +1 -0
- package/lib/log-stream-local.js +14 -1
- package/lib/log-stream-otlp.js +1 -0
- package/lib/log-stream-webhook.js +1 -0
- package/lib/mail-auth.js +69 -14
- package/lib/mail-bimi.js +6 -0
- package/lib/mail-crypto-smime.js +10 -0
- package/lib/mail-dkim.js +68 -15
- package/lib/mail.js +39 -0
- package/lib/middleware/api-encrypt.js +111 -42
- package/lib/network-dns-resolver.js +61 -11
- package/lib/network-dns.js +47 -2
- package/lib/network-nts.js +16 -0
- package/lib/network-proxy.js +55 -2
- package/lib/object-store/azure-blob-bucket-ops.js +1 -0
- package/lib/object-store/gcs-bucket-ops.js +1 -0
- package/lib/object-store/http-request.js +4 -0
- package/lib/outbox.js +29 -0
- package/lib/queue-local.js +123 -46
- package/lib/queue-sqs.js +1 -0
- package/lib/queue.js +13 -9
- package/lib/request-helpers.js +25 -6
- package/lib/self-update-standalone-verifier.js +69 -7
- package/lib/self-update.js +11 -2
- package/lib/session-device-binding.js +46 -24
- package/lib/session.js +85 -28
- package/lib/vendor/MANIFEST.json +11 -11
- package/lib/vendor/public-suffix-list.dat +6 -2
- package/lib/vendor/public-suffix-list.data.js +689 -688
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
|
@@ -52,6 +52,14 @@
|
|
|
52
52
|
* primitive falls back to b.session.touch metadata when the operator
|
|
53
53
|
* passes session=b.session AND opts in via storeInSession=true.
|
|
54
54
|
*
|
|
55
|
+
* No store at all: create() with neither bindingStore nor storeInSession
|
|
56
|
+
* still returns an instance — its stateless fingerprint(req) works (it
|
|
57
|
+
* touches no store), while bind/verify/unbind throw a clear "no store
|
|
58
|
+
* configured" error. Operators who only need the soft, store-free digest
|
|
59
|
+
* (sealed inside a self-validating cookie / JWT that compares it itself)
|
|
60
|
+
* can also skip create() entirely and call the static
|
|
61
|
+
* b.sessionDeviceBinding.fingerprint(req, opts).
|
|
62
|
+
*
|
|
55
63
|
* Audit emissions:
|
|
56
64
|
*
|
|
57
65
|
* session.device.bound every successful bind()
|
|
@@ -61,7 +69,9 @@
|
|
|
61
69
|
*
|
|
62
70
|
* Validation policy:
|
|
63
71
|
* - create() opts → throw at config time
|
|
64
|
-
* - bind / verify
|
|
72
|
+
* - bind / verify / unbind → throw on bad token / req shape (operator
|
|
73
|
+
* typo), and throw "no store configured" when called
|
|
74
|
+
* on a store-free instance
|
|
65
75
|
* - storage errors → fail-CLOSED on verify (drift indistinguishable
|
|
66
76
|
* from a wiped store, refuse rather than allow)
|
|
67
77
|
* fail-OPEN on bind (don't lose a fresh session
|
|
@@ -135,28 +145,22 @@ function _normalizeAcceptEncoding(value) {
|
|
|
135
145
|
.join(",");
|
|
136
146
|
}
|
|
137
147
|
|
|
148
|
+
// Mask the client IP to its fingerprint bucket. Routes through the shared
|
|
149
|
+
// canonical masker (requestHelpers.ipPrefix) so a `::`-shorthand address and
|
|
150
|
+
// its fully-expanded equivalent (2001:db8::1 vs 2001:db8:0:0:0:0:0:1), or a
|
|
151
|
+
// leading-zero-folded group, collapse to ONE bucket — the hand-rolled textual
|
|
152
|
+
// ':'-group slice this replaced hashed them differently and logged a roaming
|
|
153
|
+
// user out on a false drift. `bits === 0` is the documented "skip the IP check
|
|
154
|
+
// entirely" escape hatch (mobile clients that switch networks), so it returns
|
|
155
|
+
// "" before any masking. `bits` is the family-resolved configured width (cfg
|
|
156
|
+
// .v4Bits for a v4 client, cfg.v6Bits for v6 — default /24 + /48); pass it as
|
|
157
|
+
// BOTH v4Bits and v6Bits so the canonical masker applies the configured width
|
|
158
|
+
// to whichever family it detects, instead of ipPrefix's bare /24 + /64 default
|
|
159
|
+
// (which would drop the configured width AND silently tighten v6 from /48 to /64).
|
|
138
160
|
function _ipPrefix(ip, bits) {
|
|
139
161
|
if (typeof ip !== "string" || ip.length === 0) return "";
|
|
140
162
|
if (bits === 0) return "";
|
|
141
|
-
|
|
142
|
-
if (ip.indexOf(":") !== -1) {
|
|
143
|
-
var v6Bits = bits;
|
|
144
|
-
var groups = ip.split(":");
|
|
145
|
-
// Naive expansion — keep the first ceil(v6Bits/16) groups intact
|
|
146
|
-
// and zero the rest. Sufficient for fingerprint stability; not a
|
|
147
|
-
// canonical IPv6 representation.
|
|
148
|
-
var keepGroups = Math.ceil(v6Bits / 16); // IPv6 group width in bits
|
|
149
|
-
var kept = groups.slice(0, keepGroups).join(":");
|
|
150
|
-
return "v6:" + kept + "/" + v6Bits;
|
|
151
|
-
}
|
|
152
|
-
// IPv4
|
|
153
|
-
var parts = ip.split(".");
|
|
154
|
-
if (parts.length !== 4) return "v4:" + ip + "/" + bits;
|
|
155
|
-
var v4Bits = bits;
|
|
156
|
-
var keepOctets = Math.floor(v4Bits / 8); // IPv4 octet width in bits
|
|
157
|
-
var maskedOctets = parts.slice(0, keepOctets);
|
|
158
|
-
while (maskedOctets.length < 4) maskedOctets.push("0");
|
|
159
|
-
return "v4:" + maskedOctets.join(".") + "/" + v4Bits;
|
|
163
|
+
return requestHelpers.ipPrefix(ip, { v4Bits: bits, v6Bits: bits });
|
|
160
164
|
}
|
|
161
165
|
|
|
162
166
|
// Resolve operator-supplied fingerprintExtras(req) to a stable string. A
|
|
@@ -195,6 +199,7 @@ function _computeDeviceFingerprint(req, cfg) {
|
|
|
195
199
|
var ae = _normalizeAcceptEncoding(headers["accept-encoding"]);
|
|
196
200
|
var ip = "";
|
|
197
201
|
try { ip = requestHelpers.clientIp(req); } catch (_e) { ip = ""; }
|
|
202
|
+
if (typeof ip !== "string") ip = "";
|
|
198
203
|
var family = ip.indexOf(":") !== -1 ? "v6" : "v4";
|
|
199
204
|
var ipPart = _ipPrefix(ip, family === "v6" ? cfg.v6Bits : cfg.v4Bits);
|
|
200
205
|
var keyPart = "";
|
|
@@ -291,10 +296,15 @@ function create(opts) {
|
|
|
291
296
|
}
|
|
292
297
|
|
|
293
298
|
var storeInSession = !!opts.storeInSession;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
299
|
+
// A no-store instance is still useful: the stateless fingerprint() reads no
|
|
300
|
+
// store and is the soft device-binding building block for self-validating
|
|
301
|
+
// tokens (a sealed cookie / JWT carrying the fingerprint inside). Rather than
|
|
302
|
+
// refuse to construct (issue #330 — fingerprint() unreachable without a
|
|
303
|
+
// store), build the instance and let the persisted bind()/verify() lifecycle
|
|
304
|
+
// throw a clear "no store configured" when actually called. Operators wanting
|
|
305
|
+
// ONLY the stateless digest can also use the static
|
|
306
|
+
// b.sessionDeviceBinding.fingerprint(req, opts) with no create() at all.
|
|
307
|
+
var hasStore = !!(storeInSession || opts.bindingStore);
|
|
298
308
|
if (opts.bindingStore) _requireBindingStore(opts.bindingStore);
|
|
299
309
|
if (storeInSession && (!opts.session || typeof opts.session.touch !== "function")) {
|
|
300
310
|
throw new SessionDeviceBindingError("session-device-binding/bad-opt",
|
|
@@ -351,8 +361,18 @@ function create(opts) {
|
|
|
351
361
|
return { ok: true, fingerprint: r.fingerprint, components: r.components };
|
|
352
362
|
}
|
|
353
363
|
|
|
364
|
+
function _requireStore(stage) {
|
|
365
|
+
if (!hasStore) {
|
|
366
|
+
throw new SessionDeviceBindingError("session-device-binding/no-store",
|
|
367
|
+
stage + ": no store configured — pass bindingStore (b.cache-shaped) or "
|
|
368
|
+
+ "storeInSession=true to create(), or use the stateless "
|
|
369
|
+
+ "b.sessionDeviceBinding.fingerprint(req, opts) for soft binding");
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
354
373
|
async function bind(token, req) {
|
|
355
374
|
_requireToken(token);
|
|
375
|
+
_requireStore("bind");
|
|
356
376
|
var fp = _computeFingerprint(req);
|
|
357
377
|
if (!fp.ok) {
|
|
358
378
|
_emitObs("session.device.refused", { reason: fp.reason });
|
|
@@ -408,6 +428,7 @@ function create(opts) {
|
|
|
408
428
|
|
|
409
429
|
async function verify(token, req) {
|
|
410
430
|
_requireToken(token);
|
|
431
|
+
_requireStore("verify");
|
|
411
432
|
var fpResult = _computeFingerprint(req);
|
|
412
433
|
if (!fpResult.ok) {
|
|
413
434
|
_emitObs("session.device.refused", { reason: fpResult.reason });
|
|
@@ -444,6 +465,7 @@ function create(opts) {
|
|
|
444
465
|
|
|
445
466
|
async function unbind(token) {
|
|
446
467
|
_requireToken(token);
|
|
468
|
+
_requireStore("unbind");
|
|
447
469
|
if (bindingStore) {
|
|
448
470
|
try { await bindingStore.del(token); } catch (_e) { /* drop-silent */ }
|
|
449
471
|
}
|
package/lib/session.js
CHANGED
|
@@ -182,6 +182,49 @@ function _validFromConflictRefs(dialect, table) {
|
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
// CREATE TABLE IF NOT EXISTS for the valid-from boundary, matching the
|
|
186
|
+
// framework schema in db.js (single-node) / framework-schema.js (cluster mode):
|
|
187
|
+
// subjectHash PRIMARY KEY, validFromEpoch + updatedAt NOT NULL. The pluggable
|
|
188
|
+
// store is always a dedicated node:sqlite file (b.session.stores.localDbThin —
|
|
189
|
+
// see session-stores.js), so the dialect is the literal "sqlite". Used to
|
|
190
|
+
// provision the table on demand in a store-backed-only deployment (a
|
|
191
|
+
// b.session.useStore consumer that never ran b.db.init(), so the framework db
|
|
192
|
+
// — the default home of this table — is not initialized).
|
|
193
|
+
function _validFromSchemaSql() {
|
|
194
|
+
return sql.createTable(_validFromSqlTable(), [
|
|
195
|
+
{ name: "subjectHash", type: "text", primaryKey: true },
|
|
196
|
+
{ name: "validFromEpoch", type: "int", notNull: true },
|
|
197
|
+
{ name: "updatedAt", type: "int", notNull: true },
|
|
198
|
+
], { dialect: "sqlite" }).sql;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Run a valid-from boundary operation (bump write / validFrom read / check
|
|
202
|
+
// read) against the correct backend. The boundary lives in the FRAMEWORK db
|
|
203
|
+
// (clusterStorage) — it is a stateless-token revocation primitive shared across
|
|
204
|
+
// every issuer, not per-session data — so that is always the first choice and a
|
|
205
|
+
// present db is never silently bypassed. ONLY when the framework db is not
|
|
206
|
+
// initialized (single-node, b.db.init() never awaited) AND an operator store is
|
|
207
|
+
// configured (b.session.useStore) does the boundary fall back to that store, so
|
|
208
|
+
// a store-backed-only deployment's logout-everywhere still raises (and honors)
|
|
209
|
+
// the stateless boundary instead of 500ing on db/not-initialized (#340). With
|
|
210
|
+
// neither a framework db nor a store, db/not-initialized is a real
|
|
211
|
+
// misconfiguration and propagates unchanged (fail closed — the boundary is
|
|
212
|
+
// never silently dropped). The store provisions the table on demand because a
|
|
213
|
+
// session-data store (localDbThin) does not ship the valid-from DDL.
|
|
214
|
+
async function _runValidFrom(runner) {
|
|
215
|
+
try {
|
|
216
|
+
return await runner(clusterStorage);
|
|
217
|
+
} catch (e) {
|
|
218
|
+
if (e && e.code === "db/not-initialized" && _store) {
|
|
219
|
+
// Framework db absent, operator store present: route through the store,
|
|
220
|
+
// provisioning the boundary table first (idempotent CREATE IF NOT EXISTS).
|
|
221
|
+
await _store.execute(_validFromSchemaSql(), []);
|
|
222
|
+
return await runner(_store);
|
|
223
|
+
}
|
|
224
|
+
throw e;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
185
228
|
// Column order used for INSERT — kept as a constant so the placeholders
|
|
186
229
|
// list and the values list stay in sync. Must match the session table's
|
|
187
230
|
// schema in db.js (single-node) and framework-schema.js (cluster mode).
|
|
@@ -786,21 +829,23 @@ async function destroyAllForUser(userId) {
|
|
|
786
829
|
var result = await _currentStore().execute(built.sql, built.params);
|
|
787
830
|
// Also raise the stateless valid-from boundary so a "logout everywhere"
|
|
788
831
|
// revokes the operator's stateless tokens (sealed cookies / JWTs checked via
|
|
789
|
-
// b.session.check) too, not only the store-backed rows just deleted.
|
|
790
|
-
//
|
|
791
|
-
// (b.session.useStore)
|
|
792
|
-
//
|
|
793
|
-
//
|
|
832
|
+
// b.session.check) too, not only the store-backed rows just deleted. bump()
|
|
833
|
+
// writes to the framework db when one is initialized, otherwise to the
|
|
834
|
+
// configured store (b.session.useStore) — so a store-backed-only consumer who
|
|
835
|
+
// never ran b.db.init() still raises the boundary here instead of 500ing on
|
|
836
|
+
// db/not-initialized (#340). The only state in which bump still surfaces
|
|
837
|
+
// db/not-initialized is the default store (no useStore) with an uninitialized
|
|
838
|
+
// framework db — but the store DELETE above (also via clusterStorage) would
|
|
839
|
+
// have already thrown, so this rewrap is defensive belt-and-suspenders.
|
|
794
840
|
try {
|
|
795
841
|
await bump(userId);
|
|
796
842
|
} catch (e) {
|
|
797
843
|
if (e && e.code === "db/not-initialized") {
|
|
798
844
|
throw _err("MISCONFIGURED",
|
|
799
845
|
"session.destroyAllForUser raises the stateless valid-from boundary (so a " +
|
|
800
|
-
"logout-everywhere also revokes sealed-cookie / JWT sessions)
|
|
801
|
-
"b.db.init()
|
|
802
|
-
"
|
|
803
|
-
"after b.db.init() to also raise the stateless boundary.", true);
|
|
846
|
+
"logout-everywhere also revokes sealed-cookie / JWT sessions). No storage is " +
|
|
847
|
+
"available: call b.db.init() at boot, OR configure a session store via " +
|
|
848
|
+
"b.session.useStore. The store-backed rows were already deleted.", true);
|
|
804
849
|
}
|
|
805
850
|
throw e;
|
|
806
851
|
}
|
|
@@ -1340,21 +1385,27 @@ async function bump(subjectId, opts) {
|
|
|
1340
1385
|
.returning(["validFromEpoch"])
|
|
1341
1386
|
.toSql();
|
|
1342
1387
|
// The valid-from boundary is a FRAMEWORK table (FRAMEWORK_SCHEMA / cluster
|
|
1343
|
-
// DDL), NOT session data — it
|
|
1344
|
-
//
|
|
1345
|
-
//
|
|
1346
|
-
//
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1388
|
+
// DDL), NOT session data — it executes against clusterStorage (the framework
|
|
1389
|
+
// db) whenever one is initialized, never _currentStore(). When the framework
|
|
1390
|
+
// db is NOT initialized but an operator store IS configured (a store-backed-
|
|
1391
|
+
// only b.session.useStore deployment that never ran b.db.init()), the boundary
|
|
1392
|
+
// falls back to that store — provisioned on demand — so logout-everywhere
|
|
1393
|
+
// still raises the stateless boundary instead of throwing db/not-initialized
|
|
1394
|
+
// (#340). _runValidFrom resolves the target; never silently drops the boundary
|
|
1395
|
+
// when a db is present, and propagates db/not-initialized when neither exists.
|
|
1396
|
+
var row = await _runValidFrom(async function (target) {
|
|
1397
|
+
if (built.readbackSql) {
|
|
1398
|
+
// MySQL: ON DUPLICATE KEY UPDATE has no RETURNING — run the upsert, then
|
|
1399
|
+
// the readback SELECT b.sql emits (keyed on subjectHash). MySQL only ever
|
|
1400
|
+
// runs against the framework cluster db; the localDbThin fallback store is
|
|
1401
|
+
// sqlite (RETURNING), so this branch never routes through it.
|
|
1402
|
+
await target.execute(built.sql, built.params);
|
|
1403
|
+
var readback = await target.execute(built.readbackSql.sql, built.readbackSql.params);
|
|
1404
|
+
return readback.rows && readback.rows[0];
|
|
1405
|
+
}
|
|
1406
|
+
var result = await target.execute(built.sql, built.params);
|
|
1407
|
+
return result.rows && result.rows[0];
|
|
1408
|
+
});
|
|
1358
1409
|
var effective = row ? Number(row.validFromEpoch) : epochMs;
|
|
1359
1410
|
|
|
1360
1411
|
// Best-effort audit — matches the file's emit convention (safeEmit is
|
|
@@ -1393,10 +1444,16 @@ async function validFrom(subjectId) {
|
|
|
1393
1444
|
.columns(["validFromEpoch"])
|
|
1394
1445
|
.where("subjectHash", _hashSubjectId(subjectId))
|
|
1395
1446
|
.toSql();
|
|
1396
|
-
// Framework valid-from table — read from clusterStorage (the framework db)
|
|
1397
|
-
//
|
|
1398
|
-
//
|
|
1399
|
-
|
|
1447
|
+
// Framework valid-from table — read from clusterStorage (the framework db)
|
|
1448
|
+
// when one is initialized, falling back to the configured store only when it
|
|
1449
|
+
// is not (the same store bump() wrote the boundary to in a store-backed-only
|
|
1450
|
+
// deployment). _runValidFrom keeps the read on the SAME backend the write
|
|
1451
|
+
// chose, so a boundary raised via destroyAllForUser/bump is the one read back
|
|
1452
|
+
// here. See bump() for the full rationale (#340).
|
|
1453
|
+
var row = await _runValidFrom(async function (target) {
|
|
1454
|
+
var result = await target.execute(built.sql, built.params);
|
|
1455
|
+
return result.rows && result.rows.length > 0 ? result.rows[0] : null;
|
|
1456
|
+
});
|
|
1400
1457
|
return row ? Number(row.validFromEpoch) : 0;
|
|
1401
1458
|
}
|
|
1402
1459
|
|
package/lib/vendor/MANIFEST.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"hashes": {
|
|
19
19
|
"server": "sha256:5d539dfc9ef47121d4c09bd7256d76448a1f5ac47ee09ac44c78ff6a062af9ab"
|
|
20
20
|
},
|
|
21
|
-
"refreshedAt": "2026-06-
|
|
21
|
+
"refreshedAt": "2026-06-22T16:29:46.590Z"
|
|
22
22
|
},
|
|
23
23
|
"@noble/curves": {
|
|
24
24
|
"version": "2.2.0",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"hashes": {
|
|
41
41
|
"server": "sha256:ebf254d5eb56aef8705a1c4af9603f47987b4870a9bb5e657e06907b701e2731"
|
|
42
42
|
},
|
|
43
|
-
"refreshedAt": "2026-06-
|
|
43
|
+
"refreshedAt": "2026-06-22T16:29:46.590Z"
|
|
44
44
|
},
|
|
45
45
|
"@noble/post-quantum": {
|
|
46
46
|
"version": "0.6.1",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"hashes": {
|
|
72
72
|
"server": "sha256:f9190309daadca4c2e2cc2b76beaa6b96e463429cc3c390bd9f0ceaf7b588c68"
|
|
73
73
|
},
|
|
74
|
-
"refreshedAt": "2026-06-
|
|
74
|
+
"refreshedAt": "2026-06-22T16:29:46.590Z"
|
|
75
75
|
},
|
|
76
76
|
"@simplewebauthn/server": {
|
|
77
77
|
"version": "13.3.1",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"hashes": {
|
|
95
95
|
"server": "sha256:f359a782ac57e3ff56ac71083d17f5c082f88ab49d645fc2bede398b47adebdb"
|
|
96
96
|
},
|
|
97
|
-
"refreshedAt": "2026-06-
|
|
97
|
+
"refreshedAt": "2026-06-22T16:29:46.590Z"
|
|
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-06-
|
|
117
|
+
"refreshedAt": "2026-06-22T16:29:46.590Z"
|
|
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-06-
|
|
142
|
+
"refreshedAt": "2026-06-22T16:29:46.590Z"
|
|
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-
|
|
155
|
+
"bundledAt": "2026-06-22T00:00:00Z",
|
|
156
156
|
"hashes": {
|
|
157
|
-
"server": "sha256:
|
|
158
|
-
"data_js": "sha256:
|
|
157
|
+
"server": "sha256:0adddeb62057d8d40799dffb29fe14f65dd009259afe02eb2f0b4602b791aae6",
|
|
158
|
+
"data_js": "sha256:82af512cacf0fd2c60925e63f877b69477b1b2f7bb5af698fd862af61369902e"
|
|
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-06-
|
|
162
|
+
"refreshedAt": "2026-06-22T16:29:46.590Z"
|
|
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:9bbc191afaaa2b1e5757f00480457c08134cdc2c55d541df18d9155bba9cbf77"
|
|
192
192
|
},
|
|
193
|
-
"refreshedAt": "2026-06-
|
|
193
|
+
"refreshedAt": "2026-06-22T16:29:46.590Z"
|
|
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-06-
|
|
9
|
-
// COMMIT:
|
|
8
|
+
// VERSION: 2026-06-22_11-46-12_UTC
|
|
9
|
+
// COMMIT: 27a7b5d881b91def306422e6cc243f05c49f3a58
|
|
10
10
|
|
|
11
11
|
// Instructions on pulling and using this list can be found at https://publicsuffix.org/list/.
|
|
12
12
|
|
|
@@ -14721,6 +14721,10 @@ mittwaldserver.info
|
|
|
14721
14721
|
typo3server.info
|
|
14722
14722
|
project.space
|
|
14723
14723
|
|
|
14724
|
+
// MKM : https://mkm.fan/
|
|
14725
|
+
// Submitted by Kashi Ahmer <admin@mkm.fan>
|
|
14726
|
+
mkm.fan
|
|
14727
|
+
|
|
14724
14728
|
// Mocha : https://getmocha.com
|
|
14725
14729
|
// Submitted by Ben Reinhart <security@getmocha.com>
|
|
14726
14730
|
mocha.app
|