@serfab/cadre-core 1.3.0 → 1.4.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 +5 -3
- package/dist/cadre-node.d.ts +32 -19
- package/dist/cadre-node.js +120 -31
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +4 -4
- package/dist/control-formation-recorder.js +6 -6
- package/dist/control-formation-recorder.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/membership-connection-gater.d.ts +18 -5
- package/dist/membership-connection-gater.js +50 -10
- package/dist/membership-connection-gater.js.map +1 -1
- package/dist/storage-scope.d.ts +50 -12
- package/dist/storage-scope.js +85 -12
- package/dist/storage-scope.js.map +1 -1
- package/dist/strand-formation-manager.js +2 -1
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-id.d.ts +35 -0
- package/dist/strand-id.js +46 -0
- package/dist/strand-id.js.map +1 -0
- package/dist/strand-instance-manager.js +19 -2
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-network-config.d.ts +3 -3
- package/dist/strand-network-config.js +3 -3
- package/dist/strand-solicitation.js +2 -1
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/strand-watcher.d.ts +45 -0
- package/dist/strand-watcher.js +74 -13
- package/dist/strand-watcher.js.map +1 -1
- package/dist/types.d.ts +94 -15
- package/dist/types.js +59 -0
- package/dist/types.js.map +1 -1
- package/package.json +7 -7
- package/src/cadre-node.ts +126 -31
- package/src/control-formation-recorder.ts +6 -6
- package/src/index.ts +563 -554
- package/src/membership-connection-gater.ts +56 -11
- package/src/storage-scope.ts +163 -78
- package/src/strand-formation-manager.ts +647 -646
- package/src/strand-id.ts +48 -0
- package/src/strand-instance-manager.ts +20 -2
- package/src/strand-network-config.ts +250 -250
- package/src/strand-solicitation.ts +500 -499
- package/src/strand-watcher.ts +388 -325
- package/src/types.ts +97 -15
|
@@ -130,10 +130,10 @@ export declare class ControlFormationUsageRecorder implements FormationUsageReco
|
|
|
130
130
|
* Provision a NEW strand for an UNBOUND invite and record consent against it in ONE
|
|
131
131
|
* transaction (the responder-provisions fallback, now single-use-enforced).
|
|
132
132
|
*
|
|
133
|
-
* Mints a fresh, globally-unique strand id
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
133
|
+
* Mints a fresh, globally-unique strand id with {@link mintStrandId} — an
|
|
134
|
+
* unguessable CSPRNG id, and one `strand-id.ts` has already checked is usable as a
|
|
135
|
+
* storage scope key and network name — then delegates to
|
|
136
|
+
* {@link ControlDatabase.redeemInvitation}, whose
|
|
137
137
|
* single `begin … commit` inserts the consent-authorized `Strand` row AND the matching
|
|
138
138
|
* `FormationUsage` row together (both deferred CHECKs see both rows at commit). That one
|
|
139
139
|
* `FormationUsage` row makes the unbound redemption single-use exactly like the bound
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import debug from 'debug';
|
|
2
|
-
import { randomBytes } from '@optimystic/quereus-plugin-crypto';
|
|
3
2
|
import { FormationAbortedError } from './control-database.js';
|
|
3
|
+
import { mintStrandId } from './strand-id.js';
|
|
4
4
|
import { createHttpFormationApprover, verifyFormationApproval, FormationApprovalError } from './formation-approval.js';
|
|
5
5
|
const log = debug('sereus:cadre:formation-recorder');
|
|
6
6
|
/** Far-future sentinel for an invitation that never expires (max valid JS Date). */
|
|
@@ -209,10 +209,10 @@ export class ControlFormationUsageRecorder {
|
|
|
209
209
|
* Provision a NEW strand for an UNBOUND invite and record consent against it in ONE
|
|
210
210
|
* transaction (the responder-provisions fallback, now single-use-enforced).
|
|
211
211
|
*
|
|
212
|
-
* Mints a fresh, globally-unique strand id
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
212
|
+
* Mints a fresh, globally-unique strand id with {@link mintStrandId} — an
|
|
213
|
+
* unguessable CSPRNG id, and one `strand-id.ts` has already checked is usable as a
|
|
214
|
+
* storage scope key and network name — then delegates to
|
|
215
|
+
* {@link ControlDatabase.redeemInvitation}, whose
|
|
216
216
|
* single `begin … commit` inserts the consent-authorized `Strand` row AND the matching
|
|
217
217
|
* `FormationUsage` row together (both deferred CHECKs see both rows at commit). That one
|
|
218
218
|
* `FormationUsage` row makes the unbound redemption single-use exactly like the bound
|
|
@@ -238,7 +238,7 @@ export class ControlFormationUsageRecorder {
|
|
|
238
238
|
if (signal?.aborted) {
|
|
239
239
|
throw new FormationAbortedError(token, 'redemption');
|
|
240
240
|
}
|
|
241
|
-
const strandId =
|
|
241
|
+
const strandId = mintStrandId();
|
|
242
242
|
const invite = await this.controlDatabase.queryFormationInvite(token);
|
|
243
243
|
const approval = await this.obtainApproval({
|
|
244
244
|
token, usageStampId, strandId, peerKey, disclosure,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-formation-recorder.js","sourceRoot":"","sources":["../src/control-formation-recorder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"control-formation-recorder.js","sourceRoot":"","sources":["../src/control-formation-recorder.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export { MemoryTrustedOwnerStore, PersistentTrustedOwnerStore, type TrustedOwner
|
|
|
13
13
|
export type { DurableSlot } from './node-local-snapshot.js';
|
|
14
14
|
export { MemoryBootstrapPeerStore, PersistentBootstrapPeerStore, type BootstrapPeerStore, type BootstrapPeerEntry } from './bootstrap-peer-store.js';
|
|
15
15
|
export { MemoryEnrolledMachineStore, PersistentEnrolledMachineStore, type EnrolledMachineStore } from './enrolled-machine-store.js';
|
|
16
|
-
export { controlStorageScope, isControlStorageScope } from './storage-scope.js';
|
|
16
|
+
export { controlStorageScope, isControlStorageScope, isValidStrandScopeKey, assertStrandScopeKey, InvalidStrandIdError } from './storage-scope.js';
|
|
17
17
|
export { StrandDatabase, type StrandDatabaseConfig } from './strand-database.js';
|
|
18
18
|
export { StrandWatcher, type StrandWatcherCallbacks, type StrandQueryable, type SAppIdLookup, type StrandRowWithApp } from './strand-watcher.js';
|
|
19
19
|
export { StrandInstanceManager, type StartStrandConfig, type ResumeStrandOverrides, getStrandStoragePath, isAwaitingFirstSync, liveStrandStatus } from './strand-instance-manager.js';
|
|
@@ -48,7 +48,7 @@ export { anchoredTrustPolicy, pinnedKeyTrustPolicy, tofuTrustPolicy, type SeedTr
|
|
|
48
48
|
export { signSchema, verifySchema, assertSchemaSignature, SchemaVerificationError } from './schema-verification.js';
|
|
49
49
|
export { FormationListener, dialFormation, isValidResponderCreatesResult, isWellFormedMembershipInvite, sanitizeStrandAddrs, FORMATION_PROTOCOL, type FormationParty, type FormationContactMessage, type FormationResultMessage, type FormationProvisionResult, type FormationStrandInfo, type FormationDbConnectionInfo, type FormationListenerOptions, type FormationDialOptions, type FormationDialResult, type ResponderProvisionOutcome } from './strand-formation-protocol.js';
|
|
50
50
|
export { StrandFormationManager, createStrandFormationManager, MEMBERSHIP_INVITE_TTL_MS, MEMBERSHIP_INVITE_UNAVAILABLE_REASON, HOST_STRAND_MUST_BE_RECREATED_REASON, type StrandFormationManagerConfig, type StrandFormationManagerOptions } from './strand-formation-manager.js';
|
|
51
|
-
export { createMembershipConnectionGater, STRANGER_OPEN_PROTOCOLS, DEFAULT_ENROLLMENT_WINDOW_MS, ADMISSION_DECISION_TIMEOUT_MS, RELAY_ADMISSION_RESERVE_DEADLINE_MS, MAX_UNAUTHORIZED_RELAY_RESERVATIONS, UNAUTHORIZED_RESERVATION_TTL_MS, UnauthorizedReservationBudget, type InboundAdmissionPolicy, type InboundConnectionVerdict } from './membership-connection-gater.js';
|
|
51
|
+
export { createMembershipConnectionGater, STRANGER_OPEN_PROTOCOLS, DEFAULT_ENROLLMENT_WINDOW_MS, ADMISSION_DECISION_TIMEOUT_MS, RELAY_ADMISSION_RESERVE_DEADLINE_MS, RELAY_ADMISSION_CLOSE_TIMEOUT_MS, MAX_UNAUTHORIZED_RELAY_RESERVATIONS, UNAUTHORIZED_RESERVATION_TTL_MS, UnauthorizedReservationBudget, type InboundAdmissionPolicy, type InboundConnectionVerdict } from './membership-connection-gater.js';
|
|
52
52
|
export { RelayReservationFailedError, UnbindableListenAddressError, RELAY_SEARCH_LISTEN_ADDR, resolveListenAddrs } from './relay-addrs.js';
|
|
53
53
|
export { strandNodeAddrs, type StrandNodeAddrs } from './strand-network-config.js';
|
|
54
54
|
export { circuitMultiaddrs, superviseRelayReservation, DEFAULT_RELAY_RESERVE_TIMEOUT_MS, DEFAULT_RELAY_RESERVE_POLL_MS, DEFAULT_RELAY_CHECK_MS, DEFAULT_RELAY_MIN_BACKOFF_MS, DEFAULT_RELAY_MAX_BACKOFF_MS, type RelayReservationStatus, type RelayReservationState, type RelayReserveOptions, type RelayReservationSupervisor, type RelayReservationSupervisorOptions } from './relay-reservation.js';
|
package/dist/index.js
CHANGED
|
@@ -51,8 +51,10 @@ export { MemoryBootstrapPeerStore, PersistentBootstrapPeerStore } from './bootst
|
|
|
51
51
|
export { MemoryEnrolledMachineStore, PersistentEnrolledMachineStore } from './enrolled-machine-store.js';
|
|
52
52
|
// Storage scope keys — what `CadreNodeConfig.storage.provider` is called with. A
|
|
53
53
|
// strand's key is its strand id; the control database's key carries the party id,
|
|
54
|
-
// so two parties on one device never share a control store.
|
|
55
|
-
|
|
54
|
+
// so two parties on one device never share a control store. Every key stays within
|
|
55
|
+
// `[A-Za-z0-9._-]`: the control key by base64url encoding, a strand's by
|
|
56
|
+
// `assertStrandScopeKey`, which every strand launch runs.
|
|
57
|
+
export { controlStorageScope, isControlStorageScope, isValidStrandScopeKey, assertStrandScopeKey, InvalidStrandIdError } from './storage-scope.js';
|
|
56
58
|
// Strand database
|
|
57
59
|
export { StrandDatabase } from './strand-database.js';
|
|
58
60
|
// Strand management
|
|
@@ -144,7 +146,7 @@ export { FormationListener, dialFormation, isValidResponderCreatesResult, isWell
|
|
|
144
146
|
// Strand Formation manager (drives the native transport)
|
|
145
147
|
export { StrandFormationManager, createStrandFormationManager, MEMBERSHIP_INVITE_TTL_MS, MEMBERSHIP_INVITE_UNAVAILABLE_REASON, HOST_STRAND_MUST_BE_RECREATED_REASON } from './strand-formation-manager.js';
|
|
146
148
|
// Control-network inbound connection gate (membership defense-in-depth)
|
|
147
|
-
export { createMembershipConnectionGater, STRANGER_OPEN_PROTOCOLS, DEFAULT_ENROLLMENT_WINDOW_MS, ADMISSION_DECISION_TIMEOUT_MS, RELAY_ADMISSION_RESERVE_DEADLINE_MS, MAX_UNAUTHORIZED_RELAY_RESERVATIONS, UNAUTHORIZED_RESERVATION_TTL_MS, UnauthorizedReservationBudget } from './membership-connection-gater.js';
|
|
149
|
+
export { createMembershipConnectionGater, STRANGER_OPEN_PROTOCOLS, DEFAULT_ENROLLMENT_WINDOW_MS, ADMISSION_DECISION_TIMEOUT_MS, RELAY_ADMISSION_RESERVE_DEADLINE_MS, RELAY_ADMISSION_CLOSE_TIMEOUT_MS, MAX_UNAUTHORIZED_RELAY_RESERVATIONS, UNAUTHORIZED_RESERVATION_TTL_MS, UnauthorizedReservationBudget } from './membership-connection-gater.js';
|
|
148
150
|
// Thrown out of `CadreNode.start()` when a `network.relayAddrs` reservation does
|
|
149
151
|
// not land on its first attempt — the fail-fast posture of that config field now
|
|
150
152
|
// that the control node reserves AFTER control-database bring-up (relay-addrs.ts).
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,YAAY,CAAC;AAE3B,+DAA+D;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,uBAAuB;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,mBAAmB;AACnB,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,eAAe,EAAwO,MAAM,uBAAuB,CAAC;AAElZ,+EAA+E;AAC/E,qFAAqF;AACrF,yCAAyC;AACzC,OAAO,EACL,sBAAsB,EACtB,6BAA6B,EAC7B,oBAAoB,EACpB,wBAAwB,EACxB,8BAA8B,EAC9B,4BAA4B,EAC5B,iBAAiB,EAElB,MAAM,0BAA0B,CAAC;AAElC,gFAAgF;AAChF,yFAAyF;AACzF,OAAO,EACL,qBAAqB,EACrB,4BAA4B,EAC5B,4BAA4B,EAC5B,6BAA6B,EAC7B,gBAAgB,EAEjB,MAAM,yBAAyB,CAAC;AAWjC,2FAA2F;AAC3F,OAAO,EAAE,0BAA0B,EAA0C,MAAM,4BAA4B,CAAC;AAEhH,2DAA2D;AAC3D,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,0BAA0B,EAAuB,MAAM,kBAAkB,CAAC;AAE1I,2EAA2E;AAC3E,gFAAgF;AAChF,8EAA8E;AAC9E,+EAA+E;AAC/E,2BAA2B;AAC3B,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EAGxB,MAAM,gBAAgB,CAAC;AAExB,8EAA8E;AAC9E,8EAA8E;AAC9E,gFAAgF;AAChF,OAAO,EACL,uBAAuB,EACvB,aAAa,EAEd,MAAM,mBAAmB,CAAC;AAE3B,2EAA2E;AAC3E,+EAA+E;AAC/E,2EAA2E;AAC3E,6CAA6C;AAC7C,mEAAmE;AACnE,wDAAwD;AACxD,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAG5B,MAAM,0BAA0B,CAAC;AAQlC,gFAAgF;AAChF,gFAAgF;AAChF,iFAAiF;AACjF,8EAA8E;AAC9E,kDAAkD;AAClD,OAAO,EACL,wBAAwB,EACxB,4BAA4B,EAG7B,MAAM,2BAA2B,CAAC;AAEnC,8EAA8E;AAC9E,iFAAiF;AACjF,8EAA8E;AAC9E,2EAA2E;AAC3E,2DAA2D;AAC3D,iFAAiF;AACjF,+EAA+E;AAC/E,oDAAoD;AACpD,OAAO,EACL,0BAA0B,EAC1B,8BAA8B,EAE/B,MAAM,6BAA6B,CAAC;AAErC,iFAAiF;AACjF,kFAAkF;AAClF,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -88,9 +88,10 @@
|
|
|
88
88
|
* annex the party's relay capacity.
|
|
89
89
|
* - An `'admit-for-relay'` connection that is NOT reserving is dropped: it has
|
|
90
90
|
* {@link RELAY_ADMISSION_RESERVE_DEADLINE_MS} to get a reservation ADMITTED
|
|
91
|
-
* at that hook, after which the underlying connection
|
|
92
|
-
*
|
|
93
|
-
* conversation" to "in it briefly,
|
|
91
|
+
* at that hook, after which the gate CLOSES the underlying connection so
|
|
92
|
+
* both ends let go of the socket. The guarantee above thus weakens on
|
|
93
|
+
* relay-enabled nodes from "never in the conversation" to "in it briefly,
|
|
94
|
+
* and can speak nothing".
|
|
94
95
|
*
|
|
95
96
|
* The deadline clears on reservation ADMISSION, not on the reservation's own
|
|
96
97
|
* success: this gate cannot observe the server-side `reserve()` outcome, so a
|
|
@@ -187,13 +188,25 @@ export declare const ADMISSION_DECISION_TIMEOUT_MS = 2000;
|
|
|
187
188
|
/**
|
|
188
189
|
* How long an `'admit-for-relay'` connection may exist without a relay
|
|
189
190
|
* reservation being ADMITTED at the `denyInboundRelayReservation` hook, after
|
|
190
|
-
* which the gate
|
|
191
|
+
* which the gate closes the underlying connection. A reserving client asks for
|
|
191
192
|
* its slot immediately after the connection upgrades (`relay-reservation.ts`
|
|
192
193
|
* dials and requests in one drive; a strand node's configured circuit listener
|
|
193
194
|
* does the same from inside its own `listen()`), so a connection idle past this
|
|
194
195
|
* deadline is not reserving.
|
|
195
196
|
*/
|
|
196
197
|
export declare const RELAY_ADMISSION_RESERVE_DEADLINE_MS = 5000;
|
|
198
|
+
/**
|
|
199
|
+
* Bound on the graceful close of an expired relay-only connection. It exists
|
|
200
|
+
* because `AbstractMultiaddrConnection.close()` awaits an `idle`/`drain` event
|
|
201
|
+
* when the connection still has unsent bytes, and that wait has no timeout of
|
|
202
|
+
* its own — an unsignalled one never ends. This gate writes nothing to a
|
|
203
|
+
* stranger, so the wait is not reachable today; the bound is here so a timer
|
|
204
|
+
* callback can never hold an unending await.
|
|
205
|
+
*
|
|
206
|
+
* Applied through {@link withDeadline}, not `AbortSignal.timeout`: the latter is
|
|
207
|
+
* not reliably present on React Native/Hermes, which loads this same module.
|
|
208
|
+
*/
|
|
209
|
+
export declare const RELAY_ADMISSION_CLOSE_TIMEOUT_MS = 2000;
|
|
197
210
|
/**
|
|
198
211
|
* Default cap on concurrent relay reservations held by peers the membership
|
|
199
212
|
* check could not place (see {@link UnauthorizedReservationBudget}). Small on
|
|
@@ -311,7 +324,7 @@ export declare class UnauthorizedReservationBudget {
|
|
|
311
324
|
*
|
|
312
325
|
* An `'admit-for-relay'` verdict admits the connection and arms a
|
|
313
326
|
* `reserveDeadlineMs` timer against it; the timer is disarmed when a
|
|
314
|
-
* reservation for that peer is ADMITTED at the reservation hook, and
|
|
327
|
+
* reservation for that peer is ADMITTED at the reservation hook, and closes the
|
|
315
328
|
* underlying `MultiaddrConnection` when it fires first.
|
|
316
329
|
*
|
|
317
330
|
* NOTE: `base` is spread, so a gater passed as a CLASS INSTANCE would lose its
|
|
@@ -88,9 +88,10 @@
|
|
|
88
88
|
* annex the party's relay capacity.
|
|
89
89
|
* - An `'admit-for-relay'` connection that is NOT reserving is dropped: it has
|
|
90
90
|
* {@link RELAY_ADMISSION_RESERVE_DEADLINE_MS} to get a reservation ADMITTED
|
|
91
|
-
* at that hook, after which the underlying connection
|
|
92
|
-
*
|
|
93
|
-
* conversation" to "in it briefly,
|
|
91
|
+
* at that hook, after which the gate CLOSES the underlying connection so
|
|
92
|
+
* both ends let go of the socket. The guarantee above thus weakens on
|
|
93
|
+
* relay-enabled nodes from "never in the conversation" to "in it briefly,
|
|
94
|
+
* and can speak nothing".
|
|
94
95
|
*
|
|
95
96
|
* The deadline clears on reservation ADMISSION, not on the reservation's own
|
|
96
97
|
* success: this gate cannot observe the server-side `reserve()` outcome, so a
|
|
@@ -156,6 +157,7 @@
|
|
|
156
157
|
import debug from 'debug';
|
|
157
158
|
import { SEED_PROTOCOL } from './seed-bootstrap.js';
|
|
158
159
|
import { FORMATION_PROTOCOL } from './strand-formation-protocol.js';
|
|
160
|
+
import { withDeadline } from './control-stream.js';
|
|
159
161
|
const log = debug('sereus:cadre:connection-gater');
|
|
160
162
|
/**
|
|
161
163
|
* The protocols a not-yet-authorized peer may legitimately speak on a control
|
|
@@ -190,13 +192,25 @@ export const ADMISSION_DECISION_TIMEOUT_MS = 2000;
|
|
|
190
192
|
/**
|
|
191
193
|
* How long an `'admit-for-relay'` connection may exist without a relay
|
|
192
194
|
* reservation being ADMITTED at the `denyInboundRelayReservation` hook, after
|
|
193
|
-
* which the gate
|
|
195
|
+
* which the gate closes the underlying connection. A reserving client asks for
|
|
194
196
|
* its slot immediately after the connection upgrades (`relay-reservation.ts`
|
|
195
197
|
* dials and requests in one drive; a strand node's configured circuit listener
|
|
196
198
|
* does the same from inside its own `listen()`), so a connection idle past this
|
|
197
199
|
* deadline is not reserving.
|
|
198
200
|
*/
|
|
199
201
|
export const RELAY_ADMISSION_RESERVE_DEADLINE_MS = 5000;
|
|
202
|
+
/**
|
|
203
|
+
* Bound on the graceful close of an expired relay-only connection. It exists
|
|
204
|
+
* because `AbstractMultiaddrConnection.close()` awaits an `idle`/`drain` event
|
|
205
|
+
* when the connection still has unsent bytes, and that wait has no timeout of
|
|
206
|
+
* its own — an unsignalled one never ends. This gate writes nothing to a
|
|
207
|
+
* stranger, so the wait is not reachable today; the bound is here so a timer
|
|
208
|
+
* callback can never hold an unending await.
|
|
209
|
+
*
|
|
210
|
+
* Applied through {@link withDeadline}, not `AbortSignal.timeout`: the latter is
|
|
211
|
+
* not reliably present on React Native/Hermes, which loads this same module.
|
|
212
|
+
*/
|
|
213
|
+
export const RELAY_ADMISSION_CLOSE_TIMEOUT_MS = 2000;
|
|
200
214
|
/**
|
|
201
215
|
* Default cap on concurrent relay reservations held by peers the membership
|
|
202
216
|
* check could not place (see {@link UnauthorizedReservationBudget}). Small on
|
|
@@ -297,7 +311,7 @@ export class UnauthorizedReservationBudget {
|
|
|
297
311
|
*
|
|
298
312
|
* An `'admit-for-relay'` verdict admits the connection and arms a
|
|
299
313
|
* `reserveDeadlineMs` timer against it; the timer is disarmed when a
|
|
300
|
-
* reservation for that peer is ADMITTED at the reservation hook, and
|
|
314
|
+
* reservation for that peer is ADMITTED at the reservation hook, and closes the
|
|
301
315
|
* underlying `MultiaddrConnection` when it fires first.
|
|
302
316
|
*
|
|
303
317
|
* NOTE: `base` is spread, so a gater passed as a CLASS INSTANCE would lose its
|
|
@@ -406,11 +420,11 @@ export async function decideWithinDeadline(decide, fallback, timeoutMs, what) {
|
|
|
406
420
|
/**
|
|
407
421
|
* The not-reserving deadlines for `'admit-for-relay'` connections, keyed by
|
|
408
422
|
* remote peerId (a Set per peer — one peer can hold several in-flight
|
|
409
|
-
* connections). `arm` starts a timer that
|
|
423
|
+
* connections). `arm` starts a timer that closes the connection; `disarm`
|
|
410
424
|
* (called when a reservation for that peer is admitted) cancels every pending
|
|
411
425
|
* timer for the peer. Timers are unref'd so an armed deadline never holds a
|
|
412
426
|
* process open, and a timer that fires against an already-closed connection is
|
|
413
|
-
* a
|
|
427
|
+
* a no-op (`close()` returns at once on any status but `open`).
|
|
414
428
|
*
|
|
415
429
|
* Disarming is final for the connections it cancelled: a peer that reserved
|
|
416
430
|
* once and then lets its reservation lapse keeps a mute connection (the
|
|
@@ -453,12 +467,38 @@ class PendingReserveDeadlines {
|
|
|
453
467
|
if (entries?.size === 0) {
|
|
454
468
|
this.byPeer.delete(remotePeerId);
|
|
455
469
|
}
|
|
456
|
-
log('Relay-only admission expired for %s — no reservation admitted within %dms,
|
|
470
|
+
log('Relay-only admission expired for %s — no reservation admitted within %dms, closing the connection', remotePeerId, this.deadlineMs);
|
|
471
|
+
void this.drop(remotePeerId, entry.maConn);
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* End an expired relay-only connection: a bounded graceful close, with
|
|
475
|
+
* `abort()` only as the escalation. The order cannot be reversed — `abort()`
|
|
476
|
+
* marks the connection `aborted`, and `close()` returns immediately on any
|
|
477
|
+
* status that is not `open`, so aborting first would make the close a silent
|
|
478
|
+
* no-op. Closing a connection the peer already dropped returns at once
|
|
479
|
+
* without throwing, so the fallback stays unreached in the ordinary case.
|
|
480
|
+
*/
|
|
481
|
+
async drop(remotePeerId, maConn) {
|
|
482
|
+
try {
|
|
483
|
+
await withDeadline(RELAY_ADMISSION_CLOSE_TIMEOUT_MS, `relay-only close for ${remotePeerId}`, (signal) => maConn.close({ signal }));
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
catch (error) {
|
|
487
|
+
log('Closing the expired relay-only connection from %s failed — aborting: %o', remotePeerId, error);
|
|
488
|
+
}
|
|
489
|
+
// NOTE: this fallback cannot actually free a WebSocket. `@libp2p/websockets`'
|
|
490
|
+
// `sendReset()` calls `websocket.close(1006)`, and 1006 is a reserved code
|
|
491
|
+
// RFC 6455 forbids an endpoint from sending, so `ws` throws and
|
|
492
|
+
// `AbstractMessageStream.abort()` swallows it — the local end flips to
|
|
493
|
+
// `aborted` while the socket stays up. Measured against
|
|
494
|
+
// @libp2p/websockets@10.1.3 (see tickets/blocked/report-libp2p-websockets-abort-close-code.md).
|
|
495
|
+
// `MultiaddrConnection` exposes no way down to the raw socket, so this is as
|
|
496
|
+
// far as this layer can go. Revisit — drop the fallback, or go back to a
|
|
497
|
+
// plain `abort()` — once that transport sends a legal reset code.
|
|
457
498
|
try {
|
|
458
|
-
|
|
499
|
+
maConn.abort(new Error(`relay-only admission expired: no relay reservation admitted within ${this.deadlineMs}ms`));
|
|
459
500
|
}
|
|
460
501
|
catch (error) {
|
|
461
|
-
// Aborting a connection that already closed on its own is not a failure.
|
|
462
502
|
log('Aborting the expired relay-only connection from %s threw: %o', remotePeerId, error);
|
|
463
503
|
}
|
|
464
504
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"membership-connection-gater.js","sourceRoot":"","sources":["../src/membership-connection-gater.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"membership-connection-gater.js","sourceRoot":"","sources":["../src/membership-connection-gater.ts"],"names":[],"mappings":"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"}
|
package/dist/storage-scope.d.ts
CHANGED
|
@@ -23,12 +23,13 @@
|
|
|
23
23
|
* encoding the React Native app's `secureStoreKeySegment` uses on a party id for the
|
|
24
24
|
* same reason.
|
|
25
25
|
*
|
|
26
|
-
* THE STRAND ARM OF THAT CHARSET RULE IS
|
|
27
|
-
* `StrandRow.Id`, and
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* provider.
|
|
26
|
+
* THE STRAND ARM OF THAT CHARSET RULE IS ENFORCED HERE. A strand's scope key is
|
|
27
|
+
* `StrandRow.Id`, and a strand row replicated into the control database by another
|
|
28
|
+
* node in the party carries whatever id THAT node wrote. `assertStrandScopeKey`
|
|
29
|
+
* (below) is the check that makes the charset true of strand keys too; it runs
|
|
30
|
+
* unconditionally at the top of `StrandInstanceManager.startStrand`, so no strand id
|
|
31
|
+
* reaches an embedder's provider — or a libp2p protocol prefix — unvalidated. Ids
|
|
32
|
+
* cadre-core mints come from `strand-id.ts`, which is built on the same predicate.
|
|
32
33
|
*/
|
|
33
34
|
/**
|
|
34
35
|
* The storage scope key for a party's control database.
|
|
@@ -52,11 +53,48 @@ export declare function controlStorageScope(partyId: string): string;
|
|
|
52
53
|
/**
|
|
53
54
|
* Whether a scope key names a control database rather than a strand.
|
|
54
55
|
*
|
|
55
|
-
* A prefix test
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* boundary: a strand id replicated in from another node is unvalidated text that
|
|
59
|
-
* could begin `control-`, which is one more reason to close the gap the module
|
|
60
|
-
* comment names.
|
|
56
|
+
* A prefix test, and a sound one: a strand scope key can never begin `control-`,
|
|
57
|
+
* because {@link isValidStrandScopeKey} rejects that prefix and
|
|
58
|
+
* {@link assertStrandScopeKey} runs on every strand launch.
|
|
61
59
|
*/
|
|
62
60
|
export declare function isControlStorageScope(scope: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Whether a strand id is usable as a storage scope key and as a libp2p network name.
|
|
63
|
+
*
|
|
64
|
+
* A strand id is not minted locally in the general case — a strand row replicates in
|
|
65
|
+
* from another node in the party carrying whatever id THAT node wrote — and both
|
|
66
|
+
* places it lands turn it straight into a name: the embedder's storage provider
|
|
67
|
+
* (a directory under cadre-cli's storage path, a LevelDB filename, an IndexedDB
|
|
68
|
+
* database name) and the strand node's protocol prefix `/optimystic/strand-<id>`.
|
|
69
|
+
*
|
|
70
|
+
* Valid means all of:
|
|
71
|
+
* - non-empty, and at most {@link MAX_STRAND_SCOPE_KEY_LENGTH} characters;
|
|
72
|
+
* - within `[A-Za-z0-9._-]`, so no separator, drive letter, NUL or non-ASCII text;
|
|
73
|
+
* - not `.` or `..`, which the charset admits but every filesystem reads as a
|
|
74
|
+
* directory rather than a name;
|
|
75
|
+
* - not `control-`-prefixed, which would let a strand's store masquerade as a
|
|
76
|
+
* party's control database (see {@link isControlStorageScope}).
|
|
77
|
+
*/
|
|
78
|
+
export declare function isValidStrandScopeKey(strandId: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Thrown when a strand id cannot be used as a storage scope key or network name.
|
|
81
|
+
*
|
|
82
|
+
* NOT retryable: the id is a property of the strand row, so every later attempt on
|
|
83
|
+
* the same row fails identically. Callers that poll — `CadreNode.handleStrandAdded`
|
|
84
|
+
* via `StrandWatcher` — suppress the strand rather than scheduling a retry.
|
|
85
|
+
*/
|
|
86
|
+
export declare class InvalidStrandIdError extends Error {
|
|
87
|
+
readonly strandId: string;
|
|
88
|
+
constructor(strandId: string);
|
|
89
|
+
}
|
|
90
|
+
/** {@link isValidStrandScopeKey} as an assertion, throwing {@link InvalidStrandIdError}. */
|
|
91
|
+
export declare function assertStrandScopeKey(strandId: string): void;
|
|
92
|
+
/**
|
|
93
|
+
* The charset half of the rule on its own, for the CONTROL key.
|
|
94
|
+
*
|
|
95
|
+
* {@link assertStrandScopeKey} cannot serve here: it rejects the `control-` prefix by
|
|
96
|
+
* design. Asserted at the seam that calls the provider (`CadreNode.resolveControlStorage`)
|
|
97
|
+
* rather than inside {@link controlStorageScope}, so the guarantee belongs to the call
|
|
98
|
+
* that hands a key out and not to one particular way of minting one.
|
|
99
|
+
*/
|
|
100
|
+
export declare function assertScopeKeyCharset(scope: string): void;
|
package/dist/storage-scope.js
CHANGED
|
@@ -23,12 +23,13 @@
|
|
|
23
23
|
* encoding the React Native app's `secureStoreKeySegment` uses on a party id for the
|
|
24
24
|
* same reason.
|
|
25
25
|
*
|
|
26
|
-
* THE STRAND ARM OF THAT CHARSET RULE IS
|
|
27
|
-
* `StrandRow.Id`, and
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* provider.
|
|
26
|
+
* THE STRAND ARM OF THAT CHARSET RULE IS ENFORCED HERE. A strand's scope key is
|
|
27
|
+
* `StrandRow.Id`, and a strand row replicated into the control database by another
|
|
28
|
+
* node in the party carries whatever id THAT node wrote. `assertStrandScopeKey`
|
|
29
|
+
* (below) is the check that makes the charset true of strand keys too; it runs
|
|
30
|
+
* unconditionally at the top of `StrandInstanceManager.startStrand`, so no strand id
|
|
31
|
+
* reaches an embedder's provider — or a libp2p protocol prefix — unvalidated. Ids
|
|
32
|
+
* cadre-core mints come from `strand-id.ts`, which is built on the same predicate.
|
|
32
33
|
*/
|
|
33
34
|
import { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays';
|
|
34
35
|
/**
|
|
@@ -62,14 +63,86 @@ export function controlStorageScope(partyId) {
|
|
|
62
63
|
/**
|
|
63
64
|
* Whether a scope key names a control database rather than a strand.
|
|
64
65
|
*
|
|
65
|
-
* A prefix test
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* boundary: a strand id replicated in from another node is unvalidated text that
|
|
69
|
-
* could begin `control-`, which is one more reason to close the gap the module
|
|
70
|
-
* comment names.
|
|
66
|
+
* A prefix test, and a sound one: a strand scope key can never begin `control-`,
|
|
67
|
+
* because {@link isValidStrandScopeKey} rejects that prefix and
|
|
68
|
+
* {@link assertStrandScopeKey} runs on every strand launch.
|
|
71
69
|
*/
|
|
72
70
|
export function isControlStorageScope(scope) {
|
|
73
71
|
return scope.startsWith(CONTROL_SCOPE_PREFIX);
|
|
74
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* The longest strand scope key accepted.
|
|
75
|
+
*
|
|
76
|
+
* The longest id cadre-core mints is 39 characters (`strand-` plus the 32 hex
|
|
77
|
+
* characters of `randomBytes(128, 'hex')` — 128 BITS, so 16 bytes), so this leaves
|
|
78
|
+
* ample room while keeping a key clear of the 255-BYTE limit every mainstream
|
|
79
|
+
* filesystem puts on one path component. The charset is ASCII, so characters and
|
|
80
|
+
* bytes are the same count here.
|
|
81
|
+
*/
|
|
82
|
+
const MAX_STRAND_SCOPE_KEY_LENGTH = 128;
|
|
83
|
+
/** The charset every scope key stays within — see the module comment. */
|
|
84
|
+
const SCOPE_KEY_CHARSET = /^[A-Za-z0-9._-]+$/;
|
|
85
|
+
/**
|
|
86
|
+
* Whether a strand id is usable as a storage scope key and as a libp2p network name.
|
|
87
|
+
*
|
|
88
|
+
* A strand id is not minted locally in the general case — a strand row replicates in
|
|
89
|
+
* from another node in the party carrying whatever id THAT node wrote — and both
|
|
90
|
+
* places it lands turn it straight into a name: the embedder's storage provider
|
|
91
|
+
* (a directory under cadre-cli's storage path, a LevelDB filename, an IndexedDB
|
|
92
|
+
* database name) and the strand node's protocol prefix `/optimystic/strand-<id>`.
|
|
93
|
+
*
|
|
94
|
+
* Valid means all of:
|
|
95
|
+
* - non-empty, and at most {@link MAX_STRAND_SCOPE_KEY_LENGTH} characters;
|
|
96
|
+
* - within `[A-Za-z0-9._-]`, so no separator, drive letter, NUL or non-ASCII text;
|
|
97
|
+
* - not `.` or `..`, which the charset admits but every filesystem reads as a
|
|
98
|
+
* directory rather than a name;
|
|
99
|
+
* - not `control-`-prefixed, which would let a strand's store masquerade as a
|
|
100
|
+
* party's control database (see {@link isControlStorageScope}).
|
|
101
|
+
*/
|
|
102
|
+
export function isValidStrandScopeKey(strandId) {
|
|
103
|
+
return strandId.length > 0
|
|
104
|
+
&& strandId.length <= MAX_STRAND_SCOPE_KEY_LENGTH
|
|
105
|
+
&& SCOPE_KEY_CHARSET.test(strandId)
|
|
106
|
+
&& strandId !== '.'
|
|
107
|
+
&& strandId !== '..'
|
|
108
|
+
&& !isControlStorageScope(strandId);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Thrown when a strand id cannot be used as a storage scope key or network name.
|
|
112
|
+
*
|
|
113
|
+
* NOT retryable: the id is a property of the strand row, so every later attempt on
|
|
114
|
+
* the same row fails identically. Callers that poll — `CadreNode.handleStrandAdded`
|
|
115
|
+
* via `StrandWatcher` — suppress the strand rather than scheduling a retry.
|
|
116
|
+
*/
|
|
117
|
+
export class InvalidStrandIdError extends Error {
|
|
118
|
+
constructor(strandId) {
|
|
119
|
+
super(`Strand id ${JSON.stringify(strandId)} cannot be used as a storage scope key: ` +
|
|
120
|
+
`a strand id must be 1-${MAX_STRAND_SCOPE_KEY_LENGTH} characters within [A-Za-z0-9._-], ` +
|
|
121
|
+
"must not be '.' or '..', and must not begin 'control-'. " +
|
|
122
|
+
'This strand was created by a node that does not mint conforming ids; it cannot be ' +
|
|
123
|
+
'started here, because the id becomes a file, directory or database name.');
|
|
124
|
+
this.name = 'InvalidStrandIdError';
|
|
125
|
+
this.strandId = strandId;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** {@link isValidStrandScopeKey} as an assertion, throwing {@link InvalidStrandIdError}. */
|
|
129
|
+
export function assertStrandScopeKey(strandId) {
|
|
130
|
+
if (!isValidStrandScopeKey(strandId)) {
|
|
131
|
+
throw new InvalidStrandIdError(strandId);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The charset half of the rule on its own, for the CONTROL key.
|
|
136
|
+
*
|
|
137
|
+
* {@link assertStrandScopeKey} cannot serve here: it rejects the `control-` prefix by
|
|
138
|
+
* design. Asserted at the seam that calls the provider (`CadreNode.resolveControlStorage`)
|
|
139
|
+
* rather than inside {@link controlStorageScope}, so the guarantee belongs to the call
|
|
140
|
+
* that hands a key out and not to one particular way of minting one.
|
|
141
|
+
*/
|
|
142
|
+
export function assertScopeKeyCharset(scope) {
|
|
143
|
+
if (!SCOPE_KEY_CHARSET.test(scope)) {
|
|
144
|
+
throw new Error(`Storage scope key ${JSON.stringify(scope)} leaves the [A-Za-z0-9._-] charset ` +
|
|
145
|
+
'embedders rely on to use it directly as a file, directory or database name.');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
75
148
|
//# sourceMappingURL=storage-scope.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-scope.js","sourceRoot":"","sources":["../src/storage-scope.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"storage-scope.js","sourceRoot":"","sources":["../src/storage-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEjG;;;;;GAKG;AACH,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IAClD,OAAO,oBAAoB,GAAG,kBAAkB,CAAC,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;AACtG,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAa;IAClD,OAAO,KAAK,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAExC,yEAAyE;AACzE,MAAM,iBAAiB,GAAG,mBAAmB,CAAC;AAE9C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACrD,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC;WACtB,QAAQ,CAAC,MAAM,IAAI,2BAA2B;WAC9C,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC;WAChC,QAAQ,KAAK,GAAG;WAChB,QAAQ,KAAK,IAAI;WACjB,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAG9C,YAAY,QAAgB;QAC3B,KAAK,CACJ,aAAa,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,0CAA0C;YAC/E,yBAAyB,2BAA2B,qCAAqC;YACzF,0DAA0D;YAC1D,oFAAoF;YACpF,0EAA0E,CAC1E,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC1B,CAAC;CACD;AAED,4FAA4F;AAC5F,MAAM,UAAU,oBAAoB,CAAC,QAAgB;IACpD,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;AACF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAa;IAClD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CACd,qBAAqB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,qCAAqC;YAC/E,6EAA6E,CAC7E,CAAC;IACH,CAAC;AACF,CAAC"}
|
|
@@ -4,6 +4,7 @@ import { FormationApprovalError } from './formation-approval.js';
|
|
|
4
4
|
// control-database does not import this manager, so this import introduces no cycle.
|
|
5
5
|
import { FormationAbortedError, InvitationExhaustedError } from './control-database.js';
|
|
6
6
|
import { PreSplitStrandIdentityError } from './strand-membership-writer.js';
|
|
7
|
+
import { mintPlaceholderStrandId } from './strand-id.js';
|
|
7
8
|
import { canonicalJson } from './canonical-json.js';
|
|
8
9
|
import { FormationListener, INVALID_TOKEN_REASON, PROVISION_RESPONSE_TRAVEL_MARGIN_MS, dialFormation, isValidResponderCreatesResult, isWellFormedMembershipInvite } from './strand-formation-protocol.js';
|
|
9
10
|
const log = debug('sereus:cadre:formation-manager');
|
|
@@ -434,7 +435,7 @@ export class StrandFormationManager {
|
|
|
434
435
|
});
|
|
435
436
|
}
|
|
436
437
|
// No recorder + no provisioner — a structural placeholder the initiator can still validate.
|
|
437
|
-
const strandId =
|
|
438
|
+
const strandId = mintPlaceholderStrandId();
|
|
438
439
|
return this.approve({
|
|
439
440
|
strand: { strandId, createdBy: 'responder' },
|
|
440
441
|
dbConnectionInfo: { endpoint: 'local', credentialsRef: '' }
|