Skip to content

Commit 78443f2

Browse files
authored
Merge pull request #59 from flutter-webrtc/fix/e2ee-for-firefox
fix E2EE for FireFox.
2 parents ceb2849 + 40b0be1 commit 78443f2

File tree

2 files changed

+67
-68
lines changed

2 files changed

+67
-68
lines changed

lib/src/e2ee.worker/e2ee.cryptor.dart

+65-66
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,11 @@ enum CryptorError {
120120

121121
class FrameInfo {
122122
FrameInfo({
123-
required this.mimeType,
124123
required this.ssrc,
125124
required this.timestamp,
126125
required this.buffer,
127126
required this.frameType,
128127
});
129-
String? mimeType;
130128
String frameType;
131129
int ssrc;
132130
int timestamp;
@@ -144,7 +142,6 @@ class FrameCryptor {
144142
String? participantIdentity;
145143
String? trackId;
146144
String? codec;
147-
String? mineType;
148145
ParticipantKeyHandler keyHandler;
149146
KeyOptions get keyOptions => keyHandler.keyOptions;
150147
late String kind;
@@ -282,8 +279,7 @@ class FrameCryptor {
282279
data = obj.data.toDart.asUint8List();
283280
if (obj.hasProperty('type'.toJS).toDart) {
284281
frameType = obj.type;
285-
logger.finer(
286-
'frameType: $frameType, mineTye ${obj.getMetadata().mimeType}');
282+
logger.finer('frameType: $frameType');
287283
}
288284
}
289285

@@ -318,33 +314,40 @@ class FrameCryptor {
318314
}
319315

320316
FrameInfo readFrameInfo(JSObject frameObj) {
321-
Uint8List buffer;
317+
var buffer = Uint8List(0);
322318
var synchronizationSource = 0;
323319
var timestamp = 0;
324320
var frameType = '';
325321
if (frameObj is web.RTCEncodedVideoFrame) {
326322
buffer = frameObj.data.toDart.asUint8List();
327323
if (frameObj.hasProperty('type'.toJS).toDart) {
328324
frameType = frameObj.type;
329-
logger.finer(
330-
'frameType: $frameType, mineTye ${frameObj.getMetadata().mimeType}');
325+
logger.finer('frameType: $frameType');
331326
}
332327
synchronizationSource = frameObj.getMetadata().synchronizationSource;
333-
timestamp = frameObj.getMetadata().rtpTimestamp.toInt();
334-
mineType ??= frameObj.getMetadata().mimeType;
328+
if (frameObj.getMetadata().hasProperty('rtpTimestamp'.toJS).toDart) {
329+
timestamp = frameObj.getMetadata().rtpTimestamp.toInt();
330+
} else if (frameObj.hasProperty('timestamp'.toJS).toDart) {
331+
timestamp =
332+
(frameObj.getProperty('timestamp'.toJS) as JSNumber).toDartInt;
333+
}
335334
} else if (frameObj is web.RTCEncodedAudioFrame) {
336335
buffer = frameObj.data.toDart.asUint8List();
337336
synchronizationSource = frameObj.getMetadata().synchronizationSource;
338-
timestamp = frameObj.getMetadata().rtpTimestamp.toInt();
339-
mineType ??= frameObj.getMetadata().mimeType;
337+
338+
if (frameObj.getMetadata().hasProperty('rtpTimestamp'.toJS).toDart) {
339+
timestamp = frameObj.getMetadata().rtpTimestamp.toInt();
340+
} else if (frameObj.hasProperty('timestamp'.toJS).toDart) {
341+
timestamp =
342+
(frameObj.getProperty('timestamp'.toJS) as JSNumber).toDartInt;
343+
}
340344
frameType = 'audio';
341345
} else {
342346
throw Exception(
343347
'encodeFunction: frame is not a RTCEncodedVideoFrame or RTCEncodedAudioFrame');
344348
}
345349

346350
return FrameInfo(
347-
mimeType: mineType,
348351
ssrc: synchronizationSource,
349352
timestamp: timestamp,
350353
buffer: buffer,
@@ -366,43 +369,44 @@ class FrameCryptor {
366369
JSObject frameObj,
367370
web.TransformStreamDefaultController controller,
368371
) async {
369-
var srcFrame = readFrameInfo(frameObj);
370-
371-
mineType ??= srcFrame.mimeType;
372-
373-
logger.finer(
374-
'encodeFunction: frame ${srcFrame.buffer.length}, synchronizationSource ${srcFrame.ssrc} mineType $mineType frameType ${srcFrame.frameType}');
375-
376-
if (!enabled ||
377-
// skip for encryption for empty dtx frames
378-
srcFrame.buffer.isEmpty) {
379-
if (keyOptions.discardFrameWhenCryptorNotReady) {
372+
try {
373+
if (!enabled ||
374+
// skip for encryption for empty dtx frames
375+
((frameObj is web.RTCEncodedVideoFrame &&
376+
frameObj.data.toDart.lengthInBytes == 0) ||
377+
(frameObj is web.RTCEncodedAudioFrame &&
378+
frameObj.data.toDart.lengthInBytes == 0))) {
379+
if (keyOptions.discardFrameWhenCryptorNotReady) {
380+
return;
381+
}
382+
controller.enqueue(frameObj);
380383
return;
381384
}
382-
controller.enqueue(frameObj);
383-
return;
384-
}
385385

386-
var secretKey = keyHandler.getKeySet(currentKeyIndex)?.encryptionKey;
387-
var keyIndex = currentKeyIndex;
386+
var srcFrame = readFrameInfo(frameObj);
388387

389-
if (secretKey == null) {
390-
if (lastError != CryptorError.kMissingKey) {
391-
lastError = CryptorError.kMissingKey;
392-
postMessage({
393-
'type': 'cryptorState',
394-
'msgType': 'event',
395-
'participantId': participantIdentity,
396-
'trackId': trackId,
397-
'kind': kind,
398-
'state': 'missingKey',
399-
'error': 'Missing key for track $trackId',
400-
});
388+
logger.fine(
389+
'encodeFunction: buffer ${srcFrame.buffer.length}, synchronizationSource ${srcFrame.ssrc} frameType ${srcFrame.frameType}');
390+
391+
var secretKey = keyHandler.getKeySet(currentKeyIndex)?.encryptionKey;
392+
var keyIndex = currentKeyIndex;
393+
394+
if (secretKey == null) {
395+
if (lastError != CryptorError.kMissingKey) {
396+
lastError = CryptorError.kMissingKey;
397+
postMessage({
398+
'type': 'cryptorState',
399+
'msgType': 'event',
400+
'participantId': participantIdentity,
401+
'trackId': trackId,
402+
'kind': kind,
403+
'state': 'missingKey',
404+
'error': 'Missing key for track $trackId',
405+
});
406+
}
407+
return;
401408
}
402-
return;
403-
}
404409

405-
try {
406410
var headerLength =
407411
kind == 'video' ? getUnencryptedBytes(frameObj, codec) : 1;
408412

@@ -426,7 +430,7 @@ class FrameCryptor {
426430
.toDart as JSArrayBuffer;
427431

428432
logger.finer(
429-
'encodeFunction, buffer: ${srcFrame.buffer.length}, cipherText: ${cipherText.toDart.asUint8List().length}');
433+
'encodeFunction: encrypted buffer: ${srcFrame.buffer.length}, cipherText: ${cipherText.toDart.asUint8List().length}');
430434
var finalBuffer = BytesBuilder();
431435

432436
finalBuffer
@@ -436,8 +440,6 @@ class FrameCryptor {
436440
finalBuffer.add(frameTrailer.buffer.asUint8List());
437441

438442
enqueueFrame(frameObj, controller, finalBuffer);
439-
logger.finer(
440-
'encodeFunction: ssrc ${srcFrame.ssrc} buffer length ${srcFrame.buffer.length}, encrypted: ${finalBuffer.length}, headerLength $headerLength cipherText ${cipherText.toDart.asUint8List().length} iv ${iv.length} frameTrailer ${frameTrailer.buffer.asUint8List().length}');
441443

442444
if (lastError != CryptorError.kOk) {
443445
lastError = CryptorError.kOk;
@@ -453,7 +455,7 @@ class FrameCryptor {
453455
}
454456

455457
logger.finer(
456-
'encrypto kind $kind,codec $codec headerLength: $headerLength, timestamp: ${srcFrame.timestamp}, ssrc: ${srcFrame.ssrc}, data length: ${srcFrame.buffer.length}, encrypted length: ${finalBuffer.toBytes().length}, iv $iv');
458+
'encodeFunction[CryptorError.kOk]: frame enqueued kind $kind,codec $codec headerLength: $headerLength, timestamp: ${srcFrame.timestamp}, ssrc: ${srcFrame.ssrc}, data length: ${srcFrame.buffer.length}, encrypted length: ${finalBuffer.toBytes().length}, iv $iv');
457459
} catch (e) {
458460
logger.warning('encodeFunction encrypt: e ${e.toString()}');
459461
if (lastError != CryptorError.kEncryptError) {
@@ -476,11 +478,9 @@ class FrameCryptor {
476478
web.TransformStreamDefaultController controller,
477479
) async {
478480
var srcFrame = readFrameInfo(frameObj);
479-
mineType ??= srcFrame.mimeType;
480481
var ratchetCount = 0;
481482

482-
logger.finer(
483-
'decodeFunction: frame ${srcFrame.buffer.length} mineType $mineType');
483+
logger.fine('decodeFunction: frame lenght ${srcFrame.buffer.length}');
484484

485485
ByteBuffer? decrypted;
486486
KeySet? initialKeySet;
@@ -510,17 +510,18 @@ class FrameCryptor {
510510
if (sifGuard.isSifAllowed()) {
511511
var frameType =
512512
srcFrame.buffer.sublist(srcFrame.buffer.length - 1)[0];
513-
logger.finer('skip uncrypted frame, type $frameType');
513+
logger
514+
.finer('ecodeFunction: skip uncrypted frame, type $frameType');
514515
var finalBuffer = BytesBuilder();
515516
finalBuffer.add(Uint8List.fromList(srcFrame.buffer
516517
.sublist(0, srcFrame.buffer.length - (magicBytes.length + 1))));
517518
enqueueFrame(frameObj, controller, finalBuffer);
518-
logger.fine('enqueing silent frame');
519+
logger.fine('ecodeFunction: enqueing silent frame');
519520
controller.enqueue(frameObj);
520521
} else {
521-
logger.finer('SIF limit reached, dropping frame');
522+
logger.finer('ecodeFunction: SIF limit reached, dropping frame');
522523
}
523-
logger.finer('enqueing silent frame');
524+
logger.finer('ecodeFunction: enqueing silent frame');
524525
controller.enqueue(frameObj);
525526
return;
526527
} else {
@@ -545,9 +546,6 @@ class FrameCryptor {
545546
logger.finer(
546547
'decodeFunction: start decrypting frame headerLength $headerLength ${srcFrame.buffer.length} frameTrailer $frameTrailer, ivLength $ivLength, keyIndex $keyIndex, iv $iv');
547548

548-
logger.finer(
549-
'decodeFunction: ssrc ${srcFrame.ssrc} buffer length ${srcFrame.buffer.length}, encrypted: ${srcFrame.buffer.length}, headerLength $headerLength cipherText ${srcFrame.buffer.sublist(headerLength, srcFrame.buffer.length - ivLength - 2).length} iv ${iv.length} frameTrailer ${frameTrailer.buffer.asUint8List().length}');
550-
551549
/// missingKey flow:
552550
/// tries to decrypt once, fails, tries to ratchet once and decrypt again,
553551
/// fails (does not save ratcheted key), bumps _decryptionFailureCount,
@@ -589,15 +587,16 @@ class FrameCryptor {
589587
.toDart) as JSArrayBuffer)
590588
.toDart;
591589
logger.finer(
592-
'decodeFunction: decryptFrameInternal: decrypted: ${decrypted!.asUint8List().length}');
590+
'decodeFunction::decryptFrameInternal: decrypted: ${decrypted!.asUint8List().length}');
593591

594592
if (decrypted == null) {
595593
throw Exception('[decryptFrameInternal] could not decrypt');
596594
}
597595
logger.finer(
598-
'decryptFrameInternal: decrypted: ${decrypted!.asUint8List().length}');
596+
'decodeFunction::decryptFrameInternal: decrypted: ${decrypted!.asUint8List().length}');
599597
if (currentkeySet != initialKeySet) {
600-
logger.fine('ratchetKey: decryption ok, newState: kKeyRatcheted');
598+
logger.fine(
599+
'decodeFunction::decryptFrameInternal: ratchetKey: decryption ok, newState: kKeyRatcheted');
601600
await keyHandler.setKeySetFromMaterial(
602601
currentkeySet, initialKeyIndex);
603602
}
@@ -606,9 +605,9 @@ class FrameCryptor {
606605
lastError != CryptorError.kKeyRatcheted &&
607606
ratchetCount > 0) {
608607
logger.finer(
609-
'KeyRatcheted: ssrc ${srcFrame.ssrc} timestamp ${srcFrame.timestamp} ratchetCount $ratchetCount participantId: $participantIdentity');
608+
'decodeFunction::decryptFrameInternal: KeyRatcheted: ssrc ${srcFrame.ssrc} timestamp ${srcFrame.timestamp} ratchetCount $ratchetCount participantId: $participantIdentity');
610609
logger.finer(
611-
'ratchetKey: lastError != CryptorError.kKeyRatcheted, reset state to kKeyRatcheted');
610+
'decodeFunction::decryptFrameInternal: ratchetKey: lastError != CryptorError.kKeyRatcheted, reset state to kKeyRatcheted');
612611

613612
lastError = CryptorError.kKeyRatcheted;
614613
postMessage({
@@ -659,7 +658,7 @@ class FrameCryptor {
659658
keyHandler.decryptionSuccess();
660659

661660
logger.finer(
662-
'decodeFunction: buffer length ${srcFrame.buffer.length}, decrypted: ${decrypted!.asUint8List().length}');
661+
'decodeFunction: decryption success, buffer length ${srcFrame.buffer.length}, decrypted: ${decrypted!.asUint8List().length}');
663662

664663
var finalBuffer = BytesBuilder();
665664

@@ -681,8 +680,8 @@ class FrameCryptor {
681680
});
682681
}
683682

684-
logger.finer(
685-
'decrypto kind $kind, codec $mineType headerLength: $headerLength, timestamp: ${srcFrame.timestamp}, ssrc: ${srcFrame.ssrc}, data length: ${srcFrame.buffer.length}, decrypted length: ${finalBuffer.toBytes().length}, keyindex $keyIndex iv $iv');
683+
logger.fine(
684+
'decodeFunction[CryptorError.kOk]: decryption success kind $kind, headerLength: $headerLength, timestamp: ${srcFrame.timestamp}, ssrc: ${srcFrame.ssrc}, data length: ${srcFrame.buffer.length}, decrypted length: ${finalBuffer.toBytes().length}, keyindex $keyIndex iv $iv');
686685
} catch (e) {
687686
if (lastError != CryptorError.kDecryptError) {
688687
lastError = CryptorError.kDecryptError;

lib/src/e2ee.worker/e2ee.worker.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ void main() async {
6868
var kind = options.getProperty('kind'.toJS) as JSString;
6969
var participantId = options.getProperty('participantId'.toJS) as JSString;
7070
var trackId = options.getProperty('trackId'.toJS) as JSString;
71-
var codec = options.getProperty('codec'.toJS) as JSString;
71+
var codec = options.getProperty('codec'.toJS) as JSString?;
7272
var msgType = options.getProperty('msgType'.toJS) as JSString;
7373
var keyProviderId = options.getProperty('keyProviderId'.toJS) as JSString;
7474

@@ -88,7 +88,7 @@ void main() async {
8888
writable: transformer.writable,
8989
trackId: trackId.toDart,
9090
kind: kind.toDart,
91-
codec: codec.toDart);
91+
codec: codec?.toDart);
9292
}.toJS;
9393
}
9494

0 commit comments

Comments
 (0)