diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart index c4675df1c..3e4601eb3 100644 --- a/cw_bitcoin/lib/bitcoin_wallet.dart +++ b/cw_bitcoin/lib/bitcoin_wallet.dart @@ -1,4 +1,5 @@ import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; +import 'package:cw_bitcoin/encryption_file_utils.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:hive/hive.dart'; @@ -23,6 +24,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { required WalletInfo walletInfo, required Box unspentCoinsInfo, required Uint8List seedBytes, + required EncryptionFileUtils encryptionFileUtils, List? initialAddresses, ElectrumBalance? initialBalance, int initialRegularAddressIndex = 0, @@ -36,7 +38,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { initialAddresses: initialAddresses, initialBalance: initialBalance, seedBytes: seedBytes, - currency: CryptoCurrency.btc) { + currency: CryptoCurrency.btc, + encryptionFileUtils: encryptionFileUtils) { walletAddresses = BitcoinWalletAddresses( walletInfo, electrumClient: electrumClient, @@ -54,6 +57,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { required String password, required WalletInfo walletInfo, required Box unspentCoinsInfo, + required EncryptionFileUtils encryptionFileUtils, List? initialAddresses, ElectrumBalance? initialBalance, int initialRegularAddressIndex = 0, @@ -66,6 +70,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { unspentCoinsInfo: unspentCoinsInfo, initialAddresses: initialAddresses, initialBalance: initialBalance, + encryptionFileUtils: encryptionFileUtils, seedBytes: await mnemonicToSeedBytes(mnemonic), initialRegularAddressIndex: initialRegularAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex); @@ -76,8 +81,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { required WalletInfo walletInfo, required Box unspentCoinsInfo, required String password, + required EncryptionFileUtils encryptionFileUtils }) async { - final snp = await ElectrumWallletSnapshot.load(name, walletInfo.type, password); + final snp = await ElectrumWallletSnapshot.load(encryptionFileUtils, name, walletInfo.type, password); return BitcoinWallet( mnemonic: snp.mnemonic, password: password, @@ -86,6 +92,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { initialAddresses: snp.addresses, initialBalance: snp.balance, seedBytes: await mnemonicToSeedBytes(snp.mnemonic), + encryptionFileUtils: encryptionFileUtils, initialRegularAddressIndex: snp.regularAddressIndex, initialChangeAddressIndex: snp.changeAddressIndex); } diff --git a/cw_bitcoin/lib/bitcoin_wallet_service.dart b/cw_bitcoin/lib/bitcoin_wallet_service.dart index 398d68fc2..d9481b0b5 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_service.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_service.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic_is_incorrect_exception.dart'; import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart'; +import 'package:cw_bitcoin/encryption_file_utils.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_service.dart'; @@ -16,10 +17,11 @@ class BitcoinWalletService extends WalletService< BitcoinNewWalletCredentials, BitcoinRestoreWalletFromSeedCredentials, BitcoinRestoreWalletFromWIFCredentials> { - BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource); + BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect); final Box walletInfoSource; final Box unspentCoinsInfoSource; + final bool isDirect; @override WalletType getType() => WalletType.bitcoin; @@ -30,7 +32,8 @@ class BitcoinWalletService extends WalletService< mnemonic: await generateMnemonic(), password: credentials.password!, walletInfo: credentials.walletInfo!, - unspentCoinsInfo: unspentCoinsInfoSource); + unspentCoinsInfo: unspentCoinsInfoSource, + encryptionFileUtils: encryptionFileUtilsFor(isDirect)); await wallet.save(); await wallet.init(); return wallet; @@ -46,7 +49,8 @@ class BitcoinWalletService extends WalletService< (info) => info.id == WalletBase.idFor(name, getType()))!; final wallet = await BitcoinWalletBase.open( password: password, name: name, walletInfo: walletInfo, - unspentCoinsInfo: unspentCoinsInfoSource); + unspentCoinsInfo: unspentCoinsInfoSource, + encryptionFileUtils: encryptionFileUtilsFor(isDirect)); await wallet.init(); return wallet; } @@ -72,7 +76,8 @@ class BitcoinWalletService extends WalletService< password: credentials.password!, mnemonic: credentials.mnemonic, walletInfo: credentials.walletInfo!, - unspentCoinsInfo: unspentCoinsInfoSource); + unspentCoinsInfo: unspentCoinsInfoSource, + encryptionFileUtils: encryptionFileUtilsFor(isDirect)); await wallet.save(); await wallet.init(); return wallet; diff --git a/cw_bitcoin/lib/electrum_transaction_history.dart b/cw_bitcoin/lib/electrum_transaction_history.dart index 9174fb3f8..b8b7ad5ee 100644 --- a/cw_bitcoin/lib/electrum_transaction_history.dart +++ b/cw_bitcoin/lib/electrum_transaction_history.dart @@ -1,10 +1,9 @@ import 'dart:convert'; +import 'package:cw_bitcoin/encryption_file_utils.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/wallet_info.dart'; -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/transaction_history.dart'; -import 'package:cw_bitcoin/file.dart'; import 'package:cw_bitcoin/electrum_transaction_info.dart'; part 'electrum_transaction_history.g.dart'; @@ -17,13 +16,14 @@ class ElectrumTransactionHistory = ElectrumTransactionHistoryBase abstract class ElectrumTransactionHistoryBase extends TransactionHistoryBase with Store { ElectrumTransactionHistoryBase( - {required this.walletInfo, required String password}) + {required this.walletInfo, required String password, required this.encryptionFileUtils}) : _password = password, _height = 0 { transactions = ObservableMap(); } final WalletInfo walletInfo; + final EncryptionFileUtils encryptionFileUtils; String _password; int _height; @@ -45,7 +45,7 @@ abstract class ElectrumTransactionHistoryBase final path = '$dirPath/$_transactionsHistoryFileName'; final data = json.encode({'height': _height, 'transactions': transactions}); - await writeData(path: path, password: _password, data: data); + await encryptionFileUtils.write(path: path, password: _password, data: data); } catch (e) { print('Error while save bitcoin transaction history: ${e.toString()}'); } @@ -60,7 +60,7 @@ abstract class ElectrumTransactionHistoryBase final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type); final path = '$dirPath/$_transactionsHistoryFileName'; - final content = await read(path: path, password: _password); + final content = await encryptionFileUtils.read(path: path, password: _password); return json.decode(content) as Map; } diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index a36654dbb..460bc5542 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math'; import 'dart:typed_data'; +import 'package:cw_bitcoin/encryption_file_utils.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:hive/hive.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; @@ -22,7 +23,6 @@ import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; import 'package:cw_bitcoin/bitcoin_transaction_wrong_balance_exception.dart'; import 'package:cw_bitcoin/bitcoin_unspent.dart'; import 'package:cw_bitcoin/bitcoin_wallet_keys.dart'; -import 'package:cw_bitcoin/file.dart'; import 'package:cw_bitcoin/pending_bitcoin_transaction.dart'; import 'package:cw_bitcoin/script_hash.dart'; import 'package:cw_bitcoin/utils.dart'; @@ -49,6 +49,7 @@ abstract class ElectrumWalletBase extends WalletBase? initialAddresses, ElectrumClient? electrumClient, ElectrumBalance? initialBalance, @@ -70,7 +71,10 @@ abstract class ElectrumWalletBase extends WalletBase @@ -78,6 +82,7 @@ abstract class ElectrumWalletBase extends WalletBase unspentCoinsInfo; @@ -428,7 +433,7 @@ abstract class ElectrumWalletBase extends WalletBase save() async { final path = await makePath(); - await write(path: path, password: _password, data: toJSON()); + await encryptionFileUtils.write(path: path, password: _password, data: toJSON()); await transactionHistory.save(); } diff --git a/cw_bitcoin/lib/electrum_wallet_snapshot.dart b/cw_bitcoin/lib/electrum_wallet_snapshot.dart index 3755e7d18..9276efaf7 100644 --- a/cw_bitcoin/lib/electrum_wallet_snapshot.dart +++ b/cw_bitcoin/lib/electrum_wallet_snapshot.dart @@ -1,7 +1,7 @@ import 'dart:convert'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/electrum_balance.dart'; -import 'package:cw_bitcoin/file.dart'; +import 'package:cw_bitcoin/encryption_file_utils.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/wallet_type.dart'; @@ -26,9 +26,9 @@ class ElectrumWallletSnapshot { int regularAddressIndex; int changeAddressIndex; - static Future load(String name, WalletType type, String password) async { + static Future load(EncryptionFileUtils encryptionFileUtils, String name, WalletType type, String password) async { final path = await pathForWallet(name: name, type: type); - final jsonSource = await read(path: path, password: password); + final jsonSource = await encryptionFileUtils.read(path: path, password: password); final data = json.decode(jsonSource) as Map; final addressesTmp = data['addresses'] as List? ?? []; final mnemonic = data['mnemonic'] as String; diff --git a/cw_bitcoin/lib/encryption_file_utils.dart b/cw_bitcoin/lib/encryption_file_utils.dart new file mode 100644 index 000000000..95f000f04 --- /dev/null +++ b/cw_bitcoin/lib/encryption_file_utils.dart @@ -0,0 +1,42 @@ +import 'dart:io'; +import 'dart:typed_data'; +import 'package:cw_bitcoin/file.dart' as bf; +import 'package:cake_backup/backup.dart' as cwb; + +EncryptionFileUtils encryptionFileUtilsFor(bool direct) + => direct + ? XChaCha20EncryptionFileUtils() + : Salsa20EncryhptionFileUtils(); + +abstract class EncryptionFileUtils { + Future write({required String path, required String password, required String data}); + Future read({required String path, required String password}); +} + +class Salsa20EncryhptionFileUtils extends EncryptionFileUtils { + // Requires legacy complex key + iv as password + @override + Future write({required String path, required String password, required String data}) async + => await bf.write(path: path, password: password, data: data); + + // Requires legacy complex key + iv as password + @override + Future read({required String path, required String password}) async + => await bf.read(path: path, password: password); +} + +class XChaCha20EncryptionFileUtils extends EncryptionFileUtils { + @override + Future write({required String path, required String password, required String data}) async { + final encrypted = await cwb.encrypt(password, Uint8List.fromList(data.codeUnits)); + await File(path).writeAsBytes(encrypted); + } + + @override + Future read({required String path, required String password}) async { + final file = File(path); + final encrypted = await file.readAsBytes(); + final bytes = await cwb.decrypt(password, encrypted); + return String.fromCharCodes(bytes); + } +} \ No newline at end of file diff --git a/cw_bitcoin/lib/file.dart b/cw_bitcoin/lib/file.dart index 8fd236ec3..49b7d895e 100644 --- a/cw_bitcoin/lib/file.dart +++ b/cw_bitcoin/lib/file.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:cw_core/key.dart'; import 'package:encrypt/encrypt.dart' as encrypt; +// Do not use directly, move to Salsa20EncryhptionFile Future write( {required String path, required String password, diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart index 6bf1c5735..6d5171fd7 100644 --- a/cw_bitcoin/lib/litecoin_wallet.dart +++ b/cw_bitcoin/lib/litecoin_wallet.dart @@ -1,5 +1,6 @@ import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; +import 'package:cw_bitcoin/encryption_file_utils.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_bitcoin/litecoin_wallet_addresses.dart'; @@ -26,6 +27,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { required WalletInfo walletInfo, required Box unspentCoinsInfo, required Uint8List seedBytes, + required EncryptionFileUtils encryptionFileUtils, List? initialAddresses, ElectrumBalance? initialBalance, int initialRegularAddressIndex = 0, @@ -39,6 +41,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { initialAddresses: initialAddresses, initialBalance: initialBalance, seedBytes: seedBytes, + encryptionFileUtils: encryptionFileUtils, currency: CryptoCurrency.ltc) { walletAddresses = LitecoinWalletAddresses( walletInfo, @@ -58,6 +61,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { required String password, required WalletInfo walletInfo, required Box unspentCoinsInfo, + required EncryptionFileUtils encryptionFileUtils, List? initialAddresses, ElectrumBalance? initialBalance, int initialRegularAddressIndex = 0, @@ -71,6 +75,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { initialAddresses: initialAddresses, initialBalance: initialBalance, seedBytes: await mnemonicToSeedBytes(mnemonic), + encryptionFileUtils: encryptionFileUtils, initialRegularAddressIndex: initialRegularAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex); } @@ -80,8 +85,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { required WalletInfo walletInfo, required Box unspentCoinsInfo, required String password, + required EncryptionFileUtils encryptionFileUtils }) async { - final snp = await ElectrumWallletSnapshot.load (name, walletInfo.type, password); + final snp = await ElectrumWallletSnapshot.load(encryptionFileUtils, name, walletInfo.type, password); return LitecoinWallet( mnemonic: snp.mnemonic, password: password, @@ -90,6 +96,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { initialAddresses: snp.addresses, initialBalance: snp.balance, seedBytes: await mnemonicToSeedBytes(snp.mnemonic), + encryptionFileUtils: encryptionFileUtils, initialRegularAddressIndex: snp.regularAddressIndex, initialChangeAddressIndex: snp.changeAddressIndex); } diff --git a/cw_bitcoin/lib/litecoin_wallet_service.dart b/cw_bitcoin/lib/litecoin_wallet_service.dart index 2093647fd..56a5ff152 100644 --- a/cw_bitcoin/lib/litecoin_wallet_service.dart +++ b/cw_bitcoin/lib/litecoin_wallet_service.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'package:cw_bitcoin/encryption_file_utils.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:hive/hive.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; @@ -16,10 +17,11 @@ class LitecoinWalletService extends WalletService< BitcoinNewWalletCredentials, BitcoinRestoreWalletFromSeedCredentials, BitcoinRestoreWalletFromWIFCredentials> { - LitecoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource); + LitecoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect); final Box walletInfoSource; final Box unspentCoinsInfoSource; + final bool isDirect; @override WalletType getType() => WalletType.litecoin; @@ -30,7 +32,8 @@ class LitecoinWalletService extends WalletService< mnemonic: await generateMnemonic(), password: credentials.password!, walletInfo: credentials.walletInfo!, - unspentCoinsInfo: unspentCoinsInfoSource); + unspentCoinsInfo: unspentCoinsInfoSource, + encryptionFileUtils: encryptionFileUtilsFor(isDirect)); await wallet.save(); await wallet.init(); @@ -47,7 +50,8 @@ class LitecoinWalletService extends WalletService< (info) => info.id == WalletBase.idFor(name, getType()))!; final wallet = await LitecoinWalletBase.open( password: password, name: name, walletInfo: walletInfo, - unspentCoinsInfo: unspentCoinsInfoSource); + unspentCoinsInfo: unspentCoinsInfoSource, + encryptionFileUtils: encryptionFileUtilsFor(isDirect)); await wallet.init(); return wallet; } @@ -73,7 +77,8 @@ class LitecoinWalletService extends WalletService< password: credentials.password!, mnemonic: credentials.mnemonic, walletInfo: credentials.walletInfo!, - unspentCoinsInfo: unspentCoinsInfoSource); + unspentCoinsInfo: unspentCoinsInfoSource, + encryptionFileUtils: encryptionFileUtilsFor(isDirect)); await wallet.save(); await wallet.init(); return wallet; diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index 182e5c1d3..301cdf477 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -155,6 +155,15 @@ packages: url: "https://pub.dev" source: hosted version: "8.4.4" + cake_backup: + dependency: "direct main" + description: + path: "." + ref: main + resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38" + url: "https://github.com/cake-tech/cake_backup.git" + source: git + version: "1.0.0+1" characters: dependency: transitive description: @@ -219,6 +228,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.5.0" + cupertino_icons: + dependency: transitive + description: + name: cupertino_icons + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" + source: hosted + version: "1.0.5" cw_core: dependency: "direct main" description: @@ -681,6 +698,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + tuple: + dependency: transitive + description: + name: tuple + sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa" + url: "https://pub.dev" + source: hosted + version: "2.0.1" typed_data: dependency: transitive description: diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index 455ceb4a7..4c9d2e44c 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -27,6 +27,11 @@ dependencies: unorm_dart: ^0.2.0 cryptography: ^2.0.5 encrypt: ^5.0.1 + cake_backup: + git: + url: https://github.com/cake-tech/cake_backup.git + ref: main + version: 1.0.0 dev_dependencies: flutter_test: diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index 40fa670da..cb66a0f4b 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -138,12 +138,12 @@ class CWBitcoin extends Bitcoin { await bitcoinWallet.updateUnspent(); } - WalletService createBitcoinWalletService(Box walletInfoSource, Box unspentCoinSource) { - return BitcoinWalletService(walletInfoSource, unspentCoinSource); + WalletService createBitcoinWalletService(Box walletInfoSource, Box unspentCoinSource, bool isDirect) { + return BitcoinWalletService(walletInfoSource, unspentCoinSource, isDirect); } - WalletService createLitecoinWalletService(Box walletInfoSource, Box unspentCoinSource) { - return LitecoinWalletService(walletInfoSource, unspentCoinSource); + WalletService createLitecoinWalletService(Box walletInfoSource, Box unspentCoinSource, bool isDirect) { + return LitecoinWalletService(walletInfoSource, unspentCoinSource, isDirect); } @override diff --git a/lib/di.dart b/lib/di.dart index 2ab451d14..589397f22 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -583,10 +583,12 @@ Future setup( return monero!.createMoneroWalletService(_walletInfoSource); case WalletType.bitcoin: return bitcoin!.createBitcoinWalletService( - _walletInfoSource, _unspentCoinsInfoSource!); + _walletInfoSource, _unspentCoinsInfoSource!, + SettingsStoreBase.walletPasswordDirectInput); case WalletType.litecoin: return bitcoin!.createLitecoinWalletService( - _walletInfoSource, _unspentCoinsInfoSource!); + _walletInfoSource, _unspentCoinsInfoSource!, + SettingsStoreBase.walletPasswordDirectInput); default: throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService'); } diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index 18a9c2424..be128ee6a 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -50,7 +50,8 @@ class _WalletNameFormState extends State { : _formKey = GlobalKey(), _languageSelectorKey = GlobalKey(), _nameController = TextEditingController(), - _passwordController = _walletNewVM.hasWalletPassword ? TextEditingController() : null; + _passwordController = _walletNewVM.hasWalletPassword ? TextEditingController() : null, + _repeatedPasswordController = _walletNewVM.hasWalletPassword ? TextEditingController() : null; static const aspectRatioImage = 1.22; @@ -59,6 +60,7 @@ class _WalletNameFormState extends State { final WalletNewVM _walletNewVM; final TextEditingController _nameController; final TextEditingController? _passwordController; + final TextEditingController? _repeatedPasswordController; ReactionDisposer? _stateReaction; @override @@ -171,7 +173,7 @@ class _WalletNameFormState extends State { validator: WalletNameValidator(), ), if (_walletNewVM.hasWalletPassword) - TextFormField( + ...[TextFormField( onChanged: (value) => _walletNewVM.walletPassword = value, controller: _passwordController, textAlign: TextAlign.center, @@ -203,6 +205,38 @@ class _WalletNameFormState extends State { ) ) ), + TextFormField( + onChanged: (value) => _walletNewVM.repeatedWalletPassword = value, + controller: _repeatedPasswordController, + textAlign: TextAlign.center, + obscureText: true, + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w600, + color: Theme.of(context).primaryTextTheme!.headline6!.color!), + decoration: InputDecoration( + hintStyle: TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.w500, + color: Theme.of(context).accentTextTheme!.headline2!.color!), + hintText: S.of(context).repeate_wallet_password, + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context) + .accentTextTheme! + .headline2! + .decorationColor!, + width: 1.0)), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context) + .accentTextTheme! + .headline2! + .decorationColor!, + width: 1.0), + ) + ) + )], ], ), ), diff --git a/lib/src/screens/restore/wallet_restore_from_keys_form.dart b/lib/src/screens/restore/wallet_restore_from_keys_form.dart index 0096973d0..1d1288b23 100644 --- a/lib/src/screens/restore/wallet_restore_from_keys_form.dart +++ b/lib/src/screens/restore/wallet_restore_from_keys_form.dart @@ -15,6 +15,7 @@ class WalletRestoreFromKeysFrom extends StatefulWidget { WalletRestoreFromKeysFrom({ required this.walletRestoreViewModel, required this.displayWalletPassword, + required this.onRepeatedPasswordChange, this.onPasswordChange, Key? key, this.onHeightOrDateEntered,}) @@ -24,6 +25,7 @@ class WalletRestoreFromKeysFrom extends StatefulWidget { final WalletRestoreViewModel walletRestoreViewModel; final bool displayWalletPassword; final void Function(String)? onPasswordChange; + final void Function(String)? onRepeatedPasswordChange; @override WalletRestoreFromKeysFromState createState() => @@ -39,7 +41,8 @@ class WalletRestoreFromKeysFromState extends State { viewKeyController = TextEditingController(), spendKeyController = TextEditingController(), nameTextEditingController = TextEditingController(), - passwordTextEditingController = displayWalletPassword ? TextEditingController() : null; + passwordTextEditingController = displayWalletPassword ? TextEditingController() : null, + repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null; final GlobalKey formKey; final GlobalKey blockchainHeightKey; @@ -49,7 +52,9 @@ class WalletRestoreFromKeysFromState extends State { final TextEditingController spendKeyController; final TextEditingController nameTextEditingController; final TextEditingController? passwordTextEditingController; + final TextEditingController? repeatedPasswordTextEditingController; void Function()? passwordListener; + void Function()? repeatedPasswordListener; @override void initState() { @@ -57,6 +62,11 @@ class WalletRestoreFromKeysFromState extends State { passwordListener = () => widget.onPasswordChange?.call(passwordTextEditingController!.text); passwordTextEditingController?.addListener(passwordListener!); } + + if (repeatedPasswordTextEditingController != null) { + repeatedPasswordListener = () => widget.onRepeatedPasswordChange?.call(repeatedPasswordTextEditingController!.text); + repeatedPasswordTextEditingController?.addListener(repeatedPasswordListener!); + } super.initState(); } @@ -71,6 +81,10 @@ class WalletRestoreFromKeysFromState extends State { if (passwordListener != null) { passwordTextEditingController?.removeListener(passwordListener!); } + + if (repeatedPasswordListener != null) { + repeatedPasswordTextEditingController?.removeListener(repeatedPasswordListener!); + } super.dispose(); } @@ -121,12 +135,18 @@ class WalletRestoreFromKeysFromState extends State { ], ), if (widget.displayWalletPassword) - Container( + ...[Container( padding: EdgeInsets.only(top: 20.0), child: BaseTextFormField( controller: passwordTextEditingController, hintText: S.of(context).password, obscureText: true)), + Container( + padding: EdgeInsets.only(top: 20.0), + child: BaseTextFormField( + controller: repeatedPasswordTextEditingController, + hintText: S.of(context).repeate_wallet_password, + obscureText: true))], Container(height: 20), BaseTextFormField( controller: addressController, diff --git a/lib/src/screens/restore/wallet_restore_from_seed_form.dart b/lib/src/screens/restore/wallet_restore_from_seed_form.dart index f0fb7dfa2..d41d71a3f 100644 --- a/lib/src/screens/restore/wallet_restore_from_seed_form.dart +++ b/lib/src/screens/restore/wallet_restore_from_seed_form.dart @@ -23,7 +23,8 @@ class WalletRestoreFromSeedForm extends StatefulWidget { this.onHeightOrDateEntered, this.onSeedChange, this.onLanguageChange, - this.onPasswordChange}) + this.onPasswordChange, + this.onRepeatedPasswordChange}) : super(key: key); final WalletType type; @@ -35,6 +36,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget { final void Function(String)? onSeedChange; final void Function(String)? onLanguageChange; final void Function(String)? onPasswordChange; + final void Function(String)? onRepeatedPasswordChange; @override WalletRestoreFromSeedFormState createState() => @@ -48,16 +50,19 @@ class WalletRestoreFromSeedFormState extends State { formKey = GlobalKey(), languageController = TextEditingController(), nameTextEditingController = TextEditingController(), - passwordTextEditingController = displayWalletPassword ? TextEditingController() : null; + passwordTextEditingController = displayWalletPassword ? TextEditingController() : null, + repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null; final GlobalKey seedWidgetStateKey; final GlobalKey blockchainHeightKey; final TextEditingController languageController; final TextEditingController nameTextEditingController; final TextEditingController? passwordTextEditingController; + final TextEditingController? repeatedPasswordTextEditingController; final GlobalKey formKey; String language; void Function()? passwordListener; + void Function()? repeatedPasswordListener; @override void initState() { @@ -66,6 +71,11 @@ class WalletRestoreFromSeedFormState extends State { passwordListener = () => widget.onPasswordChange?.call(passwordTextEditingController!.text); passwordTextEditingController?.addListener(passwordListener!); } + + if (repeatedPasswordTextEditingController != null) { + repeatedPasswordListener = () => widget.onRepeatedPasswordChange?.call(repeatedPasswordTextEditingController!.text); + repeatedPasswordTextEditingController?.addListener(repeatedPasswordListener!); + } super.initState(); } @@ -74,6 +84,10 @@ class WalletRestoreFromSeedFormState extends State { if (passwordListener != null) { passwordTextEditingController?.removeListener(passwordListener!); } + + if (repeatedPasswordListener != null) { + repeatedPasswordTextEditingController?.removeListener(repeatedPasswordListener!); + } super.dispose(); } @@ -130,10 +144,14 @@ class WalletRestoreFromSeedFormState extends State { type: widget.type, onSeedChange: widget.onSeedChange), if (widget.displayWalletPassword) - BaseTextFormField( + ...[BaseTextFormField( controller: passwordTextEditingController, hintText: S.of(context).password, obscureText: true), + BaseTextFormField( + controller: repeatedPasswordTextEditingController, + hintText: S.of(context).repeate_wallet_password, + obscureText: true)], if (widget.displayLanguageSelector) GestureDetector( onTap: () async { diff --git a/lib/src/screens/restore/wallet_restore_page.dart b/lib/src/screens/restore/wallet_restore_page.dart index 1ee25320d..93ef93665 100644 --- a/lib/src/screens/restore/wallet_restore_page.dart +++ b/lib/src/screens/restore/wallet_restore_page.dart @@ -68,7 +68,8 @@ class WalletRestorePage extends BasePage { } }, displayWalletPassword: walletRestoreViewModel.hasWalletPassword, - onPasswordChange: (String password) => walletRestoreViewModel.walletPassword = password)); + onPasswordChange: (String password) => walletRestoreViewModel.walletPassword = password, + onRepeatedPasswordChange: (String repeatedPassword) => walletRestoreViewModel.repeatedWalletPassword = repeatedPassword)); break; case WalletRestoreMode.keys: _pages.add(WalletRestoreFromKeysFrom( @@ -76,6 +77,7 @@ class WalletRestorePage extends BasePage { walletRestoreViewModel: walletRestoreViewModel, displayWalletPassword: walletRestoreViewModel.hasWalletPassword, onPasswordChange: (String password) => walletRestoreViewModel.walletPassword = password, + onRepeatedPasswordChange: (String repeatedPassword) => walletRestoreViewModel.repeatedWalletPassword = repeatedPassword, onHeightOrDateEntered: (value) => walletRestoreViewModel.isButtonEnabled = value)); break; default: @@ -124,6 +126,8 @@ class WalletRestorePage extends BasePage { reaction((_) => walletRestoreViewModel.mode, (WalletRestoreMode mode) { walletRestoreViewModel.isButtonEnabled = false; + walletRestoreViewModel.walletPassword = null; + walletRestoreViewModel.repeatedWalletPassword = null; walletRestoreFromSeedFormKey .currentState!.blockchainHeightKey.currentState!.restoreHeightController.text = ''; diff --git a/lib/view_model/wallet_creation_vm.dart b/lib/view_model/wallet_creation_vm.dart index 65968cd30..9a28045b0 100644 --- a/lib/view_model/wallet_creation_vm.dart +++ b/lib/view_model/wallet_creation_vm.dart @@ -1,6 +1,6 @@ import 'package:cake_wallet/core/wallet_creation_service.dart'; +import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/store/settings_store.dart'; -import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/core/execution_state.dart'; @@ -31,6 +31,9 @@ abstract class WalletCreationVMBase with Store { @observable String? walletPassword; + @observable + String? repeatedWalletPassword; + bool get hasWalletPassword => SettingsStoreBase.walletPasswordDirectInput; WalletType type; @@ -52,6 +55,14 @@ abstract class WalletCreationVMBase with Store { name = await generateName(); } + if (hasWalletPassword && (walletPassword?.isEmpty ?? true)) { + throw Exception(S.current.wallet_password_is_empty); + } + + if (hasWalletPassword && walletPassword != repeatedWalletPassword) { + throw Exception(S.current.repeated_password_is_incorrect); + } + walletCreationService.checkIfExists(name); final dirPath = await pathForWalletDir(name: name, type: type); final path = await pathForWallet(name: name, type: type); diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index b55134597..f6dff063b 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -346,6 +346,9 @@ "invalid_password" : "رمز مرور خاطئ", "unlock" : "الغاء القفل", "enter_wallet_password" : "أدخل كلمة مرور المحفظة", + "repeate_wallet_password" : "كرر كلمة مرور المحفظة", + "wallet_password_is_empty" : "كلمة مرور المحفظة فارغة. يجب ألا تكون كلمة مرور المحفظة فارغة", + "repeated_password_is_incorrect" : "كلمة المرور المتكررة غير صحيحة. يرجى إعادة كلمة مرور المحفظة مرة أخرى.", "full_balance":"الرصيد الكامل", "available_balance":"الرصيد المتوفر", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 4671529bc..6d4f9add7 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -346,6 +346,9 @@ "invalid_password" : "Ongeldig wachtwoord", "unlock" : "Freischalten", "enter_wallet_password" : "Geben Sie das Wallet-Passwort ein", + "repeat_wallet_password" : "Wiederholen Sie das Wallet-Passwort", + "wallet_password_is_empty" : "Wallet-Passwort ist leer. Wallet-Passwort darf nicht leer sein", + "repeated_password_is_incorrect" : "Wiederholtes Passwort ist falsch. Bitte wiederholen Sie das Wallet-Passwort noch einmal.", "full_balance" : "Gesamtguthaben", "available_balance" : "Verfügbares Guthaben", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index dbacc1a7b..01bc959cf 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -346,6 +346,9 @@ "invalid_password" : "Invalid password", "unlock" : "Unlock", "enter_wallet_password" : "Enter the wallet password", + "repeate_wallet_password" : "Repeat the wallet password", + "wallet_password_is_empty" : "Wallet password is empty. Wallet password should not be empty", + "repeated_password_is_incorrect" : "Repeated password is incorrect. Please repeat the wallet password again.", "full_balance" : "Full Balance", "available_balance" : "Available Balance", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 8c4577215..5228cb00c 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -346,6 +346,9 @@ "invalid_password" : "Contraseña invalida", "unlock" : "desbloquear", "enter_wallet_password" : "Ingrese la contraseña de la billetera", + "repeate_wallet_password" : "Repita la contraseña de la billetera", + "wallet_password_is_empty" : "La contraseña de la billetera está vacía. La contraseña de la billetera no debe estar vacía", + "repeated_password_is_incorrect" : "La contraseña repetida es incorrecta. Repita la contraseña de la billetera nuevamente.", "full_balance" : "Balance completo", "available_balance" : "Balance disponible", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index 6ac2f8293..30da9b052 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -344,6 +344,9 @@ "invalid_password" : "Mot de passe incorrect", "unlock" : "Ouvrir", "enter_wallet_password" : "Entrez le mot de passe du portefeuille", + "repeate_wallet_password" : "Répétez le mot de passe du portefeuille", + "wallet_password_is_empty" : "Le mot de passe du portefeuille est vide. Le mot de passe du portefeuille ne doit pas être vide", + "repeated_password_is_incorrect" : "Le mot de passe répété est incorrect. Veuillez répéter le mot de passe du portefeuille.", "full_balance" : "Solde Complet", "available_balance" : "Solde Disponible", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index b4001f6d1..85697f625 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -346,6 +346,9 @@ "invalid_password" : "अवैध पासवर्ड", "unlock" : "अनलॉक", "enter_wallet_password" : "वॉलेट पासवर्ड दर्ज करें", + "repeate_wallet_password" : "वॉलेट पासवर्ड दोहराएं", + "wallet_password_is_empty" : "वॉलेट पासवर्ड खाली है। वॉलेट पासवर्ड खाली नहीं होना चाहिए", + "repeated_password_is_incorrect" : "दोहराया गया पासवर्ड गलत है। कृपया वॉलेट पासवर्ड दोबारा दोहराएं।", "full_balance" : "पूर्ण संतुलन", "available_balance" : "उपलब्ध शेष राशि", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 14d22dc65..4d3a10738 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -346,6 +346,9 @@ "invalid_password" : "Érvénytelen jelszó", "unlock" : "Kinyit", "enter_wallet_password" : "Adja meg a pénztárca jelszavát", + "repeate_wallet_password" : "Az ismételt jelszó helytelen. Kérjük, ismételje meg újra a pénztárca jelszavát.", + "wallet_password_is_empty" : "A Wallet jelszó üres. A Wallet jelszó nem lehet üres", + "repeated_password_is_incorrect" : "Az ismételt jelszó helytelen. Kérjük, ismételje meg újra a pénztárca jelszavát.", "full_balance" : "Pun iznos", "available_balance" : "Raspoloživ iznos", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 75af0881e..67ec68b65 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -346,6 +346,9 @@ "invalid_password" : "Password non valida", "unlock" : "Sbloccare", "enter_wallet_password" : "Inserisci la password del portafoglio", + "repeate_wallet_password" : "Ripeti la password del portafoglio", + "wallet_password_is_empty" : "La password del portafoglio è vuota. La password del portafoglio non deve essere vuota", + "repeated_password_is_incorrect" : "La password ripetuta non è corretta. Ripeti di nuovo la password del portafoglio.", "full_balance" : "Saldo Completo", "available_balance" : "Saldo Disponibile", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index 8cac3cc57..d6ba565fc 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -346,6 +346,9 @@ "invalid_password" : "無効なパスワード", "unlock" : "ロック解除", "enter_wallet_password" : "ウォレットのパスワードを入力してください", + "repeate_wallet_password" : "ウォレットのパスワードを繰り返す", + "wallet_password_is_empty" : "ウォレットのパスワードが空です。 ウォレットのパスワードを空にすることはできません", + "repeated_password_is_incorrect" : "繰り返されるパスワードが正しくありません。 ウォレットのパスワードをもう一度入力してください。", "full_balance" : "フルバランス", "available_balance" : "利用可能残高", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 7cf462fbc..fe72f4958 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -346,6 +346,9 @@ "invalid_password" : "유효하지 않은 비밀번호", "unlock" : "터놓다", "enter_wallet_password" : "지갑 비밀번호를 입력하세요", + "repeate_wallet_password" : "지갑 비밀번호를 반복하십시오", + "wallet_password_is_empty" : "지갑 비밀번호가 비어 있습니다. 월렛 비밀번호는 비워둘 수 없습니다.", + "repeated_password_is_incorrect" : "반복되는 비밀번호가 올바르지 않습니다. 지갑 비밀번호를 다시 한번 입력해주세요.", "full_balance" : "풀 밸런스", "available_balance" : "사용 가능한 잔액", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index 34180697d..531ea9891 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -346,6 +346,9 @@ "invalid_password" : "စကားဝှက် မမှန်ကန်ပါ။", "unlock" : "သော့ဖွင့်ပါ။", "enter_wallet_password" : "ပိုက်ဆံအိတ်စကားဝှက်ကိုထည့်ပါ။", + "repeate_wallet_password" : "ပိုက်ဆံအိတ်စကားဝှက်ကို ပြန်လုပ်ပါ။", + "wallet_password_is_empty" : "ပိုက်ဆံအိတ်စကားဝှက်သည် ဗလာဖြစ်နေသည်။ ပိုက်ဆံအိတ်စကားဝှက်သည် ဗလာမဖြစ်သင့်ပါ။", + "repeated_password_is_incorrect" : "ထပ်ခါတလဲလဲ စကားဝှက် မမှန်ပါ။ ပိုက်ဆံအိတ်စကားဝှက်ကို ထပ်လုပ်ပါ။", "full_balance" : "Balance အပြည့်", "available_balance" : "လက်ကျန်ငွေ ရရှိနိုင်", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 3f30a99e6..590188fb4 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -346,6 +346,9 @@ "invalid_password" : "Ongeldig wachtwoord", "unlock" : "Ontgrendelen", "enter_wallet_password" : "Voer het portemonnee-wachtwoord in", + "repeate_wallet_password" : "Herhaal het wachtwoord van de portemonnee", + "wallet_password_is_empty" : "Wallet-wachtwoord is leeg. Wallet-wachtwoord mag niet leeg zijn", + "repeated_password_is_incorrect" : "Herhaald wachtwoord is onjuist. Herhaal het wachtwoord van de portemonnee nogmaals.", "full_balance" : "Volledig saldo", "available_balance" : "Beschikbaar saldo", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index c006b0f53..2c8c8a575 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -346,6 +346,9 @@ "invalid_password" : "Nieprawidłowe hasło", "unlock" : "Odblokować", "enter_wallet_password" : "Wprowadź hasło do portfela", + "repeate_wallet_password" : "Powtórz hasło do portfela", + "wallet_password_is_empty" : "Hasło portfela jest puste. Hasło portfela nie powinno być puste", + "repeated_password_is_incorrect" : "Powtórzone hasło jest nieprawidłowe. Powtórz hasło do portfela jeszcze raz.", "full_balance" : "Pełne saldo", "available_balance" : "Dostępne środki", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 5ac447a46..27c2578f8 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -346,6 +346,9 @@ "invalid_password" : "Senha inválida", "unlock" : "desbloquear", "enter_wallet_password" : "Digite a senha da carteira", + "repeate_wallet_password" : "Repita a senha da carteira", + "wallet_password_is_empty" : "A senha da carteira está vazia. A senha da carteira não deve estar vazia", + "repeated_password_is_incorrect" : "A senha repetida está incorreta. Por favor, repita a senha da carteira novamente.", "full_balance" : "Saldo total", "available_balance" : "Saldo disponível", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 53a538b5d..4ed8faa59 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -346,6 +346,9 @@ "invalid_password" : "Invalid password", "unlock" : "Unlock", "enter_wallet_password" : "Enter the wallet password", + "repeate_wallet_password" : "Repeat the wallet password", + "wallet_password_is_empty" : "Wallet password is empty. Wallet password should not be empty", + "repeated_password_is_incorrect" : "Repeated password is incorrect. Please repeat the wallet password again.", "full_balance" : "Весь баланс", "available_balance" : "Доступный баланс", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 11ea7ca37..692fd39d9 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -344,6 +344,9 @@ "invalid_password" : "รหัสผ่านไม่ถูกต้อง", "unlock" : "ปลดล็อค", "enter_wallet_password" : "ป้อนรหัสผ่านกระเป๋าเงิน", + "repeate_wallet_password" : "ทำซ้ำรหัสผ่านกระเป๋าเงิน", + "wallet_password_is_empty" : "รหัสผ่าน Wallet ว่างเปล่า รหัสผ่าน Wallet ไม่ควรว่างเปล่า", + "repeated_password_is_incorrect" : "รหัสผ่านซ้ำไม่ถูกต้อง กรุณากรอกรหัสผ่านกระเป๋าเงินซ้ำอีกครั้ง", "full_balance" : "ยอดคงเหลือทั้งหมด", "available_balance" : "ยอดคงเหลือที่ใช้งานได้", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index f1fe789f7..3389cc608 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -346,6 +346,9 @@ "invalid_password" : "Geçersiz şifre", "unlock" : "Kilidini aç", "enter_wallet_password" : "cüzdan şifresini girin", + "repeate_wallet_password" : "M-cüzdan şifresini tekrarla", + "wallet_password_is_empty" : "Cüzdan şifresi boş. Cüzdan şifresi boş olmamalıdır", + "repeated_password_is_incorrect" : "Tekrarlanan şifre yanlış. Lütfen cüzdan şifresini tekrar tekrarlayın.", "full_balance" : "Tüm bakiye", "available_balance" : "Kullanılabilir Bakiye", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 696eab10a..80d78113e 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -345,6 +345,9 @@ "invalid_password" : "Невірний пароль", "unlock" : "Розблокувати", "enter_wallet_password" : "Введіть пароль гаманця", + "repeate_wallet_password" : "Повторіть пароль гаманця", + "wallet_password_is_empty" : "Пароль гаманця порожній. Пароль гаманця не повинен бути порожнім", + "repeated_password_is_incorrect" : "Повторний пароль неправильний. Будь ласка, повторіть пароль гаманця ще раз.", "full_balance" : "Весь баланс", "available_balance" : "Доступний баланс", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index c11896ad2..c97f42939 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -346,6 +346,9 @@ "invalid_password" : "无效的密码", "unlock" : "开锁", "enter_wallet_password" : "输入钱包密码", + "repeate_wallet_password" : "重复钱包密码", + "wallet_password_is_empty" : "钱包密码为空。 钱包密码不能为空", + "repeated_password_is_incorrect" : "重复的密码不正确。 请再次输入钱包密码。", "full_balance" : "全部余额", "available_balance" : "可用余额", diff --git a/tool/configure.dart b/tool/configure.dart index 3e441778a..d1ec6a569 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -94,8 +94,8 @@ abstract class Bitcoin { List getUnspents(Object wallet); void updateUnspents(Object wallet); - WalletService createBitcoinWalletService(Box walletInfoSource, Box unspentCoinSource); - WalletService createLitecoinWalletService(Box walletInfoSource, Box unspentCoinSource); + WalletService createBitcoinWalletService(Box walletInfoSource, Box unspentCoinSource, bool isDirect); + WalletService createLitecoinWalletService(Box walletInfoSource, Box unspentCoinSource, bool isDirect); TransactionPriority getBitcoinTransactionPriorityMedium(); TransactionPriority getLitecoinTransactionPriorityMedium(); TransactionPriority getBitcoinTransactionPrioritySlow();