@derec-alliance/react-native 0.0.8 → 0.0.9
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 +394 -6
- 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 +9 -0
- package/cpp/Convert.h +8 -2
- package/cpp/Primitives.cpp +113 -25
- package/cpp/StoreCallbacks.cpp +119 -20
- package/cpp/StoreCallbacks.h +8 -1
- package/cpp/derec_ffi.h +83 -15
- package/ios/DeRecFFI.xcframework/ios-arm64/Headers/derec_ffi.h +83 -15
- package/ios/DeRecFFI.xcframework/ios-arm64/libderec_library.a +0 -0
- package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/Headers/derec_ffi.h +83 -15
- package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/libderec_library.a +2 -2
- package/lib/errors.d.ts +11 -1
- package/lib/errors.js +63 -1
- package/lib/primitives.d.ts +2 -2
- package/lib/primitives.js +3 -1
- package/lib/protocol.d.ts +102 -6
- package/lib/protocol.js +158 -7
- package/lib/types.d.ts +426 -28
- package/lib/types.js +19 -0
- package/package.json +1 -1
- package/src/errors.ts +66 -1
- package/src/primitives.ts +13 -2
- package/src/protocol.ts +166 -8
- package/src/types.ts +432 -29
package/lib/types.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.channelFilterMatches = channelFilterMatches;
|
|
|
7
7
|
exports.advertisedEndpoints = advertisedEndpoints;
|
|
8
8
|
exports.protocol_version = protocol_version;
|
|
9
9
|
exports.generate_replica_id = generate_replica_id;
|
|
10
|
+
exports.shareStoreRefusal = shareStoreRefusal;
|
|
10
11
|
exports.sequentialFailover = sequentialFailover;
|
|
11
12
|
exports.singleEndpointTransport = singleEndpointTransport;
|
|
12
13
|
const native_1 = require("./native");
|
|
@@ -65,6 +66,24 @@ function protocol_version() {
|
|
|
65
66
|
function generate_replica_id() {
|
|
66
67
|
return (0, native_1.getNative)().generate_replica_id();
|
|
67
68
|
}
|
|
69
|
+
const SHARE_STORE_REFUSAL_REASONS = [
|
|
70
|
+
"too_frequent",
|
|
71
|
+
"size_limit_exceeded",
|
|
72
|
+
"rejected",
|
|
73
|
+
];
|
|
74
|
+
/**
|
|
75
|
+
* Builds the `Error` a `ShareStore`'s `save`/`recordVerification` throws, or
|
|
76
|
+
* rejects its promise with, to refuse the call: `reason` tagged onto the
|
|
77
|
+
* error's `refusal` property.
|
|
78
|
+
*/
|
|
79
|
+
function shareStoreRefusal(reason) {
|
|
80
|
+
if (!SHARE_STORE_REFUSAL_REASONS.includes(reason)) {
|
|
81
|
+
throw new Error(`unknown share store refusal reason ${JSON.stringify(reason)}; expected one of ${JSON.stringify(SHARE_STORE_REFUSAL_REASONS)}`);
|
|
82
|
+
}
|
|
83
|
+
const error = new Error(`share store refused: ${reason}`);
|
|
84
|
+
error.refusal = reason;
|
|
85
|
+
return error;
|
|
86
|
+
}
|
|
68
87
|
/**
|
|
69
88
|
* Builds a {@link Transport} that tries each endpoint in the order the peer
|
|
70
89
|
* offered it and stops at the first success.
|
package/package.json
CHANGED
package/src/errors.ts
CHANGED
|
@@ -36,9 +36,74 @@ export const DEREC_ERROR_CATEGORIES = [
|
|
|
36
36
|
|
|
37
37
|
export type DeRecErrorCategory = (typeof DEREC_ERROR_CATEGORIES)[number];
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Every code `derec_error_code_name` can return, and no others.
|
|
41
|
+
*
|
|
42
|
+
* Held to the shared enum fixture by a test, like {@link DEREC_ERROR_CATEGORIES}.
|
|
43
|
+
* Unlike the WASM bindings, this SDK raises no marshalling-level codes of its
|
|
44
|
+
* own before a value reaches the library, so this list is exactly the Rust
|
|
45
|
+
* `Code` table in `library/src/interop/error_codes.rs`.
|
|
46
|
+
*/
|
|
47
|
+
export const DEREC_ERROR_CODES = [
|
|
48
|
+
"ok",
|
|
49
|
+
"non_ok_status",
|
|
50
|
+
"version_mismatch",
|
|
51
|
+
"invariant",
|
|
52
|
+
"invalid_input",
|
|
53
|
+
"protobuf_decode",
|
|
54
|
+
"protobuf_encode",
|
|
55
|
+
"protocol_violation",
|
|
56
|
+
"store_error",
|
|
57
|
+
"builder_error",
|
|
58
|
+
"missing_shared_key",
|
|
59
|
+
"role_mismatch",
|
|
60
|
+
"replica_id_not_configured",
|
|
61
|
+
"channel_already_paired",
|
|
62
|
+
"already_restored",
|
|
63
|
+
"restore_conflict",
|
|
64
|
+
"replica_id_conflict",
|
|
65
|
+
"encryption",
|
|
66
|
+
"keygen",
|
|
67
|
+
"finish_pairing_initiator",
|
|
68
|
+
"finish_pairing_responder",
|
|
69
|
+
"empty_transport_uri",
|
|
70
|
+
"invalid_contact_message",
|
|
71
|
+
"invalid_pair_request_message",
|
|
72
|
+
"invalid_pair_response_message",
|
|
73
|
+
"prepair_hash_mismatch",
|
|
74
|
+
"missing_replica_id",
|
|
75
|
+
"unexpected_replica_id",
|
|
76
|
+
"incompatible_parameter_range",
|
|
77
|
+
"empty_channels",
|
|
78
|
+
"duplicate_channel_id",
|
|
79
|
+
"invalid_threshold",
|
|
80
|
+
"empty_secret_data",
|
|
81
|
+
"vss_share_failed",
|
|
82
|
+
"invalid_weight",
|
|
83
|
+
"too_many_subshares",
|
|
84
|
+
"empty_responses",
|
|
85
|
+
"empty_committed_derec_share",
|
|
86
|
+
"decode_committed_derec_share",
|
|
87
|
+
"decode_derec_share",
|
|
88
|
+
"secret_id_mismatch",
|
|
89
|
+
"reconstruction_failed",
|
|
90
|
+
"malformed_recovered_secret",
|
|
91
|
+
"ffi_null_ptr",
|
|
92
|
+
"ffi_bad_length",
|
|
93
|
+
"ffi_bad_utf8",
|
|
94
|
+
"ffi_bad_proto",
|
|
95
|
+
"ffi_invalid_enum",
|
|
96
|
+
"ffi_bad_shared_key",
|
|
97
|
+
"ffi_nul_in_string",
|
|
98
|
+
"transport_invalid",
|
|
99
|
+
"no_usable_endpoint",
|
|
100
|
+
] as const;
|
|
101
|
+
|
|
102
|
+
export type DeRecErrorCode = (typeof DEREC_ERROR_CODES)[number];
|
|
103
|
+
|
|
39
104
|
export interface DeRecError {
|
|
40
105
|
category: DeRecErrorCategory;
|
|
41
|
-
code:
|
|
106
|
+
code: DeRecErrorCode;
|
|
42
107
|
message: string;
|
|
43
108
|
status?: number;
|
|
44
109
|
memo?: string;
|
package/src/primitives.ts
CHANGED
|
@@ -71,6 +71,7 @@ import type {
|
|
|
71
71
|
UnpairingProcessResult,
|
|
72
72
|
VerifyShareRequestMessage,
|
|
73
73
|
VerifyShareResponseMessage,
|
|
74
|
+
WeightedChannel,
|
|
74
75
|
} from './types';
|
|
75
76
|
|
|
76
77
|
/** Shape of the `__DeRec` host object: every member is a plain callable, since
|
|
@@ -593,13 +594,23 @@ const recovery = {
|
|
|
593
594
|
const sharing = {
|
|
594
595
|
request: {
|
|
595
596
|
split(
|
|
596
|
-
channels:
|
|
597
|
+
channels: WeightedChannel[],
|
|
597
598
|
secret_id: bigint,
|
|
598
599
|
version: number,
|
|
599
600
|
secret_data: Uint8Array,
|
|
600
601
|
threshold: number,
|
|
601
602
|
): SplitResult {
|
|
602
|
-
const
|
|
603
|
+
const ids = channels.map(([channelId]) => BigInt(channelId));
|
|
604
|
+
const weights = channels.map(([, weight]) => weight);
|
|
605
|
+
const packed = call(
|
|
606
|
+
'protect_secret',
|
|
607
|
+
secret_id,
|
|
608
|
+
secret_data,
|
|
609
|
+
ids,
|
|
610
|
+
weights,
|
|
611
|
+
threshold,
|
|
612
|
+
version,
|
|
613
|
+
);
|
|
603
614
|
const shares = new Map<bigint, CommittedDeRecShare>();
|
|
604
615
|
for (const entry of decodeCommittedShareEntries(packed as ArrayBuffer)) {
|
|
605
616
|
shares.set(
|
package/src/protocol.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
ContactMessage,
|
|
12
12
|
ContactMode,
|
|
13
13
|
DeRecEvent,
|
|
14
|
+
DeRecProtocolConfig,
|
|
14
15
|
Endpoint,
|
|
15
16
|
DiscoveryParams,
|
|
16
17
|
PairingParams,
|
|
@@ -31,6 +32,7 @@ import type {
|
|
|
31
32
|
UpdateChannelInfoParams,
|
|
32
33
|
UserSecretStore,
|
|
33
34
|
VerifySharesParams,
|
|
35
|
+
StoresInit,
|
|
34
36
|
} from './types';
|
|
35
37
|
|
|
36
38
|
/** Shape of the `__DeRec` host object as seen from this file: every member is
|
|
@@ -113,13 +115,23 @@ export function buildProtectSecretParams(params: ProtectSecretParams): Record<st
|
|
|
113
115
|
if (params.description !== undefined) {
|
|
114
116
|
out.description = params.description;
|
|
115
117
|
}
|
|
118
|
+
if (params.weights != null && params.weights.size > 0) {
|
|
119
|
+
const weights: Record<string, number> = {};
|
|
120
|
+
for (const [id, weight] of params.weights) {
|
|
121
|
+
weights[id.toString()] = weight;
|
|
122
|
+
}
|
|
123
|
+
out.weights = weights;
|
|
124
|
+
}
|
|
125
|
+
if (params.threshold != null) {
|
|
126
|
+
out.threshold = params.threshold;
|
|
127
|
+
}
|
|
116
128
|
return out;
|
|
117
129
|
}
|
|
118
130
|
|
|
119
131
|
function communicationInfoOrOmit(
|
|
120
|
-
info: Record<string, string> | undefined,
|
|
132
|
+
info: Record<string, string> | null | undefined,
|
|
121
133
|
): Record<string, string> | undefined {
|
|
122
|
-
return info
|
|
134
|
+
return info != null && Object.keys(info).length > 0 ? info : undefined;
|
|
123
135
|
}
|
|
124
136
|
|
|
125
137
|
/**
|
|
@@ -127,9 +139,12 @@ function communicationInfoOrOmit(
|
|
|
127
139
|
* `SecretWire`'s own shape: `channel_id`/`replica_id` are the decimal `u64`
|
|
128
140
|
* strings the `SecretRecovered` event already carries, forwarded verbatim;
|
|
129
141
|
* `communication_info` is omitted per-entry (not sent as `{}`) whenever a
|
|
130
|
-
* helper or replica member has none
|
|
131
|
-
* the
|
|
132
|
-
*
|
|
142
|
+
* helper or replica member has none — `undefined`, `null`, or an empty map
|
|
143
|
+
* are all treated the same — matching the Go SDK's `omitempty` and the
|
|
144
|
+
* shared golden fixture byte-for-byte; `weight` is forwarded as given
|
|
145
|
+
* whenever a helper carries one; `replicas` is omitted entirely when the
|
|
146
|
+
* recovered secret has no replica group, and `threshold` when the roster
|
|
147
|
+
* records none.
|
|
133
148
|
*
|
|
134
149
|
* Exported so it can be golden-tested against the shared wire fixture
|
|
135
150
|
* without a native module.
|
|
@@ -149,6 +164,9 @@ export function buildRestoreParams(
|
|
|
149
164
|
if (info !== undefined) {
|
|
150
165
|
out.communication_info = info;
|
|
151
166
|
}
|
|
167
|
+
if (helper.weight !== undefined) {
|
|
168
|
+
out.weight = helper.weight;
|
|
169
|
+
}
|
|
152
170
|
return out;
|
|
153
171
|
}),
|
|
154
172
|
secrets: recoveredSecret.secrets.map((secret) => ({
|
|
@@ -175,6 +193,9 @@ export function buildRestoreParams(
|
|
|
175
193
|
shared_key: Array.from(recoveredSecret.replicas.shared_key),
|
|
176
194
|
};
|
|
177
195
|
}
|
|
196
|
+
if (recoveredSecret.threshold != null) {
|
|
197
|
+
recovered.threshold = recoveredSecret.threshold;
|
|
198
|
+
}
|
|
178
199
|
return { version, recovered_secret: recovered };
|
|
179
200
|
}
|
|
180
201
|
|
|
@@ -321,6 +342,20 @@ export class DeRecProtocolBuilder {
|
|
|
321
342
|
return this;
|
|
322
343
|
}
|
|
323
344
|
|
|
345
|
+
/**
|
|
346
|
+
* Set every store in one call. Forwards to {@link withChannelStore},
|
|
347
|
+
* {@link withShareStore}, {@link withSecretStore},
|
|
348
|
+
* {@link withUserSecretStore} and {@link withStateStore} in turn, so
|
|
349
|
+
* calling one of them again afterwards replaces just that store.
|
|
350
|
+
*/
|
|
351
|
+
withStores(stores: StoresInit): this {
|
|
352
|
+
return this.withChannelStore(stores.channelStore)
|
|
353
|
+
.withShareStore(stores.shareStore)
|
|
354
|
+
.withSecretStore(stores.secretStore)
|
|
355
|
+
.withUserSecretStore(stores.userSecretStore)
|
|
356
|
+
.withStateStore(stores.stateStore);
|
|
357
|
+
}
|
|
358
|
+
|
|
324
359
|
withTransport(transport: Transport): this {
|
|
325
360
|
this.stores.transport = transport;
|
|
326
361
|
return this;
|
|
@@ -346,7 +381,22 @@ export class DeRecProtocolBuilder {
|
|
|
346
381
|
return this;
|
|
347
382
|
}
|
|
348
383
|
|
|
349
|
-
/**
|
|
384
|
+
/**
|
|
385
|
+
* The starting threshold: the minimum number of subshares required to
|
|
386
|
+
* reconstruct the secret, for a secret with no threshold stored. Every
|
|
387
|
+
* publish stores the threshold it used (`UserSecrets.threshold`), the
|
|
388
|
+
* roster carries it, and `restore` and replica hydration put it back. A
|
|
389
|
+
* round splits at `ProtectSecretParams.threshold`, otherwise at the stored
|
|
390
|
+
* threshold, and only otherwise at this value, so changing it later does
|
|
391
|
+
* not change a stored threshold.
|
|
392
|
+
*
|
|
393
|
+
* A Helper holds one subshare unless `ProtectSecretParams.weights` has
|
|
394
|
+
* given it a weight, so with no weights the threshold is a number of
|
|
395
|
+
* Helpers, as before. Every weight must be below the round's threshold, so
|
|
396
|
+
* no single Helper can recover alone. When this value applies and is
|
|
397
|
+
* lowered to or below a stored weight, every publish fails with
|
|
398
|
+
* `invalid_weight` until `ProtectSecret` assigns valid weights. Default: 3.
|
|
399
|
+
*/
|
|
350
400
|
withThreshold(threshold: number): this {
|
|
351
401
|
this.config.threshold = threshold;
|
|
352
402
|
return this;
|
|
@@ -382,7 +432,12 @@ export class DeRecProtocolBuilder {
|
|
|
382
432
|
return this;
|
|
383
433
|
}
|
|
384
434
|
|
|
385
|
-
/**
|
|
435
|
+
/**
|
|
436
|
+
* Who answers an inbound request whose handling failed. `true`: the
|
|
437
|
+
* library sends the response itself. `false`: nothing is sent, and the
|
|
438
|
+
* `RequestFailed` event carries a token to pass to `reject`. Default:
|
|
439
|
+
* false.
|
|
440
|
+
*/
|
|
386
441
|
withAutoRespondOnFailure(enabled: boolean): this {
|
|
387
442
|
this.config.auto_respond_on_failure = enabled;
|
|
388
443
|
return this;
|
|
@@ -436,6 +491,10 @@ export class DeRecProtocolBuilder {
|
|
|
436
491
|
* applies its default.
|
|
437
492
|
*
|
|
438
493
|
* Default: unset — no constraints advertised, every peer range accepted.
|
|
494
|
+
*
|
|
495
|
+
* Share size is enforced by the helper; frequency limits are enforced by
|
|
496
|
+
* the app's share store (refuse from `save`/`recordVerification`); the
|
|
497
|
+
* deletion and deactivation timeouts are checked at pairing only.
|
|
439
498
|
*/
|
|
440
499
|
withParameterRange(range: Partial<ParameterRange>): this {
|
|
441
500
|
this.config.parameter_range = {
|
|
@@ -455,11 +514,89 @@ export class DeRecProtocolBuilder {
|
|
|
455
514
|
return this;
|
|
456
515
|
}
|
|
457
516
|
|
|
517
|
+
/**
|
|
518
|
+
* Cap the total number of subshares one sharing round may split the
|
|
519
|
+
* secret into — the sum of every helper's weight. Crosses to the library
|
|
520
|
+
* as a decimal string. Default: unset, no cap.
|
|
521
|
+
*
|
|
522
|
+
* Checked only by `start(ProtectSecret)`, including the publishes the
|
|
523
|
+
* library starts itself: a round over the cap fails with
|
|
524
|
+
* `too_many_subshares` before anything is sent. Recovery applies no cap.
|
|
525
|
+
* Recovering costs time that grows quadratically with the total number of
|
|
526
|
+
* subshares, so the cap bounds what a later recovery must do. A cap below
|
|
527
|
+
* the threshold makes `build()` throw.
|
|
528
|
+
*/
|
|
529
|
+
withMaxSubshares(max: bigint | number): this {
|
|
530
|
+
this.config.max_subshares = BigInt(max).toString();
|
|
531
|
+
return this;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Layer a {@link DeRecProtocolConfig} onto the builder: a field the config
|
|
536
|
+
* sets (present and not `null`) replaces what the builder currently
|
|
537
|
+
* holds, a field it leaves unset is untouched, and `timeouts` merges per
|
|
538
|
+
* field against the builder's current timeouts rather than resetting the
|
|
539
|
+
* other three. Every other nested object replaces as a whole. Apply a
|
|
540
|
+
* general config, then a per-user one, then any individual `with*` call —
|
|
541
|
+
* the last write wins per field, same as two `withConfig` calls in a row.
|
|
542
|
+
*
|
|
543
|
+
* Every key is assigned verbatim into the same `snake_case` config JSON
|
|
544
|
+
* `build()` sends to `protocol_new`, whatever it is spelled as: nothing
|
|
545
|
+
* here validates, defaults, or recognizes field names. Rust does both —
|
|
546
|
+
* `deny_unknown_fields` is what turns a misspelled key into an error.
|
|
547
|
+
*
|
|
548
|
+
* `secret_id` is not a config field — it is the constructor argument —
|
|
549
|
+
* and `build()` always sends the constructor's value last, so a config
|
|
550
|
+
* (e.g. loaded from a per-user record) can never redirect which secret
|
|
551
|
+
* this instance manages even if it carries a `secret_id` key.
|
|
552
|
+
*
|
|
553
|
+
* A config parsed from JSON can carry an own `__proto__` key. Assigning
|
|
554
|
+
* it through plain bracket notation would hit the accessor
|
|
555
|
+
* `Object.prototype` defines for that name and replace this builder's
|
|
556
|
+
* config object's prototype instead of setting a field on it — the value
|
|
557
|
+
* would then vanish from the JSON payload instead of reaching Rust to be
|
|
558
|
+
* rejected as an unknown key. `Object.defineProperty` makes it a genuine
|
|
559
|
+
* own property, the same as every other key here.
|
|
560
|
+
*/
|
|
561
|
+
withConfig(config: DeRecProtocolConfig): this {
|
|
562
|
+
for (const [key, value] of Object.entries(config as Record<string, unknown>)) {
|
|
563
|
+
if (value === undefined || value === null) {
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
566
|
+
if (key === 'timeouts') {
|
|
567
|
+
const held = (this.config.timeouts as Record<string, unknown> | undefined) ?? {};
|
|
568
|
+
const merged: Record<string, unknown> = { ...held };
|
|
569
|
+
for (const [timeoutKey, timeoutValue] of Object.entries(
|
|
570
|
+
value as Record<string, unknown>,
|
|
571
|
+
)) {
|
|
572
|
+
if (timeoutValue !== undefined && timeoutValue !== null) {
|
|
573
|
+
merged[timeoutKey] = timeoutValue;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
this.config.timeouts = merged;
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
if (key === '__proto__') {
|
|
580
|
+
Object.defineProperty(this.config, key, {
|
|
581
|
+
value,
|
|
582
|
+
writable: true,
|
|
583
|
+
enumerable: true,
|
|
584
|
+
configurable: true,
|
|
585
|
+
});
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
this.config[key] = value;
|
|
589
|
+
}
|
|
590
|
+
return this;
|
|
591
|
+
}
|
|
592
|
+
|
|
458
593
|
build(): DeRecProtocol {
|
|
459
594
|
const config = {
|
|
460
|
-
secret_id: this.secretIdValue.toString(),
|
|
461
595
|
replica_id: null,
|
|
462
596
|
...this.config,
|
|
597
|
+
// Last, so a config's own `secret_id` key (it is not a config field;
|
|
598
|
+
// see `withConfig`) can never override the constructor's.
|
|
599
|
+
secret_id: this.secretIdValue.toString(),
|
|
463
600
|
};
|
|
464
601
|
const host = (getNative() as unknown as NativeHost).protocol_new(
|
|
465
602
|
JSON.stringify(config),
|
|
@@ -591,6 +728,17 @@ export class DeRecProtocol {
|
|
|
591
728
|
return decodeEvents(buffer);
|
|
592
729
|
}
|
|
593
730
|
|
|
731
|
+
/**
|
|
732
|
+
* Accept a pending action from an `ActionRequired` event, returning the
|
|
733
|
+
* events it produces.
|
|
734
|
+
*
|
|
735
|
+
* When the action completes a pairing, the publish that follows reuses the
|
|
736
|
+
* stored helper weights. If one is no longer valid under the round's
|
|
737
|
+
* threshold, that publish fails with `invalid_weight` before anything is
|
|
738
|
+
* sent and this throws: the pairing has completed and its response was
|
|
739
|
+
* sent, but the `PairingCompleted` event is not returned. Call `start`
|
|
740
|
+
* with `ProtectSecret` and valid weights to publish.
|
|
741
|
+
*/
|
|
594
742
|
async accept(actionBytes: Uint8Array): Promise<DeRecEvent[]> {
|
|
595
743
|
const buffer = (await this.host.accept(actionBytes)) as ArrayBuffer;
|
|
596
744
|
return decodeEvents(buffer);
|
|
@@ -613,6 +761,13 @@ export class DeRecProtocol {
|
|
|
613
761
|
* group's vault: the source's publish is then installed as it arrives,
|
|
614
762
|
* with no further prompt. Ask the user before calling this; to decline,
|
|
615
763
|
* never confirm.
|
|
764
|
+
*
|
|
765
|
+
* On a promotion the current snapshot is published to the promoted peer,
|
|
766
|
+
* reusing the stored helper weights. If one is no longer valid under the
|
|
767
|
+
* current threshold, that publish fails with `invalid_weight` before
|
|
768
|
+
* anything is sent and this throws. The promotion stands: calling this
|
|
769
|
+
* again resolves `true` and publishes nothing, so call `start` with
|
|
770
|
+
* `ProtectSecret` and valid weights to reach the promoted peer.
|
|
616
771
|
*/
|
|
617
772
|
async verifyFingerprint(channelId: bigint | number, fingerprint: string): Promise<boolean> {
|
|
618
773
|
return (await this.host.verifyFingerprint(toBigInt(channelId), fingerprint)) as boolean;
|
|
@@ -633,6 +788,9 @@ export class DeRecProtocol {
|
|
|
633
788
|
* reported as a `PeerNotRestored` event in the returned array and the rest
|
|
634
789
|
* of the roster is restored.
|
|
635
790
|
*
|
|
791
|
+
* A helper's or member's `communication_info` may be absent or `null`;
|
|
792
|
+
* both mean the same thing — no entries.
|
|
793
|
+
*
|
|
636
794
|
* Rejects with a `DeRecError`; among its codes:
|
|
637
795
|
*
|
|
638
796
|
* | code | meaning |
|