refactor: Remove olm dependency

This commit is contained in:
Christian Kußowski 2025-05-30 14:33:57 +02:00
parent 5fdcbf8006
commit 6df0fb5d06
No known key found for this signature in database
GPG Key ID: E067ECD60F1A0652
33 changed files with 127 additions and 247 deletions

View File

@ -28,7 +28,7 @@ jobs:
export HOMESERVER_IMPLEMENTATION=${{matrix.homeserver}} export HOMESERVER_IMPLEMENTATION=${{matrix.homeserver}}
export HOMESERVER="localhost:80" export HOMESERVER="localhost:80"
scripts/integration-server-${{matrix.homeserver}}.sh 2>&1 > /dev/null & scripts/integration-server-${{matrix.homeserver}}.sh 2>&1 > /dev/null &
sudo apt-get update && sudo apt-get install --no-install-recommends --no-install-suggests -y libolm3 libssl3 sqlite3 libsqlite3-dev sudo apt-get update && sudo apt-get install --no-install-recommends --no-install-suggests -y libssl3 sqlite3 libsqlite3-dev
source scripts/integration-create-environment-variables.sh source scripts/integration-create-environment-variables.sh
scripts/integration-prepare-homeserver.sh scripts/integration-prepare-homeserver.sh
scripts/prepare.sh scripts/prepare.sh
@ -75,7 +75,7 @@ jobs:
gitlab_ssh: ${{ secrets.CI_SSH_PRIVATE_KEY}} gitlab_ssh: ${{ secrets.CI_SSH_PRIVATE_KEY}}
- name: Run tests - name: Run tests
run: | run: |
sudo apt-get update && sudo apt-get install --no-install-recommends --no-install-suggests -y lcov libsqlite3-0 libsqlite3-dev libolm3 libssl3 sudo apt-get update && sudo apt-get install --no-install-recommends --no-install-suggests -y lcov libsqlite3-0 libsqlite3-dev libssl3
./scripts/prepare_vodozemac.sh ./scripts/prepare_vodozemac.sh
./scripts/test.sh ./scripts/test.sh
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4

View File

