Release 4.4.3 (#415)

* Add ability for change password for wallets classes. * Update generateWalletPassword * Add WalletLoadingService * Add update monero password after wallet loading. * Update version for Cake Wallet to 4.4.2 (103) * Changed version for Cake Wallet to 4.4.3 (104). * Changed version for Cake Wallet android * Changed version for Monero.com ios and android.

mkyq committed Jul 19, 2022 at 15:29 UTC b72443a8c4f2fb50e34a7e5510afb52cf13f366d
25 files changed +214 -41
cw_bitcoin/lib/electrum_transaction_history.dart
+6 -1
@@ -24,7 +24,7 @@ abstract class ElectrumTransactionHistoryBase
24 }
25
26 final WalletInfo walletInfo;
27 - final String _password;
27 + String _password;
28 int _height;
29
30 Future<void> init() async => await _load();
@@ -51,6 +51,11 @@ abstract class ElectrumTransactionHistoryBase
51 }
52 }
53
54 + Future<void> changePassword(String password) async {
55 + _password = password;
56 + await save();
57 + }
58 +
59 Future<Map<String, Object>> _read() async {
60 final dirPath =
61 await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
cw_bitcoin/lib/electrum_wallet.dart
+8 -1
@@ -109,7 +109,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
109 BitcoinWalletKeys get keys => BitcoinWalletKeys(
110 wif: hd.wif, privateKey: hd.privKey, publicKey: hd.pubKey);
111
112 - final String _password;
112 + String _password;
113 List<BitcoinUnspent> unspentCoins;
114 List<int> _feeRates;
115 Map<String, BehaviorSubject<Object>> _scripthashesUpdateSubject;
@@ -392,6 +392,13 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
392 await transactionHistory.save();
393 }
394
395 + @override
396 + Future<void> changePassword(String password) async {
397 + _password = password;
398 + await save();
399 + await transactionHistory.changePassword(password);
400 + }
401 +
402 bitcoin.ECPair keyPairFor({@required int index}) =>
403 generateKeyPair(hd: hd, index: index, network: networkType);
404
cw_core/lib/wallet_base.dart
+2
@@ -69,4 +69,6 @@ abstract class WalletBase<
69 Future<void> rescan({int height});
70
71 void close();
72 +
73 + Future<void> changePassword(String password);
74 }
cw_haven/ios/Classes/haven_api.cpp
+10
@@ -565,6 +565,16 @@ extern "C"
565 store_lock.unlock();
566 }
567
568 + bool set_password(char *password, Utf8Box &error) {
569 + bool is_changed = get_current_wallet()->setPassword(std::string(password));
570 +
571 + if (!is_changed) {
572 + error = Utf8Box(strdup(get_current_wallet()->errorString().c_str()));
573 + }
574 +
575 + return is_changed;
576 + }
577 +
578 bool transaction_create(char *address, char *asset_type, char *payment_id, char *amount,
579 uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
580 {
cw_haven/lib/api/signatures.dart
+2
@@ -51,6 +51,8 @@ typedef set_recovering_from_seed = Void Function(Int8);
51
52 typedef store_c = Void Function(Pointer<Utf8>);
53
54 +typedef set_password = Int8 Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
55 +
56 typedef set_listener = Void Function();
57
58 typedef get_syncing_height = Int64 Function();
cw_haven/lib/api/types.dart
+2
@@ -51,6 +51,8 @@ typedef SetRecoveringFromSeed = void Function(int);
51
52 typedef Store = void Function(Pointer<Utf8>);
53
54 +typedef SetPassword = int Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
55 +
56 typedef SetListener = void Function();
57
58 typedef GetSyncingHeight = int Function();
cw_haven/lib/api/wallet.dart
+19
@@ -1,6 +1,7 @@
1 import 'dart:async';
2 import 'dart:ffi';
3 import 'package:ffi/ffi.dart';
4 +import 'package:cw_haven/api/structs/ut8_box.dart';
5 import 'package:cw_haven/api/convert_utf8_to_string.dart';
6 import 'package:cw_haven/api/signatures.dart';
7 import 'package:cw_haven/api/types.dart';
@@ -67,6 +68,9 @@ final setRecoveringFromSeedNative = havenApi
68 final storeNative =
69 havenApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
70
71 +final setPasswordNative =
72 + havenApi.lookup<NativeFunction<set_password>>('set_password').asFunction<SetPassword>();
73 +
74 final setListenerNative = havenApi
75 .lookup<NativeFunction<set_listener>>('set_listener')
76 .asFunction<SetListener>();
@@ -193,6 +197,21 @@ void storeSync() {
197 free(pathPointer);
198 }
199
200 +void setPasswordSync(String password) {
201 + final passwordPointer = Utf8.toUtf8(password);
202 + final errorMessagePointer = allocate<Utf8Box>();
203 + final changed = setPasswordNative(passwordPointer, errorMessagePointer) != 0;
204 + free(passwordPointer);
205 +
206 + if (!changed) {
207 + final message = errorMessagePointer.ref.getValue();
208 + free(errorMessagePointer);
209 + throw Exception(message);
210 + }
211 +
212 + free(errorMessagePointer);
213 +}
214 +
215 void closeCurrentWallet() => closeCurrentWalletNative();
216
217 String getSecretViewKey() =>
cw_haven/lib/haven_wallet.dart
+5
@@ -240,6 +240,11 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
240 await haven_wallet.store();
241 }
242
243 + @override
244 + Future<void> changePassword(String password) async {
245 + haven_wallet.setPasswordSync(password);
246 + }
247 +
248 Future<int> getNodeHeight() async => haven_wallet.getNodeHeight();
249
250 Future<bool> isConnected() async => haven_wallet.isConnected();
cw_monero/ios/Classes/monero_api.cpp
+10
@@ -467,6 +467,16 @@ extern "C"
467 store_lock.unlock();
468 }
469
470 + bool set_password(char *password, Utf8Box &error) {
471 + bool is_changed = get_current_wallet()->setPassword(std::string(password));
472 +
473 + if (!is_changed) {
474 + error = Utf8Box(strdup(get_current_wallet()->errorString().c_str()));
475 + }
476 +
477 + return is_changed;
478 + }
479 +
480 bool transaction_create(char *address, char *payment_id, char *amount,
481 uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
482 {
cw_monero/lib/api/signatures.dart
+2
@@ -47,6 +47,8 @@ typedef set_recovering_from_seed = Void Function(Int8);
47
48 typedef store_c = Void Function(Pointer<Utf8>);
49
50 +typedef set_password = Int8 Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
51 +
52 typedef set_listener = Void Function();
53
54 typedef get_syncing_height = Int64 Function();
cw_monero/lib/api/types.dart
+2
@@ -47,6 +47,8 @@ typedef SetRecoveringFromSeed = void Function(int);
47
48 typedef Store = void Function(Pointer<Utf8>);
49
50 +typedef SetPassword = int Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
51 +
52 typedef SetListener = void Function();
53
54 typedef GetSyncingHeight = int Function();
cw_monero/lib/api/wallet.dart
+19
@@ -1,6 +1,7 @@
1 import 'dart:async';
2 import 'dart:ffi';
3 import 'package:ffi/ffi.dart';
4 +import 'package:cw_monero/api/structs/ut8_box.dart';
5 import 'package:cw_monero/api/convert_utf8_to_string.dart';
6 import 'package:cw_monero/api/signatures.dart';
7 import 'package:cw_monero/api/types.dart';
@@ -67,6 +68,9 @@ final setRecoveringFromSeedNative = moneroApi
68 final storeNative =
69 moneroApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
70
71 +final setPasswordNative =
72 + moneroApi.lookup<NativeFunction<set_password>>('set_password').asFunction<SetPassword>();
73 +
74 final setListenerNative = moneroApi
75 .lookup<NativeFunction<set_listener>>('set_listener')
76 .asFunction<SetListener>();
@@ -197,6 +201,21 @@ void storeSync() {
201 free(pathPointer);
202 }
203
204 +void setPasswordSync(String password) {
205 + final passwordPointer = Utf8.toUtf8(password);
206 + final errorMessagePointer = allocate<Utf8Box>();
207 + final changed = setPasswordNative(passwordPointer, errorMessagePointer) != 0;
208 + free(passwordPointer);
209 +
210 + if (!changed) {
211 + final message = errorMessagePointer.ref.getValue();
212 + free(errorMessagePointer);
213 + throw Exception(message);
214 + }
215 +
216 + free(errorMessagePointer);
217 +}
218 +
219 void closeCurrentWallet() => closeCurrentWalletNative();
220
221 String getSecretViewKey() =>
cw_monero/lib/monero_wallet.dart
+5
@@ -258,6 +258,11 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
258 await monero_wallet.store();
259 }
260
261 + @override
262 + Future<void> changePassword(String password) async {
263 + monero_wallet.setPasswordSync(password);
264 + }
265 +
266 Future<int> getNodeHeight() async => monero_wallet.getNodeHeight();
267
268 Future<bool> isConnected() async => monero_wallet.isConnected();
lib/core/generate_wallet_password.dart
+2 -8
@@ -1,12 +1,6 @@
1 import 'package:uuid/uuid.dart';
2 import 'package:cw_core/key.dart';
3 -import 'package:cw_core/wallet_type.dart';
3
5 -String generateWalletPassword(WalletType type) {
6 - switch (type) {
7 - case WalletType.monero:
8 - return Uuid().v4();
9 - default:
10 - return generateKey();
11 - }
4 +String generateWalletPassword() {
5 + return generateKey();
6 }
lib/core/wallet_creation_service.dart
+36 -6
@@ -1,5 +1,6 @@
1 import 'package:cake_wallet/di.dart';
2 import 'package:cw_core/wallet_info.dart';
3 +import 'package:cake_wallet/entities/preferences_key.dart';
4 import 'package:flutter/foundation.dart';
5 import 'package:flutter_secure_storage/flutter_secure_storage.dart';
6 import 'package:hive/hive.dart';
@@ -31,6 +32,8 @@ class WalletCreationService {
32 final Box<WalletInfo> walletInfoSource;
33 WalletService _service;
34
35 + static const _isNewMoneroWalletPasswordUpdated = true;
36 +
37 void changeWalletType({@required WalletType type}) {
38 this.type = type;
39 _service = getIt.get<WalletService>(param1: type);
@@ -51,28 +54,55 @@ class WalletCreationService {
54
55 Future<WalletBase> create(WalletCredentials credentials) async {
56 checkIfExists(credentials.name);
54 - final password = generateWalletPassword(type);
57 + final password = generateWalletPassword();
58 credentials.password = password;
59 await keyService.saveWalletPassword(
60 password: password, walletName: credentials.name);
58 - return await _service.create(credentials);
61 + final wallet = await _service.create(credentials);
62 +
63 + if (wallet.type == WalletType.monero) {
64 + await sharedPreferences
65 + .setBool(
66 + PreferencesKey.moneroWalletUpdateV1Key(wallet.name),
67 + _isNewMoneroWalletPasswordUpdated);
68 + }
69 +
70 + return wallet;
71 }
72
73 Future<WalletBase> restoreFromKeys(WalletCredentials credentials) async {
74 checkIfExists(credentials.name);
63 - final password = generateWalletPassword(type);
75 + final password = generateWalletPassword();
76 credentials.password = password;
77 await keyService.saveWalletPassword(
78 password: password, walletName: credentials.name);
67 - return await _service.restoreFromKeys(credentials);
79 + final wallet = await _service.restoreFromKeys(credentials);
80 +
81 + if (wallet.type == WalletType.monero) {
82 + await sharedPreferences
83 + .setBool(
84 + PreferencesKey.moneroWalletUpdateV1Key(wallet.name),
85 + _isNewMoneroWalletPasswordUpdated);
86 + }
87 +
88 + return wallet;
89 }
90
91 Future<WalletBase> restoreFromSeed(WalletCredentials credentials) async {
92 checkIfExists(credentials.name);
72 - final password = generateWalletPassword(type);
93 + final password = generateWalletPassword();
94 credentials.password = password;
95 await keyService.saveWalletPassword(
96 password: password, walletName: credentials.name);
76 - return await _service.restoreFromSeed(credentials);
97 + final wallet = await _service.restoreFromSeed(credentials);
98 +
99 + if (wallet.type == WalletType.monero) {
100 + await sharedPreferences
101 + .setBool(
102 + PreferencesKey.moneroWalletUpdateV1Key(wallet.name),
103 + _isNewMoneroWalletPasswordUpdated);
104 + }
105 +
106 + return wallet;
107 }
108 }
lib/core/wallet_loading_service.dart new
+52
@@ -0,0 +1,52 @@
1 +import 'package:cake_wallet/core/generate_wallet_password.dart';
2 +import 'package:cake_wallet/core/key_service.dart';
3 +import 'package:cake_wallet/entities/preferences_key.dart';
4 +import 'package:cw_core/wallet_base.dart';
5 +import 'package:cw_core/wallet_service.dart';
6 +import 'package:cw_core/wallet_type.dart';
7 +import 'package:shared_preferences/shared_preferences.dart';
8 +
9 +class WalletLoadingService {
10 + WalletLoadingService(
11 + this.sharedPreferences,
12 + this.keyService,
13 + this.walletServiceFactory);
14 +
15 + final SharedPreferences sharedPreferences;
16 + final KeyService keyService;
17 + final WalletService Function(WalletType type) walletServiceFactory;
18 +
19 + Future<WalletBase> load(WalletType type, String name) async {
20 + if (walletServiceFactory == null) {
21 + throw Exception('WalletLoadingService.walletServiceFactory is not set');
22 + }
23 + final walletService = walletServiceFactory?.call(type);
24 + final password = await keyService.getWalletPassword(walletName: name);
25 + final wallet = await walletService.openWallet(name, password);
26 +
27 + if (type == WalletType.monero) {
28 + await upateMoneroWalletPassword(wallet);
29 + }
30 +
31 + return wallet;
32 + }
33 +
34 + Future<void> upateMoneroWalletPassword(WalletBase wallet) async {
35 + final key = PreferencesKey.moneroWalletUpdateV1Key(wallet.name);
36 + var isPasswordUpdated = sharedPreferences.getBool(key) ?? false;
37 +
38 + if (isPasswordUpdated) {
39 + return;
40 + }
41 +
42 + final password = generateWalletPassword();
43 + // Save new generated password with backup key for case
44 + // if wallet will change password, but it will faild to updated in secure storage
45 + final bakWalletName = '#__${wallet.name}_bak__#';
46 + await keyService.saveWalletPassword(walletName: bakWalletName, password: password);
47 + await wallet.changePassword(password);
48 + await keyService.saveWalletPassword(walletName: wallet.name, password: password);
49 + isPasswordUpdated = true;
50 + await sharedPreferences.setBool(key, isPasswordUpdated);
51 + }
52 +}
\ No newline at end of file
lib/di.dart
+8 -1
@@ -124,6 +124,7 @@ import 'package:cake_wallet/exchange/exchange_template.dart';
124 import 'package:cake_wallet/.secrets.g.dart' as secrets;
125 import 'package:cake_wallet/src/screens/dashboard/widgets/address_page.dart';
126 import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
127 +import 'package:cake_wallet/core/wallet_loading_service.dart';
128
129 final getIt = GetIt.instance;
130
@@ -218,6 +219,12 @@ Future setup(
219 sharedPreferences: getIt.get<SharedPreferences>(),
220 walletInfoSource: _walletInfoSource));
221
222 + getIt.registerFactory<WalletLoadingService>(
223 + () => WalletLoadingService(
224 + getIt.get<SharedPreferences>(),
225 + getIt.get<KeyService>(),
226 + (WalletType type) => getIt.get<WalletService>(param1: type)));
227 +
228 getIt.registerFactoryParam<WalletNewVM, WalletType, void>((type, _) =>
229 WalletNewVM(getIt.get<AppStore>(),
230 getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
@@ -352,7 +359,7 @@ Future setup(
359 getIt.registerFactory(() => WalletListViewModel(
360 _walletInfoSource,
361 getIt.get<AppStore>(),
355 - getIt.get<KeyService>()));
362 + getIt.get<WalletLoadingService>()));
363
364 getIt.registerFactory(() =>
365 WalletListPage(walletListViewModel: getIt.get<WalletListViewModel>()));
lib/entities/load_current_wallet.dart
+3 -4
@@ -5,6 +5,7 @@ import 'package:cake_wallet/core/key_service.dart';
5 import 'package:cw_core/wallet_service.dart';
6 import 'package:cake_wallet/entities/preferences_key.dart';
7 import 'package:cw_core/wallet_type.dart';
8 +import 'package:cake_wallet/core/wallet_loading_service.dart';
9
10 Future<void> loadCurrentWallet() async {
11 final appStore = getIt.get<AppStore>();
@@ -15,9 +16,7 @@ Future<void> loadCurrentWallet() async {
16 getIt.get<SharedPreferences>().getInt(PreferencesKey.currentWalletType) ??
17 0;
18 final type = deserializeFromInt(typeRaw);
18 - final password =
19 - await getIt.get<KeyService>().getWalletPassword(walletName: name);
20 - final _service = getIt.get<WalletService>(param1: type);
21 - final wallet = await _service.openWallet(name, password);
19 + final walletLoadingService = getIt.get<WalletLoadingService>();
20 + final wallet = await walletLoadingService.load(type, name);
21 appStore.changeCurrentWallet(wallet);
22 }
lib/entities/preferences_key.dart
+4
@@ -22,4 +22,8 @@ class PreferencesKey {
22 static const bitcoinTransactionPriority = 'current_fee_priority_bitcoin';
23 static const shouldShowReceiveWarning = 'should_show_receive_warning';
24 static const shouldShowYatPopup = 'should_show_yat_popup';
25 + static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
26 +
27 + static String moneroWalletUpdateV1Key(String name)
28 + => '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
29 }
lib/view_model/wallet_list/wallet_list_view_model.dart
+6 -9
@@ -1,9 +1,9 @@
1 +import 'package:cake_wallet/core/wallet_loading_service.dart';
2 import 'package:cake_wallet/view_model/wallet_new_vm.dart';
3 import 'package:hive/hive.dart';
4 import 'package:mobx/mobx.dart';
5 import 'package:cake_wallet/di.dart';
6 import 'package:cake_wallet/store/app_store.dart';
6 -import 'package:cake_wallet/core/key_service.dart';
7 import 'package:cw_core/wallet_service.dart';
8 import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
9 import 'package:cw_core/wallet_info.dart';
@@ -16,7 +16,7 @@ class WalletListViewModel = WalletListViewModelBase with _$WalletListViewModel;
16
17 abstract class WalletListViewModelBase with Store {
18 WalletListViewModelBase(this._walletInfoSource, this._appStore,
19 - this._keyService) {
19 + this._walletLoadingService) {
20 wallets = ObservableList<WalletListItem>();
21 _updateList();
22 }
@@ -26,17 +26,14 @@ abstract class WalletListViewModelBase with Store {
26
27 final AppStore _appStore;
28 final Box<WalletInfo> _walletInfoSource;
29 - final KeyService _keyService;
29 + final WalletLoadingService _walletLoadingService;
30
31 WalletType get currentWalletType => _appStore.wallet.type;
32
33 @action
34 - Future<void> loadWallet(WalletListItem wallet) async {
35 - final password =
36 - await _keyService.getWalletPassword(walletName: wallet.name);
37 - final walletService = getIt.get<WalletService>(param1: wallet.type);
38 - final loadedWallet = await walletService.openWallet(wallet.name, password);
39 - _appStore.changeCurrentWallet(loadedWallet);
34 + Future<void> loadWallet(WalletListItem walletItem) async {
35 + final wallet = await _walletLoadingService.load(walletItem.type, walletItem.name);
36 + _appStore.changeCurrentWallet(wallet);
37 _updateList();
38 }
39
lib/view_model/wallet_restoration_from_keys_vm.dart
+1 -1
@@ -45,7 +45,7 @@ abstract class WalletRestorationFromKeysVMBase extends WalletCreationVM
45
46 @override
47 WalletCredentials getCredentials(dynamic options) {
48 - final password = generateWalletPassword(type);
48 + final password = generateWalletPassword();
49
50 switch (type) {
51 case WalletType.monero:
lib/view_model/wallet_restoration_from_seed_vm.dart
+1 -1
@@ -36,7 +36,7 @@ abstract class WalletRestorationFromSeedVMBase extends WalletCreationVM
36
37 @override
38 WalletCredentials getCredentials(dynamic options) {
39 - final password = generateWalletPassword(type);
39 + final password = generateWalletPassword();
40
41 switch (type) {
42 case WalletType.monero:
lib/view_model/wallet_restore_view_model.dart
+1 -1
@@ -53,7 +53,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
53
54 @override
55 WalletCredentials getCredentials(dynamic options) {
56 - final password = generateWalletPassword(type);
56 + final password = generateWalletPassword();
57 final height = options['height'] as int;
58 name = options['name'] as String;
59
scripts/android/app_env.sh
+4 -4
@@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
14 APP_ANDROID_TYPE=$1
15
16 MONERO_COM_NAME="Monero.com"
17 -MONERO_COM_VERSION="1.0.6"
18 -MONERO_COM_BUILD_NUMBER=13
17 +MONERO_COM_VERSION="1.0.7"
18 +MONERO_COM_BUILD_NUMBER=14
19 MONERO_COM_BUNDLE_ID="com.monero.app"
20 MONERO_COM_PACKAGE="com.monero.app"
21
22 CAKEWALLET_NAME="Cake Wallet"
23 -CAKEWALLET_VERSION="4.4.1"
24 -CAKEWALLET_BUILD_NUMBER=104
23 +CAKEWALLET_VERSION="4.4.3"
24 +CAKEWALLET_BUILD_NUMBER=105
25 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
26 CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
27
scripts/ios/app_env.sh
+4 -4
@@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
13 APP_IOS_TYPE=$1
14
15 MONERO_COM_NAME="Monero.com"
16 -MONERO_COM_VERSION="1.0.6"
17 -MONERO_COM_BUILD_NUMBER=16
16 +MONERO_COM_VERSION="1.0.7"
17 +MONERO_COM_BUILD_NUMBER=17
18 MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
19
20 CAKEWALLET_NAME="Cake Wallet"
21 -CAKEWALLET_VERSION="4.4.1"
22 -CAKEWALLET_BUILD_NUMBER=100
21 +CAKEWALLET_VERSION="4.4.3"
22 +CAKEWALLET_BUILD_NUMBER=104
23 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
24
25 HAVEN_NAME="Haven"