@derec-alliance/react-native 0.0.5 → 0.0.7
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 +33 -15
- package/android/CMakeLists.txt +1 -1
- package/android/src/main/jniLibs/arm64-v8a/libderec_library.a +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libderec_library.a +0 -0
- package/android/src/main/jniLibs/x86_64/libderec_library.a +0 -0
- package/cpp/Convert.cpp +125 -0
- package/cpp/Convert.h +35 -0
- package/cpp/DeRecInstaller.cpp +0 -12
- package/cpp/Primitives.cpp +175 -26
- package/cpp/Primitives.h +33 -0
- package/cpp/ProtocolHost.cpp +38 -50
- package/cpp/StoreCallbacks.cpp +179 -301
- package/cpp/UserSecretsJson.cpp +109 -0
- package/cpp/UserSecretsJson.h +28 -0
- package/cpp/derec_ffi.h +298 -132
- package/ios/DeRecFFI.xcframework/Info.plist +5 -5
- package/ios/DeRecFFI.xcframework/ios-arm64/Headers/derec_ffi.h +298 -132
- package/ios/DeRecFFI.xcframework/ios-arm64/libderec_library.a +0 -0
- package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/Headers/derec_ffi.h +298 -132
- package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/libderec_library.a +2 -2
- package/lib/errors.d.ts +16 -0
- package/lib/native.d.ts +5 -1
- package/lib/primitives.d.ts +18 -21
- package/lib/primitives.js +48 -25
- package/lib/protocol.d.ts +65 -102
- package/lib/protocol.js +98 -171
- package/lib/types.d.ts +299 -110
- package/lib/types.js +43 -13
- package/package.json +1 -1
- package/src/errors.ts +17 -0
- package/src/native.ts +2 -1
- package/src/primitives.ts +82 -25
- package/src/protocol.ts +105 -189
- package/src/types.ts +304 -99
package/lib/types.d.ts
CHANGED
|
@@ -2,11 +2,12 @@ export interface SecretStore {
|
|
|
2
2
|
load(secretId: string, channelId: string, kind: 0 | 1 | 2): Promise<Uint8Array | null | undefined>;
|
|
3
3
|
/**
|
|
4
4
|
* Load secrets of the same `kind` for several channels in one call,
|
|
5
|
-
* scoped to `secretId`. Must return an array with one entry per
|
|
6
|
-
* id, in the same order, using `null` (or `undefined`) for channels
|
|
7
|
-
* with no stored secret of `kind`.
|
|
5
|
+
* scoped to `secretId`. Must return an array with exactly one entry per
|
|
6
|
+
* input id, in the same order, using `null` (or `undefined`) for channels
|
|
7
|
+
* with no stored secret of `kind`. Whether a missing entry is an error is
|
|
8
|
+
* decided by the library.
|
|
8
9
|
*/
|
|
9
|
-
loadMany(secretId: string, channelIds: string[], kind: 0 | 1 | 2
|
|
10
|
+
loadMany(secretId: string, channelIds: string[], kind: 0 | 1 | 2): Promise<Array<Uint8Array | null | undefined>>;
|
|
10
11
|
save(secretId: string, channelId: string, kind: 0 | 1 | 2, value: Uint8Array): Promise<void>;
|
|
11
12
|
remove(secretId: string, channelId: string, kind: 0 | 1 | 2): Promise<void>;
|
|
12
13
|
}
|
|
@@ -78,19 +79,11 @@ export declare function channelFilterMatches(filter: HelperFilter | ReplicaFilte
|
|
|
78
79
|
/**
|
|
79
80
|
* The endpoints a peer-supplied message advertises, in the peer's own order.
|
|
80
81
|
*
|
|
81
|
-
* Yields `supported_transports` when it is non-empty, and otherwise the
|
|
82
|
-
* singular `transport_protocol` — which is how every implementation predating
|
|
83
|
-
* the offer list advertises, and the reason this is a function rather than a
|
|
84
|
-
* field read. Reading `transport_protocol` directly is a bug: its meaning
|
|
85
|
-
* narrowed to "one entry of a list, and possibly absent", so a peer that has
|
|
86
|
-
* moved past it looks unreachable to a reader that was correct before 0.0.3.
|
|
87
|
-
*
|
|
88
82
|
* Reports what was advertised, not what is acceptable — nothing here is
|
|
89
83
|
* validated, and the protocol still applies its own transport policy to
|
|
90
84
|
* whatever it records.
|
|
91
85
|
*/
|
|
92
86
|
export declare function advertisedEndpoints(message: {
|
|
93
|
-
transport_protocol?: TransportProtocol;
|
|
94
87
|
supported_transports?: TransportProtocol[];
|
|
95
88
|
} | null | undefined): TransportProtocol[];
|
|
96
89
|
/**
|
|
@@ -172,7 +165,7 @@ export interface ChannelStore {
|
|
|
172
165
|
* Order explicitly to make succession predictable.
|
|
173
166
|
*/
|
|
174
167
|
listReplicas(secretId: string, filter: ReplicaFilter): Promise<Uint8Array | null | undefined>;
|
|
175
|
-
linkChannel(secretId: string,
|
|
168
|
+
linkChannel(secretId: string, a: string, b: string): Promise<void>;
|
|
176
169
|
linkedChannels(secretId: string, channelId: string): Promise<string[]>;
|
|
177
170
|
}
|
|
178
171
|
export interface Share {
|
|
@@ -198,6 +191,35 @@ export interface ShareStore {
|
|
|
198
191
|
save(secretId: string, channelId: string, share: Share): Promise<void>;
|
|
199
192
|
latestVersion(secretId: string): Promise<number | null>;
|
|
200
193
|
removeChannel(secretId: string, channelId: string): Promise<void>;
|
|
194
|
+
/**
|
|
195
|
+
* Drop the shares stored under `(secretId, channelId)` at each of
|
|
196
|
+
* `versions`. Idempotent: a version that is not stored is skipped, and
|
|
197
|
+
* an empty array is a no-op.
|
|
198
|
+
*
|
|
199
|
+
* A helper calls this to apply `StoreShareRequestMessage.keepList`, the
|
|
200
|
+
* complete set of versions the owner wants retained: every stored
|
|
201
|
+
* version outside it is removed once the incoming share is persisted.
|
|
202
|
+
* Shares under other channels or partitions must be left untouched.
|
|
203
|
+
*/
|
|
204
|
+
removeVersions(secretId: string, channelId: string, versions: number[]): Promise<void>;
|
|
205
|
+
/**
|
|
206
|
+
* Owner only: the versions every helper keeps after the owner distributes
|
|
207
|
+
* `version`. Asked once per sharing round, before anything is sent,
|
|
208
|
+
* including the rounds the library starts itself; the answer becomes
|
|
209
|
+
* `keepList` for every helper.
|
|
210
|
+
*
|
|
211
|
+
* Return `null` or `undefined` to send no `keepList` (it goes out empty):
|
|
212
|
+
* helpers then keep every version they hold. An app that wants to cap how
|
|
213
|
+
* many versions helpers retain returns that cap here. A returned list is
|
|
214
|
+
* used as is, plus `version`, which the library always adds. Helpers
|
|
215
|
+
* delete every version that is not listed, so list every version that
|
|
216
|
+
* could still become the latest: those that committed (for example, whose
|
|
217
|
+
* `SharingComplete` reported `threshold_met`) and those whose round is
|
|
218
|
+
* still open. Leave out only versions whose round failed or that the user
|
|
219
|
+
* rolled back; a list that leaves out too much can make the secret
|
|
220
|
+
* unrecoverable.
|
|
221
|
+
*/
|
|
222
|
+
keepList(secretId: string, version: number): Promise<number[] | null | undefined>;
|
|
201
223
|
}
|
|
202
224
|
export interface UserSecretEntry {
|
|
203
225
|
id: Uint8Array;
|
|
@@ -208,6 +230,10 @@ export interface UserSecrets {
|
|
|
208
230
|
version: number;
|
|
209
231
|
secrets: UserSecretEntry[];
|
|
210
232
|
description?: string;
|
|
233
|
+
/** Decimal `replica_id` of the member that published `version`. Absent
|
|
234
|
+
* when none is recorded. Store and return it unchanged: replica members
|
|
235
|
+
* compare it to detect a conflicting copy of the same version. */
|
|
236
|
+
author_replica_id?: string;
|
|
211
237
|
}
|
|
212
238
|
/**
|
|
213
239
|
* Persistence for the user-facing secret contents, keyed by `secretId`.
|
|
@@ -245,6 +271,16 @@ export interface StateStore {
|
|
|
245
271
|
remove(secretId: string, keyJson: Uint8Array): Promise<boolean>;
|
|
246
272
|
loadAll(secretId: string, kind: 0 | 1 | 2 | 3 | 4): Promise<Uint8Array[]>;
|
|
247
273
|
}
|
|
274
|
+
/** A transport protocol, by name. */
|
|
275
|
+
export type TransportProtocolName = "https" | "grpc";
|
|
276
|
+
/**
|
|
277
|
+
* One endpoint a node serves or a peer advertised, as every app-facing call
|
|
278
|
+
* and event carries it.
|
|
279
|
+
*/
|
|
280
|
+
export interface Endpoint {
|
|
281
|
+
uri: string;
|
|
282
|
+
protocol: TransportProtocolName;
|
|
283
|
+
}
|
|
248
284
|
/**
|
|
249
285
|
* Outbound message delivery.
|
|
250
286
|
*
|
|
@@ -289,10 +325,7 @@ export interface Transport {
|
|
|
289
325
|
* provide — if that is genuinely wanted, say so with
|
|
290
326
|
* {@link singleEndpointTransport} rather than by indexing.
|
|
291
327
|
*/
|
|
292
|
-
send(endpoints: ReadonlyArray<
|
|
293
|
-
protocol: string;
|
|
294
|
-
uri: string;
|
|
295
|
-
}>, message: Uint8Array): Promise<void>;
|
|
328
|
+
send(endpoints: ReadonlyArray<Endpoint>, message: Uint8Array): Promise<void>;
|
|
296
329
|
}
|
|
297
330
|
/**
|
|
298
331
|
* Delivers one message to one endpoint.
|
|
@@ -308,10 +341,22 @@ export interface Transport {
|
|
|
308
341
|
* which is the safe reading. Trying an endpoint that would have refused costs
|
|
309
342
|
* a round trip; skipping one that would have worked costs the delivery.
|
|
310
343
|
*/
|
|
311
|
-
export type SendOne = (endpoint:
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
344
|
+
export type SendOne = (endpoint: Endpoint, message: Uint8Array) => Promise<void>;
|
|
345
|
+
/**
|
|
346
|
+
* The DeRec protocol version this build speaks — the `protocolVersionMajor` /
|
|
347
|
+
* `protocolVersionMinor` it writes into every envelope it produces. Not the
|
|
348
|
+
* package version.
|
|
349
|
+
*/
|
|
350
|
+
export declare function protocol_version(): {
|
|
351
|
+
major: number;
|
|
352
|
+
minor: number;
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* A fresh, random replica id — never `0`. Generate it once per device,
|
|
356
|
+
* persist it, and pass the same value to
|
|
357
|
+
* `DeRecProtocolBuilder.withReplicaId` on every init.
|
|
358
|
+
*/
|
|
359
|
+
export declare function generate_replica_id(): bigint;
|
|
315
360
|
/**
|
|
316
361
|
* Builds a {@link Transport} that tries each endpoint in the order the peer
|
|
317
362
|
* offered it and stops at the first success.
|
|
@@ -353,7 +398,7 @@ export declare enum SenderKind {
|
|
|
353
398
|
* the scanner must fetch the actual keys over the wire via the `PrePair`
|
|
354
399
|
* round-trip and verify them against the commitment before pairing.
|
|
355
400
|
* - `NoKeys`: no key material and no commitment. The contact carries only
|
|
356
|
-
* `channel_id`, `nonce`, and `
|
|
401
|
+
* `channel_id`, `nonce`, and `supported_transports` — small enough to be
|
|
357
402
|
* hand-typed or dictated. Keys are generated on the fly by the contact
|
|
358
403
|
* creator when the `PrePairRequest` arrives; the scanner accepts them
|
|
359
404
|
* without cryptographic verification. Trust rests entirely on the OOB
|
|
@@ -393,19 +438,31 @@ export declare enum FlowKind {
|
|
|
393
438
|
* string so ids above 2^53 survive JS number handling. */
|
|
394
439
|
UnpairReplica = 8
|
|
395
440
|
}
|
|
441
|
+
/** Result status carried in every protocol response (`result.proto`). Passed
|
|
442
|
+
* to `reject()` to say why an inbound request was refused. */
|
|
443
|
+
export declare enum StatusEnum {
|
|
444
|
+
Ok = 0,
|
|
445
|
+
Partial = 1,
|
|
446
|
+
Fail = 2,
|
|
447
|
+
SizeLimitExceeded = 3,
|
|
448
|
+
TooFrequent = 4,
|
|
449
|
+
UnknownSecretId = 5,
|
|
450
|
+
UnknownShareVersion = 6,
|
|
451
|
+
DecryptionFailed = 7,
|
|
452
|
+
VerificationFailed = 8,
|
|
453
|
+
FormatError = 9,
|
|
454
|
+
Rejected = 10,
|
|
455
|
+
IncompatibleParameterRange = 11,
|
|
456
|
+
UnsupportedTransportProtocol = 12,
|
|
457
|
+
VersionConflict = 13,
|
|
458
|
+
ReplicaIdConflict = 14,
|
|
459
|
+
RequestToClose = 99
|
|
460
|
+
}
|
|
396
461
|
export type UnpairAck = "required" | "not_required";
|
|
397
462
|
export interface ContactMessage {
|
|
398
463
|
channel_id: bigint;
|
|
399
464
|
/** `ContactMode` numeric value (0 = INLINE_KEYS, 1 = HASHED_KEYS, 2 = NO_KEYS). */
|
|
400
465
|
contact_mode: number;
|
|
401
|
-
/**
|
|
402
|
-
* @deprecated Reading this field directly is incorrect: its meaning narrowed
|
|
403
|
-
* to "one entry of a list, and possibly absent", so a peer advertising only
|
|
404
|
-
* `supported_transports` looks unreachable to a reader that was correct
|
|
405
|
-
* before 0.0.3. Call {@link advertisedEndpoints}, which resolves both
|
|
406
|
-
* spellings. Removed at 0.0.5.
|
|
407
|
-
*/
|
|
408
|
-
transport_protocol?: TransportProtocol;
|
|
409
466
|
nonce: bigint;
|
|
410
467
|
/** Present only when `contact_mode === ContactMode.InlineKeys`. */
|
|
411
468
|
mlkem_encapsulation_key?: Uint8Array;
|
|
@@ -415,8 +472,7 @@ export interface ContactMessage {
|
|
|
415
472
|
contact_binding_hash?: Uint8Array;
|
|
416
473
|
timestamp?: Timestamp;
|
|
417
474
|
/** Every transport endpoint the creator of this contact can be reached
|
|
418
|
-
* on, in its own preference order.
|
|
419
|
-
* `transport_protocol` is offered". */
|
|
475
|
+
* on, in its own preference order. */
|
|
420
476
|
supported_transports: TransportProtocol[];
|
|
421
477
|
}
|
|
422
478
|
export interface UserSecret {
|
|
@@ -455,23 +511,11 @@ export interface UpdateChannelInfoParams {
|
|
|
455
511
|
/** New communication-info map. `null`/absent leaves the peer's stored
|
|
456
512
|
* map untouched; pass an empty object to clear it. */
|
|
457
513
|
communication_info?: Record<string, string>;
|
|
458
|
-
/**
|
|
459
|
-
* New transport endpoint. Absent leaves it untouched.
|
|
460
|
-
*
|
|
461
|
-
* @deprecated Use `own_transports`, which carries every endpoint this node
|
|
462
|
-
* now serves; its first entry also fills this field for peers predating the
|
|
463
|
-
* list. Removed at 0.0.5.
|
|
464
|
-
*/
|
|
465
|
-
transport_protocol?: {
|
|
466
|
-
uri: string;
|
|
467
|
-
protocol: number;
|
|
468
|
-
};
|
|
469
514
|
/**
|
|
470
515
|
* Every endpoint this node now serves, in its own preference order.
|
|
471
|
-
* Omitted leaves the target(s)' stored set untouched.
|
|
472
|
-
* over `transport_protocol`, whose first entry it also fills.
|
|
516
|
+
* Omitted leaves the target(s)' stored set untouched.
|
|
473
517
|
*/
|
|
474
|
-
own_transports?:
|
|
518
|
+
own_transports?: Endpoint[];
|
|
475
519
|
}
|
|
476
520
|
/**
|
|
477
521
|
* How long the protocol waits on each thing that can keep it waiting. Every
|
|
@@ -504,6 +548,15 @@ export interface Timeouts {
|
|
|
504
548
|
/** `ReplicaDiscovery` takes no parameters: the group and this device's own version
|
|
505
549
|
* are both read from the stores. The argument may be omitted entirely. */
|
|
506
550
|
export type ReplicaDiscoveryParams = Record<string, never>;
|
|
551
|
+
/** Any member may remove any member, the source included: a lost or stolen
|
|
552
|
+
* source must be removable by the devices that remain, and the library
|
|
553
|
+
* checks no role. Ask the user before starting this flow, above all when it
|
|
554
|
+
* names the source. Removing the source promotes the first remaining member
|
|
555
|
+
* in the order the channel store's `listReplicas` returns. The removed
|
|
556
|
+
* member is not asked and gets no event when told to leave: when a roster
|
|
557
|
+
* excluding it arrives it drops its whole `secret_id` partition and emits
|
|
558
|
+
* `SelfRemovedFromGroup`. The secret survives on the remaining members and
|
|
559
|
+
* the helpers. */
|
|
507
560
|
export interface UnpairReplicaParams {
|
|
508
561
|
/** The member to remove, as a **decimal** `u64` string — the same form
|
|
509
562
|
* `ReplicaPaired.peer_replica_id` hands back. A value naming no current
|
|
@@ -524,11 +577,30 @@ export type DeRecEvent = {
|
|
|
524
577
|
channel_id: string;
|
|
525
578
|
action: Uint8Array;
|
|
526
579
|
action_kind: PendingActionKind;
|
|
580
|
+
/** Correlation token of the inbound request, decimal-encoded. */
|
|
581
|
+
trace_id: string;
|
|
582
|
+
/** Pairing only. */
|
|
527
583
|
peer_communication_info?: Record<string, string>;
|
|
584
|
+
/** `sender_kind` of the inbound pair request (Pairing only). */
|
|
528
585
|
sender_kind?: SenderKind;
|
|
586
|
+
/** Share version (StoreShare / VerifyShare / GetShare). */
|
|
529
587
|
version?: number;
|
|
588
|
+
/** Description of the secret version (StoreShare only). */
|
|
530
589
|
share_description?: string;
|
|
590
|
+
/** Secret identifier, decimal-encoded (StoreShare / VerifyShare /
|
|
591
|
+
* GetShare). On GetShare, with `version`, names the requested share. */
|
|
531
592
|
share_secret_id?: string;
|
|
593
|
+
/** Length in bytes of the share the helper would store (StoreShare
|
|
594
|
+
* only) — what a size or quota decision is made on. */
|
|
595
|
+
share_size?: number;
|
|
596
|
+
/** The peer's memo (Unpair only). */
|
|
597
|
+
unpair_memo?: string;
|
|
598
|
+
/** Communication info the peer replaces its stored map with
|
|
599
|
+
* (UpdateChannelInfo only). Absent: unchanged. Empty: cleared. */
|
|
600
|
+
updated_communication_info?: Record<string, string>;
|
|
601
|
+
/** Endpoints the peer is moving to (UpdateChannelInfo only). Absent:
|
|
602
|
+
* unchanged. */
|
|
603
|
+
updated_transports?: Endpoint[];
|
|
532
604
|
} | {
|
|
533
605
|
type: "ShareStored";
|
|
534
606
|
channel_id: string;
|
|
@@ -541,7 +613,7 @@ export type DeRecEvent = {
|
|
|
541
613
|
type: "ShareRejected";
|
|
542
614
|
channel_id: string;
|
|
543
615
|
version: number;
|
|
544
|
-
status:
|
|
616
|
+
status: StatusEnum;
|
|
545
617
|
memo: string;
|
|
546
618
|
}
|
|
547
619
|
/** A publishing round finished — every targeted helper confirmed,
|
|
@@ -567,14 +639,17 @@ export type DeRecEvent = {
|
|
|
567
639
|
}
|
|
568
640
|
/** A group member refused a secret sync. Keyed by `replica_id`, not
|
|
569
641
|
* `channel_id`: every member answers on the one group channel. A
|
|
570
|
-
* `VERSION_CONFLICT` status means
|
|
571
|
-
*
|
|
642
|
+
* `VERSION_CONFLICT` status means another member holds a different copy
|
|
643
|
+
* of this version: do not publish from this device again until the
|
|
644
|
+
* conflict is resolved. Run `start(FlowKind.ReplicaDiscovery)` to receive
|
|
645
|
+
* the group's copy as `ReplicaVersionConflict`, merge, and publish the
|
|
646
|
+
* result once with `start(FlowKind.ProtectSecret)`. */
|
|
572
647
|
| {
|
|
573
648
|
type: "ReplicaSyncRejected";
|
|
574
649
|
replica_id: string;
|
|
575
650
|
secret_id: string;
|
|
576
651
|
version: number;
|
|
577
|
-
status:
|
|
652
|
+
status: StatusEnum;
|
|
578
653
|
memo: string;
|
|
579
654
|
}
|
|
580
655
|
/** A secret sync could not be delivered to a member at all — distinct from
|
|
@@ -602,7 +677,8 @@ export type DeRecEvent = {
|
|
|
602
677
|
/** This device left the group and dropped its whole `secret_id` partition —
|
|
603
678
|
* group channel, helper channels, shares, secrets and the snapshot. Fires
|
|
604
679
|
* only once it was told to leave *and* has since seen a roster excluding
|
|
605
|
-
* it; absence alone never destroys a copy of the secret.
|
|
680
|
+
* it; absence alone never destroys a copy of the secret. The teardown is
|
|
681
|
+
* automatic: this device is not asked first and gets no earlier event. */
|
|
606
682
|
| {
|
|
607
683
|
type: "SelfRemovedFromGroup";
|
|
608
684
|
version: number;
|
|
@@ -628,6 +704,16 @@ export type DeRecEvent = {
|
|
|
628
704
|
type: "ShareVerified";
|
|
629
705
|
channel_id: string;
|
|
630
706
|
version: number;
|
|
707
|
+
}
|
|
708
|
+
/** A helper refused a verification challenge: its response carried a
|
|
709
|
+
* non-OK `status` instead of a proof. The challenge is spent; a new
|
|
710
|
+
* `VerifyShares` round challenges the helper again. */
|
|
711
|
+
| {
|
|
712
|
+
type: "ShareVerifyRejected";
|
|
713
|
+
channel_id: string;
|
|
714
|
+
version: number;
|
|
715
|
+
status: StatusEnum;
|
|
716
|
+
memo: string;
|
|
631
717
|
} | {
|
|
632
718
|
type: "SecretsDiscovered";
|
|
633
719
|
channel_id: string;
|
|
@@ -648,6 +734,33 @@ export type DeRecEvent = {
|
|
|
648
734
|
shares_received: number;
|
|
649
735
|
error: string;
|
|
650
736
|
}
|
|
737
|
+
/** A helper refused a recovery share request: its response carried a
|
|
738
|
+
* non-OK `status` (e.g. `UNKNOWN_SHARE_VERSION`) instead of a share. The
|
|
739
|
+
* refusal is not collected — it does not count towards `shares_received`
|
|
740
|
+
* and the recovery stays open for the other helpers' shares — but it does
|
|
741
|
+
* answer that helper's `RecoverSecretStarted`. */
|
|
742
|
+
| {
|
|
743
|
+
type: "RecoveryShareRefused";
|
|
744
|
+
channel_id: string;
|
|
745
|
+
version: number;
|
|
746
|
+
status: StatusEnum;
|
|
747
|
+
memo: string;
|
|
748
|
+
}
|
|
749
|
+
/** A helper answered with a share that cannot be part of the secret;
|
|
750
|
+
* `reason` says how it failed. `Malformed` and `InvalidProof` are judged
|
|
751
|
+
* on arrival; `Inconsistent` (valid on its own but disagreeing with the
|
|
752
|
+
* shares the secret was rebuilt from) is reported alongside
|
|
753
|
+
* `SecretRecovered`, once per helper. The share is set aside — it does
|
|
754
|
+
* not count towards `shares_received` and never blocks the recovery. An
|
|
755
|
+
* honest helper never sends one, so the app may treat it as a sign of a
|
|
756
|
+
* damaged or compromised helper, e.g. offer to unpair it. It also
|
|
757
|
+
* answers that helper's `RecoverSecretStarted`. */
|
|
758
|
+
| {
|
|
759
|
+
type: "RecoveryShareCorrupted";
|
|
760
|
+
channel_id: string;
|
|
761
|
+
version: number;
|
|
762
|
+
reason: CorruptionReason;
|
|
763
|
+
}
|
|
651
764
|
/** Recovery completed — the typed `Secret` snapshot the owner
|
|
652
765
|
* originally protected. Mirrors `ReplicaSecretReceived.secret`:
|
|
653
766
|
* `secrets` is the user-facing `Vec<UserSecret>` the application
|
|
@@ -660,12 +773,9 @@ export type DeRecEvent = {
|
|
|
660
773
|
helpers: Array<{
|
|
661
774
|
channel_id: string;
|
|
662
775
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
663
|
-
transports:
|
|
664
|
-
uri: string;
|
|
665
|
-
protocol: number;
|
|
666
|
-
}>;
|
|
776
|
+
transports: Endpoint[];
|
|
667
777
|
shared_key: Uint8Array;
|
|
668
|
-
communication_info
|
|
778
|
+
communication_info?: Record<string, string>;
|
|
669
779
|
}>;
|
|
670
780
|
secrets: Array<{
|
|
671
781
|
id: Uint8Array;
|
|
@@ -685,12 +795,9 @@ export type DeRecEvent = {
|
|
|
685
795
|
members: Array<{
|
|
686
796
|
replica_id: string;
|
|
687
797
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
688
|
-
transports:
|
|
689
|
-
uri: string;
|
|
690
|
-
protocol: number;
|
|
691
|
-
}>;
|
|
798
|
+
transports: Endpoint[];
|
|
692
799
|
role: "Source" | "Destination";
|
|
693
|
-
communication_info
|
|
800
|
+
communication_info?: Record<string, string>;
|
|
694
801
|
}>;
|
|
695
802
|
shared_key: Uint8Array;
|
|
696
803
|
};
|
|
@@ -701,7 +808,7 @@ export type DeRecEvent = {
|
|
|
701
808
|
} | {
|
|
702
809
|
type: "UnpairRejected";
|
|
703
810
|
channel_id: string;
|
|
704
|
-
status:
|
|
811
|
+
status: StatusEnum;
|
|
705
812
|
memo: string;
|
|
706
813
|
}
|
|
707
814
|
/** Contact creator answered the scanner's `PrePairRequest` with a
|
|
@@ -710,7 +817,7 @@ export type DeRecEvent = {
|
|
|
710
817
|
| {
|
|
711
818
|
type: "PrePairRejected";
|
|
712
819
|
channel_id: string;
|
|
713
|
-
status:
|
|
820
|
+
status: StatusEnum;
|
|
714
821
|
memo: string;
|
|
715
822
|
}
|
|
716
823
|
/** Fires alongside `PairingCompleted` on replica-mode pair handshakes.
|
|
@@ -729,25 +836,28 @@ export type DeRecEvent = {
|
|
|
729
836
|
/** A `ReplicaSource` peer pushed a secret sync on a
|
|
730
837
|
* `ReplicaDestination` channel. The library decoded the
|
|
731
838
|
* `ReplicaSecretPayload`; the app installs `secret.secrets` and
|
|
732
|
-
* optionally uses `shares` for recovery. `from_replica_id
|
|
733
|
-
* `replica_id` fields inside `secret` are
|
|
734
|
-
* strings.
|
|
839
|
+
* optionally uses `shares` for recovery. `from_replica_id`,
|
|
840
|
+
* `author_replica_id` and the `replica_id` fields inside `secret` are
|
|
841
|
+
* `u64` as **decimal** strings.
|
|
842
|
+
*
|
|
843
|
+
* `from_replica_id` is the member this copy came from: the publisher on
|
|
844
|
+
* a push, the serving member on a catch-up. `author_replica_id` is the
|
|
845
|
+
* member that published `version`, or `null` when the serving member's
|
|
846
|
+
* snapshot records none. */
|
|
735
847
|
| {
|
|
736
848
|
type: "ReplicaSecretReceived";
|
|
737
849
|
channel_id: string;
|
|
738
850
|
from_replica_id: string;
|
|
851
|
+
author_replica_id: string | null;
|
|
739
852
|
secret_id: string;
|
|
740
853
|
version: number;
|
|
741
854
|
secret: {
|
|
742
855
|
helpers: Array<{
|
|
743
856
|
channel_id: string;
|
|
744
857
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
745
|
-
transports:
|
|
746
|
-
uri: string;
|
|
747
|
-
protocol: number;
|
|
748
|
-
}>;
|
|
858
|
+
transports: Endpoint[];
|
|
749
859
|
shared_key: Uint8Array;
|
|
750
|
-
communication_info
|
|
860
|
+
communication_info?: Record<string, string>;
|
|
751
861
|
}>;
|
|
752
862
|
secrets: Array<{
|
|
753
863
|
id: Uint8Array;
|
|
@@ -765,12 +875,9 @@ export type DeRecEvent = {
|
|
|
765
875
|
members: Array<{
|
|
766
876
|
replica_id: string;
|
|
767
877
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
768
|
-
transports:
|
|
769
|
-
uri: string;
|
|
770
|
-
protocol: number;
|
|
771
|
-
}>;
|
|
878
|
+
transports: Endpoint[];
|
|
772
879
|
role: "Source" | "Destination";
|
|
773
|
-
communication_info
|
|
880
|
+
communication_info?: Record<string, string>;
|
|
774
881
|
}>;
|
|
775
882
|
shared_key: Uint8Array;
|
|
776
883
|
};
|
|
@@ -793,18 +900,16 @@ export type DeRecEvent = {
|
|
|
793
900
|
type: "ReplicaSecretInstalled";
|
|
794
901
|
channel_id: string;
|
|
795
902
|
from_replica_id: string;
|
|
903
|
+
author_replica_id: string | null;
|
|
796
904
|
secret_id: string;
|
|
797
905
|
version: number;
|
|
798
906
|
secret: {
|
|
799
907
|
helpers: Array<{
|
|
800
908
|
channel_id: string;
|
|
801
909
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
802
|
-
transports:
|
|
803
|
-
uri: string;
|
|
804
|
-
protocol: number;
|
|
805
|
-
}>;
|
|
910
|
+
transports: Endpoint[];
|
|
806
911
|
shared_key: Uint8Array;
|
|
807
|
-
communication_info
|
|
912
|
+
communication_info?: Record<string, string>;
|
|
808
913
|
}>;
|
|
809
914
|
secrets: Array<{
|
|
810
915
|
id: Uint8Array;
|
|
@@ -822,12 +927,9 @@ export type DeRecEvent = {
|
|
|
822
927
|
members: Array<{
|
|
823
928
|
replica_id: string;
|
|
824
929
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
825
|
-
transports:
|
|
826
|
-
uri: string;
|
|
827
|
-
protocol: number;
|
|
828
|
-
}>;
|
|
930
|
+
transports: Endpoint[];
|
|
829
931
|
role: "Source" | "Destination";
|
|
830
|
-
communication_info
|
|
932
|
+
communication_info?: Record<string, string>;
|
|
831
933
|
}>;
|
|
832
934
|
shared_key: Uint8Array;
|
|
833
935
|
};
|
|
@@ -837,6 +939,59 @@ export type DeRecEvent = {
|
|
|
837
939
|
committed_share: Uint8Array;
|
|
838
940
|
}>;
|
|
839
941
|
}
|
|
942
|
+
/** A member offered a different copy of the version this device holds.
|
|
943
|
+
* Nothing was written: this device keeps its own copy and refuses the
|
|
944
|
+
* incoming one with `VERSION_CONFLICT`, so the publisher sees
|
|
945
|
+
* `ReplicaSyncRejected`. Both copies are complete states — the held one
|
|
946
|
+
* is in the local stores, the incoming one is `secret`. Resolve by
|
|
947
|
+
* publishing the chosen state with `start(FlowKind.ProtectSecret)`; the
|
|
948
|
+
* next version supersedes both on every member and helper. Until then,
|
|
949
|
+
* do not publish from this device: any further `ProtectSecret` is a
|
|
950
|
+
* higher version that every other member applies over its own copy,
|
|
951
|
+
* losing the change it never merged.
|
|
952
|
+
*
|
|
953
|
+
* `held_author_replica_id` / `incoming_author_replica_id` are the
|
|
954
|
+
* decimal `replica_id` of each copy's publisher, or `null` when that
|
|
955
|
+
* copy records none. */
|
|
956
|
+
| {
|
|
957
|
+
type: "ReplicaVersionConflict";
|
|
958
|
+
channel_id: string;
|
|
959
|
+
from_replica_id: string;
|
|
960
|
+
secret_id: string;
|
|
961
|
+
version: number;
|
|
962
|
+
held_author_replica_id: string | null;
|
|
963
|
+
incoming_author_replica_id: string | null;
|
|
964
|
+
secret: {
|
|
965
|
+
helpers: Array<{
|
|
966
|
+
channel_id: string;
|
|
967
|
+
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
968
|
+
transports: Endpoint[];
|
|
969
|
+
shared_key: Uint8Array;
|
|
970
|
+
communication_info?: Record<string, string>;
|
|
971
|
+
}>;
|
|
972
|
+
secrets: Array<{
|
|
973
|
+
id: Uint8Array;
|
|
974
|
+
name: string;
|
|
975
|
+
data: Uint8Array;
|
|
976
|
+
}>;
|
|
977
|
+
/** The same shape as `SecretRecovered.secret.replicas`. */
|
|
978
|
+
replicas?: {
|
|
979
|
+
/** The one channel every member is addressed on. */
|
|
980
|
+
channel_id: string;
|
|
981
|
+
/** Every member of the group, including the writer. Exactly one
|
|
982
|
+
* carries `role: "Source"` — that member is where the secret
|
|
983
|
+
* originated, which is why no separate owner field is needed. */
|
|
984
|
+
members: Array<{
|
|
985
|
+
replica_id: string;
|
|
986
|
+
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
987
|
+
transports: Endpoint[];
|
|
988
|
+
role: "Source" | "Destination";
|
|
989
|
+
communication_info?: Record<string, string>;
|
|
990
|
+
}>;
|
|
991
|
+
shared_key: Uint8Array;
|
|
992
|
+
};
|
|
993
|
+
};
|
|
994
|
+
}
|
|
840
995
|
/** Peer's ack of a secret sync we sent. `status` is the `StatusEnum`
|
|
841
996
|
* integer (0 = Ok), `memo` is the peer's explanation. */
|
|
842
997
|
| {
|
|
@@ -845,7 +1000,7 @@ export type DeRecEvent = {
|
|
|
845
1000
|
from_replica_id: string;
|
|
846
1001
|
secret_id: string;
|
|
847
1002
|
version: number;
|
|
848
|
-
status:
|
|
1003
|
+
status: StatusEnum;
|
|
849
1004
|
memo: string;
|
|
850
1005
|
}
|
|
851
1006
|
/** A peer announced an updated `communication_info` map and/or
|
|
@@ -862,7 +1017,7 @@ export type DeRecEvent = {
|
|
|
862
1017
|
| {
|
|
863
1018
|
type: "ChannelInfoUpdateRejected";
|
|
864
1019
|
channel_id: string;
|
|
865
|
-
status:
|
|
1020
|
+
status: StatusEnum;
|
|
866
1021
|
memo: string;
|
|
867
1022
|
}
|
|
868
1023
|
/** Emitted by `process()` in place of `ActionRequired` when the
|
|
@@ -879,6 +1034,38 @@ export type DeRecEvent = {
|
|
|
879
1034
|
} | {
|
|
880
1035
|
type: "NoOp";
|
|
881
1036
|
}
|
|
1037
|
+
/** An inbound message was dropped untouched: no store was written and
|
|
1038
|
+
* nothing was sent back. `reason` says why.
|
|
1039
|
+
*
|
|
1040
|
+
* `"PendingVerification"` means the peer sent something before this
|
|
1041
|
+
* device confirmed the channel's fingerprint — typically a replica source
|
|
1042
|
+
* pushing its first copy while this destination still shows the code.
|
|
1043
|
+
* Confirming does not replay it: after `verifyFingerprint` succeeds, a
|
|
1044
|
+
* replica destination calls `start(FlowKind.ReplicaDiscovery)` to pull
|
|
1045
|
+
* the copy itself. `"Expired"` means the message was older than the
|
|
1046
|
+
* inbound timeout. `trace_id` matches the peer's `*Started` event for
|
|
1047
|
+
* the same round (`"0"` when the sender set none). */
|
|
1048
|
+
| {
|
|
1049
|
+
type: "MessageIgnored";
|
|
1050
|
+
channel_id: string;
|
|
1051
|
+
reason: IgnoreReason;
|
|
1052
|
+
trace_id: string;
|
|
1053
|
+
}
|
|
1054
|
+
/** Returned by `restore`: a roster entry got no channel, so this device
|
|
1055
|
+
* cannot reach that peer. Every other entry and the user-secret snapshot
|
|
1056
|
+
* were restored; `reason` says why this one was not. `"NoTransports"`
|
|
1057
|
+
* means the recovered roster names no endpoint for it.
|
|
1058
|
+
*
|
|
1059
|
+
* For a helper, `channel_id` is its channel and `replica_id` is absent.
|
|
1060
|
+
* For a replica group member, `channel_id` is the group's channel and
|
|
1061
|
+
* `replica_id` names the member. The peer itself is untouched — a helper
|
|
1062
|
+
* still holds its share — and pairing with it again makes it reachable. */
|
|
1063
|
+
| {
|
|
1064
|
+
type: "PeerNotRestored";
|
|
1065
|
+
channel_id: string;
|
|
1066
|
+
replica_id?: string;
|
|
1067
|
+
reason: NotRestoredReason;
|
|
1068
|
+
}
|
|
882
1069
|
/** A pairing handshake was dispatched successfully. `kind` is the
|
|
883
1070
|
* local party's role — same value the subsequent `PairingCompleted`
|
|
884
1071
|
* will carry. Emitted by `start(Pairing)`. */
|
|
@@ -989,8 +1176,8 @@ export type DeRecEvent = {
|
|
|
989
1176
|
* inbound shares. The protocol enforces no size, quota or rate limit
|
|
990
1177
|
* of its own, and `maxShareSize` is checked for range overlap at
|
|
991
1178
|
* pairing time only, never against an actual share. While this is
|
|
992
|
-
* `false`, `ActionRequired` carries
|
|
993
|
-
*
|
|
1179
|
+
* `false`, `ActionRequired` carries `share_size`, so the application
|
|
1180
|
+
* can compare it to its quota and call `reject()` with
|
|
994
1181
|
* `StatusEnum.SizeLimitExceeded`. Setting it `true` removes that
|
|
995
1182
|
* opportunity entirely: every share from every paired Owner is stored
|
|
996
1183
|
* unconditionally, at whatever size it arrives. Keep off in any
|
|
@@ -1066,6 +1253,19 @@ export interface CommunicationInfoKeyValue {
|
|
|
1066
1253
|
export interface CommunicationInfo {
|
|
1067
1254
|
communication_info_entries: CommunicationInfoKeyValue[];
|
|
1068
1255
|
}
|
|
1256
|
+
/** Why a `MessageIgnored` event dropped a message. Matches the Rust
|
|
1257
|
+
* `IgnoreReason` discriminants one-for-one. */
|
|
1258
|
+
export type IgnoreReason = "PendingVerification" | "Expired";
|
|
1259
|
+
/** Why a `PeerNotRestored` event left a roster entry without a channel.
|
|
1260
|
+
* Matches the Rust `NotRestoredReason` discriminants one-for-one. */
|
|
1261
|
+
export type NotRestoredReason = "NoTransports";
|
|
1262
|
+
/** Why a `RecoveryShareCorrupted` event set a helper's share aside.
|
|
1263
|
+
* Matches the Rust `CorruptionReason` discriminants one-for-one:
|
|
1264
|
+
* `Malformed` — no decodable share for the requested secret and version;
|
|
1265
|
+
* `InvalidProof` — the share fails its own Merkle proof;
|
|
1266
|
+
* `Inconsistent` — valid on its own, but its commitment root or ciphertext
|
|
1267
|
+
* disagrees with the shares the secret was rebuilt from. */
|
|
1268
|
+
export type CorruptionReason = "Malformed" | "InvalidProof" | "Inconsistent";
|
|
1069
1269
|
/**
|
|
1070
1270
|
* The label vocabulary for `ActionRequired.action_kind` and
|
|
1071
1271
|
* `AutoAccepted.action_kind` — one value per pending-action kind the
|
|
@@ -1092,17 +1292,9 @@ export interface PairRequestMessage {
|
|
|
1092
1292
|
nonce: bigint;
|
|
1093
1293
|
communication_info?: CommunicationInfo;
|
|
1094
1294
|
parameter_range?: ParameterRange;
|
|
1095
|
-
/**
|
|
1096
|
-
* @deprecated Reading this field directly is incorrect: its meaning narrowed
|
|
1097
|
-
* to "one entry of a list, and possibly absent", so a peer advertising only
|
|
1098
|
-
* `supported_transports` looks unreachable to a reader that was correct
|
|
1099
|
-
* before 0.0.3. Call {@link advertisedEndpoints}, which resolves both
|
|
1100
|
-
* spellings. Removed at 0.0.5.
|
|
1101
|
-
*/
|
|
1102
|
-
transport_protocol?: TransportProtocol;
|
|
1103
1295
|
timestamp?: Timestamp;
|
|
1104
1296
|
/** Every transport endpoint the initiator can be reached on, in its own
|
|
1105
|
-
* preference order.
|
|
1297
|
+
* preference order. */
|
|
1106
1298
|
supported_transports: TransportProtocol[];
|
|
1107
1299
|
}
|
|
1108
1300
|
export interface PairResponseMessage {
|
|
@@ -1122,21 +1314,12 @@ export interface PairResponseMessage {
|
|
|
1122
1314
|
}
|
|
1123
1315
|
export interface PrePairRequestMessage {
|
|
1124
1316
|
nonce: bigint;
|
|
1125
|
-
/**
|
|
1126
|
-
* @deprecated Reading this field directly is incorrect: its meaning narrowed
|
|
1127
|
-
* to "one entry of a list, and possibly absent", so a peer advertising only
|
|
1128
|
-
* `supported_transports` looks unreachable to a reader that was correct
|
|
1129
|
-
* before 0.0.3. Call {@link advertisedEndpoints}, which resolves both
|
|
1130
|
-
* spellings. Removed at 0.0.5.
|
|
1131
|
-
*/
|
|
1132
|
-
transport_protocol?: TransportProtocol;
|
|
1133
1317
|
timestamp?: Timestamp;
|
|
1134
1318
|
/**
|
|
1135
1319
|
* Every endpoint the sender can be reached on for the PrePair reply, in
|
|
1136
|
-
* its own preference order.
|
|
1137
|
-
* must be present.
|
|
1320
|
+
* its own preference order.
|
|
1138
1321
|
*/
|
|
1139
|
-
supported_transports
|
|
1322
|
+
supported_transports: TransportProtocol[];
|
|
1140
1323
|
}
|
|
1141
1324
|
export interface PrePairResponseMessage {
|
|
1142
1325
|
result?: DeRecResult;
|
|
@@ -1292,6 +1475,12 @@ export interface PairingProcessResult {
|
|
|
1292
1475
|
export interface ProducePrePairResult {
|
|
1293
1476
|
envelope: Uint8Array;
|
|
1294
1477
|
}
|
|
1478
|
+
export interface ProducePrePairNoKeysResult {
|
|
1479
|
+
envelope: Uint8Array;
|
|
1480
|
+
/** Secret key material generated for this pairing. The caller MUST persist
|
|
1481
|
+
* it: the `PairRequest` that follows is encrypted to it. */
|
|
1482
|
+
secret_key_material: Uint8Array;
|
|
1483
|
+
}
|
|
1295
1484
|
export interface PrePairRequestExtractResult {
|
|
1296
1485
|
request: PrePairRequestMessage;
|
|
1297
1486
|
}
|