@serfab/cadre-core 0.9.0 → 0.11.0

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.
Files changed (193) hide show
  1. package/README.md +255 -253
  2. package/dist/bootstrap-peer-store-file.d.ts +13 -0
  3. package/dist/bootstrap-peer-store-file.js +42 -0
  4. package/dist/bootstrap-peer-store-file.js.map +1 -0
  5. package/dist/bootstrap-peer-store.d.ts +73 -0
  6. package/dist/bootstrap-peer-store.js +128 -0
  7. package/dist/bootstrap-peer-store.js.map +1 -0
  8. package/dist/cadre-node.d.ts +1121 -81
  9. package/dist/cadre-node.js +2276 -262
  10. package/dist/cadre-node.js.map +1 -1
  11. package/dist/control-authorization.d.ts +93 -0
  12. package/dist/control-authorization.js +57 -0
  13. package/dist/control-authorization.js.map +1 -0
  14. package/dist/control-cohort.d.ts +26 -0
  15. package/dist/control-cohort.js +26 -0
  16. package/dist/control-cohort.js.map +1 -1
  17. package/dist/control-database.d.ts +959 -54
  18. package/dist/control-database.js +1421 -148
  19. package/dist/control-database.js.map +1 -1
  20. package/dist/control-formation-recorder.d.ts +90 -10
  21. package/dist/control-formation-recorder.js +130 -14
  22. package/dist/control-formation-recorder.js.map +1 -1
  23. package/dist/control-schema.d.ts +1 -1
  24. package/dist/control-schema.js +651 -72
  25. package/dist/control-schema.js.map +1 -1
  26. package/dist/control-stream.d.ts +38 -4
  27. package/dist/control-stream.js +70 -4
  28. package/dist/control-stream.js.map +1 -1
  29. package/dist/control-write-retry.d.ts +161 -0
  30. package/dist/control-write-retry.js +412 -0
  31. package/dist/control-write-retry.js.map +1 -0
  32. package/dist/delegate-admission.d.ts +134 -0
  33. package/dist/delegate-admission.js +244 -0
  34. package/dist/delegate-admission.js.map +1 -0
  35. package/dist/device-token.d.ts +11 -11
  36. package/dist/device-token.js +14 -13
  37. package/dist/device-token.js.map +1 -1
  38. package/dist/ed25519-key.d.ts +26 -0
  39. package/dist/ed25519-key.js +56 -1
  40. package/dist/ed25519-key.js.map +1 -1
  41. package/dist/file-durable-slot.d.ts +20 -0
  42. package/dist/file-durable-slot.js +53 -0
  43. package/dist/file-durable-slot.js.map +1 -0
  44. package/dist/formation-approval.d.ts +157 -0
  45. package/dist/formation-approval.js +375 -0
  46. package/dist/formation-approval.js.map +1 -0
  47. package/dist/fs-atomic.d.ts +38 -0
  48. package/dist/fs-atomic.js +97 -0
  49. package/dist/fs-atomic.js.map +1 -0
  50. package/dist/identity-key.d.ts +49 -0
  51. package/dist/identity-key.js +81 -0
  52. package/dist/identity-key.js.map +1 -0
  53. package/dist/index.d.ts +17 -7
  54. package/dist/index.js +40 -6
  55. package/dist/index.js.map +1 -1
  56. package/dist/key-store-file.d.ts +2 -24
  57. package/dist/key-store-file.js +10 -77
  58. package/dist/key-store-file.js.map +1 -1
  59. package/dist/membership-connection-gater.d.ts +146 -0
  60. package/dist/membership-connection-gater.js +180 -0
  61. package/dist/membership-connection-gater.js.map +1 -0
  62. package/dist/node-local-snapshot.d.ts +109 -0
  63. package/dist/node-local-snapshot.js +182 -0
  64. package/dist/node-local-snapshot.js.map +1 -0
  65. package/dist/peer-addr-book.d.ts +92 -0
  66. package/dist/peer-addr-book.js +220 -0
  67. package/dist/peer-addr-book.js.map +1 -0
  68. package/dist/peer-authorization.d.ts +135 -18
  69. package/dist/peer-authorization.js +152 -21
  70. package/dist/peer-authorization.js.map +1 -1
  71. package/dist/peer-record.d.ts +21 -8
  72. package/dist/peer-record.js +26 -10
  73. package/dist/peer-record.js.map +1 -1
  74. package/dist/relay-addrs.d.ts +45 -0
  75. package/dist/relay-addrs.js +103 -0
  76. package/dist/relay-addrs.js.map +1 -0
  77. package/dist/relay-reservation.d.ts +266 -0
  78. package/dist/relay-reservation.js +613 -0
  79. package/dist/relay-reservation.js.map +1 -0
  80. package/dist/seed-bootstrap.d.ts +228 -56
  81. package/dist/seed-bootstrap.js +340 -198
  82. package/dist/seed-bootstrap.js.map +1 -1
  83. package/dist/seed-trust-policy.d.ts +47 -21
  84. package/dist/seed-trust-policy.js +24 -15
  85. package/dist/seed-trust-policy.js.map +1 -1
  86. package/dist/strand-addr-protocol.d.ts +42 -13
  87. package/dist/strand-addr-protocol.js +58 -52
  88. package/dist/strand-addr-protocol.js.map +1 -1
  89. package/dist/strand-backfill.d.ts +109 -0
  90. package/dist/strand-backfill.js +279 -0
  91. package/dist/strand-backfill.js.map +1 -0
  92. package/dist/strand-cohort.d.ts +4 -37
  93. package/dist/strand-cohort.js +4 -15
  94. package/dist/strand-cohort.js.map +1 -1
  95. package/dist/strand-database.d.ts +11 -16
  96. package/dist/strand-database.js +19 -7
  97. package/dist/strand-database.js.map +1 -1
  98. package/dist/strand-formation-manager.d.ts +36 -7
  99. package/dist/strand-formation-manager.js +115 -15
  100. package/dist/strand-formation-manager.js.map +1 -1
  101. package/dist/strand-formation-protocol.d.ts +103 -4
  102. package/dist/strand-formation-protocol.js +232 -4
  103. package/dist/strand-formation-protocol.js.map +1 -1
  104. package/dist/strand-instance-manager.d.ts +88 -19
  105. package/dist/strand-instance-manager.js +178 -34
  106. package/dist/strand-instance-manager.js.map +1 -1
  107. package/dist/strand-member-registry.d.ts +5 -5
  108. package/dist/strand-member-registry.js +18 -10
  109. package/dist/strand-member-registry.js.map +1 -1
  110. package/dist/strand-membership-writer.d.ts +484 -88
  111. package/dist/strand-membership-writer.js +751 -128
  112. package/dist/strand-membership-writer.js.map +1 -1
  113. package/dist/strand-solicitation.d.ts +99 -33
  114. package/dist/strand-solicitation.js +100 -52
  115. package/dist/strand-solicitation.js.map +1 -1
  116. package/dist/strand-transport-key.d.ts +40 -0
  117. package/dist/strand-transport-key.js +56 -0
  118. package/dist/strand-transport-key.js.map +1 -0
  119. package/dist/strand-wake-protocol.d.ts +9 -7
  120. package/dist/strand-wake-protocol.js +22 -46
  121. package/dist/strand-wake-protocol.js.map +1 -1
  122. package/dist/strand-watcher.d.ts +17 -2
  123. package/dist/strand-watcher.js +47 -3
  124. package/dist/strand-watcher.js.map +1 -1
  125. package/dist/trusted-owner-store-file.d.ts +12 -0
  126. package/dist/trusted-owner-store-file.js +39 -0
  127. package/dist/trusted-owner-store-file.js.map +1 -0
  128. package/dist/trusted-owner-store.d.ts +64 -0
  129. package/dist/trusted-owner-store.js +126 -0
  130. package/dist/trusted-owner-store.js.map +1 -0
  131. package/dist/types.d.ts +307 -44
  132. package/dist/types.js +13 -0
  133. package/dist/types.js.map +1 -1
  134. package/package.json +20 -8
  135. package/src/arachnode-stub.ts +159 -159
  136. package/src/bootstrap-peer-store-file.ts +44 -0
  137. package/src/bootstrap-peer-store.ts +172 -0
  138. package/src/cadre-node.ts +5158 -2981
  139. package/src/canonical-json.ts +30 -30
  140. package/src/control-authorization.ts +114 -0
  141. package/src/control-cohort.ts +130 -103
  142. package/src/control-database.ts +2406 -948
  143. package/src/control-formation-recorder.ts +305 -151
  144. package/src/control-schema.ts +651 -72
  145. package/src/control-stream.ts +205 -128
  146. package/src/control-write-retry.ts +483 -0
  147. package/src/delegate-admission.ts +302 -0
  148. package/src/device-token.ts +94 -89
  149. package/src/diagnostics/connection-path.ts +277 -277
  150. package/src/diagnostics/webrtc-turn-tracker.ts +222 -222
  151. package/src/ed25519-key.ts +66 -1
  152. package/src/enrollment.ts +199 -199
  153. package/src/file-durable-slot.ts +61 -0
  154. package/src/formation-approval.ts +604 -0
  155. package/src/fs-atomic.ts +107 -0
  156. package/src/hibernation-manager.ts +437 -437
  157. package/src/identity-key.ts +109 -0
  158. package/src/index.ts +137 -5
  159. package/src/key-store-file.ts +132 -203
  160. package/src/key-store.ts +99 -99
  161. package/src/membership-connection-gater.ts +204 -0
  162. package/src/node-local-snapshot.ts +260 -0
  163. package/src/peer-addr-book.ts +250 -0
  164. package/src/peer-authorization.ts +259 -81
  165. package/src/peer-record.ts +164 -146
  166. package/src/push-credentials.ts +84 -84
  167. package/src/push-node.ts +64 -64
  168. package/src/push-notifier-apns.ts +247 -247
  169. package/src/push-notifier-fcm.ts +220 -220
  170. package/src/push-notifier-shared.ts +28 -28
  171. package/src/push-notifier.ts +52 -52
  172. package/src/relay-addrs.ts +111 -0
  173. package/src/relay-reservation.ts +823 -0
  174. package/src/seed-bootstrap.ts +409 -209
  175. package/src/seed-trust-policy.ts +140 -107
  176. package/src/strand-addr-protocol.ts +441 -410
  177. package/src/strand-backfill.ts +366 -0
  178. package/src/strand-cohort.ts +38 -77
  179. package/src/strand-database.ts +202 -204
  180. package/src/strand-formation-manager.ts +491 -368
  181. package/src/strand-formation-protocol.ts +692 -391
  182. package/src/strand-instance-manager.ts +201 -46
  183. package/src/strand-member-key.ts +39 -39
  184. package/src/strand-member-registry.ts +182 -177
  185. package/src/strand-membership-writer.ts +938 -146
  186. package/src/strand-solicitation.ts +472 -407
  187. package/src/strand-transport-key.ts +58 -0
  188. package/src/strand-wake-payload.ts +32 -32
  189. package/src/strand-wake-protocol.ts +314 -331
  190. package/src/strand-watcher.ts +314 -251
  191. package/src/trusted-owner-store-file.ts +41 -0
  192. package/src/trusted-owner-store.ts +171 -0
  193. package/src/types.ts +1309 -1032
