Added option to not store the password

This commit is contained in:
Mark van Renswoude 2021-12-18 18:40:22 +01:00
parent 4c6089a991
commit 4b730b2a1a
9 changed files with 128 additions and 55 deletions

View File

@ -6,12 +6,12 @@ namespace PettingZoo.Core.Settings
{
public interface IConnectionSettingsRepository
{
Task<ConnectionSettings> GetLastUsed();
Task StoreLastUsed(ConnectionSettings connectionSettings);
Task<StoredConnectionSettings> GetLastUsed();
Task StoreLastUsed(bool storePassword, ConnectionSettings connectionSettings);
Task<IEnumerable<StoredConnectionSettings>> GetStored();
Task<StoredConnectionSettings> Add(string displayName, ConnectionSettings connectionSettings);
Task<StoredConnectionSettings> Update(Guid id, string displayName, ConnectionSettings connectionSettings);
Task<StoredConnectionSettings> Add(string displayName, bool storePassword, ConnectionSettings connectionSettings);
Task<StoredConnectionSettings> Update(Guid id, string displayName, bool storePassword, ConnectionSettings connectionSettings);
Task Delete(Guid id);
}
@ -22,7 +22,7 @@ namespace PettingZoo.Core.Settings
public string VirtualHost { get; }
public int Port { get; }
public string Username { get; }
public string? Password { get; }
public string Password { get; }
public bool Subscribe { get; }
public string Exchange { get; }
@ -32,7 +32,7 @@ namespace PettingZoo.Core.Settings
public static readonly ConnectionSettings Default = new("localhost", "/", 5672, "guest", "guest", false, "", "#");
public ConnectionSettings(string host, string virtualHost, int port, string username, string? password,
public ConnectionSettings(string host, string virtualHost, int port, string username, string password,
bool subscribe, string exchange, string routingKey)
{
Host = host;
@ -65,22 +65,26 @@ namespace PettingZoo.Core.Settings
{
public Guid Id { get; }
public string DisplayName { get; }
public bool StorePassword { get; }
public StoredConnectionSettings(Guid id, string displayName, string host, string virtualHost, int port, string username,
string? password, bool subscribe, string exchange, string routingKey)
public StoredConnectionSettings(Guid id, string displayName, bool storePassword, string host, string virtualHost, int port, string username,
string password, bool subscribe, string exchange, string routingKey)
: base(host, virtualHost, port, username, password, subscribe, exchange, routingKey)
{
Id = id;
DisplayName = displayName;
StorePassword = storePassword;
}
public StoredConnectionSettings(Guid id, string displayName, ConnectionSettings connectionSettings)
: base(connectionSettings.Host, connectionSettings.VirtualHost, connectionSettings.Port, connectionSettings.Username, connectionSettings.Password,
connectionSettings.Subscribe, connectionSettings.Exchange, connectionSettings.RoutingKey)
public StoredConnectionSettings(Guid id, string displayName, bool storePassword, ConnectionSettings connectionSettings)
: base(connectionSettings.Host, connectionSettings.VirtualHost, connectionSettings.Port, connectionSettings.Username,
connectionSettings.Password, connectionSettings.Subscribe, connectionSettings.Exchange, connectionSettings.RoutingKey)
{
Id = id;
DisplayName = displayName;
StorePassword = storePassword;
}
}
}

View File

@ -24,7 +24,10 @@ namespace PettingZoo.Settings.LiteDB
protected ILiteDatabaseAsync GetDatabase()
{
return new LiteDatabaseAsync(databaseFilename);
return new LiteDatabaseAsync(databaseFilename, new BsonMapper
{
EmptyStringToNull = false
});
}
}
}

View File

