Implement PIN settings properly.
MODIFY
WalletWasabi.Gui/Tabs/SettingsView.xaml
WalletWasabi.Gui/Tabs/SettingsView.xaml
</controls:GroupBox>
<controls:GroupBox Title="Screen Lock" TextBlock.FontSize="16" Padding="10" Margin="0 5 10 5">
<StackPanel Orientation="Vertical" Spacing="5">
- <StackPanel Margin="0 10" Orientation="Horizontal" Spacing="5">
- <ToggleButton IsChecked="{Binding EnablePinEntry}" Content="{Binding EnablePinEntry, Converter={StaticResource BooleanStringConverter}, ConverterParameter=On:Off}" Margin="0 0 10 0" Command="{Binding EnablePinLockCommand}" />
- <TextBlock VerticalAlignment="Center">Use PIN to unlock the screen.</TextBlock>
- </StackPanel>
- <StackPanel Orientation="Vertical" Spacing="5">
- <controls:NoparaPasswordBox Watermark="PIN" Password="{Binding OldPinPwdBox}" UseFloatingWatermark="True" />
- <TextBlock Text="{Binding ConfirmPinWarningMessage}" Classes="warningMessage" Margin="0 0 3 0" />
+ <StackPanel Margin="0 10" Orientation="Vertical" Spacing="5">
+ <TextBlock Margin="0 10" VerticalAlignment="Center">Note that, if you forget your PIN, you can clear it by manually deleting the hashed PIN from your UI config file.</TextBlock>
+ <DockPanel LastChildFill="True">
+ <Button DockPanel.Dock="Left" Content="{Binding IsPinSet, Converter={StaticResource BooleanStringConverter}, ConverterParameter=Clear:Set}" Margin="0 0 10 0" Command="{Binding SetClearPinCommand}" />
+ <controls:NoparaPasswordBox Watermark="PIN" Password="{Binding PinBoxText}" UseFloatingWatermark="True" />
+ </DockPanel>
+ <TextBlock Text="{Binding PinWarningMessage}" Classes="warningMessage" Margin="0 0 3 0" />
</StackPanel>
</StackPanel>
</controls:GroupBox>

