From 7e82a4f8532a3acff7db98cf6723a3e72b6e3121 Mon Sep 17 00:00:00 2001 From: Jason DeVito Date: Mon, 21 Oct 2019 07:42:56 -0500 Subject: [PATCH] Completed migration of Password Manager to PDC, added event to notify clients of a password update --- .../JsonToSimpl/JsonToSimplChildObjectBase.cs | 25 +- .../JsonToSimpl/JsonToSimplFileMaster.cs | 1 + .../PasswordManagement/Config.cs | 95 +------ .../PasswordManagement/Constants.cs | 38 ++- .../PasswordManagement/OLD-ARRAY-Config.cs | 149 +++++++++++ .../OLD-ARRAY-PasswordClient.cs | 207 ++++++++++++++++ .../OLD-ARRAY-PasswordManager.cs | 233 ++++++++++++++++++ .../PasswordManagement/PasswordClient.cs | 95 ++++--- .../PasswordManagement/PasswordManager.cs | 185 +++++++++----- .../Properties/AssemblyInfo.cs | 2 +- 10 files changed, 807 insertions(+), 223 deletions(-) create mode 100644 Pepperdash Core/Pepperdash Core/PasswordManagement/OLD-ARRAY-Config.cs create mode 100644 Pepperdash Core/Pepperdash Core/PasswordManagement/OLD-ARRAY-PasswordClient.cs create mode 100644 Pepperdash Core/Pepperdash Core/PasswordManagement/OLD-ARRAY-PasswordManager.cs diff --git a/Pepperdash Core/Pepperdash Core/JsonToSimpl/JsonToSimplChildObjectBase.cs b/Pepperdash Core/Pepperdash Core/JsonToSimpl/JsonToSimplChildObjectBase.cs index 93c5ee5..2d74bbb 100644 --- a/Pepperdash Core/Pepperdash Core/JsonToSimpl/JsonToSimplChildObjectBase.cs +++ b/Pepperdash Core/Pepperdash Core/JsonToSimpl/JsonToSimplChildObjectBase.cs @@ -8,7 +8,7 @@ using Newtonsoft.Json.Linq; namespace PepperDash.Core.JsonToSimpl { - public abstract class JsonToSimplChildObjectBase: IKeyed + public abstract class JsonToSimplChildObjectBase : IKeyed { public event EventHandler BoolChange; @@ -64,9 +64,10 @@ namespace PepperDash.Core.JsonToSimpl Debug.Console(1, "JSON Child [{0}] cannot link to master {1}", key, masterUniqueId); } - public void SetPathPrefix(string pathPrefix) { + public void SetPathPrefix(string pathPrefix) + { PathPrefix = pathPrefix; - } + } /// /// Set the JPath to evaluate for a given bool out index. /// @@ -133,20 +134,22 @@ namespace PepperDash.Core.JsonToSimpl OnBoolChange(response.Equals("true", StringComparison.OrdinalIgnoreCase), index, JsonToSimplConstants.BoolValueChange); else { } - // OnBoolChange(false, index, JsonToSimplConstants.BoolValueChange); + // OnBoolChange(false, index, JsonToSimplConstants.BoolValueChange); } // Processes the path to a ushort, converting to ushort if able, firing off UshrtChange event void ProcessUshortPath(ushort index) { string response; - if (Process(UshortPaths[index], out response)) { + if (Process(UshortPaths[index], out response)) + { ushort val; - try { val = Convert.ToUInt16(response); } catch { val = 0; } + try { val = Convert.ToUInt16(response); } + catch { val = 0; } OnUShortChange(val, index, JsonToSimplConstants.UshortValueChange); - } + } else { } - // OnUShortChange(0, index, JsonToSimplConstants.UshortValueChange); + // OnUShortChange(0, index, JsonToSimplConstants.UshortValueChange); } // Processes the path to a string property and fires of a StringChange event. @@ -156,7 +159,7 @@ namespace PepperDash.Core.JsonToSimpl if (Process(StringPaths[index], out response)) OnStringChange(response, index, JsonToSimplConstants.StringValueChange); else { } - // OnStringChange("", index, JsonToSimplConstants.StringValueChange); + // OnStringChange("", index, JsonToSimplConstants.StringValueChange); } /// @@ -170,7 +173,7 @@ namespace PepperDash.Core.JsonToSimpl bool Process(string path, out string response) { path = GetFullPath(path); - Debug.Console(1, "JSON Child[{0}] Processing {1}", Key, path); + Debug.Console(1, "JSON Child[{0}] Processing {1}", Key, path); response = ""; if (Master == null) { @@ -285,7 +288,7 @@ namespace PepperDash.Core.JsonToSimpl protected virtual string GetFullPath(string path) { return (PathPrefix != null ? PathPrefix : "") + - path + (PathSuffix != null ? PathSuffix : ""); + path + (PathSuffix != null ? PathSuffix : ""); } // Helpers for events diff --git a/Pepperdash Core/Pepperdash Core/JsonToSimpl/JsonToSimplFileMaster.cs b/Pepperdash Core/Pepperdash Core/JsonToSimpl/JsonToSimplFileMaster.cs index 0047c6c..82198c1 100644 --- a/Pepperdash Core/Pepperdash Core/JsonToSimpl/JsonToSimplFileMaster.cs +++ b/Pepperdash Core/Pepperdash Core/JsonToSimpl/JsonToSimplFileMaster.cs @@ -108,6 +108,7 @@ namespace PepperDash.Core.JsonToSimpl { Debug.SetDebugLevel(level); } + public override void Save() { // this code is duplicated in the other masters!!!!!!!!!!!!! diff --git a/Pepperdash Core/Pepperdash Core/PasswordManagement/Config.cs b/Pepperdash Core/Pepperdash Core/PasswordManagement/Config.cs index 82f1714..4d6b035 100644 --- a/Pepperdash Core/Pepperdash Core/PasswordManagement/Config.cs +++ b/Pepperdash Core/Pepperdash Core/PasswordManagement/Config.cs @@ -6,92 +6,21 @@ using Crestron.SimplSharp; namespace PepperDash.Core.PasswordManagement { - // Example JSON password configuration object - //{ - // "global":{ - // "passwords":[ - // { - // "key": "Password01", - // "name": "Technician Password", - // "enabled": true, - // "password": "1988" - // } - // ] - // } - //} - /// - /// Passwrod manager JSON configuration + /// JSON password configuration /// public class PasswordConfig { - /// - /// Key used to search for object in JSON array - /// - public string key { get; set; } - /// - /// Friendly name of password object - /// - public string name { get; set; } - /// - /// Password object enabled - /// - public bool enabled { get; set; } - /// - /// - /// - public ushort simplEnabled - { - get { return (ushort)(enabled ? 1 : 0); } - set { enabled = Convert.ToBoolean(value); } - } - /// - /// Password object configured password - /// - public string password { get; set; } - /// - /// Password type - /// - private int type { get; set; } - /// - /// Password Type for S+ - /// - public ushort simplType - { - get { return Convert.ToUInt16(type); } - set { type = value; } - } - /// - /// Constructor - /// - public PasswordConfig() - { - simplEnabled = 0; - simplType = 0; - } - } - - /// - /// Global JSON object - /// - public class GlobalConfig - { - public List passwords { get; set; } - - /// - /// Constructor - /// - public GlobalConfig() - { - - } - } - - /// - /// Root JSON object - /// - public class RootObject - { - public GlobalConfig global { get; set; } + /// + /// Password object configured password + /// + public string password { get; set; } + /// + /// Constructor + /// + public PasswordConfig() + { + + } } } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/PasswordManagement/Constants.cs b/Pepperdash Core/Pepperdash Core/PasswordManagement/Constants.cs index 9319b7b..8ba89e0 100644 --- a/Pepperdash Core/Pepperdash Core/PasswordManagement/Constants.cs +++ b/Pepperdash Core/Pepperdash Core/PasswordManagement/Constants.cs @@ -18,19 +18,19 @@ namespace PepperDash.Core.PasswordManagement /// /// Evaluated boolean change constant /// - public const ushort BoolEvaluatedChange = 2; + public const ushort PasswordInitializedChange = 2; + /// + /// Update busy change const + /// + public const ushort PasswordUpdateBusyChange = 3; /// /// Password is valid change constant /// - public const ushort PasswordIsValid = 3; - /// - /// Password is invalid change constant - /// - public const ushort PasswordIsInvalid = 4; + public const ushort PasswordValidationChange = 4; /// /// Password LED change constant /// - public const ushort PasswordLedChange = 5; + public const ushort PasswordLedFeedbackChange = 5; /// /// Generic ushort value change constant @@ -39,27 +39,19 @@ namespace PepperDash.Core.PasswordManagement /// /// Password count /// - public const ushort PasswordListCount = 102; + public const ushort PasswordManagerCountChange = 102; + /// + /// Password selecte index change constant + /// + public const ushort PasswordSelectIndexChange = 103; /// /// Password length /// - public const ushort SelectedPasswordLength = 103; - /// - /// Password to validate length - /// - public const ushort UserEnteredPasswordLength = 104; - + public const ushort PasswordLengthChange = 104; + /// /// Generic string value change constant /// - public const ushort StringValueChange = 201; - /// - /// Password key change constant - /// - public const ushort PasswordKey = 202; - /// - /// Password selected key change constant - /// - public const ushort PasswordKeySelected = 203; + public const ushort StringValueChange = 201; } } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/PasswordManagement/OLD-ARRAY-Config.cs b/Pepperdash Core/Pepperdash Core/PasswordManagement/OLD-ARRAY-Config.cs new file mode 100644 index 0000000..c49df19 --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/PasswordManagement/OLD-ARRAY-Config.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Core.PasswordManagement +{ + // Example JSON password array configuration object + //{ + // "global":{ + // "passwords":[ + // { + // "key": "Password01", + // "name": "Technician Password", + // "enabled": true, + // "password": "1988" + // } + // ] + // } + //} + + /// + /// JSON password array configuration object + /// + //public class PasswordConfig + //{ + // /// + // /// Key used to search for object in JSON array + // /// + // public string key { get; set; } + // /// + // /// Friendly name of password object + // /// + // public string name { get; set; } + // /// + // /// Password object enabled + // /// + // public bool enabled { get; set; } + // /// + // /// + // /// + // public ushort simplEnabled + // { + // get { return (ushort)(enabled ? 1 : 0); } + // set { enabled = Convert.ToBoolean(value); } + // } + // /// + // /// Password object configured password + // /// + // public string password { get; set; } + // /// + // /// Password type + // /// + // private int type { get; set; } + // /// + // /// Password Type for S+ + // /// + // public ushort simplType + // { + // get { return Convert.ToUInt16(type); } + // set { type = value; } + // } + // /// + // /// Password path + // /// **FUTURE** implementation of saving passwords recieved from Fusion or other external sources back to config + // /// + // public string path { get; set; } + // /// + // /// Constructor + // /// + // public PasswordConfig() + // { + // simplEnabled = 0; + // simplType = 0; + // } + //} + + // Example JSON password collections configuration object + //{ + // "global": { + // "passwords": { + // "1": { + // "name": "Technician Password", + // "password": "2468" + // }, + // "2": { + // "name": "System Password", + // "password": "123456" + // }, + // "3": { + // "name": "Master Password", + // "password": "abc123" + // }, + // "5": { + // "name": "Backdoor Password", + // "password": "1988" + // }, + // "10": { + // "name": "Backdoor Password", + // "password": "1988" + // } + // } + // } + //} + + /// + /// JSON password array configuration object + /// + public class PasswordConfig + { + /// + /// Password object configured password + /// + public string password { get; set; } + /// + /// Constructor + /// + public PasswordConfig() + { + + } + } + + /// + /// Global JSON object + /// + //public class GlobalConfig + //{ + // //public List passwords { get; set; } + // public Dictionary passwords { get; set; } + + // /// + // /// Constructor + // /// + // public GlobalConfig() + // { + + // } + //} + + /// + /// Root JSON object + /// + //public class RootObject + //{ + // public GlobalConfig global { get; set; } + //} +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/PasswordManagement/OLD-ARRAY-PasswordClient.cs b/Pepperdash Core/Pepperdash Core/PasswordManagement/OLD-ARRAY-PasswordClient.cs new file mode 100644 index 0000000..634badf --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/PasswordManagement/OLD-ARRAY-PasswordClient.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Core.PasswordManagement +{ + public class PasswordClient + { + /// + /// Password Client + /// + public PasswordConfig Client { get; set; } + /// + /// Used to build the password entered by the user + /// + public string PasswordToValidate { get; set; } + + /// + /// Boolean event + /// + public event EventHandler BoolChange; + /// + /// Ushort event + /// + public event EventHandler UshrtChange; + /// + /// String event + /// + public event EventHandler StringChange; + + /// + /// Constructor + /// + public PasswordClient() + { + + } + + /// + /// Initialize method + /// + /// + public void Initialize(string key) + { + OnBoolChange(false, 0, PasswordManagementConstants.BoolEvaluatedChange); + + Client = new PasswordConfig(); + PasswordToValidate = ""; + + // there has to be a better way to get the index of the current index of password + ushort i = 0; + foreach (var password in PasswordManager.Passwords) + { + i++; + OnUshrtChange((ushort)password.Key, (ushort)password.Key, PasswordManagementConstants.PasswordKey); + } + + OnBoolChange(true, 0, PasswordManagementConstants.BoolEvaluatedChange); + } + + /// + /// Retrieves password by key + /// + /// + //public void GetPasswordByKey(string key) + //{ + // if (string.IsNullOrEmpty(key)) + // { + // Debug.Console(1, "PassowrdClient.GetPasswordByKey failed:\rKey {0} is null or empty", key); + // return; + // } + + // PasswordConfig password = PasswordManager.Passwords.FirstOrDefault(p => p.key.Equals(key)); + // if (password == null) + // { + // OnUshrtChange(0, 0, PasswordManagementConstants.SelectedPasswordLength); + // return; + // } + + // Client = password; + // OnUshrtChange((ushort)Client.password.Length, 0, PasswordManagementConstants.SelectedPasswordLength); + // OnStringChange(Client.key, 0, PasswordManagementConstants.PasswordKeySelected); + //} + + /// + /// Retrieve password by index + /// + /// + public void GetPasswordByIndex(ushort key) + { + PasswordConfig pw = PasswordManager.Passwords[key]; + if (pw == null) + { + OnUshrtChange(0, 0, PasswordManagementConstants.SelectedPasswordLength); + return; + } + + Client = pw; + OnUshrtChange((ushort)Client.password.Length, 0, PasswordManagementConstants.SelectedPasswordLength); + OnUshrtChange(key, 0, PasswordManagementConstants.PasswordKeySelected); + } + + /// + /// Password validation method + /// + /// + public void ValidatePassword(string password) + { + if (string.IsNullOrEmpty(password)) + return; + + if (string.Equals(Client.password, password)) + { + OnBoolChange(true, 0, PasswordManagementConstants.PasswordIsValid); + } + else + { + OnBoolChange(true, 0, PasswordManagementConstants.PasswordIsInvalid); + } + + + OnBoolChange(false, 0, PasswordManagementConstants.PasswordIsValid); + OnBoolChange(false, 0, PasswordManagementConstants.PasswordIsInvalid); + + ClearPassword(); + } + + /// + /// Builds the user entered passwrod string, will attempt to validate the user entered + /// password against the selected password when the length of the 2 are equal + /// + /// + public void BuildPassword(string data) + { + PasswordToValidate = String.Concat(PasswordToValidate, data); + OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedChange); + + if (PasswordToValidate.Length == Client.password.Length) + ValidatePassword(PasswordToValidate); + } + + /// + /// Clears the user entered password and resets the LEDs + /// + public void ClearPassword() + { + PasswordToValidate = ""; + OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedChange); + + for(var i = 1; i <= Client.password.Length; i++) + OnBoolChange(false, (ushort)i, PasswordManagementConstants.PasswordLedChange); + } + + /// + /// 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); + } + } + } +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/PasswordManagement/OLD-ARRAY-PasswordManager.cs b/Pepperdash Core/Pepperdash Core/PasswordManagement/OLD-ARRAY-PasswordManager.cs new file mode 100644 index 0000000..b34db61 --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/PasswordManagement/OLD-ARRAY-PasswordManager.cs @@ -0,0 +1,233 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Crestron.SimplSharp; +using PepperDash.Core.JsonToSimpl; +using PepperDash.Core.JsonStandardObjects; + +namespace PepperDash.Core.PasswordManagement +{ + public class PasswordManager + { + /// + /// List of passwords configured + /// + public static Dictionary Passwords = new Dictionary(); + private Dictionary TempPasswords = new Dictionary(); + + CTimer UpdateTimer; + public long UpdateTimerElapsedMs = 5000; + + /// + /// Boolean event + /// + public event EventHandler BoolChange; + /// + /// Ushort event + /// + public event EventHandler UshrtChange; + /// + /// String event + /// + public event EventHandler StringChange; + + + /// + /// Constructor + /// + public PasswordManager() + { + Passwords.Clear(); + } + + /// + /// Initialize method + /// + /// + /// + //public void Initialize(string uniqueId, string key) + //{ + // OnBoolChange(false, 0, PasswordManagementConstants.BoolEvaluatedChange); + + // try + // { + // if(string.IsNullOrEmpty(uniqueId) || string.IsNullOrEmpty(key)) + // { + // Debug.Console(1, "PasswordManager.Initialize({0}, {1}) null or empty parameters", uniqueId, key); + // return; + // } + + // JsonToSimplMaster master = J2SGlobal.GetMasterByFile(uniqueId); + // if(master == null) + // { + // Debug.Console(1, "PassowrdManager.Initialize failed:\rCould not find JSON file with uniqueID {0}", uniqueId); + // return; + // } + + // var global = master.JsonObject.ToObject().global; + // var passwords = global.passwords; + // if(passwords == null) + // { + // Debug.Console(1, "PasswordManager.Initialize failed:\rCould not find password object"); + // return; + // } + + // foreach(var password in passwords) + // { + // if (password != null) + // { + // var index = passwords.IndexOf(password); + + // password.path = string.Format("global.passwords[{0}]", index); + // Debug.Console(1, "PasswordManager.Initialize: {0}, {1}, {2}, {3}, {4}, {5}", password.key, password.name, password.simplEnabled, password.simplType, password.password, password.path); + // //AddPassword(password); + + // OnStringChange(password.path, (ushort)index, PasswordManagementConstants.FullPathToPassword); + // OnStringChange(password.key, (ushort)index, PasswordManagementConstants.PasswordKey); + // } + // } + + // OnUshrtChange(Convert.ToUInt16(Passwords.Count), 0, PasswordManagementConstants.PasswordListCount); + // } + // catch(Exception e) + // { + // var msg = string.Format("PasswordManager.Initialize({0}, {1}) failed:\r{2}", uniqueId, key, e.Message); + // CrestronConsole.PrintLine(msg); + // ErrorLog.Error(msg); + // } + // finally + // { + // OnBoolChange(true, 0, PasswordManagementConstants.BoolEvaluatedChange); + // } + //} + + /// + /// Adds password to the list + /// + /// + //private void AddPassword(PasswordConfig password) + //{ + // if (password == null) + // return; + + // var item = Passwords.FirstOrDefault(i => i.key.Equals(password.key)); + // if (item != null) + // Passwords.Remove(item); + // Passwords.Add(password); + + // Passwords.Sort((x, y) => string.Compare(x.key, y.key)); + //} + + /// + /// Removes password from the list + /// + /// + //private void RemovePassword(PasswordConfig password) + //{ + // if (password == null) + // return; + + // var item = Passwords.FirstOrDefault(i => i.key.Equals(password.key)); + // if (item != null) + // Passwords.Remove(item); + //} + + /// + /// Updates password stored in the dictonary + /// + /// + /// + /// + public void UpdatePassword(ushort key, string password) + { + if (string.IsNullOrEmpty(password)) + return; + + var pw = TempPasswords[key]; + if (pw == null) + { + pw = new PasswordConfig(); + } + pw.password = password; + + if (UpdateTimer == null) + { + // (o) => SavePasswords removes the need to create a callback method that takes in an object + UpdateTimer = new CTimer((o) => StorePassword(), UpdateTimerElapsedMs); + } + else + { + UpdateTimer.Reset(); + } + } + + /// + /// Stores the updated passwords in TempPassword in the Passwords dictionary + /// + private void StorePassword() + { + UpdateTimer.Stop(); + + foreach (var tempPw in TempPasswords) + { + Passwords[tempPw.Key] = tempPw.Value; + } + + TempPasswords.Clear(); + } + + /// + /// 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); + } + } + } +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/PasswordManagement/PasswordClient.cs b/Pepperdash Core/Pepperdash Core/PasswordManagement/PasswordClient.cs index 7d3d254..b274842 100644 --- a/Pepperdash Core/Pepperdash Core/PasswordManagement/PasswordClient.cs +++ b/Pepperdash Core/Pepperdash Core/PasswordManagement/PasswordClient.cs @@ -9,9 +9,13 @@ namespace PepperDash.Core.PasswordManagement public class PasswordClient { /// - /// Password Client + /// Password selected /// - public PasswordConfig Client { get; set; } + public string Password { get; set; } + /// + /// Password selected key + /// + public ushort Key { get; set; } /// /// Used to build the password entered by the user /// @@ -35,53 +39,43 @@ namespace PepperDash.Core.PasswordManagement /// public PasswordClient() { - - } + PasswordManager.PasswordChange += new EventHandler(PasswordManager_PasswordChange); + } /// /// Initialize method /// - /// - public void Initialize(string key) + public void Initialize() { - OnBoolChange(false, 0, PasswordManagementConstants.BoolEvaluatedChange); + OnBoolChange(false, 0, PasswordManagementConstants.PasswordInitializedChange); - Client = new PasswordConfig(); + Password = ""; PasswordToValidate = ""; - // there has to be a better way to get the index of the current index of password - ushort i = 0; - foreach (var password in PasswordManager.Passwords) - { - i++; - OnStringChange(password.key, i, PasswordManagementConstants.PasswordKey); - } - - OnBoolChange(true, 0, PasswordManagementConstants.BoolEvaluatedChange); + OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange); + OnBoolChange(true, 0, PasswordManagementConstants.PasswordInitializedChange); } /// - /// Retrieves password by key + /// Retrieve password by index /// /// - public void GetPasswordByKey(string key) + public void GetPasswordByIndex(ushort key) { - if (string.IsNullOrEmpty(key)) + OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange); + + Key = key; + + var pw = PasswordManager.Passwords[Key]; + if (pw == null) { - Debug.Console(1, "PassowrdClient.GetPasswordByKey failed:\rKey {0} is null or empty", key); + OnUshrtChange(0, 0, PasswordManagementConstants.PasswordLengthChange); return; } - PasswordConfig password = PasswordManager.Passwords.FirstOrDefault(p => p.key.Equals(key)); - if (password == null) - { - OnUshrtChange(0, 0, PasswordManagementConstants.SelectedPasswordLength); - return; - } - - Client = password; - OnUshrtChange((ushort)Client.password.Length, 0, PasswordManagementConstants.SelectedPasswordLength); - OnStringChange(Client.key, 0, PasswordManagementConstants.PasswordKeySelected); + Password = pw; + OnUshrtChange((ushort)Password.Length, 0, PasswordManagementConstants.PasswordLengthChange); + OnUshrtChange(key, 0, PasswordManagementConstants.PasswordSelectIndexChange); } /// @@ -93,18 +87,10 @@ namespace PepperDash.Core.PasswordManagement if (string.IsNullOrEmpty(password)) return; - if (string.Equals(Client.password, password)) - { - OnBoolChange(true, 0, PasswordManagementConstants.PasswordIsValid); - } + if (string.Equals(Password, password)) + OnBoolChange(true, 0, PasswordManagementConstants.PasswordValidationChange); else - { - OnBoolChange(true, 0, PasswordManagementConstants.PasswordIsInvalid); - } - - - OnBoolChange(false, 0, PasswordManagementConstants.PasswordIsValid); - OnBoolChange(false, 0, PasswordManagementConstants.PasswordIsInvalid); + OnBoolChange(false, 0, PasswordManagementConstants.PasswordValidationChange); ClearPassword(); } @@ -117,9 +103,9 @@ namespace PepperDash.Core.PasswordManagement public void BuildPassword(string data) { PasswordToValidate = String.Concat(PasswordToValidate, data); - OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedChange); + OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedFeedbackChange); - if (PasswordToValidate.Length == Client.password.Length) + if (PasswordToValidate.Length == Password.Length) ValidatePassword(PasswordToValidate); } @@ -129,10 +115,7 @@ namespace PepperDash.Core.PasswordManagement public void ClearPassword() { PasswordToValidate = ""; - OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedChange); - - for(var i = 1; i <= Client.password.Length; i++) - OnBoolChange(false, (ushort)i, PasswordManagementConstants.PasswordLedChange); + OnBoolChange(false, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedFeedbackChange); } /// @@ -185,5 +168,21 @@ namespace PepperDash.Core.PasswordManagement StringChange(this, args); } } + + /// + /// If password changes while selected change event will be notifed and update the client + /// + /// + /// + protected void PasswordManager_PasswordChange(object sender, StringChangeEventArgs args) + { + //throw new NotImplementedException(); + if (Key == args.Index) + { + //PasswordSelectedKey = args.Index; + //PasswordSelected = args.StringValue; + GetPasswordByIndex(args.Index); + } + } } } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/PasswordManagement/PasswordManager.cs b/Pepperdash Core/Pepperdash Core/PasswordManagement/PasswordManager.cs index 15d0d5f..2ba323d 100644 --- a/Pepperdash Core/Pepperdash Core/PasswordManagement/PasswordManager.cs +++ b/Pepperdash Core/Pepperdash Core/PasswordManagement/PasswordManager.cs @@ -6,15 +6,30 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Crestron.SimplSharp; using PepperDash.Core.JsonToSimpl; +using PepperDash.Core.JsonStandardObjects; namespace PepperDash.Core.PasswordManagement { public class PasswordManager { /// - /// List of passwords configured + /// Public dictionary of known passwords /// - public static List Passwords = new List(); + 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 + /// + CTimer PasswordTimer; + /// + /// Timer length + /// + public long PasswordTimerElapsedMs = 5000; + /// /// Boolean event /// @@ -27,96 +42,135 @@ namespace PepperDash.Core.PasswordManagement /// 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() { - Passwords.Clear(); + } /// - /// Initialize method + /// 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 /// /// - /// - public void Initialize(string uniqueId, string key) + /// + public void UpdatePassword(ushort key, string password) { - OnBoolChange(false, 0, PasswordManagementConstants.BoolEvaluatedChange); + // validate the parameters + if (key > 0 && string.IsNullOrEmpty(password)) + { + Debug.Console(1, string.Format("PasswordManager.UpdatePassword: key [{0}] or password are not valid", key, password)); + return; + } try { - if(string.IsNullOrEmpty(uniqueId) || string.IsNullOrEmpty(key)) - { - Debug.Console(1, "PasswordManager.Initialize({0}, {1}) null or empty parameters", uniqueId, key); - return; - } + // if key exists, update the value + if(_passwords.ContainsKey(key)) + _passwords[key] = password; + // else add the key & value + else + _passwords.Add(key, password); + + Debug.Console(1, string.Format("PasswordManager.UpdatePassword: _password[{0}] = {1}", key, _passwords[key])); - JsonToSimplMaster master = J2SGlobal.GetMasterByFile(uniqueId); - if(master == null) + if (PasswordTimer == null) { - Debug.Console(1, "PassowrdManager.Initialize failed:\rCould not find JSON file with uniqueID {0}", uniqueId); - return; + PasswordTimer = new CTimer((o) => PasswordTimerElapsed(), PasswordTimerElapsedMs); + Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Started")); + OnBoolChange(true, 0, PasswordManagementConstants.PasswordUpdateBusyChange); } - - var passwords = master.JsonObject.ToObject().global.passwords; - if(passwords == null) - { - Debug.Console(1, "PasswordManager.Initialize failed:\rCould not find password object"); - return; - } - - foreach(var password in passwords) + else { - if (password != null) + PasswordTimer.Reset(PasswordTimerElapsedMs); + Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Reset")); + } + } + catch (Exception e) + { + var msg = string.Format("PasswordManager.UpdatePassword key-value[{0}, {1}] failed:\r{2}", key, password, e); + Debug.Console(1, msg); + } + } + + /// + /// CTimer callback function + /// + private void PasswordTimerElapsed() + { + try + { + PasswordTimer.Stop(); + Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: CTimer Stopped")); + OnBoolChange(false, 0, PasswordManagementConstants.PasswordUpdateBusyChange); + foreach (var pw in _passwords) + { + // if key exists, continue + if (Passwords.ContainsKey(pw.Key)) { - Debug.Console(1, "PasswordManager.Initialize: {0}, {1}, {2}, {3}, {4}", password.key, password.name, password.simplEnabled, password.simplType, password.password); - AddPassword(password); + Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: pw.key[{0}] = {1}", pw.Key, pw.Value)); + if (Passwords[pw.Key] != _passwords[pw.Key]) + { + Passwords[pw.Key] = _passwords[pw.Key]; + Debug.Console(1, string.Format("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(Convert.ToUInt16(Passwords.Count), 0, PasswordManagementConstants.PasswordListCount); + OnUshrtChange((ushort)Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange); } - catch(Exception e) + catch (Exception e) { - var msg = string.Format("PasswordManager.Initialize({0}, {1}) failed:\r{2}", uniqueId, key, e.Message); - CrestronConsole.PrintLine(msg); - ErrorLog.Error(msg); - } - finally - { - OnBoolChange(true, 0, PasswordManagementConstants.BoolEvaluatedChange); + var msg = string.Format("PasswordManager.PasswordTimerElapsed failed:\r{0}", e); + Debug.Console(1, msg); } } /// - /// Adds password to the list + /// Method to change the default timer value, (default 5000ms/5s) /// - /// - private void AddPassword(PasswordConfig password) + /// + public void PasswordTimerMs(ushort time) { - if (password == null) - return; - - var item = Passwords.FirstOrDefault(i => i.key.Equals(password.key)); - if (item != null) - Passwords.Remove(item); - Passwords.Add(password); + PasswordTimerElapsedMs = Convert.ToInt64(time); } /// - /// Removes password from the list + /// Helper method for debugging to see what passwords are in the lists /// - /// - private void RemovePassword(PasswordConfig password) + public void ListPasswords() { - if (password == null) - return; - - var item = Passwords.FirstOrDefault(i => i.key.Equals(password.key)); - if (item != null) - Passwords.Remove(item); + Debug.Console(0, "PasswordManager.ListPasswords:\r"); + foreach (var pw in Passwords) + Debug.Console(0, "Passwords[{0}]: {1}\r", pw.Key, pw.Value); + Debug.Console(0, "\n"); + foreach (var pw in _passwords) + Debug.Console(0, "_passwords[{0}]: {1}\r", pw.Key, pw.Value); } /// @@ -169,5 +223,22 @@ namespace PepperDash.Core.PasswordManagement 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); + } + } } } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/Properties/AssemblyInfo.cs b/Pepperdash Core/Pepperdash Core/Properties/AssemblyInfo.cs index 55b4cbb..156aca9 100644 --- a/Pepperdash Core/Pepperdash Core/Properties/AssemblyInfo.cs +++ b/Pepperdash Core/Pepperdash Core/Properties/AssemblyInfo.cs @@ -4,4 +4,4 @@ [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Pepperdash_Core")] [assembly: AssemblyCopyright("Copyright © PepperDash 2019")] -[assembly: AssemblyVersion("1.0.23.*")] +[assembly: AssemblyVersion("1.0.26.*")]