feat(password-management): update password client and manager methods, added modules

- Modified Password Management to allow username/password input for validation
- Introduced PepperDash_Core_Password_Client_A4sA3s_v02.00.usp for handling password validation and management.
- Added PepperDash_Core_Password_Manager_A4sA3s_v02.00.usp to manage multiple passwords and user authentication.
- Created corresponding .ush files for both modules to define inputs, outputs, and parameters.
- Included a compiled zip file for the password management system.
- Updated project file to include new password management functionalities and ensure compatibility with existing components.
This commit is contained in:
jdevito 2026-02-19 21:00:45 -06:00
parent 28f3ca3199
commit afa725b44e
15 changed files with 1767 additions and 1137 deletions

View file

@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// JSON password configuration
/// </summary>
public class PasswordConfig
{
/// <summary>
/// Password object configured password
/// </summary>
public string password { get; set; }
/// <summary>
/// Constructor
/// </summary>
public PasswordConfig()
{
}
}
}

View file

@ -1,149 +0,0 @@
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"
// }
// ]
// }
//}
/// <summary>
/// JSON password array configuration object
/// </summary>
//public class PasswordConfig
//{
// /// <summary>
// /// Key used to search for object in JSON array
// /// </summary>
// public string key { get; set; }
// /// <summary>
// /// Friendly name of password object
// /// </summary>
// public string name { get; set; }
// /// <summary>
// /// Password object enabled
// /// </summary>
// public bool enabled { get; set; }
// /// <summary>
// ///
// /// </summary>
// public ushort simplEnabled
// {
// get { return (ushort)(enabled ? 1 : 0); }
// set { enabled = Convert.ToBoolean(value); }
// }
// /// <summary>
// /// Password object configured password
// /// </summary>
// public string password { get; set; }
// /// <summary>
// /// Password type
// /// </summary>
// private int type { get; set; }
// /// <summary>
// /// Password Type for S+
// /// </summary>
// public ushort simplType
// {
// get { return Convert.ToUInt16(type); }
// set { type = value; }
// }
// /// <summary>
// /// Password path
// /// **FUTURE** implementation of saving passwords recieved from Fusion or other external sources back to config
// /// </summary>
// public string path { get; set; }
// /// <summary>
// /// Constructor
// /// </summary>
// 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"
// }
// }
// }
//}
/// <summary>
/// JSON password array configuration object
/// </summary>
public class PasswordConfig
{
/// <summary>
/// Password object configured password
/// </summary>
public string password { get; set; }
/// <summary>
/// Constructor
/// </summary>
public PasswordConfig()
{
}
}
/// <summary>
/// Global JSON object
/// </summary>
//public class GlobalConfig
//{
// //public List<PasswordConfig> passwords { get; set; }
// public Dictionary<uint, PasswordConfig> passwords { get; set; }
// /// <summary>
// /// Constructor
// /// </summary>
// public GlobalConfig()
// {
// }
//}
/// <summary>
/// Root JSON object
/// </summary>
//public class RootObject
//{
// public GlobalConfig global { get; set; }
//}
}

View file

@ -1,207 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement
{
public class PasswordClient
{
/// <summary>
/// Password Client
/// </summary>
public PasswordConfig Client { get; set; }
/// <summary>
/// Used to build the password entered by the user
/// </summary>
public string PasswordToValidate { get; set; }
/// <summary>
/// Boolean event
/// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary>
/// Ushort event
/// </summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// <summary>
/// String event
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// Constructor
/// </summary>
public PasswordClient()
{
}
/// <summary>
/// Initialize method
/// </summary>
/// <param name="key"></param>
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);
}
/// <summary>
/// Retrieves password by key
/// </summary>
/// <param name="key"></param>
//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);
//}
/// <summary>
/// Retrieve password by index
/// </summary>
/// <param name="index"></param>
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);
}
/// <summary>
/// Password validation method
/// </summary>
/// <param name="password"></param>
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();
}
/// <summary>
/// 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
/// </summary>
/// <param name="data"></param>
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);
}
/// <summary>
/// Clears the user entered password and resets the LEDs
/// </summary>
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);
}
/// <summary>
/// Protected boolean change event handler
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
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);
}
}
/// <summary>
/// Protected ushort change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
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);
}
}
/// <summary>
/// Protected string change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
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);
}
}
}
}

View file

@ -1,233 +0,0 @@
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
{
/// <summary>
/// List of passwords configured
/// </summary>
public static Dictionary<uint, PasswordConfig> Passwords = new Dictionary<uint, PasswordConfig>();
private Dictionary<uint, PasswordConfig> TempPasswords = new Dictionary<uint, PasswordConfig>();
CTimer UpdateTimer;
public long UpdateTimerElapsedMs = 5000;
/// <summary>
/// Boolean event
/// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary>
/// Ushort event
/// </summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// <summary>
/// String event
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// Constructor
/// </summary>
public PasswordManager()
{
Passwords.Clear();
}
/// <summary>
/// Initialize method
/// </summary>
/// <param name="key"></param>
/// <param name="uniqueId"></param>
//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<RootObject>().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);
// }
//}
/// <summary>
/// Adds password to the list
/// </summary>
/// <param name="password"></param>
//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));
//}
/// <summary>
/// Removes password from the list
/// </summary>
/// <param name="password"></param>
//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);
//}
/// <summary>
/// Updates password stored in the dictonary
/// </summary>
/// <param name="uniqueId"></param>
/// <param name="key"></param>
/// <param name="password"></param>
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();
}
}
/// <summary>
/// Stores the updated passwords in TempPassword in the Passwords dictionary
/// </summary>
private void StorePassword()
{
UpdateTimer.Stop();
foreach (var tempPw in TempPasswords)
{
Passwords[tempPw.Key] = tempPw.Value;
}
TempPasswords.Clear();
}
/// <summary>
/// Protected boolean change event handler
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
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);
}
}
/// <summary>
/// Protected ushort change event handler
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
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);
}
}
/// <summary>
/// Protected string change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
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);
}
}
}
}

