livekit-client 1.12.3 → 1.13.0
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 +83 -9
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +357 -97
- 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/api/SignalClient.d.ts +2 -5
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/turn.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/webrtc.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/websocket.d.ts.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts +5 -0
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/KeyProvider.d.ts +4 -2
- package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
- package/dist/src/e2ee/constants.d.ts +2 -0
- package/dist/src/e2ee/constants.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +7 -1
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/utils.d.ts +1 -0
- package/dist/src/e2ee/utils.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +4 -2
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
- package/dist/src/e2ee/worker/SifGuard.d.ts +11 -0
- package/dist/src/e2ee/worker/SifGuard.d.ts.map +1 -0
- package/dist/src/options.d.ts +5 -0
- package/dist/src/options.d.ts.map +1 -1
- package/dist/src/proto/livekit_models_pb.d.ts.map +1 -1
- package/dist/src/proto/livekit_rtc_pb.d.ts.map +1 -1
- package/dist/src/room/DeviceManager.d.ts +1 -0
- package/dist/src/room/DeviceManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/defaults.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +5 -0
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts +0 -5
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/timers.d.ts +2 -2
- package/dist/src/room/timers.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts +9 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +3 -3
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalVideoTrack.d.ts +6 -0
- package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/processor/types.d.ts +13 -2
- package/dist/src/room/track/processor/types.d.ts.map +1 -1
- package/dist/src/room/types.d.ts +1 -1
- package/dist/src/room/types.d.ts.map +1 -1
- package/dist/ts4.2/src/api/SignalClient.d.ts +2 -5
- package/dist/ts4.2/src/e2ee/E2eeManager.d.ts +5 -0
- package/dist/ts4.2/src/e2ee/KeyProvider.d.ts +4 -2
- package/dist/ts4.2/src/e2ee/constants.d.ts +2 -0
- package/dist/ts4.2/src/e2ee/types.d.ts +7 -1
- package/dist/ts4.2/src/e2ee/utils.d.ts +1 -0
- package/dist/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +4 -2
- package/dist/ts4.2/src/e2ee/worker/SifGuard.d.ts +11 -0
- package/dist/ts4.2/src/options.d.ts +5 -0
- package/dist/ts4.2/src/room/DeviceManager.d.ts +1 -0
- package/dist/ts4.2/src/room/Room.d.ts +1 -1
- package/dist/ts4.2/src/room/participant/Participant.d.ts +5 -0
- package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +0 -5
- package/dist/ts4.2/src/room/timers.d.ts +2 -2
- package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +9 -1
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +3 -3
- package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +6 -0
- package/dist/ts4.2/src/room/track/processor/types.d.ts +13 -2
- package/dist/ts4.2/src/room/types.d.ts +1 -1
- package/package.json +15 -16
- package/src/api/SignalClient.ts +13 -9
- package/src/connectionHelper/checks/turn.ts +1 -0
- package/src/connectionHelper/checks/webrtc.ts +9 -7
- package/src/connectionHelper/checks/websocket.ts +1 -0
- package/src/e2ee/E2eeManager.ts +27 -2
- package/src/e2ee/KeyProvider.ts +9 -4
- package/src/e2ee/constants.ts +3 -0
- package/src/e2ee/types.ts +9 -1
- package/src/e2ee/utils.ts +9 -0
- package/src/e2ee/worker/FrameCryptor.ts +46 -17
- package/src/e2ee/worker/ParticipantKeyHandler.ts +1 -0
- package/src/e2ee/worker/SifGuard.ts +47 -0
- package/src/e2ee/worker/e2ee.worker.ts +14 -0
- package/src/options.ts +6 -0
- package/src/proto/livekit_models_pb.ts +14 -0
- package/src/proto/livekit_rtc_pb.ts +14 -0
- package/src/room/DeviceManager.ts +7 -2
- package/src/room/RTCEngine.ts +3 -1
- package/src/room/Room.ts +27 -7
- package/src/room/defaults.ts +1 -0
- package/src/room/participant/LocalParticipant.ts +14 -2
- package/src/room/participant/Participant.ts +16 -0
- package/src/room/participant/RemoteParticipant.ts +0 -12
- package/src/room/track/LocalAudioTrack.ts +45 -0
- package/src/room/track/LocalTrack.ts +4 -4
- package/src/room/track/LocalVideoTrack.ts +39 -0
- package/src/room/track/RemoteAudioTrack.ts +9 -1
- package/src/room/track/RemoteTrackPublication.ts +2 -2
- package/src/room/track/processor/types.ts +17 -2
- package/src/room/types.ts +5 -1
@@ -341,6 +341,8 @@ const KEY_PROVIDER_DEFAULTS = {
|
|
341
341
|
ratchetWindowSize: 8,
|
342
342
|
failureTolerance: DECRYPTION_FAILURE_TOLERANCE
|
343
343
|
};
|
344
|
+
const MAX_SIF_COUNT = 100;
|
345
|
+
const MAX_SIF_DURATION = 2000;
|
344
346
|
|
345
347
|
class LivekitError extends Error {
|
346
348
|
constructor(code, message) {
|
@@ -865,6 +867,42 @@ function ratchet(material, salt) {
|
|
865
867
|
});
|
866
868
|
}
|
867
869
|
|
870
|
+
class SifGuard {
|
871
|
+
constructor() {
|
872
|
+
this.consecutiveSifCount = 0;
|
873
|
+
this.lastSifReceivedAt = 0;
|
874
|
+
this.userFramesSinceSif = 0;
|
875
|
+
}
|
876
|
+
recordSif() {
|
877
|
+
var _a;
|
878
|
+
this.consecutiveSifCount += 1;
|
879
|
+
(_a = this.sifSequenceStartedAt) !== null && _a !== void 0 ? _a : this.sifSequenceStartedAt = Date.now();
|
880
|
+
this.lastSifReceivedAt = Date.now();
|
881
|
+
}
|
882
|
+
recordUserFrame() {
|
883
|
+
if (this.sifSequenceStartedAt === undefined) {
|
884
|
+
return;
|
885
|
+
} else {
|
886
|
+
this.userFramesSinceSif += 1;
|
887
|
+
}
|
888
|
+
if (
|
889
|
+
// reset if we received more user frames than SIFs
|
890
|
+
this.userFramesSinceSif > this.consecutiveSifCount ||
|
891
|
+
// also reset if we got a new user frame and the latest SIF frame hasn't been updated in a while
|
892
|
+
Date.now() - this.lastSifReceivedAt > MAX_SIF_DURATION) {
|
893
|
+
this.reset();
|
894
|
+
}
|
895
|
+
}
|
896
|
+
isSifAllowed() {
|
897
|
+
return this.consecutiveSifCount < MAX_SIF_COUNT && (this.sifSequenceStartedAt === undefined || Date.now() - this.sifSequenceStartedAt < MAX_SIF_DURATION);
|
898
|
+
}
|
899
|
+
reset() {
|
900
|
+
this.userFramesSinceSif = 0;
|
901
|
+
this.consecutiveSifCount = 0;
|
902
|
+
this.sifSequenceStartedAt = undefined;
|
903
|
+
}
|
904
|
+
}
|
905
|
+
|
868
906
|
class BaseFrameCryptor extends eventsExports.EventEmitter {
|
869
907
|
encodeFunction(encodedFrame, controller) {
|
870
908
|
throw Error('not implemented for subclass');
|
@@ -886,7 +924,8 @@ class FrameCryptor extends BaseFrameCryptor {
|
|
886
924
|
this.participantId = opts.participantId;
|
887
925
|
this.rtpMap = new Map();
|
888
926
|
this.keyProviderOptions = opts.keyProviderOptions;
|
889
|
-
this.
|
927
|
+
this.sifTrailer = (_a = opts.sifTrailer) !== null && _a !== void 0 ? _a : Uint8Array.from([]);
|
928
|
+
this.sifGuard = new SifGuard();
|
890
929
|
}
|
891
930
|
/**
|
892
931
|
* Assign a different participant to the cryptor.
|
@@ -897,6 +936,7 @@ class FrameCryptor extends BaseFrameCryptor {
|
|
897
936
|
setParticipant(id, keys) {
|
898
937
|
this.participantId = id;
|
899
938
|
this.keys = keys;
|
939
|
+
this.sifGuard.reset();
|
900
940
|
}
|
901
941
|
unsetParticipant() {
|
902
942
|
this.participantId = undefined;
|
@@ -923,7 +963,9 @@ class FrameCryptor extends BaseFrameCryptor {
|
|
923
963
|
}
|
924
964
|
setupTransform(operation, readable, writable, trackId, codec) {
|
925
965
|
if (codec) {
|
926
|
-
|
966
|
+
workerLogger.info('setting codec on cryptor to', {
|
967
|
+
codec
|
968
|
+
});
|
927
969
|
this.videoCodec = codec;
|
928
970
|
}
|
929
971
|
const transformFn = operation === 'encode' ? this.encodeFunction : this.decodeFunction;
|
@@ -931,7 +973,7 @@ class FrameCryptor extends BaseFrameCryptor {
|
|
931
973
|
transform: transformFn.bind(this)
|
932
974
|
});
|
933
975
|
readable.pipeThrough(transformStream).pipeTo(writable).catch(e => {
|
934
|
-
|
976
|
+
workerLogger.warn(e);
|
935
977
|
this.emit('cryptorError', e instanceof CryptorError ? e : new CryptorError(e.message));
|
936
978
|
});
|
937
979
|
this.trackId = trackId;
|
@@ -1018,11 +1060,21 @@ class FrameCryptor extends BaseFrameCryptor {
|
|
1018
1060
|
return __awaiter(this, void 0, void 0, function* () {
|
1019
1061
|
if (!this.keys.isEnabled() ||
|
1020
1062
|
// skip for decryption for empty dtx frames
|
1021
|
-
encodedFrame.data.byteLength === 0
|
1022
|
-
|
1023
|
-
isFrameServerInjected(encodedFrame.data, this.unencryptedFrameByteTrailer)) {
|
1063
|
+
encodedFrame.data.byteLength === 0) {
|
1064
|
+
this.sifGuard.recordUserFrame();
|
1024
1065
|
return controller.enqueue(encodedFrame);
|
1025
1066
|
}
|
1067
|
+
if (isFrameServerInjected(encodedFrame.data, this.sifTrailer)) {
|
1068
|
+
this.sifGuard.recordSif();
|
1069
|
+
if (this.sifGuard.isSifAllowed()) {
|
1070
|
+
return controller.enqueue(encodedFrame);
|
1071
|
+
} else {
|
1072
|
+
workerLogger.warn('SIF limit reached, dropping frame');
|
1073
|
+
return;
|
1074
|
+
}
|
1075
|
+
} else {
|
1076
|
+
this.sifGuard.recordUserFrame();
|
1077
|
+
}
|
1026
1078
|
const data = new Uint8Array(encodedFrame.data);
|
1027
1079
|
const keyIndex = data[encodedFrame.data.byteLength - 1];
|
1028
1080
|
if (this.keys.getKeySet(keyIndex) && this.keys.hasValidKey) {
|
@@ -1045,8 +1097,11 @@ class FrameCryptor extends BaseFrameCryptor {
|
|
1045
1097
|
});
|
1046
1098
|
}
|
1047
1099
|
}
|
1100
|
+
} else if (!this.keys.getKeySet(keyIndex) && this.keys.hasValidKey) {
|
1101
|
+
// emit an error in case the key index is out of bounds but the key handler thinks we still have a valid key
|
1102
|
+
workerLogger.warn('skipping decryption due to missing key at index');
|
1103
|
+
this.emit(CryptorEvent.Error, new CryptorError("missing key at index for participant ".concat(this.participantId), CryptorErrorReason.MissingKey));
|
1048
1104
|
}
|
1049
|
-
return controller.enqueue(encodedFrame);
|
1050
1105
|
});
|
1051
1106
|
}
|
1052
1107
|
/**
|
@@ -1119,7 +1174,7 @@ class FrameCryptor extends BaseFrameCryptor {
|
|
1119
1174
|
this.keys.setKeyFromMaterial(initialMaterial.material, keyIndex);
|
1120
1175
|
}
|
1121
1176
|
workerLogger.warn('maximum ratchet attempts exceeded, resetting key');
|
1122
|
-
|
1177
|
+
throw new CryptorError("valid key missing for participant ".concat(this.participantId), CryptorErrorReason.InvalidKey);
|
1123
1178
|
}
|
1124
1179
|
} else {
|
1125
1180
|
throw new CryptorError('Decryption failed, most likely because of an invalid key', CryptorErrorReason.InvalidKey);
|
@@ -1210,6 +1265,9 @@ class FrameCryptor extends BaseFrameCryptor {
|
|
1210
1265
|
const codec = payloadType ? this.rtpMap.get(payloadType) : undefined;
|
1211
1266
|
return codec;
|
1212
1267
|
}
|
1268
|
+
setSifTrailer(trailer) {
|
1269
|
+
this.sifTrailer = trailer;
|
1270
|
+
}
|
1213
1271
|
}
|
1214
1272
|
/**
|
1215
1273
|
* Slice the NALUs present in the supplied buffer, assuming it is already byte-aligned
|
@@ -1291,6 +1349,9 @@ var NALUType;
|
|
1291
1349
|
* @internal
|
1292
1350
|
*/
|
1293
1351
|
function isFrameServerInjected(frameData, trailerBytes) {
|
1352
|
+
if (trailerBytes.byteLength === 0) {
|
1353
|
+
return false;
|
1354
|
+
}
|
1294
1355
|
const frameTrailer = new Uint8Array(frameData.slice(frameData.byteLength - trailerBytes.byteLength));
|
1295
1356
|
return trailerBytes.every((value, index) => value === frameTrailer[index]);
|
1296
1357
|
}
|
@@ -1330,6 +1391,7 @@ class ParticipantKeyHandler extends eventsExports.EventEmitter {
|
|
1330
1391
|
}
|
1331
1392
|
this.decryptionFailureCount += 1;
|
1332
1393
|
if (this.decryptionFailureCount > this.keyProviderOptions.failureTolerance) {
|
1394
|
+
workerLogger.warn("key for ".concat(this.participantId, " is being marked as invalid"));
|
1333
1395
|
this._hasValidKey = false;
|
1334
1396
|
}
|
1335
1397
|
}
|
@@ -1445,6 +1507,7 @@ let publisherKeys;
|
|
1445
1507
|
let isEncryptionEnabled = false;
|
1446
1508
|
let useSharedKey = false;
|
1447
1509
|
let sharedKey;
|
1510
|
+
let sifTrailer;
|
1448
1511
|
let keyProviderOptions = KEY_PROVIDER_DEFAULTS;
|
1449
1512
|
workerLogger.setDefaultLevel('info');
|
1450
1513
|
onmessage = ev => {
|
@@ -1505,6 +1568,10 @@ onmessage = ev => {
|
|
1505
1568
|
break;
|
1506
1569
|
case 'ratchetRequest':
|
1507
1570
|
handleRatchetRequest(data);
|
1571
|
+
break;
|
1572
|
+
case 'setSifTrailer':
|
1573
|
+
handleSifTrailer(data.trailer);
|
1574
|
+
break;
|
1508
1575
|
}
|
1509
1576
|
};
|
1510
1577
|
function handleRatchetRequest(data) {
|
@@ -1526,7 +1593,8 @@ function getTrackCryptor(participantId, trackId) {
|
|
1526
1593
|
cryptor = new FrameCryptor({
|
1527
1594
|
participantId,
|
1528
1595
|
keys: getParticipantKeyHandler(participantId),
|
1529
|
-
keyProviderOptions
|
1596
|
+
keyProviderOptions,
|
1597
|
+
sifTrailer
|
1530
1598
|
});
|
1531
1599
|
setupCryptorErrorEvents(cryptor);
|
1532
1600
|
participantCryptors.push(cryptor);
|
@@ -1608,6 +1676,12 @@ function emitRatchetedKeys(material, keyIndex) {
|
|
1608
1676
|
};
|
1609
1677
|
postMessage(msg);
|
1610
1678
|
}
|
1679
|
+
function handleSifTrailer(trailer) {
|
1680
|
+
sifTrailer = trailer;
|
1681
|
+
participantCryptors.forEach(c => {
|
1682
|
+
c.setSifTrailer(trailer);
|
1683
|
+
});
|
1684
|
+
}
|
1611
1685
|
// Operations using RTCRtpScriptTransform.
|
1612
1686
|
// @ts-ignore
|
1613
1687
|
if (self.RTCTransformEvent) {
|