@ -15,33 +15,36 @@ namespace PettingZoo.Settings.LiteDB
}
public async Task<ConnectionSettings> GetLastUsed()
public async Task<StoredConnectionSettings> GetLastUsed()
{
using var database = GetDatabase();
var collection = database.GetCollection<ConnectionSettingsRecord>(CollectionLastUsed);
var lastUsed = await collection.FindOneAsync(r => true);
if (lastUsed == null)
return ConnectionSettings.Default;
return new StoredConnectionSettings(Guid.Empty, "", false, ConnectionSettings.Default);
return new ConnectionSettings(
return new StoredConnectionSettings(
Guid.Empty,
"",
lastUsed.Password != null,
lastUsed.Host,
lastUsed.VirtualHost,
lastUsed.Port,
lastUsed.Username,
lastUsed.Password,
lastUsed.Password ?? "",
lastUsed.Subscribe,
lastUsed.Exchange,
lastUsed.RoutingKey);
}
public async Task StoreLastUsed(ConnectionSettings connectionSettings)
public async Task StoreLastUsed(bool storePassword, ConnectionSettings connectionSettings)
{
using var database = GetDatabase();
var collection = database.GetCollection<ConnectionSettingsRecord>(CollectionLastUsed);
await collection.UpsertAsync(ConnectionSettingsRecord.FromConnectionSettings(LastUsedId, connectionSettings, ""));
await collection.UpsertAsync(ConnectionSettingsRecord.FromConnectionSettings(LastUsedId, connectionSettings, "", storePassword));
}
@ -51,30 +54,30 @@ namespace PettingZoo.Settings.LiteDB
var collection = database.GetCollection<ConnectionSettingsRecord>(CollectionStored);
return (await collection.FindAllAsync())
.Select(r => new StoredConnectionSettings(r.Id, r.DisplayName, r.Host, r.VirtualHost, r.Port, r.Username, r.Password, r.Subscribe, r.Exchange, r.RoutingKey))
.Select(r => new StoredConnectionSettings(r.Id, r.DisplayName, r.Password != null, r.Host, r.VirtualHost, r.Port, r.Username, r.Password ?? "", r.Subscribe, r.Exchange, r.RoutingKey))
.ToArray();
}
public async Task<StoredConnectionSettings> Add(string displayName, ConnectionSettings connectionSettings)
public async Task<StoredConnectionSettings> Add(string displayName, bool storePassword, ConnectionSettings connectionSettings)
{
using var database = GetDatabase();
var collection = database.GetCollection<ConnectionSettingsRecord>(CollectionStored);
var id = Guid.NewGuid();
await collection.InsertAsync(ConnectionSettingsRecord.FromConnectionSettings(id, connectionSettings, displayName));
await collection.InsertAsync(ConnectionSettingsRecord.FromConnectionSettings(id, connectionSettings, displayName, storePassword));
return new StoredConnectionSettings(id, displayName, connectionSettings);
return new StoredConnectionSettings(id, displayName, storePassword, connectionSettings);
}
public async Task<StoredConnectionSettings> Update(Guid id, string displayName, ConnectionSettings connectionSettings)
public async Task<StoredConnectionSettings> Update(Guid id, string displayName, bool storePassword, ConnectionSettings connectionSettings)
{
using var database = GetDatabase();
var collection = database.GetCollection<ConnectionSettingsRecord>(CollectionStored);
await collection.UpdateAsync(ConnectionSettingsRecord.FromConnectionSettings(id, connectionSettings, displayName));
return new StoredConnectionSettings(id, displayName, connectionSettings);
await collection.UpdateAsync(ConnectionSettingsRecord.FromConnectionSettings(id, connectionSettings, displayName, storePassword));
return new StoredConnectionSettings(id, displayName, storePassword, connectionSettings);
}
@ -105,7 +108,7 @@ namespace PettingZoo.Settings.LiteDB
public string RoutingKey { get; set; } = null!;
public static ConnectionSettingsRecord FromConnectionSettings(Guid id, ConnectionSettings connectionSettings, string displayName)
public static ConnectionSettingsRecord FromConnectionSettings(Guid id, ConnectionSettings connectionSettings, string displayName, bool storePassword)
{
return new ConnectionSettingsRecord
{
@ -116,7 +119,7 @@ namespace PettingZoo.Settings.LiteDB
VirtualHost = connectionSettings.VirtualHost,
Port = connectionSettings.Port,
Username = connectionSettings.Username,
Password = connectionSettings.Password,
Password = storePassword ? connectionSettings.Password : null,
Subscribe = connectionSettings.Subscribe,
Exchange = connectionSettings.Exchange,

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
@ -6,6 +7,8 @@ namespace PettingZoo.UI
{
public class BaseViewModel : INotifyPropertyChanged
{
private int commandsChangedDisabled;
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void RaisePropertyChanged([CallerMemberName] string? propertyName = null)
@ -30,6 +33,7 @@ namespace PettingZoo.UI
RaisePropertyChanged(otherProperty);
}
// ReSharper disable once InvertIf
if (delegateCommandsChanged != null)
{
foreach (var delegateCommand in delegateCommandsChanged)
@ -38,5 +42,24 @@ namespace PettingZoo.UI
return true;
}
protected void DisableCommandsChanged(Action updateFields, params DelegateCommand[] delegateCommandsChangedAfter)
{
commandsChangedDisabled++;
try
{
updateFields();
}
finally
{
commandsChangedDisabled--;
if (commandsChangedDisabled == 0)
{
foreach (var delegateCommand in delegateCommandsChangedAfter)
delegateCommand.RaiseCanExecuteChanged();
}
}
}
}
}

View File

@ -5,14 +5,12 @@ using System.Windows;
using System.Windows.Input;
using PettingZoo.Core.Settings;
// TODO "save password" checkbox
namespace PettingZoo.UI.Connection
{
public class ConnectionViewModel : BaseViewModel
{
private readonly IConnectionSettingsRepository connectionSettingsRepository;
private readonly ConnectionSettings defaultSettings;
private readonly StoredConnectionSettings defaultSettings;
private string host = null!;
private string virtualHost = null!;
private int port;
@ -23,6 +21,8 @@ namespace PettingZoo.UI.Connection
private string exchange = null!;
private string routingKey = null!;
private bool storePassword;
private StoredConnectionSettings? selectedStoredConnection;
private readonly DelegateCommand okCommand;
@ -60,7 +60,7 @@ namespace PettingZoo.UI.Connection
public string Password
{
get => password;
set => SetField(ref password, value);
set => SetField(ref password, value, delegateCommandsChanged: connectionChangedCommands);
}
@ -91,6 +91,13 @@ namespace PettingZoo.UI.Connection
}
public bool StorePassword
{
get => storePassword;
set => SetField(ref storePassword, value, delegateCommandsChanged: connectionChangedCommands);
}
public ObservableCollection<StoredConnectionSettings> StoredConnections { get; } = new();
public StoredConnectionSettings? SelectedStoredConnection
@ -104,15 +111,21 @@ namespace PettingZoo.UI.Connection
if (!SetField(ref selectedStoredConnection, value, delegateCommandsChanged: new [] { deleteCommand }))
return;
Host = value.Host;
VirtualHost = value.VirtualHost;
Port = value.Port;
Username = value.Username;
Password = value.Password ?? "";
DisableCommandsChanged(
() =>
{
Host = value.Host;
VirtualHost = value.VirtualHost;
Port = value.Port;
Username = value.Username;
Password = value.Password;
StorePassword = value.StorePassword;
Exchange = value.Exchange;
RoutingKey = value.RoutingKey;
Subscribe = value.Subscribe;
Exchange = value.Exchange;
RoutingKey = value.RoutingKey;
Subscribe = value.Subscribe;
},
connectionChangedCommands);
}
}
@ -125,7 +138,7 @@ namespace PettingZoo.UI.Connection
public event EventHandler? OkClick;
public ConnectionViewModel(IConnectionSettingsRepository connectionSettingsRepository, ConnectionSettings defaultSettings)
public ConnectionViewModel(IConnectionSettingsRepository connectionSettingsRepository, StoredConnectionSettings defaultSettings)
{
this.connectionSettingsRepository = connectionSettingsRepository;
this.defaultSettings = defaultSettings;
@ -144,6 +157,7 @@ namespace PettingZoo.UI.Connection
var defaultConnection = new StoredConnectionSettings(
Guid.Empty,
ConnectionWindowStrings.LastUsedDisplayName,
defaultSettings.StorePassword,
defaultSettings.Host,
defaultSettings.VirtualHost,
defaultSettings.Port,
@ -157,7 +171,7 @@ namespace PettingZoo.UI.Connection
foreach (var storedConnectionSettings in await connectionSettingsRepository.GetStored())
{
if (!isStored && storedConnectionSettings.SameParameters(defaultConnection))
if (!isStored && storedConnectionSettings.SameParameters(defaultConnection, false))
{
SelectedStoredConnection = storedConnectionSettings;
isStored = true;
@ -169,7 +183,7 @@ namespace PettingZoo.UI.Connection
if (isStored)
{
// The last used parameters match a stored connection, insert the "New connection" item with default parameters
StoredConnections.Insert(0, new StoredConnectionSettings(Guid.Empty, ConnectionWindowStrings.LastUsedDisplayName, ConnectionSettings.Default));
StoredConnections.Insert(0, new StoredConnectionSettings(Guid.Empty, ConnectionWindowStrings.LastUsedDisplayName, true, ConnectionSettings.Default));
}
else
{
@ -225,7 +239,7 @@ namespace PettingZoo.UI.Connection
var selectedIndex = StoredConnections.IndexOf(SelectedStoredConnection);
var updatedStoredConnection = await connectionSettingsRepository.Update(SelectedStoredConnection.Id, SelectedStoredConnection.DisplayName, ToModel());
var updatedStoredConnection = await connectionSettingsRepository.Update(SelectedStoredConnection.Id, SelectedStoredConnection.DisplayName, StorePassword, ToModel());
StoredConnections[selectedIndex] = updatedStoredConnection;
@ -238,7 +252,10 @@ namespace PettingZoo.UI.Connection
return SelectedStoredConnection != null &&
SelectedStoredConnection.Id != Guid.Empty &&
ValidConnection(false) &&
!ToModel().SameParameters(SelectedStoredConnection, false);
(
!ToModel().SameParameters(SelectedStoredConnection, StorePassword) ||
SelectedStoredConnection.StorePassword != StorePassword
);
}
@ -250,7 +267,7 @@ namespace PettingZoo.UI.Connection
if (!ConnectionDisplayNameDialog.Execute(ref displayName))
return;
var storedConnectionSettings = await connectionSettingsRepository.Add(displayName, ToModel());
var storedConnectionSettings = await connectionSettingsRepository.Add(displayName, StorePassword, ToModel());
StoredConnections.Add(storedConnectionSettings);
SelectedStoredConnection = storedConnectionSettings;
@ -298,7 +315,7 @@ namespace PettingZoo.UI.Connection
{
public DesignTimeConnectionViewModel() : base(null!, null!)
{
StoredConnections.Add(new StoredConnectionSettings(Guid.Empty, "Dummy", ConnectionSettings.Default));
StoredConnections.Add(new StoredConnectionSettings(Guid.Empty, "Dummy", true, ConnectionSettings.Default));
}
}
}

View File

@ -42,9 +42,18 @@
</UniformGrid>
<ListBox Grid.Row="0" Grid.Column="0" Margin="0 0 8 0" Width="250" ItemsSource="{Binding StoredConnections}" SelectedValue="{Binding SelectedStoredConnection}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
<TextBlock Text="{Binding DisplayName}">
<TextBlock.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding DataContext.OkCommand, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" />
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
@ -60,7 +69,8 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="8"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="24"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
@ -79,14 +89,15 @@
<Label Grid.Column="0" Grid.Row="4" Content="{x:Static connection:ConnectionWindowStrings.LabelPassword}"/>
<PasswordBox Grid.Column="1" Grid.Row="4" ui:PasswordBoxAssistant.BindPassword="true" ui:PasswordBoxAssistant.BoundPassword="{Binding Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" GotFocus="CaretToEnd"/>
<CheckBox Grid.Column="1" Grid.Row="5" Content="{x:Static connection:ConnectionWindowStrings.LabelStorePassword}" IsChecked="{Binding StorePassword}"/>
<CheckBox Grid.Column="1" Grid.Row="6" Content="{x:Static connection:ConnectionWindowStrings.LabelSubscribe}" IsChecked="{Binding Subscribe}"/>
<CheckBox Grid.Column="1" Grid.Row="7" Content="{x:Static connection:ConnectionWindowStrings.LabelSubscribe}" IsChecked="{Binding Subscribe}"/>
<Label Grid.Column="0" Grid.Row="7" Content="{x:Static connection:ConnectionWindowStrings.LabelExchange}"/>
<TextBox Grid.Column="1" Grid.Row="7" Text="{Binding Exchange, UpdateSourceTrigger=PropertyChanged}" GotFocus="CaretToEnd"/>
<Label Grid.Column="0" Grid.Row="8" Content="{x:Static connection:ConnectionWindowStrings.LabelExchange}"/>
<TextBox Grid.Column="1" Grid.Row="8" Text="{Binding Exchange, UpdateSourceTrigger=PropertyChanged}" GotFocus="CaretToEnd"/>
<Label Grid.Column="0" Grid.Row="8" Content="{x:Static connection:ConnectionWindowStrings.LabelRoutingKey}"/>
<TextBox Grid.Column="1" Grid.Row="8" Text="{Binding RoutingKey, UpdateSourceTrigger=PropertyChanged}" GotFocus="CaretToEnd"/>
<Label Grid.Column="0" Grid.Row="9" Content="{x:Static connection:ConnectionWindowStrings.LabelRoutingKey}"/>
<TextBox Grid.Column="1" Grid.Row="9" Text="{Binding RoutingKey, UpdateSourceTrigger=PropertyChanged}" GotFocus="CaretToEnd"/>
</ui:GridLayout>
</Grid>
</Window>

View File

@ -38,7 +38,7 @@ namespace PettingZoo.UI.Connection
return null;
var newSettings = viewModel.ToModel();
await connectionSettingsRepository.StoreLastUsed(newSettings);
await connectionSettingsRepository.StoreLastUsed(viewModel.StorePassword, newSettings);
return newSettings;
}

View File

@ -168,6 +168,15 @@ namespace PettingZoo.UI.Connection {
}
}
/// <summary>
/// Looks up a localized string similar to Store password.
/// </summary>
public static string LabelStorePassword {
get {
return ResourceManager.GetString("LabelStorePassword", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Subscribe.
/// </summary>

View File

@ -153,6 +153,9 @@
<data name="LabelRoutingKey" xml:space="preserve">
<value>Routing key</value>
</data>
<data name="LabelStorePassword" xml:space="preserve">
<value>Store password</value>
</data>
<data name="LabelSubscribe" xml:space="preserve">
<value>Subscribe</value>
</data>