p2party 0.14.2 → 0.14.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 +230 -30
- package/docs/getting-started.md +15 -0
- package/docs/protocol-v4-security.md +40 -0
- package/docs/references.md +28 -8
- package/docs/session-api.md +10 -2
- package/lib/api/signalingServerApi.d.ts +13 -2
- package/lib/api/webrtc/applyIceConfiguration.d.ts +9 -0
- package/lib/api/webrtc/dataChannelHandler.d.ts +10 -0
- package/lib/api/webrtc/deleteRoomData.d.ts +13 -0
- package/lib/api/webrtc/disconnectFromAllRoomsQuery.d.ts +2 -1
- package/lib/api/webrtc/disconnectFromRoomQuery.d.ts +2 -1
- package/lib/api/webrtc/disconnectQuery.d.ts +2 -1
- package/lib/api/webrtc/iceRepair.d.ts +3 -1
- package/lib/api/webrtc/index.d.ts +2 -1
- package/lib/api/webrtc/interfaces.d.ts +37 -0
- package/lib/api/webrtc/negotiationLock.d.ts +24 -0
- package/lib/api/webrtc/pendingOffer.d.ts +29 -0
- package/lib/api/webrtc/rebindDeadline.d.ts +61 -0
- package/lib/api/webrtc/remoteTransportChange.d.ts +142 -0
- package/lib/api/webrtc/retiredRemoteTransports.d.ts +70 -0
- package/lib/api/webrtc/roomEdgeBudget.d.ts +10 -0
- package/lib/api/webrtc/setDescriptionQuery.d.ts +8 -1
- package/lib/api/webrtc/settleOnClose.d.ts +36 -0
- package/lib/blindRendezvous/admissionInput.d.ts +11 -0
- package/lib/blindRendezvous/admissionPolicy.d.ts +217 -0
- package/lib/blindRendezvous/canonicalSchema.d.ts +139 -0
- package/lib/blindRendezvous/carrierEnvelope.d.ts +105 -0
- package/lib/blindRendezvous/coreReduce.d.ts +199 -0
- package/lib/blindRendezvous/derivations.d.ts +381 -0
- package/lib/blindRendezvous/identityHelloAdmission.d.ts +89 -0
- package/lib/blindRendezvous/identityHelloAdmissionPersistence.d.ts +133 -0
- package/lib/blindRendezvous/identityHelloHistoricalEvidence.d.ts +52 -0
- package/lib/blindRendezvous/identityHelloOpen.d.ts +167 -0
- package/lib/blindRendezvous/identityHelloTrial.d.ts +271 -0
- package/lib/blindRendezvous/localAdmissibleProject.d.ts +101 -0
- package/lib/blindRendezvous/localPresenceKeyBinding.d.ts +108 -0
- package/lib/blindRendezvous/localStableIdentityCustody.d.ts +46 -0
- package/lib/blindRendezvous/normativeKernel.d.ts +222 -0
- package/lib/blindRendezvous/operation.d.ts +137 -0
- package/lib/blindRendezvous/operationPayload.d.ts +134 -0
- package/lib/blindRendezvous/pairBootstrapSuite.d.ts +93 -0
- package/lib/blindRendezvous/pairCrypto.d.ts +122 -0
- package/lib/blindRendezvous/pairLedger.d.ts +154 -0
- package/lib/blindRendezvous/pairOpenBudget.d.ts +67 -0
- package/lib/blindRendezvous/pairOpenReservation.d.ts +157 -0
- package/lib/blindRendezvous/pairPlaintext.d.ts +240 -0
- package/lib/blindRendezvous/pairStepEnvelope.d.ts +60 -0
- package/lib/blindRendezvous/plannerState.d.ts +61 -0
- package/lib/blindRendezvous/projections.d.ts +71 -0
- package/lib/blindRendezvous/publicWindow.d.ts +330 -0
- package/lib/blindRendezvous/retainedOperationStore.d.ts +187 -0
- package/lib/blindRendezvous/roomInviteV2.d.ts +92 -0
- package/lib/blindRendezvous/roomPolicyV4.d.ts +90 -0
- package/lib/blindRendezvous/schemas.d.ts +221 -0
- package/lib/blindRendezvous/storeDescriptor.d.ts +160 -0
- package/lib/cryptography/aeadWasm.d.ts +18 -0
- package/lib/cryptography/byteInput.d.ts +12 -0
- package/lib/cryptography/carrierAead.d.ts +23 -0
- package/lib/cryptography/chacha20poly1305.d.ts +7 -0
- package/lib/cryptography/fips202.d.ts +10 -0
- package/lib/cryptography/hpke.d.ts +84 -0
- package/lib/cryptography/hpkeSuite.d.ts +39 -0
- package/lib/cryptography/hybridKem.d.ts +42 -0
- package/lib/cryptography/hybridKemSuite.d.ts +22 -0
- package/lib/cryptography/interfaces.d.ts +3 -0
- package/lib/cryptography/mlkem.d.ts +27 -1
- package/lib/cryptography/mnemonic.d.ts +65 -1
- package/lib/cryptography/ownedEd25519KeyMaterial.d.ts +27 -0
- package/lib/cryptography/webCryptoSha256.d.ts +20 -0
- package/lib/cryptography/x25519.d.ts +18 -0
- package/lib/cryptography/xchacha20poly1305.d.ts +7 -0
- package/lib/db/api.d.ts +6 -3
- package/lib/db/identityEd25519ClientBoundary.d.ts +13 -0
- package/lib/db/src/getDB.d.ts +2 -2
- package/lib/db/types.d.ts +52 -4
- package/lib/db.worker.js +1 -1
- package/lib/handlers/coverChannelRegistry.d.ts +22 -0
- package/lib/handlers/edgeTeardownFollowUp.d.ts +35 -0
- package/lib/handlers/handleChallenge.d.ts +2 -1
- package/lib/handlers/handleConnectToPeer.d.ts +1 -1
- package/lib/handlers/handleHandshake.d.ts +2 -6
- package/lib/handlers/handleSendMessage.d.ts +60 -7
- package/lib/handlers/handleWebSocketMessage.d.ts +1 -1
- package/lib/handlers/handshakeCore.d.ts +2 -7
- package/lib/handlers/handshakeFrame.d.ts +25 -0
- package/lib/handlers/ratchetGateWait.d.ts +13 -0
- package/lib/handlers/reconcile.d.ts +24 -0
- package/lib/handlers/requestRoom.d.ts +30 -0
- package/lib/handlers/roomResponse.d.ts +53 -0
- package/lib/index.d.ts +99 -12
- package/lib/index.js +1 -1
- package/lib/index.min.js +1 -1
- package/lib/index.mjs +1 -1
- package/lib/libcrypto.provenance.json +5 -5
- package/lib/libcrypto.wasm +0 -0
- package/lib/middleware/roomListenerMiddleware.d.ts +4 -1
- package/lib/reducers/commonSlice.d.ts +3 -2
- package/lib/reducers/keyPairSlice.d.ts +3 -6
- package/lib/reducers/roomSlice.d.ts +81 -5
- package/lib/reducers/signalingServerSlice.d.ts +3 -2
- package/lib/session.d.ts +6 -3
- package/lib/session.js +1 -1
- package/lib/session.mjs +1 -1
- package/lib/store.d.ts +4 -2
- package/lib/utils/constants.d.ts +12 -0
- package/lib/utils/correlationId.d.ts +4 -0
- package/lib/utils/identityRestore.d.ts +108 -0
- package/lib/utils/interfaces.d.ts +25 -6
- package/lib/utils/roomConnectAdmission.d.ts +15 -0
- package/lib/utils/roomLeaveCoordinator.d.ts +38 -0
- package/lib/utils/roomRequestCoordinator.d.ts +104 -0
- package/lib/utils/roomRosterReconciler.d.ts +83 -0
- package/lib/utils/sdpFingerprint.d.ts +6 -0
- package/lib/utils/signalingAttemptLifecycle.d.ts +33 -0
- package/lib/utils/signalingAuth.d.ts +21 -2
- package/lib/utils/signalingBounds.d.ts +6 -0
- package/lib/utils/signalingFrame.d.ts +21 -0
- package/lib/utils/signalingHeartbeatWatchdog.d.ts +45 -0
- package/lib/utils/signalingIngressQueue.d.ts +49 -0
- package/lib/utils/signalingPeerRequestDebouncer.d.ts +13 -0
- package/lib/utils/signalingRoomLifecycle.d.ts +7 -0
- package/lib/utils/signalingRoomOperationLifecycle.d.ts +14 -0
- package/lib/utils/signalingServerBoundary.d.ts +11 -0
- package/lib/utils/terminalSettlement.d.ts +53 -0
- package/lib/utils/transportIdentity.d.ts +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,15 +38,24 @@ Apache-2.0 · [LICENSE.md](LICENSE.md)
|
|
|
38
38
|
Browser builds use IndexedDB and, where available, OPFS for disk-backed large
|
|
39
39
|
file receipt.
|
|
40
40
|
- Room capabilities have a compact 43-character base64url form, a versioned
|
|
41
|
-
fragment invite, and an optional checksum-protected 24-word
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
fragment invite, and an optional checksum-protected 24-word representation
|
|
42
|
+
drawn from the
|
|
43
|
+
[BIP-39 English wordlist](https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md).
|
|
44
|
+
It borrows the words, not the format: the checksum is SHA-256 over p2party's
|
|
45
|
+
own domain separator, so a BIP-39 phrase is not a valid invite. See
|
|
46
|
+
[docs/references.md](docs/references.md).
|
|
47
|
+
- An identity created from a recovery phrase can be restored on another device:
|
|
48
|
+
12 to 48 words drawn from the same wordlist, checksummed with SHA-512 and
|
|
49
|
+
stretched into the Ed25519 seed with argon2id. The derivation runs one way, so
|
|
50
|
+
a randomly generated identity cannot be exported — it can only be replaced by
|
|
51
|
+
a recoverable one. See
|
|
52
|
+
[Back up and restore your identity](#back-up-and-restore-your-identity).
|
|
44
53
|
- `p2party/session` exposes the cryptography without
|
|
45
54
|
[Redux](https://redux-toolkit.js.org/), IndexedDB, WebRTC, signaling,
|
|
46
55
|
`window`, or `localStorage`.
|
|
47
56
|
|
|
48
57
|
Immediate delivery over the existing signaling rendezvous is the shipped
|
|
49
|
-
default. Scheduled timing cover is also wired
|
|
58
|
+
default. Scheduled timing cover is also wired: a room policy may
|
|
50
59
|
pin a cadence, lane count, and frames per cell, and every edge in the room then
|
|
51
60
|
emits fixed-size cells on that schedule whether or not there is data to send.
|
|
52
61
|
Sparse post-quantum healing (the OFFER/ADVANCE/ACK epoch exchange) is likewise
|
|
@@ -81,7 +90,7 @@ npm audit signatures
|
|
|
81
90
|
|
|
82
91
|
To build the artifact yourself instead, see
|
|
83
92
|
[Building from source](CONTRIBUTING.md#building-from-source). That path needs an
|
|
84
|
-
exact toolchain (Node 24, Emscripten 6.0.
|
|
93
|
+
exact toolchain (Node 24, Emscripten 6.0.9, pinned submodules), because the
|
|
85
94
|
release build reproduces the pinned WASM and refuses to emit an artifact it
|
|
86
95
|
cannot attest.
|
|
87
96
|
|
|
@@ -192,6 +201,63 @@ protocol-v4 acknowledgement: p2party next runs its authenticated HELLO plus
|
|
|
192
201
|
three chained confirmation flights over the main channel. Message receipts are
|
|
193
202
|
a third, delivery-level acknowledgement.
|
|
194
203
|
|
|
204
|
+
### When a peer sleeps
|
|
205
|
+
|
|
206
|
+
A phone that backgrounds with its radio off for less than WebRTC's ~30 s ICE
|
|
207
|
+
consent timeout used to wake into a permanent split. Its peer had already torn
|
|
208
|
+
that edge down and built a fresh one, but the woken side still read
|
|
209
|
+
`connected`, reused the dead transport, and let its zombie `main` channel block
|
|
210
|
+
a replacement — so no handshake ever ran on the peer's new transport. One side
|
|
211
|
+
showed the peer reachable and every send failed undelivered; the other showed
|
|
212
|
+
no handshake at all and its sends hung forever. Only a manual reconnect cleared
|
|
213
|
+
it.
|
|
214
|
+
|
|
215
|
+
Seven behaviours now hold the edge together, and each is what the library does
|
|
216
|
+
rather than a guarantee about your network:
|
|
217
|
+
|
|
218
|
+
- **A peer edge is bound to the DTLS certificate it authenticated against.**
|
|
219
|
+
When the remote certificate changes, an already-authenticated transport is
|
|
220
|
+
replaced outright. One that never authenticated is re-authenticated in place
|
|
221
|
+
instead, at most once, so a peer that keeps presenting fresh certificates
|
|
222
|
+
still converges on a replacement rather than looping.
|
|
223
|
+
- **Descriptions from a retired transport are discarded**, so an answer
|
|
224
|
+
belonging to a dead connection can no longer poison the one that replaced it.
|
|
225
|
+
- **Every failure teardown re-dials the room** under its own debounce budget.
|
|
226
|
+
Deliberate teardowns — `disconnectFromPeer`, leaving, address-book removal —
|
|
227
|
+
do not. A superseded handshake attempt dies quietly instead of tearing down
|
|
228
|
+
the transport that superseded it.
|
|
229
|
+
- **A send to a peer that never authenticates fails inside a bounded wait**
|
|
230
|
+
with a stated reason, rather than hanging on the ratchet gate forever.
|
|
231
|
+
- **A half-open signaling socket is detected**, by a heartbeat watchdog (25 s
|
|
232
|
+
with no server ping) and on wake events, and marked disconnected so a
|
|
233
|
+
reconnect can run.
|
|
234
|
+
- **RTCPeerConnection operations settle when the connection closes underneath
|
|
235
|
+
them**, so a closing connection cannot strand the per-peer lock and wedge the
|
|
236
|
+
socket's ingress queue.
|
|
237
|
+
- **An interrupted transfer resumes across an edge re-authentication.** The
|
|
238
|
+
transfer's cipher and its cancel detection follow the cryptographic
|
|
239
|
+
generation rather than the connection object, so a channel closed by a
|
|
240
|
+
re-authentication reads as a resume, not as a peer cancelling on you.
|
|
241
|
+
|
|
242
|
+
Verified with two separate headless-Chromium processes against a Bun relay
|
|
243
|
+
mirroring the signaling server, one process SIGSTOPped whole-tree with its UDP
|
|
244
|
+
host-candidate buffers flooded — a phone asleep with the radio off. Across
|
|
245
|
+
seven scenarios (baseline, socket drop, a 20 s freeze in each identity role
|
|
246
|
+
with the socket dropped and with it kept, and a 45 s freeze) both sides
|
|
247
|
+
reconverge and exchange byte-exact messages 0.5–6.5 s after wake, and four
|
|
248
|
+
in-flight 8 MiB transfer configurations finish byte-exact with the sender
|
|
249
|
+
reporting `delivered`.
|
|
250
|
+
|
|
251
|
+
Two limits, since they are as real as the fixes. Resume follows a live page: a
|
|
252
|
+
send in flight does not survive reloading the sending page, though a reloaded
|
|
253
|
+
receiver replays receipts for what it already holds so a still-live sender
|
|
254
|
+
resends only the gaps. And when a frozen identity responder is carrying an
|
|
255
|
+
in-flight transfer, reconvergence takes about 37 s rather than the usual 5–7 s
|
|
256
|
+
— the surviving SCTP association accepts our new streams but not the peer's, so
|
|
257
|
+
recovery waits out the 30 s handshake step timeout. The transfer completes
|
|
258
|
+
correctly; the latency is a known open item on the
|
|
259
|
+
[roadmap](ROADMAP.md#near-term).
|
|
260
|
+
|
|
195
261
|
## Wire format
|
|
196
262
|
|
|
197
263
|
Fixed 65,490-byte cells, a 65-byte receipt frame, and outer frame tags that make
|
|
@@ -331,6 +397,98 @@ shape; [docs/getting-started.md](docs/getting-started.md#send-cancel-and-read)
|
|
|
331
397
|
covers reading inbound messages and the metadata-only read that avoids
|
|
332
398
|
materializing large files.
|
|
333
399
|
|
|
400
|
+
## Back up and restore your identity
|
|
401
|
+
|
|
402
|
+
An identity is an Ed25519 key pair in browser storage. Lose the profile and you
|
|
403
|
+
lose the identity — unless it was created from a recovery phrase, because the
|
|
404
|
+
phrase is the only thing that can reproduce it.
|
|
405
|
+
|
|
406
|
+
Three calls, introduced together: `getIdentityBackupStatus()` reports whether
|
|
407
|
+
the identity in use can be backed up at all, `createRecoverableIdentity()`
|
|
408
|
+
replaces it with one a phrase derives and hands back that phrase once, and
|
|
409
|
+
`restoreIdentityFromMnemonic()` adopts the identity a phrase encodes — on this
|
|
410
|
+
device or any other.
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
// Can the identity in use be backed up at all?
|
|
414
|
+
const status = await p2party.getIdentityBackupStatus();
|
|
415
|
+
// status.derivation === "mnemonic" -> a phrase restores it
|
|
416
|
+
// status.derivation === "random" -> nothing can; it can only be replaced
|
|
417
|
+
// status.derivation === null -> unknown: no identity is stored yet, or
|
|
418
|
+
// one whose provenance was never recorded.
|
|
419
|
+
// Treat it as having no backup.
|
|
420
|
+
|
|
421
|
+
if (status.derivation !== "mnemonic") {
|
|
422
|
+
// Replaces the identity in use and hands back the only copy of the phrase.
|
|
423
|
+
const { mnemonic, publicKey } = await p2party.createRecoverableIdentity({
|
|
424
|
+
strength: 256, // 24 words; 128 gives 12. Default 256.
|
|
425
|
+
// password: folded into the derivation, and just as unrecoverable.
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
// Show it once, in the UI. Never log it: console output is storage, and
|
|
429
|
+
// devtools, extensions and webview log shippers all keep it.
|
|
430
|
+
showRecoveryPhraseOnce(mnemonic);
|
|
431
|
+
console.log("recoverable identity", publicKey);
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
On another device, before connecting, adopt the identity a phrase encodes:
|
|
436
|
+
|
|
437
|
+
```ts
|
|
438
|
+
try {
|
|
439
|
+
const { publicKey } = await p2party.restoreIdentityFromMnemonic(
|
|
440
|
+
typedPhrase,
|
|
441
|
+
password, // omit unless one was used at creation
|
|
442
|
+
);
|
|
443
|
+
console.log("restored", publicKey);
|
|
444
|
+
} catch (error) {
|
|
445
|
+
if (error instanceof p2party.InvalidRecoveryPhraseError) {
|
|
446
|
+
// A typo. Nothing was disconnected and nothing was replaced, so keep the
|
|
447
|
+
// form open and let the user fix it.
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Both calls leave signaling disconnected. Come back online yourself.
|
|
452
|
+
await p2party.connect(roomUrl);
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**What the phrase is.** 12 to 48 words from the shared wordlist, checksummed
|
|
456
|
+
with SHA-512 and stretched by argon2id — salted with the optional password —
|
|
457
|
+
into the Ed25519 seed. It borrows the BIP-39 English words and nothing else, so
|
|
458
|
+
no BIP-39 wallet can restore one of these identities —
|
|
459
|
+
[docs/references.md](docs/references.md) has the exact differences. The
|
|
460
|
+
derivation runs one way: an identity can be _created_ from a phrase, never
|
|
461
|
+
exported to one.
|
|
462
|
+
|
|
463
|
+
**Existing identities cannot be exported.** Every identity the SDK generated
|
|
464
|
+
before this — and any it still generates on first connect — comes from a random
|
|
465
|
+
seed, so no phrase describes it. A newly generated one is recorded as
|
|
466
|
+
`"random"`; one that predates the record, or whose record no longer binds to
|
|
467
|
+
the stored key, reads `null`. Both mean the same thing to an app, and reporting
|
|
468
|
+
it is the point: say the identity has no backup instead of offering one that
|
|
469
|
+
cannot exist. The only route to a recoverable identity is
|
|
470
|
+
`createRecoverableIdentity()`, which _replaces_ the current one: contacts see a
|
|
471
|
+
new identity key for this device and their clients flag the change, exactly as
|
|
472
|
+
they would after a purge.
|
|
473
|
+
|
|
474
|
+
**The phrase is shown once and stored nowhere.** Neither the SDK nor its
|
|
475
|
+
storage keeps a copy, by design — a phrase at rest is the identity at rest — so
|
|
476
|
+
an app that drops it before the user has written it down has lost the backup.
|
|
477
|
+
The password is not stored or checked either: restoring with a different one
|
|
478
|
+
silently derives a different identity.
|
|
479
|
+
|
|
480
|
+
**What restoring does to a running mesh.** It rotates the account key, so it
|
|
481
|
+
takes the same exclusive path a purge does: signaling is disconnected, every
|
|
482
|
+
room's WebRTC transport is brought to a terminal state, and the cross-signed
|
|
483
|
+
X25519 identity is dropped so the next connection regenerates and re-signs it.
|
|
484
|
+
Rooms, messages, the address book and cached room PINs are all kept — reconnect
|
|
485
|
+
and you are in the same rooms under the restored key. An invalid phrase rejects
|
|
486
|
+
with `InvalidRecoveryPhraseError` before any of that starts.
|
|
487
|
+
|
|
488
|
+
While a phrase is being typed, `validateMnemonicWords(words)` is synchronous
|
|
489
|
+
and names the first word that is not in the wordlist; `validateMnemonic(phrase)`
|
|
490
|
+
adds the SHA-512 checksum and returns a promise.
|
|
491
|
+
|
|
334
492
|
## Cryptography without WebRTC
|
|
335
493
|
|
|
336
494
|
`p2party/session` is the same protocol-v4 cryptography with no Redux, no
|
|
@@ -446,7 +604,8 @@ const decoder = new TextDecoder();
|
|
|
446
604
|
const sealed = await alice.encrypt(encoder.encode("hello bob"));
|
|
447
605
|
|
|
448
606
|
// sealed.protocolVersion === 4
|
|
449
|
-
// sealed.root ->
|
|
607
|
+
// sealed.root -> 64-byte SHA-512 Merkle root, authenticated as AEAD
|
|
608
|
+
// additional data (decrypt() rejects any other length)
|
|
450
609
|
// sealed.frames -> [Uint8Array(65490)] one uniform cell; a 9-byte message and
|
|
451
610
|
// a 60 KiB message produce byte-identical frame sizes.
|
|
452
611
|
// Each frame is:
|
|
@@ -517,8 +676,8 @@ envelope codec and the sparse-PQ healing hooks are in
|
|
|
517
676
|
`joinRoom()` and `createSession()` are the batteries-included paths. Every step
|
|
518
677
|
they take is also a public call, so you can drive the protocol yourself.
|
|
519
678
|
|
|
520
|
-
**Identity, signing, and recovery phrases.** Keys are Ed25519
|
|
521
|
-
|
|
679
|
+
**Identity, signing, and recovery phrases.** Keys are Ed25519, and a phrase
|
|
680
|
+
derives one deterministically:
|
|
522
681
|
|
|
523
682
|
```ts
|
|
524
683
|
const mnemonic = await p2party.generateMnemonic(256); // 24 words
|
|
@@ -530,6 +689,20 @@ const signature = await p2party.sign(bytes, keyPair.secretKey);
|
|
|
530
689
|
const ok = await p2party.verify(bytes, signature, keyPair.publicKey);
|
|
531
690
|
```
|
|
532
691
|
|
|
692
|
+
**This phrase is not BIP-39, and a BIP-39 wallet cannot restore it.** It draws
|
|
693
|
+
its words from the BIP-39 English wordlist and nothing else: the checksum is
|
|
694
|
+
the leading bits of SHA-512 rather than SHA-256, entropy runs from 128 to 512
|
|
695
|
+
bits (12 to 48 words, where BIP-39 stops at 24), and the seed comes from
|
|
696
|
+
argon2id over the normalized phrase — with an optional password used as the
|
|
697
|
+
salt — rather than PBKDF2-HMAC-SHA512. The three canonical BIP-39 English test
|
|
698
|
+
vectors all fail `validateMnemonic()`. Treat it as a p2party-specific format.
|
|
699
|
+
|
|
700
|
+
These are the primitives. The identity the mesh actually uses is created,
|
|
701
|
+
replaced and restored through
|
|
702
|
+
[`createRecoverableIdentity()` and `restoreIdentityFromMnemonic()`](#back-up-and-restore-your-identity),
|
|
703
|
+
which take care of the storage, the cross-signed X25519 identity and the
|
|
704
|
+
transports authenticated by the outgoing key.
|
|
705
|
+
|
|
533
706
|
**Room policy as data.** A policy is a value you can encode, hash, compare and
|
|
534
707
|
validate before anything touches the network — useful for showing two peers
|
|
535
708
|
that they really are about to join the same room:
|
|
@@ -622,7 +795,16 @@ is what this package compiles.
|
|
|
622
795
|
|
|
623
796
|
## No build step: a script tag and the CDN
|
|
624
797
|
|
|
625
|
-
|
|
798
|
+
> **`0.14.7` is not on the CDN yet.** The release pipeline uploads its objects
|
|
799
|
+
> from the tarball it publishes, and that pipeline has not run for this
|
|
800
|
+
> version: every path under `https://cdn.p2party.com/@0.14.7/` currently
|
|
801
|
+
> answers 404, and npm still resolves `p2party` to an older release. The
|
|
802
|
+
> snippet below is generated from this build and is what the release will
|
|
803
|
+
> serve — until then, either pin the version `npm view p2party version` reports
|
|
804
|
+
> (its objects are live) or self-host the bundle, which works today and is
|
|
805
|
+
> described in the next section.
|
|
806
|
+
|
|
807
|
+
A release publishes its browser bundle, its database worker and its
|
|
626
808
|
cryptographic module as immutable, versioned CDN objects. The version is in the
|
|
627
809
|
path, so a URL names exactly one build and is safe to cache forever. Drop the
|
|
628
810
|
script in and `window.p2party` is there — no npm, no bundler, no build:
|
|
@@ -633,8 +815,8 @@ script in and `window.p2party` is there — no npm, no bundler, no build:
|
|
|
633
815
|
<title>p2party in one file</title>
|
|
634
816
|
|
|
635
817
|
<script
|
|
636
|
-
src="https://cdn.p2party.com/@0.14.
|
|
637
|
-
integrity="sha384-
|
|
818
|
+
src="https://cdn.p2party.com/@0.14.7/p2party.min.js"
|
|
819
|
+
integrity="sha384-Wh2Pxka9YN2oAZmzYgaoyLmfKQMXsMO4AfUmshluGmYjfS0+ahOZGCTBGHtKTcC9"
|
|
638
820
|
crossorigin="anonymous"
|
|
639
821
|
></script>
|
|
640
822
|
|
|
@@ -665,15 +847,15 @@ connect directly to each other.
|
|
|
665
847
|
The three published objects:
|
|
666
848
|
|
|
667
849
|
```text
|
|
668
|
-
https://cdn.p2party.com
|
|
669
|
-
https://cdn.p2party.com
|
|
670
|
-
https://cdn.p2party.com
|
|
850
|
+
https://cdn.p2party.com/@<version>/p2party.min.js UMD bundle -> window.p2party
|
|
851
|
+
https://cdn.p2party.com/@<version>/db.worker.js IndexedDB/OPFS worker
|
|
852
|
+
https://cdn.p2party.com/@<version>/libcrypto.wasm the cryptographic module
|
|
671
853
|
```
|
|
672
854
|
|
|
673
855
|
The `integrity` value above is this release's bundle, and the release build
|
|
674
856
|
fails if the README and the built artifact ever disagree — so it is safe to
|
|
675
857
|
copy verbatim. The worker, if you host it yourself, is
|
|
676
|
-
`sha384-
|
|
858
|
+
`integrity=sha384-BudWf1U+vDU/j4pf2sX+bLogS/7MuPyzKRA9AfLoZqdbduUCwYr42p38rEoQRXa8`.
|
|
677
859
|
|
|
678
860
|
The WASM is integrity-checked whether or not you pin the script: that hash is
|
|
679
861
|
compiled into the bundle and cannot be turned off.
|
|
@@ -688,40 +870,58 @@ same release bytes before calling `connect()`:
|
|
|
688
870
|
import p2party from "p2party";
|
|
689
871
|
|
|
690
872
|
p2party.setWasmSourceUrl(
|
|
691
|
-
new URL("/vendor/p2party
|
|
873
|
+
new URL("/vendor/p2party/libcrypto.wasm", window.location.href),
|
|
692
874
|
);
|
|
693
875
|
```
|
|
694
876
|
|
|
695
877
|
The SRI check remains active, so a URL serving different bytes fails closed.
|
|
696
878
|
|
|
697
|
-
###
|
|
879
|
+
### Get the WASM and check it
|
|
880
|
+
|
|
881
|
+
The npm tarball is the copy that always exists. It carries both files, and the
|
|
882
|
+
package exports them, so no network fetch is needed to obtain either:
|
|
883
|
+
|
|
884
|
+
```sh
|
|
885
|
+
npm pack p2party && tar -xzf p2party-*.tgz
|
|
886
|
+
ls package/lib/libcrypto.wasm package/lib/libcrypto.provenance.json
|
|
887
|
+
# already installed? the subpaths resolve straight out of node_modules:
|
|
888
|
+
node -p "require.resolve('p2party/libcrypto.wasm')"
|
|
889
|
+
node -p "require.resolve('p2party/libcrypto.provenance.json')"
|
|
890
|
+
```
|
|
698
891
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
892
|
+
A published release also mirrors its cryptographic module to the CDN under an
|
|
893
|
+
immutable, versioned path, so a URL names exactly one build and is safe to
|
|
894
|
+
cache forever:
|
|
702
895
|
|
|
703
896
|
```sh
|
|
704
|
-
curl -O https://cdn.p2party.com
|
|
705
|
-
curl -O https://cdn.p2party.com/@0.14.2/libcrypto.provenance.json
|
|
897
|
+
curl -O "https://cdn.p2party.com/@$(npm view p2party version)/libcrypto.wasm"
|
|
706
898
|
```
|
|
707
899
|
|
|
900
|
+
Two caveats, both current as of this release. The CDN carries only three
|
|
901
|
+
objects — `p2party.min.js`, `db.worker.js` and `libcrypto.wasm` (see the
|
|
902
|
+
`assets` array in `scripts/uploadToCDN.mjs`) — so
|
|
903
|
+
**`libcrypto.provenance.json` is not on the CDN for any version**; take it from
|
|
904
|
+
the tarball. And nothing is uploaded for this release yet, which is why the
|
|
905
|
+
command above asks npm for a version that is actually published instead of
|
|
906
|
+
naming this one.
|
|
907
|
+
|
|
708
908
|
Check what you downloaded before you serve it. The SHA-256 and the SRI value
|
|
709
|
-
are both recorded in the provenance file
|
|
909
|
+
are both recorded in the provenance file:
|
|
710
910
|
|
|
711
911
|
```sh
|
|
712
912
|
shasum -a 256 libcrypto.wasm
|
|
713
913
|
openssl dgst -sha384 -binary libcrypto.wasm | openssl base64 -A
|
|
714
914
|
```
|
|
715
915
|
|
|
716
|
-
|
|
717
|
-
`
|
|
718
|
-
`
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
`npm publish` runs, so the two can never diverge.
|
|
916
|
+
Compare them against `libcrypto.provenance.json`, which records the same
|
|
917
|
+
`sha256` and `sri` for the bytes the same release ships. CDN and npm cannot
|
|
918
|
+
diverge for a release the pipeline actually ran: `.github/workflows/release.yml`
|
|
919
|
+
unpacks the validated tarball, uploads the CDN object from it, and runs
|
|
920
|
+
`npm run verify:cdn` before `npm publish`.
|
|
722
921
|
|
|
723
922
|
Serve the file yourself and point the browser root at it with
|
|
724
923
|
`setWasmSourceUrl()` above, or hand the bytes straight to `p2party/session`.
|
|
924
|
+
Self-hosting is the path that works today for every version, published or not.
|
|
725
925
|
|
|
726
926
|
On Node and Bun, `p2party/session` needs none of this: it reads the WASM from
|
|
727
927
|
the installed package and checks it against the same pinned SHA-384, so an
|
|
@@ -750,7 +950,7 @@ release rather than surfacing later as a broken offline install.
|
|
|
750
950
|
## Development
|
|
751
951
|
|
|
752
952
|
The reproducible release toolchain is Node 24.11.1, npm 11.6.2, Bun 1.3.14,
|
|
753
|
-
Emscripten 6.0.
|
|
953
|
+
Emscripten 6.0.9, and the repository's pinned libsodium source object. npm and
|
|
754
954
|
`package-lock.json` are the dependency authority; Bun is the test runner.
|
|
755
955
|
|
|
756
956
|
```sh
|
package/docs/getting-started.md
CHANGED
|
@@ -174,6 +174,21 @@ returned. The application limit is 10 GiB. Cancellation is scoped most
|
|
|
174
174
|
precisely by the handle's transfer ID, so prefer `handle.cancel()` over a
|
|
175
175
|
content-hash lookup for concurrent identical sends.
|
|
176
176
|
|
|
177
|
+
## Back up and restore an identity
|
|
178
|
+
|
|
179
|
+
The identity behind every room is an Ed25519 key pair in browser storage, and
|
|
180
|
+
only an identity created from a recovery phrase can be brought back after that
|
|
181
|
+
storage is gone. `getIdentityBackupStatus()` says which kind is in use,
|
|
182
|
+
`createRecoverableIdentity()` replaces the current identity with one a phrase
|
|
183
|
+
reproduces and returns that phrase exactly once, and
|
|
184
|
+
`restoreIdentityFromMnemonic()` adopts the identity a phrase encodes. The
|
|
185
|
+
derivation is one way — an identity generated randomly, which is every identity
|
|
186
|
+
that existed before these calls, cannot be exported to a phrase — and both
|
|
187
|
+
calls replace the account key, so contacts see an identity change and signaling
|
|
188
|
+
is left disconnected until you `connect()` again. The full contract, including
|
|
189
|
+
what survives a restore and what a mistyped phrase costs, is in the
|
|
190
|
+
[README](../README.md#back-up-and-restore-your-identity).
|
|
191
|
+
|
|
177
192
|
## Package artifacts and WASM
|
|
178
193
|
|
|
179
194
|
The 0.14 package exports:
|
|
@@ -126,6 +126,46 @@ Putting the capability in a URL fragment keeps it out of ordinary HTTP
|
|
|
126
126
|
requests and common access logs, but the shipped legacy signaling path still
|
|
127
127
|
receives its normalized value. A fragment is not a server-blind meeting point.
|
|
128
128
|
|
|
129
|
+
## Signaling and TURN correctness boundary
|
|
130
|
+
|
|
131
|
+
SDK 0.14.7 makes legacy signaling state transitions correlated and bounded; it
|
|
132
|
+
does not make that signaling path blind.
|
|
133
|
+
|
|
134
|
+
- A room response is accepted only for the exact current socket, room
|
|
135
|
+
capability, and UUIDv4 request. A delayed response cannot configure another
|
|
136
|
+
room.
|
|
137
|
+
- Caller ICE configuration and signaling-managed TURN credentials are separate
|
|
138
|
+
inputs. Managed credentials carry an absolute expiry, are applied to every
|
|
139
|
+
live room edge before an ICE restart, refresh proactively, and are removed or
|
|
140
|
+
failed closed when they expire.
|
|
141
|
+
- `purgeRoom()` tears down local transports and durable state before waiting
|
|
142
|
+
for a correlated server acknowledgement. The leave is keyed by the stable
|
|
143
|
+
room capability rather than the server-assigned room UUID, so a purge racing
|
|
144
|
+
an in-flight join still revokes that membership. Matching `p2party-server`
|
|
145
|
+
0.1.1 unlinks the authenticated peer from the room before acknowledging. An
|
|
146
|
+
offline or non-acknowledging server produces
|
|
147
|
+
`RemoteRoomRevocationUnconfirmedError`; it is never reported as confirmed.
|
|
148
|
+
- Signaling ingress, room rosters, live mesh edges, pending ICE, and channel
|
|
149
|
+
registries have explicit client-side bounds. Those bounds limit one client's
|
|
150
|
+
exposure; they are not server-side Sybil resistance or a global availability
|
|
151
|
+
proof.
|
|
152
|
+
|
|
153
|
+
TURN is a transport relay, not a privacy proxy. The legacy REST username is
|
|
154
|
+
expiry-bound but contains the client's Ed25519 public key, and the TURN
|
|
155
|
+
operator can observe source addresses, allocations, timing, and byte volume.
|
|
156
|
+
Neither relay use nor TLS makes the signaling operator unable to read SDP, ICE,
|
|
157
|
+
room capabilities, or membership.
|
|
158
|
+
|
|
159
|
+
The current challenge proves possession of the presented Ed25519 key to the
|
|
160
|
+
server by signing a fresh nonce. Its transcript is not bound to a server
|
|
161
|
+
identity or origin, so it does not resist a malicious server relaying another
|
|
162
|
+
server's nonce as a signing oracle. The legacy service also has no
|
|
163
|
+
cross-instance session-generation fence or Byzantine quorum. Consequently none
|
|
164
|
+
of malicious-rendezvous blindness, two-server BFT, social-graph hiding,
|
|
165
|
+
server-bound authentication, shutdown survival, or post-quantum signaling
|
|
166
|
+
authentication is a property of this path. Those remain requirements of the
|
|
167
|
+
versioned blind-rendezvous design.
|
|
168
|
+
|
|
129
169
|
## Shipped, implemented core, and research
|
|
130
170
|
|
|
131
171
|
| Status | Exact boundary in 0.14 |
|
package/docs/references.md
CHANGED
|
@@ -13,13 +13,33 @@ These are compiled into the shipped `libcrypto.wasm` or bundled into the
|
|
|
13
13
|
package. Licences and notices are reproduced in
|
|
14
14
|
[THIRD_PARTY_NOTICES.md](../THIRD_PARTY_NOTICES.md).
|
|
15
15
|
|
|
16
|
-
| Project | Used for
|
|
17
|
-
| ----------------------- |
|
|
18
|
-
| libsodium | X25519, Ed25519, ChaCha20-Poly1305, BLAKE2b, HKDF, Argon2, SHA-512
|
|
19
|
-
| mlkem-native | ML-KEM-512/768/1024 (FIPS 203)
|
|
20
|
-
| Emscripten | Compiles the C cryptography to the pinned WASM module
|
|
21
|
-
| BIP-39 English wordlist | The
|
|
22
|
-
| Redux Toolkit | Browser-root state store
|
|
16
|
+
| Project | Used for | Link |
|
|
17
|
+
| ----------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
|
18
|
+
| libsodium | X25519, Ed25519, ChaCha20-Poly1305, BLAKE2b, HKDF, Argon2, SHA-512 | [github.com/jedisct1/libsodium](https://github.com/jedisct1/libsodium) |
|
|
19
|
+
| mlkem-native | ML-KEM-512/768/1024 (FIPS 203) | [github.com/pq-code-package/mlkem-native](https://github.com/pq-code-package/mlkem-native) |
|
|
20
|
+
| Emscripten | Compiles the C cryptography to the pinned WASM module | [emscripten.org](https://emscripten.org/) |
|
|
21
|
+
| BIP-39 English wordlist | The 2,048 words only, shared by room invites and identity recovery phrases — see the note below | [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md) |
|
|
22
|
+
| Redux Toolkit | Browser-root state store | [redux-toolkit.js.org](https://redux-toolkit.js.org/) |
|
|
23
|
+
|
|
24
|
+
`src/utils/wordlist.json` is the BIP-39 English list, and that is the whole
|
|
25
|
+
extent of the relationship. Two unrelated encodings share it, and **neither
|
|
26
|
+
uses BIP-39 checksum semantics**:
|
|
27
|
+
|
|
28
|
+
- the 24-word room invite (`src/roomInvite.ts`), which encodes a 32-byte room
|
|
29
|
+
capability and checksums it with SHA-256 over the domain separator
|
|
30
|
+
`p2party/room-invite/checksum/v1\0`, under its own wordlist id
|
|
31
|
+
`p2party-invite-en-v1`; and
|
|
32
|
+
- the identity recovery phrase (`src/cryptography/mnemonic.ts`), which takes
|
|
33
|
+
128–512 bits of entropy (12–48 words), checksums with the leading bits of
|
|
34
|
+
SHA-512, and derives its seed with argon2id rather than PBKDF2-HMAC-SHA512.
|
|
35
|
+
This is the phrase
|
|
36
|
+
[identity backup and restore](../README.md#back-up-and-restore-your-identity)
|
|
37
|
+
derives an Ed25519 identity from; the invite encodes a room capability and
|
|
38
|
+
restores no identity at all.
|
|
39
|
+
|
|
40
|
+
Both reject the canonical BIP-39 English test vectors — the invite decoder with
|
|
41
|
+
`Room invite checksum is invalid`, `validateMnemonic()` by returning `false` —
|
|
42
|
+
and no BIP-39 tool can restore either. Do not describe them as BIP-39.
|
|
23
43
|
|
|
24
44
|
## 2. Standards the wire format implements
|
|
25
45
|
|
|
@@ -152,6 +172,6 @@ third-party security audit. Cite the implementation:
|
|
|
152
172
|
@software{p2party,
|
|
153
173
|
title = {p2party: protocol-v4 end-to-end encryption over a WebRTC room mesh},
|
|
154
174
|
url = {https://github.com/p2party/p2party-js},
|
|
155
|
-
note = {Version 0.14.
|
|
175
|
+
note = {Version 0.14.7}
|
|
156
176
|
}
|
|
157
177
|
```
|
package/docs/session-api.md
CHANGED
|
@@ -450,8 +450,16 @@ interface SessionCryptoOptions {
|
|
|
450
450
|
|
|
451
451
|
Supplying bytes is the reproducible, offline-safe path. Resolve the exported
|
|
452
452
|
`p2party/libcrypto.wasm` package subpath or pin a self-hosted copy from the same
|
|
453
|
-
release.
|
|
454
|
-
|
|
453
|
+
release.
|
|
454
|
+
|
|
455
|
+
Omitting `wasmBinary` does not always mean a network call. On Node and Bun the
|
|
456
|
+
loader reads this release's WASM from the installed package — the file next to
|
|
457
|
+
the bundle — and hashes it against the build-pinned SHA-384 before use, so an
|
|
458
|
+
offline or air-gapped install needs no configuration. It falls back to the
|
|
459
|
+
immutable versioned p2party CDN artifact, under the same SRI, only when that
|
|
460
|
+
read fails or the digest does not match. In a browser, where there is no
|
|
461
|
+
filesystem, the CDN fetch is the only path. An explicit `setWasmSourceUrl()` is
|
|
462
|
+
honoured everywhere, including on Node, in preference to the packaged copy.
|
|
455
463
|
|
|
456
464
|
See [Protocol-v4 security](protocol-v4-security.md) for the exact claims and
|
|
457
465
|
non-claims of the session this API constructs.
|
|
@@ -1,15 +1,26 @@
|
|
|
1
|
+
import { type RequestRoomLeaveOptions } from "../utils/roomLeaveCoordinator";
|
|
1
2
|
import type { BaseQueryFn } from "@reduxjs/toolkit/query";
|
|
2
|
-
import type { WebSocketMessageCandidateSend, WebSocketMessageDescriptionSend, WebSocketMessageChallengeResponse, WebSocketMessageRoomIdRequest, WebSocketMessagePeersRequest, WebSocketMessageConnectionResponse, WebSocketMessagePongResponse, WebSocketPeerConnectionParams } from "../utils/interfaces";
|
|
3
|
+
import type { WebSocketMessageCandidateSend, WebSocketMessageDescriptionSend, WebSocketMessageChallengeResponse, WebSocketMessageRoomIdRequest, WebSocketMessagePeersRequest, WebSocketMessageConnectionResponse, WebSocketMessagePongResponse, WebSocketMessageLeaveRoomRequest, WebSocketPeerConnectionParams, WebSocketMessagePeerConnectionRequest } from "../utils/interfaces";
|
|
4
|
+
import type { BaseQueryApi } from "@reduxjs/toolkit/query";
|
|
3
5
|
export interface WebSocketParams {
|
|
4
6
|
signalingServerUrl: string;
|
|
5
7
|
}
|
|
6
8
|
export interface WebSocketMessage {
|
|
7
|
-
content: WebSocketMessagePongResponse | WebSocketMessageCandidateSend | WebSocketMessageDescriptionSend | WebSocketMessageChallengeResponse | WebSocketMessageRoomIdRequest | WebSocketMessagePeersRequest | WebSocketMessageConnectionResponse;
|
|
9
|
+
content: WebSocketMessagePongResponse | WebSocketMessageCandidateSend | WebSocketMessageDescriptionSend | WebSocketMessageChallengeResponse | WebSocketMessageRoomIdRequest | WebSocketMessageLeaveRoomRequest | WebSocketMessagePeersRequest | WebSocketMessageConnectionResponse | WebSocketMessagePeerConnectionRequest;
|
|
8
10
|
}
|
|
11
|
+
type CurrentSocketApi = Pick<BaseQueryApi, "dispatch" | "getState">;
|
|
12
|
+
/**
|
|
13
|
+
* Send a correlated leave on the exact authenticated socket and wait for its
|
|
14
|
+
* exact acknowledgement. The caller must make local room transport terminal
|
|
15
|
+
* before invoking this network-only boundary.
|
|
16
|
+
*/
|
|
17
|
+
export declare const requestCurrentSocketRoomLeave: (api: CurrentSocketApi, roomUrl: string, options?: RequestRoomLeaveOptions) => Promise<void>;
|
|
9
18
|
declare const signalingServerApi: import("@reduxjs/toolkit/query").Api<BaseQueryFn<WebSocketParams, undefined>, {
|
|
10
19
|
connectWebSocket: import("@reduxjs/toolkit/query").MutationDefinition<string, BaseQueryFn<WebSocketParams, undefined>, never, undefined, "signalingServerApi", undefined>;
|
|
11
20
|
disconnectWebSocket: import("@reduxjs/toolkit/query").MutationDefinition<undefined, BaseQueryFn<WebSocketParams, undefined>, never, undefined, "signalingServerApi", undefined>;
|
|
12
21
|
sendMessage: import("@reduxjs/toolkit/query").MutationDefinition<WebSocketMessage, BaseQueryFn<WebSocketParams, undefined>, never, undefined, "signalingServerApi", undefined>;
|
|
13
22
|
connectWithPeer: import("@reduxjs/toolkit/query").MutationDefinition<WebSocketPeerConnectionParams, BaseQueryFn<WebSocketParams, undefined>, never, undefined, "signalingServerApi", undefined>;
|
|
14
23
|
}, "signalingServerApi", never, typeof import("@reduxjs/toolkit/query").coreModuleName>;
|
|
24
|
+
/** Queue one room request or reject immediately when RTK reports no send. */
|
|
25
|
+
export declare const sendRoomRequestMessage: (api: Pick<BaseQueryApi, "dispatch">, request: WebSocketMessageRoomIdRequest) => Promise<void>;
|
|
15
26
|
export default signalingServerApi;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { IRTCPeerConnection } from "./interfaces";
|
|
2
|
+
/**
|
|
3
|
+
* Apply the room's current effective ICE servers to every live transport.
|
|
4
|
+
*
|
|
5
|
+
* getConfiguration() preserves construction-time WebRTC options that browsers
|
|
6
|
+
* do not allow setConfiguration() to change. Only the refreshable ICE list is
|
|
7
|
+
* replaced.
|
|
8
|
+
*/
|
|
9
|
+
export declare const applyRoomIceConfiguration: (peerConnections: readonly IRTCPeerConnection[], roomId: string, rtcConfig: RTCConfiguration, restartIceAfterApply?: boolean, failurePolicy?: "rollback" | "close") => number;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { handleOpenChannel } from "../../handlers/handleOpenChannel";
|
|
2
|
+
import type { IRTCDataChannel, IRTCPeerConnection } from "./interfaces";
|
|
3
|
+
/**
|
|
4
|
+
* Wires a transport's `ondatachannel` to handleOpenChannel: every inbound
|
|
5
|
+
* channel goes through the same admission as a locally created one, and an
|
|
6
|
+
* inbound `main` becomes the transport's main channel. Shared by the fresh
|
|
7
|
+
* transports built from a roster introduction (connectWithPeer) and from an
|
|
8
|
+
* inbound offer (setDescription), so the two never drift.
|
|
9
|
+
*/
|
|
10
|
+
export declare const attachDataChannelHandler: (epc: IRTCPeerConnection, dataChannels: IRTCDataChannel[], api: Parameters<typeof handleOpenChannel>[1]) => void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MessageData } from "../../db/types";
|
|
2
|
+
export interface DeleteRoomDataDependencies {
|
|
3
|
+
readonly getMessages: (roomId: string) => Promise<MessageData[]>;
|
|
4
|
+
readonly deleteRoomRecord: (roomId: string) => Promise<void>;
|
|
5
|
+
readonly deleteReceive: (merkleRootHex: string) => Promise<void>;
|
|
6
|
+
readonly deleteOutgoing: (merkleRootHex: string) => Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Await every durable room-data deletion and report only after all reachable
|
|
10
|
+
* records were attempted. `removeLocalMessage` is reducer-only; no background
|
|
11
|
+
* listener owns storage completion after this function returns.
|
|
12
|
+
*/
|
|
13
|
+
export declare const deleteRoomDataTerminal: (roomId: string, removeLocalMessage: (merkleRootHex: string) => void, dependencies?: DeleteRoomDataDependencies) => Promise<void>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { BaseQueryFn } from "@reduxjs/toolkit/query";
|
|
2
|
-
import type { IRTCDataChannel, IRTCPeerConnection, RTCDisconnectFromAllRoomsParams } from "./interfaces";
|
|
2
|
+
import type { IRTCDataChannel, IRTCPeerConnection, RTCDisconnectFromAllRoomsParams, DisconnectPeerTransport } from "./interfaces";
|
|
3
3
|
export interface RTCDisconnectFromAllRoomsParamsExtension extends RTCDisconnectFromAllRoomsParams {
|
|
4
4
|
peerConnections: IRTCPeerConnection[];
|
|
5
5
|
dataChannels: IRTCDataChannel[];
|
|
6
|
+
disconnectPeer: DisconnectPeerTransport;
|
|
6
7
|
}
|
|
7
8
|
declare const webrtcDisconnectAllRoomsQuery: BaseQueryFn<RTCDisconnectFromAllRoomsParamsExtension, undefined>;
|
|
8
9
|
export default webrtcDisconnectAllRoomsQuery;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { BaseQueryFn } from "@reduxjs/toolkit/query";
|
|
2
|
-
import type { IRTCDataChannel, IRTCPeerConnection, RTCDisconnectFromRoomParams } from "./interfaces";
|
|
2
|
+
import type { IRTCDataChannel, IRTCPeerConnection, RTCDisconnectFromRoomParams, DisconnectPeerTransport } from "./interfaces";
|
|
3
3
|
export interface RTCDisconnectFromRoomParamsExtension extends RTCDisconnectFromRoomParams {
|
|
4
4
|
peerConnections: IRTCPeerConnection[];
|
|
5
5
|
dataChannels: IRTCDataChannel[];
|
|
6
|
+
disconnectPeer: DisconnectPeerTransport;
|
|
6
7
|
}
|
|
7
8
|
declare const webrtcDisconnectRoomQuery: BaseQueryFn<RTCDisconnectFromRoomParamsExtension, undefined>;
|
|
8
9
|
export default webrtcDisconnectRoomQuery;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { BaseQueryFn } from "@reduxjs/toolkit/query";
|
|
2
|
-
import type { IRTCDataChannel, IRTCPeerConnection, RTCDisconnectParams } from "./interfaces";
|
|
2
|
+
import type { IRTCDataChannel, IRTCPeerConnection, RTCDisconnectParams, DisconnectPeerTransport } from "./interfaces";
|
|
3
3
|
export interface RTCDisconnectParamsExtension extends RTCDisconnectParams {
|
|
4
4
|
peerConnections: IRTCPeerConnection[];
|
|
5
5
|
dataChannels: IRTCDataChannel[];
|
|
6
|
+
disconnectPeer: DisconnectPeerTransport;
|
|
6
7
|
}
|
|
7
8
|
declare const webrtcDisconnectQuery: BaseQueryFn<RTCDisconnectParamsExtension, undefined>;
|
|
8
9
|
export default webrtcDisconnectQuery;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
type IceRestartTarget = Pick<RTCPeerConnection, "connectionState" | "signalingState" | "restartIce"
|
|
1
|
+
type IceRestartTarget = Pick<RTCPeerConnection, "connectionState" | "signalingState" | "restartIce"> & {
|
|
2
|
+
ensureFreshIceConfiguration?: () => Promise<boolean | void>;
|
|
3
|
+
};
|
|
2
4
|
export type IceCandidateRepairResult = "restarted" | "disconnected";
|
|
3
5
|
/**
|
|
4
6
|
* Repair a candidate-add failure without ever calling restartIce() after
|