createEncryptionRecoveryHook function

PVCacheHook createEncryptionRecoveryHook({
  1. DecryptionFailureCallback? onDecryptionFailure,
  2. bool autoClearOnFailure = false,
  3. bool throwOnFailure = false,
  4. int priority = 10,
})

Creates a hook that handles decryption failures.

This hook should run AFTER the encryption decrypt hook to catch failures. IMPORTANT: When using this hook, you must set throwOnFailure: false in the encryption decrypt hook, otherwise exceptions will be thrown before this hook can handle them.

Implementation

PVCacheHook createEncryptionRecoveryHook({
  DecryptionFailureCallback? onDecryptionFailure,
  bool autoClearOnFailure = false,
  bool throwOnFailure = false,
  int priority = 10,
}) {
  return PVCacheHook(
    eventString: 'encryption_recovery',
    eventFlow: EventFlow.postProcess,
    priority: priority,
    actionTypes: [ActionType.get, ActionType.exists],
    hookFunction: (ctx) async {
      // Check if decryption failed (value is null but _encrypted flag exists)
      final wasEncrypted = ctx.runtimeMeta['_encrypted'] == true;
      final decryptionFailed = wasEncrypted && ctx.entryValue == null;

      if (!decryptionFailed) return;

      // Call user callback if provided
      bool shouldClear = autoClearOnFailure;
      if (onDecryptionFailure != null && ctx.resolvedKey != null) {
        shouldClear = await onDecryptionFailure(ctx.resolvedKey!);
      }

      // Clear the corrupted entry if requested
      if (shouldClear && ctx.resolvedKey != null) {
        await ctx.cache.delete(ctx.resolvedKey!);
        // Mark in runtime data that entry was cleared
        ctx.runtimeData['_recovery_cleared'] = true;
      }

      // Throw error if requested
      if (throwOnFailure && ctx.resolvedKey != null) {
        throw Exception(
          'Decryption failed for key: ${ctx.resolvedKey}. The encryption key may have changed or the data is corrupted.',
        );
      }
    },
  );
}