livekit-client 2.5.8 → 2.5.9
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 +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
|
});
|