View file

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement
@ -11,14 +8,16 @@ namespace PepperDash.Core.PasswordManagement
/// </summary>
public class PasswordClient
{
/// <summary>
/// Password selected key
/// </summary>
public string Username { get; set; }
/// <summary>
/// Password selected
/// </summary>
public string Password { get; set; }
/// <summary>
/// Password selected key
/// </summary>
public ushort Key { get; set; }
/// <summary>
/// Used to build the password entered by the user
/// </summary>
@ -42,7 +41,11 @@ namespace PepperDash.Core.PasswordManagement
/// </summary>
public PasswordClient()
{
PasswordManager.PasswordChange += new EventHandler<StringChangeEventArgs>(PasswordManager_PasswordChange);
PasswordManager.Initialized += (sender, args) => Initialize();
PasswordManager.PasswordChange += PasswordManager_PasswordChange;
if (PasswordManager.IsInitialized)
Initialize();
}
/// <summary>
@ -50,52 +53,108 @@ namespace PepperDash.Core.PasswordManagement
/// </summary>
public void Initialize()
{
OnBoolChange(false, 0, PasswordManagementConstants.PasswordInitializedChange);
OnBoolChange(false, 0, PasswordConstants.Initialized);
Password = "";
PasswordToValidate = "";
Username = string.Empty;
Password = string.Empty;
PasswordToValidate = string.Empty;
OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange);
OnBoolChange(true, 0, PasswordManagementConstants.PasswordInitializedChange);
OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordConstants.Count);
OnUshrtChange(0, 0, PasswordConstants.PasswordLength);
OnStringChange(string.Empty, 0, PasswordConstants.UsernameValidated);
OnStringChange("Password client initilaized", 0, PasswordConstants.Message);
OnBoolChange(true, 0, PasswordConstants.Initialized);
}
/// <summary>
/// Retrieve password by index
/// Sends clear/0 values to S+ wrapper
/// </summary>
/// <param name="key"></param>
public void GetPasswordByIndex(ushort key)
public void ClearOutputs()
{
OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange);
//OnBoolChange(false, 0, PasswordConstants.UsernameValidated);
OnUshrtChange(0, 0, PasswordConstants.PasswordLength);
OnStringChange(string.Empty, 0, PasswordConstants.UsernameValidated);
OnStringChange(string.Empty, 0, PasswordConstants.Message);
}
Key = key;
/// <summary>
/// Sends clear/0 values to S+ wrapper
/// </summary>
/// <param name="result"></param>
public void UpdateOutputs(PasswordValidationResult result)
{
OnBoolChange(result.IsValid, 0, PasswordConstants.UsernameValidated);
OnUshrtChange((ushort)(string.IsNullOrEmpty(result.Password) ? 0 : result.Password.Length), 0, PasswordConstants.PasswordLength);
OnStringChange(string.Empty, 0, PasswordConstants.UsernameValidated);
OnStringChange(result.Message, 0, PasswordConstants.Message);
}
var pw = PasswordManager.Passwords[Key];
if (pw == null)
/// <summary>
/// Validate username
/// </summary>
/// <param name="username"></param>
public void ValidateUsername(string username)
{
if (string.IsNullOrEmpty(username))
{
OnUshrtChange(0, 0, PasswordManagementConstants.PasswordLengthChange);
OnStringChange("Username is null or empty", 0, PasswordConstants.Message);
return;
}
Password = pw;
OnUshrtChange((ushort)Password.Length, 0, PasswordManagementConstants.PasswordLengthChange);
OnUshrtChange(key, 0, PasswordManagementConstants.PasswordSelectIndexChange);
}
var result = PasswordManager.ValidateUsername(username);
if (!result.IsValid)
{
UpdateOutputs(result);
return;
}
Username = username;
Password = result.Password;
PasswordToValidate = string.Empty;
OnStringChange(Username, 0, PasswordConstants.UsernameValidated);
OnBoolChange(result.IsValid, 0, PasswordConstants.UsernameValidated);
OnUshrtChange((ushort)result.Password.Length, 0, PasswordConstants.PasswordLength);
OnStringChange(result.Message, 0, PasswordConstants.Message);
}
/// <summary>
/// Password validation method
/// Validate username and passowrd
/// </summary>
/// <param name="username"></param>
/// <param name="password"></param>
public void ValidatePassword(string password)
public void ValidateUsernameAndPassword(string username, string password)
{
if (string.IsNullOrEmpty(password))
if (string.IsNullOrEmpty(username))
{
OnStringChange("Username is null or empty", 0, PasswordConstants.Message);
return;
}
if (string.Equals(Password, password))
OnBoolChange(true, 0, PasswordManagementConstants.PasswordValidationChange);
else
OnBoolChange(false, 0, PasswordManagementConstants.PasswordValidationChange);
if (string.IsNullOrEmpty(password))
{
OnStringChange("Password is null or empty", 0, PasswordConstants.Message);
return;
}
ClearPassword();
var result = PasswordManager.ValidateUsernameAndPassword(username, password);
if (!result.IsValid)
{
UpdateOutputs(result);
return;
}
OnBoolChange(result.IsValid, 0, PasswordConstants.PasswordValidated);
OnStringChange(result.Message, 0, PasswordConstants.Message);
// Clear entered password and reset outputs after a delay (make configurable as needed)
const long clearDelayMs = 5000;
new CTimer(_ =>
{
ClearPassword();
ClearOutputs();
}, clearDelayMs);
}
/// <summary>
@ -106,10 +165,22 @@ namespace PepperDash.Core.PasswordManagement
public void BuildPassword(string data)
{
PasswordToValidate = String.Concat(PasswordToValidate, data);
OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedFeedbackChange);
OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordConstants.LedFeedback);
if (PasswordToValidate.Length == Password.Length)
ValidatePassword(PasswordToValidate);
if (string.IsNullOrEmpty(Password))
{
OnStringChange("Cannot validate password, password is null or empty", 0, PasswordConstants.Message);
return;
}
if (PasswordToValidate.Length != Password.Length) return;
if (string.IsNullOrEmpty(Username))
{
OnStringChange("Cannot validate password, username is null or empty", 0, PasswordConstants.Message);
return;
}
ValidateUsernameAndPassword(Username, PasswordToValidate);
}
/// <summary>
@ -117,8 +188,8 @@ namespace PepperDash.Core.PasswordManagement
/// </summary>
public void ClearPassword()
{
PasswordToValidate = "";
OnBoolChange(false, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedFeedbackChange);
PasswordToValidate = string.Empty;
OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordConstants.LedFeedback);
}
/// <summary>
@ -126,12 +197,23 @@ namespace PepperDash.Core.PasswordManagement
/// </summary>
public void DeletePasswordCharacter()
{
ushort PasswordLengthBeforeDelete = (ushort)PasswordToValidate.Length;
PasswordToValidate = PasswordToValidate.Substring(0, PasswordToValidate.Length - 1);
OnBoolChange(false, (ushort)PasswordLengthBeforeDelete, PasswordManagementConstants.PasswordLedFeedbackChange);
// Verify if OnStringChange is needed to update the S+ wrapper with the entered PasswordToValidate
if (string.IsNullOrEmpty(PasswordToValidate))
return;
var previousLength = (ushort)PasswordToValidate.Length;
// Remove last entered character
PasswordToValidate = PasswordToValidate.Substring(0, PasswordToValidate.Length - 1);
// Turn off the last LED that was on (old length index)
OnBoolChange(false, previousLength, PasswordConstants.LedFeedback);
// Send updated length back to S+
OnUshrtChange((ushort)PasswordToValidate.Length, 0, PasswordConstants.PasswordLength);
}
#region event handlers
/// <summary>
/// Protected boolean change event handler
/// </summary>
@ -141,12 +223,10 @@ namespace PepperDash.Core.PasswordManagement
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);
}
if (handler == null) return;
var args = new BoolChangeEventArgs(state, type) {Index = index};
BoolChange(this, args);
}
/// <summary>
@ -158,12 +238,10 @@ namespace PepperDash.Core.PasswordManagement
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);
}
if (handler == null) return;
var args = new UshrtChangeEventArgs(value, type) {Index = index};
UshrtChange(this, args);
}
/// <summary>
@ -175,12 +253,20 @@ namespace PepperDash.Core.PasswordManagement
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);
}
if (handler == null) return;
var args = new StringChangeEventArgs(value, type) { Index = index };
StringChange(this, args);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
protected void PasswordManager_Initialized(object sender, BoolChangeEventArgs args)
{
Initialize();
}
/// <summary>
@ -190,13 +276,12 @@ namespace PepperDash.Core.PasswordManagement
/// <param name="args"></param>
protected void PasswordManager_PasswordChange(object sender, StringChangeEventArgs args)
{
//throw new NotImplementedException();
if (Key == args.Index)
{
//PasswordSelectedKey = args.Index;
//PasswordSelected = args.StringValue;
GetPasswordByIndex(args.Index);
if (Username == args.StringValue && args.Type == PasswordConstants.PasswordUpdated)
{
// TODO - If the current username password changes, do something
}
}
#endregion
}
}

View file

@ -0,0 +1,24 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// JSON password configuration
/// </summary>
public class PasswordConfig
{
/// <summary>
/// Dictionary of user passwords. Key is the username, value is the password
/// </summary>
[JsonProperty("passwords")]
public Dictionary<string, string> Passwords { get; set; }
/// <summary>
/// Constructor
/// </summary>
public PasswordConfig()
{
}
}
}

View file

@ -1,57 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// Constants
/// </summary>
public class PasswordManagementConstants
{
/// <summary>
/// Generic boolean value change constant
/// </summary>
public const ushort BoolValueChange = 1;
/// <summary>
/// Evaluated boolean change constant
/// </summary>
public const ushort PasswordInitializedChange = 2;
/// <summary>
/// Update busy change const
/// </summary>
public const ushort PasswordUpdateBusyChange = 3;
/// <summary>
/// Password is valid change constant
/// </summary>
public const ushort PasswordValidationChange = 4;
/// <summary>
/// Password LED change constant
/// </summary>
public const ushort PasswordLedFeedbackChange = 5;
/// <summary>
/// Generic ushort value change constant
/// </summary>
public const ushort UshrtValueChange = 101;
/// <summary>
/// Password count
/// </summary>
public const ushort PasswordManagerCountChange = 102;
/// <summary>
/// Password selecte index change constant
/// </summary>
public const ushort PasswordSelectIndexChange = 103;
/// <summary>
/// Password length
/// </summary>
public const ushort PasswordLengthChange = 104;
/// <summary>
/// Generic string value change constant
/// </summary>
public const ushort StringValueChange = 201;
}

namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// Constants
/// </summary>
public class PasswordConstants
{
/// <summary>
/// Generic boolean value change constant
/// </summary>
public const ushort BoolValueChange = 1;
/// <summary>
/// Evaluated boolean change constant
/// </summary>
public const ushort Initialized = 2;
/// <summary>
/// Update busy change const
/// </summary>
public const ushort UpdateBusy = 3;
/// <summary>
/// Username is valid change constant
/// </summary>
public const ushort UsernameValidated = 4;
/// <summary>
/// Password is valid change constant
/// </summary>
public const ushort PasswordValidated = 5;
/// <summary>
/// Password LED change constant
/// </summary>
public const ushort LedFeedback = 6;
/// <summary>
/// Generic ushort value change constant
/// </summary>
public const ushort UshrtValueChange = 101;
/// <summary>
/// Password count
/// </summary>
public const ushort Count = 102;
/// <summary>
/// Password length
/// </summary>
public const ushort PasswordLength = 104;
/// <summary>
/// Generic string value change constant
/// </summary>
public const ushort StringValueChange = 201;
/// <summary>
/// Password message constant, used to send the password string to clients when a password is updated
/// </summary>
public const ushort Message = 202;
/// <summary>
/// Password updated
/// </summary>
public const ushort PasswordUpdated = 203;
}
}

View file

