diff --git a/lib/src/e2ee.worker/crypto.dart b/lib/src/e2ee.worker/crypto.dart index 5de9388..4770044 100644 --- a/lib/src/e2ee.worker/crypto.dart +++ b/lib/src/e2ee.worker/crypto.dart @@ -1,4 +1,3 @@ -/* import 'dart:async'; import 'dart:js_util' as jsutil; import 'dart:typed_data'; @@ -6,7 +5,6 @@ import 'dart:typed_data'; import 'package:js/js.dart'; import 'package:web/web.dart' as web; - @JS('Promise') class Promise { external factory Promise._(); @@ -94,5 +92,3 @@ Future impportKeyFromRawData(List secretKeyData, keyUsages, )); } - -*/ \ No newline at end of file diff --git a/lib/src/e2ee.worker/e2ee.cryptor.dart b/lib/src/e2ee.worker/e2ee.cryptor.dart index 0fca773..e731f2f 100644 --- a/lib/src/e2ee.worker/e2ee.cryptor.dart +++ b/lib/src/e2ee.worker/e2ee.cryptor.dart @@ -1,20 +1,18 @@ import 'dart:async'; - import 'dart:js'; import 'dart:js_interop'; +import 'dart:js_util' as jsutil; import 'dart:math'; import 'dart:typed_data'; import 'package:dart_webrtc/src/rtc_transform_stream.dart'; -import 'package:js/js_util.dart' as jsutil; import 'package:web/web.dart' as web; +import 'crypto.dart' as crypto; import 'e2ee.keyhandler.dart'; import 'e2ee.logger.dart'; import 'e2ee.sfi_guard.dart'; -final crypto = web.window.crypto.subtle; - const IV_LENGTH = 12; const kNaluTypeMask = 0x1f; @@ -223,7 +221,7 @@ class FrameCryptor { } void postMessage(Object message) { - worker.postMessage(jsutil.jsify(message)); + worker.postMessage(message.jsify()); } Future setupTransform({ @@ -339,13 +337,14 @@ class FrameCryptor { frameTrailer.setInt8(1, keyIndex); var cipherText = await jsutil.promiseToFuture(crypto.encrypt( - web.AesGcmParams( - //name: 'AES-GCM', - iv: iv.toJS, - additionalData: buffer.sublist(0, headerLength).toJS, + crypto.AesGcmParams( + name: 'AES-GCM', + iv: crypto.jsArrayBufferFrom(iv), + additionalData: + crypto.jsArrayBufferFrom(buffer.sublist(0, headerLength)), ), secretKey, - buffer.sublist(headerLength, buffer.length).toJS, + crypto.jsArrayBufferFrom(buffer.sublist(headerLength, buffer.length)), )); logger.finer( @@ -356,7 +355,7 @@ class FrameCryptor { finalBuffer.add(cipherText.asUint8List()); finalBuffer.add(iv); finalBuffer.add(frameTrailer.buffer.asUint8List()); - frame.data = finalBuffer.toBytes().buffer; + frame.data = crypto.jsArrayBufferFrom(finalBuffer.toBytes()); controller.enqueue(frame); @@ -425,7 +424,7 @@ class FrameCryptor { var finalBuffer = BytesBuilder(); finalBuffer.add(Uint8List.fromList( buffer.sublist(0, buffer.length - (magicBytes.length + 1)))); - frame.data = finalBuffer.toBytes().buffer; + frame.data = crypto.jsArrayBufferFrom(finalBuffer.toBytes()); controller.enqueue(frame); } else { logger.finer('SIF limit reached, dropping frame'); @@ -471,17 +470,19 @@ class FrameCryptor { while (!endDecLoop) { try { decrypted = await jsutil.promiseToFuture(crypto.decrypt( - web.AesGcmParams( - //name: 'AES-GCM', - iv: iv.toJS, - additionalData: buffer.sublist(0, headerLength).toJS, + crypto.AesGcmParams( + name: 'AES-GCM', + iv: crypto.jsArrayBufferFrom(iv), + additionalData: + crypto.jsArrayBufferFrom(buffer.sublist(0, headerLength)), ), currentkeySet.encryptionKey, - buffer.sublist(headerLength, buffer.length - ivLength - 2).toJS, + crypto.jsArrayBufferFrom( + buffer.sublist(headerLength, buffer.length - ivLength - 2)), )); if (currentkeySet != initialKeySet) { - logger.warning( + logger.fine( 'ratchetKey: decryption ok, reset state to kKeyRatcheted'); await keyHandler.setKeySetFromMaterial( currentkeySet, initialKeyIndex); @@ -515,10 +516,10 @@ class FrameCryptor { if (endDecLoop) { rethrow; } - var newKeyBuffer = await keyHandler.ratchet( - currentkeySet.material, keyOptions.ratchetSalt); + var newKeyBuffer = crypto.jsArrayBufferFrom(await keyHandler.ratchet( + currentkeySet.material, keyOptions.ratchetSalt)); var newMaterial = await keyHandler.ratchetMaterial( - currentkeySet.material, newKeyBuffer.buffer); + currentkeySet.material, newKeyBuffer); currentkeySet = await keyHandler.deriveKeys(newMaterial, keyOptions.ratchetSalt); ratchetCount++; @@ -531,7 +532,7 @@ class FrameCryptor { finalBuffer.add(Uint8List.fromList(buffer.sublist(0, headerLength))); finalBuffer.add(decrypted!.asUint8List()); - frame.data = finalBuffer.toBytes().buffer; + frame.data = crypto.jsArrayBufferFrom(finalBuffer.toBytes()); controller.enqueue(frame); if (lastError != CryptorError.kOk) { diff --git a/lib/src/e2ee.worker/e2ee.keyhandler.dart b/lib/src/e2ee.worker/e2ee.keyhandler.dart index 689c6fc..84f9c2a 100644 --- a/lib/src/e2ee.worker/e2ee.keyhandler.dart +++ b/lib/src/e2ee.worker/e2ee.keyhandler.dart @@ -1,15 +1,13 @@ import 'dart:async'; -import 'dart:js_interop'; import 'dart:js_util' as jsutil; import 'dart:typed_data'; import 'package:web/web.dart' as web; +import 'crypto.dart' as crypto; import 'e2ee.logger.dart'; import 'e2ee.utils.dart'; -final crypto = web.window.crypto.subtle; - class KeyOptions { KeyOptions({ required this.sharedKey, @@ -153,7 +151,8 @@ class ParticipantKeyHandler { return null; } var newKey = await ratchet(currentMaterial, keyOptions.ratchetSalt); - var newMaterial = await ratchetMaterial(currentMaterial, newKey.buffer); + var newMaterial = await ratchetMaterial( + currentMaterial, crypto.jsArrayBufferFrom(newKey)); var newKeySet = await deriveKeys(newMaterial, keyOptions.ratchetSalt); await setKeySetFromMaterial(newKeySet, keyIndex ?? currentKeyIndex); return newKey; @@ -161,15 +160,13 @@ class ParticipantKeyHandler { Future ratchetMaterial( web.CryptoKey currentMaterial, ByteBuffer newKeyBuffer) async { - var newMaterial = await crypto - .importKey( - 'raw', - newKeyBuffer.toJS, - (currentMaterial.algorithm as web.Algorithm).name.toJS, - false, - ['deriveBits'.toJS, 'deriveKey'.toJS].toJS, - ) - .toDart; + var newMaterial = await jsutil.promiseToFuture(crypto.importKey( + 'raw', + newKeyBuffer, + (currentMaterial.algorithm as crypto.Algorithm).name, + false, + ['deriveBits', 'deriveKey'], + )); return newMaterial; } @@ -178,11 +175,8 @@ class ParticipantKeyHandler { } Future setKey(Uint8List key, {int keyIndex = 0}) async { - var keyMaterial = await crypto - .importKey('raw', key.toJS, 'PBKDF2'.toJS, false, - ['deriveBits'.toJS, 'deriveKey'.toJS].toJS) - .toDart; - + var keyMaterial = await crypto.impportKeyFromRawData(key, + webCryptoAlgorithm: 'PBKDF2', keyUsages: ['deriveBits', 'deriveKey']); var keySet = await deriveKeys( keyMaterial, keyOptions.ratchetSalt, @@ -203,7 +197,7 @@ class ParticipantKeyHandler { /// See https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.1 Future deriveKeys(web.CryptoKey material, Uint8List salt) async { var algorithmOptions = - getAlgoOptions((material.algorithm as web.Algorithm).name, salt); + getAlgoOptions((material.algorithm as crypto.Algorithm).name, salt); // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey#HKDF // https://developer.mozilla.org/en-US/docs/Web/API/HkdfParams @@ -213,7 +207,7 @@ class ParticipantKeyHandler { material, jsutil.jsify({'name': 'AES-GCM', 'length': 128}), false, - ['encrypt'.toJS, 'decrypt'.toJS].toJS, + ['encrypt', 'decrypt'], )); return KeySet(material, encryptionKey); diff --git a/lib/src/e2ee.worker/e2ee.utils.dart b/lib/src/e2ee.worker/e2ee.utils.dart index b41a76d..2eb921d 100644 --- a/lib/src/e2ee.worker/e2ee.utils.dart +++ b/lib/src/e2ee.worker/e2ee.utils.dart @@ -1,12 +1,10 @@ import 'dart:js' as js; -import 'dart:js_interop'; -import 'dart:js_interop_unsafe'; import 'dart:typed_data'; import 'package:js/js_util.dart'; import 'package:web/web.dart' as web; -final crypto = web.window.crypto.subtle; +import 'crypto.dart' as crypto; bool isE2EESupported() { return isInsertableStreamSupported() || isScriptTransformSupported(); @@ -24,18 +22,13 @@ bool isInsertableStreamSupported() { Future importKey( Uint8List keyBytes, String algorithm, String usage) { // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey - - return crypto - .importKey( - 'raw', - keyBytes.toJS, - newObject()..setProperty('name'.toJS, algorithm.toJS), - false, - usage == 'derive' - ? ['deriveBits'.toJS, 'deriveKey'.toJS].toJS - : ['encrypt'.toJS, 'decrypt'.toJS].toJS, - ) - .toDart; + return promiseToFuture(crypto.importKey( + 'raw', + crypto.jsArrayBufferFrom(keyBytes), + js.JsObject.jsify({'name': algorithm}), + false, + usage == 'derive' ? ['deriveBits', 'deriveKey'] : ['encrypt', 'decrypt'], + )); } Future createKeyMaterialFromString( @@ -43,10 +36,10 @@ Future createKeyMaterialFromString( // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey return promiseToFuture(crypto.importKey( 'raw', - keyBytes.toJS, - newObject()..setProperty('name'.toJS, 'PBKDF2'.toJS), + crypto.jsArrayBufferFrom(keyBytes), + js.JsObject.jsify({'name': 'PBKDF2'}), false, - ['deriveBits'.toJS, 'deriveKey'.toJS].toJS, + ['deriveBits', 'deriveKey'], )); } @@ -55,15 +48,15 @@ dynamic getAlgoOptions(String algorithmName, Uint8List salt) { case 'HKDF': return { 'name': 'HKDF', - 'salt': salt.toJS, + 'salt': crypto.jsArrayBufferFrom(salt), 'hash': 'SHA-256', - 'info': Uint8List(128).toJS, + 'info': crypto.jsArrayBufferFrom(Uint8List(128)), }; case 'PBKDF2': { return { 'name': 'PBKDF2', - 'salt': salt.toJS, + 'salt': crypto.jsArrayBufferFrom(salt), 'hash': 'SHA-256', 'iterations': 100000, }; diff --git a/lib/src/e2ee.worker/e2ee.worker.dart b/lib/src/e2ee.worker/e2ee.worker.dart index 0361232..17d555a 100644 --- a/lib/src/e2ee.worker/e2ee.worker.dart +++ b/lib/src/e2ee.worker/e2ee.worker.dart @@ -5,7 +5,6 @@ import 'dart:typed_data'; import 'package:collection/collection.dart'; import 'package:dart_webrtc/src/rtc_transform_stream.dart'; -import 'package:js/js.dart'; import 'package:logging/logging.dart'; import 'package:web/web.dart' as web; @@ -14,43 +13,6 @@ import 'e2ee.keyhandler.dart'; import 'e2ee.logger.dart'; @JS() -abstract class TransformMessage { - external String get msgType; - external String get kind; -} - -@anonymous -@JS() -class EnableTransformMessage { - external factory EnableTransformMessage({ - ReadableStream readable, - WritableStream writable, - String msgType, - String kind, - String participantId, - String trackId, - String codec, - }); - external ReadableStream get readable; - external WritableStream get writable; - external String get msgType; // 'encode' or 'decode' - external String get participantId; - external String get trackId; - external String get kind; - external String get codec; -} - -@anonymous -@JS() -class RemoveTransformMessage { - external factory RemoveTransformMessage( - {String msgType, String participantId, String trackId}); - external String get msgType; // 'removeTransform' - external String get participantId; - external String get trackId; -} - -@JS('self') external web.DedicatedWorkerGlobalScope get self; extension PropsRTCTransformEventHandler on web.DedicatedWorkerGlobalScope { @@ -103,7 +65,7 @@ void main() async { if (js_util.getProperty(self, 'RTCTransformEvent') != null) { logger.info('setup RTCTransformEvent event handler'); - self.onrtctransform = (event) { + self.onrtctransform = (web.RTCTransformEvent event) { logger.info('Got onrtctransform event'); var transformer = (event as RTCTransformEvent).transformer; @@ -136,357 +98,352 @@ void main() async { }.toJS; } - self.addEventListener( - 'message', - (web.MessageEvent e) async { - var msg = js_util.dartify(e.data) as Map; - var msgType = msg['msgType']; - var msgId = msg['msgId'] as String?; - logger.info('Got message $msgType, msgId $msgId'); - switch (msgType) { - case 'keyProviderInit': - { - var options = msg['keyOptions']; - var keyProviderId = msg['keyProviderId'] as String; - var keyProviderOptions = KeyOptions( - sharedKey: options['sharedKey'], - ratchetSalt: Uint8List.fromList( - base64Decode(options['ratchetSalt'] as String)), - ratchetWindowSize: options['ratchetWindowSize'], - failureTolerance: options['failureTolerance'] ?? -1, - uncryptedMagicBytes: options['uncryptedMagicBytes'] != null - ? Uint8List.fromList(base64Decode( - options['uncryptedMagicBytes'] as String)) - : null); - logger.config( - 'Init with keyProviderOptions:\n ${keyProviderOptions.toString()}'); - - var keyProvider = - KeyProvider(self, keyProviderId, keyProviderOptions); - keyProviders[keyProviderId] = keyProvider; - - self.postMessage(js_util.jsify({ - 'type': 'init', - 'msgId': msgId, - 'msgType': 'response', - })); - break; - } - case 'keyProviderDispose': - { - var keyProviderId = msg['keyProviderId'] as String; - logger.config('Dispose keyProvider $keyProviderId'); - keyProviders.remove(keyProviderId); - self.postMessage(js_util.jsify({ - 'type': 'dispose', - 'msgId': msgId, - 'msgType': 'response', - })); - } + self.onmessage = (web.MessageEvent e) { + (e) async { + var msg = e.data; + var msgType = msg['msgType']; + var msgId = msg['msgId'] as String?; + logger.fine('Got message $msgType, msgId $msgId'); + switch (msgType) { + case 'keyProviderInit': + { + var options = msg['keyOptions']; + var keyProviderId = msg['keyProviderId'] as String; + var keyProviderOptions = KeyOptions( + sharedKey: options['sharedKey'], + ratchetSalt: Uint8List.fromList( + base64Decode(options['ratchetSalt'] as String)), + ratchetWindowSize: options['ratchetWindowSize'], + failureTolerance: options['failureTolerance'] ?? -1, + uncryptedMagicBytes: options['uncryptedMagicBytes'] != null + ? Uint8List.fromList( + base64Decode(options['uncryptedMagicBytes'] as String)) + : null); + logger.config( + 'Init with keyProviderOptions:\n ${keyProviderOptions.toString()}'); + + var keyProvider = + KeyProvider(self, keyProviderId, keyProviderOptions); + keyProviders[keyProviderId] = keyProvider; + + self.postMessage({ + 'type': 'init', + 'msgId': msgId, + 'msgType': 'response', + }.jsify()); break; - case 'enable': - { - var enabled = msg['enabled'] as bool; - var trackId = msg['trackId'] as String; - - var cryptors = participantCryptors - .where((c) => c.trackId == trackId) - .toList(); - for (var cryptor in cryptors) { - logger.config( - 'Set enable $enabled for trackId ${cryptor.trackId}'); - cryptor.setEnabled(enabled); - } - self.postMessage(js_util.jsify({ - 'type': 'cryptorEnabled', - 'enable': enabled, - 'msgId': msgId, - 'msgType': 'response', - })); + } + case 'keyProviderDispose': + { + var keyProviderId = msg['keyProviderId'] as String; + logger.config('Dispose keyProvider $keyProviderId'); + keyProviders.remove(keyProviderId); + self.postMessage({ + 'type': 'dispose', + 'msgId': msgId, + 'msgType': 'response', + }.jsify()); + } + break; + case 'enable': + { + var enabled = msg['enabled'] as bool; + var trackId = msg['trackId'] as String; + + var cryptors = + participantCryptors.where((c) => c.trackId == trackId).toList(); + for (var cryptor in cryptors) { + logger + .config('Set enable $enabled for trackId ${cryptor.trackId}'); + cryptor.setEnabled(enabled); } - break; - case 'decode': - case 'encode': - { - var kind = msg['kind']; - var exist = msg['exist'] as bool; - var participantId = msg['participantId'] as String; - var trackId = msg['trackId']; - var readable = msg['readableStream'] as ReadableStream; - var writable = msg['writableStream'] as WritableStream; - var keyProviderId = msg['keyProviderId'] as String; - - logger.config( - 'SetupTransform for kind $kind, trackId $trackId, participantId $participantId, ${readable.runtimeType} ${writable.runtimeType}}'); - - var keyProvider = keyProviders[keyProviderId]; - if (keyProvider == null) { - logger.warning('KeyProvider not found for $keyProviderId'); - self.postMessage(js_util.jsify({ - 'type': 'cryptorSetup', - 'participantId': participantId, - 'trackId': trackId, - 'exist': exist, - 'operation': msgType, - 'error': 'KeyProvider not found', - 'msgId': msgId, - 'msgType': 'response', - })); - return; - } - - var cryptor = - getTrackCryptor(participantId, trackId, keyProvider); - - await cryptor.setupTransform( - operation: msgType, - readable: readable, - writable: writable, - trackId: trackId, - kind: kind, - ); - - self.postMessage(js_util.jsify({ + self.postMessage({ + 'type': 'cryptorEnabled', + 'enable': enabled, + 'msgId': msgId, + 'msgType': 'response', + }.jsify()); + } + break; + case 'decode': + case 'encode': + { + var kind = msg['kind']; + var exist = msg['exist'] as bool; + var participantId = msg['participantId'] as String; + var trackId = msg['trackId']; + var readable = msg['readableStream'] as ReadableStream; + var writable = msg['writableStream'] as WritableStream; + var keyProviderId = msg['keyProviderId'] as String; + + logger.config( + 'SetupTransform for kind $kind, trackId $trackId, participantId $participantId, ${readable.runtimeType} ${writable.runtimeType}}'); + + var keyProvider = keyProviders[keyProviderId]; + if (keyProvider == null) { + logger.warning('KeyProvider not found for $keyProviderId'); + self.postMessage({ 'type': 'cryptorSetup', 'participantId': participantId, 'trackId': trackId, 'exist': exist, 'operation': msgType, + 'error': 'KeyProvider not found', 'msgId': msgId, 'msgType': 'response', - })); - cryptor.lastError = CryptorError.kNew; - } - break; - case 'removeTransform': - { - var trackId = msg['trackId'] as String; - logger.config('Removing trackId $trackId'); - unsetCryptorParticipant(trackId); - self.postMessage(js_util.jsify({ - 'type': 'cryptorRemoved', - 'trackId': trackId, - 'msgId': msgId, - 'msgType': 'response', - })); + }.jsify()); + return; } - break; - case 'setKey': - case 'setSharedKey': - { - var key = Uint8List.fromList(base64Decode(msg['key'] as String)); - var keyIndex = msg['keyIndex'] as int; - var keyProviderId = msg['keyProviderId'] as String; - var keyProvider = keyProviders[keyProviderId]; - if (keyProvider == null) { - logger.warning('KeyProvider not found for $keyProviderId'); - self.postMessage(js_util.jsify({ - 'type': 'setKey', - 'error': 'KeyProvider not found', - 'msgId': msgId, - 'msgType': 'response', - })); - return; - } - var keyProviderOptions = keyProvider.keyProviderOptions; - if (keyProviderOptions.sharedKey) { - logger.config('Set SharedKey keyIndex $keyIndex'); - keyProvider.setSharedKey(key, keyIndex: keyIndex); - } else { - var participantId = msg['participantId'] as String; - logger.config( - 'Set key for participant $participantId, keyIndex $keyIndex'); - await keyProvider - .getParticipantKeyHandler(participantId) - .setKey(key, keyIndex: keyIndex); - } - self.postMessage(js_util.jsify({ + var cryptor = getTrackCryptor(participantId, trackId, keyProvider); + + await cryptor.setupTransform( + operation: msgType, + readable: readable, + writable: writable, + trackId: trackId, + kind: kind, + ); + + self.postMessage({ + 'type': 'cryptorSetup', + 'participantId': participantId, + 'trackId': trackId, + 'exist': exist, + 'operation': msgType, + 'msgId': msgId, + 'msgType': 'response', + }.jsify()); + cryptor.lastError = CryptorError.kNew; + } + break; + case 'removeTransform': + { + var trackId = msg['trackId'] as String; + logger.config('Removing trackId $trackId'); + unsetCryptorParticipant(trackId); + self.postMessage({ + 'type': 'cryptorRemoved', + 'trackId': trackId, + 'msgId': msgId, + 'msgType': 'response', + }.jsify()); + } + break; + case 'setKey': + case 'setSharedKey': + { + var key = Uint8List.fromList(base64Decode(msg['key'] as String)); + var keyIndex = msg['keyIndex'] as int; + var keyProviderId = msg['keyProviderId'] as String; + var keyProvider = keyProviders[keyProviderId]; + if (keyProvider == null) { + logger.warning('KeyProvider not found for $keyProviderId'); + self.postMessage({ 'type': 'setKey', - 'participantId': msg['participantId'], - 'sharedKey': keyProviderOptions.sharedKey, - 'keyIndex': keyIndex, + 'error': 'KeyProvider not found', 'msgId': msgId, 'msgType': 'response', - })); + }.jsify()); + return; } - break; - case 'ratchetKey': - case 'ratchetSharedKey': - { - var keyIndex = msg['keyIndex']; + var keyProviderOptions = keyProvider.keyProviderOptions; + if (keyProviderOptions.sharedKey) { + logger.config('Set SharedKey keyIndex $keyIndex'); + keyProvider.setSharedKey(key, keyIndex: keyIndex); + } else { var participantId = msg['participantId'] as String; - var keyProviderId = msg['keyProviderId'] as String; - var keyProvider = keyProviders[keyProviderId]; - if (keyProvider == null) { - logger.warning('KeyProvider not found for $keyProviderId'); - self.postMessage(js_util.jsify({ - 'type': 'setKey', - 'error': 'KeyProvider not found', - 'msgId': msgId, - 'msgType': 'response', - })); - return; - } - var keyProviderOptions = keyProvider.keyProviderOptions; - Uint8List? newKey; - if (keyProviderOptions.sharedKey) { - logger.config('RatchetKey for SharedKey, keyIndex $keyIndex'); - newKey = await keyProvider - .getSharedKeyHandler() - .ratchetKey(keyIndex); - } else { - logger.config( - 'RatchetKey for participant $participantId, keyIndex $keyIndex'); - newKey = await keyProvider - .getParticipantKeyHandler(participantId) - .ratchetKey(keyIndex); - } + logger.config( + 'Set key for participant $participantId, keyIndex $keyIndex'); + await keyProvider + .getParticipantKeyHandler(participantId) + .setKey(key, keyIndex: keyIndex); + } - self.postMessage(js_util.jsify({ - 'type': 'ratchetKey', - 'sharedKey': keyProviderOptions.sharedKey, - 'participantId': participantId, - 'newKey': newKey != null ? base64Encode(newKey) : '', - 'keyIndex': keyIndex, + self.postMessage({ + 'type': 'setKey', + 'participantId': msg['participantId'], + 'sharedKey': keyProviderOptions.sharedKey, + 'keyIndex': keyIndex, + 'msgId': msgId, + 'msgType': 'response', + }.jsify()); + } + break; + case 'ratchetKey': + case 'ratchetSharedKey': + { + var keyIndex = msg['keyIndex']; + var participantId = msg['participantId'] as String; + var keyProviderId = msg['keyProviderId'] as String; + var keyProvider = keyProviders[keyProviderId]; + if (keyProvider == null) { + logger.warning('KeyProvider not found for $keyProviderId'); + self.postMessage({ + 'type': 'setKey', + 'error': 'KeyProvider not found', 'msgId': msgId, 'msgType': 'response', - })); + }.jsify()); + return; + } + var keyProviderOptions = keyProvider.keyProviderOptions; + Uint8List? newKey; + if (keyProviderOptions.sharedKey) { + logger.config('RatchetKey for SharedKey, keyIndex $keyIndex'); + newKey = + await keyProvider.getSharedKeyHandler().ratchetKey(keyIndex); + } else { + logger.config( + 'RatchetKey for participant $participantId, keyIndex $keyIndex'); + newKey = await keyProvider + .getParticipantKeyHandler(participantId) + .ratchetKey(keyIndex); } - break; - case 'setKeyIndex': - { - var keyIndex = msg['index']; - var trackId = msg['trackId'] as String; - logger.config('Setup key index for track $trackId'); - var cryptors = participantCryptors - .where((c) => c.trackId == trackId) - .toList(); - for (var c in cryptors) { - logger.config('Set keyIndex for trackId ${c.trackId}'); - c.setKeyIndex(keyIndex); - } - self.postMessage(js_util.jsify({ - 'type': 'setKeyIndex', - 'keyIndex': keyIndex, + self.postMessage({ + 'type': 'ratchetKey', + 'sharedKey': keyProviderOptions.sharedKey, + 'participantId': participantId, + 'newKey': newKey != null ? base64Encode(newKey) : '', + 'keyIndex': keyIndex, + 'msgId': msgId, + 'msgType': 'response', + }.jsify()); + } + break; + case 'setKeyIndex': + { + var keyIndex = msg['index']; + var trackId = msg['trackId'] as String; + logger.config('Setup key index for track $trackId'); + var cryptors = + participantCryptors.where((c) => c.trackId == trackId).toList(); + for (var c in cryptors) { + logger.config('Set keyIndex for trackId ${c.trackId}'); + c.setKeyIndex(keyIndex); + } + + self.postMessage({ + 'type': 'setKeyIndex', + 'keyIndex': keyIndex, + 'msgId': msgId, + 'msgType': 'response', + }.jsify()); + } + break; + case 'exportKey': + case 'exportSharedKey': + { + var keyIndex = msg['keyIndex'] as int; + var participantId = msg['participantId'] as String; + var keyProviderId = msg['keyProviderId'] as String; + var keyProvider = keyProviders[keyProviderId]; + if (keyProvider == null) { + logger.warning('KeyProvider not found for $keyProviderId'); + self.postMessage({ + 'type': 'setKey', + 'error': 'KeyProvider not found', 'msgId': msgId, 'msgType': 'response', - })); + }.jsify()); + return; } - break; - case 'exportKey': - case 'exportSharedKey': - { - var keyIndex = msg['keyIndex'] as int; - var participantId = msg['participantId'] as String; - var keyProviderId = msg['keyProviderId'] as String; - var keyProvider = keyProviders[keyProviderId]; - if (keyProvider == null) { - logger.warning('KeyProvider not found for $keyProviderId'); - self.postMessage(js_util.jsify({ - 'type': 'setKey', - 'error': 'KeyProvider not found', - 'msgId': msgId, - 'msgType': 'response', - })); - return; - } - var keyProviderOptions = keyProvider.keyProviderOptions; - Uint8List? key; - if (keyProviderOptions.sharedKey) { - logger.config('Export SharedKey keyIndex $keyIndex'); - key = - await keyProvider.getSharedKeyHandler().exportKey(keyIndex); - } else { - logger.config( - 'Export key for participant $participantId, keyIndex $keyIndex'); - key = await keyProvider - .getParticipantKeyHandler(participantId) - .exportKey(keyIndex); - } - self.postMessage(js_util.jsify({ - 'type': 'exportKey', - 'participantId': participantId, - 'keyIndex': keyIndex, - 'exportedKey': key != null ? base64Encode(key) : '', + var keyProviderOptions = keyProvider.keyProviderOptions; + Uint8List? key; + if (keyProviderOptions.sharedKey) { + logger.config('Export SharedKey keyIndex $keyIndex'); + key = await keyProvider.getSharedKeyHandler().exportKey(keyIndex); + } else { + logger.config( + 'Export key for participant $participantId, keyIndex $keyIndex'); + key = await keyProvider + .getParticipantKeyHandler(participantId) + .exportKey(keyIndex); + } + self.postMessage({ + 'type': 'exportKey', + 'participantId': participantId, + 'keyIndex': keyIndex, + 'exportedKey': key != null ? base64Encode(key) : '', + 'msgId': msgId, + 'msgType': 'response', + }.jsify()); + } + break; + case 'setSifTrailer': + { + var sifTrailer = + Uint8List.fromList(base64Decode(msg['sifTrailer'] as String)); + var keyProviderId = msg['keyProviderId'] as String; + var keyProvider = keyProviders[keyProviderId]; + if (keyProvider == null) { + logger.warning('KeyProvider not found for $keyProviderId'); + self.postMessage({ + 'type': 'setKey', + 'error': 'KeyProvider not found', 'msgId': msgId, 'msgType': 'response', - })); + }.jsify()); + return; + } + keyProvider.setSifTrailer(sifTrailer); + logger.config('SetSifTrailer = $sifTrailer'); + for (var c in participantCryptors) { + c.setSifTrailer(sifTrailer); } - break; - case 'setSifTrailer': - { - var sifTrailer = - Uint8List.fromList(base64Decode(msg['sifTrailer'] as String)); - var keyProviderId = msg['keyProviderId'] as String; - var keyProvider = keyProviders[keyProviderId]; - if (keyProvider == null) { - logger.warning('KeyProvider not found for $keyProviderId'); - self.postMessage(js_util.jsify({ - 'type': 'setKey', - 'error': 'KeyProvider not found', - 'msgId': msgId, - 'msgType': 'response', - })); - return; - } - keyProvider.setSifTrailer(sifTrailer); - logger.config('SetSifTrailer = $sifTrailer'); - for (var c in participantCryptors) { - c.setSifTrailer(sifTrailer); - } - self.postMessage(js_util.jsify({ - 'type': 'setSifTrailer', + self.postMessage({ + 'type': 'setSifTrailer', + 'msgId': msgId, + 'msgType': 'response', + }.jsify()); + } + break; + case 'updateCodec': + { + var codec = msg['codec'] as String; + var trackId = msg['trackId'] as String; + logger.config('Update codec for trackId $trackId, codec $codec'); + var cryptor = participantCryptors + .firstWhereOrNull((c) => c.trackId == trackId); + cryptor?.updateCodec(codec); + + self.postMessage({ + 'type': 'updateCodec', + 'msgId': msgId, + 'msgType': 'response', + }.jsify()); + } + break; + case 'dispose': + { + var trackId = msg['trackId'] as String; + logger.config('Dispose for trackId $trackId'); + var cryptor = participantCryptors + .firstWhereOrNull((c) => c.trackId == trackId); + if (cryptor != null) { + cryptor.lastError = CryptorError.kDisposed; + self.postMessage({ + 'type': 'cryptorDispose', + 'participantId': cryptor.participantIdentity, + 'trackId': trackId, 'msgId': msgId, 'msgType': 'response', - })); - } - break; - case 'updateCodec': - { - var codec = msg['codec'] as String; - var trackId = msg['trackId'] as String; - logger.config('Update codec for trackId $trackId, codec $codec'); - var cryptor = participantCryptors - .firstWhereOrNull((c) => c.trackId == trackId); - cryptor?.updateCodec(codec); - - self.postMessage(js_util.jsify({ - 'type': 'updateCodec', + }.jsify()); + } else { + self.postMessage({ + 'type': 'cryptorDispose', + 'error': 'cryptor not found', 'msgId': msgId, 'msgType': 'response', - })); + }.jsify()); } - break; - case 'dispose': - { - var trackId = msg['trackId'] as String; - logger.config('Dispose for trackId $trackId'); - var cryptor = participantCryptors - .firstWhereOrNull((c) => c.trackId == trackId); - if (cryptor != null) { - cryptor.lastError = CryptorError.kDisposed; - self.postMessage(js_util.jsify({ - 'type': 'cryptorDispose', - 'participantId': cryptor.participantIdentity, - 'trackId': trackId, - 'msgId': msgId, - 'msgType': 'response', - })); - } else { - self.postMessage(js_util.jsify({ - 'type': 'cryptorDispose', - 'error': 'cryptor not found', - 'msgId': msgId, - 'msgType': 'response', - })); - } - } - break; - default: - logger.warning('Unknown message kind $msg'); - } - }.toJS); + } + break; + default: + logger.warning('Unknown message kind $msg'); + } + }(e); + }.toJS; } diff --git a/lib/src/frame_cryptor_impl.dart b/lib/src/frame_cryptor_impl.dart index 3ab60ff..9e16bf4 100644 --- a/lib/src/frame_cryptor_impl.dart +++ b/lib/src/frame_cryptor_impl.dart @@ -372,13 +372,13 @@ class FrameCryptorFactoryImpl implements FrameCryptorFactory { 'message', (web.MessageEvent msg) { final data = dartify(msg.data) as Map; - print('master got ${msg.data}'); + //print('master got $data'); var type = data['type']; var msgId = data['msgId']; var msgType = data['msgType']; if (msgType == 'response') { - events.emit(WorkerResponse(msgId, msg.data)); + events.emit(WorkerResponse(msgId, data)); } else if (msgType == 'event') { if (type == 'cryptorState') { var trackId = data['trackId'];