@@ -1,107 +1,140 @@
1
- /**
2
- * Trust-anchor policy for control-network seeds.
3
- *
4
- * A seed carries an ed25519 signature over its body and the `signerKey` that
5
- * produced it. Verifying that signature only proves the seed is internally
6
- * consistent — it does NOT prove the signer is an owner, because both the
7
- * signer key and the seed's own `isOwner` peer flags are attacker-supplied.
8
- * The trust decision must therefore rest on an anchor that does not come from
9
- * the seed body:
10
- *
11
- * 1. DB-anchored — keys already in the receiver's `CadreControl.OwnerKey`
12
- * table (steady state: the node is enrolled / has synced control state).
13
- * 2. Pinned out-of-band — keys handed to the node from outside the seed
14
- * (carried by a `CadreInvite.ownerKeys`, or pinned by an operator).
15
- * 3. TOFU (opt-in) — an explicit confirmation callback invoked on first sight
16
- * of an unknown signer key. Interactive hosts only; off by default.
17
- *
18
- * Secure default (`dbAnchoredTrustPolicy`): a cold-start node with an empty
19
- * `OwnerKey` table and no pinned keys rejects the seed — a seed can no
20
- * longer vouch for its own signer.
21
- */
22
- export interface SeedTrustContext {
23
- /** Party the seed claims to belong to. */
24
- partyId: string;
25
- /** ed25519 base64url signer key — already signature-verified by `applySeed`. */
26
- signerKey: string;
27
- /**
28
- * The receiver's known owner keys, sourced from its `OwnerKey`
29
- * table — NOT from the seed. Empty for a cold-start node.
30
- */
31
- knownOwnerKeys: ReadonlySet<string>;
32
- }
33
-
34
- export interface SeedTrustDecision {
35
- /** Whether the signer key is trusted. */
36
- trusted: boolean;
37
- /** Human-readable reason, surfaced as the seed-apply error when not trusted. */
38
- reason?: string;
39
- }
40
-
41
- /**
42
- * Decides whether a signature-verified seed's signer key should be trusted.
43
- * May be synchronous (DB/pinned anchors) or asynchronous (TOFU confirmation).
44
- */
45
- export interface SeedTrustPolicy {
46
- evaluate(ctx: SeedTrustContext): Promise<SeedTrustDecision> | SeedTrustDecision;
47
- }
48
-
49
- /**
50
- * Default policy: trust only keys already present in the receiver's
51
- * `OwnerKey` table. A cold-start node (empty table) rejects every seed.
52
- */
53
- export function dbAnchoredTrustPolicy(): SeedTrustPolicy {
54
- return {
55
- evaluate({ signerKey, knownOwnerKeys }) {
56
- if (knownOwnerKeys.has(signerKey)) {
57
- return { trusted: true };
58
- }
59
- return {
60
- trusted: false,
61
- reason: 'Signer key is not a known owner (DB-anchored trust policy)',
62
- };
63
- },
64
- };
65
- }
66
-
67
- /**
68
- * Cold-start policy: trust keys in the receiver's `OwnerKey` table plus a
69
- * set pinned out-of-band (typically `CadreInvite.ownerKeys` or operator
70
- * config). Lets an unenrolled invitee accept its first seed without the seed
71
- * vouching for itself.
72
- */
73
- export function pinnedKeyTrustPolicy(pinned: Iterable<string>): SeedTrustPolicy {
74
- const pinnedSet = new Set(pinned);
75
- return {
76
- evaluate({ signerKey, knownOwnerKeys }) {
77
- if (knownOwnerKeys.has(signerKey) || pinnedSet.has(signerKey)) {
78
- return { trusted: true };
79
- }
80
- return {
81
- trusted: false,
82
- reason: 'Signer key is neither a known nor a pinned owner (pinned-key trust policy)',
83
- };
84
- },
85
- };
86
- }
87
-
88
- /**
89
- * Opt-in interactive policy: trust keys already in the `OwnerKey` table,
90
- * and on an unknown key invoke `confirm` (e.g. a trust-circle UI prompt). The
91
- * key is trusted iff `confirm` resolves true. Not enabled by default.
92
- */
93
- export function tofuTrustPolicy(
94
- confirm: (ctx: SeedTrustContext) => Promise<boolean>
95
- ): SeedTrustPolicy {
96
- return {
97
- async evaluate(ctx) {
98
- if (ctx.knownOwnerKeys.has(ctx.signerKey)) {
99
- return { trusted: true };
100
- }
101
- const accepted = await confirm(ctx);
102
- return accepted
103
- ? { trusted: true }
104
- : { trusted: false, reason: 'TOFU confirmation declined for unknown signer key' };
105
- },
106
- };
107
- }
1
+ /**
2
+ * Trust-anchor policy for control-network seeds.
3
+ *
4
+ * A seed carries an ed25519 signature over its body and the `signerKey` that
5
+ * produced it. Verifying that signature only proves the seed is internally
6
+ * consistent — it does NOT prove the signer is an owner, because both the
7
+ * signer key and the seed's own `isOwner` peer flags are attacker-supplied.
8
+ * The trust decision must therefore rest on an anchor that does not come from
9
+ * the seed body:
10
+ *
11
+ * 1. Anchored — keys in the receiver's NODE-LOCAL `TrustedOwnerStore`: the
12
+ * non-replicated, per-party record of owner keys established out of band
13
+ * (founding the party, the `CadreInvite` that enrolled this node, an
14
+ * operator pin). Deliberately NOT the replicated `CadreControl.OwnerKey`
15
+ * table — any connecting node can genesis-insert its own key there and let
16
+ * it replicate, so that table can be made to say "yes" by a stranger.
17
+ * 2. Pinned out-of-band — keys handed to the node for this seed only (carried
18
+ * by a `CadreInvite.ownerKeys`, or pinned by an operator) without having
19
+ * been anchored yet.
20
+ * 3. TOFU (opt-in) — an explicit confirmation callback invoked on first sight
21
+ * of an unknown signer key. Interactive hosts only; off by default.
22
+ *
23
+ * Secure default (`anchoredTrustPolicy`): a node with an empty anchor and no
24
+ * pinned keys rejects the seed — a seed can no longer vouch for its own signer,
25
+ * and neither can a polluted replicated table.
26
+ *
27
+ * A key accepted via anchor 2 or 3 is reported back through
28
+ * {@link SeedTrustDecision.anchorAs} so `applySeed` can persist it into the
29
+ * node-local anchor, and later seeds from the same owner are accepted without
30
+ * re-supplying the invite/confirmation.
31
+ */
32
+ import type { TrustSource } from './trusted-owner-store.js';
33
+
34
+ export interface SeedTrustContext {
35
+ /** Party the seed claims to belong to. */
36
+ partyId: string;
37
+ /** ed25519 base64url signer key — already signature-verified by `applySeed`. */
38
+ signerKey: string;
39
+ /**
40
+ * The receiver's anchored owner keys, sourced from its node-local
41
+ * `TrustedOwnerStore` — NOT from the seed, and NOT from the replicated
42
+ * `OwnerKey` table. Empty for a node whose anchor was never seeded.
43
+ */
44
+ knownOwnerKeys: ReadonlySet<string>;
45
+ }
46
+
47
+ export interface SeedTrustDecision {
48
+ /** Whether the signer key is trusted. */
49
+ trusted: boolean;
50
+ /** Human-readable reason, surfaced as the seed-apply error when not trusted. */
51
+ reason?: string;
52
+ /**
53
+ * Set when the key was trusted via an anchor OUTSIDE the node-local store (a
54
+ * pinned key, a TOFU confirmation): the provenance to record it under, so
55
+ * `applySeed` persists it and the next seed from that owner is anchored
56
+ * without re-supplying the pin. Omitted when the key was already anchored
57
+ * (nothing to persist) or not trusted at all.
58
+ */
59
+ anchorAs?: Exclude<TrustSource, 'genesis'>;
60
+ }
61
+
62
+ /**
63
+ * Decides whether a signature-verified seed's signer key should be trusted.
64
+ * May be synchronous (anchored/pinned) or asynchronous (TOFU confirmation).
65
+ */
66
+ export interface SeedTrustPolicy {
67
+ evaluate(ctx: SeedTrustContext): Promise<SeedTrustDecision> | SeedTrustDecision;
68
+ }
69
+
70
+ /**
71
+ * Default policy: trust only keys already in the receiver's node-local
72
+ * trusted-owner anchor. A node whose anchor was never seeded (no genesis, no
73
+ * invite pin, no operator pin) rejects every seed.
74
+ */
75
+ export function anchoredTrustPolicy(): SeedTrustPolicy {
76
+ return {
77
+ evaluate({ signerKey, knownOwnerKeys }) {
78
+ if (knownOwnerKeys.has(signerKey)) {
79
+ return { trusted: true };
80
+ }
81
+ return {
82
+ trusted: false,
83
+ reason: 'Signer key is not an anchored owner (anchored trust policy)',
84
+ };
85
+ },
86
+ };
87
+ }
88
+
89
+ /**
90
+ * Cold-start policy: trust anchored keys plus a set pinned out-of-band
91
+ * (typically `CadreInvite.ownerKeys` or operator config). Lets an unenrolled
92
+ * invitee accept its first seed without the seed vouching for itself.
93
+ *
94
+ * @param anchorAs - provenance under which a pin-only acceptance is persisted
95
+ * into the node-local anchor ('invite' by default — the invite-redemption
96
+ * case; pass 'operator' for an operator-supplied pin).
97
+ */
98
+ export function pinnedKeyTrustPolicy(
99
+ pinned: Iterable<string>,
100
+ anchorAs: Exclude<TrustSource, 'genesis'> = 'invite'
101
+ ): SeedTrustPolicy {
102
+ const pinnedSet = new Set(pinned);
103
+ return {
104
+ evaluate({ signerKey, knownOwnerKeys }) {
105
+ if (knownOwnerKeys.has(signerKey)) {
106
+ return { trusted: true };
107
+ }
108
+ if (pinnedSet.has(signerKey)) {
109
+ return { trusted: true, anchorAs };
110
+ }
111
+ return {
112
+ trusted: false,
113
+ reason: 'Signer key is neither an anchored nor a pinned owner (pinned-key trust policy)',
114
+ };
115
+ },
116
+ };
117
+ }
118
+
119
+ /**
120
+ * Opt-in interactive policy: trust keys already in the node-local anchor, and
121
+ * on an unknown key invoke `confirm` (e.g. a trust-circle UI prompt). The key is
122
+ * trusted iff `confirm` resolves true, and a confirmed key is persisted into the
123
+ * anchor as an 'operator' pin (a human at the console is the same provenance as
124
+ * an explicit operator pin) so the prompt is not repeated. Not enabled by default.
125
+ */
126
+ export function tofuTrustPolicy(
127
+ confirm: (ctx: SeedTrustContext) => Promise<boolean>
128
+ ): SeedTrustPolicy {
129
+ return {
130
+ async evaluate(ctx) {
131
+ if (ctx.knownOwnerKeys.has(ctx.signerKey)) {
132
+ return { trusted: true };
133
+ }
134
+ const accepted = await confirm(ctx);
135
+ return accepted
136
+ ? { trusted: true, anchorAs: 'operator' }
137
+ : { trusted: false, reason: 'TOFU confirmation declined for unknown signer key' };
138
+ },
139
+ };
140
+ }