Change encryption method for electrum wallets is wallet password provides directly. Add ability to user for repeat wallets password and compare with original wallet password before wallet creation for cases when wallet password provides directly.

This commit is contained in:
M 2023-04-10 19:16:13 -04:00
parent 3b82a390c1
commit f52c45b167
38 changed files with 287 additions and 39 deletions

View file

@ -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> unspentCoinsInfo,
required Uint8List seedBytes,
required EncryptionFileUtils encryptionFileUtils,
List<BitcoinAddressRecord>? 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> unspentCoinsInfo,
required EncryptionFileUtils encryptionFileUtils,
List<BitcoinAddressRecord>? 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> 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);
}

View file

@ -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<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> 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;

View file

@ -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<ElectrumTransactionInfo> with Store {
ElectrumTransactionHistoryBase(
{required this.walletInfo, required String password})
{required this.walletInfo, required String password, required this.encryptionFileUtils})
: _password = password,
_height = 0 {
transactions = ObservableMap<String, ElectrumTransactionInfo>();
}
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<String, dynamic>;
}

View file

@ -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<ElectrumBalance,
required this.networkType,
required this.mnemonic,
required Uint8List seedBytes,
required this.encryptionFileUtils,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumClient? electrumClient,
ElectrumBalance? initialBalance,
@ -70,7 +71,10 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
this.electrumClient = electrumClient ?? ElectrumClient();
this.walletInfo = walletInfo;
transactionHistory =
ElectrumTransactionHistory(walletInfo: walletInfo, password: password);
ElectrumTransactionHistory(
walletInfo: walletInfo,
password: password,
encryptionFileUtils: encryptionFileUtils);
}
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
@ -78,6 +82,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
final bitcoin.HDWallet hd;
final String mnemonic;
final EncryptionFileUtils encryptionFileUtils;
late ElectrumClient electrumClient;
Box<UnspentCoinsInfo> unspentCoinsInfo;
@ -428,7 +433,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
@override
Future<void> 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();
}

View file

@ -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<ElectrumWallletSnapshot> load(String name, WalletType type, String password) async {
static Future<ElectrumWallletSnapshot> 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? ?? <Object>[];
final mnemonic = data['mnemonic'] as String;

View file

@ -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<void> write({required String path, required String password, required String data});
Future<String> read({required String path, required String password});
}
class Salsa20EncryhptionFileUtils extends EncryptionFileUtils {
// Requires legacy complex key + iv as password
@override
Future<void> 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<String> read({required String path, required String password}) async
=> await bf.read(path: path, password: password);
}
class XChaCha20EncryptionFileUtils extends EncryptionFileUtils {
@override
Future<void> 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<String> 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);
}
}

View file

@ -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<void> write(
{required String path,
required String password,

View file

@ -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> unspentCoinsInfo,
required Uint8List seedBytes,
required EncryptionFileUtils encryptionFileUtils,
List<BitcoinAddressRecord>? 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> unspentCoinsInfo,
required EncryptionFileUtils encryptionFileUtils,
List<BitcoinAddressRecord>? 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> 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);
}

View file

@ -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<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> 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;

View file

@ -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:

View file

@ -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:

View file

@ -138,12 +138,12 @@ class CWBitcoin extends Bitcoin {
await bitcoinWallet.updateUnspent();
}
WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
return BitcoinWalletService(walletInfoSource, unspentCoinSource);
WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
return BitcoinWalletService(walletInfoSource, unspentCoinSource, isDirect);
}
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
return LitecoinWalletService(walletInfoSource, unspentCoinSource);
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
return LitecoinWalletService(walletInfoSource, unspentCoinSource, isDirect);
}
@override

View file

@ -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');
}

View file

@ -50,7 +50,8 @@ class _WalletNameFormState extends State<WalletNameForm> {
: _formKey = GlobalKey<FormState>(),
_languageSelectorKey = GlobalKey<SeedLanguageSelectorState>(),
_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<WalletNameForm> {
final WalletNewVM _walletNewVM;
final TextEditingController _nameController;
final TextEditingController? _passwordController;
final TextEditingController? _repeatedPasswordController;
ReactionDisposer? _stateReaction;
@override
@ -171,7 +173,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
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<WalletNameForm> {
)
)
),
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),
)
)
)],
],
),
),

View file

@ -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<WalletRestoreFromKeysFrom> {
viewKeyController = TextEditingController(),
spendKeyController = TextEditingController(),
nameTextEditingController = TextEditingController(),
passwordTextEditingController = displayWalletPassword ? TextEditingController() : null;
passwordTextEditingController = displayWalletPassword ? TextEditingController() : null,
repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null;
final GlobalKey<FormState> formKey;
final GlobalKey<BlockchainHeightState> blockchainHeightKey;
@ -49,7 +52,9 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
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<WalletRestoreFromKeysFrom> {
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<WalletRestoreFromKeysFrom> {
if (passwordListener != null) {
passwordTextEditingController?.removeListener(passwordListener!);
}
if (repeatedPasswordListener != null) {
repeatedPasswordTextEditingController?.removeListener(repeatedPasswordListener!);
}
super.dispose();
}
@ -121,12 +135,18 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
],
),
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,

View file

@ -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<WalletRestoreFromSeedForm> {
formKey = GlobalKey<FormState>(),
languageController = TextEditingController(),
nameTextEditingController = TextEditingController(),
passwordTextEditingController = displayWalletPassword ? TextEditingController() : null;
passwordTextEditingController = displayWalletPassword ? TextEditingController() : null,
repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null;
final GlobalKey<SeedWidgetState> seedWidgetStateKey;
final GlobalKey<BlockchainHeightState> blockchainHeightKey;
final TextEditingController languageController;
final TextEditingController nameTextEditingController;
final TextEditingController? passwordTextEditingController;
final TextEditingController? repeatedPasswordTextEditingController;
final GlobalKey<FormState> formKey;
String language;
void Function()? passwordListener;
void Function()? repeatedPasswordListener;
@override
void initState() {
@ -66,6 +71,11 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
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<WalletRestoreFromSeedForm> {
if (passwordListener != null) {
passwordTextEditingController?.removeListener(passwordListener!);
}
if (repeatedPasswordListener != null) {
repeatedPasswordTextEditingController?.removeListener(repeatedPasswordListener!);
}
super.dispose();
}
@ -130,10 +144,14 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
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 {

View file

@ -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 = '';

View file

@ -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);

View file

@ -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":"الرصيد المتوفر",

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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" : "उपलब्ध शेष राशि",

View file

@ -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",

View file

@ -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",

View file

@ -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" : "利用可能残高",

View file

@ -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" : "사용 가능한 잔액",

View file

@ -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" : "လက်ကျန်ငွေ ရရှိနိုင်",

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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" : "Доступный баланс",

View file

@ -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" : "ยอดคงเหลือที่ใช้งานได้",

View file

@ -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",

View file

@ -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" : "Доступний баланс",

View file

@ -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" : "可用余额",

View file

@ -94,8 +94,8 @@ abstract class Bitcoin {
List<Unspent> getUnspents(Object wallet);
void updateUnspents(Object wallet);
WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect);
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect);
TransactionPriority getBitcoinTransactionPriorityMedium();
TransactionPriority getLitecoinTransactionPriorityMedium();
TransactionPriority getBitcoinTransactionPrioritySlow();