From 90c1caec6af54fac1c29dc4ad7c93344b0e7f69b Mon Sep 17 00:00:00 2001 From: Krille Date: Fri, 25 Aug 2023 12:26:27 +0200 Subject: [PATCH] feat: Implement sqflite database --- .gitignore | 2 + lib/utils/client_manager.dart | 4 +- lib/utils/sqflite_database_builder.dart | 88 ++++++++ macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 199 +++++++++++++++++- pubspec.yaml | 7 + scripts/prepare-web.sh | 1 + 7 files changed, 295 insertions(+), 8 deletions(-) create mode 100644 lib/utils/sqflite_database_builder.dart diff --git a/.gitignore b/.gitignore index 0ce56e79e..ccddb40ea 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,5 @@ ios/Runner.ipa /macos/out .vs olm +web/sqflite_sw.js +web/sqlite3.wasm diff --git a/lib/utils/client_manager.dart b/lib/utils/client_manager.dart index 1ee71d491..af1e4723f 100644 --- a/lib/utils/client_manager.dart +++ b/lib/utils/client_manager.dart @@ -11,6 +11,7 @@ import 'package:fluffychat/utils/custom_http_client.dart'; import 'package:fluffychat/utils/custom_image_resizer.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart'; import 'package:fluffychat/utils/platform_infos.dart'; +import 'package:fluffychat/utils/sqflite_database_builder.dart'; import 'famedlysdk_store.dart'; abstract class ClientManager { @@ -109,7 +110,8 @@ abstract class ClientManager { EventTypes.RoomPowerLevels, }, logLevel: kReleaseMode ? Level.warning : Level.verbose, - databaseBuilder: FlutterHiveCollectionsDatabase.databaseBuilder, + databaseBuilder: sqfliteDatabaseBuilder, + legacyDatabaseBuilder: FlutterHiveCollectionsDatabase.databaseBuilder, supportedLoginTypes: { AuthenticationTypes.password, AuthenticationTypes.sso, diff --git a/lib/utils/sqflite_database_builder.dart b/lib/utils/sqflite_database_builder.dart new file mode 100644 index 000000000..616cf95c8 --- /dev/null +++ b/lib/utils/sqflite_database_builder.dart @@ -0,0 +1,88 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:math'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; + +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:matrix/matrix.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:sqflite_common_ffi/sqflite_ffi.dart' as ffi; +import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart'; +import 'package:sqflite_sqlcipher/sqflite.dart'; +import 'package:universal_html/html.dart' as html; + +import 'package:fluffychat/utils/platform_infos.dart'; + +Future sqfliteDatabaseBuilder(Client client) async { + Logs().d('Build SQFLite database...'); + if (kIsWeb) { + html.window.navigator.storage?.persist(); + return SqfliteDatabase( + await databaseFactoryFfiWeb.openDatabase( + client.clientName, + options: OpenDatabaseOptions( + version: 1, + onCreate: DbTablesExtension.create, + ), + ), + fileStoragePath: null, + maxFileSize: 0, + ); + } + final path = PlatformInfos.isMobile + ? await getDatabasesPath() + : (await getApplicationSupportDirectory()).path; + const passwordStorageKey = 'database_password'; + String? password; + Database? database; + + if (PlatformInfos.isDesktop) { + database = await ffi.databaseFactoryFfi.openDatabase( + '$path/${client.clientName}', + options: OpenDatabaseOptions( + version: 1, + onCreate: DbTablesExtension.create, + ), + ); + } else { + try { + const secureStorage = FlutterSecureStorage(); + final containsEncryptionKey = + await secureStorage.read(key: passwordStorageKey) != null; + if (!containsEncryptionKey) { + // do not try to create a buggy secure storage for new Linux users + if (Platform.isLinux) throw MissingPluginException(); + final rng = Random.secure(); + final list = Uint8List(32); + list.setAll(0, Iterable.generate(list.length, (i) => rng.nextInt(256))); + final newPassword = base64UrlEncode(list); + await secureStorage.write( + key: passwordStorageKey, + value: newPassword, + ); + } + // workaround for if we just wrote to the key and it still doesn't exist + password = await secureStorage.read(key: passwordStorageKey); + if (password == null) throw MissingPluginException(); + } catch (e, s) { + const FlutterSecureStorage() + .delete(key: passwordStorageKey) + .catchError((_) {}); + Logs().w('Unable to init database encryption', e, s); + } + database = await openDatabase( + '$path/${client.clientName}', + version: 1, + onCreate: DbTablesExtension.create, + password: password, + ); + } + + return SqfliteDatabase( + database, + fileStoragePath: await getTemporaryDirectory(), + maxFileSize: 10 * 1024 * 1024, + ); +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index f6375bfec..38d9adf91 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -29,6 +29,7 @@ import record_macos import share_plus import shared_preferences_foundation import sqflite +import sqflite_sqlcipher import url_launcher_macos import video_compress import wakelock_macos @@ -60,6 +61,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) + SqfliteSqlCipherPlugin.register(with: registry.registrar(forPlugin: "SqfliteSqlCipherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) VideoCompressPlugin.register(with: registry.registrar(forPlugin: "VideoCompressPlugin")) WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin")) diff --git a/pubspec.lock b/pubspec.lock index cb4d2e046..cd21fbf55 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -53,10 +53,10 @@ packages: dependency: "direct main" description: name: archive - sha256: e0902a06f0e00414e4e3438a084580161279f137aeb862274710f29ec10cf01e + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" url: "https://pub.dev" source: hosted - version: "3.3.9" + version: "3.3.7" args: dependency: transitive description: @@ -209,6 +209,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" + url: "https://pub.dev" + source: hosted + version: "1.6.3" cross_file: dependency: transitive description: @@ -305,6 +313,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.3" + dev_test: + dependency: transitive + description: + name: dev_test + sha256: "0d49b920844062a518edb79fc1dbf9ff6d9bf3c9ab600e3847b7502c27c0caab" + url: "https://pub.dev" + source: hosted + version: "0.16.1+4" device_info_plus: dependency: "direct main" description: @@ -754,6 +770,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.40" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" fuchsia_remote_debug_protocol: dependency: transitive description: flutter @@ -831,6 +855,14 @@ packages: url: "https://pub.dev" source: hosted version: "10.1.0" + handy_window: + dependency: "direct main" + description: + name: handy_window + sha256: "458a9f7d4ae23816e8f33c76596f943a04e7eff13d864e0867f3b40f1647d63d" + url: "https://pub.dev" + source: hosted + version: "0.3.1" highlighter: dependency: transitive description: @@ -879,6 +911,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.13.6" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" http_parser: dependency: transitive description: @@ -988,6 +1028,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.18.1" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" js: dependency: transitive description: @@ -1128,11 +1176,12 @@ packages: matrix: dependency: "direct main" description: - name: matrix - sha256: "10389562a4562db6150291b538e025a9a1b7a79998a71d38cb5c78a34ca6b007" - url: "https://pub.dev" - source: hosted - version: "0.22.3" + path: "." + ref: "krille/sqflite-database" + resolved-ref: "42ed18b03cf9c6548ee9c71ea4aeb0b4ca239d5c" + url: "https://github.com/famedly/matrix-dart-sdk.git" + source: git + version: "0.22.2" matrix_api_lite: dependency: transitive description: @@ -1205,6 +1254,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" olm: dependency: transitive description: @@ -1413,6 +1470,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" process: dependency: transitive description: @@ -1421,6 +1486,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.2.4" + process_run: + dependency: transitive + description: + name: process_run + sha256: ceacfac6d566a36c895d64edc7e429efb2d6b6303b5e28d5c13bc59fe6e8974e + url: "https://pub.dev" + source: hosted + version: "0.13.1" proj4dart: dependency: transitive description: @@ -1669,6 +1742,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" sky_engine: dependency: transitive description: flutter @@ -1682,6 +1787,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" source_span: dependency: transitive description: @@ -1706,6 +1827,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.5.0" + sqflite_common_ffi: + dependency: "direct main" + description: + name: sqflite_common_ffi + sha256: "0d5cc1be2eb18400ac6701c31211d44164393aa75886093002ecdd947be04f93" + url: "https://pub.dev" + source: hosted + version: "2.3.0+2" + sqflite_common_ffi_web: + dependency: "direct main" + description: + name: sqflite_common_ffi_web + sha256: db9a7ef6adcfb6c9b4115f628c1d3efe3774b385309a80e75c1bafb97da2c9d1 + url: "https://pub.dev" + source: hosted + version: "0.4.0" + sqflite_sqlcipher: + dependency: "direct main" + description: + name: sqflite_sqlcipher + sha256: "3b64cfdefe0d3f1be562f66a69b0802c1ab9298a31d41219a661534d069f9d50" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + sqlite3: + dependency: transitive + description: + name: sqlite3 + sha256: db65233e6b99e99b2548932f55a987961bc06d82a31a0665451fa0b4fff4c3fb + url: "https://pub.dev" + source: hosted + version: "2.1.0" stack_trace: dependency: transitive description: @@ -1762,6 +1915,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" + test: + dependency: transitive + description: + name: test + sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" + url: "https://pub.dev" + source: hosted + version: "1.24.3" test_api: dependency: transitive description: @@ -1770,6 +1931,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.0" + test_core: + dependency: transitive + description: + name: test_core + sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" + url: "https://pub.dev" + source: hosted + version: "0.5.3" timezone: dependency: transitive description: @@ -2147,6 +2316,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.4-beta" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" webdriver: dependency: transitive description: @@ -2155,6 +2332,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.2" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + url: "https://pub.dev" + source: hosted + version: "1.2.0" webrtc_interface: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index cd22e9677..550931c08 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -80,6 +80,9 @@ dependencies: share_plus: ^7.0.0 shared_preferences: ^2.2.0 # Pinned because https://github.com/flutter/flutter/issues/118401 slugify: ^2.0.0 + sqflite_common_ffi: ^2.3.0+2 + sqflite_common_ffi_web: ^0.4.0 + sqflite_sqlcipher: ^2.2.0 swipe_to_action: ^0.2.0 tor_detector_web: ^1.1.0 uni_links: ^0.5.1 @@ -157,6 +160,10 @@ dependency_overrides: git: url: https://github.com/TheOneWithTheBraid/keyboard_shortcuts.git ref: null-safety + matrix: + git: + url: https://github.com/famedly/matrix-dart-sdk.git + ref: krille/sqflite-database # blocked upgrade of package_info_plus for null safety # https://github.com/creativecreatorormaybenot/wakelock/pull/203 wakelock_windows: diff --git a/scripts/prepare-web.sh b/scripts/prepare-web.sh index 2c05a2030..48f1ba916 100755 --- a/scripts/prepare-web.sh +++ b/scripts/prepare-web.sh @@ -4,3 +4,4 @@ cd assets/js/ && curl -L 'https://gitlab.com/famedly/company/frontend/libraries/ cd assets/js/ && unzip olm.zip && cd ../../ cd assets/js/ && rm olm.zip && cd ../../ cd assets/js/ && mv javascript package && cd ../../ +dart run sqflite_common_ffi_web:setup --force \ No newline at end of file