diff --git a/lib/utils/client_manager.dart b/lib/utils/client_manager.dart index 732ec888..9221ed39 100644 --- a/lib/utils/client_manager.dart +++ b/lib/utils/client_manager.dart @@ -11,12 +11,12 @@ import 'package:sembast/sembast.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'famedlysdk_store.dart'; import 'matrix_sdk_extensions.dart/fluffybox_database.dart'; -import 'matrix_sdk_extensions.dart/flutter_matrix_sembast_database.dart'; +import 'matrix_sdk_extensions.dart/flutter_matrix_hive_database.dart'; abstract class ClientManager { static const String clientNamespace = 'im.fluffychat.store.clients'; static Future> getClients() async { - Logs().level = Level.verbose; + Logs().level = Level.warning; if (PlatformInfos.isLinux) { Hive.init((await getApplicationSupportDirectory()).path); } else { @@ -81,7 +81,7 @@ abstract class ClientManager { }, importantStateEvents: {'im.ponies.room_emotes'}, databaseBuilder: FlutterFluffyBoxDatabase.databaseBuilder, - legacyDatabaseBuilder: FlutterMatrixSembastDatabase.databaseBuilder, + legacyDatabaseBuilder: FlutterMatrixHiveStore.hiveDatabaseBuilder, supportedLoginTypes: { AuthenticationTypes.password, if (PlatformInfos.isMobile || PlatformInfos.isWeb) diff --git a/lib/utils/matrix_sdk_extensions.dart/flutter_matrix_sembast_database.dart b/lib/utils/matrix_sdk_extensions.dart/flutter_matrix_sembast_database.dart deleted file mode 100644 index c3953f5c..00000000 --- a/lib/utils/matrix_sdk_extensions.dart/flutter_matrix_sembast_database.dart +++ /dev/null @@ -1,207 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart' hide Key; -import 'package:flutter/services.dart'; - -import 'package:encrypt/encrypt.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:matrix/matrix.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:sembast/sembast.dart'; -import 'package:sembast/sembast_io.dart'; -import 'package:sembast_web/sembast_web.dart'; - -import '../platform_infos.dart'; - -class FlutterMatrixSembastDatabase extends MatrixSembastDatabase { - FlutterMatrixSembastDatabase( - String name, { - SembastCodec codec, - String path, - DatabaseFactory dbFactory, - }) : super( - name, - codec: codec, - path: path, - dbFactory: dbFactory, - ); - - static const String _cipherStorageKey = 'sembast_encryption_key'; - static const int _cipherStorageKeyLength = 512; - - static Future databaseBuilder( - Client client) async { - Logs().d('Open Sembast...'); - SembastCodec codec; - try { - // Workaround for secure storage is calling Platform.operatingSystem on web - if (kIsWeb) throw MissingPluginException(); - - const secureStorage = FlutterSecureStorage(); - final containsEncryptionKey = - await secureStorage.containsKey(key: _cipherStorageKey); - if (!containsEncryptionKey) { - final key = SecureRandom(_cipherStorageKeyLength).base64; - await secureStorage.write( - key: _cipherStorageKey, - value: key, - ); - } - - // workaround for if we just wrote to the key and it still doesn't exist - final rawEncryptionKey = await secureStorage.read(key: _cipherStorageKey); - if (rawEncryptionKey == null) throw MissingPluginException(); - - codec = getEncryptSembastCodec(password: rawEncryptionKey); - } on MissingPluginException catch (_) { - Logs().i('Sembast encryption is not supported on this platform'); - } - - final db = FlutterMatrixSembastDatabase( - client.clientName, - codec: codec, - path: await _findDatabasePath(client), - dbFactory: kIsWeb ? databaseFactoryWeb : databaseFactoryIo, - ); - await db.open(); - Logs().d('Sembast is ready'); - return db; - } - - static Future _findDatabasePath(Client client) async { - String path = client.clientName; - if (!kIsWeb) { - Directory directory; - try { - directory = await getApplicationSupportDirectory(); - } catch (_) { - try { - directory = await getLibraryDirectory(); - } catch (_) { - directory = Directory.current; - } - } - path = '${directory.path}${client.clientName}.db'; - } - return path; - } - - @override - int get maxFileSize => supportsFileStoring ? 100 * 1024 * 1024 : 0; - @override - bool get supportsFileStoring => (PlatformInfos.isIOS || - PlatformInfos.isAndroid || - PlatformInfos.isDesktop); - - Future _getFileStoreDirectory() async { - try { - try { - return (await getApplicationSupportDirectory()).path; - } catch (_) { - return (await getApplicationDocumentsDirectory()).path; - } - } catch (_) { - return (await getDownloadsDirectory()).path; - } - } - - @override - Future getFile(Uri mxcUri) async { - if (!supportsFileStoring) return null; - final tempDirectory = await _getFileStoreDirectory(); - final file = - File('$tempDirectory/${Uri.encodeComponent(mxcUri.toString())}'); - if (await file.exists() == false) return null; - final bytes = await file.readAsBytes(); - return bytes; - } - - @override - Future storeFile(Uri mxcUri, Uint8List bytes, int time) async { - if (!supportsFileStoring) return null; - final tempDirectory = await _getFileStoreDirectory(); - final file = - File('$tempDirectory/${Uri.encodeComponent(mxcUri.toString())}'); - if (await file.exists()) return; - await file.writeAsBytes(bytes); - return; - } -} - -class _EncryptEncoder extends Converter, String> { - final String key; - final String signature; - _EncryptEncoder(this.key, this.signature); - - @override - String convert(Map input) { - String encoded; - switch (signature) { - case "Salsa20": - encoded = Encrypter(Salsa20(Key.fromUtf8(key))) - .encrypt(json.encode(input), iv: IV.fromLength(8)) - .base64; - break; - case "AES": - encoded = Encrypter(AES(Key.fromUtf8(key))) - .encrypt(json.encode(input), iv: IV.fromLength(16)) - .base64; - break; - default: - throw FormatException('invalid $signature'); - break; - } - return encoded; - } -} - -class _EncryptDecoder extends Converter> { - final String key; - final String signature; - _EncryptDecoder(this.key, this.signature); - - @override - Map convert(String input) { - dynamic decoded; - switch (signature) { - case "Salsa20": - decoded = json.decode(Encrypter(Salsa20(Key.fromUtf8(key))) - .decrypt64(input, iv: IV.fromLength(8))); - break; - case "AES": - decoded = json.decode(Encrypter(AES(Key.fromUtf8(key))) - .decrypt64(input, iv: IV.fromLength(16))); - break; - default: - break; - } - if (decoded is Map) { - return decoded.cast(); - } - throw FormatException('invalid input $input'); - } -} - -class _EncryptCodec extends Codec, String> { - final String signature; - _EncryptEncoder _encoder; - _EncryptDecoder _decoder; - _EncryptCodec(String password, this.signature) { - _encoder = _EncryptEncoder(password, signature); - _decoder = _EncryptDecoder(password, signature); - } - - @override - Converter> get decoder => _decoder; - - @override - Converter, String> get encoder => _encoder; -} - -// Salsa20 (16 length key required) or AES (32 length key required) -SembastCodec getEncryptSembastCodec( - {@required String password, String signature = "Salsa20"}) => - SembastCodec( - signature: signature, codec: _EncryptCodec(password, signature)); diff --git a/pubspec.lock b/pubspec.lock index 876a5bec..9738e55f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -651,13 +651,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.0" - idb_shim: - dependency: transitive - description: - name: idb_shim - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" image: dependency: transitive description: @@ -1180,13 +1173,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.1" - sembast_web: - dependency: "direct main" - description: - name: sembast_web - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1+1" sentry: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 96093478..310ac4ef 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -63,7 +63,6 @@ dependencies: record: ^3.0.0 salomon_bottom_bar: ^3.1.0 scroll_to_index: ^2.1.0 - sembast_web: ^2.0.1+1 sentry: ^6.0.1 share: ^2.0.4 slugify: ^2.0.0