@ -1,247 +1,285 @@
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
{
/// <summary>
/// Allows passwords to be stored and managed
/// </summary>
public class PasswordManager
{
/// <summary>
/// Public dictionary of known passwords
/// </summary>
public static Dictionary<uint, string> Passwords = new Dictionary<uint, string>();
/// <summary>
/// Private dictionary, used when passwords are updated
/// </summary>
private Dictionary<uint, string> _passwords = new Dictionary<uint, string>();
/// <summary>
/// Timer used to wait until password changes have stopped before updating the dictionary
/// </summary>
CTimer PasswordTimer;
/// <summary>
/// Timer length
/// </summary>
public long PasswordTimerElapsedMs = 5000;
/// <summary>
/// Boolean event
/// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary>
/// Ushort event
/// </summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// <summary>
/// String event
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// Event to notify clients of an updated password at the specified index (uint)
/// </summary>
public static event EventHandler<StringChangeEventArgs> PasswordChange;
/// <summary>
/// Constructor
/// </summary>
public PasswordManager()
{
}
/// <summary>
/// Initialize password manager
/// </summary>
public void Initialize()
{
if (Passwords == null)
Passwords = new Dictionary<uint, string>();
if (_passwords == null)
_passwords = new Dictionary<uint, string>();
OnBoolChange(true, 0, PasswordManagementConstants.PasswordInitializedChange);
}
/// <summary>
/// Updates password stored in the dictonary
/// </summary>
/// <param name="key"></param>
/// <param name="password"></param>
public void UpdatePassword(ushort key, string password)
{
// 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 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]));
if (PasswordTimer == null)
{
PasswordTimer = new CTimer((o) => PasswordTimerElapsed(), PasswordTimerElapsedMs);
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Started"));
OnBoolChange(true, 0, PasswordManagementConstants.PasswordUpdateBusyChange);
}
else
{
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);
}
}
/// <summary>
/// CTimer callback function
/// </summary>
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, 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((ushort)Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange);
}
catch (Exception e)
{
var msg = string.Format("PasswordManager.PasswordTimerElapsed failed:\r{0}", e);
Debug.Console(1, msg);
}
}
/// <summary>
/// Method to change the default timer value, (default 5000ms/5s)
/// </summary>
/// <param name="time"></param>
public void PasswordTimerMs(ushort time)
{
PasswordTimerElapsedMs = Convert.ToInt64(time);
}
/// <summary>
/// Helper method for debugging to see what passwords are in the lists
/// </summary>
public void ListPasswords()
{
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);
}
/// <summary>
/// Protected boolean change event handler
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
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);
}
}
/// <summary>
/// Protected ushort change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
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);
}
}
/// <summary>
/// Protected string change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
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);
}
}
/// <summary>
/// Protected password change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
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);
}
}
}
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// Allows passwords to be stored and managed
/// </summary>
public class PasswordManager
{
/// <summary>
/// Public dictionary of known passwords
/// </summary>
public static Dictionary<string, string> Passwords = new Dictionary<string, string>();
/// <summary>
/// Indicates whether the manager has been initialized
/// </summary>
public static bool IsInitialized { get; private set; }
/// <summary>
/// Tracks keys changed during the debounce window for notification
/// </summary>
private readonly List<string> _pendingChanges = new List<string>();
/// <summary>
/// Timer used to wait until password changes have stopped before updating the dictionary
/// </summary>
CTimer _passwordTimer;
/// <summary>
/// Timer length
/// </summary>
public long PasswordTimerElapsedMs = 5000;
/// <summary>
/// Boolean event
/// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary>
/// Ushort event
/// </summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// <summary>
/// String event
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// Event to notify clients of an updated password at the specified index (uint)
/// </summary>
public static event EventHandler<StringChangeEventArgs> PasswordChange;
/// <summary>
/// Event to notify clients when the manager has been initialized
/// </summary>
public static event EventHandler<BoolChangeEventArgs> Initialized;
/// <summary>
/// Constructor (empty constructor required by S+)
/// </summary>
public PasswordManager()
{
}
/// <summary>
/// Initialize password manager
/// </summary>
public void Initialize()
{
if (Passwords == null)
{
Passwords = new Dictionary<string, string>();
}
OnBoolChange(true, 0, PasswordConstants.Initialized);
IsInitialized = true;
var handler = Initialized;
if (handler != null)
handler(this, new BoolChangeEventArgs(true, PasswordConstants.Initialized));
}
/// <summary>
/// Updates password stored in the dictonary
/// </summary>
/// <param name="key"></param>
/// <param name="password"></param>
public void UpdatePassword(string key, string password)
{
// validate the parameters
if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(password))
{
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: key [{0}] or password are not valid", key, password));
return;
}
try
{
Passwords[key] = password;
if (!_pendingChanges.Contains(key))
_pendingChanges.Add(key);
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: Passwords[{0}] = {1}", key, Passwords[key]));
if (_passwordTimer == null)
{
_passwordTimer = new CTimer((o) => PasswordTimerElapsed(), PasswordTimerElapsedMs);
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Started"));
OnBoolChange(true, 0, PasswordConstants.UpdateBusy);
}
else
{
_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);
}
}
/// <summary>
/// Helper method for debugging to see what passwords are in the lists
/// </summary>
public void ListEntries()
{
Debug.Console(0, "PasswordManager.ListEntries:\r");
foreach (var pw in Passwords)
{
var maskedValue = string.IsNullOrEmpty(pw.Value) ? string.Empty : new string('*', pw.Value.Length);
Debug.Console(0, "Passwords[{0}]: {1}\r", pw.Key, maskedValue);
}
}
/// <summary>
/// Validates the username against the known entries
/// </summary>
/// <param name="username"></param>
public static PasswordValidationResult ValidateUsername(string username)
{
if (Passwords == null)
return PasswordValidationResult.Failure("No entires defined, verify list is initilaized");
if (string.IsNullOrEmpty(username))
return PasswordValidationResult.Failure("Username or password is empty");
string storedPassword;
return !Passwords.TryGetValue(username, out storedPassword)
? PasswordValidationResult.Failure(string.Format("Username '{0}' not found", username))
: PasswordValidationResult.Success("Valid username", storedPassword);
}
/// <summary>
/// Validates the username password against the known entries
/// </summary>
/// <param name="username"></param>
/// <param name="password"></param>
public static PasswordValidationResult ValidateUsernameAndPassword(string username, string password)
{
if (Passwords == null)
return PasswordValidationResult.Failure("No entires defined, verify list is initilaized");
if (string.IsNullOrEmpty(username))
return PasswordValidationResult.Failure("Username is empty or null");
if(string.IsNullOrEmpty(password))
return PasswordValidationResult.Failure("Password is empty or null");
string storedPassword;
if (!Passwords.TryGetValue(username, out storedPassword))
return PasswordValidationResult.Failure(string.Format("Username '{0}' not found", username));
return !string.Equals(storedPassword, password, StringComparison.Ordinal)
? PasswordValidationResult.Failure("Invalid password, verify password and try again")
: PasswordValidationResult.Success("Valid credentials, login was successfull", storedPassword);
}
/// <summary>
/// CTimer callback function
/// </summary>
private void PasswordTimerElapsed()
{
try
{
_passwordTimer.Stop();
Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: CTimer Stopped"));
OnBoolChange(false, 0, PasswordConstants.UpdateBusy);
foreach (var key in _pendingChanges)
{
string value;
if (!Passwords.TryGetValue(key, out value)) continue;
Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: Notifying change for [{0}]", key));
OnPasswordChange(key, 0, PasswordConstants.PasswordUpdated);
}
_pendingChanges.Clear();
OnUshrtChange((ushort)Passwords.Count, 0, PasswordConstants.Count);
}
catch (Exception e)
{
var msg = string.Format("PasswordManager.PasswordTimerElapsed failed:\r{0}", e);
Debug.Console(1, msg);
}
}
/// <summary>
/// Method to change the default timer value, (default 5000ms/5s)
/// </summary>
/// <param name="time"></param>
public void PasswordTimerMs(ushort time)
{
PasswordTimerElapsedMs = Convert.ToInt64(time);
}
#region event handlers
/// <summary>
/// Protected boolean change event handler
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnBoolChange(bool state, ushort index, ushort type)
{
var handler = BoolChange;
if (handler == null) return;
var args = new BoolChangeEventArgs(state, type) {Index = index};
BoolChange(this, args);
}
/// <summary>
/// Protected ushort change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnUshrtChange(ushort value, ushort index, ushort type)
{
var handler = UshrtChange;
if (handler == null) return;
var args = new UshrtChangeEventArgs(value, type) {Index = index};
UshrtChange(this, args);
}
/// <summary>
/// Protected string change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnStringChange(string value, ushort index, ushort type)
{
var handler = StringChange;
if (handler == null) return;
var args = new StringChangeEventArgs(value, type) {Index = index};
StringChange(this, args);
}
/// <summary>
/// Protected password change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnPasswordChange(string value, ushort index, ushort type)
{
var handler = PasswordChange;
if (handler == null) return;
var args = new StringChangeEventArgs(value, type) {Index = index};
PasswordChange(this, args);
}
#endregion
}
}

