using System; using System.Collections.Generic; using System.Timers; namespace PepperDash.Core.PasswordManagement; /// /// Allows passwords to be stored and managed /// public class PasswordManager { /// /// Public dictionary of known passwords /// public static Dictionary Passwords = new Dictionary(); /// /// Private dictionary, used when passwords are updated /// private Dictionary _passwords = new Dictionary(); /// /// Timer used to wait until password changes have stopped before updating the dictionary /// Timer PasswordTimer; /// /// Timer length /// public long PasswordTimerElapsedMs = 5000; /// /// Boolean event /// public event EventHandler BoolChange; /// /// Ushort event /// public event EventHandler UshrtChange; /// /// String event /// public event EventHandler StringChange; /// /// Event to notify clients of an updated password at the specified index (uint) /// public static event EventHandler PasswordChange; /// /// Constructor /// public PasswordManager() { } /// /// Initialize password manager /// public void Initialize() { if (Passwords == null) Passwords = new Dictionary(); if (_passwords == null) _passwords = new Dictionary(); OnBoolChange(true, 0, PasswordManagementConstants.PasswordInitializedChange); } /// /// Updates password stored in the dictonary /// /// /// /// /// UpdatePassword method /// public void UpdatePassword(ushort key, string password) { // validate the parameters if (key > 0 && string.IsNullOrEmpty(password)) { Debug.LogDebug("PasswordManager.UpdatePassword: key [{0}] or password are not valid", key, password); return; } try { // if key exists, update the value if (_passwords.ContainsKey(key)) _passwords[key] = password; // else add the key & value else _passwords.Add(key, password); Debug.LogDebug("PasswordManager.UpdatePassword: _password[{0}] = {1}", key, _passwords[key]); if (PasswordTimer == null) { PasswordTimer = new Timer(PasswordTimerElapsedMs) { AutoReset = false }; PasswordTimer.Elapsed += (s, e) => PasswordTimerElapsed(s, e); PasswordTimer.Start(); Debug.LogDebug("PasswordManager.UpdatePassword: Timer Started"); OnBoolChange(true, 0, PasswordManagementConstants.PasswordUpdateBusyChange); } else { PasswordTimer.Stop(); PasswordTimer.Interval = PasswordTimerElapsedMs; PasswordTimer.Start(); Debug.LogDebug("PasswordManager.UpdatePassword: Timer Reset"); } } catch (Exception e) { var msg = string.Format("PasswordManager.UpdatePassword key-value[{0}, {1}] failed:\r{2}", key, password, e); Debug.LogError(e, msg); Debug.LogVerbose("Stack Trace:\r{0}", e.StackTrace); } } /// /// Timer callback function /// private void PasswordTimerElapsed(object sender, ElapsedEventArgs e) { try { PasswordTimer.Stop(); Debug.LogDebug("PasswordManager.PasswordTimerElapsed: Timer Stopped"); OnBoolChange(false, 0, PasswordManagementConstants.PasswordUpdateBusyChange); foreach (var pw in _passwords) { // if key exists, continue if (Passwords.ContainsKey(pw.Key)) { Debug.LogDebug("PasswordManager.PasswordTimerElapsed: pw.key[{0}] = {1}", pw.Key, pw.Value); if (Passwords[pw.Key] != _passwords[pw.Key]) { Passwords[pw.Key] = _passwords[pw.Key]; Debug.LogDebug("PasswordManager.PasswordTimerElapsed: Updated Password[{0} = {1}", pw.Key, Passwords[pw.Key]); OnPasswordChange(Passwords[pw.Key], (ushort)pw.Key, PasswordManagementConstants.StringValueChange); } } // else add the key & value else { Passwords.Add(pw.Key, pw.Value); } } OnUshrtChange((ushort)Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange); } catch (Exception ex) { var msg = string.Format("PasswordManager.PasswordTimerElapsed failed:\r{0}", ex.Message); Debug.LogError(ex, msg); Debug.LogVerbose("Stack Trace:\r{0}", ex.StackTrace); } } /// /// Method to change the default timer value, (default 5000ms/5s) /// /// /// /// PasswordTimerMs method /// public void PasswordTimerMs(ushort time) { PasswordTimerElapsedMs = Convert.ToInt64(time); } /// /// Helper method for debugging to see what passwords are in the lists /// public void ListPasswords() { Debug.LogInformation("PasswordManager.ListPasswords:\r"); foreach (var pw in Passwords) Debug.LogInformation("Passwords[{0}]: {1}\r", pw.Key, pw.Value); Debug.LogInformation("\n"); foreach (var pw in _passwords) Debug.LogInformation("_passwords[{0}]: {1}\r", pw.Key, pw.Value); } /// /// Protected boolean change event handler /// /// /// /// protected void OnBoolChange(bool state, ushort index, ushort type) { var handler = BoolChange; if (handler != null) { var args = new BoolChangeEventArgs(state, type); args.Index = index; BoolChange(this, args); } } /// /// Protected ushort change event handler /// /// /// /// protected void OnUshrtChange(ushort value, ushort index, ushort type) { var handler = UshrtChange; if (handler != null) { var args = new UshrtChangeEventArgs(value, type); args.Index = index; UshrtChange(this, args); } } /// /// Protected string change event handler /// /// /// /// protected void OnStringChange(string value, ushort index, ushort type) { var handler = StringChange; if (handler != null) { var args = new StringChangeEventArgs(value, type); args.Index = index; StringChange(this, args); } } /// /// Protected password change event handler /// /// /// /// protected void OnPasswordChange(string value, ushort index, ushort type) { var handler = PasswordChange; if (handler != null) { var args = new StringChangeEventArgs(value, type); args.Index = index; PasswordChange(this, args); } } }