@ -4,15 +4,17 @@ Matrix (matrix.org) SDK written in dart.
## Native libraries ## Native libraries
For E2EE, libolm must be provided. For E2EE, vodozemac must be provided.
Additionally, OpenSSL (libcrypto) must be provided on native platforms for E2EE. Additionally, OpenSSL (libcrypto) must be provided on native platforms for E2EE.
For flutter apps you can easily import it with the [flutter_olm](https://pub.dev/packages/flutter_olm) and the [flutter_openssl_crypto](https://pub.dev/packages/flutter_openssl_crypto) packages. For flutter apps you can easily import it with the [flutter_vodozemac](https://pub.dev/packages/flutter_vodozemac) and the [flutter_openssl_crypto](https://pub.dev/packages/flutter_openssl_crypto) packages.
```sh ```sh
flutter pub add matrix flutter pub add matrix
flutter pub add flutter_olm
# Optional: For end to end encryption:
flutter pub add flutter_vodozemac
flutter pub add flutter_openssl_crypto flutter pub add flutter_openssl_crypto
``` ```

View File

@ -0,0 +1,29 @@
To enable end to end encryption you need to setup [Vodozemac](https://pub.dev/packages/vodozemac). For this you need Rust installed locally: [rust-lang.org/tools/install](https://www.rust-lang.org/tools/install)
For Flutter you can use [flutter_vodozemac](https://pub.dev/packages/flutter_vodozemac).
```sh
flutter pub add flutter_vodozemac
```
You also need [flutter_openssl_crypto](https://pub.dev/packages/flutter_openssl_crypto).
```sh
flutter pub add flutter_openssl_crypto
```
Now before you create your `Client`, init vodozemac:
```dart
import 'package:flutter_vodozemac/flutter_vodozemac' as vod;
// ...
await vod.init();
final client = Client(/*...*/);
```
This should work on Android, iOS, macOS, Linux and Windows.
For web you need to compile vodozemac to wasm. [Please refer to the Vodozemac bindings documentation](https://pub.dev/packages/vodozemac#build-for-web).

View File

@ -6,10 +6,12 @@ In your `pubspec.yaml` file add the following dependencies:
```yaml ```yaml
matrix: <latest-version> matrix: <latest-version>
# If you plan to use the SDK in a Flutter application on IO: # (Optional) If you plan to use the SDK in a Flutter application on IO
# you need sqflite or sqflite_ffi:
sqflite: <latest-version> sqflite: <latest-version>
# For end to end encryption: # (Optional) For end to end encryption, please head on the
flutter_olm: <latest-version> # encryption guide and add these dependencies:
flutter_vodozemac: <latest-version>
flutter_openssl_crypto: <latest-version> flutter_openssl_crypto: <latest-version>
``` ```

View File

@ -1,25 +0,0 @@
To use end to end encryption in web you have to download the olm javascript/wasm library:
```sh
#!/bin/sh -ve
rm -r assets/js/package
OLM_VERSION=$(cat pubspec.yaml | yq .dependencies.flutter_olm)
DOWNLOAD_PATH="https://github.com/famedly/olm/releases/download/v$OLM_VERSION/olm.zip"
curl -L $DOWNLOAD_PATH > olm.zip
unzip olm.zip
rm olm.zip
```
...and import it in your `index.html`:
```html
<html>
<head>
...
<script src="path/to/assets/olm.js"></script>
</head>
...
</html>
```

View File

@ -19,8 +19,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/encryption/cross_signing.dart'; import 'package:matrix/encryption/cross_signing.dart';
import 'package:matrix/encryption/key_manager.dart'; import 'package:matrix/encryption/key_manager.dart';
import 'package:matrix/encryption/key_verification_manager.dart'; import 'package:matrix/encryption/key_verification_manager.dart';
@ -166,7 +164,7 @@ class Encryption {
return await olmManager.decryptToDeviceEvent(event); return await olmManager.decryptToDeviceEvent(event);
} catch (e, s) { } catch (e, s) {
Logs().w( Logs().w(
'[LibOlm] Could not decrypt to device event from ${event.sender} with content: ${event.content}', '[Vodozemac] Could not decrypt to device event from ${event.sender} with content: ${event.content}',
e, e,
s, s,
); );
@ -243,8 +241,8 @@ class Encryption {
.onError((e, _) => Logs().e('Ignoring error for updating indexes')); .onError((e, _) => Logs().e('Ignoring error for updating indexes'));
} }
decryptedPayload = json.decode(decryptResult.plaintext); decryptedPayload = json.decode(decryptResult.plaintext);
} catch (exception, stackTrace) { } catch (exception) {
Logs().w('Could not decrypt event', exception, stackTrace); Logs().d('Could not decrypt event', exception);
// alright, if this was actually by our own outbound group session, we might as well clear it // alright, if this was actually by our own outbound group session, we might as well clear it
if (exception.toString() != DecryptException.unknownSession && if (exception.toString() != DecryptException.unknownSession &&
(keyManager (keyManager

View File

@ -127,7 +127,7 @@ class KeyManager {
inboundGroupSession = vod.InboundGroupSession(content['session_key']); inboundGroupSession = vod.InboundGroupSession(content['session_key']);
} }
} catch (e, s) { } catch (e, s) {
Logs().e('[LibOlm] Could not create new InboundGroupSession', e, s); Logs().e('[Vodozemac] Could not create new InboundGroupSession', e, s);
return Future.value(); return Future.value();
} }
final newSession = SessionKey( final newSession = SessionKey(
@ -465,7 +465,7 @@ class KeyManager {
} }
} catch (e, s) { } catch (e, s) {
Logs().e( Logs().e(
'[LibOlm] Unable to re-send the session key at later index to new devices', '[Vodozemac] Unable to re-send the session key at later index to new devices',
e, e,
s, s,
); );
@ -589,7 +589,7 @@ class KeyManager {
_outboundGroupSessions[roomId] = sess; _outboundGroupSessions[roomId] = sess;
} catch (e, s) { } catch (e, s) {
Logs().e( Logs().e(
'[LibOlm] Unable to send the session key to the participating devices', '[Vodozemac] Unable to send the session key to the participating devices',
e, e,
s, s,
); );
@ -679,17 +679,15 @@ class KeyManager {
try { try {
decrypted = json.decode( decrypted = json.decode(
decryption.decrypt( decryption.decrypt(
vod.PkMessage( vod.PkMessage.fromBase64(
base64decodeUnpadded(sessionData['ciphertext'] as String), ciphertext: sessionData['ciphertext'] as String,
base64decodeUnpadded(sessionData['mac'] as String), mac: sessionData['mac'] as String,
vod.Curve25519PublicKey.fromBase64( ephemeralKey: sessionData['ephemeral'] as String,
sessionData['ephemeral'] as String,
),
), ),
), ),
); );
} catch (e, s) { } catch (e, s) {
Logs().e('[LibOlm] Error decrypting room key', e, s); Logs().e('[Vodozemac] Error decrypting room key', e, s);
} }
final senderKey = decrypted?.tryGet<String>('sender_key'); final senderKey = decrypted?.tryGet<String>('sender_key');
if (decrypted != null && senderKey != null) { if (decrypted != null && senderKey != null) {
@ -1256,14 +1254,15 @@ RoomKeys generateUploadKeysImplementation(GenerateUploadKeysArgs args) {
// fetch the device, if available... // fetch the device, if available...
//final device = args.client.getUserDeviceKeysByCurve25519Key(sess.senderKey); //final device = args.client.getUserDeviceKeysByCurve25519Key(sess.senderKey);
// aaaand finally add the session key to our payload // aaaand finally add the session key to our payload
final (ciphertext, mac, ephemeral) = encrypted.toBase64();
roomKeyBackup.sessions[sess.sessionId] = KeyBackupData( roomKeyBackup.sessions[sess.sessionId] = KeyBackupData(
firstMessageIndex: sess.inboundGroupSession!.firstKnownIndex, firstMessageIndex: sess.inboundGroupSession!.firstKnownIndex,
forwardedCount: sess.forwardingCurve25519KeyChain.length, forwardedCount: sess.forwardingCurve25519KeyChain.length,
isVerified: dbSession.verified, //device?.verified ?? false, isVerified: dbSession.verified, //device?.verified ?? false,
sessionData: { sessionData: {
'ephemeral': encrypted.ephemeralKey.toBase64(), 'ephemeral': ephemeral,
'ciphertext': base64Encode(encrypted.ciphertext), 'ciphertext': ciphertext,
'mac': base64Encode(encrypted.mac), 'mac': mac,
}, },
); );
} }

View File

@ -296,15 +296,9 @@ class OlmManager {
exception.error == MatrixError.M_UNKNOWN) { exception.error == MatrixError.M_UNKNOWN) {
Logs().w('Rotating otks because upload failed', exception); Logs().w('Rotating otks because upload failed', exception);
for (final otk in signedOneTimeKeys.values) { for (final otk in signedOneTimeKeys.values) {
// Keys can only be removed by creating a session...
final identity = olmAccount.identityKeys.curve25519.toBase64();
final key = otk.tryGet<String>('key'); final key = otk.tryGet<String>('key');
if (key != null) { if (key != null) {
olmAccount.createOutboundSession( olmAccount.removeOneTimeKey(key);
identityKey: vod.Curve25519PublicKey.fromBase64(identity),
oneTimeKey: vod.Curve25519PublicKey.fromBase64(key),
);
} }
} }
@ -440,32 +434,16 @@ class OlmManager {
if (session.session == null) { if (session.session == null) {
continue; continue;
} }
if (type == 0) {
try { try {
plaintext = session.session!.decrypt( plaintext = session.session!.decrypt(
messageType: type, messageType: type,
ciphertext: body, ciphertext: body,
); );
} catch (e) {
// The message was encrypted during this session, but is unable to decrypt
throw DecryptException(
DecryptException.decryptionFailed,
e.toString(),
);
}
await updateSessionUsage(session); await updateSessionUsage(session);
break; break;
} else if (type == 1) { } catch (_) {
try { plaintext = null;
plaintext = session.session!.decrypt(
messageType: type,
ciphertext: body,
);
await updateSessionUsage(session);
break;
} catch (_) {
plaintext = null;
}
} }
} }
} }
@ -677,8 +655,11 @@ class OlmManager {
), ),
); );
} catch (e, s) { } catch (e, s) {
Logs() Logs().e(
.e('[LibOlm] Could not create new outbound olm session', e, s); '[Vodozemac] Could not create new outbound olm session',
e,
s,
);
} }
} }
} }
@ -767,10 +748,10 @@ class OlmManager {
getFromDb: false, getFromDb: false,
); );
} on NoOlmSessionFoundException catch (e) { } on NoOlmSessionFoundException catch (e) {
Logs().d('[LibOlm] Error encrypting to-device event', e); Logs().d('[Vodozemac] Error encrypting to-device event', e);
continue; continue;
} catch (e, s) { } catch (e, s) {
Logs().wtf('[LibOlm] Error encrypting to-device event', e, s); Logs().wtf('[Vodozemac] Error encrypting to-device event', e, s);
continue; continue;
} }
} }