View file

@ -0,0 +1,54 @@
namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// Represents the result of a password validation attempt
/// </summary>
public class PasswordValidationResult
{
/// <summary>
/// Indicates whether the validation was successful
/// </summary>
public bool IsValid { get; private set; }
/// <summary>
/// Password
/// </summary>
public string Password { get; private set; }
/// <summary>
/// Message describing the validation result
/// </summary>
public string Message { get; private set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="isValid">Whether the validation was successful</param>
/// <param name="message">Message describing the result</param>
/// <param name="password"></param>
public PasswordValidationResult(bool isValid, string message, string password)
{
IsValid = isValid;
Message = message;
Password = password;
}
/// <summary>
/// Creates a successful validation result
/// </summary>
/// <param name="message">The success message</param>
public static PasswordValidationResult Success(string message, string password)
{
return new PasswordValidationResult(true, message, password);
}
/// <summary>
/// Creates a failed validation result with the specified message
/// </summary>
/// <param name="message">The failure reason</param>
public static PasswordValidationResult Failure(string message)
{
return new PasswordValidationResult(false, message, null);
}
}
}

View file

@ -0,0 +1,247 @@
[BEGIN]
Version=1
[END]
[BEGIN]
ObjTp=FSgntr
Sgntr=UserSPlus
RelVrs=1
IntStrVrs=1
SPlusVrs=4.06.00
CrossCplrVrs=1.3
[END]
[BEGIN]
ObjTp=Hd
IncludePath1=..\bin
Cmn1=INPUTS\\--------------------------------------------------------
Cmn2=-----\\Debug (d) \\- enables/disables debugging of password client||1
Cmn3=class\\\\Initialize (d) - REMOVED\\- Clients are automatically initialized||1
Cmn4=via event subscription with the Manager\\\\PasswordValidate (d)||1
Cmn5=*Optional\\- Triggers validate method, the module will automatically||1
Cmn6=trigger the \\ validate method when the entered password equals||1
Cmn7=the length of the \\ selected password\\ \\Keypad (d)\\- Used||1
Cmn8=for basic numeric pins\\\\PasswordSelect[1-10] (d)\\- Allows developer||1
Cmn9=to select different passwords used for validation\\\\PasswordSelectByIndex||1
Cmn10=(a)\\- Alternate method for selecting password used for validation\\
Cmn11=\\PasswordtoValidate (s)\\- Allows developer to supply raw alpha-
Cmn12=numeric text as the password \\ to validate. Typically fed from||1
Cmn13=a keyboard raw output\\ \\OUTPUTS\\----------------------------
Cmn14=---------------------------------\\InitializedFb (d)\\- Feedback||1
Cmn15=the client is initialized\\\\PasswordIsValid (d) *Pulse\\- Pulses||1
Cmn16=when the password entered (pin or raw text) is valid\\\\PasswordIsInvalid||1
Cmn17=(d) *Pulse\\- Pulses when the password entered (pin or raw text)||1
Cmn18=is not valid\\\\PasswordLedFb[1-10] (d)\\- Remains high while the||1
Cmn19=entered password length matches the LED length\\\\PasswordSelectedIndex||1
Cmn20=(a)\\- Feedback of the selected password\\\\PasswordSelectedLength||1
Cmn21=(a)\\- Feedback of the selected password length. Typically drives||1
Cmn22=the LED\\ SRL analog input 'Set Number of Items'\\ \\PasswordToValidateLength||1
Cmn23=(a)\\- Analog feedback of characters entered by user
[END]
[BEGIN]
ObjTp=Symbol
Exclusions=1,19,20,21,88,89,167,168,179,213,214,215,216,217,225,226,248,249,266,267,310,362,378,380,405,407,408,409,478,522,537,554,586,590,611,624,718,756,767,830,841,842,854,883,955,1032,1062,1079,1128,1129,1134,1140,1157,1158,1195,1199,1220,1221,1222,1223,1299,1348,1349,1439,1472,1473,1499,1746,1803,1975,2229,2354,2514,2523,2532,2706,2707,3235,3236,3427,3454,3567,3568,3601,3602,3708,3902,3903,3912,3918,3925,3926,4206,4207,
Exclusions_CDS=5
Inclusions_CDS=6,7
Name=PepperDash_Core_Password_Client_A4sA3s_v02.00
SmplCName=PepperDash_Core_Password_Client_A4sA3s_v02.00.usp
Code=1
SysRev5=4.006
SMWRev=3.00.00
InputCue1=[~UNUSED~]
InputSigType1=Digital
InputCue2=[~UNUSED~]
InputSigType2=Digital
InputCue3=[~UNUSED~]
InputSigType3=Digital
InputCue4=DebugEnable
InputSigType4=Digital
InputCue5=[~UNUSED~]
InputSigType5=Digital
InputCue6=[~UNUSED~]
InputSigType6=Digital
InputCue7=ValidateUsername
InputSigType7=Digital
InputCue8=ValidatePassword
InputSigType8=Digital
InputCue9=[~UNUSED~]
InputSigType9=Digital
InputCue10=KeypadClear
InputSigType10=Digital
InputCue11=KeypadBackspace
InputSigType11=Digital
InputCue12=Keypad00
InputSigType12=Digital
InputCue13=Keypad01
InputSigType13=Digital
InputCue14=Keypad02
InputSigType14=Digital
InputCue15=Keypad03
InputSigType15=Digital
InputCue16=Keypad04
InputSigType16=Digital
InputCue17=Keypad05
InputSigType17=Digital
InputCue18=Keypad06
InputSigType18=Digital
InputCue19=Keypad07
InputSigType19=Digital
InputCue20=Keypad08
InputSigType20=Digital
InputCue21=Keypad09
InputSigType21=Digital
OutputCue1=[~UNUSED~]
OutputSigType1=Digital
OutputCue2=[~UNUSED~]
OutputSigType2=Digital
OutputCue3=[~UNUSED~]
OutputSigType3=Digital
OutputCue4=[~UNUSED~]
OutputSigType4=Digital
OutputCue5=InitializedFb
OutputSigType5=Digital
OutputCue6=[~UNUSED~]
OutputSigType6=Digital
OutputCue7=UsernameIsValid
OutputSigType7=Digital
OutputCue8=UsernameIsInvalid
OutputSigType8=Digital
OutputCue9=[~UNUSED~]
OutputSigType9=Digital
OutputCue10=PasswordIsValid
OutputSigType10=Digital
OutputCue11=PasswordIsInvalid
OutputSigType11=Digital
OutputCue12=[~UNUSED~]
OutputSigType12=Digital
OutputCue13=PasswordLedFb[#]
OutputSigType13=Digital
InputList2Cue1=[~UNUSED~]
InputList2SigType1=Serial
InputList2Cue2=[~UNUSED~]
InputList2SigType2=Serial
InputList2Cue3=[~UNUSED~]
InputList2SigType3=Serial
InputList2Cue4=[~UNUSED~]
InputList2SigType4=Serial
InputList2Cue5=[~UNUSED~]
InputList2SigType5=Serial
InputList2Cue6=Username
InputList2SigType6=Serial
InputList2Cue7=Password
InputList2SigType7=Serial
OutputList2Cue1=[~UNUSED~]
OutputList2SigType1=Analog
OutputList2Cue2=PasswordSelectedLength
OutputList2SigType2=Analog
OutputList2Cue3=PasswordToValidateLength
OutputList2SigType3=Analog
OutputList2Cue4=[~UNUSED~]
OutputList2SigType4=Serial
OutputList2Cue5=UsernameFb
OutputList2SigType5=Serial
OutputList2Cue6=MessageFb
OutputList2SigType6=Serial
ParamCue1=[Reference Name]
ParamCue2=ValidatePulseLength
ParamSigType2=Constant
ParamCue3=ValidateUsernameOnChange,0d,1d
ParamSigType3=List
ParamCue4=ValidatePasswordOnChange,0d,1d
ParamSigType4=List
MinVariableInputs=21
MaxVariableInputs=21
MinVariableInputsList2=7
MaxVariableInputsList2=7
MinVariableOutputs=22
MaxVariableOutputs=22
MinVariableOutputsList2=6
MaxVariableOutputsList2=6
MinVariableParams=3
MaxVariableParams=3
Expand=expand_separately
Expand2=expand_inputs_with_outputs
ProgramTree=Logic
SymbolTree=46
UserSymTreeName=PepperDash Technology
Hint=
PdfHelp=
HelpID=
Render=4
Smpl-C=16
CompilerCode=-48
CompilerParamCode=27
CompilerParamCode5=14
NumFixedParams=1
Pp1=1
Pp2=2
Pp3=3
Pp4=4
MPp=4
NVStorage=10
ParamSigType1=String
SmplCInputCue1=o#
SmplCOutputCue1=i#
SmplCInputList2Cue1=an#
SmplCOutputList2Cue1=ai#
SPlus2CompiledName=S2_PepperDash_Core_Password_Client_A4sA3s_v02_00
SymJam=NonExclusive
FileName=PepperDash_Core_Password_Client_A4sA3s_v02.00.ush
SIMPLPlusModuleEncoding=0
clz1=PepperDash_Core
[END]
[BEGIN]
ObjTp=Dp
H=1
Tp=1
NoS=False
[END]
[BEGIN]
ObjTp=Dp
H=2
Tp=1
HD=True
DV=500d
Sgn=0
Lng=False
NF=1
NoS=True
DNF=1
VVS=1
LR=50d
HR=1000d
[END]
[BEGIN]
ObjTp=Dp
H=3
Tp=1
HD=True
DV=0d
Sgn=0
Lng=False
NF=1
NoS=True
DNF=1
VVS=2
VN=2
Val1=0d
Lbl1=False
Val2=1d
Lbl2=True
[END]
[BEGIN]
ObjTp=Dp
H=4
Tp=1
HD=True
DV=0d
Sgn=0
Lng=False
NF=1
NoS=True
DNF=1
VVS=2
VN=2
Val1=0d
Lbl1=False
Val2=1d
Lbl2=True
[END]

View file

@ -0,0 +1,389 @@
/*******************************************************************************************
Dealer Name: PepperDash Technology Corp.
Programmer: PepperDash Technology Corp.
Copyright: 2018
********************************************************************************************
Notice of Ownership and Copyright
The material in which this notice appears is the property of PepperDash Technology Corporation,
which claims copyright under the laws of the United States of America in the entire body of
material and in all parts thereof, regardless of the use to which it is being put. Any use,
in whole or in part, of this material by another party without the express written permission
of PepperDash Technology Corporation is prohibited.
PepperDash Technology Corporation reserves all rights under applicable laws.
*******************************************************************************************/
/*******************************************************************************************
Compiler Directives
(Uncomment and declare compiler directives as needed)
*******************************************************************************************/
#CATEGORY "46" "PepperDash Technology"
#DEFAULT_VOLATILE
#ENABLE_STACK_CHECKING
#ENABLE_TRACE
#ANALOG_SERIAL_EXPAND InputsWithOutputs
#DEFINE_CONSTANT MAX_LEN_SYMBOL 50
#DEFINE_CONSTANT MAX_LEN_MSG 200
#DEFINE_CONSTANT MAX_LEN_STR 250
#DEFINE_CONSTANT MAX_LEN_PULSE 50
#DEFINE_CONSTANT MAX_PASSWORDS 10
#DEFINE_CONSTANT MAX_LEDS 10
#DEFINE_CONSTANT ENUM_TYPE_NONE 0
#DEFINE_CONSTANT ENUM_TYPE_BACKDOOR 1
#DEFINE_CONSTANT ENUM_TYPE_GLOBAL 2
#DEFINE_CONSTANT ENUM_TYPE_SYSTEM 3
#DEFINE_CONSTANT ENUM_TYPE_ROOM 4
#DEFINE_CONSTANT ENUM_TYPE_TECH 5
#DEFINE_CONSTANT ENUM_TYPE_USER 6
#HELP_BEGIN
INPUTS
-------------------------------------------------------------
Debug (d)
- enables/disables debugging of password client class
Initialize (d) - REMOVED
- Clients are automatically initialized via event subscription with the Manager
PasswordValidate (d) *Optional
- Triggers validate method, the module will automatically trigger the
validate method when the entered password equals the length of the
selected password
Keypad (d)
- Used for basic numeric pins
PasswordSelect[1-10] (d)
- Allows developer to select different passwords used for validation
PasswordSelectByIndex (a)
- Alternate method for selecting password used for validation
PasswordtoValidate (s)
- Allows developer to supply raw alpha-numeric text as the password
to validate. Typically fed from a keyboard raw output
OUTPUTS
-------------------------------------------------------------
InitializedFb (d)
- Feedback the client is initialized
PasswordIsValid (d) *Pulse
- Pulses when the password entered (pin or raw text) is valid
PasswordIsInvalid (d) *Pulse
- Pulses when the password entered (pin or raw text) is not valid
PasswordLedFb[1-10] (d)
- Remains high while the entered password length matches the LED length
PasswordSelectedIndex (a)
- Feedback of the selected password
PasswordSelectedLength (a)
- Feedback of the selected password length. Typically drives the LED
SRL analog input 'Set Number of Items'
PasswordToValidateLength (a)
- Analog feedback of characters entered by user
#HELP_END
/*******************************************************************************************
Include Libraries
(Uncomment and include additional libraries as needed)
*******************************************************************************************/
// comment out or remove when PepperDash_Core.clz is local to the module
#INCLUDEPATH "..\bin"
#USER_SIMPLSHARP_LIBRARY "PepperDash_Core"
/*******************************************************************************************
DIGITAL, ANALOG and SERIAL INPUTS and OUTPUTS
(Uncomment and declare inputs and outputs as needed)
*******************************************************************************************/
DIGITAL_INPUT
_SKIP_,
_SKIP_,
_SKIP_,
DebugEnable,
_SKIP_,
_SKIP_,
ValidateUsername,
ValidatePassword,
_SKIP_,
KeypadClear,
KeypadBackspace,
Keypad00,
Keypad01,
Keypad02,
Keypad03,
Keypad04,
Keypad05,
Keypad06,
Keypad07,
Keypad08,
Keypad09;
STRING_INPUT
_SKIP_,
_SKIP_,
_SKIP_,
_SKIP_,
_SKIP_,
Username[MAX_LEN_STR],
Password[MAX_LEN_STR];
DIGITAL_OUTPUT
_SKIP_,
_SKIP_,
_SKIP_,
_SKIP_,
InitializedFb,
_SKIP_,
UsernameIsValid,
UsernameIsInvalid,
_SKIP_,
PasswordIsValid,
PasswordIsInvalid;
ANALOG_OUTPUT
_SKIP_,
PasswordSelectedLength,
PasswordToValidateLength;
STRING_OUTPUT
_SKIP_,
UsernameFb,
MessageFb;
DIGITAL_OUTPUT
_SKIP_,
PasswordLedFb[MAX_LEDS, MAX_LEDS];
/*******************************************************************************************
SIMPL # Class to be instantiated
*******************************************************************************************/
PasswordClient thisClient;
/*******************************************************************************************
Parameters
(Uncomment and declare parameters as needed)
*******************************************************************************************/
INTEGER_PARAMETER
ValidatePulseLength,
ValidateUsernameOnChange,
ValidatePasswordOnChange;
/*******************************************************************************************
Parameter Properties
(Uncomment and declare parameter properties as needed)
*******************************************************************************************/
#BEGIN_PARAMETER_PROPERTIES ValidatePulseLength
propValidUnits = unitDecimal;
propBounds = 50d, 1000d;
propDefaultValue = 500d;
#END_PARAMETER_PROPERTIES
#BEGIN_PARAMETER_PROPERTIES ValidateUsernameOnChange
propValidUnits = unitDecimal;
propDefaultValue = 0d;
propList = { 0d, "False" }, { 1d, "True" };
#END_PARAMETER_PROPERTIES
#BEGIN_PARAMETER_PROPERTIES ValidatePasswordOnChange
propValidUnits = unitDecimal;
propDefaultValue = 0d;
propList = { 0d, "False" }, { 1d, "True" };
#END_PARAMETER_PROPERTIES
/*******************************************************************************************
Structure Definitions
(Uncomment and define structure definitions as needed)
Note: Be sure to initialize all declared STRING variables as needed
For example, in Function Main: struct.myString = "";
*******************************************************************************************/
/*******************************************************************************************
Global Variables
(Uncomment and declare global variables as needed)
Note: Be sure to initialize all declared STRING variables as needed
For example, in Function Main: myString = "";
*******************************************************************************************/
String
strUsername[MAX_LEN_STR],
strPassword[MAX_LEN_STR];
/*******************************************************************************************
Functions
(Add any additional functions here)
Note: Functions must be physically placed before the location in
the code that calls them.
*******************************************************************************************/
EventHandler BoolChanged(PasswordClient sender, BoolChangeEventArgs args)
{
Switch(args.Type)
{
Case(PasswordConstants.BoolValueChange):
{
// generic bool change
}
Case(PasswordConstants.Initialized):
{
InitializedFb = args.IntValue;
}
Case(PasswordConstants.UsernameValidated):
{
If(args.IntValue = 1)
{
Pulse(ValidatePulseLength, UsernameIsValid);
strPassword = "";
}
Else
{
Pulse(ValidatePulseLength, UsernameIsInvalid);
strUsername = "";
strPassword = "";
}
}
Case(PasswordConstants.PasswordValidated):
{
If(args.IntValue = 1)
{
Pulse(ValidatePulseLength, PasswordIsValid);
strUsername = "";
strPassword = "";
}
Else
{
Pulse(ValidatePulseLength, PasswordIsInvalid);
//strUsername = "";
strPassword = "";
}
}
Case(PasswordConstants.LedFeedback):
{
If(DebugEnable) Trace("LedFeedback: Type[%u] Index[%u] IntValue[%u]\r", args.Type, args.Index, args.IntValue);
If(args.Index = 0)
SetArray(PasswordLedFb, 0);
Else
{
PasswordToValidateLength = args.Index;
PasswordLedFb[args.Index] = args.IntValue;
}
}
Default:
{
If(DebugEnable) Trace("BoolChanged: args[%u].Type[%u] = %u\r", args.Index, args.Type, args.IntValue);
}
}
}
EventHandler UshrtChanged(PasswordClient sender, UshrtChangeEventArgs args)
{
Switch(args.Type)
{
Case(PasswordConstants.UshrtValueChange):
{
// generic ushort change
}
Case(PasswordConstants.PasswordLength):
{
PasswordSelectedLength = args.IntValue;
}
Default:
{
If(DebugEnable) Trace("UshortChanged: args[%u].Type[%u] = %u\r", args.Index, args.Type, args.IntValue);
}
}
}
EventHandler StringChanged(PasswordClient sender, StringChangeEventArgs args)
{
Switch(args.Type)
{
Case(PasswordConstants.StringValueChange):
{
// generic string change
}
Case(PasswordConstants.UsernameValidated):
{
UsernameFb = args.StringValue;
}
Case(PasswordConstants.Message):
{
MessageFb = args.StringValue;
}
Default:
{
If(DebugEnable) Trace("StringChanged: args[%u].Type[%u] = %s\r", args.Index, args.Type, args.StringValue);
}
}
}
/*******************************************************************************************
Event Handlers
(Uncomment and declare additional event handlers as needed)
*******************************************************************************************/
Threadsafe Change Username
{
strUsername = Username;
If(ValidateUsernameOnChange)
{
thisClient.ValidateUsername(strUsername);
}
}
Threadsafe Change Password
{
strPassword = Password;
If(ValidatePasswordOnChange)
{
thisClient.ValidateUsernameAndPassword(strUsername, strPassword);
}
}
Push ValidateUsername
{
thisClient.ValidateUsername(strUsername);
}
Push ValidatePassword
{
thisClient.ValidateUsernameAndPassword(strUsername, strPassword);
}
Push Keypad00 { thisClient.BuildPassword("0"); }
Push Keypad01 { thisClient.BuildPassword("1"); }
Push Keypad02 { thisClient.BuildPassword("2"); }
Push Keypad03 { thisClient.BuildPassword("3"); }
Push Keypad04 { thisClient.BuildPassword("4"); }
Push Keypad05 { thisClient.BuildPassword("5"); }
Push Keypad06 { thisClient.BuildPassword("6"); }
Push Keypad07 { thisClient.BuildPassword("7"); }
Push Keypad08 { thisClient.BuildPassword("8"); }
Push Keypad09 { thisClient.BuildPassword("9"); }
Push KeypadClear { thisClient.ClearPassword(); }
Push KeypadBackspace { thisClient.DeletePasswordCharacter(); }
/*******************************************************************************************
Main()
Uncomment and place one-time startup code here
(This code will get called when the system starts up)
*******************************************************************************************/
Function Main()
{
WaitForInitializationComplete();
RegisterEvent(thisClient, BoolChange, BoolChanged);
RegisterEvent(thisClient, UshrtChange, UshrtChanged);
RegisterEvent(thisClient, StringChange, StringChanged);
}

View file

@ -0,0 +1,134 @@
[BEGIN]
Version=1
[END]
[BEGIN]
ObjTp=FSgntr
Sgntr=UserSPlus
RelVrs=1
IntStrVrs=1
SPlusVrs=4.06.00
CrossCplrVrs=1.3
[END]
[BEGIN]
ObjTp=Hd
IncludePath1=..\bin
Cmn1=INPUTS\\--------------------------------------------------------
Cmn2=-------------\\DebugEnable (d)\\- Enables/disables debug of the||1
Cmn3=password manager class\\\\Initialize (d)\\- Initializes the password||1
Cmn4=manager class\\\\ListPassword (d)\\- Prints the configured passwords||1
Cmn5=to console\\\\PasswordUpdate[1-10] (s)\\- Accepts alpha-numeric||1
Cmn6=pins/passwords that will be used\\ to validate clients against\\
Cmn7=- These values can be driven statically from code (msend/sio), from||1
Cmn8=config,\\ or from Fusion custom propeties.\\\\ \\OUTPUTS\\---
Cmn9=----------------------------------------------------------------
Cmn10=--\\InitializeFb (d)\\- Password manager class initialized feedback\\
Cmn11=\\PasswordCout (a)\\- Analog feedback of current number of passwords||1
Cmn12=configured\\\\Username\\- Can be an alpha-numeric username OR will||1
Cmn13=become the index represented as a sring\\\\Password\\- Passowrd||1
Cmn14=for the username||1
[END]
[BEGIN]
ObjTp=Symbol
Exclusions=1,19,20,21,88,89,167,168,179,213,214,215,216,217,225,226,248,249,266,267,310,362,378,380,405,407,408,409,478,522,537,554,586,590,611,624,718,756,767,830,841,842,854,883,955,1032,1062,1079,1128,1129,1134,1140,1157,1158,1195,1199,1220,1221,1222,1223,1299,1348,1349,1439,1472,1473,1499,1746,1803,1975,2229,2354,2514,2523,2532,2706,2707,3235,3236,3427,3454,3567,3568,3601,3602,3708,3902,3903,3912,3918,3925,3926,4206,4207,
Exclusions_CDS=5
Inclusions_CDS=6,7
Name=PepperDash_Core_Password_Manager_A4sA3s_v02.00
SmplCName=PepperDash_Core_Password_Manager_A4sA3s_v02.00.usp
Code=1
SysRev5=4.006
SMWRev=3.00.00
InputCue1=[~UNUSED~]
InputSigType1=Digital
InputCue2=DebugEnable
InputSigType2=Digital
InputCue3=Initialize
InputSigType3=Digital
InputCue4=[~UNUSED~]
InputSigType4=Digital
InputCue5=ListEntries
InputSigType5=Digital
OutputCue1=[~UNUSED~]
OutputSigType1=Digital
OutputCue2=[~UNUSED~]
OutputSigType2=Digital
OutputCue3=InitializedFb
OutputSigType3=Digital
OutputCue4=[~UNUSED~]
OutputSigType4=Digital
OutputCue5=[~UNUSED~]
OutputSigType5=Digital
InputList2Cue1=[~UNUSED~]
InputList2SigType1=Serial
InputList2Cue2=Username[1]
InputList2SigType2=Serial
InputList2Cue3=Username[2]
InputList2SigType3=Serial
InputList2Cue4=Username[3]
InputList2SigType4=Serial
InputList2Cue5=Username[4]
InputList2SigType5=Serial
InputList2Cue6=Username[5]
InputList2SigType6=Serial
InputList2Cue7=Username[6]
InputList2SigType7=Serial
InputList2Cue8=Username[7]
InputList2SigType8=Serial
InputList2Cue9=Username[8]
InputList2SigType9=Serial
InputList2Cue10=Username[9]
InputList2SigType10=Serial
InputList2Cue11=Username[10]
InputList2SigType11=Serial
InputList2Cue12=[~UNUSED~]
InputList2SigType12=Serial
InputList2Cue13=Password[#]
InputList2SigType13=Serial
OutputList2Cue1=[~UNUSED~]
OutputList2SigType1=Analog
OutputList2Cue2=PasswordCount
OutputList2SigType2=Analog
ParamCue1=[Reference Name]
MinVariableInputs=5
MaxVariableInputs=5
MinVariableInputsList2=22
MaxVariableInputsList2=22
MinVariableOutputs=5
MaxVariableOutputs=5
MinVariableOutputsList2=2
MaxVariableOutputsList2=2
MinVariableParams=0
MaxVariableParams=0
Expand=expand_inputs_with_outputs
Expand2=expand_inputs_with_outputs
ProgramTree=Logic
SymbolTree=46
UserSymTreeName=PepperDash Technology
Hint=
PdfHelp=
HelpID=
Render=4
Smpl-C=16
CompilerCode=-48
CompilerParamCode=27
CompilerParamCode5=14
NumFixedParams=1
Pp1=1
MPp=1
NVStorage=10
ParamSigType1=String
SmplCInputCue1=o#
SmplCOutputCue1=i#
SmplCInputList2Cue1=an#
SmplCOutputList2Cue1=ai#
SPlus2CompiledName=S2_PepperDash_Core_Password_Manager_A4sA3s_v02_00
SymJam=NonExclusive
FileName=PepperDash_Core_Password_Manager_A4sA3s_v02.00.ush
SIMPLPlusModuleEncoding=0
clz1=PepperDash_Core
[END]
[BEGIN]
ObjTp=Dp
H=1
Tp=1
NoS=False
[END]

View file

@ -0,0 +1,257 @@
/*******************************************************************************************
Dealer Name: PepperDash Technology Corp.
Programmer: PepperDash Technology Corp.
Copyright: 2026
********************************************************************************************
Notice of Ownership and Copyright
The material in which this notice appears is the property of PepperDash Technology Corporation,
which claims copyright under the laws of the United States of America in the entire body of
material and in all parts thereof, regardless of the use to which it is being put. Any use,
in whole or in part, of this material by another party without the express written permission
of PepperDash Technology Corporation is prohibited.
PepperDash Technology Corporation reserves all rights under applicable laws.
*******************************************************************************************/
/*******************************************************************************************
Compiler Directives
(Uncomment and declare compiler directives as needed)
*******************************************************************************************/
#CATEGORY "46" "PepperDash Technology"
#DEFAULT_VOLATILE
#ENABLE_STACK_CHECKING
#ENABLE_TRACE
#DIGITAL_EXPAND InputsWithOutputs
#ANALOG_SERIAL_EXPAND InputsWithOutputs
#DEFINE_CONSTANT MAX_LEN_SYMBOL 50
#DEFINE_CONSTANT MAX_LEN_MSG 200
#DEFINE_CONSTANT MAX_LEN_STR 250
#DEFINE_CONSTANT MAX_PASSWORDS 10
#HELP_BEGIN
INPUTS
---------------------------------------------------------------------
DebugEnable (d)
- Enables/disables debug of the password manager class
Initialize (d)
- Initializes the password manager class
ListPassword (d)
- Prints the configured passwords to console
PasswordUpdate[1-10] (s)
- Accepts alpha-numeric pins/passwords that will be used
to validate clients against
- These values can be driven statically from code (msend/sio), from config,
or from Fusion custom propeties.
OUTPUTS
---------------------------------------------------------------------
InitializeFb (d)
- Password manager class initialized feedback
PasswordCout (a)
- Analog feedback of current number of passwords configured
#HELP_END
/*******************************************************************************************
Include Libraries
(Uncomment and include additional libraries as needed)
*******************************************************************************************/
// comment out or remove when PepperDash_Core.clz is local to the module
#INCLUDEPATH "..\bin"
#USER_SIMPLSHARP_LIBRARY "PepperDash_Core"
/*******************************************************************************************
DIGITAL, ANALOG and SERIAL INPUTS and OUTPUTS
(Uncomment and declare inputs and outputs as needed)
*******************************************************************************************/
DIGITAL_INPUT
_SKIP_,
DebugEnable,
Initialize,
_SKIP_,
ListEntries;
STRING_INPUT
_SKIP_,
Username[MAX_PASSWORDS][MAX_LEN_STR],
_SKIP_,
Password[MAX_PASSWORDS,MAX_PASSWORDS][MAX_LEN_STR];
DIGITAL_OUTPUT
_SKIP_,
_SKIP_,
InitializedFb,
_SKIP_,
_SKIP_;
ANALOG_OUTPUT
_SKIP_,
PasswordCount;
#HELP_BEGIN
Username
- Can be an alpha-numeric username OR will become the index represented as a sring
Password
- Passowrd for the username
#HELP_END
/*******************************************************************************************
SIMPL # Class to be instantiated
*******************************************************************************************/
PasswordManager thisManager;
/*******************************************************************************************
Parameters
(Uncomment and declare parameters as needed)
*******************************************************************************************/
/*******************************************************************************************
Parameter Properties
(Uncomment and declare parameter properties as needed)
*******************************************************************************************/
/*******************************************************************************************
Structure Definitions
(Uncomment and define structure definitions as needed)
Note: Be sure to initialize all declared STRING variables as needed
For example, in Function Main: struct.myString = "";
*******************************************************************************************/
/*******************************************************************************************
Global Variables
(Uncomment and declare global variables as needed)
Note: Be sure to initialize all declared STRING variables as needed
For example, in Function Main: myString = "";
*******************************************************************************************/
/*******************************************************************************************
Functions
(Add any additional functions here)
Note: Functions must be physically placed before the location in
the code that calls them.
*******************************************************************************************/
Function UpdatePassword(Integer nKey)
{
String un[MAX_LEN_STR];
If(Len(Username[nKey]) = 0)
{
un = ItoA(nKey);
}
Else
{
un = Username[nKey];
}
thisManager.UpdatePassword(un, Password[nKey]);
}
EventHandler BoolChanged(PasswordManager sender, BoolChangeEventArgs args)
{
Integer i;
Switch(args.Type)
{
Case(PasswordConstants.BoolValueChange):
{
// generic bool change
}
Case(PasswordConstants.Initialized):
{
InitializedFb = args.IntValue;
If(InitializedFb)
{
For(i = 1 To MAX_PASSWORDS)
{
UpdatePassword(i);
}
}
}
Case(PasswordConstants.UpdateBusy):
{
If(DebugEnable) Trace("UpdateBusy: args[%u].Type[%u] = %u\r", args.Index, args.Type, args.IntValue);
}
Default:
{
If(DebugEnable) Trace("BoolChanged: args[%u].Type[%u] = %u\r", args.Index, args.Type, args.IntValue);
}
}
}
EventHandler UshrtChanged(PasswordManager sender, UshrtChangeEventArgs args)
{
Switch(args.Type)
{
Case(PasswordConstants.UshrtValueChange):
{
// generic ushort change
}
Case(PasswordConstants.Count):
{
PasswordCount = args.IntValue;
}
Default:
{
If(DebugEnable) Trace("UshortChanged: args[%u].Type[%u] = %u\r", args.Index, args.Type, args.IntValue);
}
}
}
EventHandler StringChanged(PasswordManager sender, StringChangeEventArgs args)
{
Switch(args.Type)
{
Case(PasswordConstants.StringValueChange):
{
// generic string change
}
Default:
{
If(DebugEnable) Trace("StringChanged: args[%u].Type[%u] = %s\r", args.Index, args.Type, args.StringValue);
}
}
}
/*******************************************************************************************
Event Handlers
(Uncomment and declare additional event handlers as needed)
*******************************************************************************************/
Push Initialize
{
If(InitializedFb)
Return;
thisManager.Initialize();
}
Push ListEntries
{
thisManager.ListEntries();
}
Threadsafe Change Password
{
If(InitializedFb)
UpdatePassword(GetLastModifiedArrayIndex());
}
/*******************************************************************************************
Main()
Uncomment and place one-time startup code here
(This code will get called when the system starts up)
*******************************************************************************************/
Function Main()
{
RegisterEvent(thisManager, BoolChange, BoolChanged);
RegisterEvent(thisManager, UshrtChange, UshrtChanged);
RegisterEvent(thisManager, StringChange, StringChanged);
WaitForInitializationComplete();
}

View file

@ -1,156 +1,157 @@
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{87E29B4C-569B-4368-A4ED-984AC1440C96}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PepperDash.Core</RootNamespace>
<AssemblyName>PepperDash_Core</AssemblyName>
<ProjectTypeGuids>{0B4745B0-194B-4BB6-8E21-E9057CA92500};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PlatformFamilyName>WindowsCE</PlatformFamilyName>
<PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
<OSVersion>5.0</OSVersion>
<DeployDirSuffix>SmartDeviceProject1</DeployDirSuffix>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<NativePlatformName>Windows CE</NativePlatformName>
<FormFactorID>
</FormFactorID>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<DocumentationFile>bin\PepperDash_Core.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<DocumentationFile>bin\PepperDash_Core.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpCWSHelperInterface, Version=2.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCWSHelperInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpHelperInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpNewtonsoft, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpNewtonsoft.dll</HintPath>
</Reference>
<Reference Include="SimplSharpReflectionInterface, Version=1.0.5583.25238, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Compile Include="CommunicationExtras.cs" />
<Compile Include="Comm\CommunicationStreamDebugging.cs" />
<Compile Include="Comm\ControlPropertiesConfig.cs" />
<Compile Include="Comm\GenericSecureTcpIpClient.cs" />
<Compile Include="Comm\GenericTcpIpClient_ForServer.cs" />
<Compile Include="Comm\GenericHttpSseClient.cs" />
<Compile Include="Comm\GenericSecureTcpIpServer.cs" />
<Compile Include="Comm\GenericSecureTcpIpClient_ForServer.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Comm\eControlMethods.cs" />
<Compile Include="Comm\FINISH CommStatic.cs" />
<Compile Include="Comm\CommunicationGather.cs" />
<Compile Include="Comm\EventArgs.cs" />
<Compile Include="Comm\GenericSshClient.cs" />
<Compile Include="Comm\GenericUdpServer.cs" />
<Compile Include="Comm\QscCoreDoubleTcpIpClient.cs" />
<Compile Include="Comm\TcpClientConfigObject.cs" />
<Compile Include="Comm\TcpServerConfigObject.cs" />
<Compile Include="Config\PortalConfigReader.cs" />
<Compile Include="CoreInterfaces.cs" />
<Compile Include="Web\RequestHandlers\DefaultRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\WebApiBaseRequestHandler.cs" />
<Compile Include="Web\WebApiServer.cs" />
<Compile Include="EventArgs.cs" />
<Compile Include="GenericRESTfulCommunications\Constants.cs" />
<Compile Include="GenericRESTfulCommunications\GenericRESTfulClient.cs" />
<Compile Include="JsonStandardObjects\EventArgs and Constants.cs" />
<Compile Include="JsonStandardObjects\JsonToSimplDeviceConfig.cs" />
<Compile Include="JsonStandardObjects\JsonToSimplDevice.cs" />
<Compile Include="JsonToSimpl\JsonToSimplPortalFileMaster.cs" />
<Compile Include="Logging\Debug.cs" />
<Compile Include="Logging\DebugContext.cs" />
<Compile Include="Logging\DebugMemory.cs" />
<Compile Include="Device.cs" />
<Compile Include="Comm\GenericTcpIpServer.cs" />
<Compile Include="EthernetHelper.cs" />
<Compile Include="Comm\GenericTcpIpClient.cs" />
<Compile Include="JsonToSimpl\Constants.cs" />
<Compile Include="JsonToSimpl\Global.cs" />
<Compile Include="JsonToSimpl\JsonToSimplArrayLookupChild.cs" />
<Compile Include="JsonToSimpl\JsonToSimplChildObjectBase.cs" />
<Compile Include="JsonToSimpl\JsonToSimplFileMaster.cs" />
<Compile Include="JsonToSimpl\JsonToSimplFixedPathObject.cs" />
<Compile Include="JsonToSimpl\REMOVE JsonToSimplFixedPathObject.cs" />
<Compile Include="JsonToSimpl\JsonToSimplGenericMaster.cs" />
<Compile Include="JsonToSimpl\JsonToSimplMaster.cs" />
<Compile Include="Network\DiscoveryThings.cs" />
<Compile Include="PasswordManagement\Config.cs" />
<Compile Include="PasswordManagement\Constants.cs" />
<Compile Include="PasswordManagement\PasswordClient.cs" />
<Compile Include="PasswordManagement\PasswordManager.cs" />
<Compile Include="SystemInfo\EventArgs and Constants.cs" />
<Compile Include="SystemInfo\SystemInfoConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SystemInfo\SystemInfoToSimpl.cs" />
<Compile Include="WebApi\Presets\Preset.cs" />
<Compile Include="WebApi\Presets\User.cs" />
<Compile Include="WebApi\Presets\WebApiPasscodeClient.cs" />
<Compile Include="XSigUtility\Serialization\IXSigSerialization.cs" />
<Compile Include="XSigUtility\Serialization\XSigSerializationException.cs" />
<Compile Include="XSigUtility\Tokens\XSigAnalogToken.cs" />
<Compile Include="XSigUtility\Tokens\XSigDigitalToken.cs" />
<Compile Include="XSigUtility\Tokens\XSigSerialToken.cs" />
<Compile Include="XSigUtility\Tokens\XSigToken.cs" />
<Compile Include="XSigUtility\Tokens\XSigTokenType.cs" />
<Compile Include="XSigUtility\XSigHelpers.cs" />
<Compile Include="XSigUtility\XSigTokenStreamReader.cs" />
<Compile Include="XSigUtility\XSigTokenStreamWriter.cs" />
<None Include="Properties\ControlSystem.cfg" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
<PostBuildEvent>rem S# preparation will execute after these operations</PostBuildEvent>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{87E29B4C-569B-4368-A4ED-984AC1440C96}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PepperDash.Core</RootNamespace>
<AssemblyName>PepperDash_Core</AssemblyName>
<ProjectTypeGuids>{0B4745B0-194B-4BB6-8E21-E9057CA92500};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PlatformFamilyName>WindowsCE</PlatformFamilyName>
<PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
<OSVersion>5.0</OSVersion>
<DeployDirSuffix>SmartDeviceProject1</DeployDirSuffix>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<NativePlatformName>Windows CE</NativePlatformName>
<FormFactorID>
</FormFactorID>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<DocumentationFile>bin\PepperDash_Core.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<DocumentationFile>bin\PepperDash_Core.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpCWSHelperInterface, Version=2.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCWSHelperInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpHelperInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpNewtonsoft, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpNewtonsoft.dll</HintPath>
</Reference>
<Reference Include="SimplSharpReflectionInterface, Version=1.0.5583.25238, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Compile Include="CommunicationExtras.cs" />
<Compile Include="Comm\CommunicationStreamDebugging.cs" />
<Compile Include="Comm\ControlPropertiesConfig.cs" />
<Compile Include="Comm\GenericSecureTcpIpClient.cs" />
<Compile Include="Comm\GenericTcpIpClient_ForServer.cs" />
<Compile Include="Comm\GenericHttpSseClient.cs" />
<Compile Include="Comm\GenericSecureTcpIpServer.cs" />
<Compile Include="Comm\GenericSecureTcpIpClient_ForServer.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Comm\eControlMethods.cs" />
<Compile Include="Comm\FINISH CommStatic.cs" />
<Compile Include="Comm\CommunicationGather.cs" />
<Compile Include="Comm\EventArgs.cs" />
<Compile Include="Comm\GenericSshClient.cs" />
<Compile Include="Comm\GenericUdpServer.cs" />
<Compile Include="Comm\QscCoreDoubleTcpIpClient.cs" />
<Compile Include="Comm\TcpClientConfigObject.cs" />
<Compile Include="Comm\TcpServerConfigObject.cs" />
<Compile Include="Config\PortalConfigReader.cs" />
<Compile Include="CoreInterfaces.cs" />
<Compile Include="PasswordManagement\PasswordValidationResult.cs" />
<Compile Include="Web\RequestHandlers\DefaultRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\WebApiBaseRequestHandler.cs" />
<Compile Include="Web\WebApiServer.cs" />
<Compile Include="EventArgs.cs" />
<Compile Include="GenericRESTfulCommunications\Constants.cs" />
<Compile Include="GenericRESTfulCommunications\GenericRESTfulClient.cs" />
<Compile Include="JsonStandardObjects\EventArgs and Constants.cs" />
<Compile Include="JsonStandardObjects\JsonToSimplDeviceConfig.cs" />
<Compile Include="JsonStandardObjects\JsonToSimplDevice.cs" />
<Compile Include="JsonToSimpl\JsonToSimplPortalFileMaster.cs" />
<Compile Include="Logging\Debug.cs" />
<Compile Include="Logging\DebugContext.cs" />
<Compile Include="Logging\DebugMemory.cs" />
<Compile Include="Device.cs" />
<Compile Include="Comm\GenericTcpIpServer.cs" />
<Compile Include="EthernetHelper.cs" />
<Compile Include="Comm\GenericTcpIpClient.cs" />
<Compile Include="JsonToSimpl\Constants.cs" />
<Compile Include="JsonToSimpl\Global.cs" />
<Compile Include="JsonToSimpl\JsonToSimplArrayLookupChild.cs" />
<Compile Include="JsonToSimpl\JsonToSimplChildObjectBase.cs" />
<Compile Include="JsonToSimpl\JsonToSimplFileMaster.cs" />
<Compile Include="JsonToSimpl\JsonToSimplFixedPathObject.cs" />
<Compile Include="JsonToSimpl\REMOVE JsonToSimplFixedPathObject.cs" />
<Compile Include="JsonToSimpl\JsonToSimplGenericMaster.cs" />
<Compile Include="JsonToSimpl\JsonToSimplMaster.cs" />
<Compile Include="Network\DiscoveryThings.cs" />
<Compile Include="PasswordManagement\PasswordConfig.cs" />
<Compile Include="PasswordManagement\PasswordConstants.cs" />
<Compile Include="PasswordManagement\PasswordClient.cs" />
<Compile Include="PasswordManagement\PasswordManager.cs" />
<Compile Include="SystemInfo\EventArgs and Constants.cs" />
<Compile Include="SystemInfo\SystemInfoConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SystemInfo\SystemInfoToSimpl.cs" />
<Compile Include="WebApi\Presets\Preset.cs" />
<Compile Include="WebApi\Presets\User.cs" />
<Compile Include="WebApi\Presets\WebApiPasscodeClient.cs" />
<Compile Include="XSigUtility\Serialization\IXSigSerialization.cs" />
<Compile Include="XSigUtility\Serialization\XSigSerializationException.cs" />
<Compile Include="XSigUtility\Tokens\XSigAnalogToken.cs" />
<Compile Include="XSigUtility\Tokens\XSigDigitalToken.cs" />
<Compile Include="XSigUtility\Tokens\XSigSerialToken.cs" />
<Compile Include="XSigUtility\Tokens\XSigToken.cs" />
<Compile Include="XSigUtility\Tokens\XSigTokenType.cs" />
<Compile Include="XSigUtility\XSigHelpers.cs" />
<Compile Include="XSigUtility\XSigTokenStreamReader.cs" />
<Compile Include="XSigUtility\XSigTokenStreamWriter.cs" />
<None Include="Properties\ControlSystem.cfg" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
<PostBuildEvent>rem S# preparation will execute after these operations</PostBuildEvent>
<PreBuildEvent>del "$(TargetDir)PepperDash_Core.*" /q
</PreBuildEvent>
</PropertyGroup>
</PreBuildEvent>
</PropertyGroup>
</Project>