migrateSecretsToKey method
Migrates available secrets from old keys to destinationKey.
Returns the set of secret types that were successfully migrated.
Implementation
Future<Set<String>> migrateSecretsToKey({
required OpenSSSS primaryUnlockedKey,
required OpenSSSS destinationKey,
String? unlockCredential,
Map<String, OpenSSSS>? candidateOldKeys,
bool stripKeys = false,
bool stripAsDefaultKey = true,
}) async {
final remainingSecrets = analyzeEncryptedSecrets();
final keyIds =
orderedCandidateKeyIds(remainingSecrets, primaryUnlockedKey.keyId);
if (keyIds.isEmpty) return {};
final migratedSecretTypes = <String>{};
Set<String> candidateSecretsForKey(String keyId) {
return remainingSecrets.entries
.where((entry) => entry.value.contains(keyId))
.map((entry) => entry.key)
.toSet();
}
for (final keyId in keyIds) {
final key = keyId == primaryUnlockedKey.keyId
? primaryUnlockedKey
: candidateOldKeys?[keyId] ??
await _tryOpenAndUnlockKey(
keyId,
unlockCredential: unlockCredential,
);
if (key == null || !key.isUnlocked) continue;
for (final secretType in candidateSecretsForKey(keyId)) {
try {
final secret = await key.getStored(secretType);
try {
final existing = await destinationKey.getStored(secretType);
if (existing == secret) {
remainingSecrets.remove(secretType);
continue;
}
} catch (e, s) {
Logs().v(
'Could not check existing migrated secret $secretType on destination key ${destinationKey.keyId}, this is usually fine',
e,
s,
);
}
await destinationKey.store(secretType, secret, add: true);
migratedSecretTypes.add(secretType);
remainingSecrets.remove(secretType);
} catch (e, s) {
Logs().v(
'Could not migrate $secretType using SSSS key $keyId',
e,
s,
);
}
}
if (remainingSecrets.isEmpty) break;
}
if (stripKeys) {
await _validateAndStripMigratedSecrets(
destinationKey: destinationKey,
migratedSecretTypes: migratedSecretTypes,
isDefaultKey: stripAsDefaultKey,
);
}
return migratedSecretTypes;
}