View File

@ -45,7 +45,7 @@ extension JsonSignatureCheckExtension on Map<String, dynamic> {
isValid = true; isValid = true;
} catch (e, s) { } catch (e, s) {
isValid = false; isValid = false;
Logs().w('[LibOlm] Signature check failed', e, s); Logs().w('[Vodozemac] Signature check failed', e, s);
} }
return isValid; return isValid;
} }

View File

@ -1460,7 +1460,11 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
void _handleKey(Map<String, dynamic> payload) { void _handleKey(Map<String, dynamic> payload) {
theirPublicKey = payload['key']; theirPublicKey = payload['key'];
establishedSas = sas!.establishSasSecret(payload['key']); final sas = this.sas;
if (sas == null || sas.disposed) {
throw Exception('SAS object is disposed');
}
establishedSas = sas.establishSasSecret(payload['key']);
} }
Future<bool> _validateCommitment() async { Future<bool> _validateCommitment() async {
@ -1553,9 +1557,9 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
Future<String> _makeCommitment(String pubKey, String canonicalJson) async { Future<String> _makeCommitment(String pubKey, String canonicalJson) async {
if (hash == 'sha256') { if (hash == 'sha256') {
final bytes = utf8.encode(pubKey + canonicalJson); final bytes = utf8.encoder.convert(pubKey + canonicalJson);
final digest = crypto.sha256.convert(bytes); final digest = crypto.sha256.convert(bytes);
return base64.encode(digest.bytes); return encodeBase64Unpadded(digest.bytes);
} }
throw Exception('Unknown hash method'); throw Exception('Unknown hash method');
} }

View File

@ -50,6 +50,7 @@ class OlmSession {
pickle: dbEntry['pickle'], pickle: dbEntry['pickle'],
); );
} catch (_) { } catch (_) {
Logs().d('Unable to unpickle Olm session. Try LibOlm format.');
session = vod.Session.fromOlmPickleEncrypted( session = vod.Session.fromOlmPickleEncrypted(
pickleKey: utf8.encode(key), pickleKey: utf8.encode(key),
pickle: dbEntry['pickle'], pickle: dbEntry['pickle'],
@ -60,7 +61,7 @@ class OlmSession {
DateTime.fromMillisecondsSinceEpoch(dbEntry['last_received'] ?? 0); DateTime.fromMillisecondsSinceEpoch(dbEntry['last_received'] ?? 0);
assert(sessionId == session!.sessionId); assert(sessionId == session!.sessionId);
} catch (e, s) { } catch (e, s) {
Logs().e('[LibOlm] Could not unpickle olm session', e, s); Logs().e('[Vodozemac] Could not unpickle olm session', e, s);
} }
} }
} }

