From 662d0e569d60156b7b78310a83cf02d0aedc1a7c Mon Sep 17 00:00:00 2001 From: Andreas Date: Wed, 3 Apr 2024 14:49:38 +0200 Subject: [PATCH] Add `Event` for `EncryptionErrors` This commit adds `trycatch` to the encryption stuff and invokes an event if such a error happens. --- src/MauiSettings/Enums/MauiSettingsResults.cs | 10 ++ .../Events/EncryptionErrorEventArgs.cs | 8 ++ src/MauiSettings/MauiSettingsGeneric.cs | 123 +++++++++++++++--- 3 files changed, 123 insertions(+), 18 deletions(-) create mode 100644 src/MauiSettings/Enums/MauiSettingsResults.cs create mode 100644 src/MauiSettings/Events/EncryptionErrorEventArgs.cs diff --git a/src/MauiSettings/Enums/MauiSettingsResults.cs b/src/MauiSettings/Enums/MauiSettingsResults.cs new file mode 100644 index 0000000..0776591 --- /dev/null +++ b/src/MauiSettings/Enums/MauiSettingsResults.cs @@ -0,0 +1,10 @@ +namespace AndreasReitberger.Maui.Enums +{ + public enum MauiSettingsResults + { + Success, + Skipped, + EncryptionError, + Failed, + } +} diff --git a/src/MauiSettings/Events/EncryptionErrorEventArgs.cs b/src/MauiSettings/Events/EncryptionErrorEventArgs.cs new file mode 100644 index 0000000..797b93f --- /dev/null +++ b/src/MauiSettings/Events/EncryptionErrorEventArgs.cs @@ -0,0 +1,8 @@ +namespace AndreasReitberger.Maui.Events +{ + public partial class EncryptionErrorEventArgs : EventArgs + { + public Exception? Exception { get; set; } + public string Key { get; set; } = string.Empty; + } +} diff --git a/src/MauiSettings/MauiSettingsGeneric.cs b/src/MauiSettings/MauiSettingsGeneric.cs index d5d92d7..bcfb0fa 100644 --- a/src/MauiSettings/MauiSettingsGeneric.cs +++ b/src/MauiSettings/MauiSettingsGeneric.cs @@ -3,6 +3,7 @@ using AndreasReitberger.Maui.Cloud; #endif using AndreasReitberger.Maui.Enums; +using AndreasReitberger.Maui.Events; using AndreasReitberger.Maui.Helper; using AndreasReitberger.Maui.Utilities; using AndreasReitberger.Shared.Core.Utilities; @@ -68,7 +69,7 @@ public MauiSettingsGeneric(SO settingsObject, string settingsKey) public static Task LoadSettingAsync(Expression> value, string? key = null) => Task.Run(async delegate { - await LoadObjectSettingAsync(SettingsObject, value, key: key); + await LoadObjectSettingAsync(SettingsObject, value, key: key); }); public static Task LoadSecureSettingAsync(Expression> value, string? key = null) => Task.Run(async delegate @@ -336,7 +337,8 @@ static async Task GetClassMetaAsync(object settings, MauiSettingsActions mode, M settingsObjectInfo.OrignalSettingsObject = settings; settingsObjectInfo.Info = mInfo; // Handles saving the settings to the Maui.Storage.Preferences - _ = await ProcessSettingsInfoAsync(settingsObjectInfo, settingsInfo, mode, target, secureOnly: secureOnly, key: key); + MauiSettingsResults result = await ProcessSettingsInfoAsync(settingsObjectInfo, settingsInfo, mode, target, secureOnly: secureOnly, key: key); + if (result == MauiSettingsResults.EncryptionError || result == MauiSettingsResults.Failed) { break; } } } static async Task GetMetaFromDictionaryAsync(object settings, Dictionary> dictionary, MauiSettingsActions mode, MauiSettingsTarget target = MauiSettingsTarget.Local, bool secureOnly = false, string? key = null) @@ -371,8 +373,9 @@ static async Task GetMetaFromDictionaryAsync(object settings, Dictionary settingBaseAttributes return true; } - static async Task ProcessSettingsInfoAsync(MauiSettingsMemberInfo settingsObjectInfo, MauiSettingsInfo settingsInfo, MauiSettingsActions mode, MauiSettingsTarget target, bool secureOnly = false, bool useValueFromSettingsInfo = false, string? key = null, bool keepEncrypted = false) + static async Task ProcessSettingsInfoAsync(MauiSettingsMemberInfo settingsObjectInfo, MauiSettingsInfo settingsInfo, MauiSettingsActions mode, MauiSettingsTarget target, bool secureOnly = false, bool useValueFromSettingsInfo = false, string? key = null, bool keepEncrypted = false) { settingsInfo ??= new(); MauiSettingBaseAttribute? settingBaseAttribute = null; @@ -586,7 +589,7 @@ List settingBaseAttributes if (settingBaseAttributes?.Count == 0) { // If the member has not the needed MauiSettingsAttribute, continue with the search - return false; + return MauiSettingsResults.Skipped; } settingBaseAttribute = settingBaseAttributes?.FirstOrDefault(); settingsInfo.Name = MauiSettingNameFormater.GetFullSettingName(settingsObjectInfo.OrignalSettingsObject.GetType(), settingsObjectInfo.Info, settingBaseAttribute); @@ -605,7 +608,7 @@ List settingBaseAttributes { // If only secure storage should be loaded, stop here. if (secureOnly) - return true; + return MauiSettingsResults.Skipped; // If the value is not used from the passed settingsInfo, load it switch (target) @@ -673,8 +676,23 @@ List settingBaseAttributes if (settingsInfo.Value is string secureString) { // Decrypt string - string decryptedString = EncryptionManager.DecryptStringFromBase64String(secureString, key); - MauiSettingsObjectHelper.SetSettingValue(settingsObjectInfo.Info, settingsObjectInfo.OrignalSettingsObject, decryptedString, settingsInfo.SettingsType); + try + { + string decryptedString = EncryptionManager.DecryptStringFromBase64String(secureString, key); + // Throw on key missmatch + if (string.IsNullOrEmpty(decryptedString) && !string.IsNullOrEmpty(secureString)) + throw new Exception($"The secure string is not empty, but the decrypted string is. This indicates a key missmatch!"); + MauiSettingsObjectHelper.SetSettingValue(settingsObjectInfo.Info, settingsObjectInfo.OrignalSettingsObject, decryptedString, settingsInfo.SettingsType); + } + catch(Exception ex) + { + OnEncryptionErrorEvent(new() + { + Exception = ex, + Key = key, + }); + return MauiSettingsResults.EncryptionError; + } break; } } @@ -702,8 +720,20 @@ List settingBaseAttributes if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key)); // Encrypt string - string encryptedString = EncryptionManager.EncryptStringToBase64String(secureString, key); - await MauiSettingsHelper.SetSecureSettingsValueAsync(settingsInfo.Name, encryptedString); + try + { + string encryptedString = EncryptionManager.EncryptStringToBase64String(secureString, key); + await MauiSettingsHelper.SetSecureSettingsValueAsync(settingsInfo.Name, encryptedString); + } + catch (Exception ex) + { + OnEncryptionErrorEvent(new() + { + Exception = ex, + Key = key, + }); + return MauiSettingsResults.EncryptionError; + } } else await MauiSettingsHelper.SetSecureSettingsValueAsync(settingsInfo.Name, secureString); @@ -752,9 +782,21 @@ List settingBaseAttributes { if (settingsInfo.Encrypt && !string.IsNullOrEmpty(key)) { - // Decrypt string - string encryptedString = EncryptionManager.EncryptStringToBase64String(secureString, key); - await MauiSettingsHelper.SetSecureSettingsValueAsync(settingsInfo.Name, encryptedString); + // Encrypt string + try + { + string encryptedString = EncryptionManager.EncryptStringToBase64String(secureString, key); + await MauiSettingsHelper.SetSecureSettingsValueAsync(settingsInfo.Name, encryptedString); + } + catch (Exception ex) + { + OnEncryptionErrorEvent(new() + { + Exception = ex, + Key = key, + }); + return MauiSettingsResults.EncryptionError; + } } else await MauiSettingsHelper.SetSecureSettingsValueAsync(settingsInfo.Name, secureString); @@ -795,8 +837,20 @@ List settingBaseAttributes if (settingsInfo.Encrypt && !string.IsNullOrEmpty(key)) { // Decrypt string - string encryptedString = EncryptionManager.EncryptStringToBase64String(secureString, key); - await MauiSettingsHelper.SetSecureSettingsValueAsync(settingsInfo.Name, encryptedString); + try + { + string encryptedString = EncryptionManager.EncryptStringToBase64String(secureString, key); + await MauiSettingsHelper.SetSecureSettingsValueAsync(settingsInfo.Name, encryptedString); + } + catch (Exception ex) + { + OnEncryptionErrorEvent(new() + { + Exception = ex, + Key = key, + }); + return MauiSettingsResults.EncryptionError; + } } else await MauiSettingsHelper.SetSecureSettingsValueAsync(settingsInfo.Name, secureString); @@ -816,7 +870,7 @@ List settingBaseAttributes default: break; } - return true; + return MauiSettingsResults.Success; } static async Task ProcessSettingsInfoAsKeyValuePairAsync(MauiSettingsMemberInfo settingsObjectInfo, MauiSettingsInfo settingsInfo, bool secureOnly = false, string? key = null, bool keeyEncrypted = false) @@ -860,8 +914,26 @@ List settingBaseAttributes if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key)); // Decrypt string - string decryptedString = EncryptionManager.DecryptStringFromBase64String(settingsInfo.Value as string, key); - settingsInfo.Value = decryptedString; + if (settingsInfo.Value is string secureString) + { + try + { + string decryptedString = EncryptionManager.DecryptStringFromBase64String(secureString, key); + // Throw on key missmatch + if (string.IsNullOrEmpty(decryptedString) && !string.IsNullOrEmpty(secureString)) + throw new Exception($"The secure string is not empty, but the decrypted string is. This indicates a key missmatch!"); + settingsInfo.Value = decryptedString; + } + catch (Exception ex) + { + OnEncryptionErrorEvent(new() + { + Exception = ex, + Key = key, + }); + return null; + } + } } } else @@ -875,5 +947,20 @@ List settingBaseAttributes #endregion #endregion + + #region Events + + public static event EventHandler? ErrorEvent; + protected static void OnErrorEvent(ErrorEventArgs e) + { + ErrorEvent?.Invoke(typeof(MauiSettingsGeneric), e); + } + + public static event EventHandler? EncryptionErrorEvent; + protected static void OnEncryptionErrorEvent(EncryptionErrorEventArgs e) + { + EncryptionErrorEvent?.Invoke(typeof(MauiSettingsGeneric), e); + } + #endregion } }