CW-1092-restoring-from-backup-doesnt-maintain-hardware-wallets (#2319)

* feat: add hardware wallet verification during backup restoration

* style: improve readability of verifyHardwareWallets in backup_service_v3.dart
This commit is contained in:
Konstantin Ullrich 2025-06-17 00:31:49 +02:00 committed by GitHub
parent 4fb2fc47ad
commit 85d3e727e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 42 additions and 5 deletions

View file

@ -10,6 +10,7 @@ import 'package:cake_wallet/utils/package_info.dart';
import 'package:crypto/crypto.dart';
import 'package:cw_core/root_dir.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:flutter/foundation.dart';
enum BackupVersion {
@ -305,6 +306,7 @@ class BackupServiceV3 extends $BackupService {
// Continue importing the backup the old way
await super.verifyWallets();
await verifyHardwareWallets(password);
await super.importKeychainDumpV2(password);
await super.importPreferencesDump();
await super.importTransactionDescriptionDump();
@ -313,6 +315,39 @@ class BackupServiceV3 extends $BackupService {
decryptedData.deleteSync();
}
Future<void> verifyHardwareWallets(String password,
{String keychainSalt = secrets.backupKeychainSalt}) async {
final walletInfoSource = await reloadHiveWalletInfoBox();
final appDir = await getAppDir();
final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
final decryptedKeychainDumpFileData = await decryptV2(
keychainDumpFile.readAsBytesSync(), '$keychainSalt$password');
final keychainJSON = json.decode(utf8.decode(decryptedKeychainDumpFileData))
as Map<String, dynamic>;
final keychainWalletsInfo = keychainJSON['wallets'] as List;
final expectedHardwareWallets = keychainWalletsInfo
.where((e) =>
(e as Map<String, dynamic>).containsKey("hardwareWalletType") &&
e["hardwareWalletType"] != null)
.toList();
for (final expectedHardwareWallet in expectedHardwareWallets) {
final info = expectedHardwareWallet as Map<String, dynamic>;
final actualWalletInfo = walletInfoSource.values
.where((e) =>
e.name == info['name'] && e.type.toString() == info['type'])
.firstOrNull;
if (actualWalletInfo != null &&
info["hardwareWalletType"] !=
actualWalletInfo.hardwareWalletType?.index) {
actualWalletInfo.hardwareWalletType =
HardwareWalletType.values[info["hardwareWalletType"] as int];
await actualWalletInfo.save();
}
}
}
Future<File> exportBackupFileV3(String password, {String nonce = secrets.backupSalt}) async {
final metadata = BackupMetadata(
version: BackupVersion.v3,
@ -467,4 +502,4 @@ This backup was created on ${DateTime.now().toIso8601String()}
file.writeAsBytesSync(data);
return file;
}
}
}