livekit-client 1.13.0 → 1.13.2
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/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +122 -105
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +172 -109
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts +4 -3
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/KeyProvider.d.ts +7 -6
- package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
- package/dist/src/e2ee/events.d.ts +34 -0
- package/dist/src/e2ee/events.d.ts.map +1 -0
- package/dist/src/e2ee/index.d.ts +1 -0
- package/dist/src/e2ee/index.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +17 -33
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +15 -12
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts +6 -8
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +1 -0
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/processor/types.d.ts +2 -1
- package/dist/src/room/track/processor/types.d.ts.map +1 -1
- package/dist/ts4.2/src/e2ee/E2eeManager.d.ts +4 -3
- package/dist/ts4.2/src/e2ee/KeyProvider.d.ts +7 -6
- package/dist/ts4.2/src/e2ee/events.d.ts +34 -0
- package/dist/ts4.2/src/e2ee/index.d.ts +1 -0
- package/dist/ts4.2/src/e2ee/types.d.ts +17 -33
- package/dist/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +15 -12
- package/dist/ts4.2/src/e2ee/worker/ParticipantKeyHandler.d.ts +6 -8
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +1 -0
- package/dist/ts4.2/src/room/track/processor/types.d.ts +2 -1
- package/package.json +1 -1
- package/src/e2ee/E2eeManager.ts +105 -77
- package/src/e2ee/KeyProvider.ts +23 -13
- package/src/e2ee/events.ts +48 -0
- package/src/e2ee/index.ts +1 -0
- package/src/e2ee/types.ts +19 -41
- package/src/e2ee/worker/FrameCryptor.ts +51 -43
- package/src/e2ee/worker/ParticipantKeyHandler.ts +25 -27
- package/src/e2ee/worker/e2ee.worker.ts +61 -68
- package/src/room/PCTransport.ts +12 -2
- package/src/room/RTCEngine.ts +0 -1
- package/src/room/Room.ts +20 -15
- package/src/room/participant/LocalParticipant.ts +5 -1
- package/src/room/track/LocalTrack.ts +18 -10
- package/src/room/track/facingMode.ts +1 -1
- package/src/room/track/processor/types.ts +2 -1
package/src/e2ee/E2eeManager.ts
CHANGED
@@ -13,8 +13,8 @@ import type { Track } from '../room/track/Track';
|
|
13
13
|
import type { VideoCodec } from '../room/track/options';
|
14
14
|
import type { BaseKeyProvider } from './KeyProvider';
|
15
15
|
import { E2EE_FLAG } from './constants';
|
16
|
+
import { type E2EEManagerCallbacks, EncryptionEvent, KeyProviderEvent } from './events';
|
16
17
|
import type {
|
17
|
-
E2EEManagerCallbacks,
|
18
18
|
E2EEOptions,
|
19
19
|
E2EEWorkerMessage,
|
20
20
|
EnableMessage,
|
@@ -28,7 +28,6 @@ import type {
|
|
28
28
|
SifTrailerMessage,
|
29
29
|
UpdateCodecMessage,
|
30
30
|
} from './types';
|
31
|
-
import { EncryptionEvent } from './types';
|
32
31
|
import { isE2EESupported, isScriptTransformSupported, mimeTypeToVideoCodecString } from './utils';
|
33
32
|
|
34
33
|
/**
|
@@ -43,10 +42,6 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
43
42
|
|
44
43
|
private keyProvider: BaseKeyProvider;
|
45
44
|
|
46
|
-
get isEnabled() {
|
47
|
-
return this.encryptionEnabled;
|
48
|
-
}
|
49
|
-
|
50
45
|
constructor(options: E2EEOptions) {
|
51
46
|
super();
|
52
47
|
this.keyProvider = options.keyProvider;
|
@@ -86,18 +81,9 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
86
81
|
/**
|
87
82
|
* @internal
|
88
83
|
*/
|
89
|
-
|
90
|
-
log.
|
91
|
-
|
92
|
-
if (this.worker) {
|
93
|
-
const enableMsg: EnableMessage = {
|
94
|
-
kind: 'enable',
|
95
|
-
data: { enabled, participantId },
|
96
|
-
};
|
97
|
-
this.worker.postMessage(enableMsg);
|
98
|
-
} else {
|
99
|
-
throw new ReferenceError('failed to enable e2ee, worker is not ready');
|
100
|
-
}
|
84
|
+
setParticipantCryptorEnabled(enabled: boolean, participantIdentity: string) {
|
85
|
+
log.debug(`set e2ee to ${enabled} for participant ${participantIdentity}`);
|
86
|
+
this.postEnable(enabled, participantIdentity);
|
101
87
|
}
|
102
88
|
|
103
89
|
/**
|
@@ -115,19 +101,35 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
115
101
|
const { kind, data } = ev.data;
|
116
102
|
switch (kind) {
|
117
103
|
case 'error':
|
118
|
-
|
119
|
-
this.emit(EncryptionEvent.
|
104
|
+
log.error(data.error.message);
|
105
|
+
this.emit(EncryptionEvent.EncryptionError, data.error);
|
106
|
+
break;
|
107
|
+
case 'initAck':
|
108
|
+
if (data.enabled) {
|
109
|
+
this.keyProvider.getKeys().forEach((keyInfo) => {
|
110
|
+
this.postKey(keyInfo);
|
111
|
+
});
|
112
|
+
}
|
120
113
|
break;
|
114
|
+
|
121
115
|
case 'enable':
|
122
|
-
if (
|
116
|
+
if (
|
117
|
+
this.encryptionEnabled !== data.enabled &&
|
118
|
+
data.participantIdentity === this.room?.localParticipant.identity
|
119
|
+
) {
|
123
120
|
this.emit(
|
124
121
|
EncryptionEvent.ParticipantEncryptionStatusChanged,
|
125
122
|
data.enabled,
|
126
|
-
this.room
|
123
|
+
this.room!.localParticipant,
|
127
124
|
);
|
128
125
|
this.encryptionEnabled = data.enabled;
|
129
|
-
} else if (data.
|
130
|
-
const participant = this.room?.getParticipantByIdentity(data.
|
126
|
+
} else if (data.participantIdentity) {
|
127
|
+
const participant = this.room?.getParticipantByIdentity(data.participantIdentity);
|
128
|
+
if (!participant) {
|
129
|
+
throw TypeError(
|
130
|
+
`couldn't set encryption status, participant not found${data.participantIdentity}`,
|
131
|
+
);
|
132
|
+
}
|
131
133
|
this.emit(EncryptionEvent.ParticipantEncryptionStatusChanged, data.enabled, participant);
|
132
134
|
}
|
133
135
|
if (this.encryptionEnabled) {
|
@@ -137,7 +139,7 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
137
139
|
}
|
138
140
|
break;
|
139
141
|
case 'ratchetKey':
|
140
|
-
this.keyProvider.emit(
|
142
|
+
this.keyProvider.emit(KeyProviderEvent.KeyRatcheted, data.material, data.keyIndex);
|
141
143
|
break;
|
142
144
|
default:
|
143
145
|
break;
|
@@ -146,7 +148,7 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
146
148
|
|
147
149
|
private onWorkerError = (ev: ErrorEvent) => {
|
148
150
|
log.error('e2ee worker encountered an error:', { error: ev.error });
|
149
|
-
this.emit(EncryptionEvent.
|
151
|
+
this.emit(EncryptionEvent.EncryptionError, ev.error);
|
150
152
|
};
|
151
153
|
|
152
154
|
public setupEngine(engine: RTCEngine) {
|
@@ -162,69 +164,78 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
162
164
|
participant.identity,
|
163
165
|
),
|
164
166
|
);
|
165
|
-
room
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
167
|
+
room
|
168
|
+
.on(RoomEvent.ConnectionStateChanged, (state) => {
|
169
|
+
if (state === ConnectionState.Connected) {
|
170
|
+
room.participants.forEach((participant) => {
|
171
|
+
participant.tracks.forEach((pub) => {
|
172
|
+
this.setParticipantCryptorEnabled(
|
173
|
+
pub.trackInfo!.encryption !== Encryption_Type.NONE,
|
174
|
+
participant.identity,
|
175
|
+
);
|
176
|
+
});
|
173
177
|
});
|
178
|
+
}
|
179
|
+
})
|
180
|
+
.on(RoomEvent.TrackUnsubscribed, (track, _, participant) => {
|
181
|
+
const msg: RemoveTransformMessage = {
|
182
|
+
kind: 'removeTransform',
|
183
|
+
data: {
|
184
|
+
participantIdentity: participant.identity,
|
185
|
+
trackId: track.mediaStreamID,
|
186
|
+
},
|
187
|
+
};
|
188
|
+
this.worker?.postMessage(msg);
|
189
|
+
})
|
190
|
+
.on(RoomEvent.TrackSubscribed, (track, pub, participant) => {
|
191
|
+
this.setupE2EEReceiver(track, participant.identity, pub.trackInfo);
|
192
|
+
})
|
193
|
+
.on(RoomEvent.SignalConnected, () => {
|
194
|
+
if (!this.room) {
|
195
|
+
throw new TypeError(`expected room to be present on signal connect`);
|
196
|
+
}
|
197
|
+
this.setParticipantCryptorEnabled(
|
198
|
+
this.room.localParticipant.isE2EEEnabled,
|
199
|
+
this.room.localParticipant.identity,
|
200
|
+
);
|
201
|
+
keyProvider.getKeys().forEach((keyInfo) => {
|
202
|
+
this.postKey(keyInfo);
|
174
203
|
});
|
175
|
-
}
|
176
|
-
});
|
177
|
-
|
178
|
-
room.on(RoomEvent.TrackUnsubscribed, (track, _, participant) => {
|
179
|
-
const msg: RemoveTransformMessage = {
|
180
|
-
kind: 'removeTransform',
|
181
|
-
data: {
|
182
|
-
participantId: participant.identity,
|
183
|
-
trackId: track.mediaStreamID,
|
184
|
-
},
|
185
|
-
};
|
186
|
-
this.worker?.postMessage(msg);
|
187
|
-
});
|
188
|
-
room.on(RoomEvent.TrackSubscribed, (track, pub, participant) => {
|
189
|
-
this.setupE2EEReceiver(track, participant.identity, pub.trackInfo);
|
190
|
-
});
|
204
|
+
});
|
191
205
|
room.localParticipant.on(ParticipantEvent.LocalTrackPublished, async (publication) => {
|
192
|
-
this.setupE2EESender(
|
193
|
-
publication.track!,
|
194
|
-
publication.track!.sender!,
|
195
|
-
room.localParticipant.identity,
|
196
|
-
);
|
206
|
+
this.setupE2EESender(publication.track!, publication.track!.sender!);
|
197
207
|
});
|
198
208
|
|
199
209
|
keyProvider
|
200
|
-
.on(
|
201
|
-
.on(
|
210
|
+
.on(KeyProviderEvent.SetKey, (keyInfo) => this.postKey(keyInfo))
|
211
|
+
.on(KeyProviderEvent.RatchetRequest, (participantId, keyIndex) =>
|
202
212
|
this.postRatchetRequest(participantId, keyIndex),
|
203
213
|
);
|
204
214
|
}
|
205
215
|
|
206
|
-
private postRatchetRequest(
|
216
|
+
private postRatchetRequest(participantIdentity?: string, keyIndex?: number) {
|
207
217
|
if (!this.worker) {
|
208
218
|
throw Error('could not ratchet key, worker is missing');
|
209
219
|
}
|
210
220
|
const msg: RatchetRequestMessage = {
|
211
221
|
kind: 'ratchetRequest',
|
212
222
|
data: {
|
213
|
-
|
223
|
+
participantIdentity: participantIdentity,
|
214
224
|
keyIndex,
|
215
225
|
},
|
216
226
|
};
|
217
227
|
this.worker.postMessage(msg);
|
218
228
|
}
|
219
229
|
|
220
|
-
private postKey({ key,
|
230
|
+
private postKey({ key, participantIdentity, keyIndex }: KeyInfo) {
|
221
231
|
if (!this.worker) {
|
222
232
|
throw Error('could not set key, worker is missing');
|
223
233
|
}
|
224
234
|
const msg: SetKeyMessage = {
|
225
235
|
kind: 'setKey',
|
226
236
|
data: {
|
227
|
-
|
237
|
+
participantIdentity: participantIdentity,
|
238
|
+
isPublisher: participantIdentity === this.room?.localParticipant.identity,
|
228
239
|
key,
|
229
240
|
keyIndex,
|
230
241
|
},
|
@@ -232,14 +243,33 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
232
243
|
this.worker.postMessage(msg);
|
233
244
|
}
|
234
245
|
|
246
|
+
private postEnable(enabled: boolean, participantIdentity: string) {
|
247
|
+
if (this.worker) {
|
248
|
+
const enableMsg: EnableMessage = {
|
249
|
+
kind: 'enable',
|
250
|
+
data: {
|
251
|
+
enabled,
|
252
|
+
participantIdentity,
|
253
|
+
},
|
254
|
+
};
|
255
|
+
this.worker.postMessage(enableMsg);
|
256
|
+
} else {
|
257
|
+
throw new ReferenceError('failed to enable e2ee, worker is not ready');
|
258
|
+
}
|
259
|
+
}
|
260
|
+
|
235
261
|
private postRTPMap(map: Map<number, VideoCodec>) {
|
236
262
|
if (!this.worker) {
|
237
|
-
throw
|
263
|
+
throw TypeError('could not post rtp map, worker is missing');
|
264
|
+
}
|
265
|
+
if (!this.room?.localParticipant.identity) {
|
266
|
+
throw TypeError('could not post rtp map, local participant identity is missing');
|
238
267
|
}
|
239
268
|
const msg: RTPVideoMapMessage = {
|
240
269
|
kind: 'setRTPMap',
|
241
270
|
data: {
|
242
271
|
map,
|
272
|
+
participantIdentity: this.room.localParticipant.identity,
|
243
273
|
},
|
244
274
|
};
|
245
275
|
this.worker.postMessage(msg);
|
@@ -273,12 +303,12 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
273
303
|
);
|
274
304
|
}
|
275
305
|
|
276
|
-
private setupE2EESender(track: Track, sender: RTCRtpSender
|
306
|
+
private setupE2EESender(track: Track, sender: RTCRtpSender) {
|
277
307
|
if (!(track instanceof LocalTrack) || !sender) {
|
278
308
|
if (!sender) log.warn('early return because sender is not ready');
|
279
309
|
return;
|
280
310
|
}
|
281
|
-
this.handleSender(sender, track.mediaStreamID,
|
311
|
+
this.handleSender(sender, track.mediaStreamID, undefined);
|
282
312
|
}
|
283
313
|
|
284
314
|
/**
|
@@ -289,7 +319,7 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
289
319
|
private async handleReceiver(
|
290
320
|
receiver: RTCRtpReceiver,
|
291
321
|
trackId: string,
|
292
|
-
|
322
|
+
participantIdentity: string,
|
293
323
|
codec?: VideoCodec,
|
294
324
|
) {
|
295
325
|
if (!this.worker) {
|
@@ -299,7 +329,7 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
299
329
|
if (isScriptTransformSupported()) {
|
300
330
|
const options = {
|
301
331
|
kind: 'decode',
|
302
|
-
|
332
|
+
participantIdentity,
|
303
333
|
trackId,
|
304
334
|
codec,
|
305
335
|
};
|
@@ -313,7 +343,7 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
313
343
|
data: {
|
314
344
|
trackId,
|
315
345
|
codec,
|
316
|
-
|
346
|
+
participantIdentity: participantIdentity,
|
317
347
|
},
|
318
348
|
};
|
319
349
|
this.worker.postMessage(msg);
|
@@ -341,7 +371,7 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
341
371
|
writableStream: writable,
|
342
372
|
trackId: trackId,
|
343
373
|
codec,
|
344
|
-
|
374
|
+
participantIdentity: participantIdentity,
|
345
375
|
},
|
346
376
|
};
|
347
377
|
this.worker.postMessage(msg, [readable, writable]);
|
@@ -356,22 +386,20 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
356
386
|
* a frame encoder.
|
357
387
|
*
|
358
388
|
*/
|
359
|
-
private handleSender(
|
360
|
-
sender: RTCRtpSender,
|
361
|
-
trackId: string,
|
362
|
-
participantId: string,
|
363
|
-
codec?: VideoCodec,
|
364
|
-
) {
|
389
|
+
private handleSender(sender: RTCRtpSender, trackId: string, codec?: VideoCodec) {
|
365
390
|
if (E2EE_FLAG in sender || !this.worker) {
|
366
391
|
return;
|
367
392
|
}
|
368
393
|
|
394
|
+
if (!this.room?.localParticipant.identity || this.room.localParticipant.identity === '') {
|
395
|
+
throw TypeError('local identity needs to be known in order to set up encrypted sender');
|
396
|
+
}
|
397
|
+
|
369
398
|
if (isScriptTransformSupported()) {
|
370
399
|
log.info('initialize script transform');
|
371
|
-
|
372
400
|
const options = {
|
373
401
|
kind: 'encode',
|
374
|
-
|
402
|
+
participantIdentity: this.room.localParticipant.identity,
|
375
403
|
trackId,
|
376
404
|
codec,
|
377
405
|
};
|
@@ -388,7 +416,7 @@ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2
|
|
388
416
|
writableStream: senderStreams.writable,
|
389
417
|
codec,
|
390
418
|
trackId,
|
391
|
-
|
419
|
+
participantIdentity: this.room.localParticipant.identity,
|
392
420
|
},
|
393
421
|
};
|
394
422
|
this.worker.postMessage(msg, [senderStreams.readable, senderStreams.writable]);
|
package/src/e2ee/KeyProvider.ts
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
import { EventEmitter } from 'events';
|
2
2
|
import type TypedEventEmitter from 'typed-emitter';
|
3
|
+
import log from '../logger';
|
3
4
|
import { KEY_PROVIDER_DEFAULTS } from './constants';
|
4
|
-
import
|
5
|
+
import { type KeyProviderCallbacks, KeyProviderEvent } from './events';
|
6
|
+
import type { KeyInfo, KeyProviderOptions } from './types';
|
5
7
|
import { createKeyMaterialFromBuffer, createKeyMaterialFromString } from './utils';
|
6
8
|
|
7
9
|
/**
|
@@ -16,29 +18,29 @@ export class BaseKeyProvider extends (EventEmitter as new () => TypedEventEmitte
|
|
16
18
|
super();
|
17
19
|
this.keyInfoMap = new Map();
|
18
20
|
this.options = { ...KEY_PROVIDER_DEFAULTS, ...options };
|
19
|
-
this.on(
|
21
|
+
this.on(KeyProviderEvent.KeyRatcheted, this.onKeyRatcheted);
|
20
22
|
}
|
21
23
|
|
22
24
|
/**
|
23
25
|
* callback to invoke once a key has been set for a participant
|
24
26
|
* @param key
|
25
|
-
* @param
|
27
|
+
* @param participantIdentity
|
26
28
|
* @param keyIndex
|
27
29
|
*/
|
28
|
-
protected onSetEncryptionKey(key: CryptoKey,
|
29
|
-
const keyInfo: KeyInfo = { key,
|
30
|
-
this.keyInfoMap.set(`${
|
31
|
-
this.emit(
|
30
|
+
protected onSetEncryptionKey(key: CryptoKey, participantIdentity?: string, keyIndex?: number) {
|
31
|
+
const keyInfo: KeyInfo = { key, participantIdentity, keyIndex };
|
32
|
+
this.keyInfoMap.set(`${participantIdentity ?? 'shared'}-${keyIndex ?? 0}`, keyInfo);
|
33
|
+
this.emit(KeyProviderEvent.SetKey, keyInfo);
|
32
34
|
}
|
33
35
|
|
34
36
|
/**
|
35
|
-
* callback being invoked after a ratchet request has been performed on
|
37
|
+
* callback being invoked after a ratchet request has been performed on a participant
|
36
38
|
* that surfaces the new key material.
|
37
39
|
* @param material
|
38
40
|
* @param keyIndex
|
39
41
|
*/
|
40
42
|
protected onKeyRatcheted = (material: CryptoKey, keyIndex?: number) => {
|
41
|
-
|
43
|
+
log.debug('key ratcheted event received', { material, keyIndex });
|
42
44
|
};
|
43
45
|
|
44
46
|
getKeys() {
|
@@ -49,8 +51,8 @@ export class BaseKeyProvider extends (EventEmitter as new () => TypedEventEmitte
|
|
49
51
|
return this.options;
|
50
52
|
}
|
51
53
|
|
52
|
-
ratchetKey(
|
53
|
-
this.emit(
|
54
|
+
ratchetKey(participantIdentity?: string, keyIndex?: number) {
|
55
|
+
this.emit(KeyProviderEvent.RatchetRequest, participantIdentity, keyIndex);
|
54
56
|
}
|
55
57
|
}
|
56
58
|
|
@@ -63,14 +65,22 @@ export class ExternalE2EEKeyProvider extends BaseKeyProvider {
|
|
63
65
|
ratchetInterval: number | undefined;
|
64
66
|
|
65
67
|
constructor(options: Partial<Omit<KeyProviderOptions, 'sharedKey'>> = {}) {
|
66
|
-
const opts: Partial<KeyProviderOptions> = {
|
68
|
+
const opts: Partial<KeyProviderOptions> = {
|
69
|
+
...options,
|
70
|
+
sharedKey: true,
|
71
|
+
// for a shared key provider failing to decrypt for a specific participant
|
72
|
+
// should not mark the key as invalid, so we accept wrong keys forever
|
73
|
+
// and won't try to auto-ratchet
|
74
|
+
ratchetWindowSize: 0,
|
75
|
+
failureTolerance: -1,
|
76
|
+
};
|
67
77
|
super(opts);
|
68
78
|
}
|
69
79
|
|
70
80
|
/**
|
71
81
|
* Accepts a passphrase that's used to create the crypto keys.
|
72
82
|
* When passing in a string, PBKDF2 is used.
|
73
|
-
*
|
83
|
+
* When passing in an Array buffer of cryptographically random numbers, HKDF is being used. (recommended)
|
74
84
|
* @param key
|
75
85
|
*/
|
76
86
|
async setKey(key: string | ArrayBuffer) {
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import type Participant from '../room/participant/Participant';
|
2
|
+
import type { CryptorError } from './errors';
|
3
|
+
import type { KeyInfo } from './types';
|
4
|
+
|
5
|
+
export enum KeyProviderEvent {
|
6
|
+
SetKey = 'setKey',
|
7
|
+
RatchetRequest = 'ratchetRequest',
|
8
|
+
KeyRatcheted = 'keyRatcheted',
|
9
|
+
}
|
10
|
+
|
11
|
+
export type KeyProviderCallbacks = {
|
12
|
+
[KeyProviderEvent.SetKey]: (keyInfo: KeyInfo) => void;
|
13
|
+
[KeyProviderEvent.RatchetRequest]: (participantIdentity?: string, keyIndex?: number) => void;
|
14
|
+
[KeyProviderEvent.KeyRatcheted]: (material: CryptoKey, keyIndex?: number) => void;
|
15
|
+
};
|
16
|
+
|
17
|
+
export enum KeyHandlerEvent {
|
18
|
+
KeyRatcheted = 'keyRatcheted',
|
19
|
+
}
|
20
|
+
|
21
|
+
export type ParticipantKeyHandlerCallbacks = {
|
22
|
+
[KeyHandlerEvent.KeyRatcheted]: (
|
23
|
+
material: CryptoKey,
|
24
|
+
participantIdentity: string,
|
25
|
+
keyIndex?: number,
|
26
|
+
) => void;
|
27
|
+
};
|
28
|
+
|
29
|
+
export enum EncryptionEvent {
|
30
|
+
ParticipantEncryptionStatusChanged = 'participantEncryptionStatusChanged',
|
31
|
+
EncryptionError = 'encryptionError',
|
32
|
+
}
|
33
|
+
|
34
|
+
export type E2EEManagerCallbacks = {
|
35
|
+
[EncryptionEvent.ParticipantEncryptionStatusChanged]: (
|
36
|
+
enabled: boolean,
|
37
|
+
participant: Participant,
|
38
|
+
) => void;
|
39
|
+
[EncryptionEvent.EncryptionError]: (error: Error) => void;
|
40
|
+
};
|
41
|
+
|
42
|
+
export type CryptorCallbacks = {
|
43
|
+
[CryptorEvent.Error]: (error: CryptorError) => void;
|
44
|
+
};
|
45
|
+
|
46
|
+
export enum CryptorEvent {
|
47
|
+
Error = 'cryptorError',
|
48
|
+
}
|
package/src/e2ee/index.ts
CHANGED
package/src/e2ee/types.ts
CHANGED
@@ -1,7 +1,5 @@
|
|
1
|
-
import type Participant from '../room/participant/Participant';
|
2
1
|
import type { VideoCodec } from '../room/track/options';
|
3
2
|
import type { BaseKeyProvider } from './KeyProvider';
|
4
|
-
import type { CryptorError } from './errors';
|
5
3
|
|
6
4
|
export interface BaseMessage {
|
7
5
|
kind: string;
|
@@ -18,7 +16,8 @@ export interface InitMessage extends BaseMessage {
|
|
18
16
|
export interface SetKeyMessage extends BaseMessage {
|
19
17
|
kind: 'setKey';
|
20
18
|
data: {
|
21
|
-
|
19
|
+
participantIdentity?: string;
|
20
|
+
isPublisher: boolean;
|
22
21
|
key: CryptoKey;
|
23
22
|
keyIndex?: number;
|
24
23
|
};
|
@@ -28,6 +27,7 @@ export interface RTPVideoMapMessage extends BaseMessage {
|
|
28
27
|
kind: 'setRTPMap';
|
29
28
|
data: {
|
30
29
|
map: Map<number, VideoCodec>;
|
30
|
+
participantIdentity: string;
|
31
31
|
};
|
32
32
|
}
|
33
33
|
|
@@ -41,7 +41,7 @@ export interface SifTrailerMessage extends BaseMessage {
|
|
41
41
|
export interface EncodeMessage extends BaseMessage {
|
42
42
|
kind: 'decode' | 'encode';
|
43
43
|
data: {
|
44
|
-
|
44
|
+
participantIdentity: string;
|
45
45
|
readableStream: ReadableStream;
|
46
46
|
writableStream: WritableStream;
|
47
47
|
trackId: string;
|
@@ -52,7 +52,7 @@ export interface EncodeMessage extends BaseMessage {
|
|
52
52
|
export interface RemoveTransformMessage extends BaseMessage {
|
53
53
|
kind: 'removeTransform';
|
54
54
|
data: {
|
55
|
-
|
55
|
+
participantIdentity: string;
|
56
56
|
trackId: string;
|
57
57
|
};
|
58
58
|
}
|
@@ -60,7 +60,7 @@ export interface RemoveTransformMessage extends BaseMessage {
|
|
60
60
|
export interface UpdateCodecMessage extends BaseMessage {
|
61
61
|
kind: 'updateCodec';
|
62
62
|
data: {
|
63
|
-
|
63
|
+
participantIdentity: string;
|
64
64
|
trackId: string;
|
65
65
|
codec: VideoCodec;
|
66
66
|
};
|
@@ -69,7 +69,7 @@ export interface UpdateCodecMessage extends BaseMessage {
|
|
69
69
|
export interface RatchetRequestMessage extends BaseMessage {
|
70
70
|
kind: 'ratchetRequest';
|
71
71
|
data: {
|
72
|
-
|
72
|
+
participantIdentity?: string;
|
73
73
|
keyIndex?: number;
|
74
74
|
};
|
75
75
|
}
|
@@ -77,7 +77,7 @@ export interface RatchetRequestMessage extends BaseMessage {
|
|
77
77
|
export interface RatchetMessage extends BaseMessage {
|
78
78
|
kind: 'ratchetKey';
|
79
79
|
data: {
|
80
|
-
|
80
|
+
participantIdentity: string;
|
81
81
|
keyIndex?: number;
|
82
82
|
material: CryptoKey;
|
83
83
|
};
|
@@ -93,8 +93,14 @@ export interface ErrorMessage extends BaseMessage {
|
|
93
93
|
export interface EnableMessage extends BaseMessage {
|
94
94
|
kind: 'enable';
|
95
95
|
data: {
|
96
|
-
|
97
|
-
|
96
|
+
participantIdentity: string;
|
97
|
+
enabled: boolean;
|
98
|
+
};
|
99
|
+
}
|
100
|
+
|
101
|
+
export interface InitAck extends BaseMessage {
|
102
|
+
kind: 'initAck';
|
103
|
+
data: {
|
98
104
|
enabled: boolean;
|
99
105
|
};
|
100
106
|
}
|
@@ -110,7 +116,8 @@ export type E2EEWorkerMessage =
|
|
110
116
|
| UpdateCodecMessage
|
111
117
|
| RatchetRequestMessage
|
112
118
|
| RatchetMessage
|
113
|
-
| SifTrailerMessage
|
119
|
+
| SifTrailerMessage
|
120
|
+
| InitAck;
|
114
121
|
|
115
122
|
export type KeySet = { material: CryptoKey; encryptionKey: CryptoKey };
|
116
123
|
|
@@ -121,38 +128,9 @@ export type KeyProviderOptions = {
|
|
121
128
|
failureTolerance: number;
|
122
129
|
};
|
123
130
|
|
124
|
-
export type KeyProviderCallbacks = {
|
125
|
-
setKey: (keyInfo: KeyInfo) => void;
|
126
|
-
ratchetRequest: (participantId?: string, keyIndex?: number) => void;
|
127
|
-
/** currently only emitted for local participant */
|
128
|
-
keyRatcheted: (material: CryptoKey, keyIndex?: number) => void;
|
129
|
-
};
|
130
|
-
|
131
|
-
export type ParticipantKeyHandlerCallbacks = {
|
132
|
-
keyRatcheted: (material: CryptoKey, keyIndex?: number, participantId?: string) => void;
|
133
|
-
};
|
134
|
-
|
135
|
-
export type E2EEManagerCallbacks = {
|
136
|
-
participantEncryptionStatusChanged: (enabled: boolean, participant?: Participant) => void;
|
137
|
-
encryptionError: (error: Error) => void;
|
138
|
-
};
|
139
|
-
|
140
|
-
export const EncryptionEvent = {
|
141
|
-
ParticipantEncryptionStatusChanged: 'participantEncryptionStatusChanged',
|
142
|
-
Error: 'encryptionError',
|
143
|
-
} as const;
|
144
|
-
|
145
|
-
export type CryptorCallbacks = {
|
146
|
-
cryptorError: (error: CryptorError) => void;
|
147
|
-
};
|
148
|
-
|
149
|
-
export const CryptorEvent = {
|
150
|
-
Error: 'cryptorError',
|
151
|
-
} as const;
|
152
|
-
|
153
131
|
export type KeyInfo = {
|
154
132
|
key: CryptoKey;
|
155
|
-
|
133
|
+
participantIdentity?: string;
|
156
134
|
keyIndex?: number;
|
157
135
|
};
|
158
136
|
|