@serfab/cadre-core 0.8.1 → 0.9.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.
- package/README.md +2 -2
- package/dist/cadre-node.d.ts +101 -61
- package/dist/cadre-node.js +165 -124
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-cohort.d.ts +15 -15
- package/dist/control-cohort.js +14 -14
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +51 -34
- package/dist/control-database.js +72 -56
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +2 -2
- package/dist/control-formation-recorder.js +2 -2
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +57 -33
- package/dist/control-schema.js.map +1 -1
- package/dist/device-token.d.ts +1 -1
- package/dist/device-token.js +1 -1
- package/dist/{authority-key.d.ts → ed25519-key.d.ts} +11 -10
- package/dist/{authority-key.js → ed25519-key.js} +9 -10
- package/dist/ed25519-key.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/key-store.d.ts +1 -1
- package/dist/key-store.js +1 -1
- package/dist/peer-authorization.d.ts +28 -6
- package/dist/peer-authorization.js +33 -7
- package/dist/peer-authorization.js.map +1 -1
- package/dist/peer-record.d.ts +3 -3
- package/dist/peer-record.js +3 -3
- package/dist/push-node.d.ts +38 -0
- package/dist/push-node.js +48 -0
- package/dist/push-node.js.map +1 -0
- package/dist/push-notifier-apns.d.ts +10 -2
- package/dist/push-notifier-apns.js +14 -10
- package/dist/push-notifier-apns.js.map +1 -1
- package/dist/push-notifier-fcm.d.ts +7 -1
- package/dist/push-notifier-fcm.js +9 -10
- package/dist/push-notifier-fcm.js.map +1 -1
- package/dist/push-notifier.d.ts +16 -35
- package/dist/push-notifier.js +16 -44
- package/dist/push-notifier.js.map +1 -1
- package/dist/seed-bootstrap.d.ts +70 -51
- package/dist/seed-bootstrap.js +168 -106
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/seed-trust-policy.d.ts +11 -11
- package/dist/seed-trust-policy.js +11 -11
- package/dist/seed-trust-policy.js.map +1 -1
- package/dist/strand-database.d.ts +5 -5
- package/dist/strand-database.js +4 -4
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +1 -1
- package/dist/strand-formation-protocol.js +1 -1
- package/dist/strand-instance-manager.d.ts +1 -1
- package/dist/strand-instance-manager.js +1 -1
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-member-key.d.ts +6 -6
- package/dist/strand-member-key.js +6 -6
- package/dist/strand-member-key.js.map +1 -1
- package/dist/strand-member-registry.d.ts +7 -7
- package/dist/strand-member-registry.js +5 -5
- package/dist/strand-member-registry.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +84 -84
- package/dist/strand-membership-writer.js +90 -90
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/types.d.ts +52 -32
- package/dist/types.js.map +1 -1
- package/package.json +7 -3
- package/src/cadre-node.ts +170 -126
- package/src/control-cohort.ts +17 -17
- package/src/control-database.ts +76 -59
- package/src/control-formation-recorder.ts +2 -2
- package/src/control-schema.ts +57 -33
- package/src/device-token.ts +1 -1
- package/src/{authority-key.ts → ed25519-key.ts} +12 -11
- package/src/index.ts +21 -19
- package/src/key-store.ts +1 -1
- package/src/peer-authorization.ts +35 -7
- package/src/peer-record.ts +3 -3
- package/src/push-node.ts +64 -0
- package/src/push-notifier-apns.ts +16 -12
- package/src/push-notifier-fcm.ts +9 -10
- package/src/push-notifier.ts +16 -57
- package/src/seed-bootstrap.ts +179 -115
- package/src/seed-trust-policy.ts +18 -18
- package/src/strand-database.ts +6 -6
- package/src/strand-formation-protocol.ts +1 -1
- package/src/strand-instance-manager.ts +2 -2
- package/src/strand-member-key.ts +7 -7
- package/src/strand-member-registry.ts +10 -10
- package/src/strand-membership-writer.ts +127 -127
- package/src/types.ts +52 -32
- package/dist/authority-key.js.map +0 -1
package/dist/seed-bootstrap.d.ts
CHANGED
|
@@ -18,10 +18,10 @@ export declare function decodeLengthPrefixedFrame(data: Uint8Array, maxLength?:
|
|
|
18
18
|
*
|
|
19
19
|
* An Ed25519 PeerId is an identity multihash of the public key, so
|
|
20
20
|
* `peerIdFromString(id).publicKey.raw` is the 32-byte ed25519 key whose
|
|
21
|
-
* base64url form matches the `
|
|
22
|
-
* `
|
|
21
|
+
* base64url form matches the `OwnerKey.Key` representation (and
|
|
22
|
+
* `ed25519KeyPairFromLibp2p().publicKeyB64`). Returns null for a non-Ed25519
|
|
23
23
|
* id, a missing embedded key, or any parse failure — callers treat null as
|
|
24
|
-
* "not an
|
|
24
|
+
* "not an owner" rather than throwing.
|
|
25
25
|
*/
|
|
26
26
|
export declare function ed25519PublicKeyB64FromPeerId(peerId: string): string | null;
|
|
27
27
|
/**
|
|
@@ -40,10 +40,10 @@ export declare function canonicalSeedPayload(seed: Pick<ControlNetworkSeed, 'par
|
|
|
40
40
|
export interface SeedBootstrapConfig {
|
|
41
41
|
/** Party ID for this cadre */
|
|
42
42
|
partyId: string;
|
|
43
|
-
/**
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
|
|
43
|
+
/** Owner private key for signing seeds and peer authorizations (base64url) */
|
|
44
|
+
ownerPrivateKey?: string;
|
|
45
|
+
/** Owner public key (base64url) - derived from private key if not provided */
|
|
46
|
+
ownerPublicKey?: string;
|
|
47
47
|
/**
|
|
48
48
|
* Optional async resolver returning the multiaddrs to embed in invites.
|
|
49
49
|
* When unset, `libp2pNode.getMultiaddrs()` is used. Hosts behind NAT supply
|
|
@@ -53,9 +53,9 @@ export interface SeedBootstrapConfig {
|
|
|
53
53
|
inviteAddressResolver?: () => Promise<string[]>;
|
|
54
54
|
/**
|
|
55
55
|
* Trust anchor for incoming seeds. Decides whether a signature-verified
|
|
56
|
-
* `signerKey` should be trusted, against the receiver's known
|
|
56
|
+
* `signerKey` should be trusted, against the receiver's known owner
|
|
57
57
|
* keys (NOT the seed body). Defaults to `dbAnchoredTrustPolicy()`, which
|
|
58
|
-
* rejects any signer not already in the `
|
|
58
|
+
* rejects any signer not already in the `OwnerKey` table. An enrollment
|
|
59
59
|
* caller can pass a per-seed override to `applySeed` instead.
|
|
60
60
|
*
|
|
61
61
|
* A `CadreNode` forwards its node-wide `CadreNodeConfig.seedTrustPolicy` here
|
|
@@ -98,7 +98,7 @@ export declare class SeedBootstrapService {
|
|
|
98
98
|
private readonly config;
|
|
99
99
|
private libp2pNode;
|
|
100
100
|
private controlDatabase;
|
|
101
|
-
private readonly
|
|
101
|
+
private readonly ownerPublicKey;
|
|
102
102
|
private readonly trustPolicy;
|
|
103
103
|
private readonly seedReadTimeoutMs;
|
|
104
104
|
private readonly maxConcurrentSeeds;
|
|
@@ -112,12 +112,12 @@ export declare class SeedBootstrapService {
|
|
|
112
112
|
*/
|
|
113
113
|
setEventCallbacks(callbacks: SeedEventCallbacks): void;
|
|
114
114
|
/**
|
|
115
|
-
* Whether this service holds an
|
|
116
|
-
*
|
|
115
|
+
* Whether this service holds an owner private key, i.e. can produce the
|
|
116
|
+
* owner signatures that gate `CadrePeer` / `DeviceToken` inserts, deletes,
|
|
117
117
|
* and re-authorizations. A seed-listener-only service (`enableSeedListener`,
|
|
118
|
-
* no
|
|
119
|
-
* or re-issue
|
|
120
|
-
* drain to skip
|
|
118
|
+
* no owner key) returns false: it can receive/apply seeds but cannot author
|
|
119
|
+
* or re-issue owner writes. Used by the write-while-alone re-replication
|
|
120
|
+
* drain to skip owner work on a non-owner node.
|
|
121
121
|
*/
|
|
122
122
|
canAuthorize(): boolean;
|
|
123
123
|
/**
|
|
@@ -137,73 +137,92 @@ export declare class SeedBootstrapService {
|
|
|
137
137
|
}): void;
|
|
138
138
|
/**
|
|
139
139
|
* Authorize a new peer to join the cadre.
|
|
140
|
-
* Signs the peer ID with the
|
|
140
|
+
* Signs the peer ID with the owner key and inserts into CadrePeer table.
|
|
141
141
|
*
|
|
142
|
-
* The
|
|
142
|
+
* The owner vouches the `PublicKey <-> PeerId` binding: rather than trust a
|
|
143
143
|
* caller-supplied key, the binding is enforced by construction — `PublicKey` is
|
|
144
144
|
* DERIVED from the (Ed25519) `peerId`. A non-Ed25519 peer id yields a null
|
|
145
145
|
* `PublicKey`, and such a row can never be self-updated (it has no key to
|
|
146
146
|
* verify against), which is correct. The row is inserted with a fresh
|
|
147
|
-
* `UpdatedAt` but no self-signature (`Sig` null) — the
|
|
147
|
+
* `UpdatedAt` but no self-signature (`Sig` null) — the owner cannot produce
|
|
148
148
|
* the peer's self-signature, so the peer must self-publish (see
|
|
149
149
|
* {@link CadreNode.registerSelf}) before the row resolves.
|
|
150
150
|
*/
|
|
151
151
|
authorizePeer(options: AuthorizePeerOptions): Promise<void>;
|
|
152
152
|
/**
|
|
153
|
-
*
|
|
153
|
+
* Owner-signed INSERT of this node's OWN self-signed address record.
|
|
154
154
|
*
|
|
155
155
|
* Used by {@link CadreNode.registerSelf} when the node is not yet a member and
|
|
156
|
-
* is its own
|
|
156
|
+
* is its own owner (it holds the owner key): the row is owner-signed
|
|
157
157
|
* (satisfying `AuthorizedInsert`) AND carries a valid self-`Sig`, so it resolves
|
|
158
158
|
* immediately without a follow-up self-update.
|
|
159
159
|
*/
|
|
160
160
|
insertSelfPeerRecord(record: PeerAddressRecord): Promise<void>;
|
|
161
161
|
/**
|
|
162
|
-
* Shared
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
162
|
+
* Shared owner-signed `CadrePeer` INSERT. Mints a fresh single-use `StampId`
|
|
163
|
+
* and signs the voucher digest `digest(peerId, stampId)` ({@link cadrePeerVoucherDigest})
|
|
164
|
+
* with the owner key (satisfying `AuthorizedInsert`), then writes the full record
|
|
165
|
+
* row with the vouching (owner, signature) persisted into VouchOwner/VouchSig.
|
|
166
|
+
* The owner signature does NOT cover the address columns — those are vouched only
|
|
167
|
+
* as far as the owner asserts them, and a peer's own `Sig` (when present) is what
|
|
168
|
+
* makes the row resolvable.
|
|
167
169
|
*/
|
|
168
170
|
private insertCadrePeerRow;
|
|
169
171
|
/**
|
|
170
|
-
*
|
|
172
|
+
* Owner-signed INSERT of a peer's OWN self-signed `DeviceToken` row.
|
|
171
173
|
*
|
|
172
174
|
* Counterpart to {@link insertSelfPeerRecord} for the device-token registry: the
|
|
173
|
-
* row is
|
|
175
|
+
* row is owner-signed (satisfying `DeviceToken.AuthorizedInsert`, which vouches
|
|
174
176
|
* membership exactly as `CadrePeer.AuthorizedInsert` does) AND carries the peer's
|
|
175
|
-
* own self-`Sig` over the token payload. The
|
|
177
|
+
* own self-`Sig` over the token payload. The owner signature covers only the
|
|
176
178
|
* PeerId — it does NOT vouch the token contents; the peer's `Sig` (verified at
|
|
177
179
|
* resolve time against the bound `CadrePeer.PublicKey`) is what makes the row
|
|
178
180
|
* resolvable. Used by {@link CadreNode.registerDeviceToken} for the first publish
|
|
179
|
-
* when the node is its own
|
|
181
|
+
* when the node is its own owner.
|
|
180
182
|
*/
|
|
181
183
|
insertSelfDeviceToken(record: DeviceTokenRecord): Promise<void>;
|
|
182
184
|
/**
|
|
183
|
-
*
|
|
185
|
+
* Owner-signed DELETE of a peer's `DeviceToken` row (logout / token
|
|
184
186
|
* invalidation). The `DeviceToken.AuthorizedInsert` constraint gates both insert
|
|
185
|
-
* AND delete on an
|
|
186
|
-
* {@link removePeer} for `CadrePeer` — clearing a token requires the
|
|
187
|
+
* AND delete on an owner signature over `digest(old.PeerId)`, so — like
|
|
188
|
+
* {@link removePeer} for `CadrePeer` — clearing a token requires the owner key.
|
|
187
189
|
*/
|
|
188
190
|
deleteDeviceToken(peerId: string): Promise<void>;
|
|
189
191
|
/**
|
|
190
|
-
* Sign a peer ID with the
|
|
192
|
+
* Sign a peer ID with the owner key for a `CadrePeer` / `DeviceToken`
|
|
191
193
|
* insert-or-delete. The signed bytes come from the shared
|
|
192
194
|
* {@link peerAuthorizationDigest} helper so the offline `cadre enroll register`
|
|
193
|
-
* verifier checks the exact same construction. Throws if no
|
|
195
|
+
* verifier checks the exact same construction. Throws if no owner key is set.
|
|
194
196
|
*/
|
|
195
197
|
private signPeerAuthorization;
|
|
196
198
|
/**
|
|
197
|
-
*
|
|
199
|
+
* Return the configured owner private key, or throw if none is set. The single
|
|
200
|
+
* precondition gate for every owner-signed write. {@link removePeer} /
|
|
201
|
+
* {@link reauthorizePeer} read the row's `StampId` from the DB BEFORE they sign, so
|
|
202
|
+
* they call this up front — otherwise a keyless service would either surface the
|
|
203
|
+
* wrong "Control database not initialized" error or, worse, silently no-op when the
|
|
204
|
+
* target row is absent (the early `stampId === null` return) instead of rejecting.
|
|
205
|
+
*/
|
|
206
|
+
private requireOwnerPrivateKey;
|
|
207
|
+
/**
|
|
208
|
+
* Sign a base64url digest with the owner key (ed25519). The single place the
|
|
209
|
+
* owner private key is applied; callers pass the canonical digest for the specific
|
|
210
|
+
* action ({@link cadrePeerVoucherDigest} / {@link cadrePeerRemoveDigest} /
|
|
211
|
+
* {@link peerAuthorizationDigest}). Throws if no owner key is set.
|
|
212
|
+
*/
|
|
213
|
+
private signDigest;
|
|
214
|
+
/**
|
|
215
|
+
* Remove a peer from the cadre by owner signature.
|
|
198
216
|
*
|
|
199
|
-
* The
|
|
200
|
-
* signature over `digest(old.PeerId
|
|
201
|
-
*
|
|
217
|
+
* The `CadrePeer.AuthorizedDelete` (`check on delete`) constraint validates a
|
|
218
|
+
* signature over the DISTINCT 'remove'-scoped digest `digest(old.PeerId, old.StampId,
|
|
219
|
+
* 'remove')` ({@link cadrePeerRemoveDigest}) by an owner key — deliberately NOT the
|
|
220
|
+
* insert voucher digest, so the row's stored `VouchSig` can never be replayed to delete.
|
|
202
221
|
*/
|
|
203
222
|
removePeer(peerId: string): Promise<void>;
|
|
204
223
|
/**
|
|
205
|
-
*
|
|
206
|
-
* `UpdatedAt` under the
|
|
224
|
+
* Owner "re-touch" of an existing `CadrePeer` membership row: bump
|
|
225
|
+
* `UpdatedAt` under the owner branch of `CadrePeer.AuthorizedUpdate` (a
|
|
207
226
|
* signature over `digest(peerId)` — the same construction {@link authorizePeer}
|
|
208
227
|
* uses) so the row is re-emitted as a fresh, broadcasting transaction.
|
|
209
228
|
*
|
|
@@ -220,13 +239,13 @@ export declare class SeedBootstrapService {
|
|
|
220
239
|
*
|
|
221
240
|
* @param peerId - the membership row to re-touch.
|
|
222
241
|
* @param updatedAt - the strictly-increasing freshness stamp to write.
|
|
223
|
-
* @throws if no
|
|
242
|
+
* @throws if no owner private key is configured (a non-owner cannot
|
|
224
243
|
* re-sign another peer's row) or the control database is not initialized.
|
|
225
244
|
*/
|
|
226
245
|
reauthorizePeer(peerId: string, updatedAt: number): Promise<void>;
|
|
227
246
|
/**
|
|
228
247
|
* Create a seed from the current control network state.
|
|
229
|
-
* The seed contains peer information and is signed by an
|
|
248
|
+
* The seed contains peer information and is signed by an owner.
|
|
230
249
|
*/
|
|
231
250
|
createSeed(): Promise<ControlNetworkSeed>;
|
|
232
251
|
/**
|
|
@@ -234,9 +253,9 @@ export declare class SeedBootstrapService {
|
|
|
234
253
|
*
|
|
235
254
|
* Validates the seed signature, then evaluates a trust anchor for the
|
|
236
255
|
* `signerKey` that does NOT come from the seed body: the receiver's
|
|
237
|
-
* `
|
|
256
|
+
* `OwnerKey` table (DB-anchored), optionally augmented by pinned keys or
|
|
238
257
|
* TOFU via the configured/overriding `SeedTrustPolicy`. A forged
|
|
239
|
-
* self-asserting seed — one that merely lists its own signer as an
|
|
258
|
+
* self-asserting seed — one that merely lists its own signer as an owner
|
|
240
259
|
* peer — no longer passes.
|
|
241
260
|
*
|
|
242
261
|
* @param seed - The seed to apply (already transport-decoded).
|
|
@@ -271,12 +290,12 @@ export declare class SeedBootstrapService {
|
|
|
271
290
|
/**
|
|
272
291
|
* Query peers from the control database.
|
|
273
292
|
*
|
|
274
|
-
*
|
|
293
|
+
* Owner identity is sourced from the `OwnerKey` table, not from the
|
|
275
294
|
* transport peer ID. An Ed25519 libp2p PeerId embeds its public key (identity
|
|
276
295
|
* multihash), so each peer's ed25519 key is derivable from its `PeerId`; a
|
|
277
|
-
* peer is an
|
|
278
|
-
* This makes any
|
|
279
|
-
* `
|
|
296
|
+
* peer is an owner iff that derived key is in the `OwnerKey` set.
|
|
297
|
+
* This makes any owner node markable — not just the local one — and ties
|
|
298
|
+
* `isOwner` to the control table rather than to `peerId === self`.
|
|
280
299
|
*/
|
|
281
300
|
private queryPeers;
|
|
282
301
|
/**
|
|
@@ -357,11 +376,11 @@ export declare class SeedBootstrapService {
|
|
|
357
376
|
*/
|
|
358
377
|
decodeInvite(encoded: string): CadreInvite;
|
|
359
378
|
/**
|
|
360
|
-
* Dial an
|
|
361
|
-
* Use this on a phone after receiving an invite to connect to the
|
|
379
|
+
* Dial an owner from an invite.
|
|
380
|
+
* Use this on a phone after receiving an invite to connect to the owner.
|
|
362
381
|
*
|
|
363
382
|
* @param invite - The invite received out-of-band
|
|
364
|
-
* @returns Connection to the
|
|
383
|
+
* @returns Connection to the owner
|
|
365
384
|
*/
|
|
366
385
|
dialInvite(invite: CadreInvite): Promise<void>;
|
|
367
386
|
}
|