resumePendingRotation method

Future<void> resumePendingRotation(
  1. String localId
)

Finishes a rotation that was interrupted, if there is one.

Idempotent, and safe to call when nothing is pending. Called by openDatabase and reopenDatabase before they touch a store, which is why an interrupted rotation is invisible in practice.

Every journalled store is tried under the key in force and then under the pending one: whichever opens it decides whether it still has to be re-encrypted. Throws StateError when localId is open (close it first) or when a store opens under neither key.

Implementation

Future<void> resumePendingRotation(String localId) async {
  final rotationKey = _rotationEntryKey(localId);
  final journal = await _keyStore.getKey(rotationKey);
  if (journal == null) return;
  if (_databases.containsKey(localId)) {
    throw StateError(
      'Close database "$localId" before finishing its passphrase rotation.',
    );
  }

  final (newKey, collections) = _decodeRotation(journal);
  final entryKey = '${_config.appId}/$localId';
  final current = await _keyStore.getKey(entryKey) ?? newKey;
  for (final collection in collections) {
    await _finishRekey(localId, collection, from: current, to: newKey);
  }
  await _keyStore.setKey(entryKey, newKey);
  _databaseKeys[localId] = newKey;
  await _keyStore.clear(rotationKey);
}