mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 20:39:51 +00:00
* implement v3 backup system - Add new BackupServiceV3 with chunked backup support and checksums - Implement json-based metadata in backup system - Instead of binary file export a .zip file that user can open and see that it is a cake backup (should also prevent 3rd party software from corrupting binary data inside of the file, in case it doesn't checksum will fail, and user will know for sure that backup got corrupted) - Update flutter to 3.27.4 to use archive ^4.x.x (it offers in memory archive operations) * fix wallets not getting restored properly * prevent out of memory errors on files that are way too big during restore * Update lib/view_model/backup_view_model.dart [skip ci] * Update lib/core/backup_service.dart [skip ci] * Update lib/core/backup_service.dart --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
112 lines
3.4 KiB
Dart
112 lines
3.4 KiB
Dart
import 'dart:io';
|
|
import 'package:cake_wallet/core/backup_service.dart';
|
|
import 'package:cake_wallet/core/backup_service_v3.dart';
|
|
import 'package:cake_wallet/core/execution_state.dart';
|
|
import 'package:cake_wallet/core/secure_storage.dart';
|
|
import 'package:cake_wallet/entities/secret_store_key.dart';
|
|
import 'package:cake_wallet/store/secret_store.dart';
|
|
import 'package:cw_core/root_dir.dart';
|
|
import 'package:cw_core/utils/print_verbose.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:mobx/mobx.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:cake_wallet/wallet_type_utils.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
|
|
part 'backup_view_model.g.dart';
|
|
|
|
class BackupExportFile {
|
|
BackupExportFile(this.file, {required this.name});
|
|
|
|
final String name;
|
|
final File file;
|
|
}
|
|
|
|
class BackupViewModel = BackupViewModelBase with _$BackupViewModel;
|
|
|
|
abstract class BackupViewModelBase with Store {
|
|
BackupViewModelBase(this.secureStorage, this.secretStore, this.backupService)
|
|
: isBackupPasswordVisible = false,
|
|
backupPassword = '',
|
|
state = InitialExecutionState() {
|
|
final key = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
|
|
secretStore.values.observe((change) {
|
|
if (change.key == key) {
|
|
backupPassword = secretStore.read(key);
|
|
}
|
|
}, fireImmediately: true);
|
|
}
|
|
|
|
final SecureStorage secureStorage;
|
|
final SecretStore secretStore;
|
|
final BackupServiceV3 backupService;
|
|
|
|
@observable
|
|
ExecutionState state;
|
|
|
|
@observable
|
|
bool isBackupPasswordVisible;
|
|
|
|
@observable
|
|
String backupPassword;
|
|
|
|
@action
|
|
Future<void> init() async {
|
|
final key = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
|
|
backupPassword = (await secureStorage.read(key: key))!;
|
|
}
|
|
|
|
@action
|
|
Future<BackupExportFile?> exportBackup() async {
|
|
try {
|
|
state = IsExecutingState();
|
|
final backupFile = await backupService.exportBackupFile(backupPassword);
|
|
state = ExecutedSuccessfullyState();
|
|
final now = DateTime.now();
|
|
final formatter = DateFormat('yyyy-MM-dd_Hm');
|
|
final snakeAppName = approximatedAppName.replaceAll(' ', '_').toLowerCase();
|
|
final fileName = '${snakeAppName}_backup_${formatter.format(now)}.zip';
|
|
|
|
return BackupExportFile(backupFile, name: fileName);
|
|
} catch (e) {
|
|
printV(e.toString());
|
|
state = FailureState(e.toString());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<String> saveBackupFileLocally(BackupExportFile backup) async {
|
|
final appDir = await getAppDir();
|
|
final path = '${appDir.path}/${backup.name}';
|
|
if (File(path).existsSync()) {
|
|
File(path).deleteSync();
|
|
}
|
|
await backup.file.copy(path);
|
|
return path;
|
|
}
|
|
|
|
Future<void> removeBackupFileLocally(BackupExportFile backup) async {
|
|
final appDir = await getAppDir();
|
|
final path = '${appDir.path}/${backup.name}';
|
|
if (File(path).existsSync()) {
|
|
File(path).deleteSync();
|
|
}
|
|
}
|
|
|
|
@action
|
|
void showMasterPassword() => isBackupPasswordVisible = true;
|
|
|
|
@action
|
|
Future<void> saveToDownload(String name, File file) async {
|
|
if (!Platform.isAndroid) {
|
|
return;
|
|
}
|
|
const downloadDirPath = '/storage/emulated/0/Download'; // For Android
|
|
final filePath = '$downloadDirPath/${name}';
|
|
final downloadFile = File(filePath);
|
|
if (downloadFile.existsSync()) {
|
|
downloadFile.deleteSync();
|
|
}
|
|
await file.copy(filePath);
|
|
}
|
|
}
|