@cello-protocol/daemon 0.0.182 → 0.0.183
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/dist/agent-settings-keys.d.ts.map +1 -1
- package/dist/agent-settings-keys.js +18 -0
- package/dist/agent-settings-keys.js.map +1 -1
- package/dist/consortium-bootstrap.d.ts.map +1 -1
- package/dist/consortium-bootstrap.js +117 -2
- package/dist/consortium-bootstrap.js.map +1 -1
- package/dist/content-encryption-status.d.ts +97 -0
- package/dist/content-encryption-status.d.ts.map +1 -0
- package/dist/content-encryption-status.js +122 -0
- package/dist/content-encryption-status.js.map +1 -0
- package/dist/content-park-client.d.ts +10 -0
- package/dist/content-park-client.d.ts.map +1 -1
- package/dist/content-park-client.js +84 -3
- package/dist/content-park-client.js.map +1 -1
- package/dist/content-park.d.ts.map +1 -1
- package/dist/content-park.js +184 -13
- package/dist/content-park.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +306 -23
- package/dist/daemon.js.map +1 -1
- package/dist/document-handlers.d.ts.map +1 -1
- package/dist/document-handlers.js +119 -0
- package/dist/document-handlers.js.map +1 -1
- package/dist/document-layer.d.ts +0 -2
- package/dist/document-layer.d.ts.map +1 -1
- package/dist/document-layer.js.map +1 -1
- package/dist/initiate-session-handler.d.ts.map +1 -1
- package/dist/initiate-session-handler.js +34 -3
- package/dist/initiate-session-handler.js.map +1 -1
- package/dist/manifest-deps.d.ts +0 -11
- package/dist/manifest-deps.d.ts.map +1 -1
- package/dist/manifest-deps.js +28 -2
- package/dist/manifest-deps.js.map +1 -1
- package/dist/manifest-validity.d.ts +2 -0
- package/dist/manifest-validity.d.ts.map +1 -1
- package/dist/manifest-validity.js +1 -1
- package/dist/manifest-validity.js.map +1 -1
- package/dist/outbound-sessions.d.ts.map +1 -1
- package/dist/outbound-sessions.js +19 -0
- package/dist/outbound-sessions.js.map +1 -1
- package/dist/park-envelope.d.ts +23 -0
- package/dist/park-envelope.d.ts.map +1 -1
- package/dist/park-envelope.js +76 -0
- package/dist/park-envelope.js.map +1 -1
- package/dist/register-handler.d.ts.map +1 -1
- package/dist/register-handler.js +76 -0
- package/dist/register-handler.js.map +1 -1
- package/dist/relay-only.d.ts +133 -0
- package/dist/relay-only.d.ts.map +1 -0
- package/dist/relay-only.js +183 -0
- package/dist/relay-only.js.map +1 -0
- package/dist/retry-queue.d.ts +26 -1
- package/dist/retry-queue.d.ts.map +1 -1
- package/dist/retry-queue.js +18 -1
- package/dist/retry-queue.js.map +1 -1
- package/dist/session-ceremony.d.ts +6 -0
- package/dist/session-ceremony.d.ts.map +1 -1
- package/dist/session-ceremony.js +26 -0
- package/dist/session-ceremony.js.map +1 -1
- package/dist/session-content-handlers.d.ts +12 -0
- package/dist/session-content-handlers.d.ts.map +1 -1
- package/dist/session-content-handlers.js +39 -4
- package/dist/session-content-handlers.js.map +1 -1
- package/dist/session-node-manager.d.ts +247 -4
- package/dist/session-node-manager.d.ts.map +1 -1
- package/dist/session-node-manager.js +3088 -304
- package/dist/session-node-manager.js.map +1 -1
- package/dist/session-read-handlers.d.ts.map +1 -1
- package/dist/session-read-handlers.js +16 -1
- package/dist/session-read-handlers.js.map +1 -1
- package/dist/session-relay-client.d.ts +116 -0
- package/dist/session-relay-client.d.ts.map +1 -1
- package/dist/session-relay-client.js +395 -6
- package/dist/session-relay-client.js.map +1 -1
- package/dist/session-salt-agreement.d.ts +58 -4
- package/dist/session-salt-agreement.d.ts.map +1 -1
- package/dist/session-salt-agreement.js +110 -3
- package/dist/session-salt-agreement.js.map +1 -1
- package/dist/signaling-connect.d.ts +18 -1
- package/dist/signaling-connect.d.ts.map +1 -1
- package/dist/signaling-connect.js +164 -1
- package/dist/signaling-connect.js.map +1 -1
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/wire-content-hash.d.ts +15 -3
- package/dist/wire-content-hash.d.ts.map +1 -1
- package/dist/wire-content-hash.js +15 -3
- package/dist/wire-content-hash.js.map +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-settings-keys.d.ts","sourceRoot":"","sources":["../src/agent-settings-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"agent-settings-keys.d.ts","sourceRoot":"","sources":["../src/agent-settings-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,gGAAgG;AAChG,eAAO,MAAM,mBAAmB,qDAAqE,CAAC;AACtG,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE;;4DAE4D;AAC5D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAQtE;AAED,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,WAAW,CAAC;AAEtD,qDAAqD;AACrD,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CAEjF;AAED,gDAAgD;AAChD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAEjE;AAED,gGAAgG;AAChG,eAAO,MAAM,gBAAgB,iBAAiB,CAAC;AAgB/C;;0CAE0C;AAC1C,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,IAAI,MAAM,EAAE,CAEzC;AAED,4FAA4F;AAC5F,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAqC7G;AAED,yGAAyG;AACzG,eAAO,MAAM,oBAAoB,OAAO,CAAC"}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* refused before any reply). So the settable tiers are unknown / known / whitelisted / vip.
|
|
15
15
|
*/
|
|
16
16
|
import { TIER } from "./contacts-tier-migration.js";
|
|
17
|
+
import { RELAY_ONLY_KEY } from "./relay-only.js";
|
|
17
18
|
/** The tiers whose bounds and away texts are settable (BLOCKED is fixed, never overridable). */
|
|
18
19
|
export const SETTABLE_TIER_NAMES = Object.freeze(["unknown", "known", "whitelisted", "vip"]);
|
|
19
20
|
/** The tier NAME for a tier integer, or null for an unknown/unsettable value (e.g. BLOCKED=0).
|
|
@@ -42,6 +43,9 @@ const BOUND_FIELDS = Object.freeze(["max_sessions", "max_bytes"]);
|
|
|
42
43
|
/** Every valid setting key, precomputed. The handler validates a `set` against this exact set. */
|
|
43
44
|
const VALID_KEYS = new Set([
|
|
44
45
|
AWAY_DEFAULT_KEY,
|
|
46
|
+
// DOD-M15-RELAYONLY-1: relay-only routing. A BOOLEAN key, and the first one here — see
|
|
47
|
+
// `validateSettingValue`, where it needs its own branch or the away-text fallback swallows it.
|
|
48
|
+
RELAY_ONLY_KEY,
|
|
45
49
|
...SETTABLE_TIER_NAMES.flatMap((t) => [
|
|
46
50
|
...BOUND_FIELDS.map((f) => boundSettingKey(t, f)),
|
|
47
51
|
awayTierSettingKey(t),
|
|
@@ -79,6 +83,20 @@ export function validateSettingValue(key, value) {
|
|
|
79
83
|
}
|
|
80
84
|
return { ok: true };
|
|
81
85
|
}
|
|
86
|
+
// DOD-M15-RELAYONLY-1: a BOOLEAN key, and it must be caught BEFORE the away-text fallback below.
|
|
87
|
+
//
|
|
88
|
+
// ⚠️ THE FALLBACK IS THE HAZARD, not an edge case. Everything that is not a bound key falls
|
|
89
|
+
// through to away-text validation, which accepts any non-empty string under 2048 characters. So
|
|
90
|
+
// without this branch `transport.relay_only = "yes"` — or `"flase"` — would STORE successfully and
|
|
91
|
+
// then read as not-"true" forever: the operator sets the privacy control, is told it was saved,
|
|
92
|
+
// and has no protection. `isRelayOnly` deliberately treats anything but "true" as OFF, which is
|
|
93
|
+
// only safe because a bad value cannot get past here to be misread later.
|
|
94
|
+
if (key === RELAY_ONLY_KEY) {
|
|
95
|
+
if (value !== "true" && value !== "false") {
|
|
96
|
+
return { ok: false, reason: `${RELAY_ONLY_KEY} must be exactly "true" or "false"` };
|
|
97
|
+
}
|
|
98
|
+
return { ok: true };
|
|
99
|
+
}
|
|
82
100
|
// Away-text (review F2/F3): an EMPTY / whitespace-only away text is refused — to CLEAR, use null
|
|
83
101
|
// (cello_contact_set_away) or omit the key; storing "" would silently blank every away reply,
|
|
84
102
|
// including the minimal stranger disclosure. Bounded to a sane length (an answering-machine line,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-settings-keys.js","sourceRoot":"","sources":["../src/agent-settings-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-settings-keys.js","sourceRoot":"","sources":["../src/agent-settings-keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consortium-bootstrap.d.ts","sourceRoot":"","sources":["../src/consortium-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,KAAK,EACV,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,2BAA2B,CAAC;AAInC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"consortium-bootstrap.d.ts","sourceRoot":"","sources":["../src/consortium-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,KAAK,EACV,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,2BAA2B,CAAC;AAInC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,OAAO,EAGL,KAAK,kBAAkB,EAEvB,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,qBAAqB,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,qFAAqF;IACrF,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,gBAAgB,EAAE,OAAO,CAAC;IAC1B,+EAA+E;IAC/E,uBAAuB,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,mBAAmB,EAAE,kBAAkB,EAAE,CAAC;IAC1C;;;;;;;;OAQG;IACH,gBAAgB,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC5C;;;;;;;;;;;;;OAaG;IACH,eAAe,EAAE,kBAAkB,EAAE,CAAC;IACtC;;;;;;;OAOG;IACH,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAkI/F;AAED,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,qBAAqB,CAAC;IAC5C,qBAAqB,CAAC,EAAE,sBAAsB,CAAC;IAC/C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yBAAyB,CAAC,EAAE,MAAM,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACvD,kFAAkF;IAClF,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1C;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,uBAAuB,EAAE,MAAM,OAAO,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC,CAAC;IACpE;;;;;OAKG;IACH,wBAAwB,EAAE,CAAC,MAAM,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;IAChF;;;;;;;OAOG;IACH,kBAAkB,EAAE,MAAM,kBAAkB,EAAE,CAAC;IAC/C,gGAAgG;IAChG,oBAAoB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAC1C,2FAA2F;IAC3F,oBAAoB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAC1C,8EAA8E;IAC9E,mBAAmB,EAAE,MAAM,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAC7D,qFAAqF;IACrF,oBAAoB,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CAChD;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,qBAAqB,GAAG,iBAAiB,CAyNtF"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { startHttpManifestPoll } from "./http-manifest-poll.js";
|
|
3
|
+
import { classifyManifestValidity } from "./manifest-validity.js";
|
|
3
4
|
import { resolveDirectoryUrl, manifestNodesToEndpoints, FAST_PROBE, createRosterAwareEndpointResolver, } from "./directory-bootstrap.js";
|
|
4
5
|
/**
|
|
5
6
|
* Load + verify the manifest, then resolve its node set to live endpoints.
|
|
@@ -20,17 +21,52 @@ export async function verifyStartupManifest(deps) {
|
|
|
20
21
|
}
|
|
21
22
|
try {
|
|
22
23
|
const manifest = await manifestProvider.loadAndVerify(manifestRootKeys, manifestThreshold);
|
|
24
|
+
/**
|
|
25
|
+
* DOD-M15-EXPIRY-CONSUMER-POLICY-1 — THIS GATE HAD THE NaN HOLE ITS OWN CLASSIFIER WAS WRITTEN
|
|
26
|
+
* TO CLOSE, and the whole line's premise rested on it.
|
|
27
|
+
*
|
|
28
|
+
* It was `new Date(manifest.expires)` compared with `<=`. `new Date("nonsense")` is Invalid
|
|
29
|
+
* Date, and **every comparison against NaN is false** — so a manifest with an unparseable
|
|
30
|
+
* `expires` passed BOTH checks, set `manifestVerified = true`, and started the daemon on an
|
|
31
|
+
* artefact nobody can date. `manifest-validity.ts` says exactly this about exactly this code —
|
|
32
|
+
* *"the startup check's own shape waves a garbage timestamp through as though it were
|
|
33
|
+
* in-window"* — and fixed it for the RUNTIME classifier while leaving the startup gate as it
|
|
34
|
+
* found it. `signal-submission.ts` and `preauth-capability.ts` both get it right; this was the
|
|
35
|
+
* odd one out.
|
|
36
|
+
*
|
|
37
|
+
* **It also falsified the argument the rest of this line rests on.** Everything else here reasons
|
|
38
|
+
* that a lapsed manifest exists only inside a LONG-RUNNING daemon, so refusing would strand a
|
|
39
|
+
* live operator. For the unparseable case that was untrue: such a daemon starts FRESH into the
|
|
40
|
+
* lapsed-equivalent state and stays there permanently — while both new events tell the operator
|
|
41
|
+
* *"do not restart, it will not come back."* It comes back cleanly, forever, on the same broken
|
|
42
|
+
* file. Wrong advice, in the one case where refusing costs nothing.
|
|
43
|
+
*
|
|
44
|
+
* Now one policy object for the startup gate and the runtime surface, which is what this DoD
|
|
45
|
+
* line is about. Refuses anything that is not affirmatively in-window.
|
|
46
|
+
*/
|
|
47
|
+
const validity = classifyManifestValidity(manifest, Date.now());
|
|
48
|
+
if (validity.state === "unreadable_window" || (validity.state === "expired" && !Number.isFinite(Date.parse(manifest.expires)))) {
|
|
49
|
+
logger.error("directory.auth.manifest.unreadable.window", {
|
|
50
|
+
manifestVersion: manifest.version,
|
|
51
|
+
notBefore: manifest.not_before,
|
|
52
|
+
expires: manifest.expires,
|
|
53
|
+
detail: "a validity-window field does not parse — the artefact is malformed, not merely stale. " +
|
|
54
|
+
"A hand-edited file or a broken generator is the usual cause. Refusing rather than treating " +
|
|
55
|
+
"an undateable manifest as in-window.",
|
|
56
|
+
});
|
|
57
|
+
return { manifestVerified, verifiedManifestVersion, consortiumEndpoints, verifiedManifest, unresolvedNodes, unresolvedSweptAt };
|
|
58
|
+
}
|
|
23
59
|
const now = new Date();
|
|
24
60
|
const notBefore = new Date(manifest.not_before);
|
|
25
61
|
const expiresAt = new Date(manifest.expires);
|
|
26
|
-
if (now < notBefore) {
|
|
62
|
+
if (validity.state === "not_yet_valid" || now < notBefore) {
|
|
27
63
|
logger.error("directory.auth.manifest.not.yet.valid", {
|
|
28
64
|
manifestVersion: manifest.version,
|
|
29
65
|
notBefore: manifest.not_before,
|
|
30
66
|
});
|
|
31
67
|
return { manifestVerified, verifiedManifestVersion, consortiumEndpoints, verifiedManifest, unresolvedNodes, unresolvedSweptAt };
|
|
32
68
|
}
|
|
33
|
-
if (expiresAt <= now) {
|
|
69
|
+
if (validity.state === "expired" || expiresAt <= now) {
|
|
34
70
|
logger.error("directory.auth.manifest.expired", {
|
|
35
71
|
manifestVersion: manifest.version,
|
|
36
72
|
expiresAt: manifest.expires,
|
|
@@ -181,11 +217,60 @@ export function createConsortiumRouting(deps) {
|
|
|
181
217
|
// DECLARED membership, straight off the verified manifest — no probe. Lets the resolver reject a
|
|
182
218
|
// primary that resolves but belongs to a different consortium (the compiled-in default URL after
|
|
183
219
|
// a consortium move) without mistaking a momentarily-down member for a non-member.
|
|
220
|
+
/**
|
|
221
|
+
* DOD-M15-EXPIRY-CONSUMER-POLICY-1 — THE FOURTH CONSUMER, missed by the line's own enumeration and
|
|
222
|
+
* found by its review. The line named three; this is where the residual risk actually lives.
|
|
223
|
+
*
|
|
224
|
+
* This is the consortium MEMBERSHIP set: it lets the resolver reject a directory endpoint that
|
|
225
|
+
* resolves but belongs to a different consortium. Read from a lapsed manifest, a node REMOVED
|
|
226
|
+
* since the lapse is still a member here — so it can still be accepted as the endpoint this daemon
|
|
227
|
+
* talks to, which is the seat that coordinates a ceremony and declares the participant count.
|
|
228
|
+
*
|
|
229
|
+
* **Same verdict as the other two permitting consumers, for the same reason.** Refusing means the
|
|
230
|
+
* resolver can accept no endpoint at all, which takes a running daemon offline for a manifest that
|
|
231
|
+
* was valid when it started — the identical bricking cost, and this one is reached inside the 10 s
|
|
232
|
+
* signaling wait, so it fails fast and silently.
|
|
233
|
+
*
|
|
234
|
+
* **Reported once per manifest version.** This runs per resolution attempt, not per challenge, so
|
|
235
|
+
* a version key is the right granularity — unlike the challenge verifier, where a per-node key was
|
|
236
|
+
* needed because `nodeId` is in the payload.
|
|
237
|
+
*/
|
|
238
|
+
let lapsedMembershipReportedFor = null;
|
|
184
239
|
const getManifestPeerIds = () => {
|
|
185
240
|
const m = manifestProvider?.getCurrentManifest();
|
|
186
241
|
if (!m)
|
|
187
242
|
return null;
|
|
188
243
|
const ids = m.nodes.map((n) => n.peerId).filter((p) => typeof p === "string" && p.length > 0);
|
|
244
|
+
/**
|
|
245
|
+
* ⚠️ REPORT ONLY IF A MEMBERSHIP SET IS ACTUALLY PRODUCED — pass 2, and this is the over-claim
|
|
246
|
+
* class that the register-handler rewording had just fixed, reintroduced by me in the consumer
|
|
247
|
+
* that review asked for.
|
|
248
|
+
*
|
|
249
|
+
* The first version reported BEFORE this filter. `ids.length === 0` returns `null`, and the
|
|
250
|
+
* caller treats `null` as **skip the membership check entirely** — so the event announced that
|
|
251
|
+
* "the set deciding which endpoints this daemon will accept came from a lapsed manifest" when no
|
|
252
|
+
* set was produced and nothing was decided. Not an edge case: `peerId` is OPTIONAL, and
|
|
253
|
+
* manifests written before the field existed carry none — for those the claim is ALWAYS false,
|
|
254
|
+
* and the once-per-version budget is spent saying it.
|
|
255
|
+
*
|
|
256
|
+
* `members` is the FILTERED count for the same reason: the member set is what survives the
|
|
257
|
+
* filter, not how many nodes the manifest lists.
|
|
258
|
+
*/
|
|
259
|
+
const validity = classifyManifestValidity(m, Date.now());
|
|
260
|
+
if (ids.length > 0 && validity.state !== "valid" && validity.state !== "expiring_soon" && lapsedMembershipReportedFor !== m.version) {
|
|
261
|
+
lapsedMembershipReportedFor = m.version;
|
|
262
|
+
logger.warn("directory.membership.manifest.lapsed", {
|
|
263
|
+
manifestVersion: m.version,
|
|
264
|
+
state: validity.state,
|
|
265
|
+
members: ids.length,
|
|
266
|
+
impact: "the set deciding WHICH directory endpoints this daemon will accept came from a manifest " +
|
|
267
|
+
"outside its validity window. A node removed from the consortium since then is still a " +
|
|
268
|
+
"member by this reckoning, so it can still be accepted as the directory this daemon talks " +
|
|
269
|
+
"to — the seat that coordinates a ceremony and declares the participant count.",
|
|
270
|
+
guidance: "Endpoint selection was NOT blocked — refusing here accepts no directory at all and takes " +
|
|
271
|
+
"a running daemon offline. cello_status reports the window and where the manifest came from.",
|
|
272
|
+
});
|
|
273
|
+
}
|
|
189
274
|
return ids.length > 0 ? new Set(ids) : null;
|
|
190
275
|
};
|
|
191
276
|
const failoverEndpointResolver = directoryEndpointResolver
|
|
@@ -206,6 +291,36 @@ export function createConsortiumRouting(deps) {
|
|
|
206
291
|
// could not). Off on the M6 back-compat path (no scheduler), and off without real root keys: a
|
|
207
292
|
// poll that verifies against an empty key set verifies against nothing.
|
|
208
293
|
let stopHttpManifestPoll;
|
|
294
|
+
/**
|
|
295
|
+
* DOD-M15-DIRAUTH-1 (Andre's quick win #3) — **AN EMPTY KEY SET MUST NOT DISABLE THE POLL IN
|
|
296
|
+
* SILENCE.**
|
|
297
|
+
*
|
|
298
|
+
* The condition below is correct and stays correct: a poll that verifies against no keys verifies
|
|
299
|
+
* against nothing, so it must not run. What was wrong is what happened when that triggered —
|
|
300
|
+
* nothing at all. The daemon started, looked healthy, and simply never adopted a new manifest
|
|
301
|
+
* again, which is the failure mode you discover months later when a rotated directory key is not
|
|
302
|
+
* picked up.
|
|
303
|
+
*
|
|
304
|
+
* ⚠️ THE DISTINCTION THAT MAKES THIS SAFE, and the reason it is not a blanket throw: **"no
|
|
305
|
+
* scheduler" is a legitimate configuration** — the M6 back-compat path deliberately runs without
|
|
306
|
+
* one, and failing startup there would brick a supported setup. **"Scheduler and provider are
|
|
307
|
+
* wired, but the keys are empty" is a MISCONFIGURATION** — someone intended verification and
|
|
308
|
+
* supplied nothing to verify with. Only the second refuses.
|
|
309
|
+
*/
|
|
310
|
+
if (manifestPollScheduler && manifestProvider) {
|
|
311
|
+
const keyCount = manifestRootKeys?.length ?? 0;
|
|
312
|
+
if (keyCount === 0 || !manifestThreshold || manifestThreshold < 1) {
|
|
313
|
+
const detail = `rootKeys=${String(keyCount)} threshold=${String(manifestThreshold ?? 0)}`;
|
|
314
|
+
logger.error("directory.manifest.poll.misconfigured", {
|
|
315
|
+
rootKeyCount: keyCount,
|
|
316
|
+
threshold: manifestThreshold ?? 0,
|
|
317
|
+
impact: "the manifest poll is wired but has no key set to verify against, so it would adopt " +
|
|
318
|
+
"manifests unverified or never adopt one at all — refusing at startup instead of running " +
|
|
319
|
+
"with directory-key rotation silently dead",
|
|
320
|
+
});
|
|
321
|
+
throw new Error(`directory_manifest_poll_misconfigured: ${detail}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
209
324
|
if (manifestPollScheduler && manifestProvider && manifestRootKeys && manifestRootKeys.length > 0 && manifestThreshold && manifestThreshold >= 1) {
|
|
210
325
|
stopHttpManifestPoll = startHttpManifestPoll({
|
|
211
326
|
scheduler: manifestPollScheduler,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consortium-bootstrap.js","sourceRoot":"","sources":["../src/consortium-bootstrap.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EAAE,UAAU,EAEpC,iCAAiC,GAElC,MAAM,0BAA0B,CAAC;AA2DlC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,IAAsB;IAChE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAE9G,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,IAAI,uBAAuB,GAAG,CAAC,CAAC;IAChC,IAAI,mBAAmB,GAAyB,EAAE,CAAC;IACnD,IAAI,gBAAgB,GAA8B,IAAI,CAAC;IACvD,MAAM,eAAe,GAAyB,EAAE,CAAC;IACjD,IAAI,iBAAiB,GAAkB,IAAI,CAAC;IAE5C,IAAI,CAAC,gBAAgB,IAAI,CAAC,gBAAgB,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;QAC9E,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC;IAClI,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,aAAa,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC;QAE3F,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAChD,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAE7C,IAAI,GAAG,GAAG,SAAS,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"consortium-bootstrap.js","sourceRoot":"","sources":["../src/consortium-bootstrap.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EAAE,UAAU,EAEpC,iCAAiC,GAElC,MAAM,0BAA0B,CAAC;AA2DlC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,IAAsB;IAChE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAE9G,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,IAAI,uBAAuB,GAAG,CAAC,CAAC;IAChC,IAAI,mBAAmB,GAAyB,EAAE,CAAC;IACnD,IAAI,gBAAgB,GAA8B,IAAI,CAAC;IACvD,MAAM,eAAe,GAAyB,EAAE,CAAC;IACjD,IAAI,iBAAiB,GAAkB,IAAI,CAAC;IAE5C,IAAI,CAAC,gBAAgB,IAAI,CAAC,gBAAgB,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;QAC9E,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC;IAClI,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,aAAa,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC;QAE3F;;;;;;;;;;;;;;;;;;;;;;WAsBG;QACH,MAAM,QAAQ,GAAG,wBAAwB,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAChE,IAAI,QAAQ,CAAC,KAAK,KAAK,mBAAmB,IAAI,CAAC,QAAQ,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/H,MAAM,CAAC,KAAK,CAAC,2CAA2C,EAAE;gBACxD,eAAe,EAAE,QAAQ,CAAC,OAAO;gBACjC,SAAS,EAAE,QAAQ,CAAC,UAAU;gBAC9B,OAAO,EAAE,QAAQ,CAAC,OAAO;gBACzB,MAAM,EAAE,wFAAwF;oBAC9F,6FAA6F;oBAC7F,sCAAsC;aACzC,CAAC,CAAC;YACH,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC;QAClI,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAChD,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAE7C,IAAI,QAAQ,CAAC,KAAK,KAAK,eAAe,IAAI,GAAG,GAAG,SAAS,EAAE,CAAC;YAC1D,MAAM,CAAC,KAAK,CAAC,uCAAuC,EAAE;gBACpD,eAAe,EAAE,QAAQ,CAAC,OAAO;gBACjC,SAAS,EAAE,QAAQ,CAAC,UAAU;aAC/B,CAAC,CAAC;YACH,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC;QAClI,CAAC;QACD,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC;YACrD,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE;gBAC9C,eAAe,EAAE,QAAQ,CAAC,OAAO;gBACjC,SAAS,EAAE,QAAQ,CAAC,OAAO;aAC5B,CAAC,CAAC;YACH,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC;QAClI,CAAC;QAED,+FAA+F;QAC/F,uCAAuC;QACvC,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,kBAAkB,EAAE,CAAC;QACjE,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,OAAO,GAAG,QAAQ,EAAE,CAAC;YACrD,MAAM,CAAC,KAAK,CAAC,0CAA0C,EAAE;gBACvD,eAAe,EAAE,QAAQ,CAAC,OAAO;gBACjC,eAAe,EAAE,QAAQ;aAC1B,CAAC,CAAC;YACH,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC;QAClI,CAAC;QAED,MAAM,oBAAoB,CAAC,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC5D,gBAAgB,GAAG,IAAI,CAAC;QACxB,uBAAuB,GAAG,QAAQ,CAAC,OAAO,CAAC;QAC3C,+FAA+F;QAC/F,yBAAyB;QACzB,gBAAgB,GAAG,QAAQ,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,kCAAkC,EAAE;YAC9C,eAAe,EAAE,QAAQ,CAAC,OAAO;YACjC,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,MAAM;SACxC,CAAC,CAAC;QAEH,4FAA4F;QAC5F,0FAA0F;QAC1F,4FAA4F;QAC5F,yFAAyF;QACzF,mBAAmB,GAAG,MAAM,wBAAwB,CAAC,QAAQ,CAAC,KAAK,EAAE;YACnE,MAAM;YACN,OAAO;YACP,oFAAoF;YACpF,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;SACjD,CAAC,CAAC;QACH,iBAAiB,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC7C,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;QAC5C,MAAM,aAAa,GAAG,mBAAmB,CAAC,MAAM,CAAC;QACjD,4FAA4F;QAC5F,6FAA6F;QAC7F,MAAM,aAAa,GAAG;YACpB,eAAe,EAAE,QAAQ,CAAC,OAAO;YACjC,aAAa;YACb,aAAa;YACb,KAAK,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;SAChF,CAAC;QACF,qFAAqF;QACrF,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,KAAK,CAAC,2BAA2B,EAAE,aAAa,CAAC,CAAC;QAC3D,CAAC;aAAM,IAAI,aAAa,GAAG,aAAa,EAAE,CAAC;YACzC,MAAM,CAAC,IAAI,CAAC,8BAA8B,EAAE,aAAa,CAAC,CAAC;QAC7D,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,+BAA+B,EAAE,aAAa,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,CAAC,KAAK,CAAC,qCAAqC,EAAE;YAClD,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC;AAClI,CAAC;AAuDD,MAAM,UAAU,uBAAuB,CAAC,IAA2B;IACjE,MAAM,EACJ,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,oBAAoB,EAC3E,qBAAqB,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,EAAE,OAAO,GACpF,GAAG,IAAI,CAAC;IAET,gGAAgG;IAChG,kGAAkG;IAClG,sFAAsF;IACtF,EAAE;IACF,gGAAgG;IAChG,+FAA+F;IAC/F,8FAA8F;IAC9F,8FAA8F;IAC9F,IAAI,eAAe,GAAyB,CAAC,GAAG,CAAC,IAAI,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC,CAAC;IACrF,IAAI,iBAAiB,GAAkB,IAAI,CAAC,wBAAwB,IAAI,IAAI,CAAC;IAC7E,MAAM,kBAAkB,GAAG,GAAyB,EAAE,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC;IAC5E,MAAM,oBAAoB,GAAG,GAAkB,EAAE,CAAC,iBAAiB,CAAC;IAEpE;;;OAGG;IACH,IAAI,qBAAqB,GAAG,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE1G,MAAM,uBAAuB,GAAG,KAAK,EAAE,MAAoB,EAAwC,EAAE;QACnG,MAAM,CAAC,GAAG,gBAAgB,EAAE,kBAAkB,EAAE,CAAC;QACjD,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,4FAA4F;YAC5F,6FAA6F;YAC7F,2FAA2F;YAC3F,MAAM,CAAC,IAAI,CAAC,oCAAoC,EAAE;gBAChD,MAAM,EACJ,2FAA2F;oBAC3F,wDAAwD;aAC3D,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QACD;;;;;;;;;;;;WAYG;QACH,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAyB,EAAE,CAAC;QAC1C,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,CAAC,CAAC,KAAK,EAAE;YACxD,MAAM;YACN,OAAO;YACP,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;YACzC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3C,CAAC,CAAC;QACH,IAAI,WAAW,IAAI,qBAAqB,EAAE,CAAC;YACzC,eAAe,GAAG,QAAQ,CAAC;YAC3B,iBAAiB,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC;YACxD,qBAAqB,GAAG,WAAW,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,2FAA2F;YAC3F,iEAAiE;YACjE,MAAM,CAAC,IAAI,CAAC,mCAAmC,EAAE;gBAC/C,SAAS,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE;gBAC9C,oBAAoB,EAAE,IAAI,IAAI,CAAC,qBAAqB,CAAC,CAAC,WAAW,EAAE;gBACnE,MAAM,EAAE,uGAAuG;aAChH,CAAC,CAAC;QACL,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;IAEF;;;;;;;;;;;;OAYG;IACH,MAAM,oBAAoB,GAAG,GAAkB,EAAE,CAAC,gBAAgB,EAAE,kBAAkB,EAAE,EAAE,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC;IAE/G,iGAAiG;IACjG,iGAAiG;IACjG,mFAAmF;IACnF;;;;;;;;;;;;;;;;;OAiBG;IACH,IAAI,2BAA2B,GAAkB,IAAI,CAAC;IACtD,MAAM,kBAAkB,GAAG,GAAuB,EAAE;QAClD,MAAM,CAAC,GAAG,gBAAgB,EAAE,kBAAkB,EAAE,CAAC;QACjD,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACpB,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC3G;;;;;;;;;;;;;;WAcG;QACH,MAAM,QAAQ,GAAG,wBAAwB,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACzD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,KAAK,OAAO,IAAI,QAAQ,CAAC,KAAK,KAAK,eAAe,IAAI,2BAA2B,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;YACpI,2BAA2B,GAAG,CAAC,CAAC,OAAO,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,sCAAsC,EAAE;gBAClD,eAAe,EAAE,CAAC,CAAC,OAAO;gBAC1B,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,OAAO,EAAE,GAAG,CAAC,MAAM;gBACnB,MAAM,EACJ,0FAA0F;oBAC1F,wFAAwF;oBACxF,2FAA2F;oBAC3F,+EAA+E;gBACjF,QAAQ,EACN,2FAA2F;oBAC3F,6FAA6F;aAChG,CAAC,CAAC;QACL,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,CAAC,CAAC;IAEF,MAAM,wBAAwB,GAAG,yBAAyB;QACxD,CAAC,CAAC,iCAAiC,CAAC;YAChC,eAAe,EAAE,yBAAyB;YAC1C,yFAAyF;YACzF,mFAAmF;YACnF,uFAAuF;YACvF,wFAAwF;YACxF,mBAAmB,EAAE,GAAG,EAAE,CAAC,uBAAuB,CAAC,UAAU,CAAC;YAC9D,kBAAkB;YAClB,MAAM;SACP,CAAC;QACJ,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,mBAAmB,GAAG,KAAK,IAAuC,EAAE,CACxE,wBAAwB,CAAC,CAAC,CAAC,MAAM,wBAAwB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAErE,8FAA8F;IAC9F,iGAAiG;IACjG,+FAA+F;IAC/F,wEAAwE;IACxE,IAAI,oBAA8C,CAAC;IACnD;;;;;;;;;;;;;;;OAeG;IACH,IAAI,qBAAqB,IAAI,gBAAgB,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAG,gBAAgB,EAAE,MAAM,IAAI,CAAC,CAAC;QAC/C,IAAI,QAAQ,KAAK,CAAC,IAAI,CAAC,iBAAiB,IAAI,iBAAiB,GAAG,CAAC,EAAE,CAAC;YAClE,MAAM,MAAM,GAAG,YAAY,MAAM,CAAC,QAAQ,CAAC,cAAc,MAAM,CAAC,iBAAiB,IAAI,CAAC,CAAC,EAAE,CAAC;YAC1F,MAAM,CAAC,KAAK,CAAC,uCAAuC,EAAE;gBACpD,YAAY,EAAE,QAAQ;gBACtB,SAAS,EAAE,iBAAiB,IAAI,CAAC;gBACjC,MAAM,EACJ,qFAAqF;oBACrF,0FAA0F;oBAC1F,2CAA2C;aAC9C,CAAC,CAAC;YACH,MAAM,IAAI,KAAK,CAAC,0CAA0C,MAAM,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IACD,IAAI,qBAAqB,IAAI,gBAAgB,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,IAAI,iBAAiB,IAAI,iBAAiB,IAAI,CAAC,EAAE,CAAC;QAChJ,oBAAoB,GAAG,qBAAqB,CAAC;YAC3C,SAAS,EAAE,qBAAqB;YAChC,YAAY,EAAE,gBAAgB,IAAI,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC;YAClE,gBAAgB;YAChB,oBAAoB;YACpB,QAAQ,EAAE,gBAAgB;YAC1B,SAAS,EAAE,iBAAiB;YAC5B,MAAM;YACN,iBAAiB,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;SACtC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,CAAC;AAC1K,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHY A SESSION HAS NO AGREED CONTENT KEY — `DOD-M15-EPHEMERAL-AUTH-1` (007-CRYPTO).
|
|
3
|
+
*
|
|
4
|
+
* ─── The rule, and it is deliberately absolute ─────────────────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* **A live message body is encrypted under the agreed session key, or it is not sent.** There is no
|
|
7
|
+
* degraded mode, no "unencrypted but visibly so", and no negotiation.
|
|
8
|
+
*
|
|
9
|
+
* That is not strictness for its own sake — it is what removes an entire class of defect. A
|
|
10
|
+
* fallback to plaintext is a thing an attacker steers a session into: strip the key frame, and a
|
|
11
|
+
* system that "carries on, visibly degraded" hands over exactly the plaintext the attacker wanted,
|
|
12
|
+
* while the operator sees a warning they have learned to scroll past. The salt can degrade because
|
|
13
|
+
* a missing salt costs a correlation property; a missing KEY costs the message.
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ AND THERE IS NO COMPATIBILITY CASE TO SERVE. CELLO is pre-launch with no external installs, so
|
|
16
|
+
* "the counterparty is on a build that predates this" is not a state anything is in. Every reason
|
|
17
|
+
* below is a FAULT — local, transient, or a counterparty that did not complete an exchange it is
|
|
18
|
+
* running the code for. None of them is an accepted steady state, and none of them may be described
|
|
19
|
+
* to an operator as one.
|
|
20
|
+
*
|
|
21
|
+
* ─── Not the same question as the salt ─────────────────────────────────────────────────────────
|
|
22
|
+
*
|
|
23
|
+
* `content_hashes_salted` is about a relay CONFIRMING a guess at a stored hash. This is about a
|
|
24
|
+
* relay READING the message. A session can be salted and unencrypted; it cannot send while
|
|
25
|
+
* unencrypted.
|
|
26
|
+
*
|
|
27
|
+
* ─── Why a closed set and a total map ──────────────────────────────────────────────────────────
|
|
28
|
+
*
|
|
29
|
+
* Copied from `refusal-reasons.ts`, which exists because a free-form `reason: string` let a new code
|
|
30
|
+
* slip past every test in its own guard file. A `Record` over the union means a reason cannot be
|
|
31
|
+
* added without something for the reader to do about it.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* The `content_encryption` marker on a `content_frame`, naming the scheme its body is under.
|
|
35
|
+
*
|
|
36
|
+
* On the WIRE rather than inferred, so a receiver never has to guess a layout from a length — and
|
|
37
|
+
* ABSENT is refused rather than read as plaintext. There is no unencrypted sender to accommodate, so
|
|
38
|
+
* a missing marker is not "an old peer", it is a frame something rewrote.
|
|
39
|
+
*/
|
|
40
|
+
export declare const SESSION_CONTENT_ENCRYPTION_V1 = "session-aes-256-gcm-v1";
|
|
41
|
+
export declare const CONTENT_ENCRYPTION_REASONS: {
|
|
42
|
+
/**
|
|
43
|
+
* The exchange has not finished yet. Transient, and the ordinary state for the instant between a
|
|
44
|
+
* session opening and its first connect completing.
|
|
45
|
+
*/
|
|
46
|
+
readonly NOT_YET_AGREED: "not_yet_agreed";
|
|
47
|
+
/**
|
|
48
|
+
* THIS machine has no identity key to sign its half with, so it cannot take part at all.
|
|
49
|
+
*
|
|
50
|
+
* Local setup fault — a signing-only or threshold provider, or an agent loaded without one. Named
|
|
51
|
+
* apart from the peer cases because "we could not sign" and "they did not answer" send the
|
|
52
|
+
* operator to opposite machines.
|
|
53
|
+
*/
|
|
54
|
+
readonly NO_LOCAL_IDENTITY: "no_local_identity";
|
|
55
|
+
/** THIS side's half never left the machine. Local and transient; the next connect re-announces. */
|
|
56
|
+
readonly OUR_ANNOUNCE_FAILED: "our_announce_failed";
|
|
57
|
+
/**
|
|
58
|
+
* TERMINAL. The peer's key could not be tied to them and the session was stopped.
|
|
59
|
+
*
|
|
60
|
+
* ⚠️ THIS MUST SURVIVE THE TEARDOWN THAT FOLLOWS IT — review F2. The freeze destroys the session's
|
|
61
|
+
* key material, and clearing the reason with it left the listing recomputing `NOT_YET_AGREED`, so
|
|
62
|
+
* the one detection in this unit that means *someone may be substituting keys on your connection*
|
|
63
|
+
* reached the agent as "still agreeing, please wait". A security refusal that reads as a
|
|
64
|
+
* reassurance is worse than silence.
|
|
65
|
+
*/
|
|
66
|
+
readonly KEY_REFUSED: "key_refused";
|
|
67
|
+
/**
|
|
68
|
+
* The counterparty never sent their half.
|
|
69
|
+
*
|
|
70
|
+
* NOT "they are on an old build" — they are running this code. Something between the two of you
|
|
71
|
+
* dropped the frame, or their daemon is not answering.
|
|
72
|
+
*/
|
|
73
|
+
readonly PEER_SILENT: "peer_silent";
|
|
74
|
+
};
|
|
75
|
+
export type ContentEncryptionReason = (typeof CONTENT_ENCRYPTION_REASONS)[keyof typeof CONTENT_ENCRYPTION_REASONS];
|
|
76
|
+
/**
|
|
77
|
+
* What the operator should DO. TOTAL over the union by construction.
|
|
78
|
+
*
|
|
79
|
+
* ⚠️ EVERY ENTRY NAMES A VERB THE READER CAN PERFORM, and none of them says "this is expected" —
|
|
80
|
+
* because none of these is. An affordance that resolves to nothing is worse than none, and a
|
|
81
|
+
* reassurance attached to a fault is worse than both.
|
|
82
|
+
*/
|
|
83
|
+
export declare const CONTENT_ENCRYPTION_GUIDANCE: Record<ContentEncryptionReason, string>;
|
|
84
|
+
/**
|
|
85
|
+
* Render a reason for an agent.
|
|
86
|
+
*
|
|
87
|
+
* ⚠️ NO UNKNOWN-REASON FALLBACK, deliberately. The value is produced and consumed in one process
|
|
88
|
+
* from the closed set above — there is no column it is read back from and no other build writing
|
|
89
|
+
* one, so a "reason this version does not recognise" is a state nothing can be in. An earlier cut
|
|
90
|
+
* carried that branch anyway and described the value as coming off a database row, which was simply
|
|
91
|
+
* untrue. Unreachable defensive code that states a false provenance is worse than no code: it reads
|
|
92
|
+
* as a considered case and it is scaffolding for a world that does not exist.
|
|
93
|
+
*
|
|
94
|
+
* The map is TOTAL over the union, so the type is the check.
|
|
95
|
+
*/
|
|
96
|
+
export declare function contentEncryptionGuidanceFor(reason: ContentEncryptionReason): string;
|
|
97
|
+
//# sourceMappingURL=content-encryption-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-encryption-status.d.ts","sourceRoot":"","sources":["../src/content-encryption-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,2BAA2B,CAAC;AAEtE,eAAO,MAAM,0BAA0B;IACrC;;;OAGG;;IAEH;;;;;;OAMG;;IAEH,mGAAmG;;IAEnG;;;;;;;;OAQG;;IAEH;;;;;OAKG;;CAEK,CAAC;AAEX,MAAM,MAAM,uBAAuB,GACjC,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,OAAO,0BAA0B,CAAC,CAAC;AAE/E;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,EAAE,MAAM,CAAC,uBAAuB,EAAE,MAAM,CA6B/E,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,uBAAuB,GAAG,MAAM,CAEpF"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHY A SESSION HAS NO AGREED CONTENT KEY — `DOD-M15-EPHEMERAL-AUTH-1` (007-CRYPTO).
|
|
3
|
+
*
|
|
4
|
+
* ─── The rule, and it is deliberately absolute ─────────────────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* **A live message body is encrypted under the agreed session key, or it is not sent.** There is no
|
|
7
|
+
* degraded mode, no "unencrypted but visibly so", and no negotiation.
|
|
8
|
+
*
|
|
9
|
+
* That is not strictness for its own sake — it is what removes an entire class of defect. A
|
|
10
|
+
* fallback to plaintext is a thing an attacker steers a session into: strip the key frame, and a
|
|
11
|
+
* system that "carries on, visibly degraded" hands over exactly the plaintext the attacker wanted,
|
|
12
|
+
* while the operator sees a warning they have learned to scroll past. The salt can degrade because
|
|
13
|
+
* a missing salt costs a correlation property; a missing KEY costs the message.
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ AND THERE IS NO COMPATIBILITY CASE TO SERVE. CELLO is pre-launch with no external installs, so
|
|
16
|
+
* "the counterparty is on a build that predates this" is not a state anything is in. Every reason
|
|
17
|
+
* below is a FAULT — local, transient, or a counterparty that did not complete an exchange it is
|
|
18
|
+
* running the code for. None of them is an accepted steady state, and none of them may be described
|
|
19
|
+
* to an operator as one.
|
|
20
|
+
*
|
|
21
|
+
* ─── Not the same question as the salt ─────────────────────────────────────────────────────────
|
|
22
|
+
*
|
|
23
|
+
* `content_hashes_salted` is about a relay CONFIRMING a guess at a stored hash. This is about a
|
|
24
|
+
* relay READING the message. A session can be salted and unencrypted; it cannot send while
|
|
25
|
+
* unencrypted.
|
|
26
|
+
*
|
|
27
|
+
* ─── Why a closed set and a total map ──────────────────────────────────────────────────────────
|
|
28
|
+
*
|
|
29
|
+
* Copied from `refusal-reasons.ts`, which exists because a free-form `reason: string` let a new code
|
|
30
|
+
* slip past every test in its own guard file. A `Record` over the union means a reason cannot be
|
|
31
|
+
* added without something for the reader to do about it.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* The `content_encryption` marker on a `content_frame`, naming the scheme its body is under.
|
|
35
|
+
*
|
|
36
|
+
* On the WIRE rather than inferred, so a receiver never has to guess a layout from a length — and
|
|
37
|
+
* ABSENT is refused rather than read as plaintext. There is no unencrypted sender to accommodate, so
|
|
38
|
+
* a missing marker is not "an old peer", it is a frame something rewrote.
|
|
39
|
+
*/
|
|
40
|
+
export const SESSION_CONTENT_ENCRYPTION_V1 = "session-aes-256-gcm-v1";
|
|
41
|
+
export const CONTENT_ENCRYPTION_REASONS = {
|
|
42
|
+
/**
|
|
43
|
+
* The exchange has not finished yet. Transient, and the ordinary state for the instant between a
|
|
44
|
+
* session opening and its first connect completing.
|
|
45
|
+
*/
|
|
46
|
+
NOT_YET_AGREED: "not_yet_agreed",
|
|
47
|
+
/**
|
|
48
|
+
* THIS machine has no identity key to sign its half with, so it cannot take part at all.
|
|
49
|
+
*
|
|
50
|
+
* Local setup fault — a signing-only or threshold provider, or an agent loaded without one. Named
|
|
51
|
+
* apart from the peer cases because "we could not sign" and "they did not answer" send the
|
|
52
|
+
* operator to opposite machines.
|
|
53
|
+
*/
|
|
54
|
+
NO_LOCAL_IDENTITY: "no_local_identity",
|
|
55
|
+
/** THIS side's half never left the machine. Local and transient; the next connect re-announces. */
|
|
56
|
+
OUR_ANNOUNCE_FAILED: "our_announce_failed",
|
|
57
|
+
/**
|
|
58
|
+
* TERMINAL. The peer's key could not be tied to them and the session was stopped.
|
|
59
|
+
*
|
|
60
|
+
* ⚠️ THIS MUST SURVIVE THE TEARDOWN THAT FOLLOWS IT — review F2. The freeze destroys the session's
|
|
61
|
+
* key material, and clearing the reason with it left the listing recomputing `NOT_YET_AGREED`, so
|
|
62
|
+
* the one detection in this unit that means *someone may be substituting keys on your connection*
|
|
63
|
+
* reached the agent as "still agreeing, please wait". A security refusal that reads as a
|
|
64
|
+
* reassurance is worse than silence.
|
|
65
|
+
*/
|
|
66
|
+
KEY_REFUSED: "key_refused",
|
|
67
|
+
/**
|
|
68
|
+
* The counterparty never sent their half.
|
|
69
|
+
*
|
|
70
|
+
* NOT "they are on an old build" — they are running this code. Something between the two of you
|
|
71
|
+
* dropped the frame, or their daemon is not answering.
|
|
72
|
+
*/
|
|
73
|
+
PEER_SILENT: "peer_silent",
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* What the operator should DO. TOTAL over the union by construction.
|
|
77
|
+
*
|
|
78
|
+
* ⚠️ EVERY ENTRY NAMES A VERB THE READER CAN PERFORM, and none of them says "this is expected" —
|
|
79
|
+
* because none of these is. An affordance that resolves to nothing is worse than none, and a
|
|
80
|
+
* reassurance attached to a fault is worse than both.
|
|
81
|
+
*/
|
|
82
|
+
export const CONTENT_ENCRYPTION_GUIDANCE = {
|
|
83
|
+
[CONTENT_ENCRYPTION_REASONS.NOT_YET_AGREED]: "This session has not finished agreeing its encryption key with your counterparty, which happens " +
|
|
84
|
+
"as soon as you are both connected. A message sent before it completes is NOT held and is NOT " +
|
|
85
|
+
"sent in the open: it goes to your counterparty's relay mailbox instead, encrypted to their " +
|
|
86
|
+
"long-term key, and they receive it when they next collect. It arrives — it just takes the slow " +
|
|
87
|
+
"route, and that copy does not have the forward secrecy the direct path gives you. If this " +
|
|
88
|
+
"persists, your counterparty is not reachable right now.",
|
|
89
|
+
[CONTENT_ENCRYPTION_REASONS.NO_LOCAL_IDENTITY]: "THIS machine has no identity key available for this agent, so it cannot sign its half of the " +
|
|
90
|
+
"session encryption key — and every session it opens has the same problem. Your counterparty did " +
|
|
91
|
+
"nothing and does not need to change anything. Check that this agent was loaded with its identity " +
|
|
92
|
+
"key, then start a new session.",
|
|
93
|
+
[CONTENT_ENCRYPTION_REASONS.OUR_ANNOUNCE_FAILED]: "THIS side could not send its half of the session encryption key — the frame never left this " +
|
|
94
|
+
"machine, so your counterparty was never asked. Do not raise it with them. Look for " +
|
|
95
|
+
"session.key.announce.failed immediately above this line for the connection error; most often the " +
|
|
96
|
+
"direct link dropped between connecting and sending. It re-announces on the next connect.",
|
|
97
|
+
[CONTENT_ENCRYPTION_REASONS.KEY_REFUSED]: "STOPPED ON PURPOSE. The session encryption key your counterparty sent could not be tied to " +
|
|
98
|
+
"them, so this session was stopped rather than carried on in the open. The ordinary cause is a " +
|
|
99
|
+
"build mismatch. The one that matters is something between you substituting its own key so it " +
|
|
100
|
+
"can read what you send — which is exactly what this check exists to catch. Confirm with your " +
|
|
101
|
+
"counterparty OUT OF BAND, not over CELLO, before opening another session with them.",
|
|
102
|
+
[CONTENT_ENCRYPTION_REASONS.PEER_SILENT]: "Your counterparty never sent their half of the session encryption key. They are running the same " +
|
|
103
|
+
"protocol, so this is not a version difference — either the frame was dropped between you, or " +
|
|
104
|
+
"their daemon is not answering. Check they are online, then start a new session. Nothing was sent " +
|
|
105
|
+
"in the open in the meantime.",
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Render a reason for an agent.
|
|
109
|
+
*
|
|
110
|
+
* ⚠️ NO UNKNOWN-REASON FALLBACK, deliberately. The value is produced and consumed in one process
|
|
111
|
+
* from the closed set above — there is no column it is read back from and no other build writing
|
|
112
|
+
* one, so a "reason this version does not recognise" is a state nothing can be in. An earlier cut
|
|
113
|
+
* carried that branch anyway and described the value as coming off a database row, which was simply
|
|
114
|
+
* untrue. Unreachable defensive code that states a false provenance is worse than no code: it reads
|
|
115
|
+
* as a considered case and it is scaffolding for a world that does not exist.
|
|
116
|
+
*
|
|
117
|
+
* The map is TOTAL over the union, so the type is the check.
|
|
118
|
+
*/
|
|
119
|
+
export function contentEncryptionGuidanceFor(reason) {
|
|
120
|
+
return CONTENT_ENCRYPTION_GUIDANCE[reason];
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=content-encryption-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-encryption-status.js","sourceRoot":"","sources":["../src/content-encryption-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,wBAAwB,CAAC;AAEtE,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC;;;OAGG;IACH,cAAc,EAAE,gBAAgB;IAChC;;;;;;OAMG;IACH,iBAAiB,EAAE,mBAAmB;IACtC,mGAAmG;IACnG,mBAAmB,EAAE,qBAAqB;IAC1C;;;;;;;;OAQG;IACH,WAAW,EAAE,aAAa;IAC1B;;;;;OAKG;IACH,WAAW,EAAE,aAAa;CAClB,CAAC;AAKX;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAA4C;IAClF,CAAC,0BAA0B,CAAC,cAAc,CAAC,EACzC,kGAAkG;QAClG,+FAA+F;QAC/F,6FAA6F;QAC7F,iGAAiG;QACjG,4FAA4F;QAC5F,yDAAyD;IAC3D,CAAC,0BAA0B,CAAC,iBAAiB,CAAC,EAC5C,+FAA+F;QAC/F,kGAAkG;QAClG,mGAAmG;QACnG,gCAAgC;IAClC,CAAC,0BAA0B,CAAC,mBAAmB,CAAC,EAC9C,8FAA8F;QAC9F,qFAAqF;QACrF,mGAAmG;QACnG,0FAA0F;IAC5F,CAAC,0BAA0B,CAAC,WAAW,CAAC,EACtC,6FAA6F;QAC7F,gGAAgG;QAChG,+FAA+F;QAC/F,+FAA+F;QAC/F,qFAAqF;IACvF,CAAC,0BAA0B,CAAC,WAAW,CAAC,EACtC,mGAAmG;QACnG,+FAA+F;QAC/F,mGAAmG;QACnG,8BAA8B;CACjC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,4BAA4B,CAAC,MAA+B;IAC1E,OAAO,2BAA2B,CAAC,MAAM,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { CelloNode } from "@cello-protocol/transport";
|
|
2
2
|
import type { KeyProvider } from "@cello-protocol/crypto";
|
|
3
3
|
import type { Logger } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* DOD-M15-RELAYAUTH-1 review HIGH-3: the relay REFUSED to release parked content, as distinct from
|
|
6
|
+
* having none. Thrown rather than returned so it cannot be mistaken for an empty result — the whole
|
|
7
|
+
* defect was a refusal flattening into `[]`, which reads to an operator as "nothing was waiting".
|
|
8
|
+
*/
|
|
9
|
+
export declare class ContentParkRefusedError extends Error {
|
|
10
|
+
readonly reason: string;
|
|
11
|
+
constructor(reason: string);
|
|
12
|
+
}
|
|
4
13
|
/** A single parked entry returned by pull(). */
|
|
5
14
|
export interface ParkedEntry {
|
|
6
15
|
contentHashHex: string;
|
|
@@ -30,6 +39,7 @@ export declare class ContentParkClient {
|
|
|
30
39
|
}): Promise<{
|
|
31
40
|
ok: boolean;
|
|
32
41
|
reason?: string;
|
|
42
|
+
retryAfterMs?: number;
|
|
33
43
|
}>;
|
|
34
44
|
/**
|
|
35
45
|
* Pull the recipient's parked entries (recipient side). Runs the relay's auth challenge:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-park-client.d.ts","sourceRoot":"","sources":["../src/content-park-client.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAiBzC,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,sFAAsF;IACtF,WAAW,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,iBAAiB;;gBAKhB,IAAI,EAAE,wBAAwB;IAM1C;;;;OAIG;IACG,OAAO,CACX,IAAI,EAAE,SAAS,EACf,IAAI,EAAE;QAAE,eAAe,EAAE,UAAU,CAAC;QAAC,WAAW,EAAE,UAAU,CAAC;QAAC,SAAS,EAAE,UAAU,CAAC;QAAC,UAAU,EAAE,UAAU,CAAA;KAAE,GAC5G,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"content-park-client.d.ts","sourceRoot":"","sources":["../src/content-park-client.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAiBzC;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBACZ,MAAM,EAAE,MAAM;CAK3B;AAED,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,sFAAsF;IACtF,WAAW,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,iBAAiB;;gBAKhB,IAAI,EAAE,wBAAwB;IAM1C;;;;OAIG;IACG,OAAO,CACX,IAAI,EAAE,SAAS,EACf,IAAI,EAAE;QAAE,eAAe,EAAE,UAAU,CAAC;QAAC,WAAW,EAAE,UAAU,CAAC;QAAC,SAAS,EAAE,UAAU,CAAC;QAAC,UAAU,EAAE,UAAU,CAAA;KAAE,GAC5G,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IA8CnE;;;;OAIG;IACG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAiFrG;;;;;;OAMG;IACG,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;CAmF5H"}
|