Initial Commit
This commit is contained in:
407
TomcatServer/PlutoServer.MSL/Connectors/DBCache.cs
Normal file
407
TomcatServer/PlutoServer.MSL/Connectors/DBCache.cs
Normal file
@@ -0,0 +1,407 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Sdaleo;
|
||||
using System.Net;
|
||||
using Yaulw.Xml;
|
||||
using Yaulw.File;
|
||||
using CrossProduct.Core;
|
||||
using System.Data;
|
||||
using Sdaleo.Systems.SQLServer;
|
||||
using Sdaleo.Systems.Advantage;
|
||||
using Sdaleo.Systems;
|
||||
using Pluto.Api;
|
||||
|
||||
namespace PlutoServer.MSL.Connectors
|
||||
{
|
||||
/// <summary>
|
||||
/// Responsible for cachine SystemAPIKeys to physical Databases/Connections
|
||||
/// Since we are now seperated from the instance, the practice needs to be looked up
|
||||
/// in the practice list table. The Practice List Table will contain UserApiKeys that we
|
||||
/// have to convert to SystemApiKeys. This cache will save us a lookup, as well as do the work for us
|
||||
/// </summary>
|
||||
public static class DBCache
|
||||
{
|
||||
private static Dictionary<string, SQLServerCredential> _LytecConnetions = new Dictionary<string, SQLServerCredential>();
|
||||
private static Dictionary<string, AdvantageCredential> _MedisoftConnections = new Dictionary<string, AdvantageCredential>();
|
||||
|
||||
// Static Instance of the Current Configuration Data
|
||||
private static DBCacheDataStore s_DBCredentialCacheDataStore = new DBCacheDataStore();
|
||||
private static XSerializer s_xmlserializer = new XSerializer();
|
||||
private static ISReadWrite s_ISReadWrite = new ISReadWrite("DBCache.enc");
|
||||
|
||||
#region Construction
|
||||
|
||||
static DBCache()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mobile Test Settings
|
||||
|
||||
/// <summary>
|
||||
/// Is this computer a computer used for mobile testing?
|
||||
/// </summary>
|
||||
public static bool IsMachine_Used_ForTesting = false;
|
||||
|
||||
/// <summary>
|
||||
/// Used for Unit Testing Purposes
|
||||
/// </summary>
|
||||
public static SQLServerCredential TestLytecUserDBCredential = null;
|
||||
|
||||
/// <summary>
|
||||
/// Used for Unit Testing Purposes
|
||||
/// </summary>
|
||||
public static AdvantageCredential TestMedisoftDBCredential = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region AddSharedDataConnections (Public for Test Framework)
|
||||
|
||||
/// <summary>
|
||||
/// Add a new SQL Server Credential to the datastore if it doesn't already exist
|
||||
/// </summary>
|
||||
/// <param name="bSaveToFile">true to save to the DataStore File</param>
|
||||
public static void AddSharedDataConnectionToDataStore(SQLServerCredential credential, bool bSaveToFile)
|
||||
{
|
||||
// Check if exists
|
||||
DBCacheDataStore.Credential[] existing_creds = s_DBCredentialCacheDataStore.SQLServerCredentials.Credentials;
|
||||
foreach (DBCacheDataStore.Credential existing_cred in existing_creds)
|
||||
{
|
||||
if (String.Compare(credential.Server, existing_cred.SqlServer, true) == 0 &&
|
||||
String.Compare(credential.Instance, existing_cred.SqlInstance, true) == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// else Add to persisten store
|
||||
DBCacheDataStore.Credential cred = new DBCacheDataStore.Credential();
|
||||
cred.SqlServer = credential.Server;
|
||||
cred.SqlInstance = credential.Instance;
|
||||
cred.SqlUser = credential.User;
|
||||
cred.SqlPassword = ConnStr.RetrieveValue("PASSWORD", credential.ConnectionString);
|
||||
s_DBCredentialCacheDataStore.SQLServerCredentials.AddCredential(cred);
|
||||
|
||||
// Log this
|
||||
MSLSpecific.Logger.Info("Adding a new SQL Server Credential to the Datastore for Server:{0} Instance:{1}", cred.SqlServer, cred.SqlInstance);
|
||||
|
||||
// Save to File
|
||||
if (bSaveToFile)
|
||||
SaveDataStore();
|
||||
|
||||
// Load all User Api Keys for new Connection
|
||||
IterateSharedConnectionAndLoadUserApiKeyConnections(credential);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a new Advantage Credential * Shared Credential * to the datastore if it doesn't already exist
|
||||
/// </summary>
|
||||
/// <param name="bSaveToFile">true to save to the DataStore File</param>
|
||||
public static void AddSharedDataConnectionToDataStore(AdvantageCredential credential, bool bSaveToFile)
|
||||
{
|
||||
// Check if exists
|
||||
DBCacheDataStore.Credential[] existing_creds = s_DBCredentialCacheDataStore.AdvantageCredentials.Credentials;
|
||||
foreach (DBCacheDataStore.Credential existing_cred in existing_creds)
|
||||
{
|
||||
if (String.Compare(credential.DataSource, existing_cred.AdvDataSource, true) == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// else Add to persisten store
|
||||
DBCacheDataStore.Credential cred = new DBCacheDataStore.Credential();
|
||||
cred.AdvDataSource = credential.DataSource;
|
||||
cred.AdvIsRemote = (ConnStr.RetrieveValue("SERVERTYPE", credential.ConnectionString) == "REMOTE");
|
||||
s_DBCredentialCacheDataStore.AdvantageCredentials.AddCredential(cred);
|
||||
|
||||
// Log this
|
||||
MSLSpecific.Logger.Info("Adding a new Advantage Credential to the Datastore DataSource:{0} Remote:{1}", cred.AdvDataSource, cred.AdvIsRemote);
|
||||
|
||||
// Save to File
|
||||
if (bSaveToFile)
|
||||
SaveDataStore();
|
||||
|
||||
// Load all User Api Keys for new Connection
|
||||
IterateSharedConnectionAndLoadUserApiKeyConnections(credential);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Persistent DBCache File Store (Internal)
|
||||
|
||||
/// <summary>
|
||||
/// Read from the DataStore into user connections * Reads in all credentials from a file into SQLServer & Medisoft Connections *
|
||||
/// Additionally, pulls out UserApiKeys from the Practice List of the corresponding Databases
|
||||
/// </summary>
|
||||
/// <returns>true if file doesn't exist or if successfull read occured, false otherwise</returns>
|
||||
internal static bool ReadInDataStore()
|
||||
{
|
||||
try
|
||||
{
|
||||
string ISFileContent = s_ISReadWrite.ReadFromIS();
|
||||
if (!String.IsNullOrEmpty(ISFileContent))
|
||||
{
|
||||
// Ran into the issue that the data in the DBCache is total nonsense after decrypting,
|
||||
// not sure yet how to doeal with yet * however if that is the case * what else can we
|
||||
// do but ignore the input?
|
||||
try
|
||||
{
|
||||
ISFileContent = Encryption.DecryptText(ISFileContent);
|
||||
s_DBCredentialCacheDataStore = s_xmlserializer.ReadFromString<DBCacheDataStore>(ISFileContent);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// error occured parsing the file, ignore the read!
|
||||
PlutoService.AppLogError(String.Format("DBCache File is invalid. Ignoring and erasing the cache: {0}", e.Message));
|
||||
s_ISReadWrite.WriteToIS(String.Empty);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test to see if a single successful read occured
|
||||
bool bASuccessFullLytecReadOccured = false;
|
||||
// Iterate thru all the SQL Connections
|
||||
_LytecConnetions.Clear();
|
||||
bool bLytecConnectionsFound = false;
|
||||
int nLytecCount = 0;
|
||||
foreach (DBCacheDataStore.Credential credential in s_DBCredentialCacheDataStore.SQLServerCredentials.Credentials)
|
||||
{
|
||||
if (credential != null)
|
||||
{
|
||||
bLytecConnectionsFound = true;
|
||||
SQLServerCredential tempCred = new SQLServerCredential(credential.SqlServer, credential.SqlInstance, "Lytec SharedData", credential.SqlUser, credential.SqlPassword);
|
||||
bool bSuccess = IterateSharedConnectionAndLoadUserApiKeyConnections(tempCred);
|
||||
if (bSuccess)
|
||||
{
|
||||
bASuccessFullLytecReadOccured = true;
|
||||
nLytecCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bLytecConnectionsFound && !bASuccessFullLytecReadOccured)
|
||||
PlutoService.AppLogInfo("Not one valid Lytec Connection was found in the DataStore");
|
||||
if(nLytecCount > 0)
|
||||
PlutoService.AppLogInfo(String.Format("Loaded {0} Lytec Shared Connection",nLytecCount));
|
||||
|
||||
// Test to see if a single successful read occured
|
||||
bool bASuccessFullMedisoftReadOccured = false;
|
||||
// Iterate thru all the Advantage Connections
|
||||
_MedisoftConnections.Clear();
|
||||
bool bMedisoftConnectionsFound = false;
|
||||
int nMedisoftCount = 0;
|
||||
foreach (DBCacheDataStore.Credential credential in s_DBCredentialCacheDataStore.AdvantageCredentials.Credentials)
|
||||
{
|
||||
if (credential != null)
|
||||
{
|
||||
bMedisoftConnectionsFound = true;
|
||||
AdvantageCredential tempCred = new AdvantageCredential(credential.AdvDataSource, "SharedDataUser", "AndPassword", credential.AdvIsRemote ? AdvantageCredential.ServerType.REMOTE : AdvantageCredential.ServerType.LOCAL);
|
||||
bool bSuccess = IterateSharedConnectionAndLoadUserApiKeyConnections(tempCred);
|
||||
if (bSuccess)
|
||||
{
|
||||
bASuccessFullMedisoftReadOccured = true;
|
||||
nMedisoftCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bMedisoftConnectionsFound && !bASuccessFullMedisoftReadOccured)
|
||||
PlutoService.AppLogInfo("Not one valid Medisoft Connection was found in the DataStore");
|
||||
if (nMedisoftCount > 0)
|
||||
PlutoService.AppLogInfo(String.Format("Loaded {0} Medisoft Shared Connection", nMedisoftCount));
|
||||
|
||||
return (bASuccessFullLytecReadOccured || bASuccessFullMedisoftReadOccured);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
PlutoService.AppLogError(String.Format("Error thrown reading DataStore: {0}", e.Message));
|
||||
return false;
|
||||
}
|
||||
|
||||
// No File exists, always return true
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save user connnections to the DataStore any existing connections * Writes in all SQLServer & Medisoft Connectios to a file *
|
||||
/// Note: UserApiKeys are never saved only the paths/credentials of the Connection
|
||||
/// </summary>
|
||||
internal static void SaveDataStore()
|
||||
{
|
||||
string ISFileContent = s_xmlserializer.WriteToString<DBCacheDataStore>(s_DBCredentialCacheDataStore);
|
||||
ISFileContent = Encryption.EncryptText(ISFileContent);
|
||||
s_ISReadWrite.WriteToIS(ISFileContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load all SQL Server User Credentials from a Shared Connection
|
||||
/// </summary>
|
||||
/// <param name="credential"></param>
|
||||
internal static bool IterateSharedConnectionAndLoadUserApiKeyConnections(SQLServerCredential credential)
|
||||
{
|
||||
bool bSuccess = false;
|
||||
if (credential != null)
|
||||
{
|
||||
DBRetVal retVal = LytecConnector.GetPracticeList(credential);
|
||||
if (retVal.IsValid)
|
||||
{
|
||||
bSuccess = true;
|
||||
foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
|
||||
{
|
||||
string UserApiKey = DataRet.Retrieve(row["UserAPIKey"]);
|
||||
if (!String.IsNullOrEmpty(UserApiKey))
|
||||
{
|
||||
SystemAccessVerifier verifier = new SystemAccessVerifier(UserApiKey);
|
||||
if (!String.IsNullOrEmpty(verifier.SystemApiKey))
|
||||
{
|
||||
string UserDB = DataRet.Retrieve(row["Database Name"]);
|
||||
string Password = ConnStr.RetrieveValue("PASSWORD", credential.ConnectionString);
|
||||
|
||||
// We must ensure uniqueness. Somehow both Medisoft & Lytec can create scenarios
|
||||
// where they are not unique amongst themselves! strange, but true
|
||||
// Don't overwrite connections that are already loaded (invalid state)
|
||||
if (!_LytecConnetions.ContainsKey(verifier.SystemApiKey))
|
||||
{
|
||||
MSLSpecific.Logger.Info("Loading ApiKey Connection for DataBase:{0}", UserDB);
|
||||
_LytecConnetions[verifier.SystemApiKey] = new SQLServerCredential(credential.Server, credential.Instance, UserDB, credential.User, Password);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load all Advantage User Credentials from a Shared Connection
|
||||
/// </summary>
|
||||
/// <param name="credential"></param>
|
||||
internal static bool IterateSharedConnectionAndLoadUserApiKeyConnections(AdvantageCredential credential)
|
||||
{
|
||||
bool bSuccess = false;
|
||||
if (credential != null)
|
||||
{
|
||||
DBRetVal retVal = MedisoftConnector.GetPracticeList(credential);
|
||||
if (retVal.IsValid)
|
||||
{
|
||||
bSuccess = true;
|
||||
foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
|
||||
{
|
||||
string UserApiKey = DataRet.Retrieve(row["UserAPIKey"]);
|
||||
if (!String.IsNullOrEmpty(UserApiKey))
|
||||
{
|
||||
SystemAccessVerifier verifier = new SystemAccessVerifier(UserApiKey);
|
||||
if (!String.IsNullOrEmpty(verifier.SystemApiKey))
|
||||
{
|
||||
string UserDB = DataRet.Retrieve(row["Data Path"]);
|
||||
bool bIsRemote = (ConnStr.RetrieveValue("SERVERTYPE", credential.ConnectionString) == "REMOTE");
|
||||
|
||||
// We must ensure uniqueness. Somehow both Medisoft & Lytec can create scenarios
|
||||
// where they are not unique amongst themselves! strange, but true
|
||||
// Don't overwrite connections that are already loaded (invalid state)
|
||||
if(!_MedisoftConnections.ContainsKey(verifier.SystemApiKey))
|
||||
{
|
||||
MSLSpecific.Logger.Info("Loading ApiKey Connection for DataBase:{0}", UserDB);
|
||||
_MedisoftConnections[verifier.SystemApiKey] = new AdvantageCredential(UserDB + "\\mwddf.add", "user", "password", bIsRemote ? AdvantageCredential.ServerType.REMOTE : AdvantageCredential.ServerType.LOCAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Specific Connection
|
||||
|
||||
internal static SQLServerCredential GetSQLServerConnection(string SystemApiKey)
|
||||
{
|
||||
IConnectDb connection = GetConnectionForSystemApiKey(SystemApiKey);
|
||||
if (connection is SQLServerCredential)
|
||||
return (SQLServerCredential)connection;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static AdvantageCredential GetAdvantageConnection(string SystemApiKey)
|
||||
{
|
||||
IConnectDb connection = GetConnectionForSystemApiKey(SystemApiKey);
|
||||
if (connection is AdvantageCredential)
|
||||
return (AdvantageCredential)connection;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static AdvantageCredential GetAdvantageConnection(string SystemApiKey, string User)
|
||||
{
|
||||
AdvantageCredential credentialSystem = GetAdvantageConnection(SystemApiKey);
|
||||
if (credentialSystem != null && !String.IsNullOrEmpty(User))
|
||||
{
|
||||
// First Retrieve the Password for that user
|
||||
string SQL = String.Format("SELECT [Password] FROM [mwSEC] WHERE upper([Code]) = '{0}'", User.Replace("'", "''").ToUpper());
|
||||
DB db = DB.Create(credentialSystem);
|
||||
DBRetVal retVal = db.ExecuteScalar(SQL);
|
||||
if (retVal.IsValid)
|
||||
{
|
||||
// Now Create a new Connection with the User and Password for Advantage
|
||||
// ~Medisoft attaches 'mwmw' to the username for DB Connections
|
||||
string pwd = retVal.GetScalarRetVal().Trim();
|
||||
AdvantageCredential credentialUser = new AdvantageCredential(credentialSystem.DataSource, (User + "mwmw").ToUpper(), pwd.ToUpper(), credentialSystem.Type);
|
||||
return credentialUser;
|
||||
}
|
||||
}
|
||||
|
||||
// Something Failed
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get General Connection
|
||||
|
||||
/// <summary>
|
||||
/// Looks up the System string in the Local User DB Connection cache and retrieves it,
|
||||
/// if found. otherwise throws System not properly installed error for (release builds,
|
||||
/// of this service). On Test machines it will always return something.
|
||||
/// </summary>
|
||||
/// <param name="SystemApiKey">SystemKey to check</param>
|
||||
/// <returns></returns>
|
||||
private static IConnectDb GetConnectionForSystemApiKey(string SystemApiKey)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(SystemApiKey))
|
||||
{
|
||||
if (_LytecConnetions.ContainsKey(SystemApiKey))
|
||||
return _LytecConnetions[SystemApiKey];
|
||||
|
||||
if (_MedisoftConnections.ContainsKey(SystemApiKey))
|
||||
return _MedisoftConnections[SystemApiKey];
|
||||
|
||||
// * Setup Any Debug/Test Connections * Used Internally Only
|
||||
if (IsMachine_Used_ForTesting)
|
||||
{
|
||||
if (ProductType.IsKeyLytec(SystemApiKey) && TestLytecUserDBCredential != null)
|
||||
return TestLytecUserDBCredential;
|
||||
else if (ProductType.IsKeyMedisoft(SystemApiKey) && TestMedisoftDBCredential != null)
|
||||
return TestMedisoftDBCredential;
|
||||
else
|
||||
throw new Exception("Failed to retrieve DBCredential for ApiKey. Test Machine not properly configured.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// not internally recognized, something went wrong or just Lytec / Medisoft
|
||||
// calling in the wrong order * either way * nothing to return
|
||||
// returning null will just mean something else blows up, so might as well
|
||||
// throw an error and let the pluto api return false
|
||||
PlutoService.AppLogError("Failed to retrieve ApiKey. System not properly configured.");
|
||||
throw new Exception("Failed to retrieve ApiKey. System not properly configured.");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
108
TomcatServer/PlutoServer.MSL/Connectors/DBCacheDataStore.cs
Normal file
108
TomcatServer/PlutoServer.MSL/Connectors/DBCacheDataStore.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using System.Collections;
|
||||
|
||||
namespace PlutoServer.MSL.Connectors
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializable Xml Object used to store all Configuration data - place any new class objects in here
|
||||
/// </summary>
|
||||
[XmlRoot("configuration", Namespace = "PlutoServerMSL", IsNullable = false)]
|
||||
public class DBCacheDataStore
|
||||
{
|
||||
// Member Tags <>
|
||||
public SQLServerCredentialsW SQLServerCredentials = null;
|
||||
public AdvantageCredentialsW AdvantageCredentials = null;
|
||||
|
||||
public class SQLServerCredentialsW
|
||||
{
|
||||
private ArrayList m_ArrayList;
|
||||
|
||||
public SQLServerCredentialsW()
|
||||
{
|
||||
m_ArrayList = new ArrayList();
|
||||
}
|
||||
|
||||
[XmlElement("Credential")]
|
||||
public Credential[] Credentials
|
||||
{
|
||||
get
|
||||
{
|
||||
Credential[] credentials = new Credential[m_ArrayList.Count];
|
||||
m_ArrayList.CopyTo(credentials);
|
||||
return credentials;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null) return;
|
||||
Credential[] credentials = (Credential[])value;
|
||||
m_ArrayList.Clear();
|
||||
foreach (Credential credential in credentials)
|
||||
m_ArrayList.Add(credential);
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddCredential(Credential credential)
|
||||
{
|
||||
m_ArrayList.Add(credential);
|
||||
}
|
||||
}
|
||||
|
||||
public class AdvantageCredentialsW
|
||||
{
|
||||
private ArrayList m_ArrayList;
|
||||
|
||||
public AdvantageCredentialsW()
|
||||
{
|
||||
m_ArrayList = new ArrayList();
|
||||
}
|
||||
|
||||
[XmlElement("Credential")]
|
||||
public Credential[] Credentials
|
||||
{
|
||||
get
|
||||
{
|
||||
Credential[] credentials = new Credential[m_ArrayList.Count];
|
||||
m_ArrayList.CopyTo(credentials);
|
||||
return credentials;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null) return;
|
||||
Credential[] credentials = (Credential[])value;
|
||||
m_ArrayList.Clear();
|
||||
foreach (Credential credential in credentials)
|
||||
m_ArrayList.Add(credential);
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddCredential(Credential credential)
|
||||
{
|
||||
m_ArrayList.Add(credential);
|
||||
}
|
||||
}
|
||||
|
||||
public class Credential
|
||||
{
|
||||
public string SqlServer;
|
||||
public string SqlInstance;
|
||||
public string SqlUser;
|
||||
public string SqlPassword;
|
||||
public string AdvDataSource;
|
||||
public bool AdvIsRemote;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DBCacheDataStore configuration - Constructor
|
||||
/// </summary>
|
||||
public DBCacheDataStore()
|
||||
{
|
||||
SQLServerCredentials = new SQLServerCredentialsW();
|
||||
AdvantageCredentials = new AdvantageCredentialsW();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
1223
TomcatServer/PlutoServer.MSL/Connectors/LytecConnector.cs
Normal file
1223
TomcatServer/PlutoServer.MSL/Connectors/LytecConnector.cs
Normal file
File diff suppressed because it is too large
Load Diff
1342
TomcatServer/PlutoServer.MSL/Connectors/MedisoftConnector.cs
Normal file
1342
TomcatServer/PlutoServer.MSL/Connectors/MedisoftConnector.cs
Normal file
File diff suppressed because it is too large
Load Diff
128
TomcatServer/PlutoServer.MSL/Connectors/ProductType.cs
Normal file
128
TomcatServer/PlutoServer.MSL/Connectors/ProductType.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using Yaulw.Assembly;
|
||||
using Yaulw.Tools;
|
||||
using Sdaleo.Systems.SQLServer;
|
||||
using Sdaleo.Systems.Advantage;
|
||||
|
||||
namespace PlutoServer.MSL.Connectors
|
||||
{
|
||||
/// <summary>
|
||||
/// Dummy wrapper class that makes it pretty to figgure out what
|
||||
/// product we are in. Just do a ProductType.IsKeyLytec() or ProductType.IsKeyMedisoft() etc.
|
||||
/// </summary>
|
||||
internal static class ProductType
|
||||
{
|
||||
#region consts
|
||||
|
||||
/// <summary>
|
||||
/// Parent folder name where SuperBills are to be stored
|
||||
/// </summary>
|
||||
internal const string MOBILE_SB_FILE_FOLDER_NAME = "SuperBills";
|
||||
|
||||
/// <summary>
|
||||
/// The File Extension for the Mobile SB Files
|
||||
/// </summary>
|
||||
internal const string MOBILE_SB_FILE_TYPE = "msb";
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Is System Key of type Lytec
|
||||
/// </summary>
|
||||
/// <param name="SystemApiKey"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool IsKeyLytec(string SystemApiKey)
|
||||
{
|
||||
return (SystemAccessVerifier.GetProductTypeFromSystemApiKey(SystemApiKey) == 'L');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is System Key of type Medisoft
|
||||
/// </summary>
|
||||
/// <param name="SystemApiKey"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool IsKeyMedisoft(string SystemApiKey)
|
||||
{
|
||||
return (SystemAccessVerifier.GetProductTypeFromSystemApiKey(SystemApiKey) == 'M');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetProductName by bool bIsMedisoft, if false returns Lytec
|
||||
/// </summary>
|
||||
/// <param name="bIsMedisoft"></param>
|
||||
/// <returns></returns>
|
||||
internal static string GetProductName(bool bIsMedisoft)
|
||||
{
|
||||
if (bIsMedisoft)
|
||||
return "Medisoft";
|
||||
else
|
||||
return "Lytec";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the Directory for the superbills, depending on product and DataSet or Database Name.
|
||||
/// This means that the connection must already be in the DBCache, in order for this function to work.
|
||||
/// If it is not in the DBCache, it will just default to the default superbill directory.
|
||||
/// </summary>
|
||||
/// <param name="SystemApiKey"></param>
|
||||
/// <returns></returns>
|
||||
internal static string GetProductSpecificSuperBillDirectoryPath(string SystemApiKey)
|
||||
{
|
||||
#if !DEBUG
|
||||
// Create Default Superbill Directory, if it doesn't exists
|
||||
string AsmPath = AssemblyW.SpecializedAssemblyInfo.GetAssemblyPath(AssemblyW.AssemblyST.Executing);
|
||||
string SuperBillsPath = AsmPath + "\\" + MOBILE_SB_FILE_FOLDER_NAME;
|
||||
if (!Directory.Exists(SuperBillsPath))
|
||||
Directory.CreateDirectory(SuperBillsPath);
|
||||
|
||||
// Figgure out which subdirectory to use, allows us to sub-divide
|
||||
// Superbills by Practice/DataSet
|
||||
string subDirectory = "";
|
||||
if (ProductType.IsKeyLytec(SystemApiKey))
|
||||
{
|
||||
// Stripe out all invalid Chars (import for SQL Databases which can have different chars than the file system)
|
||||
SQLServerCredential credential = DBCache.GetSQLServerConnection(SystemApiKey);
|
||||
if(credential != null)
|
||||
subDirectory = PathNaming.MakeDirectoryPathValid(credential.Database);
|
||||
}
|
||||
else if (ProductType.IsKeyMedisoft(SystemApiKey))
|
||||
{
|
||||
// Retrieve the last Directory Name (DataSet Name from the DataSource)
|
||||
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
|
||||
if (credential != null)
|
||||
subDirectory = PathNaming.RetrieveLastDirectoryNameInPath(credential.DataSource);
|
||||
}
|
||||
|
||||
// Create the SubDirectory (and if files exist in the main directory)
|
||||
// then copy those over, make those the default files * allows people to specify the new files to use in a practice *
|
||||
if (!String.IsNullOrEmpty(subDirectory))
|
||||
{
|
||||
if (!Directory.Exists(SuperBillsPath + "\\" + subDirectory))
|
||||
{
|
||||
// Create the directory and copy all *.msb files from the main directory into it,
|
||||
// allows the vars to put it into the main directory to be redistributed automatically
|
||||
Directory.CreateDirectory(SuperBillsPath + "\\" + subDirectory);
|
||||
string[] files = Directory.GetFiles(SuperBillsPath, "*." + ProductType.MOBILE_SB_FILE_TYPE, SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
{
|
||||
string FileName = Path.GetFileName(file);
|
||||
File.Copy(SuperBillsPath + "\\" + FileName, SuperBillsPath + "\\" + subDirectory + "\\" + FileName, false);
|
||||
}
|
||||
}
|
||||
return PathNaming.PathEndsWithNoSlash(SuperBillsPath + "\\" + subDirectory);
|
||||
}
|
||||
return PathNaming.PathEndsWithNoSlash(SuperBillsPath);
|
||||
#else
|
||||
// Temp Path may not be perfect,
|
||||
// but at least it is a central location not in the Release folder where we
|
||||
// are building
|
||||
return PathNaming.PathEndsWithNoSlash(Path.GetTempPath());
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
280
TomcatServer/PlutoServer.MSL/Connectors/SystemAccessVerifier.cs
Normal file
280
TomcatServer/PlutoServer.MSL/Connectors/SystemAccessVerifier.cs
Normal file
@@ -0,0 +1,280 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PlutoServer.MSL.Connectors
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is copied (Stripped down to it's core, with all unneccessary stuff for this instance removed)
|
||||
/// from Registration Server's SystemAccessVerifier.
|
||||
/// All new code should go there. No Pin is generated here. The pin for a userkey
|
||||
/// should always be generated at the registration server.
|
||||
/// This class however can be used to convert a SystemApiKey to a UserApiKey, usefull for what we are
|
||||
/// trying to do in this service
|
||||
/// </summary>
|
||||
internal class SystemAccessVerifier
|
||||
{
|
||||
#region Consts
|
||||
const int SYSTEM_API_KEY_LENGTH = 22;
|
||||
const int USER_API_KEY_LENGTH = 20;
|
||||
const int PIN_LENGTH = 6;
|
||||
const string SYSTEM_API_KEY_BEGIN_MARKER = "$";
|
||||
const string SYSTEM_API_KEY_END_MARKER = "#";
|
||||
internal static readonly string LETTER_CHARS = "AZXVGLTCIRKPNOMQJSHUFWDEYB";
|
||||
internal static int GET_LETTER_CHARS_COUNT { get { return LETTER_CHARS.Length; } }
|
||||
#endregion
|
||||
|
||||
#region System Api Key
|
||||
private string _systemApiKey = String.Empty;
|
||||
internal string SystemApiKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return _systemApiKey;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (ValidateSystemKey(value))
|
||||
_systemApiKey = value.ToUpper().Trim();
|
||||
}
|
||||
}
|
||||
private static bool ValidateSystemKey(string key)
|
||||
{
|
||||
if(!String.IsNullOrEmpty(key))
|
||||
key = key.ToUpper().Trim();
|
||||
|
||||
// $247B2CB4A437EB74C62#M
|
||||
if (!String.IsNullOrEmpty(key) && key.Length == SYSTEM_API_KEY_LENGTH &&
|
||||
key[0] == Char.Parse(SYSTEM_API_KEY_BEGIN_MARKER) && key[SYSTEM_API_KEY_LENGTH - 2] == Char.Parse(SYSTEM_API_KEY_END_MARKER) &&
|
||||
Char.IsLetter(key[SYSTEM_API_KEY_LENGTH - 1]))
|
||||
{
|
||||
// AllAreLettersOrDigit?
|
||||
for (int i = 1; i < SYSTEM_API_KEY_LENGTH - 2; ++i)
|
||||
{
|
||||
if (!Char.IsLetterOrDigit(key[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region User Api Key
|
||||
private string _UserApiKey = String.Empty;
|
||||
internal string UserApiKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return _UserApiKey;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (ValidateUserKey(value))
|
||||
_UserApiKey = value.ToUpper().Trim();
|
||||
}
|
||||
}
|
||||
private static bool ValidateUserKey(string key)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(key))
|
||||
key = key.ToUpper().Trim();
|
||||
|
||||
//247BQCB4A-37EB-4C62M
|
||||
if (!String.IsNullOrEmpty(key) && key.Length == USER_API_KEY_LENGTH &&
|
||||
Char.IsLetter(key[USER_API_KEY_LENGTH - 1]) &&
|
||||
Char.IsLetter(key[4]) && key[9] == '-' && key[14] == '-')
|
||||
{
|
||||
// Perform Product Security check
|
||||
char productType = key[USER_API_KEY_LENGTH - 1];
|
||||
int v = (int)productType % GET_LETTER_CHARS_COUNT;
|
||||
if (key[4] == LETTER_CHARS[v])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Product Type
|
||||
private char _productType = '\0';
|
||||
internal char ProductType { get { return Char.ToUpper(_productType); } }
|
||||
internal bool IsValidProductType { get { return (_productType != '\0'); } }
|
||||
#endregion
|
||||
|
||||
#region Construction
|
||||
|
||||
internal SystemAccessVerifier(string userApiKey)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(userApiKey))
|
||||
userApiKey = userApiKey.ToUpper().Trim();
|
||||
|
||||
if (ValidateUserKey(userApiKey))
|
||||
{
|
||||
UserApiKey = userApiKey;
|
||||
ConvertUserToSystemApiKey();
|
||||
_productType = GetProductTypeFromSystemApiKey(SystemApiKey);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Converters
|
||||
|
||||
private void ConvertUserToSystemApiKey()
|
||||
{
|
||||
if (ValidateUserKey(UserApiKey))
|
||||
{
|
||||
// 247BQCB4A-37EB-4C62M
|
||||
StringBuilder sb = new StringBuilder(UserApiKey);
|
||||
char productType = sb[USER_API_KEY_LENGTH - 1];
|
||||
sb.Remove(USER_API_KEY_LENGTH - 1, 1);
|
||||
|
||||
// Add More Randomness into this (nobody will ever know :S)
|
||||
// Dynamic Calc for 2 - 2, 12 - 4
|
||||
int a = (int)'A';
|
||||
int z = (int)'Z';
|
||||
int ic = (int)sb[2];
|
||||
if ((ic - 2 >= a) && (ic <= z))
|
||||
sb[2] = (char)(ic - 2);
|
||||
ic = sb[12];
|
||||
if ((ic - 4 >= a) && (ic <= z))
|
||||
sb[12] = (char)(ic - 4);
|
||||
|
||||
//Otherway arround arbitrary swap (just in case)
|
||||
// Swap 3 to 10, and 5 to 16
|
||||
char c = sb[3];
|
||||
sb[3] = sb[10];
|
||||
sb[10] = c;
|
||||
c = sb[5];
|
||||
sb[5] = sb[16];
|
||||
sb[16] = c;
|
||||
|
||||
// Assign '-'
|
||||
sb[4] = '-';
|
||||
|
||||
// How clever :S
|
||||
string s = ReverseString(sb.ToString());
|
||||
int n = 0;
|
||||
sb = new StringBuilder(s);
|
||||
for (int i = 0; i < s.Length; ++i)
|
||||
{
|
||||
if (s[i] == '-')
|
||||
{
|
||||
sb[i] = (s[n]);
|
||||
n++;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb[i] = (s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// $247B2CB4A437EB74C62#M
|
||||
s = SYSTEM_API_KEY_BEGIN_MARKER + sb.ToString() + SYSTEM_API_KEY_END_MARKER + Char.ToUpper(productType);
|
||||
SystemApiKey = s;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Statics
|
||||
|
||||
internal static char GetProductTypeFromSystemApiKey(string systemApiKey)
|
||||
{
|
||||
if (ValidateSystemKey(systemApiKey))
|
||||
return Char.ToUpper(systemApiKey[SYSTEM_API_KEY_LENGTH - 1]);
|
||||
else
|
||||
return '\0';
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private static Key Generation Helper Functions
|
||||
|
||||
private static string ReverseString(string str)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(str))
|
||||
{
|
||||
Stack<char> stack = new Stack<char>();
|
||||
foreach (char c in str)
|
||||
stack.Push(c);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (stack.Count > 0)
|
||||
sb.Append(stack.Pop());
|
||||
return sb.ToString();
|
||||
}
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform checksum on string
|
||||
/// </summary>
|
||||
/// <param name="strAboutToBeChecksummed"></param>
|
||||
/// <returns>Checksum</returns>
|
||||
private static int PerformChecksum(string strAboutToBeChecksummed)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(strAboutToBeChecksummed))
|
||||
{
|
||||
int nChecksum = 0;
|
||||
for (int i = 0; i < strAboutToBeChecksummed.Length; ++i)
|
||||
{
|
||||
if (Char.IsDigit(strAboutToBeChecksummed[i]))
|
||||
nChecksum = nChecksum + int.Parse(strAboutToBeChecksummed[i].ToString());
|
||||
}
|
||||
return nChecksum;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dash a String every Nth Character
|
||||
/// </summary>
|
||||
/// <returns>a dashed string</returns>
|
||||
private static string MakeIntoDashSeperatedString(string strAboutToBeDashed, int DashEveryNthCharacter)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(strAboutToBeDashed))
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < strAboutToBeDashed.Length; i++)
|
||||
{
|
||||
if ((i != 0) && ((i % DashEveryNthCharacter) == 0))
|
||||
sb.Append("-");
|
||||
sb.Append(strAboutToBeDashed[i]);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undash a String
|
||||
/// </summary>
|
||||
/// <returns>a string without dashes</returns>
|
||||
private static string MakeIntoDashUnseperatedString(string strAboutToBeUndashed)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(strAboutToBeUndashed))
|
||||
return strAboutToBeUndashed.Replace("-", "");
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the passed in string contains only digits
|
||||
/// </summary>
|
||||
/// <param name="strToCheckForDigits">string to check for digits for</param>
|
||||
/// <returns>true, if all digits are numbers</returns>
|
||||
private static bool ContainsOnlyDigits(string strToCheckForDigits)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(strToCheckForDigits))
|
||||
{
|
||||
for (int i = 0; i < strToCheckForDigits.Length; ++i)
|
||||
{
|
||||
if (!Char.IsDigit(strToCheckForDigits[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user