View File

@ -71,7 +71,7 @@ class OutboundGroupSession {
pickle: dbEntry['pickle'], pickle: dbEntry['pickle'],
); );
} catch (_) { } catch (_) {
Logs().e('[LibOlm] Unable to unpickle outboundGroupSession', e, s); Logs().e('[Vodozemac] Unable to unpickle outboundGroupSession', e, s);
} }
} }
} }

View File

@ -107,12 +107,13 @@ class SessionKey {
); );
} catch (e, s) { } catch (e, s) {
try { try {
Logs().d('Unable to unpickle inboundGroupSession. Try LibOlm format.');
inboundGroupSession = vod.InboundGroupSession.fromOlmPickleEncrypted( inboundGroupSession = vod.InboundGroupSession.fromOlmPickleEncrypted(
pickle: dbEntry.pickle, pickle: dbEntry.pickle,
pickleKey: utf8.encode(key), pickleKey: utf8.encode(key),
); );
} catch (_) { } catch (_) {
Logs().e('[LibOlm] Unable to unpickle inboundGroupSession', e, s); Logs().e('[Vodozemac] Unable to unpickle inboundGroupSession', e, s);
rethrow; rethrow;
} }
} }

View File

@ -1,5 +1,4 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:http/http.dart'; import 'package:http/http.dart';

View File

@ -27,6 +27,7 @@ import 'package:collection/collection.dart' show IterableExtension;
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:mime/mime.dart'; import 'package:mime/mime.dart';
import 'package:random_string/random_string.dart'; import 'package:random_string/random_string.dart';
import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/encryption.dart'; import 'package:matrix/encryption.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
@ -35,7 +36,6 @@ import 'package:matrix/msc_extensions/msc_unpublished_custom_refresh_token_lifet
import 'package:matrix/src/models/timeline_chunk.dart'; import 'package:matrix/src/models/timeline_chunk.dart';
import 'package:matrix/src/utils/cached_stream_controller.dart'; import 'package:matrix/src/utils/cached_stream_controller.dart';
import 'package:matrix/src/utils/client_init_exception.dart'; import 'package:matrix/src/utils/client_init_exception.dart';
import 'package:matrix/src/utils/compute_callback.dart';
import 'package:matrix/src/utils/multilock.dart'; import 'package:matrix/src/utils/multilock.dart';
import 'package:matrix/src/utils/run_benchmarked.dart'; import 'package:matrix/src/utils/run_benchmarked.dart';
import 'package:matrix/src/utils/run_in_root.dart'; import 'package:matrix/src/utils/run_in_root.dart';
@ -106,20 +106,6 @@ class Client extends MatrixApi {
final bool convertLinebreaksInFormatting; final bool convertLinebreaksInFormatting;
final ComputeCallback? compute;
@Deprecated('Use [nativeImplementations] instead')
Future<T> runInBackground<T, U>(
FutureOr<T> Function(U arg) function,
U arg,
) async {
final compute = this.compute;
if (compute != null) {
return await compute(function, arg);
}
return await function(arg);
}
final Duration sendTimelineEventTimeout; final Duration sendTimelineEventTimeout;
/// The timeout until a typing indicator gets removed automatically. /// The timeout until a typing indicator gets removed automatically.
@ -208,8 +194,7 @@ class Client extends MatrixApi {
Set<String>? supportedLoginTypes, Set<String>? supportedLoginTypes,
this.mxidLocalPartFallback = true, this.mxidLocalPartFallback = true,
this.formatLocalpart = true, this.formatLocalpart = true,
@Deprecated('Use [nativeImplementations] instead') this.compute, this.nativeImplementations = NativeImplementations.dummy,
NativeImplementations nativeImplementations = NativeImplementations.dummy,
Level? logLevel, Level? logLevel,
Filter? syncFilter, Filter? syncFilter,
Duration defaultNetworkRequestTimeout = const Duration(seconds: 35), Duration defaultNetworkRequestTimeout = const Duration(seconds: 35),
@ -247,9 +232,6 @@ class Client extends MatrixApi {
supportedLoginTypes = supportedLoginTypes =
supportedLoginTypes ?? {AuthenticationTypes.password}, supportedLoginTypes ?? {AuthenticationTypes.password},
verificationMethods = verificationMethods ?? <KeyVerificationMethod>{}, verificationMethods = verificationMethods ?? <KeyVerificationMethod>{},
nativeImplementations = compute != null
? NativeImplementationsIsolate(compute)
: nativeImplementations,
super( super(
httpClient: FixedTimeoutHttpClient( httpClient: FixedTimeoutHttpClient(
httpClient ?? http.Client(), httpClient ?? http.Client(),
@ -2100,12 +2082,14 @@ class Client extends MatrixApi {
} }
await encryption?.dispose(); await encryption?.dispose();
try { if (vod.isInitialized()) {
_encryption = Encryption(client: this); try {
} catch (e) { _encryption = Encryption(client: this);
Logs().e('Error initializing encryption $e'); } catch (e) {
await encryption?.dispose(); Logs().e('Error initializing encryption $e');
_encryption = null; await encryption?.dispose();
_encryption = null;
}
} }
onInitStateChanged?.call(InitState.settingUpEncryption); onInitStateChanged?.call(InitState.settingUpEncryption);
await encryption?.init(olmAccount); await encryption?.init(olmAccount);
@ -3427,7 +3411,7 @@ class Client extends MatrixApi {
}); });
} }
} catch (e, s) { } catch (e, s) {
Logs().e('[LibOlm] Unable to update user device keys', e, s); Logs().e('[Vodozemac] Unable to update user device keys', e, s);
} }
} }

View File

@ -11,12 +11,3 @@ typedef ComputeRunner = Future<T> Function<T, U>(
FutureOr<T> Function(U arg) function, FutureOr<T> Function(U arg) function,
U arg, U arg,
); );
ComputeCallback computeCallbackFromRunInBackground(ComputeRunner runner) {
return <U, T>(
FutureOr<T> Function(U arg) callback,
U arg, {
String? debugLabel,
}) =>
runner.call(callback, arg);
}

View File

@ -27,7 +27,6 @@ import 'package:image/image.dart';
import 'package:mime/mime.dart'; import 'package:mime/mime.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:matrix/src/utils/compute_callback.dart';
class MatrixFile { class MatrixFile {
final Uint8List bytes; final Uint8List bytes;
@ -112,13 +111,8 @@ class MatrixImageFile extends MatrixFile {
required Uint8List bytes, required Uint8List bytes,
required String name, required String name,
String? mimeType, String? mimeType,
@Deprecated('Use [nativeImplementations] instead') ComputeRunner? compute,
NativeImplementations nativeImplementations = NativeImplementations.dummy, NativeImplementations nativeImplementations = NativeImplementations.dummy,
}) async { }) async {
if (compute != null) {
nativeImplementations =
NativeImplementationsIsolate.fromRunInBackground(compute);
}
final metaData = await nativeImplementations.calcImageMetadata(bytes); final metaData = await nativeImplementations.calcImageMetadata(bytes);
return MatrixImageFile( return MatrixImageFile(
@ -142,13 +136,8 @@ class MatrixImageFile extends MatrixFile {
Future<MatrixImageFileResizedResponse?> Function( Future<MatrixImageFileResizedResponse?> Function(
MatrixImageFileResizeArguments, MatrixImageFileResizeArguments,
)? customImageResizer, )? customImageResizer,
@Deprecated('Use [nativeImplementations] instead') ComputeRunner? compute,
NativeImplementations nativeImplementations = NativeImplementations.dummy, NativeImplementations nativeImplementations = NativeImplementations.dummy,
}) async { }) async {
if (compute != null) {
nativeImplementations =
NativeImplementationsIsolate.fromRunInBackground(compute);
}
final image = MatrixImageFile(name: name, mimeType: mimeType, bytes: bytes); final image = MatrixImageFile(name: name, mimeType: mimeType, bytes: bytes);
return await image.generateThumbnail( return await image.generateThumbnail(
@ -196,13 +185,8 @@ class MatrixImageFile extends MatrixFile {
Future<MatrixImageFileResizedResponse?> Function( Future<MatrixImageFileResizedResponse?> Function(
MatrixImageFileResizeArguments, MatrixImageFileResizeArguments,
)? customImageResizer, )? customImageResizer,
@Deprecated('Use [nativeImplementations] instead') ComputeRunner? compute,
NativeImplementations nativeImplementations = NativeImplementations.dummy, NativeImplementations nativeImplementations = NativeImplementations.dummy,
}) async { }) async {
if (compute != null) {
nativeImplementations =
NativeImplementationsIsolate.fromRunInBackground(compute);
}
final arguments = MatrixImageFileResizeArguments( final arguments = MatrixImageFileResizeArguments(
bytes: bytes, bytes: bytes,
maxDimension: dimension, maxDimension: dimension,

View File

@ -133,19 +133,13 @@ class NativeImplementationsDummy extends NativeImplementations {
class NativeImplementationsIsolate extends NativeImplementations { class NativeImplementationsIsolate extends NativeImplementations {
/// pass by Flutter's compute function here /// pass by Flutter's compute function here
final ComputeCallback compute; final ComputeCallback compute;
final Future<void> Function()? vodozemacInit;
NativeImplementationsIsolate(this.compute); NativeImplementationsIsolate(
this.compute, {
/// creates a [NativeImplementationsIsolate] based on a [ComputeRunner] as /// To generate upload keys, vodozemac needs to be initialized in the isolate.
// ignore: deprecated_member_use_from_same_package this.vodozemacInit,
/// known from [Client.runInBackground] });
factory NativeImplementationsIsolate.fromRunInBackground(
ComputeRunner runInBackground,
) {
return NativeImplementationsIsolate(
computeCallbackFromRunInBackground(runInBackground),
);
}
Future<T> runInBackground<T, U>( Future<T> runInBackground<T, U>(
FutureOr<T> Function(U arg) function, FutureOr<T> Function(U arg) function,
@ -172,7 +166,10 @@ class NativeImplementationsIsolate extends NativeImplementations {
bool retryInDummy = true, bool retryInDummy = true,
}) async { }) async {
return runInBackground<RoomKeys, GenerateUploadKeysArgs>( return runInBackground<RoomKeys, GenerateUploadKeysArgs>(
NativeImplementations.dummy.generateUploadKeys, (GenerateUploadKeysArgs args) async {
await vodozemacInit?.call();
return NativeImplementations.dummy.generateUploadKeys(args);
},
args, args,
); );
} }

View File

@ -24,18 +24,13 @@ dependencies:
js: ^0.6.3 js: ^0.6.3
markdown: ^7.1.1 markdown: ^7.1.1
mime: ">=1.0.0 <3.0.0" mime: ">=1.0.0 <3.0.0"
olm: ^3.1.0
random_string: ^2.3.1 random_string: ^2.3.1
sdp_transform: ^0.3.2 sdp_transform: ^0.3.2
slugify: ^2.0.0 slugify: ^2.0.0
sqflite_common: ^2.4.5 sqflite_common: ^2.4.5
sqlite3: ^2.1.0 sqlite3: ^2.1.0
typed_data: ^1.3.2 typed_data: ^1.3.2
vodozemac: vodozemac: ^0.2.0
git:
url: https://github.com/famedly/dart-vodozemac.git
path: dart
ref: main
webrtc_interface: ^1.2.0 webrtc_interface: ^1.2.0
dev_dependencies: dev_dependencies:

View File

@ -1,35 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
ENTRYPOINT="$(pwd)"
mkdir js
cd js
curl -O 'https://packages.matrix.org/npm/olm/olm-3.1.4.tgz'
tar xaf olm-3.1.4.tgz
cd ..
if [ -f /usr/lib/x86_64-linux-gnu/libolm.so.3 ]; then
mkdir -p ffi/olm/
ln -sf /usr/lib/x86_64-linux-gnu/libolm.so.3 ffi/olm/libolm.so
# alpine specific location
elif [ -f /usr/lib/libolm.so.3 ]; then
mkdir -p ffi/olm
ln -sf /usr/lib/libolm.so.3 ffi/olm/libolm.so
else
mkdir ffi
cd ffi
cd ..
git clone --depth 1 https://gitlab.matrix.org/matrix-org/olm.git
cd olm
cmake -DCMAKE_BUILD_TYPE=Release .
cmake --build .
cd ..
fi
cd "$ENTRYPOINT"
if which flutter >/dev/null; then if which flutter >/dev/null; then
flutter pub get flutter pub get
else else

View File

@ -1,5 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
rm -rf rust
git clone https://github.com/famedly/dart-vodozemac.git git clone https://github.com/famedly/dart-vodozemac.git
mv ./dart-vodozemac/rust ./ mv ./dart-vodozemac/rust ./
rm -rf dart-vodozemac rm -rf dart-vodozemac

View File

@ -23,9 +23,9 @@ import 'dart:typed_data';
import 'package:canonical_json/canonical_json.dart'; import 'package:canonical_json/canonical_json.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:olm/olm.dart' as olm;
import 'package:path/path.dart' show join; import 'package:path/path.dart' show join;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:matrix/src/utils/client_init_exception.dart'; import 'package:matrix/src/utils/client_init_exception.dart';
@ -1069,9 +1069,8 @@ void main() {
final deviceKeys = <DeviceKeys>[]; final deviceKeys = <DeviceKeys>[];
for (var i = 0; i < 30; i++) { for (var i = 0; i < 30; i++) {
final account = olm.Account(); final account = vod.Account();
account.create(); final keys = account.identityKeys;
final keys = json.decode(account.identity_keys());
final userId = '@testuser:example.org'; final userId = '@testuser:example.org';
final deviceId = 'DEVICE$i'; final deviceId = 'DEVICE$i';
final keyObj = { final keyObj = {
@ -1082,18 +1081,17 @@ void main() {
'm.megolm.v1.aes-sha2', 'm.megolm.v1.aes-sha2',
], ],
'keys': { 'keys': {
'curve25519:$deviceId': keys['curve25519'], 'curve25519:$deviceId': keys.curve25519.toBase64(),
'ed25519:$deviceId': keys['ed25519'], 'ed25519:$deviceId': keys.ed25519.toBase64(),
}, },
}; };
final signature = final signature =
account.sign(String.fromCharCodes(canonicalJson.encode(keyObj))); account.sign(String.fromCharCodes(canonicalJson.encode(keyObj)));
keyObj['signatures'] = { keyObj['signatures'] = {
userId: { userId: {
'ed25519:$deviceId': signature, 'ed25519:$deviceId': signature.toBase64(),
}, },
}; };
account.free();
deviceKeys.add(DeviceKeys.fromJson(keyObj, matrix)); deviceKeys.add(DeviceKeys.fromJson(keyObj, matrix));
} }
FakeMatrixApi.calledEndpoints.clear(); FakeMatrixApi.calledEndpoints.clear();

View File

@ -19,7 +19,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vodozemac/vodozemac.dart' as vod; import 'package:vodozemac/vodozemac.dart' as vod;
@ -40,8 +39,7 @@ void main() {
wasmPath: './pkg/', wasmPath: './pkg/',
libraryPath: './rust/target/debug/', libraryPath: './rust/target/debug/',
); );
await olm.init();
olm.get_library_version();
client = await getClient(); client = await getClient();
}); });

View File

@ -18,7 +18,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vodozemac/vodozemac.dart' as vod; import 'package:vodozemac/vodozemac.dart' as vod;
@ -36,8 +35,7 @@ void main() {
wasmPath: './pkg/', wasmPath: './pkg/',
libraryPath: './rust/target/debug/', libraryPath: './rust/target/debug/',
); );
await olm.init();
olm.get_library_version();
client = await getClient(); client = await getClient();
await client.abortSync(); await client.abortSync();
}); });

View File

@ -16,7 +16,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vodozemac/vodozemac.dart' as vod; import 'package:vodozemac/vodozemac.dart' as vod;
@ -38,8 +37,7 @@ void main() {
wasmPath: './pkg/', wasmPath: './pkg/',
libraryPath: './rust/target/debug/', libraryPath: './rust/target/debug/',
); );
await olm.init();
olm.get_library_version();
client = await getClient(); client = await getClient();
room = client.getRoomById(roomId)!; room = client.getRoomById(roomId)!;
}); });

View File

@ -16,7 +16,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vodozemac/vodozemac.dart' as vod; import 'package:vodozemac/vodozemac.dart' as vod;
@ -44,8 +43,7 @@ void main() async {
wasmPath: './pkg/', wasmPath: './pkg/',
libraryPath: './rust/target/debug/', libraryPath: './rust/target/debug/',
); );
await olm.init();
olm.get_library_version();
client = await getClient(); client = await getClient();
}); });

View File

@ -18,7 +18,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vodozemac/vodozemac.dart' as vod; import 'package:vodozemac/vodozemac.dart' as vod;
@ -35,8 +34,7 @@ void main() {
wasmPath: './pkg/', wasmPath: './pkg/',
libraryPath: './rust/target/debug/', libraryPath: './rust/target/debug/',
); );
await olm.init();
olm.get_library_version();
client = await getClient(); client = await getClient();
}); });

View File

