createSelectiveEncryptionDecryptHook function

PVCacheHook createSelectiveEncryptionDecryptHook({
  1. String? encryptionKey,
  2. String keyName = DEFAULT_ENCRYPTION_KEY_NAME,
  3. int priority = 0,
})

Creates a hook that decrypts selectively encrypted fields.

Implementation

PVCacheHook createSelectiveEncryptionDecryptHook({
  String? encryptionKey,
  String keyName = DEFAULT_ENCRYPTION_KEY_NAME,
  int priority = 0,
}) {
  return PVCacheHook(
    eventString: 'selective_encryption_decrypt',
    eventFlow: EventFlow.postProcess,
    priority: priority,
    actionTypes: [ActionType.get, ActionType.exists],
    hookFunction: (ctx) async {
      // Skip if no value
      if (ctx.entryValue == null) return;

      // Check if this entry has selective encryption
      final nonces = ctx.runtimeMeta['_encryption_nonces'] as Map?;
      if (nonces == null || nonces.isEmpty) return;

      // Get encryption key
      final key = encryptionKey ?? await getOrCreateEncryptionKey(keyName);
      final cipher = AESCipher(key);

      // Make a deep copy of the value to modify
      final valueJson = jsonEncode(ctx.entryValue);
      final modifiedValue = jsonDecode(valueJson);

      // Decrypt each field
      for (final entry in nonces.entries) {
        final path = entry.key as String;
        // Note: nonce is stored in metadata but not needed for decryption
        // The IV generated from the nonce is embedded in the encrypted data

        // Get the encrypted value at this path
        final encryptedValue = getNestedValue(modifiedValue, path);
        if (encryptedValue == null || encryptedValue is! String) continue;

        try {
          // Decrypt (IV is extracted from encrypted data)
          final decrypted = cipher.decryptString(encryptedValue);

          // Parse JSON back to original value
          final fieldValue = jsonDecode(decrypted);

          // Restore decrypted value
          setNestedValue(modifiedValue, path, fieldValue);
        } catch (e) {
          // If decryption fails for this field, leave it as is
          print('Warning: Failed to decrypt field "$path": $e');
        }
      }

      // Update entry value with decrypted data
      ctx.entryValue = modifiedValue;
    },
  );
}