From 36405f82160c30f09b5146111421e3901b9bef2d Mon Sep 17 00:00:00 2001 From: Sorunome Date: Sun, 25 Oct 2020 16:59:55 +0100 Subject: [PATCH] fix: Multiple related store things --- lib/components/matrix.dart | 3 +- lib/components/theme_switcher.dart | 2 +- lib/main.dart | 4 +- lib/utils/famedlysdk_store.dart | 255 +++-------------------------- lib/utils/sentry_controller.dart | 8 +- lib/views/settings.dart | 2 +- pubspec.lock | 2 +- pubspec.yaml | 2 +- 8 files changed, 37 insertions(+), 241 deletions(-) diff --git a/lib/components/matrix.dart b/lib/components/matrix.dart index f626e5e..47842b5 100644 --- a/lib/components/matrix.dart +++ b/lib/components/matrix.dart @@ -81,8 +81,7 @@ class MatrixState extends State { void clean() async { if (!kIsWeb) return; - final storage = await getLocalStorage(); - await storage.deleteItem(widget.clientName); + await store.deleteItem(widget.clientName); } void _initWithStore() async { diff --git a/lib/components/theme_switcher.dart b/lib/components/theme_switcher.dart index a212b82..dafdd4c 100644 --- a/lib/components/theme_switcher.dart +++ b/lib/components/theme_switcher.dart @@ -175,7 +175,7 @@ class ThemeSwitcherWidgetState extends State { BuildContext context; Future loadSelection(MatrixState matrix) async { - String item = await matrix.store.getItem('theme') ?? 'system'; + var item = await matrix.store.getItem('theme') ?? 'system'; selectedTheme = Themes.values.firstWhere( (e) => e.toString() == 'Themes.' + item, orElse: () => Themes.system); diff --git a/lib/main.dart b/lib/main.dart index a08f001..fecdff2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -21,8 +21,8 @@ final sentry = SentryClient(dsn: '8591d0d863b646feb4f3dda7e5dcab38'); void captureException(error, stackTrace) async { debugPrint(error.toString()); debugPrint(stackTrace.toString()); - final storage = await getLocalStorage(); - if (storage.getItem('sentry') == true) { + final storage = Store(); + if (await storage.getItem('sentry') == 'true') { await sentry.captureException( exception: error, stackTrace: stackTrace, diff --git a/lib/utils/famedlysdk_store.dart b/lib/utils/famedlysdk_store.dart index 25acf11..6bb3f9c 100644 --- a/lib/utils/famedlysdk_store.dart +++ b/lib/utils/famedlysdk_store.dart @@ -1,27 +1,13 @@ -import 'dart:convert'; - import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/utils/platform_infos.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:localstorage/localstorage.dart'; import 'package:path_provider/path_provider.dart'; import 'dart:async'; import 'dart:core'; import './database/shared.dart'; -import 'package:olm/olm.dart' as olm; // needed for migration import 'package:random_string/random_string.dart'; -Future getLocalStorage() async { - final directory = PlatformInfos.isBetaDesktop - ? await getApplicationSupportDirectory() - : (PlatformInfos.isWeb ? null : await getApplicationDocumentsDirectory()); - final localStorage = LocalStorage('LocalStorage', directory?.path); - await localStorage.ready; - return localStorage; -} - Future getDatabase(Client client) async { while (_generateDatabaseLock) { await Future.delayed(Duration(milliseconds: 50)); @@ -31,9 +17,9 @@ Future getDatabase(Client client) async { if (_db != null) return _db; final store = Store(); var password = await store.getItem('database-password'); - var needMigration = false; + var newPassword = false; if (password == null || password.isEmpty) { - needMigration = true; + newPassword = true; password = randomString(255); } _db = await constructDb( @@ -41,11 +27,7 @@ Future getDatabase(Client client) async { filename: 'moor.sqlite', password: password, ); - // Check if database is open: - debugPrint((await _db.customSelect('SELECT 1').get()).toString()); - if (needMigration) { - debugPrint('[Moor] Start migration'); - await migrate(client.clientName, _db, store); + if (newPassword) { await store.setItem('database-password', password); } return _db; @@ -57,239 +39,54 @@ Future getDatabase(Client client) async { Database _db; bool _generateDatabaseLock = false; -Future migrate(String clientName, Database db, Store store) async { - debugPrint('[Store] attempting old migration to moor...'); - final oldKeys = await store.getAllItems(); - if (oldKeys == null || oldKeys.isEmpty) { - debugPrint('[Store] empty store!'); - return; // we are done! - } - final credentialsStr = oldKeys[clientName]; - if (credentialsStr == null || credentialsStr.isEmpty) { - debugPrint('[Store] no credentials found!'); - return; // no credentials - } - final Map credentials = json.decode(credentialsStr); - if (!credentials.containsKey('homeserver') || - !credentials.containsKey('token') || - !credentials.containsKey('userID')) { - debugPrint('[Store] invalid credentials!'); - return; // invalid old store, we are done, too! - } - var clientId = 0; - final oldClient = await db.getClient(clientName); - if (oldClient == null) { - clientId = await db.insertClient( - clientName, - credentials['homeserver'], - credentials['token'], - credentials['userID'], - credentials['deviceID'], - credentials['deviceName'], - null, - credentials['olmAccount'], - ); - } else { - clientId = oldClient.clientId; - await db.updateClient( - credentials['homeserver'], - credentials['token'], - credentials['userID'], - credentials['deviceID'], - credentials['deviceName'], - null, - credentials['olmAccount'], - clientId, - ); - } - await db.clearCache(clientId); - debugPrint('[Store] Inserted/updated client, clientId = ${clientId}'); - await db.transaction(() async { - // alright, we stored / updated the client and have the account ID, time to import everything else! - // user_device_keys and user_device_keys_key - debugPrint('[Store] Migrating user device keys...'); - final deviceKeysListString = oldKeys['${clientName}.user_device_keys']; - if (deviceKeysListString != null && deviceKeysListString.isNotEmpty) { - Map rawUserDeviceKeys = - json.decode(deviceKeysListString); - for (final entry in rawUserDeviceKeys.entries) { - final map = entry.value; - await db.storeUserDeviceKeysInfo( - clientId, map['user_id'], map['outdated']); - for (final rawKey in map['device_keys'].entries) { - final jsonVaue = rawKey.value; - await db.storeUserDeviceKey( - clientId, - jsonVaue['user_id'], - jsonVaue['device_id'], - json.encode(jsonVaue), - jsonVaue['verified'], - jsonVaue['blocked']); - } - } - } - for (final entry in oldKeys.entries) { - final key = entry.key; - final value = entry.value; - if (value == null || value.isEmpty) { - continue; - } - // olm_sessions - final olmSessionsMatch = - RegExp(r'^\/clients\/([^\/]+)\/olm-sessions$').firstMatch(key); - if (olmSessionsMatch != null) { - if (olmSessionsMatch[1] != credentials['deviceID']) { - continue; - } - debugPrint('[Store] migrating olm sessions...'); - final identityKey = json.decode(value); - for (final olmKey in identityKey.entries) { - final identKey = olmKey.key; - final sessions = olmKey.value; - for (final pickle in sessions) { - var sess = olm.Session(); - sess.unpickle(credentials['userID'], pickle); - await db.storeOlmSession( - clientId, identKey, sess.session_id(), pickle, null); - sess?.free(); - } - } - } - // outbound_group_sessions - final outboundGroupSessionsMatch = RegExp( - r'^\/clients\/([^\/]+)\/rooms\/([^\/]+)\/outbound_group_session$') - .firstMatch(key); - if (outboundGroupSessionsMatch != null) { - if (outboundGroupSessionsMatch[1] != credentials['deviceID']) { - continue; - } - final pickle = value; - final roomId = outboundGroupSessionsMatch[2]; - debugPrint( - '[Store] Migrating outbound group sessions for room ${roomId}...'); - final devicesString = oldKeys[ - '/clients/${outboundGroupSessionsMatch[1]}/rooms/${roomId}/outbound_group_session_devices']; - var devices = []; - if (devicesString != null) { - devices = List.from(json.decode(devicesString)); - } - await db.storeOutboundGroupSession( - clientId, - roomId, - pickle, - json.encode(devices), - DateTime.now().millisecondsSinceEpoch, - 0, - ); - } - // session_keys - final sessionKeysMatch = - RegExp(r'^\/clients\/([^\/]+)\/rooms\/([^\/]+)\/session_keys$') - .firstMatch(key); - if (sessionKeysMatch != null) { - if (sessionKeysMatch[1] != credentials['deviceID']) { - continue; - } - final roomId = sessionKeysMatch[2]; - debugPrint('[Store] Migrating session keys for room ${roomId}...'); - final map = json.decode(value); - for (final entry in map.entries) { - await db.storeInboundGroupSession( - clientId, - roomId, - entry.key, - entry.value['inboundGroupSession'], - json.encode(entry.value['content']), - json.encode(entry.value['indexes']), - null, - null); - } - } - } - }); -} - -// see https://github.com/mogol/flutter_secure_storage/issues/161#issuecomment-704578453 -class AsyncMutex { - Completer _completer; - - Future lock() async { - while (_completer != null) { - await _completer.future; - } - - _completer = Completer(); - } - - void unlock() { - assert(_completer != null); - final completer = _completer; - _completer = null; - completer.complete(); - } -} - class Store { - final LocalStorage storage; + LocalStorage storage; final FlutterSecureStorage secureStorage; - static final _mutex = AsyncMutex(); Store() - : storage = LocalStorage('LocalStorage'), - secureStorage = PlatformInfos.isMobile ? FlutterSecureStorage() : null; + : secureStorage = PlatformInfos.isMobile ? FlutterSecureStorage() : null; - Future getItem(String key) async { - if (!PlatformInfos.isMobile) { + Future _setupLocalStorage() async { + if (storage == null) { + final directory = PlatformInfos.isBetaDesktop + ? await getApplicationSupportDirectory() + : (PlatformInfos.isWeb + ? null + : await getApplicationDocumentsDirectory()); + storage = LocalStorage('LocalStorage', directory?.path); await storage.ready; + } + } + + Future getItem(String key) async { + if (!PlatformInfos.isMobile) { + await _setupLocalStorage(); try { - return await storage.getItem(key); + return await storage.getItem(key).toString(); } catch (_) { return null; } } try { - await _mutex.lock(); return await secureStorage.read(key: key); } catch (_) { return null; - } finally { - _mutex.unlock(); } } Future setItem(String key, String value) async { if (!PlatformInfos.isMobile) { - await storage.ready; + await _setupLocalStorage(); return await storage.setItem(key, value); } - if (value == null) { - return await secureStorage.delete(key: key); - } else { - try { - await _mutex.lock(); - return await secureStorage.write(key: key, value: value); - } finally { - _mutex.unlock(); - } - } + return await secureStorage.write(key: key, value: value); } - Future> getAllItems() async { + Future deleteItem(String key) async { if (!PlatformInfos.isMobile) { - try { - final rawStorage = await getLocalstorage('LocalStorage'); - return json.decode(rawStorage); - } catch (_) { - return {}; - } - } - try { - await _mutex.lock(); - return await secureStorage.readAll(); - } catch (_) { - return {}; - } finally { - _mutex.unlock(); + await _setupLocalStorage(); + return await storage.deleteItem(key); } + return await secureStorage.delete(key: key); } } diff --git a/lib/utils/sentry_controller.dart b/lib/utils/sentry_controller.dart index 970a419..09a3a67 100644 --- a/lib/utils/sentry_controller.dart +++ b/lib/utils/sentry_controller.dart @@ -13,14 +13,14 @@ abstract class SentryController { confirmText: L10n.of(context).ok, cancelText: L10n.of(context).no, ); - final storage = await getLocalStorage(); - await storage.setItem('sentry', enableSentry); + final storage = Store(); + await storage.setItem('sentry', enableSentry.toString()); BotToast.showText(text: L10n.of(context).changesHaveBeenSaved); return; } static Future getSentryStatus() async { - final storage = await getLocalStorage(); - return storage.getItem('sentry') as bool; + final storage = Store(); + return await storage.getItem('sentry') == 'true'; } } diff --git a/lib/views/settings.dart b/lib/views/settings.dart index 8896a39..bd4d4a5 100644 --- a/lib/views/settings.dart +++ b/lib/views/settings.dart @@ -185,7 +185,7 @@ class _SettingsState extends State { void deleteWallpaperAction(BuildContext context) async { Matrix.of(context).wallpaper = null; - await Matrix.of(context).store.setItem('chat.fluffy.wallpaper', null); + await Matrix.of(context).store.deleteItem('chat.fluffy.wallpaper'); setState(() => null); } diff --git a/pubspec.lock b/pubspec.lock index cc8eab9..aefa679 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -362,7 +362,7 @@ packages: name: flutter_secure_storage url: "https://pub.dartlang.org" source: hosted - version: "3.3.4" + version: "3.3.5" flutter_slidable: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 5dfbe56..b3fb5ca 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,7 +41,7 @@ dependencies: path_provider: ^1.5.1 webview_flutter: ^0.3.19+9 share: ^0.6.3+5 - flutter_secure_storage: ^3.3.4 + flutter_secure_storage: ^3.3.5 http: ^0.12.0+4 universal_html: ^1.1.12 receive_sharing_intent: ^1.3.3