Advertisement
Guest User

Untitled

a guest
Oct 28th, 2016
301
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.47 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Runtime.InteropServices;
  6. using System.Security;
  7. using System.Security.Cryptography;
  8. using System.Text;
  9. using RG_SRVLib.Interop;
  10. using Serilog;
  11. using Serilog.Events;
  12. using Visma.Core.Security.CryptoServices;
  13.  
  14. /*
  15. * Requires: RG_SRVLib.Interop, Visma.Core.Security.CryptoServices, Serilog
  16. */
  17.  
  18. public class GlobalServerConnection : IDisposable
  19. {
  20. private readonly Stack<object> _componentReferences = new Stack<object>();
  21.  
  22. private readonly Stopwatch _sw;
  23.  
  24. private int _retries;
  25.  
  26. private IBisComServer _server;
  27.  
  28. public GlobalServerConnection(string clientNumber, string userName, string password, string bapi)
  29. : this(clientNumber, userName, password.ToSecureString(), bapi)
  30. {
  31.  
  32. }
  33. public GlobalServerConnection(string clientNumber,
  34. string userName,
  35. SecureString password,
  36. string bapi)
  37. {
  38. GlobalClient = clientNumber;
  39. GlobalUser = userName;
  40. GlobalPassword = password;
  41. GlobalBapiKey = bapi;
  42. if (Log.IsEnabled(LogEventLevel.Debug))
  43. {
  44. _sw = Stopwatch.StartNew();
  45. Log.Debug("GlobalServerConnection({clientNumber}) START", GlobalClient);
  46. }
  47. Logon();
  48. }
  49.  
  50. public GlobalServerConnection(IBisCom source)
  51. {
  52. _server = source.bcGetServer();
  53. if (Log.IsEnabled(LogEventLevel.Debug))
  54. {
  55. _sw = Stopwatch.StartNew();
  56. Log.Debug("GlobalServerConnection({clientNumber}) START FROM COMPONENT", GlobalClient);
  57. }
  58. }
  59.  
  60. public string GlobalClient { get; }
  61. public string GlobalUser { get; private set; }
  62. private SecureString GlobalPassword { get; }
  63. public string GlobalBapiKey { get; }
  64.  
  65. public dynamic this[GLOBAL_Components component] => GetComponent((int) component);
  66.  
  67. public dynamic this[int component] => GetComponent(component);
  68.  
  69. public dynamic this[string component] => GetComponent<IBisCom>(component);
  70.  
  71. public void Dispose()
  72. {
  73. var count = _componentReferences.Count;
  74. while (_componentReferences.Any())
  75. {
  76. Marshal.ReleaseComObject(_componentReferences.Pop());
  77. }
  78. Marshal.ReleaseComObject(_server);
  79.  
  80. if (Log.IsEnabled(LogEventLevel.Debug) && _sw != null && _sw.IsRunning)
  81. {
  82. _sw.Stop();
  83. Log.Debug("GlobalServerConnection({clientNumber}) DONE @{elapsed}ms ({componentsUsed} components)",
  84. GlobalClient, _sw.ElapsedMilliseconds, count);
  85. }
  86. GC.SuppressFinalize(this);
  87. }
  88.  
  89. public static List<string> GetAvailableCompanies()
  90. {
  91. var compRgSrv = new GlobalServerComponent();
  92. object arrInputClientId, arrInputDataConnections;
  93. compRgSrv.bcGetAvailableDataConnections("", "", out arrInputClientId, out arrInputDataConnections);
  94. var response = ((Array) arrInputDataConnections)?.Cast<string>();
  95. Marshal.ReleaseComObject(compRgSrv);
  96. return response?.ToList() ?? new List<string>();
  97. }
  98.  
  99. private void Logon()
  100. {
  101. if (_server != null)
  102. {
  103. Marshal.ReleaseComObject(_server);
  104. _server = null;
  105. }
  106. _server = new GlobalServerComponent();
  107.  
  108. var globalPasswordUnsecure = GlobalPassword.ToUnsecureString();
  109. string strPassword;
  110. if (!string.IsNullOrEmpty(GlobalUser) && !string.IsNullOrEmpty(globalPasswordUnsecure))
  111. {
  112. var strEncryptKey = _server.bcGetEncryptionKey();
  113. var strCryptPassword = CredentialEncryption.Encrypt(globalPasswordUnsecure,
  114. strEncryptKey);
  115. strPassword = "6C783FE0-B7D2-11DD-8B01-CB9755D89593" + strCryptPassword;
  116. }
  117. else
  118. {
  119. strPassword = "";
  120. GlobalUser = "";
  121. }
  122.  
  123. var logon = _server.bcLogon(GlobalClient, GlobalUser, strPassword, GlobalBapiKey);
  124. if (logon > 0)
  125. {
  126. var exception = new GlobalLogonException(logon);
  127. Log.Fatal(exception, "Logon client {0} failed. Error: {1} ({ret}).", GlobalClient, exception.Message);
  128. throw exception;
  129. }
  130. if (Log.IsEnabled(LogEventLevel.Debug) && _sw != null && _sw.IsRunning)
  131. {
  132. Log.Debug("GlobalServerConnection({clientNumber}) LOGON @{elapsed}ms", GlobalClient, _sw.ElapsedMilliseconds);
  133. }
  134. }
  135.  
  136. private dynamic GetComponent(int component)
  137. {
  138. try
  139. {
  140. if (_server.bcHaveLicense(component) != 1)
  141. throw new ComponentLicenseMissingException(
  142. $"{GlobalClient} does not have license for component {component}");
  143. if (_server.bcHaveAccess(component) != 1)
  144. throw new ComponentAccessDeniedException(
  145. $"{GlobalUser ?? "The current user"} does not have access to component {component}");
  146. var cmp = _server.bcBusinessComponent[component];
  147. _retries = 0;
  148. return cmp;
  149. }
  150. catch (COMException e) when (_retries < 3)
  151. {
  152. _retries++;
  153. Log.Error(e, "Connection with Global lost - retrying ({retries}) - {message}", _retries, e.Message);
  154. Logon();
  155. return GetComponent(component);
  156. }
  157. }
  158.  
  159. public T GetComponent<T>(GLOBAL_Components component)
  160. {
  161. var comObject = (T) GetComponent((int) component);
  162. _componentReferences.Push(comObject);
  163. return comObject;
  164. }
  165.  
  166. public T GetComponent<T>(GLOBAL_Components component, bool establishData) where T : IBisCom
  167. {
  168. var comObject = GetComponent<T>(component);
  169. if (establishData)
  170. {
  171. comObject.bcEstablishData();
  172. comObject.bcBindData();
  173. }
  174. return comObject;
  175. }
  176.  
  177. public T GetComponent<T>(string name, bool establishData = false) where T : IBisCom
  178. {
  179. object dictionaryObj;
  180. _server.bcGetSrvDictionary(out dictionaryObj);
  181. var dictComp = (ISrvDictionary) dictionaryObj;
  182. var tableId = dictComp.bcGetTableIDFromName(name);
  183. if (tableId > 0)
  184. {
  185. Log.Debug("Found component with name {componentName}. Id is {componentId}", name, tableId);
  186. var obj = (T) GetComponent(tableId);
  187. if (establishData)
  188. {
  189. obj.bcEstablishData();
  190. obj.bcBindData();
  191. }
  192. return obj;
  193. }
  194. return default(T);
  195. }
  196. }
  197.  
  198. internal class ComponentLicenseMissingException : Exception
  199. {
  200. public ComponentLicenseMissingException(string msg) : base(msg)
  201. {
  202. }
  203. }
  204.  
  205. internal class ComponentAccessDeniedException : Exception
  206. {
  207. public ComponentAccessDeniedException(string msg) : base(msg)
  208. {
  209. }
  210. }
  211.  
  212. public class GlobalLogonException : Exception
  213. {
  214. private static readonly Dictionary<int, string> Messages = new Dictionary<int, string>
  215. {
  216. {11, "Invalid username or password"},
  217. {12, "Wrong BAPI"},
  218. {16, "Failed to connect to database"},
  219. {21, "Too many concurrent users at the moment"},
  220. {27, "The Visma Global license has expired."},
  221. {28, "The Visma Global license has expired."}
  222. };
  223.  
  224. public GlobalLogonException(int logon) : base(GetMessage(logon))
  225. {
  226. }
  227.  
  228. public GlobalLogonException(string msg) : base(msg)
  229. {
  230.  
  231. }
  232.  
  233. private static string GetMessage(int errorId)
  234. {
  235. string value;
  236. if (Messages.TryGetValue(errorId, out value))
  237. return value;
  238. return $"Generic unknown error ({errorId})";
  239. }
  240. }
  241.  
  242. public static class IBisComExtentions
  243. {
  244. public static Dictionary<string, T> ToDictionary<T>(this IBisComNavigate component, string valueColumn)
  245. {
  246. return ToDictionary<T>(component, component.GetObjectIdFromColumnName(valueColumn));
  247. }
  248.  
  249. public static Dictionary<string, TValue> ToDictionary<TValue>(this IBisComNavigate component, int valueColumn)
  250. {
  251. var dictionary = new Dictionary<string, TValue>();
  252. var keyfield = component.bcGetKeyField();
  253. component.bcFetchFirst(0);
  254. do
  255. {
  256. object value;
  257. component.bcGetValue(valueColumn, out value);
  258. dictionary.Add(component.bcGetStr(keyfield), (TValue)value);
  259. } while (component.bcFetchNext(0) == 0);
  260. return dictionary;
  261. }
  262. public static int GetObjectIdFromColumnName(this IBisCom component, string columnName)
  263. {
  264. if (string.IsNullOrEmpty(columnName))
  265. return 0;
  266.  
  267. object varrObjectIds;
  268. component.bcGetAllObjectIDs(out varrObjectIds, component.bcGetID());
  269. if (varrObjectIds != null)
  270. {
  271. foreach (int objectId in (object[])varrObjectIds)
  272. {
  273. if (component.bcGetTableObjectName(objectId).EndsWith($".{columnName}", StringComparison.OrdinalIgnoreCase))
  274. {
  275. return objectId;
  276. }
  277. }
  278. }
  279. Log.Error("Could not find object id for column {name} on component {id}. Available object ids are {@objectids}", columnName, component.bcGetID(), (object[])varrObjectIds);
  280. return 0;
  281. }
  282.  
  283. public static int Set<T>(this IBisCom component, string columnName, T value, List<int> changedIdList = null)
  284. {
  285. var objectId = component.GetObjectIdFromColumnName(columnName);
  286. if (objectId > 0)
  287. {
  288. return Set(component, objectId, value, changedIdList);
  289. }
  290. Log.Error("Could not find objectid for {columnName}", columnName);
  291. return 1;
  292. }
  293. public static int Set<T>(this IBisCom component, int objectId, T value, List<int> changedIdList = null)
  294. {
  295. var returnValue = SetValueOnComponent(component, objectId, value);
  296. if (returnValue != 0)
  297. {
  298. Log.Error("Could not set value on component. {error}. Component: {component}, ObjectId: {id}, Value: {value}",
  299. component.bcGetMessageText(returnValue), component.bcGetID(), objectId, value);
  300. } else {
  301. changedIdList?.Add(objectId);
  302. }
  303. return returnValue;
  304. }
  305.  
  306. private static int SetValueOnComponent<T>(IBisCom component, int objectId, T value)
  307. {
  308. if (typeof(T) == typeof(double) || typeof(T) == typeof(decimal))
  309. return component.bcUpdateDouble(objectId, Convert.ToDouble(value));
  310. if (typeof(T) == typeof(DateTime))
  311. return component.bcUpdateDate(objectId, Convert.ToDateTime(value));
  312. if (typeof(T) == typeof(int) || typeof(T) == typeof(bool))
  313. return component.bcUpdateInt(objectId, Convert.ToInt32(value));
  314.  
  315. return component.bcUpdateStr(objectId, Convert.ToString(value));
  316. }
  317. }
  318. public static class StringExtensions
  319. {
  320. public static string Encrypt(this string input)
  321. {
  322. if (string.IsNullOrEmpty(input)) return input;
  323. var bytes = Encoding.UTF8.GetBytes(input);
  324. var encrypted = ProtectedData.Protect(bytes, null, DataProtectionScope.CurrentUser);
  325. return Convert.ToBase64String(encrypted);
  326. }
  327.  
  328. public static string Decrypt(this string input)
  329. {
  330. if (string.IsNullOrEmpty(input)) return input;
  331. var bytes = Convert.FromBase64String(input);
  332. var decrypted = ProtectedData.Unprotect(bytes, null, DataProtectionScope.CurrentUser);
  333. return Encoding.UTF8.GetString(decrypted);
  334. }
  335.  
  336. public static SecureString DecryptToSecure(this string input)
  337. {
  338. if (string.IsNullOrEmpty(input)) return new SecureString();
  339. var bytes = Convert.FromBase64String(input);
  340. var decrypted = ProtectedData.Unprotect(bytes, null, DataProtectionScope.CurrentUser);
  341. var secure = new SecureString();
  342. foreach (var c in Encoding.UTF8.GetChars(decrypted))
  343. {
  344. secure.AppendChar(c);
  345. }
  346. secure.MakeReadOnly();
  347. return secure;
  348. }
  349.  
  350. public static SecureString ToSecureString(this string input)
  351. {
  352. var secure = new SecureString();
  353. if (string.IsNullOrEmpty(input))
  354. return secure;
  355.  
  356. foreach (char c in input)
  357. {
  358. secure.AppendChar(c);
  359. }
  360. secure.MakeReadOnly();
  361. return secure;
  362. }
  363.  
  364. public static string ToUnsecureString(this SecureString input)
  365. {
  366. if (input == null)
  367. return "";
  368.  
  369. var unmanagedString = IntPtr.Zero;
  370. try
  371. {
  372. unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(input);
  373. return Marshal.PtrToStringUni(unmanagedString) ?? "";
  374. }
  375. finally
  376. {
  377. Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
  378. }
  379. }
  380. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement