fix: allow bakcups to be created even if one of the wallets is corrupted (#2221)

cyan committed Apr 22, 2025 at 21:41 UTC 3e25be6dcf283219ceee852d056356ef2dde098a
2 files changed +22 -6
lib/core/backup_service.dart
+14 -6
@@ -265,16 +265,24 @@ class $BackupService {
265 {String keychainSalt = secrets.backupKeychainSalt}) async {
266 final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
267 final wallets = await Future.wait(walletInfoSource.values.map((walletInfo) async {
268 - return {
269 - 'name': walletInfo.name,
270 - 'type': walletInfo.type.toString(),
271 - 'password': await keyService.getWalletPassword(walletName: walletInfo.name)
272 - };
268 + try {
269 + return {
270 + 'name': walletInfo.name,
271 + 'type': walletInfo.type.toString(),
272 + 'password': await keyService.getWalletPassword(walletName: walletInfo.name)
273 + };
274 + } catch (e) {
275 + return {
276 + 'name': walletInfo.name,
277 + 'type': walletInfo.type.toString(),
278 + 'password': ''
279 + };
280 + }
281 }));
282 final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
283 final backupPassword = await _secureStorage.read(key: backupPasswordKey);
284 final data = utf8.encode(
277 - json.encode({'wallets': wallets, backupPasswordKey: backupPassword}));
285 + json.encode({'wallets': wallets, backupPasswordKey: backupPassword, '_all': await _secureStorage.readAll()}));
286 final encrypted = await _encryptV2(Uint8List.fromList(data), '$keychainSalt$password');
287
288 return encrypted;
tool/configure.dart
+8
@@ -1629,6 +1629,7 @@ abstract class SecureStorage {
1629 Future<void> delete({required String key});
1630 // Legacy
1631 Future<String?> readNoIOptions({required String key});
1632 + Future<Map<String, String>> readAll();
1633 }""";
1634 const defaultSecureStorage = """
1635 class DefaultSecureStorage extends SecureStorage {
@@ -1667,6 +1668,11 @@ class DefaultSecureStorage extends SecureStorage {
1668 iOptions: useNoIOptions ? IOSOptions() : null,
1669 );
1670 }
1671 +
1672 + @override
1673 + Future<Map<String, String>> readAll() async {
1674 + return await _secureStorage.readAll();
1675 + }
1676 }""";
1677 const fakeSecureStorage = """
1678 class FakeSecureStorage extends SecureStorage {
@@ -1678,6 +1684,8 @@ class FakeSecureStorage extends SecureStorage {
1684 Future<void> delete({required String key}) async {}
1685 @override
1686 Future<String?> readNoIOptions({required String key}) async => null;
1687 + @override
1688 + Future<Map<String, String>> readAll() async => {};
1689 }""";
1690 final outputFile = File(secureStoragePath);
1691 final header = hasFlutterSecureStorage