MODIFY
WalletWasabi.Gui/Tabs/SettingsViewModel.cs
WalletWasabi.Gui/Tabs/SettingsViewModel.cs
@@ -5,6 +5,7 @@ using ReactiveUI;
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reactive;
@@ -27,20 +28,21 @@ namespace WalletWasabi.Gui.Tabs
private bool _autocopy;
private bool _useTor;
private bool _isModified;
- private bool _enablePinLock;
private string _somePrivacyLevel;
private string _finePrivacyLevel;
private string _strongPrivacyLevel;
private string _dustThreshold;
- private string _oldPinPwdBox;
- private string _confirmPinWarningMessage;
+ private string _pinBoxText;
+ private string _pinWarningMessage;
- private Regex PinNumOnlyRegex { get; } = new Regex("^[0-9]+$");
+ private ObservableAsPropertyHelper<bool> _isPinSet;
+
+ public bool IsPinSet => _isPinSet?.Value ?? false;
private AsyncLock ConfigLock { get; } = new AsyncLock();
public ReactiveCommand<Unit, Unit> OpenConfigFileCommand { get; }
public ReactiveCommand<Unit, Unit> LurkingWifeModeCommand { get; }
- public ReactiveCommand<Unit, Unit> EnablePinLockCommand { get; }
+ public ReactiveCommand<Unit, Unit> SetClearPinCommand { get; }
public ReactiveCommand<Unit, Unit> TextBoxLostFocusCommand { get; }
public SettingsViewModel(Global global) : base(global, "Settings")
@@ -91,8 +93,6 @@ namespace WalletWasabi.Gui.Tabs
DustThreshold = config.DustThreshold.ToString();
IsModified = await Global.Config.CheckFileChangeAsync();
-
- EnablePinEntry = Global.UiConfig.LockScreenPinHash != string.Empty;
});
OpenConfigFileCommand = ReactiveCommand.Create(OpenConfigFile);
@@ -103,37 +103,48 @@ namespace WalletWasabi.Gui.Tabs
await Global.UiConfig.ToFileAsync();
});
- EnablePinLockCommand = ReactiveCommand.CreateFromTask(async () =>
+ SetClearPinCommand = ReactiveCommand.Create(() =>
{
- if (_oldPinPwdBox == string.Empty)
+ var pinBoxText = PinBoxText?.Trim();
+ if (string.IsNullOrWhiteSpace(pinBoxText))
{
- ConfirmPinWarningMessage = "Both PIN entries must be filled out.";
- EnablePinEntry = !EnablePinEntry;
+ PinWarningMessage = "Please provide PIN.";
return;
}
- var uiConfigPinHash = Global.UiConfig.LockScreenPinHash;
- var enteredPinHash = HashHelpers.GenerateSha256Hash(_oldPinPwdBox);
+ if (pinBoxText.Length > 10)
+ {
+ PinWarningMessage = "PIN too long.";
+ return;
+ }
- if (EnablePinEntry)
+ if (pinBoxText.Any(x => !char.IsDigit(x)))
{
- Global.UiConfig.LockScreenPinHash = enteredPinHash;
- await Global.UiConfig.ToFileAsync();
+ PinWarningMessage = "Invalid PIN.";
+ return;
}
- else
+
+ var uiConfigPinHash = Global.UiConfig.LockScreenPinHash;
+ var enteredPinHash = HashHelpers.GenerateSha256Hash(pinBoxText);
+
+ if (IsPinSet)
{
if (uiConfigPinHash != enteredPinHash)
{
- ConfirmPinWarningMessage = "Wrong PIN.";
- EnablePinEntry = true;
+ PinWarningMessage = "Wrong PIN.";
+ PinBoxText = string.Empty;
return;
}
+
Global.UiConfig.LockScreenPinHash = string.Empty;
- await Global.UiConfig.ToFileAsync();
+ }
+ else
+ {
+ Global.UiConfig.LockScreenPinHash = enteredPinHash;
}
- OldPinPwdBox = string.Empty;
- ConfirmPinWarningMessage = string.Empty;
+ PinBoxText = string.Empty;
+ PinWarningMessage = string.Empty;
});
TextBoxLostFocusCommand = ReactiveCommand.Create(Save);
@@ -153,6 +164,15 @@ namespace WalletWasabi.Gui.Tabs
this.RaisePropertyChanged(nameof(LurkingWifeMode));
}).DisposeWith(Disposables);
+ _isPinSet = Global.UiConfig.WhenAnyValue(x => x.LockScreenPinHash, x => !string.IsNullOrWhiteSpace(x))
+ .ToProperty(this, x => x.IsPinSet, scheduler: RxApp.MainThreadScheduler)
+ .DisposeWith(Disposables);
+
+ Global.UiConfig.WhenAnyValue(x => x.LockScreenPinHash)
+ .ObserveOn(RxApp.TaskpoolScheduler)
+ .Subscribe(async x => await Global.UiConfig.ToFileAsync())
+ .DisposeWith(Disposables);
+
base.OnOpen();
}
@@ -239,22 +259,16 @@ namespace WalletWasabi.Gui.Tabs
public bool LurkingWifeMode => Global.UiConfig.LurkingWifeMode is true;
- public bool EnablePinEntry
- {
- get => _enablePinLock;
- set => this.RaiseAndSetIfChanged(ref _enablePinLock, value);
- }
-
- public string OldPinPwdBox
+ public string PinBoxText
{
- get => _oldPinPwdBox;
- set => this.RaiseAndSetIfChanged(ref _oldPinPwdBox, value);
+ get => _pinBoxText;
+ set => this.RaiseAndSetIfChanged(ref _pinBoxText, value);
}
- public string ConfirmPinWarningMessage
+ public string PinWarningMessage
{
- get => _confirmPinWarningMessage;
- set => this.RaiseAndSetIfChanged(ref _confirmPinWarningMessage, value);
+ get => _pinWarningMessage;
+ set => this.RaiseAndSetIfChanged(ref _pinWarningMessage, value);
}
private void Save()

Implement PIN settings properly.