diff --git a/cw_monero/pubspec.lock b/cw_monero/pubspec.lock index 9a700609c..f1510b4bc 100644 --- a/cw_monero/pubspec.lock +++ b/cw_monero/pubspec.lock @@ -511,8 +511,8 @@ packages: dependency: "direct main" description: path: "impls/monero.dart" - ref: "629fa4a346ca29d5ed18a2b44895b8858ba7c9f7" - resolved-ref: "629fa4a346ca29d5ed18a2b44895b8858ba7c9f7" + ref: "65608c09e9093f1cd42c6afd8e9131016c82574b" + resolved-ref: "65608c09e9093f1cd42c6afd8e9131016c82574b" url: "https://github.com/mrcyjanek/monero_c" source: git version: "0.0.0" diff --git a/cw_monero/pubspec.yaml b/cw_monero/pubspec.yaml index 37835d1ff..6a96e41cc 100644 --- a/cw_monero/pubspec.yaml +++ b/cw_monero/pubspec.yaml @@ -25,7 +25,7 @@ dependencies: monero: git: url: https://github.com/mrcyjanek/monero_c - ref: 629fa4a346ca29d5ed18a2b44895b8858ba7c9f7 + ref: 65608c09e9093f1cd42c6afd8e9131016c82574b path: impls/monero.dart mutex: ^3.1.0 ledger_flutter_plus: ^1.4.1 diff --git a/cw_wownero/pubspec.lock b/cw_wownero/pubspec.lock index 7e520fd50..44182ed9f 100644 --- a/cw_wownero/pubspec.lock +++ b/cw_wownero/pubspec.lock @@ -471,8 +471,8 @@ packages: dependency: "direct main" description: path: "impls/monero.dart" - ref: "629fa4a346ca29d5ed18a2b44895b8858ba7c9f7" - resolved-ref: "629fa4a346ca29d5ed18a2b44895b8858ba7c9f7" + ref: "65608c09e9093f1cd42c6afd8e9131016c82574b" + resolved-ref: "65608c09e9093f1cd42c6afd8e9131016c82574b" url: "https://github.com/mrcyjanek/monero_c" source: git version: "0.0.0" diff --git a/cw_wownero/pubspec.yaml b/cw_wownero/pubspec.yaml index f5a83ce48..a57c2f25b 100644 --- a/cw_wownero/pubspec.yaml +++ b/cw_wownero/pubspec.yaml @@ -25,7 +25,7 @@ dependencies: monero: git: url: https://github.com/mrcyjanek/monero_c - ref: 629fa4a346ca29d5ed18a2b44895b8858ba7c9f7 # monero_c hash + ref: 65608c09e9093f1cd42c6afd8e9131016c82574b # monero_c hash path: impls/monero.dart mutex: ^3.1.0 diff --git a/cw_zano/lib/api/model/create_wallet_result.dart b/cw_zano/lib/api/model/create_wallet_result.dart index 91b6fc00b..236911db1 100644 --- a/cw_zano/lib/api/model/create_wallet_result.dart +++ b/cw_zano/lib/api/model/create_wallet_result.dart @@ -1,27 +1,34 @@ import 'package:cw_zano/api/model/recent_history.dart'; import 'package:cw_zano/api/model/wi.dart'; +import 'package:cw_zano/zano_wallet.dart'; class CreateWalletResult { final String name; final String pass; final RecentHistory recentHistory; final bool recovered; - final String seed; final int walletFileSize; final int walletId; final int walletLocalBcSize; final Wi wi; + final String privateSpendKey; + final String privateViewKey; + final String publicSpendKey; + final String publicViewKey; CreateWalletResult( {required this.name, required this.pass, required this.recentHistory, required this.recovered, - required this.seed, required this.walletFileSize, required this.walletId, required this.walletLocalBcSize, - required this.wi}); + required this.wi, + required this.privateSpendKey, + required this.privateViewKey, + required this.publicSpendKey, + required this.publicViewKey}); factory CreateWalletResult.fromJson(Map<String, dynamic> json) => CreateWalletResult( @@ -30,10 +37,16 @@ class CreateWalletResult { recentHistory: RecentHistory.fromJson( json['recent_history'] as Map<String, dynamic>? ?? {}), recovered: json['recovered'] as bool? ?? false, - seed: json['seed'] as String? ?? '', walletFileSize: json['wallet_file_size'] as int? ?? 0, walletId: json['wallet_id'] as int? ?? 0, walletLocalBcSize: json['wallet_local_bc_size'] as int? ?? 0, wi: Wi.fromJson(json['wi'] as Map<String, dynamic>? ?? {}), + privateSpendKey: json['private_spend_key'] as String? ?? '', + privateViewKey: json['private_view_key'] as String? ?? '', + publicSpendKey: json['public_spend_key'] as String? ?? '', + publicViewKey: json['public_view_key'] as String? ?? '', ); + Future<String> seed(ZanoWalletBase api) { + return api.getSeed(); + } } diff --git a/cw_zano/lib/api/model/wi_extended.dart b/cw_zano/lib/api/model/wi_extended.dart index ab7e8efbd..ef2745992 100644 --- a/cw_zano/lib/api/model/wi_extended.dart +++ b/cw_zano/lib/api/model/wi_extended.dart @@ -1,17 +1,21 @@ +import 'package:cw_zano/zano_wallet.dart'; + class WiExtended { - final String seed; final String spendPrivateKey; final String spendPublicKey; final String viewPrivateKey; final String viewPublicKey; - WiExtended({required this.seed, required this.spendPrivateKey, required this.spendPublicKey, required this.viewPrivateKey, required this.viewPublicKey}); + WiExtended({required this.spendPrivateKey, required this.spendPublicKey, required this.viewPrivateKey, required this.viewPublicKey}); factory WiExtended.fromJson(Map<String, dynamic> json) => WiExtended( - seed: json['seed'] as String? ?? '', spendPrivateKey: json['spend_private_key'] as String? ?? '', spendPublicKey: json['spend_public_key'] as String? ?? '', viewPrivateKey: json['view_private_key'] as String? ?? '', viewPublicKey: json['view_public_key'] as String? ?? '', ); + + Future<String> seed(ZanoWalletBase api) { + return api.getSeed(); + } } \ No newline at end of file diff --git a/cw_zano/lib/zano_wallet.dart b/cw_zano/lib/zano_wallet.dart index b2283b082..7f68b71e6 100644 --- a/cw_zano/lib/zano_wallet.dart +++ b/cw_zano/lib/zano_wallet.dart @@ -82,6 +82,9 @@ abstract class ZanoWalletBase @override String seed = ''; + @override + String? passphrase = ''; + @override ZanoWalletKeys keys = ZanoWalletKeys( privateSpendKey: '', privateViewKey: '', publicSpendKey: '', publicViewKey: ''); @@ -133,6 +136,11 @@ abstract class ZanoWalletBase final createWalletResult = await wallet.createWallet(path, credentials.password!); await wallet.initWallet(); await wallet.parseCreateWalletResult(createWalletResult); + if (credentials.passphrase != null) { + await wallet.setPassphrase(credentials.passphrase!); + wallet.seed = await createWalletResult.seed(wallet); + wallet.passphrase = await wallet.getPassphrase(); + } await wallet.init(createWalletResult.wi.address); return wallet; } @@ -146,6 +154,11 @@ abstract class ZanoWalletBase path, credentials.password!, credentials.mnemonic, credentials.passphrase); await wallet.initWallet(); await wallet.parseCreateWalletResult(createWalletResult); + if (credentials.passphrase != null) { + await wallet.setPassphrase(credentials.passphrase!); + wallet.seed = await createWalletResult.seed(wallet); + wallet.passphrase = await wallet.getPassphrase(); + } await wallet.init(createWalletResult.wi.address); return wallet; } @@ -172,7 +185,15 @@ abstract class ZanoWalletBase Future<void> parseCreateWalletResult(CreateWalletResult result) async { hWallet = result.walletId; - seed = result.seed; + seed = await result.seed(this); + keys = ZanoWalletKeys( + privateSpendKey: result.privateSpendKey, + privateViewKey: result.privateViewKey, + publicSpendKey: result.publicSpendKey, + publicViewKey: result.publicViewKey, + ); + passphrase = await getPassphrase(); + printV('setting hWallet = ${result.walletId}'); walletAddresses.address = result.wi.address; await loadAssets(result.wi.balances, maxRetries: _maxLoadAssetsRetries); @@ -511,7 +532,7 @@ abstract class ZanoWalletBase // we can call getWalletInfo ONLY if getWalletStatus returns NOT is in long refresh and wallet state is 2 (ready) if (!walletStatus.isInLongRefresh && walletStatus.walletState == 2) { final walletInfo = await getWalletInfo(); - seed = walletInfo.wiExtended.seed; + seed = await walletInfo.wiExtended.seed(this); keys = ZanoWalletKeys( privateSpendKey: walletInfo.wiExtended.spendPrivateKey, privateViewKey: walletInfo.wiExtended.viewPrivateKey, diff --git a/cw_zano/lib/zano_wallet_api.dart b/cw_zano/lib/zano_wallet_api.dart index 4947ff3b5..f2c5469c4 100644 --- a/cw_zano/lib/zano_wallet_api.dart +++ b/cw_zano/lib/zano_wallet_api.dart @@ -26,6 +26,7 @@ import 'package:ffi/ffi.dart'; import 'package:json_bigint/json_bigint.dart'; import 'package:monero/zano.dart' as zano; import 'package:monero/src/generated_bindings_zano.g.dart' as zanoapi; +import 'package:path/path.dart' as p; mixin ZanoWalletApi { static const _maxReopenAttempts = 5; @@ -45,7 +46,7 @@ mixin ZanoWalletApi { void setPassword(String password) => zano.PlainWallet_resetWalletPassword(hWallet, password); void closeWallet(int? walletToClose, {bool force = false}) async { - printV('close_wallet ${walletToClose ?? hWallet}'); + printV('close_wallet ${walletToClose ?? hWallet}: $force'); if (Platform.isWindows || force) { final result = await _closeWallet(walletToClose ?? hWallet); printV('close_wallet result $result'); @@ -53,10 +54,9 @@ mixin ZanoWalletApi { } } - bool isInit = false; + static bool isInit = false; Future<bool> initWallet() async { - // pathForWallet(name: , type: type) if (isInit) return true; final result = zano.PlainWallet_init("", "", 0); isInit = true; @@ -68,6 +68,68 @@ mixin ZanoWalletApi { return true; } + Future<Directory> getWalletDir() async { + final walletInfoResult = await getWalletInfo(); + return Directory(p.dirname(walletInfoResult.wi.path)); + } + + Future<File> _getWalletSecretsFile() async { + final dir = await getWalletDir(); + final file = File(p.join(dir.path, "zano-secrets.json.bin")); + return file; + } + + Future<Map<String, dynamic>> _getSecrets() async { + final file = await _getWalletSecretsFile(); + if (!file.existsSync()) { + return {}; + } + final data = file.readAsBytesSync(); + final b64 = convert.base64.encode(data); + final respStr = await invokeMethod("decrypt_data", {"buff": "$b64"}); + final resp = convert.json.decode(respStr); + final dataBytes = convert.base64.decode(resp["result"]["res_buff"] as String); + final dataStr = convert.utf8.decode(dataBytes); + final dataObject = convert.json.decode(dataStr); + return dataObject as Map<String, dynamic>; + } + + Future<void> _setSecrets(Map<String, dynamic> data) async { + final dataStr = convert.json.encode(data); + final b64 = convert.base64.encode(convert.utf8.encode(dataStr)); + final respStr = await invokeMethod("encrypt_data", {"buff": "$b64"}); + final resp = convert.json.decode(respStr); + final dataBytes = convert.base64.decode(resp["result"]["res_buff"] as String); + final file = await _getWalletSecretsFile(); + file.writeAsBytesSync(dataBytes); + } + + Future<String?> _getWalletSecret(String key) async { + final secrets = await _getSecrets(); + return secrets[key] as String?; + } + + Future<void> _setWalletSecret(String key, String value) async { + final secrets = await _getSecrets(); + secrets[key] = value; + await _setSecrets(secrets); + } + + Future<String?> getPassphrase() async { + return await _getWalletSecret("passphrase"); + } + + Future<void> setPassphrase(String passphrase) { + return _setWalletSecret("passphrase", passphrase); + } + + Future<String> getSeed() async { + final passphrase = await getPassphrase(); + final respStr = await invokeMethod("get_restore_info", {"seed_password": passphrase??""}); + final resp = convert.json.decode(respStr); + return resp["result"]["seed_phrase"] as String; + } + Future<GetWalletInfoResult> getWalletInfo() async { final json = await _getWalletInfo(hWallet); final result = GetWalletInfoResult.fromJson(jsonDecode(json)); @@ -192,7 +254,7 @@ mixin ZanoWalletApi { Future<StoreResult?> store() async { try { - final json = await invokeMethod('store', '{}'); + final json = await invokeMethod('store', {}); final map = jsonDecode(json) as Map<String, dynamic>?; _checkForErrors(map); return StoreResult.fromJson(map!['result'] as Map<String, dynamic>); @@ -247,12 +309,12 @@ mixin ZanoWalletApi { } final result = CreateWalletResult.fromJson(map!['result'] as Map<String, dynamic>); openWalletCache[path] = result; - printV('create_wallet ${result.name} ${result.seed}'); + printV('create_wallet ${result.name}'); return result; } Future<CreateWalletResult> restoreWalletFromSeed(String path, String password, String seed, String? passphrase) async { - printV('restore_wallet path $path password ${_shorten(password)} seed ${_shorten(seed)}'); + printV('restore_wallet path $path'); final json = zano.PlainWallet_restore(seed, path, password, passphrase??''); final map = jsonDecode(json) as Map<String, dynamic>?; if (map?['error'] != null) { @@ -274,8 +336,8 @@ mixin ZanoWalletApi { return result; } - Future<CreateWalletResult>loadWallet(String path, String password, [int attempt = 0]) async { - printV('load_wallet1 path $path password ${_shorten(password)}'); + Future<CreateWalletResult> loadWallet(String path, String password, [int attempt = 0]) async { + printV('load_wallet1 path $path'); final String json; try { json = zano.PlainWallet_open(path, password); @@ -283,7 +345,7 @@ mixin ZanoWalletApi { printV('error in loadingWallet $e'); rethrow; } - // printV('load_wallet2: $json'); + final map = jsonDecode(json) as Map<String, dynamic>?; if (map?['error'] != null) { final code = map?['error']!['code'] ?? ''; @@ -435,10 +497,8 @@ Future<String> _getWalletInfo(int hWallet) async { } Future<String> _setupNode(int hWallet, String nodeUrl) async { - final resp = await callSyncMethod("reset_connection_url", hWallet, nodeUrl); - printV(resp); - final resp2 = await callSyncMethod("run_wallet", hWallet, ""); - printV(resp2); + await callSyncMethod("reset_connection_url", hWallet, nodeUrl); + await callSyncMethod("run_wallet", hWallet, ""); return "OK"; } diff --git a/cw_zano/lib/zano_wallet_service.dart b/cw_zano/lib/zano_wallet_service.dart index 5bb7ed266..879402cff 100644 --- a/cw_zano/lib/zano_wallet_service.dart +++ b/cw_zano/lib/zano_wallet_service.dart @@ -14,7 +14,7 @@ import 'package:hive/hive.dart'; import 'package:monero/zano.dart' as zano; class ZanoNewWalletCredentials extends WalletCredentials { - ZanoNewWalletCredentials({required String name, String? password}) : super(name: name, password: password); + ZanoNewWalletCredentials({required String name, String? password, required String? passphrase}) : super(name: name, password: password, passphrase: passphrase); } class ZanoRestoreWalletFromSeedCredentials extends WalletCredentials { diff --git a/cw_zano/pubspec.lock b/cw_zano/pubspec.lock index 7ea7e6f86..74a87487e 100644 --- a/cw_zano/pubspec.lock +++ b/cw_zano/pubspec.lock @@ -476,8 +476,8 @@ packages: dependency: "direct main" description: path: "impls/monero.dart" - ref: "629fa4a346ca29d5ed18a2b44895b8858ba7c9f7" - resolved-ref: "629fa4a346ca29d5ed18a2b44895b8858ba7c9f7" + ref: "65608c09e9093f1cd42c6afd8e9131016c82574b" + resolved-ref: "65608c09e9093f1cd42c6afd8e9131016c82574b" url: "https://github.com/mrcyjanek/monero_c" source: git version: "0.0.0" diff --git a/cw_zano/pubspec.yaml b/cw_zano/pubspec.yaml index 136f38fde..111731f4f 100644 --- a/cw_zano/pubspec.yaml +++ b/cw_zano/pubspec.yaml @@ -26,7 +26,7 @@ dependencies: monero: git: url: https://github.com/mrcyjanek/monero_c - ref: 629fa4a346ca29d5ed18a2b44895b8858ba7c9f7 # monero_c hash + ref: 65608c09e9093f1cd42c6afd8e9131016c82574b # monero_c hash path: impls/monero.dart dev_dependencies: flutter_test: diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart index a942be00d..e5853570e 100644 --- a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart +++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart @@ -202,7 +202,7 @@ class _AdvancedPrivacySettingsBodyState extends State<_AdvancedPrivacySettingsBo ); return Container(); }), - if (widget.privacySettingsViewModel.hasPassphraseOption(widget.isFromRestore)) + if (widget.privacySettingsViewModel.hasPassphraseOption) Padding( padding: EdgeInsets.all(24), child: Form( diff --git a/lib/src/screens/wallet_keys/wallet_keys_page.dart b/lib/src/screens/wallet_keys/wallet_keys_page.dart index a8a35096a..ab6762f8d 100644 --- a/lib/src/screens/wallet_keys/wallet_keys_page.dart +++ b/lib/src/screens/wallet_keys/wallet_keys_page.dart @@ -160,8 +160,11 @@ class _WalletKeysPageBodyState extends State<WalletKeysPageBody> Widget _buildSeedTab(BuildContext context, bool isLegacySeed) { return Column( children: [ - if (isLegacySeedOnly || isLegacySeed) _buildHeightBox(), - const SizedBox(height: 20), + if (isLegacySeedOnly || isLegacySeed) + ...[ + _buildHeightBox(), + const SizedBox(height: 20), + ], (_buildPassphraseBox() ?? Container()), if (widget.walletKeysViewModel.passphrase.isNotEmpty) const SizedBox(height: 20), Expanded( diff --git a/lib/view_model/advanced_privacy_settings_view_model.dart b/lib/view_model/advanced_privacy_settings_view_model.dart index b6a9d58f9..14d7ad566 100644 --- a/lib/view_model/advanced_privacy_settings_view_model.dart +++ b/lib/view_model/advanced_privacy_settings_view_model.dart @@ -71,7 +71,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store { bool get isNanoSeedTypeOptionsEnabled => [WalletType.nano].contains(type); - bool hasPassphraseOption(bool isRestore) => [ + bool get hasPassphraseOption => [ WalletType.bitcoin, WalletType.litecoin, WalletType.bitcoinCash, @@ -80,7 +80,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store { WalletType.tron, WalletType.monero, WalletType.wownero, - if (isRestore) WalletType.zano, + WalletType.zano, ].contains(type); @computed diff --git a/lib/view_model/wallet_new_vm.dart b/lib/view_model/wallet_new_vm.dart index f09f972cd..aa933eadc 100644 --- a/lib/view_model/wallet_new_vm.dart +++ b/lib/view_model/wallet_new_vm.dart @@ -175,6 +175,7 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store { return zano!.createZanoNewWalletCredentials( name: name, password: walletPassword, + passphrase: passphrase, ); case WalletType.none: throw Exception('Unexpected type: ${type.toString()}'); diff --git a/lib/zano/cw_zano.dart b/lib/zano/cw_zano.dart index a1cae19c8..19fec04e4 100644 --- a/lib/zano/cw_zano.dart +++ b/lib/zano/cw_zano.dart @@ -53,8 +53,8 @@ class CWZano extends Zano { } @override - WalletCredentials createZanoNewWalletCredentials({required String name, required String? password}) { - return ZanoNewWalletCredentials(name: name, password: password); + WalletCredentials createZanoNewWalletCredentials({required String name, required String? password, required String? passphrase}) { + return ZanoNewWalletCredentials(name: name, password: password, passphrase: passphrase); } @override diff --git a/scripts/prepare_moneroc.sh b/scripts/prepare_moneroc.sh index eefa9d5ef..ec2cb4908 100755 --- a/scripts/prepare_moneroc.sh +++ b/scripts/prepare_moneroc.sh @@ -8,7 +8,7 @@ if [[ ! -d "monero_c/.git" ]]; then git clone https://github.com/mrcyjanek/monero_c --branch master monero_c cd monero_c - git checkout 629fa4a346ca29d5ed18a2b44895b8858ba7c9f7 + git checkout 65608c09e9093f1cd42c6afd8e9131016c82574b git reset --hard git submodule update --init --force --recursive ./apply_patches.sh monero diff --git a/tool/configure.dart b/tool/configure.dart index 3a49438e4..7fb72d5e4 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -1443,7 +1443,7 @@ abstract class Zano { List<String> getWordList(String language); WalletCredentials createZanoRestoreWalletFromSeedCredentials({required String name, required String password, required String passphrase, required int height, required String mnemonic}); - WalletCredentials createZanoNewWalletCredentials({required String name, required String? password}); + WalletCredentials createZanoNewWalletCredentials({required String name, required String? password, required String? passphrase}); Map<String, String> getKeys(Object wallet); Object createZanoTransactionCredentials({required List<Output> outputs, required TransactionPriority priority, required CryptoCurrency currency}); double formatterIntAmountToDouble({required int amount, required CryptoCurrency currency, required bool forFee});