diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs
index 5df5c1a2..37ef79a8 100644
--- a/PepperDashEssentials/ControlSystem.cs
+++ b/PepperDashEssentials/ControlSystem.cs
@@ -36,6 +36,7 @@ namespace PepperDash.Essentials
Thread.MaxNumberOfUserThreads = 400;
Global.ControlSystem = this;
DeviceManager.Initialize(this);
+ SecretsManager.Initialize();
SystemMonitor.ProgramInitialization.ProgramInitializationUnderUserControl = true;
}
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/GenericComm.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/GenericComm.cs
index 8380a290..7648a379 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/GenericComm.cs
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/GenericComm.cs
@@ -25,6 +25,7 @@ namespace PepperDash.Essentials.Core
public GenericComm(DeviceConfig config)
: base(config)
{
+
PropertiesConfig = CommFactory.GetControlPropertiesConfig(config);
var commPort = CommFactory.CreateCommForDevice(config);
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/DeviceConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/DeviceConfig.cs
index bb95da01..1d9ed1c2 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/DeviceConfig.cs
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/DeviceConfig.cs
@@ -30,7 +30,19 @@ namespace PepperDash.Essentials.Core.Config
[JsonProperty("properties")]
[JsonConverter(typeof(DevicePropertiesConverter))]
- public JToken Properties { get; set; }
+ public JToken Properties { get; set; }
+
+ public DeviceConfig(DeviceConfig dc)
+ {
+ Key = dc.Key;
+ Uid = dc.Uid;
+ Name = dc.Name;
+ Group = dc.Group;
+ Type = dc.Type;
+ Properties = JToken.FromObject(dc.Properties);
+ }
+
+ public DeviceConfig() {}
}
///
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs
index 3f38e2d5..a0108490 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs
@@ -7,6 +7,8 @@ using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.GeneralIO;
using Crestron.SimplSharp.Reflection;
using PepperDash.Core;
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.CrestronIO;
@@ -91,24 +93,84 @@ namespace PepperDash.Essentials.Core
///
///
///
- public static IKeyed GetDevice(DeviceConfig dc)
- {
- var key = dc.Key;
- var name = dc.Name;
- var type = dc.Type;
- var properties = dc.Properties;
-
- var typeName = dc.Type.ToLower();
-
- // Check for types that have been added by plugin dlls.
- if (FactoryMethods.ContainsKey(typeName))
- {
- Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loading '{0}' from Essentials Core", dc.Type);
- return FactoryMethods[typeName].FactoryMethod(dc);
- }
-
- return null;
- }
+ public static IKeyed GetDevice(DeviceConfig dc)
+ {
+ try
+ {
+ Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loading '{0}' from Essentials Core", dc.Type);
+
+ var localDc = new DeviceConfig(dc);
+
+ var key = localDc.Key;
+ var name = localDc.Name;
+ var type = localDc.Type;
+ var properties = localDc.Properties;
+
+
+
+ var typeName = localDc.Type.ToLower();
+
+ Debug.Console(2, "typeName = {0}", typeName);
+ // Check for types that have been added by plugin dlls.
+ if (FactoryMethods.ContainsKey(typeName))
+ {
+ //look for secret in username
+ var userSecretToken = properties["control"]["tcpSshProperties"]["username"]["secret"];
+
+ if (userSecretToken != null)
+ {
+ Debug.Console(2, "Found a secret for {0} - attempting to retrieve it!", name);
+ var userSecretResult =
+ JsonConvert.DeserializeObject(userSecretToken.ToString());
+ var userProvider = SecretsManager.GetSecretProviderByKey(userSecretResult.Provider);
+ if (userProvider != null)
+ {
+ var user = userProvider.GetSecret(userSecretResult.Key);
+ if (user == null)
+ {
+ Debug.Console(1,
+ "Unable to retrieve secret for {0} - Make sure you've added it to the secrets provider");
+ return null;
+ }
+ properties["control"]["tcpSshProperties"]["username"] = (string) user.Value;
+ }
+ }
+
+ //look for secret in password
+ var passwordSecretToken = properties["control"]["tcpSshProperties"]["password"]["secret"];
+
+ if (passwordSecretToken != null)
+ {
+ Debug.Console(2, "Found a secret for {0} - attempting to retrieve it!", name);
+
+ var passwordSecretResult =
+ JsonConvert.DeserializeObject(passwordSecretToken.ToString());
+ var passwordProvider = SecretsManager.GetSecretProviderByKey(passwordSecretResult.Provider);
+ if (passwordProvider != null)
+ {
+ var password = passwordProvider.GetSecret(passwordSecretResult.Key);
+ if (password == null)
+ {
+ Debug.Console(1,
+ "Unable to retrieve secret for {0} - Make sure you've added it to the secrets provider");
+ return null;
+ }
+ properties["control"]["tcpSshProperties"]["password"] = (string) password.Value;
+ }
+ }
+
+ Debug.Console(0, "{0}", localDc.Properties.ToString());
+
+ return FactoryMethods[typeName].FactoryMethod(localDc);
+ }
+ return null;
+ }
+ catch (Exception ex)
+ {
+ Debug.Console(2, "Issue with getting device - {0}", ex.Message);
+ return null;
+ }
+ }
///
/// Prints the type names and associated metadata from the FactoryMethods collection.
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj
index e4c775d0..f202434e 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj
@@ -320,6 +320,10 @@
+
+
+
+
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/CrestronSecretsProvider.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/CrestronSecretsProvider.cs
new file mode 100644
index 00000000..54a3f3c8
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/CrestronSecretsProvider.cs
@@ -0,0 +1,84 @@
+using System;
+using Crestron.SimplSharp;
+using Crestron.SimplSharp.CrestronDataStore;
+using PepperDash.Core;
+
+
+namespace PepperDash.Essentials.Core
+{
+ public class CrestronSecretsProvider : ISecretProvider
+ {
+ public string Key { get; set; }
+ //Added for reference
+ //private readonly bool _secureSupported;
+ public CrestronSecretsProvider(string key)
+ {
+ Key = key;
+ //Added for future encrypted reference
+ //_secureSupported = CrestronSecureStorage.Supported;
+
+ //if (_secureSupported)
+ //{
+ // return;
+ //}
+ CrestronDataStoreStatic.InitCrestronDataStore();
+
+ }
+
+
+ public void SetSecret(string key, object value)
+ {
+ var secret = value as string;
+ if (String.IsNullOrEmpty(secret))
+ {
+ Debug.Console(2, this, "Unable to set secret for {0}:{1} - value is empty.", Key, key);
+ return;
+ }
+ Debug.Console(2, this, "Attempting to set Secret to {0}", secret);
+ var setErrorCode = CrestronDataStoreStatic.SetLocalStringValue(key, secret);
+ switch (setErrorCode)
+ {
+ case CrestronDataStore.CDS_ERROR.CDS_SUCCESS:
+ Debug.Console(2, this,"Secret Successfully Set for {0}:{1}", Key, key);
+ break;
+ default:
+ Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Unable to set secret for {0}:{1} - {2}", Key, key, setErrorCode.ToString());
+ break;
+ }
+ }
+
+ public ISecret GetSecret(string key)
+ {
+ string mySecret;
+ var getErrorCode = CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret);
+
+ switch (getErrorCode)
+ {
+ case CrestronDataStore.CDS_ERROR.CDS_SUCCESS:
+ Debug.Console(2, this, "Secret Successfully retrieved for {0}:{1}", Key, key);
+ Debug.Console(2, this, "Retreived Secret = {0}", mySecret);
+ return new CrestronSecret(key, mySecret, this);
+ default:
+ Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Unable to retrieve secret for {0}:{1} - {2}",
+ Key, key, getErrorCode.ToString());
+ return null;
+ }
+ }
+ }
+
+ public class CrestronSecret : ISecret
+ {
+ public ISecretProvider Provider { get; private set; }
+ public string Key { get; private set; }
+
+ public object Value { get; private set; }
+
+ public CrestronSecret(string key, string value, ISecretProvider provider)
+ {
+ Key = key;
+ Value = value;
+ Provider = provider;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/Interfaces.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/Interfaces.cs
new file mode 100644
index 00000000..51b0b389
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/Interfaces.cs
@@ -0,0 +1,18 @@
+using PepperDash.Core;
+
+namespace PepperDash.Essentials.Core
+{
+ public interface ISecretProvider : IKeyed
+ {
+ void SetSecret(string key, object value);
+
+ ISecret GetSecret(string key);
+ }
+
+ public interface ISecret
+ {
+ ISecretProvider Provider { get; }
+ string Key { get; }
+ object Value { get; }
+ }
+}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/SecretsManager.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/SecretsManager.cs
new file mode 100644
index 00000000..c14bfdc6
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/SecretsManager.cs
@@ -0,0 +1,220 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Crestron.SimplSharp;
+using PepperDash.Core;
+
+
+namespace PepperDash.Essentials.Core
+{
+ public static class SecretsManager
+ {
+ public static List Secrets { get; set; }
+
+ public static void Initialize()
+ {
+ Secrets = new List {new CrestronSecretsProvider("default")};
+
+ CrestronConsole.AddNewConsoleCommand(SetSecretProcess, "setsecret",
+ "Adds secrets to secret provider",
+ ConsoleAccessLevelEnum.AccessOperator);
+
+ CrestronConsole.AddNewConsoleCommand(UpdateSecretProcess, "updatesecret",
+ "Updates secrets in secret provider",
+ ConsoleAccessLevelEnum.AccessAdministrator);
+
+ CrestronConsole.AddNewConsoleCommand(DeleteSecretProcess, "deletesecret",
+ "Deletes secrets in secret provider",
+ ConsoleAccessLevelEnum.AccessAdministrator);
+
+
+ }
+
+ public static ISecretProvider GetSecretProviderByKey(string key)
+ {
+ var secret = Secrets.FirstOrDefault(o => o.Key == key);
+ if (secret == null)
+ {
+ Debug.Console(1, "SecretsManager unable to retrieve SecretProvider with the key '{0}'", key);
+ }
+ return secret;
+ }
+
+ private static void SetSecretProcess(string cmd)
+ {
+ string response;
+ var args = cmd.Split(' ');
+
+ if (args.Length == 0)
+ {
+ //some Instructional Text
+ response = "Adds secrets to secret provider. Format 'setsecret ";
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+ }
+
+ if (args.Length == 1 && args[0] == "?")
+ {
+ response = "Adds secrets to secret provider. Format 'setsecret ";
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+ }
+
+ if (args.Length < 3)
+ {
+ response = "Improper number of arguments";
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+
+ }
+
+ var provider = Secrets.FirstOrDefault(o => o.Key == args[0]);
+
+ if (provider == null)
+ {
+ //someFail
+ response = "Provider key invalid";
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+
+ }
+
+ var key = args[1];
+ var secret = args[2];
+
+ if (provider.GetSecret(key) == null)
+ {
+ provider.SetSecret(key, secret);
+ response =
+ String.Format(
+ "Secret successfully set for {0}:{1}",
+ provider.Key, key);
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+ }
+ response =
+ String.Format(
+ "Unable to set secret for {0}:{1} - Please use the 'UpdateSecret' command to modify it");
+ CrestronConsole.ConsoleCommandResponse(response);
+ }
+
+ private static void UpdateSecretProcess(string cmd)
+ {
+ string response;
+ var args = cmd.Split(' ');
+
+ if (args.Length == 0)
+ {
+ //some Instructional Text
+ response = "Updates secrets in secret provider. Format 'updatesecret ";
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+
+ }
+
+ if (args.Length == 1 && args[0] == "?")
+ {
+ response = "Updates secrets in secret provider. Format 'updatesecret ";
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+ }
+
+
+ if (args.Length < 3)
+ {
+ //someFail
+ response = "Improper number of arguments";
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+
+ }
+
+ var provider = Secrets.FirstOrDefault(o => o.Key == args[0]);
+
+ if (provider == null)
+ {
+ //someFail
+ response = "Provider key invalid";
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+
+ }
+
+ var key = args[1];
+ var secret = args[2];
+
+ if (provider.GetSecret(key) != null)
+ {
+ provider.SetSecret(key, secret);
+ response =
+ String.Format(
+ "Secret successfully updated for {0}:{1}",
+ provider.Key, key);
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+ }
+
+ response =
+ String.Format(
+ "Unable to update secret for {0}:{1} - Please use the 'SetSecret' command to create a new secret");
+ CrestronConsole.ConsoleCommandResponse(response);
+ }
+
+ private static void DeleteSecretProcess(string cmd)
+ {
+ string response;
+ var args = cmd.Split(' ');
+
+ if (args.Length == 0)
+ {
+ //some Instructional Text
+ response = "Deletes secrets in secret provider. Format 'deletesecret ";
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+
+ }
+ if (args.Length == 1 && args[0] == "?")
+ {
+ response = "Deletes secrets in secret provider. Format 'deletesecret ";
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+ }
+
+
+
+ if (args.Length < 2)
+ {
+ //someFail
+ response = "Improper number of arguments";
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+
+ }
+
+ var provider = Secrets.FirstOrDefault(o => o.Key == args[0]);
+
+ if (provider == null)
+ {
+ //someFail
+ response = "Provider key invalid";
+ CrestronConsole.ConsoleCommandResponse(response);
+ return;
+
+ }
+
+ var key = args[1];
+
+
+ provider.SetSecret(key, "");
+ response =
+ String.Format(
+ "Secret successfully deleted for {0}:{1}",
+ provider.Key, key);
+ CrestronConsole.ConsoleCommandResponse(response);
+
+
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/SecretsPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/SecretsPropertiesConfig.cs
new file mode 100644
index 00000000..b17b9000
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/SecretsPropertiesConfig.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Crestron.SimplSharp;
+using Newtonsoft.Json;
+
+namespace PepperDash.Essentials.Core
+{
+ public class SecretsPropertiesConfig
+ {
+ [JsonProperty("provider")]
+ public string Provider { get; set; }
+ [JsonProperty("key")]
+ public string Key { get; set; }
+ }
+}
\ No newline at end of file