From bbbfabb5afafd2fdb52e714941d5eb94a3ebc021 Mon Sep 17 00:00:00 2001 From: Hanh Date: Sun, 5 Mar 2023 15:15:49 +1000 Subject: [PATCH] Db encryption --- ios/Podfile.lock | 2 +- lib/generated/intl/messages_en.dart | 17 ++++ lib/generated/intl/messages_es.dart | 17 ++++ lib/generated/intl/messages_fr.dart | 17 ++++ lib/generated/l10n.dart | 90 +++++++++++++++++++ lib/home.dart | 57 ++++++++++++ lib/l10n/intl_en.arb | 11 ++- lib/l10n/intl_es.arb | 11 ++- lib/l10n/intl_fr.arb | 11 ++- lib/main.dart | 60 +++++++++++-- lib/settings.dart | 8 +- lib/store.dart | 2 + linux/flutter/generated_plugin_registrant.cc | 4 - linux/flutter/generated_plugins.cmake | 1 - macos/Flutter/GeneratedPluginRegistrant.swift | 2 - macos/Podfile.lock | 8 +- macos/Runner.xcodeproj/project.pbxproj | 3 +- native/zcash-sync | 2 +- packages/warp_api_ffi/lib/warp_api.dart | 19 +++- .../warp_api_ffi/lib/warp_api_generated.dart | 90 +++++++++++++++++++ packages/warp_api_ffi/pubspec.yaml | 2 +- pubspec.lock | 48 ---------- pubspec.yaml | 3 +- .../flutter/generated_plugin_registrant.cc | 3 - windows/flutter/generated_plugins.cmake | 1 - 25 files changed, 397 insertions(+), 92 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 42acd9f..b045f5c 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -203,4 +203,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: e1af8a78652670a5b7b8de8c5f3641ce5c737641 -COCOAPODS: 1.11.3 +COCOAPODS: 1.12.0 diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index c1a8574..74a562a 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -190,8 +190,16 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Tap + to add a new contact"), "crypto": MessageLookupByLibrary.simpleMessage("Crypto"), "currency": MessageLookupByLibrary.simpleMessage("Currency"), + "currentPassword": + MessageLookupByLibrary.simpleMessage("Current Password"), + "currentPasswordIncorrect": + MessageLookupByLibrary.simpleMessage("Current password incorrect"), "custom": MessageLookupByLibrary.simpleMessage("Custom"), "dark": MessageLookupByLibrary.simpleMessage("Dark"), + "databaseEncrypted": MessageLookupByLibrary.simpleMessage( + "Database Encrypted. Please Restart the App."), + "databasePassword": + MessageLookupByLibrary.simpleMessage("Database Password"), "databaseUpdatedPleaseRestartTheApp": MessageLookupByLibrary.simpleMessage( "Database updated. Please restart the app."), @@ -219,6 +227,8 @@ class MessageLookup extends MessageLookupByLibrary { "duplicateContact": MessageLookupByLibrary.simpleMessage( "Another contact has this address"), "editContact": MessageLookupByLibrary.simpleMessage("Edit Contact"), + "encryptDatabase": + MessageLookupByLibrary.simpleMessage("Encrypt Database"), "encryptedBackup": m6, "encryptionKey": MessageLookupByLibrary.simpleMessage("Encryption Key"), "enterSecretShareIfAccountIsMultisignature": @@ -255,6 +265,8 @@ class MessageLookup extends MessageLookupByLibrary { "invalidAddress": MessageLookupByLibrary.simpleMessage("Invalid Address"), "invalidKey": MessageLookupByLibrary.simpleMessage("Invalid Key"), + "invalidPassword": + MessageLookupByLibrary.simpleMessage("Invalid Password"), "invalidQrCode": m8, "key": MessageLookupByLibrary.simpleMessage( "Seed, Secret Key or View Key (optional)"), @@ -295,6 +307,9 @@ class MessageLookup extends MessageLookupByLibrary { "nameIsEmpty": MessageLookupByLibrary.simpleMessage("Name is empty"), "newAccount": MessageLookupByLibrary.simpleMessage("New Account"), "newLabel": MessageLookupByLibrary.simpleMessage("New"), + "newPassword": MessageLookupByLibrary.simpleMessage("New Password"), + "newPasswordsDoNotMatch": + MessageLookupByLibrary.simpleMessage("New passwords do not match"), "newSnapAddress": MessageLookupByLibrary.simpleMessage("New Snap Address"), "newSubAccount": @@ -360,6 +375,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Receive Payment"), "received": m13, "recipient": MessageLookupByLibrary.simpleMessage("Recipient"), + "repeatNewPassword": + MessageLookupByLibrary.simpleMessage("Repeat New Password"), "reply": MessageLookupByLibrary.simpleMessage("Reply"), "rescan": MessageLookupByLibrary.simpleMessage("Rescan"), "rescanFrom": MessageLookupByLibrary.simpleMessage("Rescan from..."), diff --git a/lib/generated/intl/messages_es.dart b/lib/generated/intl/messages_es.dart index d31885d..2618c79 100644 --- a/lib/generated/intl/messages_es.dart +++ b/lib/generated/intl/messages_es.dart @@ -193,8 +193,16 @@ class MessageLookup extends MessageLookupByLibrary { "Crea un contacto y aparecerá aquí."), "crypto": MessageLookupByLibrary.simpleMessage("Crypto"), "currency": MessageLookupByLibrary.simpleMessage("Moneda"), + "currentPassword": + MessageLookupByLibrary.simpleMessage("Current password"), + "currentPasswordIncorrect": + MessageLookupByLibrary.simpleMessage("Current password incorrect"), "custom": MessageLookupByLibrary.simpleMessage("Personalizado"), "dark": MessageLookupByLibrary.simpleMessage("Noche"), + "databaseEncrypted": MessageLookupByLibrary.simpleMessage( + "Database Encrypted. Please Restart the App."), + "databasePassword": + MessageLookupByLibrary.simpleMessage("Database Password"), "databaseUpdatedPleaseRestartTheApp": MessageLookupByLibrary.simpleMessage( "Por favor reinicie la aplicación"), @@ -221,6 +229,8 @@ class MessageLookup extends MessageLookupByLibrary { "duplicateAccount": MessageLookupByLibrary.simpleMessage("Cuenta duplicada"), "editContact": MessageLookupByLibrary.simpleMessage("Editar contacto"), + "encryptDatabase": + MessageLookupByLibrary.simpleMessage("Encrypt Database"), "encryptedBackup": m6, "encryptionKey": MessageLookupByLibrary.simpleMessage("Clave de encriptación"), @@ -260,6 +270,8 @@ class MessageLookup extends MessageLookupByLibrary { "invalidAddress": MessageLookupByLibrary.simpleMessage("La Dirección no es válida"), "invalidKey": MessageLookupByLibrary.simpleMessage("Tecla inválida"), + "invalidPassword": + MessageLookupByLibrary.simpleMessage("Invalid Password"), "invalidQrCode": m8, "key": MessageLookupByLibrary.simpleMessage("Clave"), "keyTool": MessageLookupByLibrary.simpleMessage("Clave Utilidad"), @@ -300,6 +312,9 @@ class MessageLookup extends MessageLookupByLibrary { "nameIsEmpty": MessageLookupByLibrary.simpleMessage("Nombre vacío"), "newAccount": MessageLookupByLibrary.simpleMessage("Nueva cuenta"), "newLabel": MessageLookupByLibrary.simpleMessage("Nueva"), + "newPassword": MessageLookupByLibrary.simpleMessage("New Password"), + "newPasswordsDoNotMatch": + MessageLookupByLibrary.simpleMessage("New passwords do not match"), "newSnapAddress": MessageLookupByLibrary.simpleMessage("Nueva Dirección instantánea"), "newSubAccount": @@ -364,6 +379,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Recibir un pago"), "received": m13, "recipient": MessageLookupByLibrary.simpleMessage("Destinatario"), + "repeatNewPassword": + MessageLookupByLibrary.simpleMessage("Repeat New Password"), "reply": MessageLookupByLibrary.simpleMessage("Responder"), "rescan": MessageLookupByLibrary.simpleMessage("Escanear"), "rescanFrom": diff --git a/lib/generated/intl/messages_fr.dart b/lib/generated/intl/messages_fr.dart index a2cc104..165a1eb 100644 --- a/lib/generated/intl/messages_fr.dart +++ b/lib/generated/intl/messages_fr.dart @@ -192,8 +192,16 @@ class MessageLookup extends MessageLookupByLibrary { "Créez un nouveau contact et il apparaîtra ici"), "crypto": MessageLookupByLibrary.simpleMessage("Crypto"), "currency": MessageLookupByLibrary.simpleMessage("Devise"), + "currentPassword": + MessageLookupByLibrary.simpleMessage("Current password"), + "currentPasswordIncorrect": + MessageLookupByLibrary.simpleMessage("Current password incorrect"), "custom": MessageLookupByLibrary.simpleMessage("Personnaliser"), "dark": MessageLookupByLibrary.simpleMessage("Sombre"), + "databaseEncrypted": MessageLookupByLibrary.simpleMessage( + "Database Encrypted. Please Restart the App."), + "databasePassword": + MessageLookupByLibrary.simpleMessage("Database Password"), "databaseUpdatedPleaseRestartTheApp": MessageLookupByLibrary.simpleMessage("Redémarrer l\'appli SVP"), "date": MessageLookupByLibrary.simpleMessage("Date"), @@ -221,6 +229,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Compte en double"), "editContact": MessageLookupByLibrary.simpleMessage("Changer le Contact"), + "encryptDatabase": + MessageLookupByLibrary.simpleMessage("Encrypt Database"), "encryptedBackup": m6, "encryptionKey": MessageLookupByLibrary.simpleMessage("Clé Publique"), "enterSecretShareIfAccountIsMultisignature": @@ -259,6 +269,8 @@ class MessageLookup extends MessageLookupByLibrary { "invalidAddress": MessageLookupByLibrary.simpleMessage("Adresse invalide"), "invalidKey": MessageLookupByLibrary.simpleMessage("Clé invalide"), + "invalidPassword": + MessageLookupByLibrary.simpleMessage("Invalid Password"), "invalidQrCode": m8, "key": MessageLookupByLibrary.simpleMessage("Clé"), "keyTool": MessageLookupByLibrary.simpleMessage("Clés Utilitaires"), @@ -300,6 +312,9 @@ class MessageLookup extends MessageLookupByLibrary { "nameIsEmpty": MessageLookupByLibrary.simpleMessage("Le nom est vide"), "newAccount": MessageLookupByLibrary.simpleMessage("Nouveau Compte"), "newLabel": MessageLookupByLibrary.simpleMessage("Nouveau"), + "newPassword": MessageLookupByLibrary.simpleMessage("New Password"), + "newPasswordsDoNotMatch": + MessageLookupByLibrary.simpleMessage("New passwords do not match"), "newSnapAddress": MessageLookupByLibrary.simpleMessage( "Nouvelle adresse instantanée"), "newSubAccount": @@ -365,6 +380,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Recevoir un payment"), "received": m13, "recipient": MessageLookupByLibrary.simpleMessage("Destinataire"), + "repeatNewPassword": + MessageLookupByLibrary.simpleMessage("Repeat New Password"), "reply": MessageLookupByLibrary.simpleMessage("Répondre"), "rescan": MessageLookupByLibrary.simpleMessage("Parcourir à nouveau"), "rescanFrom": diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index 4026a36..ae21ddf 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -3031,6 +3031,96 @@ class S { args: [], ); } + + /// `Encrypt Database` + String get encryptDatabase { + return Intl.message( + 'Encrypt Database', + name: 'encryptDatabase', + desc: '', + args: [], + ); + } + + /// `Current Password` + String get currentPassword { + return Intl.message( + 'Current Password', + name: 'currentPassword', + desc: '', + args: [], + ); + } + + /// `New Password` + String get newPassword { + return Intl.message( + 'New Password', + name: 'newPassword', + desc: '', + args: [], + ); + } + + /// `Repeat New Password` + String get repeatNewPassword { + return Intl.message( + 'Repeat New Password', + name: 'repeatNewPassword', + desc: '', + args: [], + ); + } + + /// `Database Password` + String get databasePassword { + return Intl.message( + 'Database Password', + name: 'databasePassword', + desc: '', + args: [], + ); + } + + /// `Current password incorrect` + String get currentPasswordIncorrect { + return Intl.message( + 'Current password incorrect', + name: 'currentPasswordIncorrect', + desc: '', + args: [], + ); + } + + /// `New passwords do not match` + String get newPasswordsDoNotMatch { + return Intl.message( + 'New passwords do not match', + name: 'newPasswordsDoNotMatch', + desc: '', + args: [], + ); + } + + /// `Database Encrypted. Please Restart the App.` + String get databaseEncrypted { + return Intl.message( + 'Database Encrypted. Please Restart the App.', + name: 'databaseEncrypted', + desc: '', + args: [], + ); + } + + /// `Invalid Password` + String get invalidPassword { + return Intl.message( + 'Invalid Password', + name: 'invalidPassword', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/lib/home.dart b/lib/home.dart index a526ea1..20220f5 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -6,16 +6,19 @@ import 'package:flutter/material.dart'; import 'package:flutter_foreground_task/flutter_foreground_task.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:warp_api/data_fb_generated.dart'; import 'package:warp_api/types.dart'; import 'package:warp_api/warp_api.dart'; import 'package:badges/badges.dart' as Badges; +import 'package:path/path.dart' as p; import 'about.dart'; import 'account.dart'; import 'animated_qr.dart'; import 'budget.dart'; +import 'coin/coins.dart'; import 'contact.dart'; import 'db.dart'; import 'history.dart'; @@ -194,6 +197,7 @@ class HomeInnerState extends State with SingleTickerProviderState PopupMenuButton( child: Text(s.advanced), itemBuilder: (_) => [ + if (!isMobile()) PopupMenuItem(child: Text(s.encryptDatabase), value: "Encrypt"), PopupMenuItem(child: Text(s.rewindToCheckpoint), value: "Rewind"), PopupMenuItem(child: Text(s.convertToWatchonly), enabled: active.canPay, value: "Cold"), PopupMenuItem(child: Text(s.signOffline), enabled: active.canPay, value: "Sign"), @@ -297,6 +301,9 @@ class HomeInnerState extends State with SingleTickerProviderState case "Expert": Navigator.of(context).pushNamed('/dev'); break; + case "Encrypt": + _encryptDb(); + break; case "Ledger": _ledger(); break; @@ -474,6 +481,56 @@ class HomeInnerState extends State with SingleTickerProviderState // } } + _encryptDb() async { + final s = S.of(context); + final hasPasswd = settings.dbPasswd.isNotEmpty; + final oldPasswdController = TextEditingController(); + final newPasswdController = TextEditingController(); + final repeatPasswdController = TextEditingController(); + final confirmed = await showDialog( + context: context, + barrierDismissible: false, + builder: (context) => + AlertDialog( + title: Text(s.encryptDatabase), + contentPadding: EdgeInsets.all(16), + content: Form(child: SingleChildScrollView(child: Column(children: [ + if (hasPasswd) TextFormField( + decoration: InputDecoration(labelText: s.currentPassword), + obscureText: true, + controller: oldPasswdController), + TextFormField( + decoration: InputDecoration(labelText: s.newPassword), + obscureText: true, + controller: newPasswdController), + TextFormField( + decoration: InputDecoration(labelText: s.repeatNewPassword), + obscureText: true, + controller: repeatPasswdController), + ]))), + actions: confirmButtons( + context, () => Navigator.of(context).pop(true), + cancelValue: false))) ?? + false; + if (confirmed) { + if (oldPasswdController.text != settings.dbPasswd) + showSnackBar(s.currentPasswordIncorrect); + else if (newPasswdController.text != repeatPasswdController.text) { + showSnackBar(s.newPasswordsDoNotMatch); + } + else { + final passwd = newPasswdController.text; + for (var c in coins) { + final tempPath = p.join(settings.tempDir, c.dbName); + WarpApi.cloneDbWithPasswd(c.coin, tempPath, passwd); + } + final prefs = await SharedPreferences.getInstance(); + prefs.setBool('recover', true); + showSnackBar(s.databaseEncrypted); + } + } + } + _convertToWatchOnly() { WarpApi.convertToWatchOnly(active.coin, active.id); active.canPay = false; diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index c663531..9d76f56 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -296,5 +296,14 @@ "signingPleaseWait": "Signing, please wait...", "sweep": "Sweep", "transparentKey": "Transparent Key", - "unifiedViewingKey": "Unified Viewing Key" + "unifiedViewingKey": "Unified Viewing Key", + "encryptDatabase": "Encrypt Database", + "currentPassword": "Current Password", + "newPassword": "New Password", + "repeatNewPassword": "Repeat New Password", + "databasePassword": "Database Password", + "currentPasswordIncorrect": "Current password incorrect", + "newPasswordsDoNotMatch": "New passwords do not match", + "databaseEncrypted": "Database Encrypted. Please Restart the App.", + "invalidPassword": "Invalid Password" } diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index 1c2bdb5..b1a994c 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -294,5 +294,14 @@ "signingPleaseWait": "Firmando", "sweep": "Barrer", "transparentKey": "Transparente Clavo", - "unifiedViewingKey": "Clave de visualización Unidad" + "unifiedViewingKey": "Clave de visualización Unidad", + "encryptDatabase": "Encrypt Database", + "currentPassword": "Current password", + "newPassword": "New Password", + "repeatNewPassword": "Repeat New Password", + "databasePassword": "Database Password", + "currentPasswordIncorrect": "Current password incorrect", + "newPasswordsDoNotMatch": "New passwords do not match", + "databaseEncrypted": "Database Encrypted. Please Restart the App.", + "invalidPassword": "Invalid Password" } diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 7131964..c87bd90 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -294,5 +294,14 @@ "signingPleaseWait": "Signature en cours...", "sweep": "Balayer", "transparentKey": "Clé Transparente", - "unifiedViewingKey": "Clé publique unifiée" + "unifiedViewingKey": "Clé publique unifiée", + "encryptDatabase": "Encrypt Database", + "currentPassword": "Current password", + "newPassword": "New Password", + "repeatNewPassword": "Repeat New Password", + "databasePassword": "Database Password", + "currentPasswordIncorrect": "Current password incorrect", + "newPasswordsDoNotMatch": "New passwords do not match", + "databaseEncrypted": "Database Encrypted. Please Restart the App.", + "invalidPassword": "Invalid Password" } diff --git a/lib/main.dart b/lib/main.dart index 245d9b0..74afd6f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,7 +8,6 @@ import 'dart:ui'; import 'package:app_links/app_links.dart'; import 'package:camera/camera.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:path/path.dart' as p; import 'package:csv/csv.dart'; import 'package:currency_text_input_formatter/currency_text_input_formatter.dart'; @@ -212,11 +211,6 @@ void main() async { if (!isMobile()) { await windowManager.ensureInitialized(); - final secureStorage = FlutterSecureStorage(); - await secureStorage.write(key: 'TEST_KEY', value: '1000'); - final v = await secureStorage.read(key: 'TEST_KEY'); - print(v); - final prefs = await SharedPreferences.getInstance(); final width = prefs.getDouble('width'); final height = prefs.getDouble('height'); @@ -391,9 +385,20 @@ class ZWalletAppState extends State { _setProgress(0, 'Mempool'); print("db path $dbPath"); WarpApi.mempoolRun(unconfirmedBalancePort.sendPort.nativePort); + + final c = coins.first; + if (!isMobile()) { + if (!WarpApi.decryptDb(c.dbFullPath, '')) { + final passwd = await getDbPasswd(context, c.dbFullPath); + if (passwd != null) { + settings.dbPasswd = passwd; + } + } + } + for (var c in coins) { _setProgress(0.2 * (c.coin+1), 'Initializing ${c.ticker}'); - await compute(_initWallet, c); + await compute(_initWallet, { 'coin': c, 'passwd': settings.dbPasswd }); } _setProgress(0.7, 'Restoring Active Account'); @@ -451,7 +456,10 @@ class ZWalletAppState extends State { return false; } - static void _initWallet(CoinBase c) { + static void _initWallet(Map args) { + CoinBase c = args['coin']; + String passwd = args['passwd']; + WarpApi.setDbPasswd(c.coin, passwd); WarpApi.migrateWallet(c.coin, c.dbFullPath); WarpApi.initWallet(c.coin, c.dbFullPath); try { @@ -915,7 +923,7 @@ Future getDataPath() async { String? home; if (Platform.isAndroid) home = (await getApplicationDocumentsDirectory()).parent.path; if (Platform.isWindows) home = Platform.environment['LOCALAPPDATA']; - if (Platform.isLinux) home = Platform.environment['XDG_DATA_HOME']; + if (Platform.isLinux) home = Platform.environment['XDG_DATA_HOME'] ?? Platform.environment['HOME']; if (Platform.isMacOS) home = Platform.environment['HOME']; final h = home ?? ""; return h; @@ -967,3 +975,37 @@ class NotificationController { void resetApp() { WarpApi.truncateData(); } + +Future getDbPasswd(BuildContext context, String dbPath) async { + final s = S.of(context); + final passwdController = TextEditingController(); + final checkPasswd = (String? v) { + final valid = WarpApi.decryptDb(dbPath, passwdController.text); + if (!valid) return s.invalidPassword; + return null; + }; + final formKey = GlobalKey(); + + final confirmed = await showDialog( + context: context, + barrierColor: Colors.black, + builder: (context) { + return AlertDialog( + content: Container( + width: double.maxFinite, + child: SingleChildScrollView(child: Form(key: formKey, child: Column(children: [ + TextFormField( + decoration: InputDecoration(labelText: s.databasePassword), + controller: passwdController, + validator: checkPasswd, + obscureText: true, + ), + ])))), + actions: confirmButtons(context, () { + if (formKey.currentState!.validate()) + Navigator.of(context).pop(true); + }, okLabel: s.ok), + ); + }) ?? false; + return confirmed ? passwdController.text : null; +} diff --git a/lib/settings.dart b/lib/settings.dart index 8ca1282..cd5ea0f 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -152,13 +152,6 @@ class SettingsState extends State _needAuth = true; }, onSaved: _onProtectOpen)), - // if (coin.supportsUA) - // Expanded( - // child: FormBuilderCheckbox( - // name: 'use_ua', - // title: Text(s.useUa), - // initialValue: settings.useUA, - // onSaved: _onUseUA)), ]), if (!simpleMode) @@ -304,6 +297,7 @@ class SettingsState extends State keyboardType: TextInputType.number, controller: _gapLimitController, onSaved: _onGapLimit), + Padding(padding: EdgeInsets.symmetric(vertical: 8)), ButtonBar(children: confirmButtons(context, _onSave)) ])))))); } diff --git a/lib/store.dart b/lib/store.dart index 3c3d058..f809b25 100644 --- a/lib/store.dart +++ b/lib/store.dart @@ -221,6 +221,8 @@ abstract class _Settings with Store { @observable int minPrivacyLevel = 0; + String dbPasswd = ""; + @action Future restore() async { if (Platform.isIOS) SharedPreferencesIOS.registerWith(); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index fe0ced2..026cff7 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -20,9 +19,6 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) awesome_notifications_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "AwesomeNotificationsPlugin"); awesome_notifications_plugin_register_with_registrar(awesome_notifications_registrar); - g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); - flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); g_autoptr(FlPluginRegistrar) screen_retriever_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin"); screen_retriever_plugin_register_with_registrar(screen_retriever_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index dc229ec..17f3601 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -5,7 +5,6 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_linux awesome_notifications - flutter_secure_storage_linux screen_retriever url_launcher_linux window_manager diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index f3ac507..3a3d8a5 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,7 +9,6 @@ import app_links import audioplayers_darwin import awesome_notifications import connectivity_plus_macos -import flutter_secure_storage_macos import network_info_plus_macos import path_provider_foundation import screen_retriever @@ -23,7 +22,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) AwesomeNotificationsPlugin.register(with: registry.registrar(forPlugin: "AwesomeNotificationsPlugin")) ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) - FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 8a944a6..a11b75a 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -8,8 +8,6 @@ PODS: - connectivity_plus_macos (0.0.1): - FlutterMacOS - ReachabilitySwift - - flutter_secure_storage_macos (6.1.1): - - FlutterMacOS - FlutterMacOS (1.0.0) - network_info_plus_macos (0.0.1): - FlutterMacOS @@ -34,7 +32,6 @@ DEPENDENCIES: - audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos`) - awesome_notifications (from `Flutter/ephemeral/.symlinks/plugins/awesome_notifications/macos`) - connectivity_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos`) - - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - network_info_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/network_info_plus_macos/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos`) @@ -57,8 +54,6 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/awesome_notifications/macos connectivity_plus_macos: :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos - flutter_secure_storage_macos: - :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos FlutterMacOS: :path: Flutter/ephemeral network_info_plus_macos: @@ -81,7 +76,6 @@ SPEC CHECKSUMS: audioplayers_darwin: dcad41de4fbd0099cb3749f7ab3b0cb8f70b810c awesome_notifications: 428f5c15a700b117418aed09e29c21c5806fcf69 connectivity_plus_macos: f6e86fd000e971d361e54b5afcadc8c8fa773308 - flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 network_info_plus_macos: d2b9e6c01c291449b91a584217aa53b113847dbd path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852 @@ -94,4 +88,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 -COCOAPODS: 1.11.3 +COCOAPODS: 1.12.0 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 90cf1c6..2947b61 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -582,12 +582,13 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NAME)"; + DEVELOPMENT_TEAM = 26RX6RJ8ED; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = me.hanh.ywallet; + PRODUCT_BUNDLE_IDENTIFIER = me.hanh.ywallet.ios; PROVISIONING_PROFILE_SPECIFIER = ""; STRIP_STYLE = "non-global"; SWIFT_VERSION = 5.0; diff --git a/native/zcash-sync b/native/zcash-sync index 1a2dbc9..17301a6 160000 --- a/native/zcash-sync +++ b/native/zcash-sync @@ -1 +1 @@ -Subproject commit 1a2dbc991fe877783aa7ef3c38ab323a0d220aa5 +Subproject commit 17301a6900fdc0a274c9631b2ffb59394829ce3e diff --git a/packages/warp_api_ffi/lib/warp_api.dart b/packages/warp_api_ffi/lib/warp_api.dart index e408441..fc574d7 100644 --- a/packages/warp_api_ffi/lib/warp_api.dart +++ b/packages/warp_api_ffi/lib/warp_api.dart @@ -38,6 +38,11 @@ Pointer toNativeBytes(Uint8List bytes) { return ptr; } +bool unwrapResultBool(CResult_bool r) { + if (r.error != nullptr) throw convertCString(r.error); + return r.value != 0; +} + int unwrapResultU8(CResult_u8 r) { if (r.error != nullptr) throw convertCString(r.error); return r.value; @@ -313,7 +318,11 @@ class WarpApi { syncHistoricalPricesIsolateFn, SyncHistoricalPricesParams(currency)); } - static updateLWD(int coin, String url) { + static void setDbPasswd(int coin, String passwd) { + warp_api_lib.set_coin_passwd(coin, toNative(passwd)); + } + + static void updateLWD(int coin, String url) { warp_api_lib.set_coin_lwd_url(coin, url.toNativeUtf8().cast()); } @@ -569,6 +578,14 @@ class WarpApi { static void clearTxDetails(int coin, int account) { warp_api_lib.clear_tx_details(coin, account); } + + static void cloneDbWithPasswd(int coin, String tempPath, String passwd) { + warp_api_lib.clone_db_with_passwd(coin, toNative(tempPath), toNative(passwd)); + } + + static bool decryptDb(String dbPath, String passwd) { + return unwrapResultBool(warp_api_lib.decrypt_db(toNative(dbPath), toNative(passwd))); + } } String signOnlyIsolateFn(SignOnlyParams params) { diff --git a/packages/warp_api_ffi/lib/warp_api_generated.dart b/packages/warp_api_ffi/lib/warp_api_generated.dart index 3bcc950..43f0424 100644 --- a/packages/warp_api_ffi/lib/warp_api_generated.dart +++ b/packages/warp_api_ffi/lib/warp_api_generated.dart @@ -152,6 +152,21 @@ class NativeLibrary { late final _dart_get_lwd_url _get_lwd_url = _get_lwd_url_ptr.asFunction<_dart_get_lwd_url>(); + void set_coin_passwd( + int coin, + ffi.Pointer passwd, + ) { + return _set_coin_passwd( + coin, + passwd, + ); + } + + late final _set_coin_passwd_ptr = + _lookup>('set_coin_passwd'); + late final _dart_set_coin_passwd _set_coin_passwd = + _set_coin_passwd_ptr.asFunction<_dart_set_coin_passwd>(); + void reset_app() { return _reset_app(); } @@ -1279,6 +1294,39 @@ class NativeLibrary { late final _dart_get_checkpoints _get_checkpoints = _get_checkpoints_ptr.asFunction<_dart_get_checkpoints>(); + CResult_bool decrypt_db( + ffi.Pointer db_path, + ffi.Pointer passwd, + ) { + return _decrypt_db( + db_path, + passwd, + ); + } + + late final _decrypt_db_ptr = + _lookup>('decrypt_db'); + late final _dart_decrypt_db _decrypt_db = + _decrypt_db_ptr.asFunction<_dart_decrypt_db>(); + + CResult_u8 clone_db_with_passwd( + int coin, + ffi.Pointer temp_path, + ffi.Pointer passwd, + ) { + return _clone_db_with_passwd( + coin, + temp_path, + passwd, + ); + } + + late final _clone_db_with_passwd_ptr = + _lookup>( + 'clone_db_with_passwd'); + late final _dart_clone_db_with_passwd _clone_db_with_passwd = + _clone_db_with_passwd_ptr.asFunction<_dart_clone_db_with_passwd>(); + int has_cuda() { return _has_cuda(); } @@ -1364,6 +1412,16 @@ class CResult_u64 extends ffi.Struct { external int len; } +class CResult_bool extends ffi.Struct { + @ffi.Int8() + external int value; + + external ffi.Pointer error; + + @ffi.Uint32() + external int len; +} + const int EXPIRY_HEIGHT_OFFSET = 50; const int QR_DATA_SIZE = 256; @@ -1550,6 +1608,16 @@ typedef _dart_get_lwd_url = ffi.Pointer Function( int coin, ); +typedef _c_set_coin_passwd = ffi.Void Function( + ffi.Uint8 coin, + ffi.Pointer passwd, +); + +typedef _dart_set_coin_passwd = void Function( + int coin, + ffi.Pointer passwd, +); + typedef _c_reset_app = ffi.Void Function(); typedef _dart_reset_app = void Function(); @@ -2298,6 +2366,28 @@ typedef _dart_get_checkpoints = CResult______u8 Function( int coin, ); +typedef _c_decrypt_db = CResult_bool Function( + ffi.Pointer db_path, + ffi.Pointer passwd, +); + +typedef _dart_decrypt_db = CResult_bool Function( + ffi.Pointer db_path, + ffi.Pointer passwd, +); + +typedef _c_clone_db_with_passwd = CResult_u8 Function( + ffi.Uint8 coin, + ffi.Pointer temp_path, + ffi.Pointer passwd, +); + +typedef _dart_clone_db_with_passwd = CResult_u8 Function( + int coin, + ffi.Pointer temp_path, + ffi.Pointer passwd, +); + typedef _c_has_cuda = ffi.Int8 Function(); typedef _dart_has_cuda = int Function(); diff --git a/packages/warp_api_ffi/pubspec.yaml b/packages/warp_api_ffi/pubspec.yaml index 99f0061..839b11b 100644 --- a/packages/warp_api_ffi/pubspec.yaml +++ b/packages/warp_api_ffi/pubspec.yaml @@ -30,7 +30,7 @@ ffigen: - '../../native/zcash-sync/binding.h' # On MacOS llvm-path: - - '/opt/homebrew/Cellar/llvm/15.0.6' + - '/opt/homebrew/Cellar/llvm/15.0.7_1' # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/pubspec.lock b/pubspec.lock index 076aa3c..b3963bf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -685,54 +685,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.0" - flutter_secure_storage: - dependency: "direct main" - description: - name: flutter_secure_storage - sha256: "98352186ee7ad3639ccc77ad7924b773ff6883076ab952437d20f18a61f0a7c5" - url: "https://pub.dev" - source: hosted - version: "8.0.0" - flutter_secure_storage_linux: - dependency: transitive - description: - name: flutter_secure_storage_linux - sha256: "0912ae29a572230ad52d8a4697e5518d7f0f429052fd51df7e5a7952c7efe2a3" - url: "https://pub.dev" - source: hosted - version: "1.1.3" - flutter_secure_storage_macos: - dependency: transitive - description: - name: flutter_secure_storage_macos - sha256: "083add01847fc1c80a07a08e1ed6927e9acd9618a35e330239d4422cd2a58c50" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - flutter_secure_storage_platform_interface: - dependency: transitive - description: - name: flutter_secure_storage_platform_interface - sha256: b3773190e385a3c8a382007893d678ae95462b3c2279e987b55d140d3b0cb81b - url: "https://pub.dev" - source: hosted - version: "1.0.1" - flutter_secure_storage_web: - dependency: transitive - description: - name: flutter_secure_storage_web - sha256: "42938e70d4b872e856e678c423cc0e9065d7d294f45bc41fc1981a4eb4beaffe" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - flutter_secure_storage_windows: - dependency: transitive - description: - name: flutter_secure_storage_windows - sha256: fc2910ec9b28d60598216c29ea763b3a96c401f0ce1d13cdf69ccb0e5c93c3ee - url: "https://pub.dev" - source: hosted - version: "2.0.0" flutter_speed_dial: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index e9f7515..022dc17 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.3.5+390 +version: 1.3.5+392 environment: sdk: ">=2.12.0 <3.0.0" @@ -39,7 +39,6 @@ dependencies: rflutter_alert: ^2.0.4 sprintf: ^6.0.0 local_auth: ^2.1.2 - flutter_secure_storage: ^8.0.0 key_guardmanager: ^1.0.0 shared_preferences: ^2.0.7 shared_preferences_android: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 782e33e..0ce6f58 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -26,8 +25,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("AwesomeNotificationsPluginCApi")); ConnectivityPlusWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); - FlutterSecureStorageWindowsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); LocalAuthPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("LocalAuthPlugin")); NetworkInfoPlusWindowsPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 4766bac..719ab99 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -7,7 +7,6 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_windows awesome_notifications connectivity_plus_windows - flutter_secure_storage_windows local_auth_windows network_info_plus_windows screen_retriever