IPCClient.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. using InABox.Client.IPC;
  2. using InABox.Clients;
  3. using InABox.Core;
  4. using NPOI.SS.Formula.Functions;
  5. namespace InABox.IPC
  6. {
  7. internal static class LocalCache
  8. {
  9. public static string Password { get; set; }
  10. }
  11. public class IPCClient<TEntity> : BaseClient<TEntity> where TEntity : Entity, new()
  12. {
  13. private IPCClientTransport _pipe;
  14. public IPCClient(string pipeName)
  15. {
  16. _pipe = IPCClientFactory.GetClient(pipeName);
  17. Timeout = TimeSpan.FromSeconds(300);
  18. }
  19. public override bool IsConnected() => _pipe?.Disconnected == false;
  20. public override DatabaseInfo Info()
  21. {
  22. try
  23. {
  24. var request = new InfoRequest();
  25. PrepareRequest(request, false);
  26. var response = Send(IPCMessage.Info(request), 5000).GetResponse<InfoResponse>();
  27. return response.Info;
  28. }
  29. catch (Exception)
  30. {
  31. return new DatabaseInfo();
  32. }
  33. }
  34. private void PrepareRequest(Request request, bool doCredentials = true)
  35. {
  36. if(request is not ValidateRequest && _pipe.Disconnected)
  37. {
  38. ClientFactory.Validate(ClientFactory.UserID, LocalCache.Password);
  39. }
  40. if (doCredentials)
  41. {
  42. request.Credentials.Platform = ClientFactory.Platform;
  43. request.Credentials.Version = ClientFactory.Version;
  44. request.Credentials.Session = ClientFactory.SessionID;
  45. }
  46. Request.BeforeRequest?.Invoke(request);
  47. }
  48. private IPCMessage Send(IPCMessage request, int? timeout = null)
  49. {
  50. return _pipe.Send(request, timeout ?? Convert.ToInt32(Timeout.TotalMilliseconds));
  51. }
  52. protected override bool DoCheck2FA(string code, Guid? session)
  53. {
  54. var request = new Check2FARequest(code);
  55. PrepareRequest(request);
  56. var response = Send(IPCMessage.Check2FA(request)).GetResponse<Check2FAResponse>();
  57. if (response != null)
  58. {
  59. return response.Status switch
  60. {
  61. StatusCode.OK => response.Valid,
  62. StatusCode.Unauthenticated => false,
  63. _ => throw new IPCException(response.Messages),
  64. };
  65. }
  66. return false;
  67. }
  68. protected override bool DoPing()
  69. {
  70. try
  71. {
  72. var request = new PingRequest();
  73. PrepareRequest(request);
  74. var response = Send(IPCMessage.Ping(request), 10_000).GetResponse<PingResponse>();
  75. if (response != null)
  76. {
  77. return response.Status switch
  78. {
  79. StatusCode.Error or StatusCode.BadServer or StatusCode.Incomplete => throw new IPCException(response.Messages),
  80. _ => true
  81. };
  82. }
  83. }
  84. catch (Exception) { }
  85. return false;
  86. }
  87. protected override void DoDelete(TEntity entity, string auditnote)
  88. {
  89. var request = new DeleteRequest<TEntity>(entity, auditnote);
  90. PrepareRequest(request);
  91. var response = Send(IPCMessage.Delete(request)).GetResponse<DeleteResponse<TEntity>>();
  92. switch (response.Status)
  93. {
  94. case StatusCode.OK:
  95. break;
  96. case StatusCode.Unauthenticated:
  97. throw new IPCException("Client not authenticated");
  98. default:
  99. throw new IPCException(response.Messages);
  100. }
  101. }
  102. protected override void DoDelete(IEnumerable<TEntity> entities, string auditnote)
  103. {
  104. var items = entities.AsArray();
  105. var request = new MultiDeleteRequest<TEntity>(items, auditnote);
  106. PrepareRequest(request);
  107. var response = Send(IPCMessage.MultiDelete(request)).GetResponse<MultiDeleteResponse<TEntity>>();
  108. switch (response.Status)
  109. {
  110. case StatusCode.OK:
  111. break;
  112. case StatusCode.Unauthenticated:
  113. throw new IPCException("Client not authenticated");
  114. default:
  115. throw new IPCException(response.Messages);
  116. }
  117. }
  118. protected override TEntity[] DoLoad(Filter<TEntity>? filter = null, SortOrder<TEntity>? sort = null)
  119. {
  120. var request = new QueryRequest<TEntity>(filter, null, sort);
  121. PrepareRequest(request);
  122. var result = new List<TEntity>();
  123. var response = Send(IPCMessage.Query(request)).GetResponse<QueryResponse<TEntity>>();
  124. if (response.Items != null)
  125. foreach (var row in response.Items.Rows)
  126. result.Add(row.ToObject<TEntity>());
  127. return result.ToArray();
  128. }
  129. protected override CoreTable DoQuery(Filter<TEntity>? filter, Columns<TEntity>? columns, SortOrder<TEntity>? sort = null)
  130. {
  131. var request = new QueryRequest<TEntity>(filter, columns, sort);
  132. PrepareRequest(request);
  133. var response = Send(IPCMessage.Query(request)).GetResponse<QueryResponse<TEntity>>();
  134. if (response != null)
  135. {
  136. return response.Status switch
  137. {
  138. StatusCode.OK => response.Items,
  139. StatusCode.Unauthenticated => throw new IPCException("Client not authenticated", StatusCode.Unauthenticated),
  140. _ => throw new IPCException(response.Messages),
  141. };
  142. }
  143. return null;
  144. }
  145. protected override Dictionary<string, CoreTable> DoQueryMultiple(Dictionary<string, IQueryDef> queries)
  146. {
  147. var request = new MultiQueryRequest();
  148. foreach (var item in queries)
  149. {
  150. request.AddQuery(item.Key, item.Value);
  151. }
  152. PrepareRequest(request);
  153. var response = Send(IPCMessage.QueryMultiple(request)).GetResponse<MultiQueryResponse>();
  154. if (response != null)
  155. {
  156. return response.Status switch
  157. {
  158. StatusCode.OK => response.Tables,
  159. StatusCode.Unauthenticated => throw new IPCException("Client not authenticated"),
  160. _ => throw new IPCException(response.Messages),
  161. };
  162. }
  163. return null;
  164. }
  165. protected override void DoSave(TEntity entity, string auditnote)
  166. {
  167. var request = new SaveRequest<TEntity>(entity, auditnote)
  168. {
  169. ReturnOnlyChanged = true
  170. };
  171. PrepareRequest(request);
  172. var response = Send(IPCMessage.Save(request)).GetResponse<SaveResponse<TEntity>>();
  173. switch (response.Status)
  174. {
  175. case StatusCode.OK:
  176. /*var props = CoreUtils.PropertyList(typeof(TEntity), x => true, true);
  177. entity.SetObserving(false);
  178. foreach (var prop in props.Keys)
  179. {
  180. var value = CoreUtils.GetPropertyValue(response.Item, prop);
  181. CoreUtils.SetPropertyValue(entity, prop, value);
  182. }
  183. entity.CommitChanges();
  184. entity.SetObserving(true);*/
  185. entity.SetObserving(false);
  186. foreach (var (key, value) in response.ChangedValues)
  187. {
  188. if (CoreUtils.TryGetProperty<TEntity>(key, out var property))
  189. {
  190. CoreUtils.SetPropertyValue(entity, key, CoreUtils.ChangeType(value, property.PropertyType));
  191. }
  192. }
  193. entity.CommitChanges();
  194. entity.SetObserving(true);
  195. break;
  196. case StatusCode.Unauthenticated:
  197. throw new IPCException("Client not authenticated");
  198. default:
  199. throw new IPCException(response.Messages);
  200. }
  201. }
  202. protected override void DoSave(IEnumerable<TEntity> entities, string auditnote)
  203. {
  204. var items = entities.ToArray();
  205. var request = new MultiSaveRequest<TEntity>(items, auditnote)
  206. {
  207. ReturnOnlyChanged = true
  208. };
  209. PrepareRequest(request);
  210. var response = Send(IPCMessage.MultiSave(request)).GetResponse<MultiSaveResponse<TEntity>>();
  211. switch (response.Status)
  212. {
  213. case StatusCode.OK:
  214. /*var props = CoreUtils.PropertyList(typeof(TEntity), x => true, true);
  215. for (var i = 0; i < items.Length; i++)
  216. {
  217. items[i].SetObserving(false);
  218. foreach (var prop in props.Keys)
  219. {
  220. var value = CoreUtils.GetPropertyValue(response.Items[i], prop);
  221. CoreUtils.SetPropertyValue(items[i], prop, value);
  222. }
  223. //CoreUtils.DeepClone<TEntity>(response.Items[i], items[i]);
  224. items[i].CommitChanges();
  225. items[i].SetObserving(true);
  226. }*/
  227. for (int i = 0; i < items.Length; ++i)
  228. {
  229. var entity = items[i];
  230. var changedValues = response.ChangedValues[i];
  231. entity.SetObserving(false);
  232. foreach (var (key, value) in changedValues)
  233. {
  234. if (CoreUtils.TryGetProperty<TEntity>(key, out var property))
  235. {
  236. CoreUtils.SetPropertyValue(entity, key, CoreUtils.ChangeType(value, property.PropertyType));
  237. }
  238. }
  239. entity.CommitChanges();
  240. entity.SetObserving(true);
  241. }
  242. break;
  243. case StatusCode.Unauthenticated:
  244. throw new IPCException("Client not authenticated");
  245. default:
  246. throw new IPCException(response.Messages);
  247. }
  248. }
  249. protected override IValidationData DoValidate(Guid session)
  250. {
  251. return Validate(
  252. null, null, false, session);
  253. }
  254. protected override IValidationData DoValidate(string pin, Guid session)
  255. {
  256. return Validate(
  257. null, pin, true, session);
  258. }
  259. protected override IValidationData DoValidate(string userid, string password, Guid session)
  260. {
  261. return Validate(
  262. userid, password, false, session);
  263. }
  264. private IValidationData Validate(string? userid, string? password, bool usePin, Guid session = default)
  265. {
  266. var ticks = DateTime.Now.ToUniversalTime().Ticks.ToString();
  267. var request = new ValidateRequest { UsePIN = usePin };
  268. if (usePin)
  269. {
  270. request.UserID = Encryption.Encrypt(ticks, "wCq9rryEJEuHIifYrxRjxg", true);
  271. request.Password = Encryption.Encrypt(ticks, "7mhvLnqMwkCAzN+zNGlyyg", true);
  272. request.PIN = password;
  273. }
  274. else
  275. {
  276. request.UserID = userid;
  277. request.Password = password;
  278. }
  279. request.Credentials.Platform = ClientFactory.Platform;
  280. request.Credentials.Version = ClientFactory.Version;
  281. PrepareRequest(request, false);
  282. if(session != Guid.Empty)
  283. {
  284. request.Credentials.Session = session;
  285. }
  286. var response = Send(IPCMessage.Validate(request), 10000).GetResponse<ValidateResponse>();
  287. if (response != null)
  288. if (response.Status.Equals(StatusCode.OK))
  289. {
  290. LocalCache.Password = password;
  291. return new ValidationData(
  292. response.ValidationStatus,
  293. response.UserID,
  294. response.UserGuid,
  295. response.SecurityID,
  296. response.Session,
  297. response.Recipient2FA,
  298. response.PasswordExpiration
  299. );
  300. }
  301. else if (response.Status == StatusCode.BadServer)
  302. {
  303. throw new IPCException(response.Messages);
  304. }
  305. return new ValidationData(
  306. ValidationStatus.INVALID,
  307. "",
  308. Guid.Empty,
  309. Guid.Empty,
  310. Guid.Empty,
  311. null,
  312. DateTime.MinValue
  313. );
  314. }
  315. public override string Version()
  316. {
  317. try
  318. {
  319. var request = new VersionRequest();
  320. PrepareRequest(request, false);
  321. var response = Send(IPCMessage.Version(request)).GetResponse<VersionResponse>();
  322. return response.Version;
  323. }
  324. catch (Exception)
  325. {
  326. return "";
  327. }
  328. }
  329. public override string ReleaseNotes()
  330. {
  331. try
  332. {
  333. var request = new ReleaseNotesRequest();
  334. PrepareRequest(request, false);
  335. var response = Send(IPCMessage.ReleaseNotes(request)).GetResponse<ReleaseNotesResponse>();
  336. return response.ReleaseNotes;
  337. }
  338. catch (Exception)
  339. {
  340. return "";
  341. }
  342. }
  343. public override byte[]? Installer()
  344. {
  345. try
  346. {
  347. var request = new InstallerRequest();
  348. PrepareRequest(request, false);
  349. var response = Send(IPCMessage.Installer(request)).GetResponse<InstallerResponse>();
  350. return response.Installer;
  351. }
  352. catch (Exception)
  353. {
  354. return null;
  355. }
  356. }
  357. }
  358. }