@ -18,7 +18,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vodozemac/vodozemac.dart' as vod; import 'package:vodozemac/vodozemac.dart' as vod;
@ -47,8 +46,6 @@ void main() {
wasmPath: './pkg/', wasmPath: './pkg/',
libraryPath: './rust/target/debug/', libraryPath: './rust/target/debug/',
); );
await olm.init();
olm.get_library_version();
}); });
final validSessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU'; final validSessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU';

View File

@ -20,7 +20,6 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vodozemac/vodozemac.dart' as vod; import 'package:vodozemac/vodozemac.dart' as vod;
@ -63,8 +62,6 @@ void main() async {
wasmPath: './pkg/', wasmPath: './pkg/',
libraryPath: './rust/target/debug/', libraryPath: './rust/target/debug/',
); );
await olm.init();
olm.get_library_version();
}); });
setUp(() async { setUp(() async {

View File

@ -18,7 +18,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vodozemac/vodozemac.dart' as vod; import 'package:vodozemac/vodozemac.dart' as vod;
@ -37,8 +36,7 @@ void main() {
wasmPath: './pkg/', wasmPath: './pkg/',
libraryPath: './rust/target/debug/', libraryPath: './rust/target/debug/',
); );
await olm.init();
olm.get_library_version();
client = await getClient(); client = await getClient();
}); });

View File

@ -18,7 +18,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vodozemac/vodozemac.dart' as vod; import 'package:vodozemac/vodozemac.dart' as vod;
@ -40,8 +39,7 @@ void main() {
wasmPath: './pkg/', wasmPath: './pkg/',
libraryPath: './rust/target/debug/', libraryPath: './rust/target/debug/',
); );
await olm.init();
olm.get_library_version();
client = await getClient(); client = await getClient();
}); });
@ -91,20 +89,19 @@ void main() {
}); });
test('upload key', () async { test('upload key', () async {
final session = olm.OutboundGroupSession(); final session = vod.GroupSession();
session.create(); final inbound = vod.InboundGroupSession(session.sessionKey);
final inbound = olm.InboundGroupSession();
inbound.create(session.session_key());
final senderKey = client.identityKey; final senderKey = client.identityKey;
final roomId = '!someroom:example.org'; final roomId = '!someroom:example.org';
final sessionId = inbound.session_id(); final sessionId = inbound.sessionId;
// set a payload... // set a payload...
final sessionPayload = <String, dynamic>{ final sessionPayload = <String, dynamic>{
'algorithm': AlgorithmTypes.megolmV1AesSha2, 'algorithm': AlgorithmTypes.megolmV1AesSha2,
'room_id': roomId, 'room_id': roomId,
'forwarding_curve25519_key_chain': [client.identityKey], 'forwarding_curve25519_key_chain': [client.identityKey],
'session_id': sessionId, 'session_id': sessionId,
'session_key': inbound.export_session(1), 'session_key': inbound.exportAt(1),
'sender_key': senderKey, 'sender_key': senderKey,
'sender_claimed_ed25519_key': client.fingerprintKey, 'sender_claimed_ed25519_key': client.fingerprintKey,
}; };

View File

@ -20,7 +20,6 @@ import 'dart:convert';
import 'dart:math'; import 'dart:math';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vodozemac/vodozemac.dart' as vod; import 'package:vodozemac/vodozemac.dart' as vod;
@ -59,8 +58,7 @@ void main() {
wasmPath: './pkg/', wasmPath: './pkg/',
libraryPath: './rust/target/debug/', libraryPath: './rust/target/debug/',
); );
await olm.init();
olm.get_library_version();
client = await getClient(); client = await getClient();
}); });

View File

@ -18,7 +18,6 @@
import 'dart:io'; import 'dart:io';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vodozemac/vodozemac.dart' as vod; import 'package:vodozemac/vodozemac.dart' as vod;
@ -44,9 +43,6 @@ void main() => group(
wasmPath: './pkg/', wasmPath: './pkg/',
libraryPath: './rust/target/debug/', libraryPath: './rust/target/debug/',
); );
await olm.init();
olm.Account();
Logs().i('[LibOlm] Enabled');
final homeserverUri = Uri.parse(homeserver); final homeserverUri = Uri.parse(homeserver);
Logs().i('++++ Using homeserver $homeserverUri ++++'); Logs().i('++++ Using homeserver $homeserverUri ++++');
@ -490,10 +486,6 @@ void main() => group(
Client? testClientA, testClientB; Client? testClientA, testClientB;
try { try {
await olm.init();
olm.Account();
Logs().i('[LibOlm] Enabled');
final homeserverUri = Uri.parse(homeserver); final homeserverUri = Uri.parse(homeserver);
Logs().i('++++ Using homeserver $homeserverUri ++++'); Logs().i('++++ Using homeserver $homeserverUri ++++');