@abraca/dabra 1.1.2 → 1.3.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/dist/abracadabra-provider.cjs +313 -143
- package/dist/abracadabra-provider.cjs.map +1 -1
- package/dist/abracadabra-provider.esm.js +313 -143
- package/dist/abracadabra-provider.esm.js.map +1 -1
- package/dist/index.d.ts +81 -43
- package/package.json +1 -1
- package/src/BackgroundSyncManager.ts +2 -2
- package/src/CryptoIdentityKeystore.ts +335 -203
- package/src/IdentityDoc.ts +2 -2
- package/src/webrtc/AbracadabraWebRTC.ts +61 -29
- package/src/webrtc/types.ts +1 -1
package/src/IdentityDoc.ts
CHANGED
|
@@ -132,8 +132,8 @@ export interface IdentityDocConfiguration {
|
|
|
132
132
|
signalingServerUrl: string;
|
|
133
133
|
/** Token for the signaling server. */
|
|
134
134
|
token: string | (() => string) | (() => Promise<string>);
|
|
135
|
-
/** E2EE identity for the data channel. */
|
|
136
|
-
e2ee?: E2EEIdentity;
|
|
135
|
+
/** E2EE identity for the data channel. Accepts a factory for lazy derivation. */
|
|
136
|
+
e2ee?: E2EEIdentity | (() => Promise<E2EEIdentity>);
|
|
137
137
|
/** ICE servers. */
|
|
138
138
|
iceServers?: RTCIceServer[];
|
|
139
139
|
};
|
|
@@ -49,10 +49,14 @@ export class AbracadabraWebRTC extends EventEmitter {
|
|
|
49
49
|
enableAwarenessSync: boolean;
|
|
50
50
|
enableFileTransfer: boolean;
|
|
51
51
|
fileChunkSize: number;
|
|
52
|
-
e2ee: E2EEIdentity | null;
|
|
52
|
+
e2ee: E2EEIdentity | (() => Promise<E2EEIdentity>) | null;
|
|
53
53
|
WebSocketPolyfill: any;
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
+
/** Cached resolved E2EE identity (lazily resolved from factory on first peer connect). */
|
|
57
|
+
private _resolvedE2ee: E2EEIdentity | null = null;
|
|
58
|
+
private _resolveE2eePromise: Promise<E2EEIdentity> | null = null;
|
|
59
|
+
|
|
56
60
|
public readonly peers = new Map<string, PeerState>();
|
|
57
61
|
public localPeerId: string | null = null;
|
|
58
62
|
public isConnected = false;
|
|
@@ -471,40 +475,68 @@ export class AbracadabraWebRTC extends EventEmitter {
|
|
|
471
475
|
return pc;
|
|
472
476
|
}
|
|
473
477
|
|
|
478
|
+
/** Resolve the E2EE identity, supporting both pre-resolved objects and lazy factories. */
|
|
479
|
+
private async resolveE2ee(): Promise<E2EEIdentity | null> {
|
|
480
|
+
if (this._resolvedE2ee) return this._resolvedE2ee;
|
|
481
|
+
if (!this.config.e2ee) return null;
|
|
482
|
+
if (typeof this.config.e2ee === "function") {
|
|
483
|
+
if (!this._resolveE2eePromise) {
|
|
484
|
+
this._resolveE2eePromise = this.config.e2ee().then((id) => {
|
|
485
|
+
this._resolvedE2ee = id;
|
|
486
|
+
return id;
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
return this._resolveE2eePromise;
|
|
490
|
+
}
|
|
491
|
+
this._resolvedE2ee = this.config.e2ee;
|
|
492
|
+
return this._resolvedE2ee;
|
|
493
|
+
}
|
|
494
|
+
|
|
474
495
|
private attachDataHandlers(peerId: string, pc: PeerConnection): void {
|
|
475
496
|
// Set up E2EE if configured.
|
|
476
497
|
if (this.config.e2ee) {
|
|
477
|
-
|
|
478
|
-
this.
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
pc.router.on("channelMessage", async ({ name, data }: { name: string; data: any }) => {
|
|
483
|
-
if (name === KEY_EXCHANGE_CHANNEL) {
|
|
484
|
-
try {
|
|
485
|
-
const buf = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
|
486
|
-
await e2ee.handleKeyExchange(buf);
|
|
487
|
-
} catch (err) {
|
|
488
|
-
this.emit("e2eeFailed", { peerId, error: err });
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
});
|
|
492
|
-
|
|
493
|
-
// When key-exchange channel opens, send our public key.
|
|
494
|
-
pc.router.on("channelOpen", ({ name, channel }: { name: string; channel: RTCDataChannel }) => {
|
|
495
|
-
if (name === KEY_EXCHANGE_CHANNEL) {
|
|
496
|
-
channel.send(e2ee.getKeyExchangeMessage());
|
|
498
|
+
// Resolve E2EE identity (may be lazy — e.g. passkey-derived X25519 key).
|
|
499
|
+
this.resolveE2ee().then((identity) => {
|
|
500
|
+
if (!identity) {
|
|
501
|
+
this.startDataSync(peerId, pc);
|
|
502
|
+
return;
|
|
497
503
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
//
|
|
503
|
-
|
|
504
|
-
|
|
504
|
+
const e2ee = new E2EEChannel(identity, this.config.docId);
|
|
505
|
+
this.e2eeChannels.set(peerId, e2ee);
|
|
506
|
+
pc.router.setEncryptor(e2ee);
|
|
507
|
+
|
|
508
|
+
// Listen for key-exchange messages on the router.
|
|
509
|
+
pc.router.on("channelMessage", async ({ name, data }: { name: string; data: any }) => {
|
|
510
|
+
if (name === KEY_EXCHANGE_CHANNEL) {
|
|
511
|
+
try {
|
|
512
|
+
const buf = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
|
513
|
+
await e2ee.handleKeyExchange(buf);
|
|
514
|
+
} catch (err) {
|
|
515
|
+
this.emit("e2eeFailed", { peerId, error: err });
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
});
|
|
505
519
|
|
|
506
|
-
|
|
520
|
+
// When key-exchange channel opens, send our public key.
|
|
521
|
+
pc.router.on("channelOpen", ({ name, channel }: { name: string; channel: RTCDataChannel }) => {
|
|
522
|
+
if (name === KEY_EXCHANGE_CHANNEL) {
|
|
523
|
+
channel.send(e2ee.getKeyExchangeMessage());
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
e2ee.on("established", () => {
|
|
528
|
+
this.emit("e2eeEstablished", { peerId });
|
|
529
|
+
// Now that E2EE is ready, start Y.js sync (deferred).
|
|
530
|
+
this.startDataSync(peerId, pc);
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
e2ee.on("error", (err: Error) => {
|
|
534
|
+
this.emit("e2eeFailed", { peerId, error: err });
|
|
535
|
+
});
|
|
536
|
+
}).catch((err) => {
|
|
507
537
|
this.emit("e2eeFailed", { peerId, error: err });
|
|
538
|
+
// Fall back to unencrypted sync on E2EE resolution failure.
|
|
539
|
+
this.startDataSync(peerId, pc);
|
|
508
540
|
});
|
|
509
541
|
} else {
|
|
510
542
|
// No E2EE — start data sync immediately.
|
package/src/webrtc/types.ts
CHANGED
|
@@ -158,7 +158,7 @@ export interface AbracadabraWebRTCConfiguration {
|
|
|
158
158
|
* When provided, all data channel messages (except key-exchange) are
|
|
159
159
|
* encrypted with AES-256-GCM using X25519 ECDH-derived session keys.
|
|
160
160
|
*/
|
|
161
|
-
e2ee?: import("./E2EEChannel.ts").E2EEIdentity;
|
|
161
|
+
e2ee?: import("./E2EEChannel.ts").E2EEIdentity | (() => Promise<import("./E2EEChannel.ts").E2EEIdentity>);
|
|
162
162
|
|
|
163
163
|
/** WebSocket polyfill for signaling (e.g. for Node.js). */
|
|
164
164
|
WebSocketPolyfill?: any;
|