livekit-client 2.5.8 → 2.5.9
Sign up to get free protection for your applications and to get access to all the features.
- 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 +49 -20
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +2 -2
- 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/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts +25 -5
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/ts4.2/src/e2ee/worker/ParticipantKeyHandler.d.ts +25 -5
- package/package.json +2 -2
- package/src/e2ee/worker/FrameCryptor.test.ts +311 -113
- package/src/e2ee/worker/FrameCryptor.ts +10 -5
- package/src/e2ee/worker/ParticipantKeyHandler.test.ts +169 -5
- package/src/e2ee/worker/ParticipantKeyHandler.ts +50 -20
- package/src/e2ee/worker/__snapshots__/ParticipantKeyHandler.test.ts.snap +356 -0
- package/src/room/participant/LocalParticipant.ts +4 -1
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"FrameCryptor.d.ts","sourceRoot":"","sources":["../../../../src/e2ee/worker/FrameCryptor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,iBAAiB,MAAM,eAAe,CAAC;AAEnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAG3D,OAAO,EAAE,KAAK,gBAAgB,EAAgB,MAAM,WAAW,CAAC;AAChE,OAAO,KAAK,EAAwB,kBAAkB,EAAU,MAAM,UAAU,CAAC;AAEjF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAGrE,eAAO,MAAM,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAa,CAAC;AAEpE,MAAM,WAAW,uBAAuB;IACtC,KAAK,IAAI,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;CACxC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,cAAc,CAAC;IACzB,WAAW,EAAE,eAAe,CAAC;IAC7B,eAAe,EAAE,eAAe,CAAC;CAClC;+CAEgE,iBAAiB,CAAC,gBAAgB,CAAC;AAApG,qBAAa,gBAAiB,SAAQ,qBAA+D;IACnG,SAAS,CAAC,cAAc,CACtB,YAAY,EAAE,oBAAoB,GAAG,oBAAoB,EACzD,UAAU,EAAE,gCAAgC,GAC3C,OAAO,CAAC,GAAG,CAAC;IAIf,SAAS,CAAC,cAAc,CACtB,YAAY,EAAE,oBAAoB,GAAG,oBAAoB,EACzD,UAAU,EAAE,gCAAgC,GAC3C,OAAO,CAAC,GAAG,CAAC;CAGhB;AAED;;;GAGG;AACH,qBAAa,YAAa,SAAQ,gBAAgB;IAChD,OAAO,CAAC,UAAU,CAAsB;IAExC,OAAO,CAAC,mBAAmB,CAAqB;IAEhD,OAAO,CAAC,OAAO,CAAqB;IAEpC,OAAO,CAAC,IAAI,CAAwB;IAEpC,OAAO,CAAC,UAAU,CAAC,CAAa;IAEhC,OAAO,CAAC,MAAM,CAA0B;IAExC,OAAO,CAAC,kBAAkB,CAAqB;IAE/C;;OAEG;IACH,OAAO,CAAC,UAAU,CAAa;IAE/B,OAAO,CAAC,QAAQ,CAAW;IAE3B,OAAO,CAAC,aAAa,CAAC,CAAa;gBAEvB,IAAI,EAAE;QAChB,IAAI,EAAE,qBAAqB,CAAC;QAC5B,mBAAmB,EAAE,MAAM,CAAC;QAC5B,kBAAkB,EAAE,kBAAkB,CAAC;QACvC,UAAU,CAAC,EAAE,UAAU,CAAC;KACzB;IAWD,OAAO,KAAK,UAAU,GAMrB;IAED;;;;;OAKG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB;IAkBtD,gBAAgB;IAKhB,SAAS;IAQT,sBAAsB;IAItB,UAAU;IAIV;;;OAGG;IACH,aAAa,CAAC,KAAK,EAAE,UAAU;IAI/B;;;OAGG;IACH,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC;IAItC,cAAc,CACZ,SAAS,EAAE,QAAQ,GAAG,QAAQ,EAC9B,QAAQ,EAAE,cAAc,CAAC,oBAAoB,GAAG,oBAAoB,CAAC,EACrE,QAAQ,EAAE,cAAc,CAAC,oBAAoB,GAAG,oBAAoB,CAAC,EACrE,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,UAAU;IAkCpB,aAAa,CAAC,OAAO,EAAE,UAAU;IAKjC;;;;;;;;;;;;;;;;;;;;;OAqBG;cACa,cAAc,CAC5B,YAAY,EAAE,oBAAoB,GAAG,oBAAoB,EACzD,UAAU,EAAE,gCAAgC;IA+F9C;;;;;OAKG;cACa,cAAc,CAC5B,YAAY,EAAE,oBAAoB,GAAG,oBAAoB,EACzD,UAAU,EAAE,gCAAgC;
|
1
|
+
{"version":3,"file":"FrameCryptor.d.ts","sourceRoot":"","sources":["../../../../src/e2ee/worker/FrameCryptor.ts"],"names":[],"mappings":"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"}
|
@@ -13,20 +13,40 @@ declare const ParticipantKeyHandler_base: new () => TypedEventEmitter<Participan
|
|
13
13
|
export declare class ParticipantKeyHandler extends ParticipantKeyHandler_base {
|
14
14
|
private currentKeyIndex;
|
15
15
|
private cryptoKeyRing;
|
16
|
+
private decryptionFailureCounts;
|
16
17
|
private keyProviderOptions;
|
17
18
|
private ratchetPromiseMap;
|
18
19
|
private participantIdentity;
|
19
|
-
|
20
|
-
|
20
|
+
/**
|
21
|
+
* true if the current key has not been marked as invalid
|
22
|
+
*/
|
21
23
|
get hasValidKey(): boolean;
|
22
24
|
constructor(participantIdentity: string, keyProviderOptions: KeyProviderOptions);
|
23
|
-
|
24
|
-
|
25
|
+
/**
|
26
|
+
* Returns true if the key at the given index is marked as invalid.
|
27
|
+
*
|
28
|
+
* @param keyIndex the index of the key
|
29
|
+
*/
|
30
|
+
hasInvalidKeyAtIndex(keyIndex: number): boolean;
|
31
|
+
/**
|
32
|
+
* Informs the key handler that a decryption failure occurred for an encryption key.
|
33
|
+
* @internal
|
34
|
+
* @param keyIndex the key index for which the failure occurred. Defaults to the current key index.
|
35
|
+
*/
|
36
|
+
decryptionFailure(keyIndex?: number): void;
|
37
|
+
/**
|
38
|
+
* Informs the key handler that a frame was successfully decrypted using an encryption key.
|
39
|
+
* @internal
|
40
|
+
* @param keyIndex the key index for which the success occurred. Defaults to the current key index.
|
41
|
+
*/
|
42
|
+
decryptionSuccess(keyIndex?: number): void;
|
25
43
|
/**
|
26
44
|
* Call this after user initiated ratchet or a new key has been set in order to make sure to mark potentially
|
27
45
|
* invalid keys as valid again
|
46
|
+
*
|
47
|
+
* @param keyIndex the index of the key. Defaults to the current key index.
|
28
48
|
*/
|
29
|
-
resetKeyStatus(): void;
|
49
|
+
resetKeyStatus(keyIndex?: number): void;
|
30
50
|
/**
|
31
51
|
* Ratchets the current key (or the one at keyIndex if provided) and
|
32
52
|
* returns the ratcheted material
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"ParticipantKeyHandler.d.ts","sourceRoot":"","sources":["../../../../src/e2ee/worker/ParticipantKeyHandler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,iBAAiB,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAmB,KAAK,8BAA8B,EAAE,MAAM,WAAW,CAAC;AACjF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;oDAcW,iBAAiB,CAAC,8BAA8B,CAAC;AARvH;;;;;;;GAOG;AACH,qBAAa,qBAAsB,SAAQ,0BAA6E;IACtH,OAAO,CAAC,eAAe,CAAS;IAEhC,OAAO,CAAC,aAAa,CAA4B;IAEjD,OAAO,CAAC,kBAAkB,CAAqB;IAE/C,OAAO,CAAC,iBAAiB,CAAkC;IAE3D,OAAO,CAAC,mBAAmB,CAAS;IAEpC
|
1
|
+
{"version":3,"file":"ParticipantKeyHandler.d.ts","sourceRoot":"","sources":["../../../../src/e2ee/worker/ParticipantKeyHandler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,iBAAiB,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAmB,KAAK,8BAA8B,EAAE,MAAM,WAAW,CAAC;AACjF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;oDAcW,iBAAiB,CAAC,8BAA8B,CAAC;AARvH;;;;;;;GAOG;AACH,qBAAa,qBAAsB,SAAQ,0BAA6E;IACtH,OAAO,CAAC,eAAe,CAAS;IAEhC,OAAO,CAAC,aAAa,CAA4B;IAEjD,OAAO,CAAC,uBAAuB,CAAgB;IAE/C,OAAO,CAAC,kBAAkB,CAAqB;IAE/C,OAAO,CAAC,iBAAiB,CAAkC;IAE3D,OAAO,CAAC,mBAAmB,CAAS;IAEpC;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;gBAEW,mBAAmB,EAAE,MAAM,EAAE,kBAAkB,EAAE,kBAAkB;IAa/E;;;;OAIG;IACH,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAO/C;;;;OAIG;IACH,iBAAiB,CAAC,QAAQ,GAAE,MAA6B,GAAG,IAAI;IAchE;;;;OAIG;IACH,iBAAiB,CAAC,QAAQ,GAAE,MAA6B,GAAG,IAAI;IAIhE;;;;;OAKG;IACH,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAQvC;;;;;;OAMG;IACH,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,UAAO,GAAG,OAAO,CAAC,SAAS,CAAC;IA0ChE;;;;;OAKG;IACG,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,SAAI;IAK9C;;;;;OAKG;IACG,kBAAkB,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,UAAQ;IAYxF,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,UAAQ;IAQ9D,kBAAkB,CAAC,KAAK,EAAE,MAAM;IAKtC,kBAAkB;IAIlB;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM;CAG5B"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"LocalParticipant.d.ts","sourceRoot":"","sources":["../../../../src/room/participant/LocalParticipant.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,EAIL,eAAe,EACf,qBAAqB,EAUtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEzD,OAAO,KAAK,SAAS,MAAM,cAAc,CAAC;AAW1C,OAAO,UAAU,MAAM,qBAAqB,CAAC;AAC7C,OAAO,qBAAqB,MAAM,gCAAgC,CAAC;AAEnE,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACxB,yBAAyB,EACzB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;AAS1B,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAYhE,OAAO,WAAW,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAS/E,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,WAAW;IACvD,sBAAsB,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IAE3D,sBAAsB,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IAE3D,+CAA+C;IAC/C,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IAEtD,gBAAgB;IAChB,MAAM,EAAE,SAAS,CAAC;IAElB,gBAAgB;IAChB,eAAe,EAAE,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAE9C,OAAO,CAAC,iBAAiB,CAA2B;IAEpD,OAAO,CAAC,sBAAsB,CAAyD;IAEvF,OAAO,CAAC,gBAAgB,CAA4B;IAEpD,OAAO,CAAC,WAAW,CAAoB;IAEvC,OAAO,CAAC,eAAe,CAAoB;IAE3C,OAAO,CAAC,2BAA2B,CAAyC;IAE5E,OAAO,CAAC,iCAAiC,CAAiB;IAG1D,OAAO,CAAC,WAAW,CAAsB;IAEzC,OAAO,CAAC,cAAc,CAAyC;IAE/D,OAAO,CAAC,eAAe,CAAC,CAAe;IAEvC,OAAO,CAAC,qBAAqB,CAO3B;IAEF,OAAO,CAAC,yBAAyB,CAAe;IAEhD,gBAAgB;gBACJ,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB;IAe1F,IAAI,eAAe,IAAI,KAAK,GAAG,SAAS,CAEvC;IAED,IAAI,mBAAmB,IAAI,KAAK,GAAG,SAAS,CAE3C;IAED,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,qBAAqB,GAAG,SAAS;IAO5E,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS;IAO1E;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,SAAS;IA0B7B,OAAO,CAAC,kBAAkB,CAIxB;IAEF,OAAO,CAAC,iBAAiB,CAIvB;IAEF,OAAO,CAAC,kBAAkB,CAMxB;IAEF,OAAO,CAAC,2BAA2B,CASjC;IAEF;;;;;OAKG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD;;;;;OAKG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1C;;;;;OAKG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;YAIxC,qBAAqB;
|
1
|
+
{"version":3,"file":"LocalParticipant.d.ts","sourceRoot":"","sources":["../../../../src/room/participant/LocalParticipant.ts"],"names":[],"mappings":"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"}
|
@@ -13,20 +13,40 @@ declare const ParticipantKeyHandler_base: new () => TypedEventEmitter<Participan
|
|
13
13
|
export declare class ParticipantKeyHandler extends ParticipantKeyHandler_base {
|
14
14
|
private currentKeyIndex;
|
15
15
|
private cryptoKeyRing;
|
16
|
+
private decryptionFailureCounts;
|
16
17
|
private keyProviderOptions;
|
17
18
|
private ratchetPromiseMap;
|
18
19
|
private participantIdentity;
|
19
|
-
|
20
|
-
|
20
|
+
/**
|
21
|
+
* true if the current key has not been marked as invalid
|
22
|
+
*/
|
21
23
|
get hasValidKey(): boolean;
|
22
24
|
constructor(participantIdentity: string, keyProviderOptions: KeyProviderOptions);
|
23
|
-
|
24
|
-
|
25
|
+
/**
|
26
|
+
* Returns true if the key at the given index is marked as invalid.
|
27
|
+
*
|
28
|
+
* @param keyIndex the index of the key
|
29
|
+
*/
|
30
|
+
hasInvalidKeyAtIndex(keyIndex: number): boolean;
|
31
|
+
/**
|
32
|
+
* Informs the key handler that a decryption failure occurred for an encryption key.
|
33
|
+
* @internal
|
34
|
+
* @param keyIndex the key index for which the failure occurred. Defaults to the current key index.
|
35
|
+
*/
|
36
|
+
decryptionFailure(keyIndex?: number): void;
|
37
|
+
/**
|
38
|
+
* Informs the key handler that a frame was successfully decrypted using an encryption key.
|
39
|
+
* @internal
|
40
|
+
* @param keyIndex the key index for which the success occurred. Defaults to the current key index.
|
41
|
+
*/
|
42
|
+
decryptionSuccess(keyIndex?: number): void;
|
25
43
|
/**
|
26
44
|
* Call this after user initiated ratchet or a new key has been set in order to make sure to mark potentially
|
27
45
|
* invalid keys as valid again
|
46
|
+
*
|
47
|
+
* @param keyIndex the index of the key. Defaults to the current key index.
|
28
48
|
*/
|
29
|
-
resetKeyStatus(): void;
|
49
|
+
resetKeyStatus(keyIndex?: number): void;
|
30
50
|
/**
|
31
51
|
* Ratchets the current key (or the one at keyIndex if provided) and
|
32
52
|
* returns the ratcheted material
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "livekit-client",
|
3
|
-
"version": "2.5.
|
3
|
+
"version": "2.5.9",
|
4
4
|
"description": "JavaScript/TypeScript client SDK for LiveKit",
|
5
5
|
"main": "./dist/livekit-client.umd.js",
|
6
6
|
"unpkg": "./dist/livekit-client.umd.js",
|
@@ -71,7 +71,7 @@
|
|
71
71
|
"eslint-plugin-ecmascript-compat": "^3.0.0",
|
72
72
|
"eslint-plugin-import": "2.30.0",
|
73
73
|
"gh-pages": "6.1.1",
|
74
|
-
"
|
74
|
+
"happy-dom": "^15.7.4",
|
75
75
|
"prettier": "^3.0.0",
|
76
76
|
"rollup": "4.24.0",
|
77
77
|
"rollup-plugin-delete": "^2.0.0",
|
@@ -60,6 +60,21 @@ class TestUnderlyingSink<T> implements UnderlyingSink<T> {
|
|
60
60
|
function prepareParticipantTestDecoder(
|
61
61
|
participantIdentity: string,
|
62
62
|
partialKeyProviderOptions: Partial<KeyProviderOptions>,
|
63
|
+
) {
|
64
|
+
return prepareParticipantTest('decode', participantIdentity, partialKeyProviderOptions);
|
65
|
+
}
|
66
|
+
|
67
|
+
function prepareParticipantTestEncoder(
|
68
|
+
participantIdentity: string,
|
69
|
+
partialKeyProviderOptions: Partial<KeyProviderOptions>,
|
70
|
+
) {
|
71
|
+
return prepareParticipantTest('encode', participantIdentity, partialKeyProviderOptions);
|
72
|
+
}
|
73
|
+
|
74
|
+
function prepareParticipantTest(
|
75
|
+
mode: 'encode' | 'decode',
|
76
|
+
participantIdentity: string,
|
77
|
+
partialKeyProviderOptions: Partial<KeyProviderOptions>,
|
63
78
|
): {
|
64
79
|
keys: ParticipantKeyHandler;
|
65
80
|
cryptor: FrameCryptor;
|
@@ -80,12 +95,7 @@ function prepareParticipantTestDecoder(
|
|
80
95
|
|
81
96
|
const input = new TestUnderlyingSource<RTCEncodedVideoFrame>();
|
82
97
|
const output = new TestUnderlyingSink<RTCEncodedVideoFrame>();
|
83
|
-
cryptor.setupTransform(
|
84
|
-
'decode',
|
85
|
-
new ReadableStream(input),
|
86
|
-
new WritableStream(output),
|
87
|
-
'testTrack',
|
88
|
-
);
|
98
|
+
cryptor.setupTransform(mode, new ReadableStream(input), new WritableStream(output), 'testTrack');
|
89
99
|
|
90
100
|
return { keys, cryptor, input, output };
|
91
101
|
}
|
@@ -93,10 +103,6 @@ function prepareParticipantTestDecoder(
|
|
93
103
|
describe('FrameCryptor', () => {
|
94
104
|
const participantIdentity = 'testParticipant';
|
95
105
|
|
96
|
-
afterEach(() => {
|
97
|
-
encryptionEnabledMap.clear();
|
98
|
-
});
|
99
|
-
|
100
106
|
it('identifies server injected frame correctly', () => {
|
101
107
|
const frameTrailer = new TextEncoder().encode('LKROCKS');
|
102
108
|
const frameData = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, ...frameTrailer]).buffer;
|
@@ -113,154 +119,346 @@ describe('FrameCryptor', () => {
|
|
113
119
|
expect(isFrameServerInjected(frameData.buffer, frameTrailer)).toBe(false);
|
114
120
|
});
|
115
121
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
122
|
+
describe('encode', () => {
|
123
|
+
afterEach(() => {
|
124
|
+
encryptionEnabledMap.clear();
|
125
|
+
});
|
120
126
|
|
121
|
-
|
122
|
-
|
127
|
+
it('passthrough if participant encryption disabled', async () => {
|
128
|
+
vitest.useFakeTimers();
|
129
|
+
try {
|
130
|
+
const { input, output } = prepareParticipantTestEncoder(participantIdentity, {});
|
123
131
|
|
124
|
-
|
132
|
+
// disable encryption for participant
|
133
|
+
encryptionEnabledMap.set(participantIdentity, false);
|
125
134
|
|
126
|
-
|
127
|
-
await vitest.advanceTimersToNextTimerAsync();
|
135
|
+
const frame = mockRTCEncodedVideoFrame(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]));
|
128
136
|
|
129
|
-
|
130
|
-
|
131
|
-
vitest.useRealTimers();
|
132
|
-
}
|
133
|
-
});
|
137
|
+
input.write(frame);
|
138
|
+
await vitest.advanceTimersToNextTimerAsync();
|
134
139
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
140
|
+
expect(output.chunks).toEqual([frame]);
|
141
|
+
} finally {
|
142
|
+
vitest.useRealTimers();
|
143
|
+
}
|
144
|
+
});
|
139
145
|
|
140
|
-
|
141
|
-
|
146
|
+
it('passthrough for empty frame', async () => {
|
147
|
+
vitest.useFakeTimers();
|
148
|
+
try {
|
149
|
+
const { input, output } = prepareParticipantTestEncoder(participantIdentity, {});
|
142
150
|
|
143
|
-
|
144
|
-
|
151
|
+
// empty frame
|
152
|
+
const frame = mockRTCEncodedVideoFrame(new Uint8Array(0));
|
145
153
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
154
|
+
input.write(frame);
|
155
|
+
await vitest.advanceTimersToNextTimerAsync();
|
156
|
+
|
157
|
+
expect(output.chunks).toEqual([frame]);
|
158
|
+
} finally {
|
159
|
+
vitest.useRealTimers();
|
160
|
+
}
|
161
|
+
});
|
162
|
+
|
163
|
+
it('immediately drops frame and emits error if no key set', async () => {
|
164
|
+
vitest.useFakeTimers();
|
165
|
+
try {
|
166
|
+
const { cryptor, input, output } = prepareParticipantTestEncoder(participantIdentity, {});
|
167
|
+
|
168
|
+
const errorListener = vitest.fn();
|
169
|
+
cryptor.on(CryptorEvent.Error, errorListener);
|
170
|
+
|
171
|
+
const frame = mockRTCEncodedVideoFrame(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]));
|
151
172
|
|
152
|
-
|
153
|
-
|
154
|
-
try {
|
155
|
-
const { keys, input, output } = prepareParticipantTestDecoder(participantIdentity, {
|
156
|
-
failureTolerance: 0,
|
157
|
-
});
|
173
|
+
input.write(frame);
|
174
|
+
await vitest.advanceTimersToNextTimerAsync();
|
158
175
|
|
159
|
-
|
176
|
+
expect(output.chunks).toEqual([]);
|
177
|
+
expect(errorListener).toHaveBeenCalled();
|
178
|
+
} finally {
|
179
|
+
vitest.useRealTimers();
|
180
|
+
}
|
181
|
+
});
|
182
|
+
|
183
|
+
it('encrypts frame', async () => {
|
184
|
+
vitest.useFakeTimers();
|
185
|
+
try {
|
186
|
+
const { keys, input, output } = prepareParticipantTestEncoder(participantIdentity, {});
|
187
|
+
|
188
|
+
await keys.setKey(await createKeyMaterialFromString('key1'), 1);
|
160
189
|
|
161
|
-
|
190
|
+
const plainTextData = new Uint8Array([
|
191
|
+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
192
|
+
]);
|
193
|
+
const frame = mockRTCEncodedVideoFrame(plainTextData);
|
162
194
|
|
163
|
-
|
164
|
-
|
195
|
+
input.write(frame);
|
196
|
+
await vitest.waitFor(() => expect(output.chunks).toHaveLength(1));
|
165
197
|
|
166
|
-
|
167
|
-
|
198
|
+
expect(output.chunks).toEqual([frame]);
|
199
|
+
expect(frame.data.byteLength).toBeGreaterThan(16);
|
168
200
|
|
169
|
-
|
170
|
-
|
171
|
-
await vitest.advanceTimersToNextTimerAsync();
|
201
|
+
// first bytes are unencrypted
|
202
|
+
expect(new Uint8Array(frame.data.slice(0, 10))).toEqual(plainTextData.subarray(0, 10));
|
172
203
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
204
|
+
// remainder should not be the same
|
205
|
+
expect(new Uint8Array(frame.data.slice(10, 16))).not.toEqual(
|
206
|
+
plainTextData.subarray(10, 16),
|
207
|
+
);
|
208
|
+
|
209
|
+
const frameTrailer = new Uint8Array(frame.data.slice(frame.data.byteLength - 2));
|
210
|
+
// IV length
|
211
|
+
expect(frameTrailer[0]).toEqual(IV_LENGTH);
|
212
|
+
// key index
|
213
|
+
expect(frameTrailer[1]).toEqual(1);
|
214
|
+
} finally {
|
215
|
+
vitest.useRealTimers();
|
216
|
+
}
|
217
|
+
});
|
178
218
|
});
|
179
219
|
|
180
|
-
|
181
|
-
|
182
|
-
|
220
|
+
describe('decode', () => {
|
221
|
+
afterEach(() => {
|
222
|
+
encryptionEnabledMap.clear();
|
183
223
|
});
|
184
224
|
|
185
|
-
|
225
|
+
it('passthrough if participant encryption disabled', async () => {
|
226
|
+
vitest.useFakeTimers();
|
227
|
+
try {
|
228
|
+
const { input, output } = prepareParticipantTestDecoder(participantIdentity, {});
|
186
229
|
|
187
|
-
|
230
|
+
// disable encryption for participant
|
231
|
+
encryptionEnabledMap.set(participantIdentity, false);
|
188
232
|
|
189
|
-
|
190
|
-
vitest.spyOn(keys, 'decryptionFailure');
|
233
|
+
const frame = mockEncryptedRTCEncodedVideoFrame(1);
|
191
234
|
|
192
|
-
|
193
|
-
|
235
|
+
input.write(frame);
|
236
|
+
await vitest.advanceTimersToNextTimerAsync();
|
237
|
+
|
238
|
+
expect(output.chunks).toEqual([frame]);
|
239
|
+
} finally {
|
240
|
+
vitest.useRealTimers();
|
241
|
+
}
|
194
242
|
});
|
195
|
-
cryptor.on(CryptorEvent.Error, errorListener);
|
196
243
|
|
197
|
-
|
244
|
+
it('passthrough for empty frame', async () => {
|
245
|
+
vitest.useFakeTimers();
|
246
|
+
try {
|
247
|
+
const { input, output } = prepareParticipantTestDecoder(participantIdentity, {});
|
198
248
|
|
199
|
-
|
200
|
-
|
201
|
-
expect(keys.decryptionFailure).toHaveBeenCalledTimes(1);
|
202
|
-
expect(keys.getKeySet).toHaveBeenCalled();
|
203
|
-
expect(keys.getKeySet).toHaveBeenLastCalledWith(1);
|
204
|
-
expect(keys.hasValidKey).toBe(true);
|
249
|
+
// empty frame
|
250
|
+
const frame = mockRTCEncodedVideoFrame(new Uint8Array(0));
|
205
251
|
|
206
|
-
|
252
|
+
input.write(frame);
|
253
|
+
await vitest.advanceTimersToNextTimerAsync();
|
207
254
|
|
208
|
-
|
255
|
+
expect(output.chunks).toEqual([frame]);
|
256
|
+
} finally {
|
257
|
+
vitest.useRealTimers();
|
258
|
+
}
|
259
|
+
});
|
209
260
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
261
|
+
it('immediately drops frames when key marked invalid', async () => {
|
262
|
+
vitest.useFakeTimers();
|
263
|
+
try {
|
264
|
+
const { keys, input, output } = prepareParticipantTestDecoder(participantIdentity, {
|
265
|
+
failureTolerance: 0,
|
266
|
+
});
|
216
267
|
|
217
|
-
|
268
|
+
keys.decryptionFailure();
|
218
269
|
|
219
|
-
|
220
|
-
|
270
|
+
input.write(mockEncryptedRTCEncodedVideoFrame(1));
|
271
|
+
await vitest.advanceTimersToNextTimerAsync();
|
221
272
|
|
222
|
-
|
223
|
-
// decryptionFailure() isn't called in this case
|
224
|
-
expect(keys.getKeySet).toHaveBeenCalled();
|
225
|
-
expect(keys.getKeySet).toHaveBeenLastCalledWith(0);
|
226
|
-
expect(keys.hasValidKey).toBe(false);
|
227
|
-
});
|
273
|
+
expect(output.chunks).toEqual([]);
|
228
274
|
|
229
|
-
|
230
|
-
const { keys, input } = prepareParticipantTestDecoder(participantIdentity, {
|
231
|
-
failureTolerance: 0,
|
232
|
-
});
|
275
|
+
keys.decryptionFailure();
|
233
276
|
|
234
|
-
|
235
|
-
|
277
|
+
input.write(mockEncryptedRTCEncodedVideoFrame(0));
|
278
|
+
await vitest.advanceTimersToNextTimerAsync();
|
236
279
|
|
237
|
-
|
280
|
+
expect(output.chunks).toEqual([]);
|
281
|
+
} finally {
|
282
|
+
vitest.useRealTimers();
|
283
|
+
}
|
284
|
+
});
|
238
285
|
|
239
|
-
|
286
|
+
it('calls decryptionFailure on missing key and emits error', async () => {
|
287
|
+
vitest.useFakeTimers();
|
288
|
+
try {
|
289
|
+
const { cryptor, keys, input } = prepareParticipantTestDecoder(participantIdentity, {});
|
290
|
+
|
291
|
+
const errorListener = vitest.fn();
|
292
|
+
cryptor.on(CryptorEvent.Error, errorListener);
|
293
|
+
vitest.spyOn(keys, 'decryptionFailure');
|
294
|
+
|
295
|
+
// no key is set at this index
|
296
|
+
input.write(mockEncryptedRTCEncodedVideoFrame(1));
|
297
|
+
await vitest.advanceTimersToNextTimerAsync();
|
298
|
+
|
299
|
+
expect(keys.decryptionFailure).toHaveBeenCalledTimes(1);
|
300
|
+
expect(keys.decryptionFailure).toHaveBeenCalledWith(1);
|
301
|
+
expect(errorListener).toHaveBeenCalled();
|
302
|
+
} finally {
|
303
|
+
vitest.useRealTimers();
|
304
|
+
}
|
305
|
+
});
|
240
306
|
|
241
|
-
|
307
|
+
it('immediately drops frame if no key', async () => {
|
308
|
+
vitest.useFakeTimers();
|
309
|
+
try {
|
310
|
+
const { input, output } = prepareParticipantTestDecoder(participantIdentity, {});
|
242
311
|
|
243
|
-
|
312
|
+
vitest.spyOn(crypto.subtle, 'decrypt');
|
244
313
|
|
245
|
-
|
246
|
-
|
314
|
+
input.write(mockEncryptedRTCEncodedVideoFrame(1));
|
315
|
+
await vitest.advanceTimersToNextTimerAsync();
|
247
316
|
|
248
|
-
|
249
|
-
|
250
|
-
|
317
|
+
expect(crypto.subtle.decrypt).not.toHaveBeenCalled();
|
318
|
+
expect(output.chunks).toEqual([]);
|
319
|
+
} finally {
|
320
|
+
vitest.useRealTimers();
|
321
|
+
}
|
251
322
|
});
|
252
323
|
|
253
|
-
|
254
|
-
|
324
|
+
it('calls decryptionFailure with incorrect key and emits error', async () => {
|
325
|
+
vitest.useFakeTimers();
|
326
|
+
try {
|
327
|
+
const { cryptor, keys, input, output } = prepareParticipantTestDecoder(
|
328
|
+
participantIdentity,
|
329
|
+
{ ratchetWindowSize: 0 },
|
330
|
+
);
|
331
|
+
|
332
|
+
vitest.spyOn(crypto.subtle, 'decrypt');
|
333
|
+
vitest.spyOn(keys, 'decryptionFailure');
|
334
|
+
const errorListener = vitest.fn();
|
335
|
+
cryptor.on(CryptorEvent.Error, errorListener);
|
336
|
+
|
337
|
+
await keys.setKey(await createKeyMaterialFromString('incorrect key'), 1);
|
338
|
+
|
339
|
+
const frame = mockRTCEncodedVideoFrame(
|
340
|
+
new Uint8Array([
|
341
|
+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 254, 96, 91, 111, 187, 132, 31, 12, 207, 136, 17, 221,
|
342
|
+
233, 116, 174, 6, 50, 37, 214, 71, 119, 196, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255,
|
343
|
+
199, 51, 12, 1,
|
344
|
+
]),
|
345
|
+
);
|
346
|
+
// global.RTCEncodedAudioFrame = vitest.fn();
|
347
|
+
input.write(frame);
|
348
|
+
await vitest.waitFor(() => expect(keys.decryptionFailure).toHaveBeenCalled());
|
349
|
+
|
350
|
+
expect(crypto.subtle.decrypt).toHaveBeenCalled();
|
351
|
+
expect(output.chunks).toEqual([]);
|
352
|
+
expect(errorListener).toHaveBeenCalled();
|
353
|
+
expect(keys.decryptionFailure).toHaveBeenCalledTimes(1);
|
354
|
+
expect(keys.decryptionFailure).toHaveBeenCalledWith(1);
|
355
|
+
} finally {
|
356
|
+
vitest.useRealTimers();
|
357
|
+
}
|
358
|
+
});
|
359
|
+
|
360
|
+
it('decrypts frame with correct key', async () => {
|
361
|
+
vitest.useFakeTimers();
|
362
|
+
try {
|
363
|
+
const { keys, input, output } = prepareParticipantTestDecoder(participantIdentity, {});
|
364
|
+
|
365
|
+
vitest.spyOn(keys, 'decryptionSuccess');
|
255
366
|
|
256
|
-
|
367
|
+
await keys.setKey(await createKeyMaterialFromString('key1'), 1);
|
257
368
|
|
258
|
-
|
369
|
+
const frame = mockRTCEncodedVideoFrame(
|
370
|
+
new Uint8Array([
|
371
|
+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 254, 96, 91, 111, 187, 132, 31, 12, 207, 136, 17, 221,
|
372
|
+
233, 116, 174, 6, 50, 37, 214, 71, 119, 196, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255,
|
373
|
+
199, 51, 12, 1,
|
374
|
+
]),
|
375
|
+
);
|
376
|
+
input.write(frame);
|
377
|
+
await vitest.waitFor(() => expect(output.chunks).toHaveLength(1));
|
259
378
|
|
260
|
-
|
379
|
+
expect(output.chunks).toEqual([frame]);
|
261
380
|
|
262
|
-
|
381
|
+
expect(keys.decryptionSuccess).toHaveBeenCalledTimes(1);
|
382
|
+
expect(keys.decryptionSuccess).toHaveBeenCalledWith(1);
|
263
383
|
|
264
|
-
|
384
|
+
expect(frame.data.byteLength).toBe(16);
|
385
|
+
|
386
|
+
expect(new Uint8Array(frame.data)).toEqual(
|
387
|
+
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
|
388
|
+
);
|
389
|
+
} finally {
|
390
|
+
vitest.useRealTimers();
|
391
|
+
}
|
392
|
+
});
|
393
|
+
|
394
|
+
it('recovers from delayed use of rotated key', async () => {
|
395
|
+
vitest.useFakeTimers();
|
396
|
+
try {
|
397
|
+
// 1. we (the local participant) have just joined a room and do not have the existing key (index 0) for the existing/remote participant
|
398
|
+
const { keys, input, output } = prepareParticipantTestDecoder(participantIdentity, {
|
399
|
+
failureTolerance: 1,
|
400
|
+
ratchetWindowSize: 0,
|
401
|
+
});
|
402
|
+
vitest.spyOn(keys, 'decryptionFailure');
|
403
|
+
|
404
|
+
// 2. we receive some frames from the existing participant encrypted with the existing key 0 that we don't have
|
405
|
+
input.write(mockEncryptedRTCEncodedVideoFrame(0));
|
406
|
+
input.write(mockEncryptedRTCEncodedVideoFrame(0));
|
407
|
+
input.write(mockEncryptedRTCEncodedVideoFrame(0));
|
408
|
+
input.write(mockEncryptedRTCEncodedVideoFrame(0));
|
409
|
+
|
410
|
+
// 3. we should have marked key at index 0 as invalid by now and dropped all the frames
|
411
|
+
await vitest.waitFor(() => expect(keys.decryptionFailure).toHaveBeenCalledTimes(2));
|
412
|
+
expect(keys.hasInvalidKeyAtIndex(0)).toBe(true);
|
413
|
+
expect(output.chunks).toEqual([]);
|
414
|
+
|
415
|
+
// 4. the existing participant then notices that we have joined the room and generates a new key (with a new key index 1)
|
416
|
+
// and distributes it out of band to us
|
417
|
+
await keys.setKey(await createKeyMaterialFromString('key1'), 1);
|
418
|
+
|
419
|
+
// 5. the existing participant waits a period of time before using the new key and continues sending media using the previous key 0.
|
420
|
+
// we receive these frames and should drop them as we still don't have the key.
|
421
|
+
input.write(mockEncryptedRTCEncodedVideoFrame(0));
|
422
|
+
input.write(mockEncryptedRTCEncodedVideoFrame(0));
|
423
|
+
input.write(mockEncryptedRTCEncodedVideoFrame(0));
|
424
|
+
input.write(mockEncryptedRTCEncodedVideoFrame(0));
|
425
|
+
|
426
|
+
await vitest.advanceTimersToNextTimerAsync();
|
427
|
+
expect(output.chunks).toEqual([]);
|
428
|
+
|
429
|
+
// 6. the existing participant moves over to the new key index 1 and we start to receive frames for index 1 that we
|
430
|
+
// should be able to decrypt even though we had the previous failures.
|
431
|
+
input.write(
|
432
|
+
mockRTCEncodedVideoFrame(
|
433
|
+
new Uint8Array([
|
434
|
+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 254, 96, 91, 111, 187, 132, 31, 12, 207, 136, 17, 221,
|
435
|
+
233, 116, 174, 6, 50, 37, 214, 71, 119, 196, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255,
|
436
|
+
199, 51, 12, 1,
|
437
|
+
]),
|
438
|
+
),
|
439
|
+
);
|
440
|
+
|
441
|
+
input.write(
|
442
|
+
mockRTCEncodedVideoFrame(
|
443
|
+
new Uint8Array([
|
444
|
+
99, 2, 3, 4, 5, 6, 7, 8, 9, 10, 154, 108, 209, 239, 253, 33, 72, 111, 13, 125, 10,
|
445
|
+
101, 28, 209, 141, 162, 0, 238, 189, 254, 66, 156, 255, 255, 255, 255, 0, 0, 0, 0,
|
446
|
+
255, 255, 96, 247, 12, 1,
|
447
|
+
]),
|
448
|
+
),
|
449
|
+
);
|
450
|
+
|
451
|
+
await vitest.waitFor(() => expect(output.chunks.length).toEqual(2));
|
452
|
+
|
453
|
+
expect(new Uint8Array(output.chunks[0].data)).toEqual(
|
454
|
+
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
|
455
|
+
);
|
456
|
+
expect(new Uint8Array(output.chunks[1].data)).toEqual(
|
457
|
+
new Uint8Array([99, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
|
458
|
+
);
|
459
|
+
} finally {
|
460
|
+
vitest.useRealTimers();
|
461
|
+
}
|
462
|
+
});
|
265
463
|
});
|
266
464
|
});
|