mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Backup stuff.
This commit is contained in:
parent
9a79fcdc23
commit
47ceac2dd6
24 changed files with 459 additions and 253 deletions
|
@ -14,128 +14,58 @@ import 'package:cake_wallet/entities/encrypt.dart';
|
|||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
|
||||
class BackupService {
|
||||
BackupService(this._flutterSecureStorage, this._authService,
|
||||
this._walletInfoSource, this._keyService, this._sharedPreferences)
|
||||
BackupService(this._flutterSecureStorage, this._walletInfoSource,
|
||||
this._keyService, this._sharedPreferences)
|
||||
: _cipher = chacha20Poly1305Aead;
|
||||
|
||||
static const currentVersion = _v1;
|
||||
|
||||
static const _v1 = 1;
|
||||
|
||||
final Cipher _cipher;
|
||||
final FlutterSecureStorage _flutterSecureStorage;
|
||||
final SharedPreferences _sharedPreferences;
|
||||
final AuthService _authService;
|
||||
final Box<WalletInfo> _walletInfoSource;
|
||||
final KeyService _keyService;
|
||||
|
||||
Future<void> importBackup(Uint8List data, String password,
|
||||
{@required String nonce}) async {
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final decryptedData = await _decrypt(data, password, nonce);
|
||||
final zip = ZipDecoder().decodeBytes(decryptedData);
|
||||
{String nonce = secrets.backupSalt}) async {
|
||||
final version = getVersion(data);
|
||||
final backupBytes = data.toList()..removeAt(0);
|
||||
final backupData = Uint8List.fromList(backupBytes);
|
||||
|
||||
zip.files.forEach((file) {
|
||||
final filename = file.name;
|
||||
|
||||
if (file.isFile) {
|
||||
final data = file.content as List<int>;
|
||||
File('${appDir.path}/' + filename)
|
||||
..createSync(recursive: true)
|
||||
..writeAsBytesSync(data);
|
||||
} else {
|
||||
Directory('${appDir.path}/' + filename)..create(recursive: true);
|
||||
}
|
||||
|
||||
print(filename);
|
||||
});
|
||||
|
||||
await importKeychainDump(password, nonce: nonce);
|
||||
await importPreferencesDump();
|
||||
}
|
||||
|
||||
Future<void> importPreferencesDump() async {
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final preferencesFile = File('${appDir.path}/~_preferences_dump');
|
||||
|
||||
if (!preferencesFile.existsSync()) {
|
||||
return;
|
||||
switch (version) {
|
||||
case _v1:
|
||||
await _importBackupV1(backupData, password, nonce: nonce);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
final data =
|
||||
json.decode(preferencesFile.readAsStringSync()) as Map<String, Object>;
|
||||
print('data $data');
|
||||
|
||||
await _sharedPreferences.setString(PreferencesKey.currentWalletName,
|
||||
data[PreferencesKey.currentWalletName] as String);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentNodeIdKey,
|
||||
data[PreferencesKey.currentNodeIdKey] as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentBalanceDisplayModeKey,
|
||||
data[PreferencesKey.currentBalanceDisplayModeKey] as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentWalletType,
|
||||
data[PreferencesKey.currentWalletType] as int);
|
||||
await _sharedPreferences.setString(PreferencesKey.currentFiatCurrencyKey,
|
||||
data[PreferencesKey.currentFiatCurrencyKey] as String);
|
||||
await _sharedPreferences.setBool(
|
||||
PreferencesKey.shouldSaveRecipientAddressKey,
|
||||
data[PreferencesKey.shouldSaveRecipientAddressKey] as bool);
|
||||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentTransactionPriorityKey,
|
||||
data[PreferencesKey.currentTransactionPriorityKey] as int);
|
||||
await _sharedPreferences.setBool(
|
||||
PreferencesKey.allowBiometricalAuthenticationKey,
|
||||
data[PreferencesKey.allowBiometricalAuthenticationKey] as bool);
|
||||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentBitcoinElectrumSererIdKey,
|
||||
data[PreferencesKey.currentBitcoinElectrumSererIdKey] as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentLanguageCode,
|
||||
data[PreferencesKey.currentLanguageCode] as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.displayActionListModeKey,
|
||||
data[PreferencesKey.displayActionListModeKey] as int);
|
||||
await _sharedPreferences.setInt(
|
||||
'current_theme', data['current_theme'] as int);
|
||||
|
||||
await preferencesFile.delete();
|
||||
}
|
||||
|
||||
Future<void> importKeychainDump(String password,
|
||||
{@required String nonce}) async {
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
|
||||
final decryptedKeychainDumpFileData =
|
||||
await _decrypt(keychainDumpFile.readAsBytesSync(), password, nonce);
|
||||
final keychainJSON = json.decode(utf8.decode(decryptedKeychainDumpFileData))
|
||||
as Map<String, dynamic>;
|
||||
final keychainWalletsInfo = keychainJSON['wallets'] as List;
|
||||
final decodedPin = keychainJSON['pin'] as String;
|
||||
final pinCodeKey = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||
|
||||
keychainWalletsInfo.forEach((dynamic rawInfo) async {
|
||||
final info = rawInfo as Map<String, dynamic>;
|
||||
await importWalletKeychainInfo(info);
|
||||
});
|
||||
|
||||
await _flutterSecureStorage.write(
|
||||
key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
|
||||
|
||||
keychainDumpFile.deleteSync();
|
||||
}
|
||||
|
||||
Future<void> importWalletKeychainInfo(Map<String, dynamic> info) async {
|
||||
final name = info['name'] as String;
|
||||
final password = info['password'] as String;
|
||||
|
||||
await _keyService.saveWalletPassword(walletName: name, password: password);
|
||||
}
|
||||
|
||||
Future<Uint8List> exportBackup(String password,
|
||||
{@required String nonce}) async {
|
||||
{String nonce = secrets.backupSalt, int version = currentVersion}) async {
|
||||
switch (version) {
|
||||
case _v1:
|
||||
return await _exportBackupV1(password, nonce: nonce);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Uint8List> _exportBackupV1(String password,
|
||||
{String nonce = secrets.backupSalt}) async {
|
||||
final zipEncoder = ZipFileEncoder();
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final now = DateTime.now();
|
||||
final tmpDir = Directory('${appDir.path}/~_BACKUP_TMP');
|
||||
final archivePath = '${tmpDir.path}/backup_${now.toString()}.zip';
|
||||
final fileEntities = appDir.listSync(recursive: false);
|
||||
final keychainDump = await exportKeychainDump(password, nonce: nonce);
|
||||
final preferencesDump = await exportPreferencesJSON();
|
||||
final keychainDump = await _exportKeychainDump(password, nonce: nonce);
|
||||
final preferencesDump = await _exportPreferencesJSON();
|
||||
final preferencesDumpFile = File('${tmpDir.path}/~_preferences_dump_TMP');
|
||||
final keychainDumpFile = File('${tmpDir.path}/~_keychain_dump_TMP');
|
||||
|
||||
|
@ -165,12 +95,120 @@ class BackupService {
|
|||
|
||||
final content = File(archivePath).readAsBytesSync();
|
||||
tmpDir.deleteSync(recursive: true);
|
||||
final encryptedData = await _encrypt(content, password, nonce);
|
||||
|
||||
return await _encrypt(content, password, nonce);
|
||||
return setVersion(encryptedData, currentVersion);
|
||||
}
|
||||
|
||||
Future<Uint8List> exportKeychainDump(String password,
|
||||
Future<void> _importBackupV1(Uint8List data, String password,
|
||||
{@required String nonce}) async {
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final decryptedData = await _decrypt(data, password, nonce);
|
||||
final zip = ZipDecoder().decodeBytes(decryptedData);
|
||||
|
||||
zip.files.forEach((file) {
|
||||
final filename = file.name;
|
||||
|
||||
if (file.isFile) {
|
||||
final content = file.content as List<int>;
|
||||
File('${appDir.path}/' + filename)
|
||||
..createSync(recursive: true)
|
||||
..writeAsBytesSync(content);
|
||||
} else {
|
||||
Directory('${appDir.path}/' + filename)..create(recursive: true);
|
||||
}
|
||||
});
|
||||
|
||||
await _importKeychainDump(password, nonce: nonce);
|
||||
await _importPreferencesDump();
|
||||
}
|
||||
|
||||
Future<void> _importPreferencesDump() async {
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final preferencesFile = File('${appDir.path}/~_preferences_dump');
|
||||
const defaultSettingsMigrationVersionKey = PreferencesKey.currentDefaultSettingsMigrationVersion;
|
||||
|
||||
if (!preferencesFile.existsSync()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final data =
|
||||
json.decode(preferencesFile.readAsStringSync()) as Map<String, Object>;
|
||||
|
||||
await _sharedPreferences.setString(PreferencesKey.currentWalletName,
|
||||
data[PreferencesKey.currentWalletName] as String);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentNodeIdKey,
|
||||
data[PreferencesKey.currentNodeIdKey] as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentBalanceDisplayModeKey,
|
||||
data[PreferencesKey.currentBalanceDisplayModeKey] as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentWalletType,
|
||||
data[PreferencesKey.currentWalletType] as int);
|
||||
await _sharedPreferences.setString(PreferencesKey.currentFiatCurrencyKey,
|
||||
data[PreferencesKey.currentFiatCurrencyKey] as String);
|
||||
await _sharedPreferences.setBool(
|
||||
PreferencesKey.shouldSaveRecipientAddressKey,
|
||||
data[PreferencesKey.shouldSaveRecipientAddressKey] as bool);
|
||||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentTransactionPriorityKey,
|
||||
data[PreferencesKey.currentTransactionPriorityKey] as int);
|
||||
await _sharedPreferences.setBool(
|
||||
PreferencesKey.allowBiometricalAuthenticationKey,
|
||||
data[PreferencesKey.allowBiometricalAuthenticationKey] as bool);
|
||||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentBitcoinElectrumSererIdKey,
|
||||
data[PreferencesKey.currentBitcoinElectrumSererIdKey] as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentLanguageCode,
|
||||
data[PreferencesKey.currentLanguageCode] as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.displayActionListModeKey,
|
||||
data[PreferencesKey.displayActionListModeKey] as int);
|
||||
await _sharedPreferences.setInt(
|
||||
'current_theme', data['current_theme'] as int);
|
||||
await _sharedPreferences.setInt(defaultSettingsMigrationVersionKey,
|
||||
data[defaultSettingsMigrationVersionKey] as int);
|
||||
|
||||
await preferencesFile.delete();
|
||||
}
|
||||
|
||||
Future<void> _importKeychainDump(String password,
|
||||
{@required String nonce,
|
||||
String keychainSalt = secrets.backupKeychainSalt}) async {
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
|
||||
final decryptedKeychainDumpFileData = await _decrypt(
|
||||
keychainDumpFile.readAsBytesSync(), '$keychainSalt$password', nonce);
|
||||
final keychainJSON = json.decode(utf8.decode(decryptedKeychainDumpFileData))
|
||||
as Map<String, dynamic>;
|
||||
final keychainWalletsInfo = keychainJSON['wallets'] as List;
|
||||
final decodedPin = keychainJSON['pin'] as String;
|
||||
final pinCodeKey = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||
final backupPasswordKey =
|
||||
generateStoreKeyFor(key: SecretStoreKey.backupPassword);
|
||||
final backupPassword = keychainJSON[backupPasswordKey] as String;
|
||||
|
||||
await _flutterSecureStorage.write(
|
||||
key: backupPasswordKey, value: backupPassword);
|
||||
|
||||
keychainWalletsInfo.forEach((dynamic rawInfo) async {
|
||||
final info = rawInfo as Map<String, dynamic>;
|
||||
await importWalletKeychainInfo(info);
|
||||
});
|
||||
|
||||
await _flutterSecureStorage.write(
|
||||
key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
|
||||
|
||||
keychainDumpFile.deleteSync();
|
||||
}
|
||||
|
||||
Future<void> importWalletKeychainInfo(Map<String, dynamic> info) async {
|
||||
final name = info['name'] as String;
|
||||
final password = info['password'] as String;
|
||||
|
||||
await _keyService.saveWalletPassword(walletName: name, password: password);
|
||||
}
|
||||
|
||||
Future<Uint8List> _exportKeychainDump(String password,
|
||||
{@required String nonce,
|
||||
String keychainSalt = secrets.backupKeychainSalt}) async {
|
||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||
final encodedPin = await _flutterSecureStorage.read(key: key);
|
||||
final decodedPin = decodedPinCode(pin: encodedPin);
|
||||
|
@ -183,15 +221,25 @@ class BackupService {
|
|||
await _keyService.getWalletPassword(walletName: walletInfo.name)
|
||||
};
|
||||
}));
|
||||
|
||||
final data =
|
||||
utf8.encode(json.encode({'pin': decodedPin, 'wallets': wallets}));
|
||||
final encrypted = await _encrypt(Uint8List.fromList(data), password, nonce);
|
||||
final backupPasswordKey =
|
||||
generateStoreKeyFor(key: SecretStoreKey.backupPassword);
|
||||
final backupPassword =
|
||||
await _flutterSecureStorage.read(key: backupPasswordKey);
|
||||
final data = utf8.encode(json.encode({
|
||||
'pin': decodedPin,
|
||||
'wallets': wallets,
|
||||
backupPasswordKey: backupPassword
|
||||
}));
|
||||
final encrypted = await _encrypt(
|
||||
Uint8List.fromList(data), '$keychainSalt$password', nonce);
|
||||
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
Future<String> exportPreferencesJSON() async {
|
||||
Future<String> _exportPreferencesJSON() async {
|
||||
const defaultSettingsMigrationVersionKey =
|
||||
'current_default_settings_migration_version';
|
||||
|
||||
final preferences = <String, Object>{
|
||||
PreferencesKey.currentWalletName:
|
||||
_sharedPreferences.getString(PreferencesKey.currentWalletName),
|
||||
|
@ -219,13 +267,22 @@ class BackupService {
|
|||
_sharedPreferences.getString(PreferencesKey.currentLanguageCode),
|
||||
PreferencesKey.displayActionListModeKey:
|
||||
_sharedPreferences.getInt(PreferencesKey.displayActionListModeKey),
|
||||
PreferencesKey.currentTheme: _sharedPreferences.getInt(PreferencesKey.currentTheme)
|
||||
// FIX-ME: Unnamed constant.
|
||||
PreferencesKey.currentTheme:
|
||||
_sharedPreferences.getInt(PreferencesKey.currentTheme),
|
||||
defaultSettingsMigrationVersionKey:
|
||||
_sharedPreferences.getInt(defaultSettingsMigrationVersionKey)
|
||||
};
|
||||
|
||||
return json.encode(preferences);
|
||||
}
|
||||
|
||||
int getVersion(Uint8List data) => data.toList().first;
|
||||
|
||||
Uint8List setVersion(Uint8List data, int version) {
|
||||
final bytes = data.toList()..insert(0, version);
|
||||
return Uint8List.fromList(bytes);
|
||||
}
|
||||
|
||||
Future<Uint8List> _encrypt(
|
||||
Uint8List data, String secretKeySource, String nonceBase64) async {
|
||||
final secretKeyHash = await sha256.hash(utf8.encode(secretKeySource));
|
79
lib/di.dart
79
lib/di.dart
|
@ -1,5 +1,5 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin_wallet_service.dart';
|
||||
import 'package:cake_wallet/core/backup.dart';
|
||||
import 'package:cake_wallet/core/backup_service.dart';
|
||||
import 'package:cake_wallet/core/wallet_service.dart';
|
||||
import 'package:cake_wallet/entities/biometric_auth.dart';
|
||||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
|
@ -105,6 +105,15 @@ import 'package:cake_wallet/exchange/exchange_template.dart';
|
|||
|
||||
final getIt = GetIt.instance;
|
||||
|
||||
var _isSetupFinished = false;
|
||||
Box<WalletInfo> _walletInfoSource;
|
||||
Box<Node> _nodeSource;
|
||||
Box<Contact> _contactSource;
|
||||
Box<Trade> _tradesSource;
|
||||
Box<Template> _templates;
|
||||
Box<ExchangeTemplate> _exchangeTemplates;
|
||||
Box<TransactionDescription> _transactionDescriptionBox;
|
||||
|
||||
Future setup(
|
||||
{Box<WalletInfo> walletInfoSource,
|
||||
Box<Node> nodeSource,
|
||||
|
@ -113,12 +122,26 @@ Future setup(
|
|||
Box<Template> templates,
|
||||
Box<ExchangeTemplate> exchangeTemplates,
|
||||
Box<TransactionDescription> transactionDescriptionBox}) async {
|
||||
getIt.registerSingletonAsync<SharedPreferences>(
|
||||
() => SharedPreferences.getInstance());
|
||||
_walletInfoSource = walletInfoSource;
|
||||
_nodeSource = nodeSource;
|
||||
_contactSource = contactSource;
|
||||
_tradesSource = tradesSource;
|
||||
_templates = templates;
|
||||
_exchangeTemplates = exchangeTemplates;
|
||||
_transactionDescriptionBox = transactionDescriptionBox;
|
||||
|
||||
final settingsStore = await SettingsStoreBase.load(nodeSource: nodeSource);
|
||||
if (!_isSetupFinished) {
|
||||
getIt.registerSingletonAsync<SharedPreferences>(
|
||||
() => SharedPreferences.getInstance());
|
||||
}
|
||||
|
||||
getIt.registerSingleton<Box<Node>>(nodeSource);
|
||||
final settingsStore = await SettingsStoreBase.load(nodeSource: _nodeSource);
|
||||
|
||||
if (_isSetupFinished) {
|
||||
return;
|
||||
}
|
||||
|
||||
getIt.registerFactory<Box<Node>>(() => _nodeSource);
|
||||
|
||||
getIt.registerSingleton<FlutterSecureStorage>(FlutterSecureStorage());
|
||||
getIt.registerSingleton(AuthenticationStore());
|
||||
|
@ -131,14 +154,14 @@ Future setup(
|
|||
settingsStore: getIt.get<SettingsStore>(),
|
||||
nodeListStore: getIt.get<NodeListStore>()));
|
||||
getIt.registerSingleton<TradesStore>(TradesStore(
|
||||
tradesSource: tradesSource, settingsStore: getIt.get<SettingsStore>()));
|
||||
tradesSource: _tradesSource, settingsStore: getIt.get<SettingsStore>()));
|
||||
getIt.registerSingleton<TradeFilterStore>(TradeFilterStore());
|
||||
getIt.registerSingleton<TransactionFilterStore>(TransactionFilterStore());
|
||||
getIt.registerSingleton<FiatConversionStore>(FiatConversionStore());
|
||||
getIt.registerSingleton<SendTemplateStore>(
|
||||
SendTemplateStore(templateSource: templates));
|
||||
SendTemplateStore(templateSource: _templates));
|
||||
getIt.registerSingleton<ExchangeTemplateStore>(
|
||||
ExchangeTemplateStore(templateSource: exchangeTemplates));
|
||||
ExchangeTemplateStore(templateSource: _exchangeTemplates));
|
||||
|
||||
final secretStore =
|
||||
await SecretStoreBase.load(getIt.get<FlutterSecureStorage>());
|
||||
|
@ -157,7 +180,7 @@ Future setup(
|
|||
|
||||
getIt.registerFactoryParam<WalletNewVM, WalletType, void>((type, _) =>
|
||||
WalletNewVM(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), walletInfoSource,
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
type: type));
|
||||
|
||||
getIt
|
||||
|
@ -167,7 +190,7 @@ Future setup(
|
|||
final mnemonic = args[2] as String;
|
||||
|
||||
return WalletRestorationFromSeedVM(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), walletInfoSource,
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
type: type, language: language, seed: mnemonic);
|
||||
});
|
||||
|
||||
|
@ -177,7 +200,7 @@ Future setup(
|
|||
final language = args[1] as String;
|
||||
|
||||
return WalletRestorationFromKeysVM(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), walletInfoSource,
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
type: type, language: language);
|
||||
});
|
||||
|
||||
|
@ -262,7 +285,7 @@ Future setup(
|
|||
getIt.get<AppStore>().settingsStore,
|
||||
getIt.get<SendTemplateStore>(),
|
||||
getIt.get<FiatConversionStore>(),
|
||||
transactionDescriptionBox));
|
||||
_transactionDescriptionBox));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => SendPage(sendViewModel: getIt.get<SendViewModel>()));
|
||||
|
@ -271,7 +294,7 @@ Future setup(
|
|||
() => SendTemplatePage(sendViewModel: getIt.get<SendViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => WalletListViewModel(
|
||||
walletInfoSource,
|
||||
_walletInfoSource,
|
||||
getIt.get<AppStore>(),
|
||||
getIt.get<KeyService>(),
|
||||
getIt.get<WalletNewVM>(param1: WalletType.monero)));
|
||||
|
@ -342,10 +365,10 @@ Future setup(
|
|||
|
||||
getIt.registerFactoryParam<ContactViewModel, ContactRecord, void>(
|
||||
(ContactRecord contact, _) =>
|
||||
ContactViewModel(contactSource, contact: contact));
|
||||
ContactViewModel(_contactSource, contact: contact));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => ContactListViewModel(contactSource, walletInfoSource));
|
||||
() => ContactListViewModel(_contactSource, _walletInfoSource));
|
||||
|
||||
getIt.registerFactoryParam<ContactListPage, bool, void>(
|
||||
(bool isEditable, _) => ContactListPage(getIt.get<ContactListViewModel>(),
|
||||
|
@ -358,27 +381,27 @@ Future setup(
|
|||
getIt.registerFactory(() {
|
||||
final appStore = getIt.get<AppStore>();
|
||||
return NodeListViewModel(
|
||||
nodeSource, appStore.wallet, appStore.settingsStore);
|
||||
_nodeSource, appStore.wallet, appStore.settingsStore);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => NodeListPage(getIt.get<NodeListViewModel>()));
|
||||
|
||||
getIt.registerFactory(() =>
|
||||
NodeCreateOrEditViewModel(nodeSource, getIt.get<AppStore>().wallet));
|
||||
NodeCreateOrEditViewModel(_nodeSource, getIt.get<AppStore>().wallet));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => NodeCreateOrEditPage(getIt.get<NodeCreateOrEditViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => ExchangeViewModel(
|
||||
getIt.get<AppStore>().wallet,
|
||||
tradesSource,
|
||||
_tradesSource,
|
||||
getIt.get<ExchangeTemplateStore>(),
|
||||
getIt.get<TradesStore>(),
|
||||
getIt.get<AppStore>().settingsStore));
|
||||
|
||||
getIt.registerFactory(() => ExchangeTradeViewModel(
|
||||
wallet: getIt.get<AppStore>().wallet,
|
||||
trades: tradesSource,
|
||||
trades: _tradesSource,
|
||||
tradesStore: getIt.get<TradesStore>(),
|
||||
sendViewModel: getIt.get<SendViewModel>()));
|
||||
|
||||
|
@ -393,9 +416,9 @@ Future setup(
|
|||
getIt.registerFactory(
|
||||
() => ExchangeTemplatePage(getIt.get<ExchangeViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => MoneroWalletService(walletInfoSource));
|
||||
getIt.registerFactory(() => MoneroWalletService(_walletInfoSource));
|
||||
|
||||
getIt.registerFactory(() => BitcoinWalletService(walletInfoSource));
|
||||
getIt.registerFactory(() => BitcoinWalletService(_walletInfoSource));
|
||||
|
||||
getIt.registerFactoryParam<WalletService, WalletType, void>(
|
||||
(WalletType param1, __) {
|
||||
|
@ -428,7 +451,7 @@ Future setup(
|
|||
|
||||
getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>(
|
||||
(type, _) => WalletRestoreViewModel(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), walletInfoSource,
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
type: type));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>((type, _) =>
|
||||
|
@ -438,7 +461,7 @@ Future setup(
|
|||
.registerFactoryParam<TransactionDetailsViewModel, TransactionInfo, void>(
|
||||
(TransactionInfo transactionInfo, _) => TransactionDetailsViewModel(
|
||||
transactionInfo: transactionInfo,
|
||||
transactionDescriptionBox: transactionDescriptionBox,
|
||||
transactionDescriptionBox: _transactionDescriptionBox,
|
||||
settingsStore: getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactoryParam<TransactionDetailsPage, TransactionInfo, void>(
|
||||
|
@ -455,12 +478,11 @@ Future setup(
|
|||
(WalletType type, _) => PreSeedPage(type));
|
||||
|
||||
getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>((trade, _) =>
|
||||
TradeDetailsViewModel(tradeForDetails: trade, trades: tradesSource));
|
||||
TradeDetailsViewModel(tradeForDetails: trade, trades: _tradesSource));
|
||||
|
||||
getIt.registerFactory(() => BackupService(
|
||||
getIt.get<FlutterSecureStorage>(),
|
||||
getIt.get<AuthService>(),
|
||||
walletInfoSource,
|
||||
_walletInfoSource,
|
||||
getIt.get<KeyService>(),
|
||||
getIt.get<SharedPreferences>()));
|
||||
|
||||
|
@ -476,8 +498,7 @@ Future setup(
|
|||
getIt.registerFactory(
|
||||
() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<RestoreOptionsPage, WalletType, void>(
|
||||
(WalletType type, _) => RestoreOptionsPage(type: type));
|
||||
getIt.registerFactory(() => RestoreOptionsPage());
|
||||
|
||||
getIt.registerFactory(
|
||||
() => RestoreFromBackupViewModel(getIt.get<BackupService>()));
|
||||
|
@ -487,4 +508,6 @@ Future setup(
|
|||
|
||||
getIt.registerFactoryParam<TradeDetailsPage, Trade, void>((Trade trade, _) =>
|
||||
TradeDetailsPage(getIt.get<TradeDetailsViewModel>(param1: trade)));
|
||||
|
||||
_isSetupFinished = true;
|
||||
}
|
||||
|
|
|
@ -5,11 +5,12 @@ import 'package:cake_wallet/utils/mobx.dart';
|
|||
|
||||
part 'contact.g.dart';
|
||||
|
||||
@HiveType(typeId: 0)
|
||||
@HiveType(typeId: Contact.typeId)
|
||||
class Contact extends HiveObject with Keyable {
|
||||
Contact({@required this.name, @required this.address, CryptoCurrency type})
|
||||
: raw = type?.raw;
|
||||
|
||||
static const typeId = 0;
|
||||
static const boxName = 'Contacts';
|
||||
|
||||
@HiveField(0)
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import 'dart:io' show File, Platform;
|
||||
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
||||
import 'package:cake_wallet/core/key_service.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/entities/pathForWallet.dart';
|
||||
import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||
import 'package:cake_wallet/monero/monero_wallet_service.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
|
@ -17,10 +20,12 @@ import 'package:cake_wallet/entities/contact.dart';
|
|||
import 'package:cake_wallet/entities/fs_migration.dart';
|
||||
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:encrypt/encrypt.dart' as encrypt;
|
||||
|
||||
Future defaultSettingsMigration(
|
||||
{@required int version,
|
||||
@required SharedPreferences sharedPreferences,
|
||||
@required FlutterSecureStorage secureStorage,
|
||||
@required Box<Node> nodes,
|
||||
@required Box<WalletInfo> walletInfoSource,
|
||||
@required Box<Trade> tradeSource,
|
||||
|
@ -29,9 +34,9 @@ Future defaultSettingsMigration(
|
|||
await ios_migrate_v1(walletInfoSource, tradeSource, contactSource);
|
||||
}
|
||||
|
||||
final currentVersion =
|
||||
sharedPreferences.getInt('current_default_settings_migration_version') ??
|
||||
0;
|
||||
final currentVersion = sharedPreferences
|
||||
.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) ??
|
||||
0;
|
||||
if (currentVersion >= version) {
|
||||
return;
|
||||
}
|
||||
|
@ -85,6 +90,10 @@ Future defaultSettingsMigration(
|
|||
await updateDisplayModes(sharedPreferences);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
await generateBackupPassword(secureStorage);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -230,5 +239,17 @@ Future<void> updateDisplayModes(SharedPreferences sharedPreferences) async {
|
|||
final currentBalanceDisplayMode =
|
||||
sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey);
|
||||
final balanceDisplayMode = currentBalanceDisplayMode < 2 ? 3 : 2;
|
||||
await sharedPreferences.setInt(PreferencesKey.currentBalanceDisplayModeKey, balanceDisplayMode);
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentBalanceDisplayModeKey, balanceDisplayMode);
|
||||
}
|
||||
|
||||
Future<void> generateBackupPassword(FlutterSecureStorage secureStorage) async {
|
||||
final key = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
|
||||
|
||||
if ((await secureStorage.read(key: key))?.isNotEmpty ?? false) {
|
||||
return;
|
||||
}
|
||||
|
||||
final password = encrypt.Key.fromSecureRandom(32).base16;
|
||||
await secureStorage.write(key: key, value: password);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import 'package:cake_wallet/entities/digest_request.dart';
|
|||
|
||||
part 'node.g.dart';
|
||||
|
||||
@HiveType(typeId: 1)
|
||||
@HiveType(typeId: Node.typeId)
|
||||
class Node extends HiveObject with Keyable {
|
||||
Node(
|
||||
{@required this.uri,
|
||||
|
@ -26,6 +26,7 @@ class Node extends HiveObject with Keyable {
|
|||
typeRaw = map['typeRaw'] as int,
|
||||
useSSL = map['useSSL'] as bool;
|
||||
|
||||
static const typeId = 1;
|
||||
static const boxName = 'Nodes';
|
||||
|
||||
@HiveField(0)
|
||||
|
|
|
@ -14,4 +14,5 @@ class PreferencesKey {
|
|||
static const displayActionListModeKey = 'display_list_mode';
|
||||
static const currentPinLength = 'current_pin_length';
|
||||
static const currentLanguageCode = 'language_code';
|
||||
static const currentDefaultSettingsMigrationVersion = 'current_default_settings_migration_version';
|
||||
}
|
|
@ -2,10 +2,11 @@ import 'package:hive/hive.dart';
|
|||
|
||||
part 'template.g.dart';
|
||||
|
||||
@HiveType(typeId: 6)
|
||||
@HiveType(typeId: Template.typeId)
|
||||
class Template extends HiveObject {
|
||||
Template({this.name, this.address, this.cryptoCurrency, this.amount});
|
||||
|
||||
static const typeId = 6;
|
||||
static const boxName = 'Template';
|
||||
|
||||
@HiveField(0)
|
||||
|
|
|
@ -2,10 +2,11 @@ import 'package:hive/hive.dart';
|
|||
|
||||
part 'transaction_description.g.dart';
|
||||
|
||||
@HiveType(typeId: 2)
|
||||
@HiveType(typeId: TransactionDescription.typeId)
|
||||
class TransactionDescription extends HiveObject {
|
||||
TransactionDescription({this.id, this.recipientAddress, this.transactionNote});
|
||||
|
||||
static const typeId = 2;
|
||||
static const boxName = 'TransactionDescriptions';
|
||||
static const boxKey = 'transactionDescriptionsBoxKey';
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:cake_wallet/entities/wallet_type.dart';
|
|||
|
||||
part 'wallet_info.g.dart';
|
||||
|
||||
@HiveType(typeId: 4)
|
||||
@HiveType(typeId: WalletInfo.typeId)
|
||||
class WalletInfo extends HiveObject {
|
||||
WalletInfo(this.id, this.name, this.type, this.isRecovery, this.restoreHeight,
|
||||
this.timestamp, this.dirPath, this.path, this.address);
|
||||
|
@ -23,6 +23,7 @@ class WalletInfo extends HiveObject {
|
|||
date.millisecondsSinceEpoch ?? 0, dirPath, path, address);
|
||||
}
|
||||
|
||||
static const typeId = 4;
|
||||
static const boxName = 'WalletInfo';
|
||||
|
||||
@HiveField(0)
|
||||
|
|
|
@ -4,8 +4,9 @@ import 'package:hive/hive.dart';
|
|||
part 'wallet_type.g.dart';
|
||||
|
||||
const walletTypes = [WalletType.monero, WalletType.bitcoin];
|
||||
const walletTypeTypeId = 5;
|
||||
|
||||
@HiveType(typeId: 5)
|
||||
@HiveType(typeId: walletTypeTypeId)
|
||||
enum WalletType {
|
||||
@HiveField(0)
|
||||
monero,
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'package:hive/hive.dart';
|
|||
|
||||
part 'exchange_template.g.dart';
|
||||
|
||||
@HiveType(typeId: 7)
|
||||
@HiveType(typeId: ExchangeTemplate.typeId)
|
||||
class ExchangeTemplate extends HiveObject {
|
||||
ExchangeTemplate({
|
||||
this.amount,
|
||||
|
@ -13,6 +13,7 @@ class ExchangeTemplate extends HiveObject {
|
|||
this.receiveAddress
|
||||
});
|
||||
|
||||
static const typeId = 7;
|
||||
static const boxName = 'ExchangeTemplate';
|
||||
|
||||
@HiveField(0)
|
||||
|
|
|
@ -6,7 +6,7 @@ import 'package:cake_wallet/entities/format_amount.dart';
|
|||
|
||||
part 'trade.g.dart';
|
||||
|
||||
@HiveType(typeId: 3)
|
||||
@HiveType(typeId: Trade.typeId)
|
||||
class Trade extends HiveObject {
|
||||
Trade(
|
||||
{this.id,
|
||||
|
@ -27,6 +27,7 @@ class Trade extends HiveObject {
|
|||
toRaw = to?.raw,
|
||||
stateRaw = state?.raw;
|
||||
|
||||
static const typeId = 3;
|
||||
static const boxName = 'Trades';
|
||||
static const boxKey = 'tradesBoxKey';
|
||||
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
import 'package:cake_wallet/core/backup.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/backup_page.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
@ -12,6 +8,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
|||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cw_monero/wallet.dart' as monero_wallet;
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/router.dart' as Router;
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -32,20 +29,46 @@ import 'package:cake_wallet/src/screens/root/root.dart';
|
|||
|
||||
final navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
void main() async {
|
||||
Future<void> main() async {
|
||||
try {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
await Hive.close();
|
||||
Hive.init(appDir.path);
|
||||
Hive.registerAdapter(ContactAdapter());
|
||||
Hive.registerAdapter(NodeAdapter());
|
||||
Hive.registerAdapter(TransactionDescriptionAdapter());
|
||||
Hive.registerAdapter(TradeAdapter());
|
||||
Hive.registerAdapter(WalletInfoAdapter());
|
||||
Hive.registerAdapter(WalletTypeAdapter());
|
||||
Hive.registerAdapter(TemplateAdapter());
|
||||
Hive.registerAdapter(ExchangeTemplateAdapter());
|
||||
|
||||
if (!Hive.isAdapterRegistered(Contact.typeId)) {
|
||||
Hive.registerAdapter(ContactAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(Node.typeId)) {
|
||||
Hive.registerAdapter(NodeAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(TransactionDescription.typeId)) {
|
||||
Hive.registerAdapter(TransactionDescriptionAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(Trade.typeId)) {
|
||||
Hive.registerAdapter(TradeAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(WalletInfo.typeId)) {
|
||||
Hive.registerAdapter(WalletInfoAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(walletTypeTypeId)) {
|
||||
Hive.registerAdapter(WalletTypeAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(Template.typeId)) {
|
||||
Hive.registerAdapter(TemplateAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(ExchangeTemplate.typeId)) {
|
||||
Hive.registerAdapter(ExchangeTemplateAdapter());
|
||||
}
|
||||
|
||||
final secureStorage = FlutterSecureStorage();
|
||||
final transactionDescriptionsBoxKey = await getEncryptionKey(
|
||||
secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
|
||||
|
@ -57,11 +80,11 @@ void main() async {
|
|||
TransactionDescription.boxName,
|
||||
encryptionKey: transactionDescriptionsBoxKey);
|
||||
final trades =
|
||||
await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
|
||||
await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
|
||||
final walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||
final templates = await Hive.openBox<Template>(Template.boxName);
|
||||
final exchangeTemplates =
|
||||
await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
|
||||
await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
|
||||
await initialSetup(
|
||||
sharedPreferences: await SharedPreferences.getInstance(),
|
||||
nodes: nodes,
|
||||
|
@ -72,7 +95,8 @@ void main() async {
|
|||
templates: templates,
|
||||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptions: transactionDescriptions,
|
||||
initialMigrationVersion: 5);
|
||||
secureStorage: secureStorage,
|
||||
initialMigrationVersion: 9);
|
||||
runApp(App());
|
||||
} catch (e) {
|
||||
runApp(MaterialApp(
|
||||
|
@ -80,7 +104,7 @@ void main() async {
|
|||
home: Scaffold(
|
||||
body: Container(
|
||||
margin:
|
||||
EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20),
|
||||
EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20),
|
||||
child: Text(
|
||||
'Error:\n${e.toString()}',
|
||||
style: TextStyle(fontSize: 22),
|
||||
|
@ -88,17 +112,20 @@ void main() async {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> initialSetup({@required SharedPreferences sharedPreferences,
|
||||
@required Box<Node> nodes,
|
||||
@required Box<WalletInfo> walletInfoSource,
|
||||
@required Box<Contact> contactSource,
|
||||
@required Box<Trade> tradesSource,
|
||||
// @required FiatConvertationService fiatConvertationService,
|
||||
@required Box<Template> templates,
|
||||
@required Box<ExchangeTemplate> exchangeTemplates,
|
||||
@required Box<TransactionDescription> transactionDescriptions,
|
||||
int initialMigrationVersion = 6}) async {
|
||||
Future<void> initialSetup(
|
||||
{@required SharedPreferences sharedPreferences,
|
||||
@required Box<Node> nodes,
|
||||
@required Box<WalletInfo> walletInfoSource,
|
||||
@required Box<Contact> contactSource,
|
||||
@required Box<Trade> tradesSource,
|
||||
// @required FiatConvertationService fiatConvertationService,
|
||||
@required Box<Template> templates,
|
||||
@required Box<ExchangeTemplate> exchangeTemplates,
|
||||
@required Box<TransactionDescription> transactionDescriptions,
|
||||
FlutterSecureStorage secureStorage,
|
||||
int initialMigrationVersion = 9}) async {
|
||||
await defaultSettingsMigration(
|
||||
secureStorage: secureStorage,
|
||||
version: initialMigrationVersion,
|
||||
sharedPreferences: sharedPreferences,
|
||||
walletInfoSource: walletInfoSource,
|
||||
|
@ -113,7 +140,7 @@ Future<void> initialSetup({@required SharedPreferences sharedPreferences,
|
|||
templates: templates,
|
||||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptionBox: transactionDescriptions);
|
||||
bootstrap(navigatorKey);
|
||||
await bootstrap(navigatorKey);
|
||||
monero_wallet.onStartup();
|
||||
}
|
||||
|
||||
|
@ -125,16 +152,14 @@ class App extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final settingsStore = getIt
|
||||
.get<AppStore>()
|
||||
.settingsStore;
|
||||
final statusBarColor = Colors.transparent;
|
||||
final authenticationStore = getIt.get<AuthenticationStore>();
|
||||
final initialRoute = authenticationStore.state == AuthenticationState.denied
|
||||
? Routes.disclaimer
|
||||
: Routes.login;
|
||||
|
||||
return Observer(builder: (BuildContext context) {
|
||||
final settingsStore = getIt.get<AppStore>().settingsStore;
|
||||
final statusBarColor = Colors.transparent;
|
||||
final authenticationStore = getIt.get<AuthenticationStore>();
|
||||
final initialRoute =
|
||||
authenticationStore.state == AuthenticationState.denied
|
||||
? Routes.disclaimer
|
||||
: Routes.login;
|
||||
final currentTheme = settingsStore.currentTheme;
|
||||
final statusBarBrightness = currentTheme.type == ThemeType.dark
|
||||
? Brightness.light
|
||||
|
|
|
@ -19,14 +19,12 @@ Future<void> bootstrap(GlobalKey<NavigatorState> navigatorKey) async {
|
|||
final settingsStore = getIt.get<SettingsStore>();
|
||||
final fiatConversionStore = getIt.get<FiatConversionStore>();
|
||||
|
||||
if (authenticationStore.state == AuthenticationState.uninitialized) {
|
||||
final currentWalletName = getIt
|
||||
.get<SharedPreferences>()
|
||||
.getString(PreferencesKey.currentWalletName);
|
||||
authenticationStore.state = currentWalletName == null
|
||||
? AuthenticationState.denied
|
||||
: AuthenticationState.installed;
|
||||
}
|
||||
final currentWalletName = getIt
|
||||
.get<SharedPreferences>()
|
||||
.getString(PreferencesKey.currentWalletName);
|
||||
authenticationStore.state = currentWalletName == null
|
||||
? AuthenticationState.denied
|
||||
: AuthenticationState.installed;
|
||||
|
||||
startAuthenticationStateChange(authenticationStore, navigatorKey);
|
||||
startCurrentWalletChangeReaction(
|
||||
|
|
|
@ -106,9 +106,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
param2: false));
|
||||
|
||||
case Routes.restoreOptions:
|
||||
final type = settings.arguments as WalletType;
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<RestoreOptionsPage>(param1: type));
|
||||
builder: (_) => getIt.get<RestoreOptionsPage>());
|
||||
|
||||
case Routes.restoreWalletOptions:
|
||||
final type = WalletType.monero; //settings.arguments as WalletType;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
|
@ -34,7 +36,7 @@ class BackupPage extends BasePage {
|
|||
Center(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 20, right: 20),
|
||||
height: 225,
|
||||
height: 300,
|
||||
child: Column(children: [
|
||||
Text(
|
||||
'Backup password:',
|
||||
|
@ -43,9 +45,21 @@ class BackupPage extends BasePage {
|
|||
Padding(
|
||||
padding: EdgeInsets.only(top: 20, bottom: 10),
|
||||
child: Observer(
|
||||
builder: (_) => Text(
|
||||
backupViewModelBase.backupPassword,
|
||||
style: TextStyle(fontSize: 26),
|
||||
builder: (_) => GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(
|
||||
text:
|
||||
backupViewModelBase.backupPassword));
|
||||
showBar<void>(
|
||||
context,
|
||||
S.of(context).transaction_details_copied(
|
||||
'Backup password'));
|
||||
},
|
||||
child: Text(
|
||||
backupViewModelBase.backupPassword,
|
||||
style: TextStyle(fontSize: 26),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
))),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(20),
|
||||
|
|
|
@ -84,5 +84,6 @@ class RestoreFromBackupPage extends BasePage {
|
|||
}
|
||||
|
||||
await restoreFromBackupViewModel.import(textEditingController.text);
|
||||
textEditingController.text = '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:cake_wallet/entities/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -7,10 +6,9 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class RestoreOptionsPage extends BasePage {
|
||||
RestoreOptionsPage({@required this.type});
|
||||
|
||||
RestoreOptionsPage();
|
||||
|
||||
static const _aspectRatioImage = 2.086;
|
||||
final WalletType type;
|
||||
|
||||
@override
|
||||
String get title => S.current.restore_restore_wallet;
|
||||
|
@ -21,33 +19,30 @@ class RestoreOptionsPage extends BasePage {
|
|||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
padding: EdgeInsets.all(24),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
RestoreButton(
|
||||
onPressed: () =>
|
||||
Navigator.pushNamed(
|
||||
context, Routes.restoreWalletOptionsFromWelcome),
|
||||
image: imageSeedKeys,
|
||||
title: S.of(context).restore_title_from_seed_keys,
|
||||
description: S.of(context).restore_description_from_seed_keys
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: RestoreButton(
|
||||
onPressed: () => Navigator.pushNamed(
|
||||
context, Routes.restoreFromBackup),
|
||||
image: imageBackup,
|
||||
title: S.of(context).restore_title_from_backup,
|
||||
description: S.of(context).restore_description_from_backup
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
);
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
padding: EdgeInsets.all(24),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
RestoreButton(
|
||||
onPressed: () =>
|
||||
Navigator.pushNamed(context, Routes.restoreWalletOptionsFromWelcome),
|
||||
image: imageSeedKeys,
|
||||
title: S.of(context).restore_title_from_seed_keys,
|
||||
description:
|
||||
S.of(context).restore_description_from_seed_keys),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: RestoreButton(
|
||||
onPressed: () =>
|
||||
Navigator.pushNamed(context, Routes.restoreFromBackup),
|
||||
image: imageBackup,
|
||||
title: S.of(context).restore_title_from_backup,
|
||||
description: S.of(context).restore_description_from_backup),
|
||||
)
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ class WelcomePage extends BasePage {
|
|||
child: PrimaryImageButton(
|
||||
onPressed: () =>
|
||||
Navigator.pushNamed(context,
|
||||
Routes.restoreWalletOptionsFromWelcome),
|
||||
Routes.restoreOptions),
|
||||
image: restoreWalletImage,
|
||||
text: S
|
||||
.of(context)
|
||||
|
|
|
@ -18,7 +18,7 @@ class TrailButton extends StatelessWidget {
|
|||
caption,
|
||||
style: TextStyle(
|
||||
color:
|
||||
Theme.of(context).accentTextTheme.display4.decorationColor,
|
||||
Theme.of(context).accentTextTheme.bodyText2.color,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14),
|
||||
),
|
||||
|
|
|
@ -85,10 +85,10 @@ abstract class SettingsStoreBase with Store {
|
|||
(String languageCode) => sharedPreferences.setString(
|
||||
PreferencesKey.currentLanguageCode, languageCode));
|
||||
|
||||
reaction((_) => balanceDisplayMode,
|
||||
(BalanceDisplayMode mode) => sharedPreferences.setInt(
|
||||
PreferencesKey.currentBalanceDisplayModeKey,
|
||||
mode.serialize()));
|
||||
reaction(
|
||||
(_) => balanceDisplayMode,
|
||||
(BalanceDisplayMode mode) => sharedPreferences.setInt(
|
||||
PreferencesKey.currentBalanceDisplayModeKey, mode.serialize()));
|
||||
|
||||
this
|
||||
.nodes
|
||||
|
@ -158,7 +158,7 @@ abstract class SettingsStoreBase with Store {
|
|||
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
|
||||
false;
|
||||
final legacyTheme =
|
||||
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
|
||||
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
|
||||
? ThemeType.dark.index
|
||||
: ThemeType.bright.index;
|
||||
final savedTheme = ThemeList.deserialize(
|
||||
|
@ -203,6 +203,29 @@ abstract class SettingsStoreBase with Store {
|
|||
initialLanguageCode: savedLanguageCode);
|
||||
}
|
||||
|
||||
Future<void> reload(
|
||||
{@required Box<Node> nodeSource,
|
||||
FiatCurrency initialFiatCurrency = FiatCurrency.usd,
|
||||
TransactionPriority initialTransactionPriority = TransactionPriority.slow,
|
||||
BalanceDisplayMode initialBalanceDisplayMode =
|
||||
BalanceDisplayMode.availableBalance}) async {
|
||||
final settings = await SettingsStoreBase.load(
|
||||
nodeSource: nodeSource,
|
||||
initialBalanceDisplayMode: initialBalanceDisplayMode,
|
||||
initialFiatCurrency: initialFiatCurrency,
|
||||
initialTransactionPriority: initialTransactionPriority);
|
||||
fiatCurrency = settings.fiatCurrency;
|
||||
actionlistDisplayMode = settings.actionlistDisplayMode;
|
||||
transactionPriority = settings.transactionPriority;
|
||||
balanceDisplayMode = settings.balanceDisplayMode;
|
||||
shouldSaveRecipientAddress = settings.shouldSaveRecipientAddress;
|
||||
allowBiometricalAuthentication = settings.allowBiometricalAuthentication;
|
||||
currentTheme = settings.currentTheme;
|
||||
pinCodeLength = settings.pinCodeLength;
|
||||
languageCode = settings.languageCode;
|
||||
appVersion = settings.appVersion;
|
||||
}
|
||||
|
||||
Future<void> _saveCurrentNode(Node node, WalletType walletType) async {
|
||||
switch (walletType) {
|
||||
case WalletType.bitcoin:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:cake_wallet/core/backup.dart';
|
||||
import 'package:cake_wallet/core/backup_service.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||
import 'package:cake_wallet/store/secret_store.dart';
|
||||
|
@ -52,7 +52,7 @@ abstract class BackupViewModelBase with Store {
|
|||
Future<BackupExportFile> exportBackup() async {
|
||||
try {
|
||||
state = IsExecutingState();
|
||||
final backupContent = await backupService.exportBackup('', nonce: '');
|
||||
final backupContent = await backupService.exportBackup(backupPassword);
|
||||
state = ExecutedSuccessfullyState();
|
||||
|
||||
return BackupExportFile(backupContent.toList(),
|
||||
|
@ -60,6 +60,7 @@ abstract class BackupViewModelBase with Store {
|
|||
} catch (e) {
|
||||
print(e.toString());
|
||||
state = FailureState(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/core/backup.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/main.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/core/backup_service.dart';
|
||||
import 'package:cake_wallet/entities/node.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/authentication_store.dart';
|
||||
|
||||
part 'restore_from_backup_view_model.g.dart';
|
||||
|
||||
class RestoreFromBackupViewModel = RestoreFromBackupViewModelBase with _$RestoreFromBackupViewModel;
|
||||
class RestoreFromBackupViewModel = RestoreFromBackupViewModelBase
|
||||
with _$RestoreFromBackupViewModel;
|
||||
|
||||
abstract class RestoreFromBackupViewModelBase with Store {
|
||||
RestoreFromBackupViewModelBase(this.backupService);
|
||||
|
@ -15,15 +21,36 @@ abstract class RestoreFromBackupViewModelBase with Store {
|
|||
|
||||
final BackupService backupService;
|
||||
|
||||
@action
|
||||
void reset() => filePath = '';
|
||||
|
||||
Future<void> import(String password) async {
|
||||
if (filePath?.isEmpty ?? true) {
|
||||
// FIXME: throw exception;
|
||||
return;
|
||||
try {
|
||||
if (filePath?.isEmpty ?? true) {
|
||||
// FIXME: throw exception;
|
||||
return;
|
||||
}
|
||||
|
||||
final file = File(filePath);
|
||||
final data = await file.readAsBytes();
|
||||
|
||||
await backupService.importBackup(data, password);
|
||||
await main();
|
||||
|
||||
final store = getIt.get<AppStore>();
|
||||
ReactionDisposer reaction;
|
||||
await store.settingsStore.reload(nodeSource: getIt.get<Box<Node>>());
|
||||
|
||||
reaction = autorun((_) {
|
||||
final wallet = store.wallet;
|
||||
|
||||
if (wallet != null) {
|
||||
store.authenticationStore.state = AuthenticationState.allowed;
|
||||
reaction?.reaction?.dispose();
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
|
||||
final file = File(filePath);
|
||||
final data = await file.readAsBytes();
|
||||
|
||||
await backupService.importBackup(data, password, nonce: null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,19 @@ abstract class SettingsViewModelBase with Store {
|
|||
onItemSelected: (ThemeBase theme) =>
|
||||
_settingsStore.currentTheme = theme)
|
||||
],
|
||||
[
|
||||
RegularListItem(
|
||||
title: 'Backup',
|
||||
handler: (BuildContext context) {
|
||||
Navigator.of(context).pushNamed(Routes.auth, arguments:
|
||||
(bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
auth.close();
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
Navigator.of(context).pushNamed(Routes.backup);
|
||||
}
|
||||
});
|
||||
}),
|
||||
],
|
||||
[
|
||||
LinkListItem(
|
||||
title: 'Email',
|
||||
|
|
Loading…
Reference in a new issue