From 1b7bb26def19bd002d3114d040e76692b7ac51a6 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 23 Jan 2026 00:17:19 -0500 Subject: [PATCH] refactor(securestore): remove password-based authentication in favor of key-file only Simplify SecureStore by removing MasterKeyEnvVar and password-based methods, leaving only key-file authentication for better security practices. --- .../Options/SecureStoreOptions.cs | 8 +- NEW/src/JdeScoping.Host/appsettings.json | 95 +------- .../Security/SecureStoreService.cs | 33 +-- .../Models/ConfigModel.cs | 7 +- .../Dialogs/NewStoreDialogViewModel.cs | 90 +------ .../Dialogs/UnlockStoreDialogViewModel.cs | 77 +----- .../Views/Dialogs/NewStoreDialog.axaml | 50 +--- .../Views/Dialogs/UnlockStoreDialog.axaml | 43 +--- .../Application/StoreUseCases.cs | 54 ++--- .../Services/ISecureStoreManager.cs | 14 -- .../Services/SecureStoreManager.cs | 45 ---- .../ViewModels/DialogViewModels.cs | 160 +------------ .../ViewModels/MainWindowViewModel.cs | 48 ++-- .../Views/MainWindow.axaml.cs | 10 +- .../Views/NewStoreDialog.axaml | 51 +--- .../Views/OpenStoreDialog.axaml | 45 +--- .../Dialogs/NewStoreDialogViewModelTests.cs | 224 +----------------- .../UnlockStoreDialogViewModelTests.cs | 187 +-------------- .../Services/SecureStoreManagerTests.cs | 41 ---- .../ViewModels/DialogViewModelTests.cs | 198 +--------------- .../ViewModels/MainWindowViewModelTests.cs | 34 +-- .../Views/NewStoreDialogTests.cs | 8 +- 22 files changed, 101 insertions(+), 1421 deletions(-) diff --git a/NEW/src/JdeScoping.Core/Options/SecureStoreOptions.cs b/NEW/src/JdeScoping.Core/Options/SecureStoreOptions.cs index ed11905..0e6cc9d 100644 --- a/NEW/src/JdeScoping.Core/Options/SecureStoreOptions.cs +++ b/NEW/src/JdeScoping.Core/Options/SecureStoreOptions.cs @@ -17,17 +17,11 @@ public class SecureStoreOptions public string StorePath { get; set; } = "data/secrets.json"; /// - /// Path to the key file (used in development). + /// Path to the key file used for encryption/decryption. /// Defaults to "data/secrets.key" relative to app directory. /// public string KeyFilePath { get; set; } = "data/secrets.key"; - /// - /// Environment variable name containing the master key (used in production). - /// If set and the env var exists, it takes precedence over the key file. - /// - public string MasterKeyEnvVar { get; set; } = "SCOPINGTOOL_MASTER_KEY"; - /// /// Whether to auto-create the store and generate a key file on first run. /// diff --git a/NEW/src/JdeScoping.Host/appsettings.json b/NEW/src/JdeScoping.Host/appsettings.json index 3d39c51..c5bd6fb 100644 --- a/NEW/src/JdeScoping.Host/appsettings.json +++ b/NEW/src/JdeScoping.Host/appsettings.json @@ -19,99 +19,7 @@ "BulkCopyBatchSize": 10000, "LookbackMultiplier": 3, "PurgeRetentionDays": 30, - "SyncTimeoutSeconds": 3600, - "DataSources": [ - { - "TableName": "WorkOrder_Curr", - "SourceSystem": "JDE", - "SourceData": "WORKORDER", - "IsEnabled": true, - "MassConfig": { "Enabled": true, "IntervalMinutes": 10080 }, - "DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 }, - "HourlyConfig": { "Enabled": true, "IntervalMinutes": 60 } - }, - { - "TableName": "LotUsage_Curr", - "SourceSystem": "JDE", - "SourceData": "LOTUSAGE", - "IsEnabled": true, - "MassConfig": { "Enabled": true, "IntervalMinutes": 10080 }, - "DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 }, - "HourlyConfig": { "Enabled": true, "IntervalMinutes": 60 } - }, - { - "TableName": "Item", - "SourceSystem": "JDE", - "SourceData": "ITEM", - "IsEnabled": true, - "MassConfig": { "Enabled": true, "IntervalMinutes": 10080 }, - "DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 }, - "HourlyConfig": { "Enabled": false } - }, - { - "TableName": "Lot", - "SourceSystem": "JDE", - "SourceData": "LOT", - "IsEnabled": true, - "MassConfig": { "Enabled": true, "IntervalMinutes": 10080 }, - "DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 }, - "HourlyConfig": { "Enabled": true, "IntervalMinutes": 60 } - }, - { - "TableName": "WorkCenter", - "SourceSystem": "JDE", - "SourceData": "WORKCENTER", - "IsEnabled": true, - "MassConfig": { "Enabled": true, "IntervalMinutes": 10080 }, - "DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 }, - "HourlyConfig": { "Enabled": false } - }, - { - "TableName": "ProfitCenter", - "SourceSystem": "JDE", - "SourceData": "PROFITCENTER", - "IsEnabled": true, - "MassConfig": { "Enabled": true, "IntervalMinutes": 10080 }, - "DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 }, - "HourlyConfig": { "Enabled": false } - }, - { - "TableName": "JdeUser", - "SourceSystem": "JDE", - "SourceData": "JDEUSER", - "IsEnabled": true, - "MassConfig": { "Enabled": true, "IntervalMinutes": 10080 }, - "DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 }, - "HourlyConfig": { "Enabled": false } - }, - { - "TableName": "Branch", - "SourceSystem": "JDE", - "SourceData": "BRANCH", - "IsEnabled": true, - "MassConfig": { "Enabled": true, "IntervalMinutes": 10080 }, - "DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 }, - "HourlyConfig": { "Enabled": false } - }, - { - "TableName": "MisData_Curr", - "SourceSystem": "CMS", - "SourceData": "MISDATA_CURR", - "IsEnabled": true, - "MassConfig": { "Enabled": true, "IntervalMinutes": 10080 }, - "DailyConfig": { "Enabled": true, "IntervalMinutes": 1440 }, - "HourlyConfig": { "Enabled": false } - }, - { - "TableName": "MisData_Hist", - "SourceSystem": "CMS", - "SourceData": "MISDATA_HIST", - "IsEnabled": true, - "MassConfig": { "Enabled": true, "IntervalMinutes": 10080 }, - "DailyConfig": { "Enabled": false }, - "HourlyConfig": { "Enabled": false } - } - ] + "SyncTimeoutSeconds": 3600 }, "Auth": { "CookieName": "ScopingTool.Auth", @@ -142,7 +50,6 @@ "SecureStore": { "StorePath": "data/secrets.json", "KeyFilePath": "data/secrets.key", - "MasterKeyEnvVar": "SCOPINGTOOL_MASTER_KEY", "AutoCreateStore": true, "RequiredKeys": [ "RsaPrivateKey", diff --git a/NEW/src/JdeScoping.Infrastructure/Security/SecureStoreService.cs b/NEW/src/JdeScoping.Infrastructure/Security/SecureStoreService.cs index 595cde1..7189e3f 100644 --- a/NEW/src/JdeScoping.Infrastructure/Security/SecureStoreService.cs +++ b/NEW/src/JdeScoping.Infrastructure/Security/SecureStoreService.cs @@ -37,26 +37,12 @@ public class SecureStoreService : ISecureStoreService ? opts.KeyFilePath : Path.Combine(AppContext.BaseDirectory, opts.KeyFilePath); - // Check for master key in environment variable (production) - var masterKey = Environment.GetEnvironmentVariable(opts.MasterKeyEnvVar); - var useMasterKey = !string.IsNullOrEmpty(masterKey); - if (File.Exists(_storePath)) { // Load existing store _logger.LogInformation("Loading secure store from {StorePath}", _storePath); _secretsManager = SecretsManager.LoadStore(_storePath); - - // Load the key - if (useMasterKey) - { - _secretsManager.LoadKeyFromPassword(masterKey!); - } - else - { - _secretsManager.LoadKeyFromFile(keyFilePath); - } - + _secretsManager.LoadKeyFromFile(keyFilePath); LoadKeys(); } else if (opts.AutoCreateStore) @@ -64,21 +50,12 @@ public class SecureStoreService : ISecureStoreService // Create new store _logger.LogInformation("Creating new secure store at {StorePath}", _storePath); EnsureDirectory(_storePath); + EnsureDirectory(keyFilePath); _secretsManager = SecretsManager.CreateStore(); - - if (useMasterKey) - { - _secretsManager.LoadKeyFromPassword(masterKey!); - } - else - { - // Generate key file for development - EnsureDirectory(keyFilePath); - _secretsManager.GenerateKey(); - _secretsManager.ExportKey(keyFilePath); - _logger.LogInformation("Generated key file at {KeyFilePath}", keyFilePath); - } + _secretsManager.GenerateKey(); + _secretsManager.ExportKey(keyFilePath); + _logger.LogInformation("Generated key file at {KeyFilePath}", keyFilePath); // Save empty store _secretsManager.SaveStore(_storePath); diff --git a/NEW/src/Utils/JdeScoping.ConfigManager/Models/ConfigModel.cs b/NEW/src/Utils/JdeScoping.ConfigManager/Models/ConfigModel.cs index 6fcfba8..0c2d7ed 100644 --- a/NEW/src/Utils/JdeScoping.ConfigManager/Models/ConfigModel.cs +++ b/NEW/src/Utils/JdeScoping.ConfigManager/Models/ConfigModel.cs @@ -252,15 +252,10 @@ public class SecureStoreSection public string StorePath { get; set; } = "data/secrets.json"; /// - /// Gets or sets the path to the key file for decryption. + /// Gets or sets the path to the key file for encryption/decryption. /// public string KeyFilePath { get; set; } = "data/secrets.key"; - /// - /// Gets or sets the environment variable name for the master key. - /// - public string MasterKeyEnvVar { get; set; } = "SCOPINGTOOL_MASTER_KEY"; - /// /// Gets or sets a value indicating whether to auto-create the store if it doesn't exist. /// diff --git a/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Dialogs/NewStoreDialogViewModel.cs b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Dialogs/NewStoreDialogViewModel.cs index 4a0322e..e2abe8f 100644 --- a/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Dialogs/NewStoreDialogViewModel.cs +++ b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Dialogs/NewStoreDialogViewModel.cs @@ -10,10 +10,6 @@ public class NewStoreDialogViewModel : ViewModelBase { private string _storePath = string.Empty; private string _keyFilePath = string.Empty; - private string _password = string.Empty; - private string _confirmPassword = string.Empty; - private bool _useKeyFile = true; - private bool _usePassword; /// /// Initializes a new instance of the class. @@ -51,64 +47,6 @@ public class NewStoreDialogViewModel : ViewModelBase } } - /// - /// Gets or sets the password for store encryption. - /// - public string Password - { - get => _password; - set - { - if (SetProperty(ref _password, value)) - NotifyValidationChanged(); - } - } - - /// - /// Gets or sets the password confirmation value. - /// - public string ConfirmPassword - { - get => _confirmPassword; - set - { - if (SetProperty(ref _confirmPassword, value)) - NotifyValidationChanged(); - } - } - - /// - /// Gets or sets whether to use key file for store encryption. - /// - public bool UseKeyFile - { - get => _useKeyFile; - set - { - if (SetProperty(ref _useKeyFile, value)) - { - if (value) UsePassword = false; - NotifyValidationChanged(); - } - } - } - - /// - /// Gets or sets whether to use password for store encryption. - /// - public bool UsePassword - { - get => _usePassword; - set - { - if (SetProperty(ref _usePassword, value)) - { - if (value) UseKeyFile = false; - NotifyValidationChanged(); - } - } - } - /// /// Gets the command to browse for store path location. /// @@ -127,22 +65,7 @@ public class NewStoreDialogViewModel : ViewModelBase /// /// Gets a value indicating whether the dialog input is valid. /// - public bool IsValid - { - get - { - if (string.IsNullOrWhiteSpace(StorePath)) - return false; - - if (UseKeyFile) - return !string.IsNullOrWhiteSpace(KeyFilePath); - - if (UsePassword) - return !string.IsNullOrWhiteSpace(Password) && Password == ConfirmPassword; - - return false; - } - } + public bool IsValid => !string.IsNullOrWhiteSpace(StorePath) && !string.IsNullOrWhiteSpace(KeyFilePath); /// /// Gets the validation error message, or null if valid. @@ -154,18 +77,9 @@ public class NewStoreDialogViewModel : ViewModelBase if (string.IsNullOrWhiteSpace(StorePath)) return SecureStoreStrings.StorePathRequired; - if (UseKeyFile && string.IsNullOrWhiteSpace(KeyFilePath)) + if (string.IsNullOrWhiteSpace(KeyFilePath)) return SecureStoreStrings.KeyFilePathRequired; - if (UsePassword) - { - if (string.IsNullOrWhiteSpace(Password)) - return SecureStoreStrings.PasswordRequired; - - if (Password != ConfirmPassword) - return SecureStoreStrings.PasswordsDoNotMatch; - } - return null; } } diff --git a/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Dialogs/UnlockStoreDialogViewModel.cs b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Dialogs/UnlockStoreDialogViewModel.cs index 0f60d44..d063fcc 100644 --- a/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Dialogs/UnlockStoreDialogViewModel.cs +++ b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Dialogs/UnlockStoreDialogViewModel.cs @@ -10,9 +10,6 @@ public class UnlockStoreDialogViewModel : ViewModelBase { private readonly string _storePath; private string _keyFilePath = string.Empty; - private string _password = string.Empty; - private bool _useKeyFile = true; - private bool _usePassword; /// /// Initializes a new instance of the class. @@ -42,51 +39,6 @@ public class UnlockStoreDialogViewModel : ViewModelBase } } - /// - /// Gets or sets the password for store decryption. - /// - public string Password - { - get => _password; - set - { - if (SetProperty(ref _password, value)) - NotifyValidationChanged(); - } - } - - /// - /// Gets or sets whether to use key file for store decryption. - /// - public bool UseKeyFile - { - get => _useKeyFile; - set - { - if (SetProperty(ref _useKeyFile, value)) - { - if (value) UsePassword = false; - NotifyValidationChanged(); - } - } - } - - /// - /// Gets or sets whether to use password for store decryption. - /// - public bool UsePassword - { - get => _usePassword; - set - { - if (SetProperty(ref _usePassword, value)) - { - if (value) UseKeyFile = false; - NotifyValidationChanged(); - } - } - } - /// /// Gets the command to browse for key file path location. /// @@ -99,19 +51,10 @@ public class UnlockStoreDialogViewModel : ViewModelBase { get { - if (UseKeyFile) - { - if (string.IsNullOrWhiteSpace(KeyFilePath)) - return false; + if (string.IsNullOrWhiteSpace(KeyFilePath)) + return false; - if (!System.IO.File.Exists(KeyFilePath)) - return false; - } - - if (UsePassword) - return !string.IsNullOrWhiteSpace(Password); - - return false; + return System.IO.File.Exists(KeyFilePath); } } @@ -122,17 +65,11 @@ public class UnlockStoreDialogViewModel : ViewModelBase { get { - if (UseKeyFile) - { - if (string.IsNullOrWhiteSpace(KeyFilePath)) - return SecureStoreStrings.KeyFilePathRequired; + if (string.IsNullOrWhiteSpace(KeyFilePath)) + return SecureStoreStrings.KeyFilePathRequired; - if (!System.IO.File.Exists(KeyFilePath)) - return SecureStoreStrings.KeyFileNotFound; - } - - if (UsePassword && string.IsNullOrWhiteSpace(Password)) - return SecureStoreStrings.PasswordRequired; + if (!System.IO.File.Exists(KeyFilePath)) + return SecureStoreStrings.KeyFileNotFound; return null; } diff --git a/NEW/src/Utils/JdeScoping.ConfigManager/Views/Dialogs/NewStoreDialog.axaml b/NEW/src/Utils/JdeScoping.ConfigManager/Views/Dialogs/NewStoreDialog.axaml index 697676f..2f56e7c 100644 --- a/NEW/src/Utils/JdeScoping.ConfigManager/Views/Dialogs/NewStoreDialog.axaml +++ b/NEW/src/Utils/JdeScoping.ConfigManager/Views/Dialogs/NewStoreDialog.axaml @@ -4,8 +4,8 @@ x:Class="JdeScoping.ConfigManager.Views.Dialogs.NewStoreDialog" x:DataType="vm:NewStoreDialogViewModel" Title="Create New Secure Store" - Width="550" Height="480" - MinWidth="450" MinHeight="400" + Width="550" Height="350" + MinWidth="450" MinHeight="300" Background="#151920" WindowStartupLocation="CenterOwner" CanResize="False" @@ -56,28 +56,14 @@ - + - - - - - - - - - + - - - - - - - - - - - - - - + - - - - - - - - - + - - - - - - - - - - - - /// Creates a new store with either key file or password authentication. + /// Creates a new store with key file authentication. /// /// The path where the store will be created. - /// The path to the key file, or null for password-based authentication. - /// The password for authentication, or null for key file-based authentication. - public void CreateStore(string storePath, string? keyFilePath, string? password) + /// The path to the key file. + public void CreateStore(string storePath, string keyFilePath) { - _logger.LogInformation("Creating store at {StorePath}", storePath); + if (string.IsNullOrEmpty(keyFilePath)) + throw new ArgumentException("Key file path must be provided.", nameof(keyFilePath)); - if (!string.IsNullOrEmpty(keyFilePath)) - { - _storeManager.CreateStore(storePath, keyFilePath); - _logger.LogInformation("Store created with key file: {KeyFilePath}", keyFilePath); - } - else if (!string.IsNullOrEmpty(password)) - { - _storeManager.CreateStoreWithPassword(storePath, password); - _logger.LogInformation("Password-protected store created"); - } - else - { - throw new ArgumentException("Either key file path or password must be provided."); - } + _logger.LogInformation("Creating store at {StorePath}", storePath); + _storeManager.CreateStore(storePath, keyFilePath); + _logger.LogInformation("Store created with key file: {KeyFilePath}", keyFilePath); } /// - /// Opens an existing store with either key file or password authentication. + /// Opens an existing store with key file authentication. /// /// The path to the existing store. - /// The path to the key file, or null for password-based authentication. - /// The password for authentication, or null for key file-based authentication. - public void OpenStore(string storePath, string? keyFilePath, string? password) + /// The path to the key file. + public void OpenStore(string storePath, string keyFilePath) { - _logger.LogInformation("Opening store at {StorePath}", storePath); + if (string.IsNullOrEmpty(keyFilePath)) + throw new ArgumentException("Key file path must be provided.", nameof(keyFilePath)); - if (!string.IsNullOrEmpty(keyFilePath)) - { - _storeManager.OpenStore(storePath, keyFilePath); - _logger.LogDebug("Store opened with key file"); - } - else if (!string.IsNullOrEmpty(password)) - { - _storeManager.OpenStoreWithPassword(storePath, password); - _logger.LogDebug("Store opened with password"); - } - else - { - throw new ArgumentException("Either key file path or password must be provided."); - } + _logger.LogInformation("Opening store at {StorePath}", storePath); + _storeManager.OpenStore(storePath, keyFilePath); + _logger.LogDebug("Store opened with key file"); } /// diff --git a/NEW/src/Utils/JdeScoping.SecureStoreManager/Services/ISecureStoreManager.cs b/NEW/src/Utils/JdeScoping.SecureStoreManager/Services/ISecureStoreManager.cs index dd93693..d843914 100644 --- a/NEW/src/Utils/JdeScoping.SecureStoreManager/Services/ISecureStoreManager.cs +++ b/NEW/src/Utils/JdeScoping.SecureStoreManager/Services/ISecureStoreManager.cs @@ -27,13 +27,6 @@ public interface ISecureStoreManager /// Path for the key file (.key). void CreateStore(string storePath, string keyFilePath); - /// - /// Creates a new store secured with a password. - /// - /// Path for the new store file (.json). - /// Password to encrypt the store. - void CreateStoreWithPassword(string storePath, string password); - /// /// Opens an existing store using a key file. /// @@ -41,13 +34,6 @@ public interface ISecureStoreManager /// Path to the key file (.key). void OpenStore(string storePath, string keyFilePath); - /// - /// Opens an existing store using a password. - /// - /// Path to the store file (.json). - /// Password to decrypt the store. - void OpenStoreWithPassword(string storePath, string password); - /// /// Closes the currently open store without saving. /// diff --git a/NEW/src/Utils/JdeScoping.SecureStoreManager/Services/SecureStoreManager.cs b/NEW/src/Utils/JdeScoping.SecureStoreManager/Services/SecureStoreManager.cs index df26b26..7b8b25f 100644 --- a/NEW/src/Utils/JdeScoping.SecureStoreManager/Services/SecureStoreManager.cs +++ b/NEW/src/Utils/JdeScoping.SecureStoreManager/Services/SecureStoreManager.cs @@ -72,29 +72,6 @@ public class SecureStoreManager : ISecureStoreManager, IDisposable _logger.LogInformation("Store created with key file: {KeyFilePath}", keyFilePath); } - /// - public void CreateStoreWithPassword(string storePath, string password) - { - ThrowIfDisposed(); - _logger.LogInformation("Creating password-protected store at {StorePath}", storePath); - CloseStoreInternal(); - - if (string.IsNullOrEmpty(password)) - throw new ArgumentException("Password cannot be empty.", nameof(password)); - - EnsureDirectory(storePath); - - _secretsManager = SecretsManager.CreateStore(); - _secretsManager.LoadKeyFromPassword(password); - - _currentStorePath = storePath; - _keys.Clear(); - _hasUnsavedChanges = true; - - Save(); - _logger.LogInformation("Password-protected store created"); - } - /// public void OpenStore(string storePath, string keyFilePath) { @@ -117,28 +94,6 @@ public class SecureStoreManager : ISecureStoreManager, IDisposable _logger.LogDebug("Store opened with key file, contains {KeyCount} keys", _keys.Count); } - /// - public void OpenStoreWithPassword(string storePath, string password) - { - ThrowIfDisposed(); - _logger.LogInformation("Opening store at {StorePath} with password", storePath); - CloseStoreInternal(); - - if (!File.Exists(storePath)) - throw new FileNotFoundException("Store file not found.", storePath); - - if (string.IsNullOrEmpty(password)) - throw new ArgumentException("Password cannot be empty.", nameof(password)); - - _secretsManager = SecretsManager.LoadStore(storePath); - _secretsManager.LoadKeyFromPassword(password); - - _currentStorePath = storePath; - LoadKeysMetadata(); - _hasUnsavedChanges = false; - _logger.LogDebug("Store opened with password, contains {KeyCount} keys", _keys.Count); - } - /// public void CloseStore() { diff --git a/NEW/src/Utils/JdeScoping.SecureStoreManager/ViewModels/DialogViewModels.cs b/NEW/src/Utils/JdeScoping.SecureStoreManager/ViewModels/DialogViewModels.cs index 7b8695a..f5efd95 100644 --- a/NEW/src/Utils/JdeScoping.SecureStoreManager/ViewModels/DialogViewModels.cs +++ b/NEW/src/Utils/JdeScoping.SecureStoreManager/ViewModels/DialogViewModels.cs @@ -10,10 +10,6 @@ public class NewStoreDialogViewModel : ViewModelBase { private string _storePath = string.Empty; private string _keyFilePath = string.Empty; - private string _password = string.Empty; - private string _confirmPassword = string.Empty; - private bool _useKeyFile = true; - private bool _usePassword; /// /// Initializes a new instance of the class. @@ -50,64 +46,6 @@ public class NewStoreDialogViewModel : ViewModelBase } } - /// - /// Gets or sets the password for store encryption. - /// - public string Password - { - get => _password; - set - { - if (SetProperty(ref _password, value)) - NotifyValidationChanged(); - } - } - - /// - /// Gets or sets the password confirmation value. - /// - public string ConfirmPassword - { - get => _confirmPassword; - set - { - if (SetProperty(ref _confirmPassword, value)) - NotifyValidationChanged(); - } - } - - /// - /// Gets or sets whether to use key file for store encryption. - /// - public bool UseKeyFile - { - get => _useKeyFile; - set - { - if (SetProperty(ref _useKeyFile, value)) - { - if (value) UsePassword = false; - NotifyValidationChanged(); - } - } - } - - /// - /// Gets or sets whether to use password for store encryption. - /// - public bool UsePassword - { - get => _usePassword; - set - { - if (SetProperty(ref _usePassword, value)) - { - if (value) UseKeyFile = false; - NotifyValidationChanged(); - } - } - } - private void NotifyValidationChanged() { OnPropertyChanged(nameof(IsValid)); @@ -127,22 +65,7 @@ public class NewStoreDialogViewModel : ViewModelBase /// /// Gets a value indicating whether the dialog input is valid. /// - public bool IsValid - { - get - { - if (string.IsNullOrWhiteSpace(StorePath)) - return false; - - if (UseKeyFile) - return !string.IsNullOrWhiteSpace(KeyFilePath); - - if (UsePassword) - return !string.IsNullOrWhiteSpace(Password) && Password == ConfirmPassword; - - return false; - } - } + public bool IsValid => !string.IsNullOrWhiteSpace(StorePath) && !string.IsNullOrWhiteSpace(KeyFilePath); /// /// Gets the validation error message, or null if valid. @@ -154,18 +77,9 @@ public class NewStoreDialogViewModel : ViewModelBase if (string.IsNullOrWhiteSpace(StorePath)) return DialogStrings.StorePathRequired; - if (UseKeyFile && string.IsNullOrWhiteSpace(KeyFilePath)) + if (string.IsNullOrWhiteSpace(KeyFilePath)) return DialogStrings.KeyFilePathRequired; - if (UsePassword) - { - if (string.IsNullOrWhiteSpace(Password)) - return DialogStrings.PasswordRequired; - - if (Password != ConfirmPassword) - return DialogStrings.PasswordsDoNotMatch; - } - return null; } } @@ -217,9 +131,6 @@ public class OpenStoreDialogViewModel : ViewModelBase { private string _storePath = string.Empty; private string _keyFilePath = string.Empty; - private string _password = string.Empty; - private bool _useKeyFile = true; - private bool _usePassword; /// /// Initializes a new instance of the class. @@ -256,51 +167,6 @@ public class OpenStoreDialogViewModel : ViewModelBase } } - /// - /// Gets or sets the password for store decryption. - /// - public string Password - { - get => _password; - set - { - if (SetProperty(ref _password, value)) - NotifyValidationChanged(); - } - } - - /// - /// Gets or sets whether to use key file for store decryption. - /// - public bool UseKeyFile - { - get => _useKeyFile; - set - { - if (SetProperty(ref _useKeyFile, value)) - { - if (value) UsePassword = false; - NotifyValidationChanged(); - } - } - } - - /// - /// Gets or sets whether to use password for store decryption. - /// - public bool UsePassword - { - get => _usePassword; - set - { - if (SetProperty(ref _usePassword, value)) - { - if (value) UseKeyFile = false; - NotifyValidationChanged(); - } - } - } - private void NotifyValidationChanged() { OnPropertyChanged(nameof(IsValid)); @@ -327,13 +193,7 @@ public class OpenStoreDialogViewModel : ViewModelBase if (string.IsNullOrWhiteSpace(StorePath)) return false; - if (UseKeyFile) - return !string.IsNullOrWhiteSpace(KeyFilePath); - - if (UsePassword) - return !string.IsNullOrWhiteSpace(Password); - - return false; + return !string.IsNullOrWhiteSpace(KeyFilePath); } } @@ -350,17 +210,11 @@ public class OpenStoreDialogViewModel : ViewModelBase if (!System.IO.File.Exists(StorePath)) return DialogStrings.StoreFileNotFound; - if (UseKeyFile) - { - if (string.IsNullOrWhiteSpace(KeyFilePath)) - return DialogStrings.KeyFilePathRequired; + if (string.IsNullOrWhiteSpace(KeyFilePath)) + return DialogStrings.KeyFilePathRequired; - if (!System.IO.File.Exists(KeyFilePath)) - return DialogStrings.KeyFileNotFound; - } - - if (UsePassword && string.IsNullOrWhiteSpace(Password)) - return DialogStrings.PasswordRequired; + if (!System.IO.File.Exists(KeyFilePath)) + return DialogStrings.KeyFileNotFound; return null; } diff --git a/NEW/src/Utils/JdeScoping.SecureStoreManager/ViewModels/MainWindowViewModel.cs b/NEW/src/Utils/JdeScoping.SecureStoreManager/ViewModels/MainWindowViewModel.cs index 2d841fc..6e2c15e 100644 --- a/NEW/src/Utils/JdeScoping.SecureStoreManager/ViewModels/MainWindowViewModel.cs +++ b/NEW/src/Utils/JdeScoping.SecureStoreManager/ViewModels/MainWindowViewModel.cs @@ -161,30 +161,22 @@ public class MainWindowViewModel : ViewModelBase public ICommand ExportKeyCommand { get; } /// - /// Creates a new store. Called by the dialog. + /// Creates a new store with a key file. Called by the dialog. /// /// The path where the store file will be created. - /// Optional path to a key file for encryption. - /// Optional password for encryption. - public async Task CreateNewStoreAsync(string storePath, string? keyFilePath, string? password) + /// The path to a key file for encryption. + public async Task CreateNewStoreAsync(string storePath, string keyFilePath) { try { - if (!string.IsNullOrEmpty(keyFilePath)) + if (string.IsNullOrEmpty(keyFilePath)) { - _storeManager.CreateStore(storePath, keyFilePath); - StatusMessage = $"Created store with key file: {keyFilePath}"; - } - else if (!string.IsNullOrEmpty(password)) - { - _storeManager.CreateStoreWithPassword(storePath, password); - StatusMessage = "Created password-protected store"; - } - else - { - throw new ArgumentException("Either key file path or password must be provided."); + throw new ArgumentException("Key file path must be provided."); } + _storeManager.CreateStore(storePath, keyFilePath); + StatusMessage = $"Created store with key file: {keyFilePath}"; + RefreshSecrets(); NotifyStoreChanged(); } @@ -198,30 +190,22 @@ public class MainWindowViewModel : ViewModelBase } /// - /// Opens an existing store. Called by the dialog. + /// Opens an existing store with a key file. Called by the dialog. /// /// The path to the store file to open. - /// Optional path to a key file for decryption. - /// Optional password for decryption. - public async Task OpenExistingStoreAsync(string storePath, string? keyFilePath, string? password) + /// The path to a key file for decryption. + public async Task OpenExistingStoreAsync(string storePath, string keyFilePath) { try { - if (!string.IsNullOrEmpty(keyFilePath)) + if (string.IsNullOrEmpty(keyFilePath)) { - _storeManager.OpenStore(storePath, keyFilePath); - StatusMessage = "Opened store with key file"; - } - else if (!string.IsNullOrEmpty(password)) - { - _storeManager.OpenStoreWithPassword(storePath, password); - StatusMessage = "Opened password-protected store"; - } - else - { - throw new ArgumentException("Either key file path or password must be provided."); + throw new ArgumentException("Key file path must be provided."); } + _storeManager.OpenStore(storePath, keyFilePath); + StatusMessage = "Opened store with key file"; + RefreshSecrets(); NotifyStoreChanged(); } diff --git a/NEW/src/Utils/JdeScoping.SecureStoreManager/Views/MainWindow.axaml.cs b/NEW/src/Utils/JdeScoping.SecureStoreManager/Views/MainWindow.axaml.cs index a7a1e78..9ff6f4a 100644 --- a/NEW/src/Utils/JdeScoping.SecureStoreManager/Views/MainWindow.axaml.cs +++ b/NEW/src/Utils/JdeScoping.SecureStoreManager/Views/MainWindow.axaml.cs @@ -61,10 +61,7 @@ public partial class MainWindow : Window if (result == true) { var vm = dialog.ViewModel; - await ViewModel.CreateNewStoreAsync( - vm.StorePath, - vm.UseKeyFile ? vm.KeyFilePath : null, - vm.UsePassword ? vm.Password : null); + await ViewModel.CreateNewStoreAsync(vm.StorePath, vm.KeyFilePath); } } @@ -77,10 +74,7 @@ public partial class MainWindow : Window if (result == true) { var vm = dialog.ViewModel; - await ViewModel.OpenExistingStoreAsync( - vm.StorePath, - vm.UseKeyFile ? vm.KeyFilePath : null, - vm.UsePassword ? vm.Password : null); + await ViewModel.OpenExistingStoreAsync(vm.StorePath, vm.KeyFilePath); } } diff --git a/NEW/src/Utils/JdeScoping.SecureStoreManager/Views/NewStoreDialog.axaml b/NEW/src/Utils/JdeScoping.SecureStoreManager/Views/NewStoreDialog.axaml index b175c70..dc61f4a 100644 --- a/NEW/src/Utils/JdeScoping.SecureStoreManager/Views/NewStoreDialog.axaml +++ b/NEW/src/Utils/JdeScoping.SecureStoreManager/Views/NewStoreDialog.axaml @@ -3,13 +3,13 @@ xmlns:vm="clr-namespace:JdeScoping.SecureStoreManager.ViewModels" x:Class="JdeScoping.SecureStoreManager.Views.NewStoreDialog" Title="Create New Store" - Height="400" Width="500" + Height="280" Width="500" WindowStartupLocation="CenterOwner" CanResize="False" ShowInTaskbar="False"> - + @@ -26,25 +26,13 @@ - - - - - - - - - - + + - - - - - - - - - - - - - - - +