diff --git a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs index fbd0f19ec1..b57b12bff7 100644 --- a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs +++ b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs @@ -2220,6 +2220,15 @@ public static string Country { } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Create daily backup ähnelt. + /// + public static string CreateDailyBackup { + get { + return ResourceManager.GetString("CreateDailyBackup", resourceCulture); + } + } + /// /// Sucht eine lokalisierte Zeichenfolge, die Credential ähnelt. /// @@ -4450,6 +4459,15 @@ public static string HelpMessage_ExperimentalFeatures { } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Number of backups that are retained before the oldest one is deleted. ähnelt. + /// + public static string HelpMessage_MaximumNumberOfBackups { + get { + return ResourceManager.GetString("HelpMessage_MaximumNumberOfBackups", resourceCulture); + } + } + /// /// Sucht eine lokalisierte Zeichenfolge, die Application that is displayed at startup. ähnelt. /// @@ -5783,6 +5801,15 @@ public static string MaximumHops { } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Maximum number of backups ähnelt. + /// + public static string MaximumNumberOfBackups { + get { + return ResourceManager.GetString("MaximumNumberOfBackups", resourceCulture); + } + } + /// /// Sucht eine lokalisierte Zeichenfolge, die Maximum number ({0}) of hops/router reached! ähnelt. /// diff --git a/Source/NETworkManager.Localization/Resources/Strings.resx b/Source/NETworkManager.Localization/Resources/Strings.resx index 28ccf1c004..3dd4967eaf 100644 --- a/Source/NETworkManager.Localization/Resources/Strings.resx +++ b/Source/NETworkManager.Localization/Resources/Strings.resx @@ -3951,4 +3951,13 @@ If you click Cancel, the profile file will remain unencrypted. Could not parse "{0}". + + Maximum number of backups + + + Create daily backup + + + Number of backups that are retained before the oldest one is deleted. + \ No newline at end of file diff --git a/Source/NETworkManager.Models/Network/NetworkInterface.cs b/Source/NETworkManager.Models/Network/NetworkInterface.cs index d7662f6704..7cd8c34038 100644 --- a/Source/NETworkManager.Models/Network/NetworkInterface.cs +++ b/Source/NETworkManager.Models/Network/NetworkInterface.cs @@ -527,7 +527,6 @@ private static void RemoveIPAddressFromNetworkInterface(NetworkInterfaceConfig c #endregion - #region Events /// diff --git a/Source/NETworkManager.Profiles/ProfileManager.cs b/Source/NETworkManager.Profiles/ProfileManager.cs index e7cdb73390..c236eab1ac 100644 --- a/Source/NETworkManager.Profiles/ProfileManager.cs +++ b/Source/NETworkManager.Profiles/ProfileManager.cs @@ -25,14 +25,14 @@ public static class ProfileManager private const string ProfilesFolderName = "Profiles"; /// - /// Default profile name. + /// Profiles backups directory name. /// - private const string ProfilesDefaultFileName = "Default"; + private static string BackupFolderName => "Backups"; /// - /// Profiles backups directory name. + /// Default profile name. /// - private static string BackupFolderName => "Backups"; + private const string ProfilesDefaultFileName = "Default"; /// /// Profile file extension. @@ -290,14 +290,21 @@ public static void CreateEmptyProfileFile(string profileName) /// New of the profile file. public static void RenameProfileFile(ProfileFileInfo profileFileInfo, string newProfileName) { + // Check if the profile is currently in use var switchProfile = false; - + if (LoadedProfileFile != null && LoadedProfileFile.Equals(profileFileInfo)) { Save(); switchProfile = true; } + // Create backup + Backup(profileFileInfo.Path, + GetProfilesBackupFolderLocation(), + TimestampHelper.GetTimestampFilename(Path.GetFileName(profileFileInfo.Path))); + + // Create new profile info with the new name ProfileFileInfo newProfileFileInfo = new(newProfileName, Path.Combine(GetProfilesFolderLocation(), $"{newProfileName}{Path.GetExtension(profileFileInfo.Path)}"), profileFileInfo.IsEncrypted) @@ -306,15 +313,18 @@ public static void RenameProfileFile(ProfileFileInfo profileFileInfo, string new IsPasswordValid = profileFileInfo.IsPasswordValid }; + // Copy the profile file to the new location File.Copy(profileFileInfo.Path, newProfileFileInfo.Path); ProfileFiles.Add(newProfileFileInfo); + // Switch profile, if it was previously loaded if (switchProfile) { Switch(newProfileFileInfo, false); LoadedProfileFileChanged(LoadedProfileFile, true); } + // Remove the old profile file File.Delete(profileFileInfo.Path); ProfileFiles.Remove(profileFileInfo); } @@ -353,6 +363,11 @@ public static void EnableEncryption(ProfileFileInfo profileFileInfo, SecureStrin switchProfile = true; } + // Create backup + Backup(profileFileInfo.Path, + GetProfilesBackupFolderLocation(), + TimestampHelper.GetTimestampFilename(Path.GetFileName(profileFileInfo.Path))); + // Create a new profile info with the encryption infos var newProfileFileInfo = new ProfileFileInfo(profileFileInfo.Name, Path.ChangeExtension(profileFileInfo.Path, ProfileFileExtensionEncrypted), true) @@ -361,9 +376,9 @@ public static void EnableEncryption(ProfileFileInfo profileFileInfo, SecureStrin IsPasswordValid = true }; - List profiles = Path.GetExtension(profileFileInfo.Path) == LegacyProfileFileExtension - ? DeserializeFromXmlFile(profileFileInfo.Path) - : DeserializeFromFile(profileFileInfo.Path); + List profiles = Path.GetExtension(profileFileInfo.Path) == LegacyProfileFileExtension ? + DeserializeFromXmlFile(profileFileInfo.Path) : + DeserializeFromFile(profileFileInfo.Path); // Save the encrypted file var decryptedBytes = SerializeToByteArray(profiles); @@ -409,7 +424,12 @@ public static void ChangeMasterPassword(ProfileFileInfo profileFileInfo, SecureS switchProfile = true; } - // Create a new profile info with the encryption infos + // Create backup + Backup(profileFileInfo.Path, + GetProfilesBackupFolderLocation(), + TimestampHelper.GetTimestampFilename(Path.GetFileName(profileFileInfo.Path))); + + // Create new profile info with the encryption infos var newProfileFileInfo = new ProfileFileInfo(profileFileInfo.Name, Path.ChangeExtension(profileFileInfo.Path, ProfileFileExtensionEncrypted), true) { @@ -423,11 +443,9 @@ public static void ChangeMasterPassword(ProfileFileInfo profileFileInfo, SecureS GlobalStaticConfiguration.Profile_EncryptionKeySize, GlobalStaticConfiguration.Profile_EncryptionIterations); - List profiles; - - profiles = IsXmlContent(decryptedBytes) - ? DeserializeFromXmlByteArray(decryptedBytes) - : DeserializeFromByteArray(decryptedBytes); + List profiles = IsXmlContent(decryptedBytes) ? + DeserializeFromXmlByteArray(decryptedBytes) : + DeserializeFromByteArray(decryptedBytes); // Save the encrypted file decryptedBytes = SerializeToByteArray(profiles); @@ -468,7 +486,12 @@ public static void DisableEncryption(ProfileFileInfo profileFileInfo, SecureStri switchProfile = true; } - // Create a new profile info + // Create backup + Backup(profileFileInfo.Path, + GetProfilesBackupFolderLocation(), + TimestampHelper.GetTimestampFilename(Path.GetFileName(profileFileInfo.Path))); + + // Create new profile info var newProfileFileInfo = new ProfileFileInfo(profileFileInfo.Name, Path.ChangeExtension(profileFileInfo.Path, ProfileFileExtension)); @@ -478,9 +501,10 @@ public static void DisableEncryption(ProfileFileInfo profileFileInfo, SecureStri GlobalStaticConfiguration.Profile_EncryptionKeySize, GlobalStaticConfiguration.Profile_EncryptionIterations); - List profiles = IsXmlContent(decryptedBytes) - ? DeserializeFromXmlByteArray(decryptedBytes) - : DeserializeFromByteArray(decryptedBytes); + List profiles = IsXmlContent(decryptedBytes) ? + DeserializeFromXmlByteArray(decryptedBytes) : + DeserializeFromByteArray(decryptedBytes); + // Save the decrypted profiles to the profile file SerializeToFile(newProfileFileInfo.Path, profiles); diff --git a/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs b/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs index af7ea9117d..851a5c233c 100644 --- a/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs +++ b/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs @@ -46,9 +46,6 @@ public static class GlobalStaticConfiguration public static string ZipFileExtensionFilter => "ZIP Archive (*.zip)|*.zip"; public static string XmlFileExtensionFilter => "XML-File (*.xml)|*.xml"; - // Backup settings - public static int Backup_MaximumNumberOfBackups => 10; - #endregion #region Default settings @@ -74,18 +71,23 @@ public static class GlobalStaticConfiguration public static bool Status_ShowWindowOnNetworkChange => true; public static int Status_WindowCloseTime => 10; - // HotKey + // Settings: HotKey public static int HotKey_ShowWindowKey => 79; public static int HotKey_ShowWindowModifier => 3; - // Update + // Settings: Update public static bool Update_CheckForUpdatesAtStartup => true; - public static bool Update_CheckForPreReleases => false; - - // Experimental public static bool Experimental_EnableExperimentalFeatures => false; + // Settings: Profiles + public static bool Profiles_IsDailyBackupEnabled => true; + public static int Profiles_MaximumNumberOfBackups => 10; + + // Settings: Settings + public static bool Settings_IsDailyBackupEnabled => true; + public static int Settings_MaximumNumberOfBackups => 10; + // Application: Dashboard public static string Dashboard_PublicIPv4Address => "1.1.1.1"; public static string Dashboard_PublicIPv6Address => "2606:4700:4700::1111"; diff --git a/Source/NETworkManager.Settings/SettingsInfo.cs b/Source/NETworkManager.Settings/SettingsInfo.cs index 4a41e94680..97834d7515 100644 --- a/Source/NETworkManager.Settings/SettingsInfo.cs +++ b/Source/NETworkManager.Settings/SettingsInfo.cs @@ -582,6 +582,67 @@ public string Profiles_LastSelected } } + private bool _profiles_IsDailyBackupEnabled = GlobalStaticConfiguration.Profiles_IsDailyBackupEnabled; + + public bool Profiles_IsDailyBackupEnabled + { + get => _profiles_IsDailyBackupEnabled; + set + { + if (value == _profiles_IsDailyBackupEnabled) + return; + + _profiles_IsDailyBackupEnabled = value; + OnPropertyChanged(); + } + } + + private int _profiles_MaximumNumberOfBackups = GlobalStaticConfiguration.Profiles_MaximumNumberOfBackups; + + public int Profiles_MaximumNumberOfBackups + { + get => _profiles_MaximumNumberOfBackups; + set + { + if (value == _profiles_MaximumNumberOfBackups) + return; + + _profiles_MaximumNumberOfBackups = value; + OnPropertyChanged(); + } + } + + // Settings + private bool _settings_IsDailyBackupEnabled = GlobalStaticConfiguration.Settings_IsDailyBackupEnabled; + + public bool Settings_IsDailyBackupEnabled + { + get => _settings_IsDailyBackupEnabled; + set + { + if (value == _settings_IsDailyBackupEnabled) + return; + + _settings_IsDailyBackupEnabled = value; + OnPropertyChanged(); + } + } + + private int _settings_MaximumNumberOfBackups = GlobalStaticConfiguration.Settings_MaximumNumberOfBackups; + + public int Settings_MaximumNumberOfBackups + { + get => _settings_MaximumNumberOfBackups; + set + { + if (value == _settings_MaximumNumberOfBackups) + return; + + _settings_MaximumNumberOfBackups = value; + OnPropertyChanged(); + } + } + #endregion #region Others diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs index 7c0041f063..a0c5c9c1ca 100644 --- a/Source/NETworkManager.Settings/SettingsManager.cs +++ b/Source/NETworkManager.Settings/SettingsManager.cs @@ -265,6 +265,14 @@ private static void SerializeToFile(string filePath) /// called as part of a daily maintenance routine. private static void CreateDailyBackupIfNeeded() { + // Check if backups are disabled + if (!Current.Settings_IsDailyBackupEnabled) + { + Log.Debug("Daily backups are disabled. Skipping backup creation..."); + + return; + } + var currentDate = DateTime.Now.Date; if (Current.LastBackup < currentDate) @@ -284,7 +292,7 @@ private static void CreateDailyBackupIfNeeded() // Cleanup old backups CleanupBackups(GetSettingsBackupFolderLocation(), GetSettingsFileName(), - GlobalStaticConfiguration.Backup_MaximumNumberOfBackups); + Current.Settings_MaximumNumberOfBackups); Current.LastBackup = currentDate; } diff --git a/Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs b/Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs index fd42c76821..7dd0e17546 100644 --- a/Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs +++ b/Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs @@ -22,6 +22,8 @@ public class SettingsProfilesViewModel : ViewModelBase public Action CloseAction { get; set; } + private readonly bool _isLoading; + private string _location; public string Location @@ -67,12 +69,49 @@ public ProfileFileInfo SelectedProfileFile } } + private bool _isDailyBackupEnabled; + + public bool IsDailyBackupEnabled + { + get => _isDailyBackupEnabled; + set + { + if (value == _isDailyBackupEnabled) + return; + + if (!_isLoading) + SettingsManager.Current.Profiles_IsDailyBackupEnabled = value; + + _isDailyBackupEnabled = value; + OnPropertyChanged(); + } + } + + private int _maximumNumberOfBackups; + + public int MaximumNumberOfBackups + { + get => _maximumNumberOfBackups; + set + { + if (value == _maximumNumberOfBackups) + return; + + if (!_isLoading) + SettingsManager.Current.Profiles_MaximumNumberOfBackups = value; + + _maximumNumberOfBackups = value; + OnPropertyChanged(); + } + } #endregion #region Constructor, LoadSettings public SettingsProfilesViewModel() { + _isLoading = true; + ProfileFiles = new CollectionViewSource { Source = ProfileManager.ProfileFiles }.View; ProfileFiles.SortDescriptions.Add( new SortDescription(nameof(ProfileFileInfo.Name), ListSortDirection.Ascending)); @@ -80,11 +119,15 @@ public SettingsProfilesViewModel() SelectedProfileFile = ProfileFiles.Cast().FirstOrDefault(); LoadSettings(); + + _isLoading = false; } private void LoadSettings() { Location = ProfileManager.GetProfilesFolderLocation(); + IsDailyBackupEnabled = SettingsManager.Current.Profiles_IsDailyBackupEnabled; + MaximumNumberOfBackups = SettingsManager.Current.Profiles_MaximumNumberOfBackups; } #endregion diff --git a/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs b/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs index 399ffb1e02..dc1d7d95b1 100644 --- a/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs +++ b/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs @@ -1,8 +1,6 @@ -using MahApps.Metro.SimpleChildWindow; -using NETworkManager.Localization.Resources; +using NETworkManager.Localization.Resources; using NETworkManager.Settings; using NETworkManager.Utilities; -using NETworkManager.Views; using System; using System.Diagnostics; using System.Threading.Tasks; @@ -16,6 +14,8 @@ public class SettingsSettingsViewModel : ViewModelBase #region Variables public Action CloseAction { get; set; } + private readonly bool _isLoading; + private string _location; public string Location @@ -30,18 +30,61 @@ public string Location OnPropertyChanged(); } } + + private bool _isDailyBackupEnabled; + + public bool IsDailyBackupEnabled + { + get => _isDailyBackupEnabled; + set + { + if (value == _isDailyBackupEnabled) + return; + + if (!_isLoading) + SettingsManager.Current.Settings_IsDailyBackupEnabled = value; + + _isDailyBackupEnabled = value; + OnPropertyChanged(); + } + } + + private int _maximumNumberOfBackups; + + public int MaximumNumberOfBackups + { + get => _maximumNumberOfBackups; + set + { + if (value == _maximumNumberOfBackups) + return; + + if (!_isLoading) + SettingsManager.Current.Settings_MaximumNumberOfBackups = value; + + _maximumNumberOfBackups = value; + OnPropertyChanged(); + } + } + #endregion #region Constructor, LoadSettings public SettingsSettingsViewModel() { + _isLoading = true; + LoadSettings(); + + _isLoading = false; } private void LoadSettings() { Location = SettingsManager.GetSettingsFolderLocation(); + IsDailyBackupEnabled = SettingsManager.Current.Settings_IsDailyBackupEnabled; + MaximumNumberOfBackups = SettingsManager.Current.Settings_MaximumNumberOfBackups; } #endregion diff --git a/Source/NETworkManager/Views/SettingsProfilesView.xaml b/Source/NETworkManager/Views/SettingsProfilesView.xaml index d73f2640c8..0989c4a24d 100644 --- a/Source/NETworkManager/Views/SettingsProfilesView.xaml +++ b/Source/NETworkManager/Views/SettingsProfilesView.xaml @@ -3,6 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" xmlns:converters="clr-namespace:NETworkManager.Converters;assembly=NETworkManager.Converters" xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF" @@ -144,7 +145,8 @@ + + + + + + + +