mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-03-21 06:38:49 +00:00
cleaner backup changes
This commit is contained in:
parent
41bf68c886
commit
e699cb0335
1 changed files with 14 additions and 80 deletions
|
@ -28,11 +28,10 @@ class BackupService {
|
||||||
: _cipher = Cryptography.instance.chacha20Poly1305Aead(),
|
: _cipher = Cryptography.instance.chacha20Poly1305Aead(),
|
||||||
_correctWallets = <WalletInfo>[];
|
_correctWallets = <WalletInfo>[];
|
||||||
|
|
||||||
static const currentVersion = _v3;
|
static const currentVersion = _v2;
|
||||||
|
|
||||||
static const _v1 = 1;
|
static const _v1 = 1;
|
||||||
static const _v2 = 2;
|
static const _v2 = 2;
|
||||||
static const _v3 = 3;
|
|
||||||
|
|
||||||
final Cipher _cipher;
|
final Cipher _cipher;
|
||||||
final FlutterSecureStorage _flutterSecureStorage;
|
final FlutterSecureStorage _flutterSecureStorage;
|
||||||
|
@ -54,9 +53,6 @@ class BackupService {
|
||||||
case _v2:
|
case _v2:
|
||||||
await _importBackupV2(data, password);
|
await _importBackupV2(data, password);
|
||||||
break;
|
break;
|
||||||
case _v3:
|
|
||||||
await _importBackupV3(data, password);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -69,8 +65,6 @@ class BackupService {
|
||||||
return await _exportBackupV1(password, nonce: nonce);
|
return await _exportBackupV1(password, nonce: nonce);
|
||||||
case _v2:
|
case _v2:
|
||||||
return await _exportBackupV2(password);
|
return await _exportBackupV2(password);
|
||||||
case _v3:
|
|
||||||
return await _exportBackupV3(password);
|
|
||||||
default:
|
default:
|
||||||
throw Exception('Incorrect version: $version for exportBackup');
|
throw Exception('Incorrect version: $version for exportBackup');
|
||||||
}
|
}
|
||||||
|
@ -80,16 +74,14 @@ class BackupService {
|
||||||
Future<Uint8List> _exportBackupV1(String password, {String nonce = secrets.backupSalt}) async =>
|
Future<Uint8List> _exportBackupV1(String password, {String nonce = secrets.backupSalt}) async =>
|
||||||
throw Exception('Deprecated. Export for backups v1 is deprecated. Please use export v2.');
|
throw Exception('Deprecated. Export for backups v1 is deprecated. Please use export v2.');
|
||||||
|
|
||||||
Future<Uint8List> _exportBackupV2(String password, {bool keychainV3 = false}) async {
|
Future<Uint8List> _exportBackupV2(String password) async {
|
||||||
final zipEncoder = ZipFileEncoder();
|
final zipEncoder = ZipFileEncoder();
|
||||||
final appDir = await getApplicationDocumentsDirectory();
|
final appDir = await getApplicationDocumentsDirectory();
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
final tmpDir = Directory('${appDir.path}/~_BACKUP_TMP');
|
final tmpDir = Directory('${appDir.path}/~_BACKUP_TMP');
|
||||||
final archivePath = '${tmpDir.path}/backup_${now.toString()}.zip';
|
final archivePath = '${tmpDir.path}/backup_${now.toString()}.zip';
|
||||||
final fileEntities = appDir.listSync(recursive: false);
|
final fileEntities = appDir.listSync(recursive: false);
|
||||||
final keychainDump = keychainV3
|
final keychainDump = await _exportKeychainDumpV2(password);
|
||||||
? (await _exportKeychainDumpV2(password))
|
|
||||||
: (await _exportKeychainDumpV3(password));
|
|
||||||
final preferencesDump = await _exportPreferencesJSON();
|
final preferencesDump = await _exportPreferencesJSON();
|
||||||
final preferencesDumpFile = File('${tmpDir.path}/~_preferences_dump_TMP');
|
final preferencesDumpFile = File('${tmpDir.path}/~_preferences_dump_TMP');
|
||||||
final keychainDumpFile = File('${tmpDir.path}/~_keychain_dump_TMP');
|
final keychainDumpFile = File('${tmpDir.path}/~_keychain_dump_TMP');
|
||||||
|
@ -123,10 +115,6 @@ class BackupService {
|
||||||
return await _encryptV2(content, password);
|
return await _encryptV2(content, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Uint8List> _exportBackupV3(String password) async {
|
|
||||||
return await _exportBackupV2(password, keychainV3: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _importBackupV1(Uint8List data, String password, {required String nonce}) async {
|
Future<void> _importBackupV1(Uint8List data, String password, {required String nonce}) async {
|
||||||
final appDir = await getApplicationDocumentsDirectory();
|
final appDir = await getApplicationDocumentsDirectory();
|
||||||
final decryptedData = await _decryptV1(data, password, nonce);
|
final decryptedData = await _decryptV1(data, password, nonce);
|
||||||
|
@ -150,7 +138,7 @@ class BackupService {
|
||||||
await _importPreferencesDump();
|
await _importPreferencesDump();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _importBackupV2(Uint8List data, String password, {bool keychainV3 = false}) async {
|
Future<void> _importBackupV2(Uint8List data, String password) async {
|
||||||
final appDir = await getApplicationDocumentsDirectory();
|
final appDir = await getApplicationDocumentsDirectory();
|
||||||
final decryptedData = await _decryptV2(data, password);
|
final decryptedData = await _decryptV2(data, password);
|
||||||
final zip = ZipDecoder().decodeBytes(decryptedData);
|
final zip = ZipDecoder().decodeBytes(decryptedData);
|
||||||
|
@ -169,18 +157,10 @@ class BackupService {
|
||||||
});
|
});
|
||||||
|
|
||||||
await _verifyWallets();
|
await _verifyWallets();
|
||||||
if (keychainV3) {
|
|
||||||
await _importKeychainDumpV3(password);
|
|
||||||
} else {
|
|
||||||
await _importKeychainDumpV2(password);
|
await _importKeychainDumpV2(password);
|
||||||
}
|
|
||||||
await _importPreferencesDump();
|
await _importPreferencesDump();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _importBackupV3(Uint8List data, String password) async {
|
|
||||||
await _importBackupV2(data, password, keychainV3: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _verifyWallets() async {
|
Future<void> _verifyWallets() async {
|
||||||
final walletInfoSource = await _reloadHiveWalletInfoBox();
|
final walletInfoSource = await _reloadHiveWalletInfoBox();
|
||||||
_correctWallets =
|
_correctWallets =
|
||||||
|
@ -465,6 +445,7 @@ class BackupService {
|
||||||
});
|
});
|
||||||
|
|
||||||
await _flutterSecureStorage.delete(key: pinCodeKey);
|
await _flutterSecureStorage.delete(key: pinCodeKey);
|
||||||
|
// we know it's the old pin format since it's a v1 import:
|
||||||
await _flutterSecureStorage.write(
|
await _flutterSecureStorage.write(
|
||||||
key: pinCodeKey, value: (await argon2Hash(password: decodedPin)));
|
key: pinCodeKey, value: (await argon2Hash(password: decodedPin)));
|
||||||
|
|
||||||
|
@ -480,7 +461,7 @@ class BackupService {
|
||||||
final keychainJSON =
|
final keychainJSON =
|
||||||
json.decode(utf8.decode(decryptedKeychainDumpFileData)) as Map<String, dynamic>;
|
json.decode(utf8.decode(decryptedKeychainDumpFileData)) as Map<String, dynamic>;
|
||||||
final keychainWalletsInfo = keychainJSON['wallets'] as List;
|
final keychainWalletsInfo = keychainJSON['wallets'] as List;
|
||||||
final decodedPin = keychainJSON['pin'] as String;
|
final potentiallyDecodedPin = keychainJSON['pin'] as String;
|
||||||
final pinCodeKey = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
final pinCodeKey = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||||
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
|
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
|
||||||
final backupPassword = keychainJSON[backupPasswordKey] as String;
|
final backupPassword = keychainJSON[backupPasswordKey] as String;
|
||||||
|
@ -493,35 +474,14 @@ class BackupService {
|
||||||
await importWalletKeychainInfo(info);
|
await importWalletKeychainInfo(info);
|
||||||
});
|
});
|
||||||
|
|
||||||
await _flutterSecureStorage.delete(key: pinCodeKey);
|
late String encodedPin;
|
||||||
await _flutterSecureStorage.write(
|
// not a formal check but an argon2 hash is always going to be > 10 characters long (and decoded pins either 4 or 6)
|
||||||
key: pinCodeKey, value: (await argon2Hash(password: decodedPin)));
|
if (potentiallyDecodedPin.length < 10) {
|
||||||
|
encodedPin = await argon2Hash(password: potentiallyDecodedPin);
|
||||||
keychainDumpFile.deleteSync();
|
} else {
|
||||||
|
encodedPin = potentiallyDecodedPin;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _importKeychainDumpV3(String password,
|
|
||||||
{String keychainSalt = secrets.backupKeychainSalt}) async {
|
|
||||||
final appDir = await getApplicationDocumentsDirectory();
|
|
||||||
final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
|
|
||||||
final decryptedKeychainDumpFileData =
|
|
||||||
await _decryptV3(keychainDumpFile.readAsBytesSync(), '$keychainSalt$password');
|
|
||||||
final keychainJSON =
|
|
||||||
json.decode(utf8.decode(decryptedKeychainDumpFileData)) as Map<String, dynamic>;
|
|
||||||
final keychainWalletsInfo = keychainJSON['wallets'] as List;
|
|
||||||
final encodedPin = keychainJSON['pin'] as String;
|
|
||||||
final pinCodeKey = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
|
||||||
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
|
|
||||||
final backupPassword = keychainJSON[backupPasswordKey] as String;
|
|
||||||
|
|
||||||
await _flutterSecureStorage.delete(key: backupPasswordKey);
|
|
||||||
await _flutterSecureStorage.write(key: backupPasswordKey, value: backupPassword);
|
|
||||||
|
|
||||||
keychainWalletsInfo.forEach((dynamic rawInfo) async {
|
|
||||||
final info = rawInfo as Map<String, dynamic>;
|
|
||||||
await importWalletKeychainInfo(info);
|
|
||||||
});
|
|
||||||
|
|
||||||
await _flutterSecureStorage.delete(key: pinCodeKey);
|
await _flutterSecureStorage.delete(key: pinCodeKey);
|
||||||
await _flutterSecureStorage.write(key: pinCodeKey, value: encodedPin);
|
await _flutterSecureStorage.write(key: pinCodeKey, value: encodedPin);
|
||||||
|
|
||||||
|
@ -561,26 +521,6 @@ class BackupService {
|
||||||
return encrypted;
|
return encrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Uint8List> _exportKeychainDumpV3(String password,
|
|
||||||
{String keychainSalt = secrets.backupKeychainSalt}) async {
|
|
||||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
|
||||||
final encodedPin = await _flutterSecureStorage.read(key: key);
|
|
||||||
final wallets = await Future.wait(_walletInfoSource.values.map((walletInfo) async {
|
|
||||||
return {
|
|
||||||
'name': walletInfo.name,
|
|
||||||
'type': walletInfo.type.toString(),
|
|
||||||
'password': await _keyService.getWalletPassword(walletName: walletInfo.name)
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
|
|
||||||
final backupPassword = await _flutterSecureStorage.read(key: backupPasswordKey);
|
|
||||||
final data = utf8.encode(
|
|
||||||
json.encode({'pin': encodedPin, 'wallets': wallets, backupPasswordKey: backupPassword}));
|
|
||||||
final encrypted = await _encryptV3(Uint8List.fromList(data), '$keychainSalt$password');
|
|
||||||
|
|
||||||
return encrypted;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> _exportPreferencesJSON() async {
|
Future<String> _exportPreferencesJSON() async {
|
||||||
final preferences = <String, dynamic>{
|
final preferences = <String, dynamic>{
|
||||||
PreferencesKey.currentWalletName:
|
PreferencesKey.currentWalletName:
|
||||||
|
@ -689,10 +629,4 @@ class BackupService {
|
||||||
|
|
||||||
Future<Uint8List> _decryptV2(Uint8List data, String passphrase) async =>
|
Future<Uint8List> _decryptV2(Uint8List data, String passphrase) async =>
|
||||||
cake_backup.decrypt(passphrase, data);
|
cake_backup.decrypt(passphrase, data);
|
||||||
|
|
||||||
Future<Uint8List> _encryptV3(Uint8List data, String passphrase) async =>
|
|
||||||
cake_backup.encrypt(passphrase, data, version: _v3);
|
|
||||||
|
|
||||||
Future<Uint8List> _decryptV3(Uint8List data, String passphrase) async =>
|
|
||||||
cake_backup.decrypt(passphrase, data);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue