diff --git a/.gitignore b/.gitignore index f7eb152..2ac8ff8 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,8 @@ MongoDB/ .gitea-token master.key openrouter.key +# #567: Hash des Einstellungs-Passworts (PBKDF2) - gehoert zur Installation, nicht ins Repository +settings-password.json # Packager-Zugangsdaten (FTP, updateservice:publish-Token) – Vorlage in deploy/packager.config.example.json deploy/packager.config.json diff --git a/src/PolyTrader.App.Avalonia/Controls/SettingsEditor.axaml.cs b/src/PolyTrader.App.Avalonia/Controls/SettingsEditor.axaml.cs index 5dd24d9..92d8f68 100644 --- a/src/PolyTrader.App.Avalonia/Controls/SettingsEditor.axaml.cs +++ b/src/PolyTrader.App.Avalonia/Controls/SettingsEditor.axaml.cs @@ -17,10 +17,11 @@ namespace PolyTrader.App.Avalonia.Controls public SettingsEditor() => AvaloniaXamlLoader.Load(this); /// Setzt das anzuzeigende Objekt (oder null, um zu leeren). - public void Show(object? target) + /// false blendet Geheimnisfelder aus (#567). + public void Show(object? target, bool includeSensitive = true) { var list = this.FindControl("sections")!; - list.ItemsSource = target == null ? null : SettingsModelBuilder.Build(target); + list.ItemsSource = target == null ? null : SettingsModelBuilder.Build(target, includeSensitive); } } } diff --git a/src/PolyTrader.App.Avalonia/Program.cs b/src/PolyTrader.App.Avalonia/Program.cs index 1318629..90cbf1f 100644 --- a/src/PolyTrader.App.Avalonia/Program.cs +++ b/src/PolyTrader.App.Avalonia/Program.cs @@ -293,6 +293,14 @@ namespace PolyTrader.App.Avalonia // Einstellungsdatei zur Laufzeit fortzuschreiben - gemeinsam fuer Desktop und WebUI. services.AddSingleton(new KnownModules(allModules)); services.AddSingleton(new ServerSettingsFile(ServerSettingsPath)); + + // #567: Passwortschutz fuer Konten, Geheimnisse und WebUI-Zugang in der Desktop-Oberflaeche. + // Eigene Datei neben master.key - nicht in server_settings.xml, die das WebUI mitschreibt. + services.AddSingleton(sp => new SettingsLock( + new SettingsPasswordStore( + Path.Combine(AppContext.BaseDirectory, "settings-password.json"), + onWarning: m => sp.GetRequiredService().Warning(m)), + log: m => sp.GetRequiredService().Info(m))); services.AddSingleton(logger); services.AddSingleton(); services.AddSingleton(); diff --git a/src/PolyTrader.App.Avalonia/Shell/CoreViews.cs b/src/PolyTrader.App.Avalonia/Shell/CoreViews.cs index c650fc3..2fbc3d0 100644 --- a/src/PolyTrader.App.Avalonia/Shell/CoreViews.cs +++ b/src/PolyTrader.App.Avalonia/Shell/CoreViews.cs @@ -64,7 +64,8 @@ namespace PolyTrader.App.Avalonia.Shell services.GetService(), services.GetService(), services.GetService(), - services.GetService()) + services.GetService(), + services.GetRequiredService()) }); host.RegisterView(new ModuleView diff --git a/src/PolyTrader.App.Avalonia/ViewModels/SettingsFields.cs b/src/PolyTrader.App.Avalonia/ViewModels/SettingsFields.cs index 9046c13..ff610df 100644 --- a/src/PolyTrader.App.Avalonia/ViewModels/SettingsFields.cs +++ b/src/PolyTrader.App.Avalonia/ViewModels/SettingsFields.cs @@ -244,12 +244,17 @@ namespace PolyTrader.App.Avalonia.ViewModels /// public static class SettingsModelBuilder { - public static IReadOnlyList Build(object target) + /// + /// false blendet Felder mit aus – + /// solange die geschützten Einstellungen gesperrt sind (#567). + /// + public static IReadOnlyList Build(object target, bool includeSensitive = true) { var fields = target.GetType() .GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.GetIndexParameters().Length == 0) .Where(p => p.GetCustomAttribute()?.Browsable != false) + .Where(p => includeSensitive || p.GetCustomAttribute() == null) .Select(p => new { Property = p, diff --git a/src/PolyTrader.App.Avalonia/Views/PasswordDialog.axaml b/src/PolyTrader.App.Avalonia/Views/PasswordDialog.axaml new file mode 100644 index 0000000..bc317cc --- /dev/null +++ b/src/PolyTrader.App.Avalonia/Views/PasswordDialog.axaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + +