123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556 |
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Linq;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Automation.Peers;
- using System.Windows.Automation.Provider;
- using System.Windows.Controls;
- using System.Windows.Input;
- using Comal.Classes;
- using InABox.Clients;
- using InABox.Configuration;
- using InABox.Core;
- using InABox.Wpf;
- using InABox.WPF;
- using PRSDesktop.Forms;
- namespace PRSDesktop;
- /// <summary>
- /// Interaction logic for PinLogin.xaml
- /// </summary>
- public partial class PinLogin : ThemableWindow
- {
- private bool _isloggedin = false;
- private enum Page
- {
- PIN,
- PASSWORD,
- _2FA
- }
- private bool PINPage;
- private Page CurrentPage;
- private bool Checking = false;
- private List<TextBox> codeInputs = new();
- public PinLogin(string version, ValidationStatus status)
- {
- InitializeComponent();
- Title = $"{(String.Equals(App.Profile?.ToUpper(), "DEFAULT") ? "PRS Desktop" : App.Profile)} (Release {CoreUtils.GetVersion()})";
- foreach (var codeInput in CodeInput.Children)
- {
- var tb = codeInput as TextBox;
- tb.PreviewKeyDown += Code2FA_PreviewKeyDown;
- tb.PreviewTextInput += Code2FA_Preview;
- tb.TextChanged += Code2FA_TextChanged;
- codeInputs.Add(tb);
- }
- UserID.Text = App.DatabaseSettings.UserID;
- Password.Password = App.DatabaseSettings.Password;
- if (status == ValidationStatus.PASSWORD_EXPIRED)
- {
- status = TryValidation("", status);
- }
- PINPage = App.DatabaseSettings.LoginType == LoginType.PIN;
- if (status == ValidationStatus.REQUIRE_2FA)
- Show2FAPage();
- else if (PINPage)
- ShowPINPage();
- else
- ShowPasswordPage();
- //AutoLogin.IsChecked = _settings.Autologin;
- }
- private void ShowPINPage()
- {
- CurrentPage = Page.PIN;
- OverallLayout.ColumnDefinitions[0].Width = new GridLength(1, GridUnitType.Star);
- OverallLayout.ColumnDefinitions[1].Width = new GridLength(0, GridUnitType.Star);
- OverallLayout.ColumnDefinitions[2].Width = new GridLength(0, GridUnitType.Star);
- PINLayout.RowDefinitions[3].Height = new GridLength(70, GridUnitType.Pixel);
- PINLayout.RowDefinitions[4].Height = new GridLength(70, GridUnitType.Pixel);
- Layout_2FA.RowDefinitions[3].Height = new GridLength(0, GridUnitType.Pixel);
- }
- private void ShowPasswordPage()
- {
- CurrentPage = Page.PASSWORD;
- OverallLayout.ColumnDefinitions[0].Width = new GridLength(0, GridUnitType.Star);
- OverallLayout.ColumnDefinitions[1].Width = new GridLength(1, GridUnitType.Star);
- OverallLayout.ColumnDefinitions[2].Width = new GridLength(0, GridUnitType.Star);
- PINLayout.RowDefinitions[3].Height = new GridLength(0, GridUnitType.Pixel);
- PINLayout.RowDefinitions[4].Height = new GridLength(0, GridUnitType.Pixel);
- Layout_2FA.RowDefinitions[3].Height = new GridLength(0, GridUnitType.Pixel);
- }
- private void Show2FAPage()
- {
- CurrentPage = Page._2FA;
- OverallLayout.ColumnDefinitions[0].Width = new GridLength(0, GridUnitType.Star);
- OverallLayout.ColumnDefinitions[1].Width = new GridLength(0, GridUnitType.Star);
- OverallLayout.ColumnDefinitions[2].Width = new GridLength(1, GridUnitType.Star);
- PINLayout.RowDefinitions[3].Height = new GridLength(0, GridUnitType.Pixel);
- PINLayout.RowDefinitions[4].Height = new GridLength(0, GridUnitType.Pixel);
- Layout_2FA.RowDefinitions[3].Height = new GridLength(70, GridUnitType.Pixel);
- foreach (var codeInput in codeInputs)
- {
- codeInput.Text = "";
- }
- codeInputs[0].Focus();
- Label_2FA.Content = string.Format("Please enter the code that was sent to {0}", ClientFactory.Recipient2FA);
- }
- private void ViewPINClick(object sender, RoutedEventArgs e)
- {
- ShowPINPage();
- PIN.Focus();
- PINPage = true;
- }
- private void ViewPasswordClick(object sender, RoutedEventArgs e)
- {
- ShowPasswordPage();
- UserID.Focus();
- PINPage = false;
- }
- private void Button_Click(object sender, RoutedEventArgs e)
- {
- var button = (Button)sender;
- PIN.Password += button.Content;
- }
- private void Back_Click(object sender, RoutedEventArgs e)
- {
- if (!string.IsNullOrEmpty(PIN.Password))
- PIN.Password = PIN.Password[..^1]; //.Reverse().Skip(1).Reverse().ToString();
- }
- private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
- {
- if(CurrentPage == Page._2FA)
- {
- if (e.Key == Key.Enter || e.Key == Key.Return)
- {
- e.Handled = true;
- Do2FA();
- }
- return;
- }
- if (CurrentPage != Page.PIN)
- return;
- e.Handled = true;
- Button button = null;
- if (e.Key == Key.Enter || e.Key == Key.Return)
- button = OK;
- else if (e.Key == Key.D1 || e.Key == Key.NumPad1)
- button = Key1;
- else if (e.Key == Key.D2 || e.Key == Key.NumPad2)
- button = Key2;
- else if (e.Key == Key.D3 || e.Key == Key.NumPad3)
- button = Key3;
- else if (e.Key == Key.D4 || e.Key == Key.NumPad4)
- button = Key4;
- else if (e.Key == Key.D5 || e.Key == Key.NumPad5)
- button = Key5;
- else if (e.Key == Key.D6 || e.Key == Key.NumPad6)
- button = Key6;
- else if (e.Key == Key.D7 || e.Key == Key.NumPad7)
- button = Key7;
- else if (e.Key == Key.D8 || e.Key == Key.NumPad8)
- button = Key8;
- else if (e.Key == Key.D9 || e.Key == Key.NumPad9)
- button = Key9;
- else if (e.Key == Key.D0 || e.Key == Key.NumPad0)
- button = Key0;
- else if (e.Key == Key.Back)
- button = Back;
- if (button == null || !button.IsEnabled)
- return;
- var peer = new ButtonAutomationPeer(button);
- var invokeProv = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
- invokeProv.Invoke();
- }
- private void PINChanged(object sender, RoutedEventArgs e)
- {
- Back.IsEnabled = !string.IsNullOrEmpty(PIN.Password);
- OK.IsEnabled = !string.IsNullOrEmpty(PIN.Password);
- }
- private string? ShowChangePassword(string userID)
- {
- using (var session = new BypassSession())
- {
- var user = new Client<User>().Query(
- new Filter<User>(x => x.UserID).IsEqualTo(userID),
- new Columns<User>(x => x.ID)).Rows.FirstOrDefault()?.ToObject<User>();
- if(user != null)
- {
- var changePassword = new ChangePassword(user.ID);
- if (changePassword.ShowDialog() == true && changePassword.Password != null)
- {
- ChangePassword.ChangeUserPassword(user, changePassword.Password);
- new Client<User>().Save(user, "Changed password");
- return changePassword.Password;
- }
- else
- {
- if (PINPage)
- ShowPINPage();
- else
- ShowPasswordPage();
- }
- }
- else
- {
- MessageBox.Show($"No user with username {userID}");
- }
- }
- return null;
- }
- private void OK_Click(object sender, RoutedEventArgs e)
- {
- ValidationStatus? result;
- using (new WaitCursor())
- {
- try
- {
- result = ClientFactory.Validate(PIN.Password);
- }
- catch(Exception err)
- {
- Logger.Send(LogType.Error, ClientFactory.UserID, $"Error connecting to server: {CoreUtils.FormatException(err)}");
- MessageBox.Show("Error connecting to server! Check the server URL and port number.");
- result = null;
- }
- }
- if (result == ValidationStatus.REQUIRE_2FA)
- {
- Show2FAPage();
- return;
- }
- var bOK = result == ValidationStatus.VALID;
- if (bOK)
- {
- App.DatabaseSettings.LoginType = LoginType.PIN;
- App.DatabaseSettings.Autologin = false;
- App.DatabaseSettings.UserID = "";
- App.DatabaseSettings.Password = "";
- DialogResult = true;
- Close();
- }
- else
- {
- if(result != null)
- {
- MessageBox.Show("Invalid PIN!");
- }
- PIN.Password = "";
- }
- }
- private void UserID_TextChanged(object sender, TextChangedEventArgs e)
- {
- Login.IsEnabled = !string.IsNullOrEmpty(UserID.Text) && !string.IsNullOrEmpty(Password.Password);
- }
- private void Password_PasswordChanged(object sender, RoutedEventArgs e)
- {
- Login.IsEnabled = !string.IsNullOrEmpty(UserID.Text) && !string.IsNullOrEmpty(Password.Password);
- }
- private void AutoLogin_Checked(object sender, RoutedEventArgs e)
- {
- }
- private ValidationStatus TryValidation(string password, ValidationStatus? result = null)
- {
- while (true)
- {
- if(result == null)
- {
- using (new WaitCursor())
- {
- try
- {
- result = ClientFactory.Validate(UserID.Text, password);
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, ClientFactory.UserID, $"Error connecting to server: {CoreUtils.FormatException(e)}");
- MessageBox.Show("Error connecting to server! Check the server URL and port number.");
- }
- }
- }
- if (result == ValidationStatus.PASSWORD_EXPIRED)
- {
- MessageBox.Show("Your password has expired!");
- var newPassword = ShowChangePassword(UserID.Text);
- if (newPassword == null)
- {
- break;
- }
- else
- {
- password = newPassword;
- Password.Clear();
- }
- }
- else
- {
- break;
- }
- result = null;
- }
- return result ?? ValidationStatus.INVALID;
- }
- private void Login_Click(object sender, RoutedEventArgs e)
- {
- ValidationStatus status = TryValidation(Password.Password);
- if (status == ValidationStatus.REQUIRE_2FA)
- {
- Show2FAPage();
- return;
- }
- var bOK = status == ValidationStatus.VALID;
- if (bOK)
- {
- //if (AutoLogin.IsChecked == true)
- //{
- // _settings.LoginType = LoginType.UserID;
- // _settings.UserID = UserID.Text;
- // _settings.Password = Password.Password;
- // _settings.Autologin = true;
- // new LocalConfiguration<DatabaseSettings>().Save(_settings);
- //}
- DialogResult = true;
- Close();
- }
- else
- {
- MessageBox.Show("Login Failed!");
- }
- }
- private void Window_Closing(object sender, CancelEventArgs e)
- {
- //e.Cancel = ClientFactory.UserGuid == Guid.Empty;
- if(!PINPage && DialogResult == true && App.DatabaseSettings.Autologin
- && App.DatabaseSettings.UserID == UserID.Text
- && App.DatabaseSettings.Password != Password.Password)
- {
- if(MessageBox.Show("You have logged in with a new password. Would you like to update your password in your settings so that you login automatically next time?",
- "Update password?",
- MessageBoxButton.YesNo) == MessageBoxResult.Yes)
- {
- App.DatabaseSettings.Password = Password.Password;
- App.SaveDatabaseSettings();
- }
- }
- }
- private void Password_KeyUp(object sender, KeyEventArgs e)
- {
- if (e.Key == Key.Enter || e.Key == Key.Return)
- {
- e.Handled = true;
- var peer = new ButtonAutomationPeer(Login);
- var invokeProv = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
- invokeProv.Invoke();
- }
- }
- private void UserID_KeyUp(object sender, KeyEventArgs e)
- {
- if (e.Key == Key.Enter || e.Key == Key.Return)
- {
- e.Handled = true;
- Password.Focus();
- }
- }
- private bool HasFilled2FABoxes()
- {
- foreach (var codeInput in CodeInput.Children)
- {
- var digit = (codeInput as TextBox)?.Text;
- if (digit == null || digit.Length != 1 || !char.IsDigit(digit[0]))
- {
- return false;
- }
- }
- return true;
- }
- private void Do2FA(bool showMessage = true)
- {
- if (Checking) return;
- Checking = true;
- var code = "";
- foreach (var codeInput in CodeInput.Children)
- {
- var digit = (codeInput as TextBox)?.Text;
- if (digit != null && digit.Length == 1 && char.IsDigit(digit[0]))
- {
- code += digit[0];
- }
- else
- {
- MessageBox.Show("All boxes must be filled and must contain a number");
- return;
- }
- }
- Task.Run(() =>
- {
- if (ClientFactory.Check2FA(code))
- {
- Dispatcher.Invoke(() =>
- {
- DialogResult = true;
- Close();
- });
- }
- else
- {
- MessageBox.Show("Code is incorrect!");
- Checking = false;
- }
- });
- }
- private void Click_2FA(object sender, RoutedEventArgs e)
- {
- Do2FA();
- }
- private void Back_2FA(object sender, RoutedEventArgs e)
- {
- ClientFactory.InvalidateUser();
- if (PINPage)
- ShowPINPage();
- else
- ShowPasswordPage();
- }
- private void MoveFocus()
- {
- var element = Keyboard.FocusedElement;
- if (element is TextBox)
- {
- var tb = element as TextBox;
- if (tb.Text.Length == 1)
- {
- var index = codeInputs.IndexOf(tb) + 1;
- if (index >= codeInputs.Count)
- {
- Focus();
- if (HasFilled2FABoxes())
- {
- Do2FA();
- }
- }
- else
- {
- var nextChild = codeInputs[index];
- nextChild.Focus();
- }
- }
- }
- }
- private void Code2FA_Preview(object sender, TextCompositionEventArgs e)
- {
- var tb = sender as TextBox;
- var oldText = tb!.Text;
- var newText = e.Text;
- var valid = newText.Length == 0 || (newText.Length == 1 && char.IsDigit(newText[0]));
- if (oldText.Length != 0 && valid)
- {
- tb.Text = "";
- }
- e.Handled = !valid;
- if (!valid && oldText.Length + newText.Length > 0)
- {
- MoveFocus();
- }
- }
- private void Code2FA_TextChanged(object sender, TextChangedEventArgs e)
- {
- MoveFocus();
- }
- private void Code2FA_PreviewKeyDown(object sender, KeyEventArgs e)
- {
- if (sender is TextBox tb)
- {
- var currentIndex = codeInputs.IndexOf(tb);
- int? newIndex = null;
- switch (e.Key)
- {
- case Key.Back:
- tb.Text = "";
- newIndex = Math.Max(currentIndex - 1, 0);
- e.Handled = true;
- break;
- case Key.Left:
- newIndex = Math.Max(currentIndex - 1, 0);
- e.Handled = true;
- break;
- case Key.Right:
- newIndex = Math.Min(currentIndex + 1, codeInputs.Count - 1);
- e.Handled = true;
- break;
- }
- if(newIndex != null)
- {
- var nextChild = codeInputs[newIndex ?? 0];
- nextChild.Focus();
- }
- }
- }
- }
|