mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-25 12:06:05 +00:00
Add Encryption file utils to Ethereum (#1025)
This commit is contained in:
parent
74b5ee315a
commit
bdb3ec2048
8 changed files with 89 additions and 19 deletions
42
cw_ethereum/lib/encryption_file_utils.dart
Normal file
42
cw_ethereum/lib/encryption_file_utils.dart
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:cw_ethereum/file.dart' as ef;
|
||||||
|
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 ef.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 ef.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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import 'dart:convert';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_ethereum/file.dart';
|
import 'package:cw_ethereum/encryption_file_utils.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cw_core/transaction_history.dart';
|
import 'package:cw_core/transaction_history.dart';
|
||||||
import 'package:cw_ethereum/ethereum_transaction_info.dart';
|
import 'package:cw_ethereum/ethereum_transaction_info.dart';
|
||||||
|
@ -15,12 +15,16 @@ class EthereumTransactionHistory = EthereumTransactionHistoryBase with _$Ethereu
|
||||||
|
|
||||||
abstract class EthereumTransactionHistoryBase
|
abstract class EthereumTransactionHistoryBase
|
||||||
extends TransactionHistoryBase<EthereumTransactionInfo> with Store {
|
extends TransactionHistoryBase<EthereumTransactionInfo> with Store {
|
||||||
EthereumTransactionHistoryBase({required this.walletInfo, required String password})
|
EthereumTransactionHistoryBase({
|
||||||
: _password = password {
|
required this.walletInfo,
|
||||||
|
required String password,
|
||||||
|
required this.encryptionFileUtils,
|
||||||
|
}) : _password = password {
|
||||||
transactions = ObservableMap<String, EthereumTransactionInfo>();
|
transactions = ObservableMap<String, EthereumTransactionInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
final WalletInfo walletInfo;
|
final WalletInfo walletInfo;
|
||||||
|
final EncryptionFileUtils encryptionFileUtils;
|
||||||
String _password;
|
String _password;
|
||||||
|
|
||||||
Future<void> init() async => await _load();
|
Future<void> init() async => await _load();
|
||||||
|
@ -31,7 +35,7 @@ abstract class EthereumTransactionHistoryBase
|
||||||
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
final path = '$dirPath/$transactionsHistoryFileName';
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
final data = json.encode({'transactions': transactions});
|
final data = json.encode({'transactions': transactions});
|
||||||
await writeData(path: path, password: _password, data: data);
|
await encryptionFileUtils.write(path: path, password: _password, data: data);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
print('Error while save ethereum transaction history: ${e.toString()}');
|
print('Error while save ethereum transaction history: ${e.toString()}');
|
||||||
print(s);
|
print(s);
|
||||||
|
@ -48,7 +52,7 @@ abstract class EthereumTransactionHistoryBase
|
||||||
Future<Map<String, dynamic>> _read() async {
|
Future<Map<String, dynamic>> _read() async {
|
||||||
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
final path = '$dirPath/$transactionsHistoryFileName';
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
final content = await read(path: path, password: _password);
|
final content = await encryptionFileUtils.read(path: path, password: _password);
|
||||||
if (content.isEmpty) {
|
if (content.isEmpty) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import 'package:cw_core/wallet_addresses.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_ethereum/default_erc20_tokens.dart';
|
import 'package:cw_ethereum/default_erc20_tokens.dart';
|
||||||
|
import 'package:cw_ethereum/encryption_file_utils.dart';
|
||||||
import 'package:cw_ethereum/erc20_balance.dart';
|
import 'package:cw_ethereum/erc20_balance.dart';
|
||||||
import 'package:cw_ethereum/ethereum_client.dart';
|
import 'package:cw_ethereum/ethereum_client.dart';
|
||||||
import 'package:cw_ethereum/ethereum_exceptions.dart';
|
import 'package:cw_ethereum/ethereum_exceptions.dart';
|
||||||
|
@ -47,19 +48,25 @@ abstract class EthereumWalletBase
|
||||||
String? mnemonic,
|
String? mnemonic,
|
||||||
String? privateKey,
|
String? privateKey,
|
||||||
required String password,
|
required String password,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
ERC20Balance? initialBalance,
|
ERC20Balance? initialBalance,
|
||||||
}) : syncStatus = NotConnectedSyncStatus(),
|
}) : syncStatus = NotConnectedSyncStatus(),
|
||||||
_password = password,
|
_password = password,
|
||||||
_mnemonic = mnemonic,
|
_mnemonic = mnemonic,
|
||||||
_hexPrivateKey = privateKey,
|
_hexPrivateKey = privateKey,
|
||||||
_isTransactionUpdating = false,
|
_isTransactionUpdating = false,
|
||||||
|
_encryptionFileUtils = encryptionFileUtils,
|
||||||
_client = EthereumClient(),
|
_client = EthereumClient(),
|
||||||
walletAddresses = EthereumWalletAddresses(walletInfo),
|
walletAddresses = EthereumWalletAddresses(walletInfo),
|
||||||
balance = ObservableMap<CryptoCurrency, ERC20Balance>.of(
|
balance = ObservableMap<CryptoCurrency, ERC20Balance>.of(
|
||||||
{CryptoCurrency.eth: initialBalance ?? ERC20Balance(BigInt.zero)}),
|
{CryptoCurrency.eth: initialBalance ?? ERC20Balance(BigInt.zero)}),
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
this.walletInfo = walletInfo;
|
this.walletInfo = walletInfo;
|
||||||
transactionHistory = EthereumTransactionHistory(walletInfo: walletInfo, password: password);
|
transactionHistory = EthereumTransactionHistory(
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
password: password,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
|
);
|
||||||
|
|
||||||
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
|
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
|
||||||
CakeHive.registerAdapter(Erc20TokenAdapter());
|
CakeHive.registerAdapter(Erc20TokenAdapter());
|
||||||
|
@ -72,6 +79,8 @@ abstract class EthereumWalletBase
|
||||||
final String? _hexPrivateKey;
|
final String? _hexPrivateKey;
|
||||||
final String _password;
|
final String _password;
|
||||||
|
|
||||||
|
final EncryptionFileUtils _encryptionFileUtils;
|
||||||
|
|
||||||
late final Box<Erc20Token> erc20TokensBox;
|
late final Box<Erc20Token> erc20TokensBox;
|
||||||
|
|
||||||
late final EthPrivateKey _ethPrivateKey;
|
late final EthPrivateKey _ethPrivateKey;
|
||||||
|
@ -301,7 +310,7 @@ abstract class EthereumWalletBase
|
||||||
Future<void> save() async {
|
Future<void> save() async {
|
||||||
await walletAddresses.updateAddressesInBox();
|
await walletAddresses.updateAddressesInBox();
|
||||||
final path = await makePath();
|
final path = await makePath();
|
||||||
await write(path: path, password: _password, data: toJSON());
|
await _encryptionFileUtils.write(path: path, password: _password, data: toJSON());
|
||||||
await transactionHistory.save();
|
await transactionHistory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,9 +353,10 @@ abstract class EthereumWalletBase
|
||||||
required String name,
|
required String name,
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
}) async {
|
}) async {
|
||||||
final path = await pathForWallet(name: name, type: walletInfo.type);
|
final path = await pathForWallet(name: name, type: walletInfo.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 data = json.decode(jsonSource) as Map;
|
||||||
final mnemonic = data['mnemonic'] as String?;
|
final mnemonic = data['mnemonic'] as String?;
|
||||||
final privateKey = data['private_key'] as String?;
|
final privateKey = data['private_key'] as String?;
|
||||||
|
@ -358,6 +368,7 @@ abstract class EthereumWalletBase
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
privateKey: privateKey,
|
privateKey: privateKey,
|
||||||
initialBalance: balance,
|
initialBalance: balance,
|
||||||
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:cw_ethereum/encryption_file_utils.dart';
|
||||||
import 'package:cw_ethereum/ethereum_mnemonics.dart';
|
import 'package:cw_ethereum/ethereum_mnemonics.dart';
|
||||||
import 'package:cw_ethereum/ethereum_wallet.dart';
|
import 'package:cw_ethereum/ethereum_wallet.dart';
|
||||||
import 'package:cw_ethereum/ethereum_wallet_creation_credentials.dart';
|
import 'package:cw_ethereum/ethereum_wallet_creation_credentials.dart';
|
||||||
|
@ -14,9 +15,10 @@ import 'package:collection/collection.dart';
|
||||||
|
|
||||||
class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
|
class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
|
||||||
EthereumRestoreWalletFromSeedCredentials, EthereumRestoreWalletFromPrivateKey> {
|
EthereumRestoreWalletFromSeedCredentials, EthereumRestoreWalletFromPrivateKey> {
|
||||||
EthereumWalletService(this.walletInfoSource);
|
EthereumWalletService(this.walletInfoSource, this.isDirect);
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
final bool isDirect;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<EthereumWallet> create(EthereumNewWalletCredentials credentials) async {
|
Future<EthereumWallet> create(EthereumNewWalletCredentials credentials) async {
|
||||||
|
@ -25,6 +27,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -49,6 +52,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -60,8 +64,8 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
|
||||||
@override
|
@override
|
||||||
Future<void> remove(String wallet) async {
|
Future<void> remove(String wallet) async {
|
||||||
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
|
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
|
||||||
final walletInfo = walletInfoSource.values.firstWhereOrNull(
|
final walletInfo = walletInfoSource.values
|
||||||
(info) => info.id == WalletBase.idFor(wallet, getType()))!;
|
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
|
||||||
await walletInfoSource.delete(walletInfo.key);
|
await walletInfoSource.delete(walletInfo.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +75,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
privateKey: credentials.privateKey,
|
privateKey: credentials.privateKey,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -91,6 +96,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
mnemonic: credentials.mnemonic,
|
mnemonic: credentials.mnemonic,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -105,7 +111,11 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
|
||||||
final currentWalletInfo = walletInfoSource.values
|
final currentWalletInfo = walletInfoSource.values
|
||||||
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||||
final currentWallet = await EthereumWalletBase.open(
|
final currentWallet = await EthereumWalletBase.open(
|
||||||
password: password, name: currentName, walletInfo: currentWalletInfo);
|
password: password,
|
||||||
|
name: currentName,
|
||||||
|
walletInfo: currentWalletInfo,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,11 @@ dependencies:
|
||||||
shared_preferences: ^2.0.15
|
shared_preferences: ^2.0.15
|
||||||
cw_core:
|
cw_core:
|
||||||
path: ../cw_core
|
path: ../cw_core
|
||||||
|
cake_backup:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/cake_backup.git
|
||||||
|
ref: main
|
||||||
|
version: 1.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
@ -748,11 +748,9 @@ Future<void> setup({
|
||||||
getIt.registerFactoryParam<WalletService, WalletType, void>((WalletType param1, __) {
|
getIt.registerFactoryParam<WalletService, WalletType, void>((WalletType param1, __) {
|
||||||
switch (param1) {
|
switch (param1) {
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
return haven!.createHavenWalletService(
|
return haven!.createHavenWalletService(_walletInfoSource);
|
||||||
_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
|
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
return monero!.createMoneroWalletService(_walletInfoSource, _unspentCoinsInfoSource,
|
return monero!.createMoneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||||
SettingsStoreBase.walletPasswordDirectInput);
|
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
return bitcoin!.createBitcoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!,
|
return bitcoin!.createBitcoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!,
|
||||||
SettingsStoreBase.walletPasswordDirectInput);
|
SettingsStoreBase.walletPasswordDirectInput);
|
||||||
|
|
|
@ -4,8 +4,8 @@ class CWEthereum extends Ethereum {
|
||||||
@override
|
@override
|
||||||
List<String> getEthereumWordList(String language) => EthereumMnemonics.englishWordlist;
|
List<String> getEthereumWordList(String language) => EthereumMnemonics.englishWordlist;
|
||||||
|
|
||||||
WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource) =>
|
WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
|
||||||
EthereumWalletService(walletInfoSource);
|
EthereumWalletService(walletInfoSource, isDirect);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createEthereumNewWalletCredentials({
|
WalletCredentials createEthereumNewWalletCredentials({
|
||||||
|
|
|
@ -496,7 +496,7 @@ import 'package:cw_ethereum/ethereum_transaction_priority.dart';
|
||||||
const ethereumContent = """
|
const ethereumContent = """
|
||||||
abstract class Ethereum {
|
abstract class Ethereum {
|
||||||
List<String> getEthereumWordList(String language);
|
List<String> getEthereumWordList(String language);
|
||||||
WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource);
|
WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource, bool isDirect);
|
||||||
WalletCredentials createEthereumNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password});
|
WalletCredentials createEthereumNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password});
|
||||||
WalletCredentials createEthereumRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password});
|
WalletCredentials createEthereumRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password});
|
||||||
WalletCredentials createEthereumRestoreWalletFromPrivateKey({required String name, required String privateKey, required String password});
|
WalletCredentials createEthereumRestoreWalletFromPrivateKey({required String name, required String privateKey, required String password});
|
||||||
|
|
Loading…
Reference in a new issue