| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 | 
							- using System.Reflection;
 
- using InABox.Clients;
 
- using InABox.Core;
 
- using InABox.Database;
 
- using InABox.IPC;
 
- namespace InABox.API
 
- {
 
-     public class RestService
 
-     {
 
-         public static bool CheckPasswordExpiration { get; set; } = true;
 
-         public static bool IsHTTPS { get; set; } = false;
 
-         protected static void GarbageCollection()
 
-         {
 
-             //DateTime now = DateTime.Now;
 
-             //GC.Collect();
 
-             //GC.WaitForPendingFinalizers();
 
-             //GC.Collect();
 
-             //Logger.Send(LogType.Information, "", String.Format("Garbage Collection takes {0:F2}ms", (DateTime.Now - now).TotalMilliseconds));
 
-         }
 
-         protected static Guid ValidateRequest(Request request, out string? userID)
 
-         {
 
-             var session = request.Credentials.Session;
 
-             if (session != Guid.Empty)
 
-             {
 
-                 var valid = CredentialsCache.Validate(session, out userID);
 
-                 if (valid != Guid.Empty)
 
-                 {
 
-                     CredentialsCache.RefreshSessionExpiry(session);
 
-                 }
 
-                 return valid;
 
-             }
 
-             else if (request.Credentials.UserID is not null
 
-                 && request.Credentials.Password is not null
 
-                 && CredentialsCache.IsBypassed(request.Credentials.UserID, request.Credentials.Password))
 
-             {
 
-                 userID = "";
 
-                 return CoreUtils.FullGuid;
 
-             }
 
-             userID = null;
 
-             return Guid.Empty;
 
-         }
 
-         public static MultiQueryResponse QueryMultiple(MultiQueryRequest request, bool isSecure)
 
-         {
 
-             var start = DateTime.Now;
 
-             var response = new MultiQueryResponse();
 
-             var userguid = ValidateRequest(request, out var userid);
 
-             if (userguid == Guid.Empty)
 
-                 return response;
 
-             Logger.Send(LogType.Information, userid, string.Format("[{0} {1}] QueryMultiple({2})",
 
-                 request.Credentials.Platform,
 
-                 request.Credentials.Version,
 
-                 request.Queries.Count));
 
-             try
 
-             {
 
-                 var queries = new Dictionary<string, IQueryDef>();
 
-                 foreach (var (key, query) in request.Queries)
 
-                 {
 
-                     var type = CoreUtils.GetEntity(query.Type);
 
-                     if (type.IsAssignableTo(typeof(ISecure)) && !isSecure)
 
-                     {
 
-                         Logger.Send(LogType.Error, userid, $"{query.Type} is a secure entity. Request failed");
 
-                     }
 
-                     else
 
-                     {
 
-                         queries.Add(key, Activator.CreateInstance(typeof(QueryDef<>).MakeGenericType(type), query.Filter, query.Columns, query.Sort) as IQueryDef);
 
-                     }
 
-                 }
 
-                 response.Tables = DbFactory.QueryMultiple(queries, userguid, userid, request.Credentials.Platform, request.Credentials.Version);
 
-                 response.Status = StatusCode.OK;
 
-                 Logger.Send(LogType.Information, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] QueryMultiple Complete", request.Credentials.Platform, request.Credentials.Version,
 
-                         (int)DateTime.Now.Subtract(start).TotalMilliseconds));
 
-             }
 
-             catch (Exception err)
 
-             {
 
-                 response.Status = StatusCode.Error;
 
-                 response.Messages.Add(err.Message);
 
-                 Logger.Send(LogType.Error, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] QueryMultiple Failed: {3} ", request.Credentials.Platform, request.Credentials.Version,
 
-                         (int)DateTime.Now.Subtract(start).TotalMilliseconds, err.Message));
 
-             }
 
-             GarbageCollection();
 
-             return response;
 
-         }
 
-         public static ValidateResponse Validate(ValidateRequest request)
 
-         {
 
-             var response = new ValidateResponse();
 
-             User? user = null;
 
-             bool reLogin = false;
 
-             if (request.Credentials.Session != Guid.Empty)
 
-             {
 
-                 var session = request.Credentials.Session;
 
-                 user = CredentialsCache.Validate(session);
 
-                 if (user != null)
 
-                 {
 
-                     Logger.Send(LogType.Information, "", $"{session} re-logged in!");
 
-                     CredentialsCache.RefreshSessionExpiry(session);
 
-                     reLogin = true;
 
-                 }
 
-             }
 
-             if (user == null)
 
-             {
 
-                 if (request.UsePIN)
 
-                 {
 
-                     Logger.Send(LogType.Information, "", $"Login request with PIN {request.PIN}");
 
-                     user = CredentialsCache.ValidateUser(request.PIN);
 
-                 }
 
-                 else
 
-                 {
 
-                     var userID = request.UserID ?? request.Credentials.UserID;
 
-                     var password = request.Password ?? request.Credentials.Password;
 
-                     if (userID == null || password == null)
 
-                         return response.Status(StatusCode.Error);
 
-                     user = CredentialsCache.ValidateUser(userID, password);
 
-                     if (user?.ID != CoreUtils.FullGuid)
 
-                     {
 
-                         Logger.Send(LogType.Information, userID, $"Login request for {userID}");
 
-                     }
 
-                 }
 
-             }
 
-             response.Status = StatusCode.OK;
 
-             if (user == null)
 
-             {
 
-                 Logger.Send(LogType.Information, "", $"Login failed!");
 
-                 response.ValidationStatus = ValidationStatus.INVALID;
 
-             }
 
-             else if (CheckPasswordExpiration && !request.UsePIN && user.PasswordExpiration > DateTime.MinValue && user.PasswordExpiration < DateTime.Now)
 
-             {
 
-                 Logger.Send(LogType.Information, user.UserID, $"Password for ({user.UserID}) has expired!");
 
-                 response.ValidationStatus = ValidationStatus.PASSWORD_EXPIRED;
 
-             }
 
-             else if (reLogin)
 
-             {
 
-                 Logger.Send(LogType.Information, user.UserID, $"Login ({user.UserID}) success!");
 
-                 response.ValidationStatus = ValidationStatus.VALID;
 
-                 response.UserGuid = user.ID;
 
-                 response.UserID = user.UserID;
 
-                 response.SecurityID = user.SecurityGroup.ID;
 
-                 response.Session = request.Credentials.Session;
 
-                 response.PasswordExpiration = CheckPasswordExpiration ? user.PasswordExpiration : DateTime.MinValue;
 
-             }
 
-             else if (user.ID == CoreUtils.FullGuid || !user.Use2FA)
 
-             {
 
-                 Logger.Send(LogType.Information, user.UserID, $"Login ({user.UserID}) success!");
 
-                 response.ValidationStatus = ValidationStatus.VALID;
 
-                 response.UserGuid = user.ID;
 
-                 response.UserID = user.UserID;
 
-                 response.SecurityID = user.SecurityGroup.ID;
 
-                 response.Session = user.ID == CoreUtils.FullGuid ?
 
-                     CredentialsCache.NewSession(user, true, DateTime.MaxValue) :
 
-                     CredentialsCache.NewSession(user, true);
 
-                 response.PasswordExpiration = CheckPasswordExpiration ? user.PasswordExpiration : DateTime.MinValue;
 
-             }
 
-             else
 
-             {
 
-                 Logger.Send(LogType.Information, user.UserID, $"Login ({user.UserID}) requires 2FA. Sending code...");
 
-                 var session = CredentialsCache.SendCode(user.ID, out var recipient);
 
-                 if (session != null)
 
-                 {
 
-                     response.ValidationStatus = ValidationStatus.REQUIRE_2FA;
 
-                     response.UserGuid = user.ID;
 
-                     response.UserID = user.UserID;
 
-                     response.SecurityID = user.SecurityGroup.ID;
 
-                     response.Session = session ?? Guid.Empty;
 
-                     response.Recipient2FA = recipient;
 
-                     response.PasswordExpiration = CheckPasswordExpiration ? user.PasswordExpiration : DateTime.MinValue;
 
-                 }
 
-                 else
 
-                 {
 
-                     response.Status = StatusCode.Error;
 
-                     response.Messages.Add("Code failed to send");
 
-                 }
 
-             }
 
-             return response;
 
-         }
 
-         public static Check2FAResponse Check2FA(Check2FARequest request)
 
-         {
 
-             var response = new Check2FAResponse();
 
-             Logger.Send(LogType.Information, "", $"2FA check for session {request.Credentials.Session} and code {request.Code}");
 
-             response.Valid = CredentialsCache.ValidateCode(request.Credentials.Session, request.Code);
 
-             response.Status = StatusCode.OK;
 
-             return response;
 
-         }
 
-         public static InfoResponse Info(InfoRequest request)
 
-         {
 
-             var response = new InfoResponse(new DatabaseInfo(DbFactory.ColorScheme, DbFactory.Logo, CoreUtils.GetVersion(), IsHTTPS, DbFactory.RestPort, DbFactory.RPCPort, DbFactory.ID));
 
-             response.Status = StatusCode.OK;
 
-             return response;
 
-         }
 
-     }
 
-     public class RestService<TEntity> : RestService where TEntity : Entity, new()
 
-     {
 
-         private static string SimpleName(Type t)
 
-         {
 
-             return t.Name.Split('.').Last();
 
-         }
 
-         public static QueryResponse<TEntity> List(QueryRequest<TEntity> request)
 
-         {
 
-             var start = DateTime.Now;
 
-             var response = new QueryResponse<TEntity>();
 
-             var userguid = ValidateRequest(request, out var userid);
 
-             if (userguid == Guid.Empty)
 
-                 return response.Status(StatusCode.Unauthenticated);
 
-             Logger.Send(LogType.Information, userid,
 
-                 string.Format("[{0} {1}] Query{2}: Filter=[{3}] Sort=[{4}]", request.Credentials.Platform, request.Credentials.Version,
 
-                     SimpleName(typeof(TEntity)), request.Filter != null ? request.Filter.ToString() : "",
 
-                     request.Sort != null ? request.Sort.AsOData() : ""));
 
-             try
 
-             {
 
-                 var store = DbFactory.FindStore<TEntity>(userguid, userid, request.Credentials.Platform, request.Credentials.Version);
 
-                 response.Items = store.Query(request.Filter, request.Columns, request.Sort, request.Range);
 
-                 response.Status = StatusCode.OK;
 
-                 Logger.Send(LogType.Information, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] Query{3} Complete: {4} records / {5} columns returned", request.Credentials.Platform,
 
-                         request.Credentials.Version, (int)DateTime.Now.Subtract(start).TotalMilliseconds, SimpleName(typeof(TEntity)),
 
-                         response.Items.Rows.Count, response.Items.Columns.Count));
 
-             }
 
-             catch (Exception err)
 
-             {
 
-                 response.Status = StatusCode.Error;
 
-                 response.Messages.Add(err.Message);
 
-                 Logger.Send(LogType.Error, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] Query{3} Failed: {4} ", request.Credentials.Platform, request.Credentials.Version,
 
-                         (int)DateTime.Now.Subtract(start).TotalMilliseconds, SimpleName(typeof(TEntity)), err.Message));
 
-             }
 
-             GarbageCollection();
 
-             return response;
 
-         }
 
-         /*public static LoadResponse<TEntity> Load(LoadRequest<TEntity> request)
 
-         {
 
-             var start = DateTime.Now;
 
-             var response = new LoadResponse<TEntity>();
 
-             var userguid = ValidateRequest(request, out var userid);
 
-             if (userguid == Guid.Empty)
 
-                 return response.Status(StatusCode.Unauthenticated);
 
-             Logger.Send(LogType.Information, userid,
 
-                 string.Format("[{0} {1}] Load{2}: Filter=[{3}]", request.Credentials.Platform, request.Credentials.Version,
 
-                     SimpleName(typeof(TEntity)),
 
-                     request.Filter != null ? request.Filter.AsOData() : ""));
 
-             try
 
-             {
 
-                 var store = DbFactory.FindStore<TEntity>(userguid, userid, request.Credentials.Platform, request.Credentials.Version);
 
-                 response.Items = store.Load(request.Filter, request.Sort);
 
-                 response.Status = StatusCode.OK;
 
-                 Logger.Send(LogType.Information, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] Load{3} Complete: {4} records returned", request.Credentials.Platform,
 
-                         request.Credentials.Version,
 
-                         (uint)DateTime.Now.Subtract(start).TotalMilliseconds, SimpleName(typeof(TEntity)), response.Items.Count()));
 
-             }
 
-             catch (Exception err)
 
-             {
 
-                 response.Status = StatusCode.Error;
 
-                 response.Messages.Add(err.Message);
 
-                 Logger.Send(LogType.Error, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] Load{3} Failed: {4} ", request.Credentials.Platform, request.Credentials.Version,
 
-                         (int)DateTime.Now.Subtract(start).TotalMilliseconds, SimpleName(typeof(TEntity)), err.Message));
 
-             }
 
-             GarbageCollection();
 
-             return response;
 
-         }*/
 
-         public static SaveResponse<TEntity> Save(SaveRequest<TEntity> request)
 
-         {
 
-             var start = DateTime.Now;
 
-             var response = new SaveResponse<TEntity>();
 
-             var userguid = ValidateRequest(request, out var userid);
 
-             if (userguid == Guid.Empty)
 
-                 return response.Status(StatusCode.Unauthenticated);
 
-             Logger.Send(LogType.Information, userid,
 
-                 string.Format("[{0} {1}] Save{2}: Data=[{3}]", request.Credentials.Platform, request.Credentials.Version, SimpleName(typeof(TEntity)),
 
-                     request.Item != null ? request.Item.ToString() : request + " (null)"));
 
-             try
 
-             {
 
-                 var e = request.Item;
 
-                 var preSaveChanges = BaseObjectExtensions.GetOriginaValues(e);
 
-                 var store = DbFactory.FindStore<TEntity>(userguid, userid, request.Credentials.Platform, request.Credentials.Version);
 
-                 store.Save(e, request.AuditNote);
 
-                 if (request.ReturnOnlyChanged)
 
-                 {
 
-                     var currentChanges = BaseObjectExtensions.GetOriginaValues(e);
 
-                     foreach (var (key, value) in currentChanges)
 
-                     {
 
-                         if (preSaveChanges.TryGetValue(key, out var oldValue))
 
-                         {
 
-                             if (!Equals(value, oldValue))
 
-                             {
 
-                                 response.ChangedValues.Add(key, CoreUtils.GetPropertyValue(e, key));
 
-                             }                          
 
-                         }
 
-                         else
 
-                         {
 
-                             response.ChangedValues.Add(key, CoreUtils.GetPropertyValue(e, key));
 
-                         }
 
-                     }
 
-                 }
 
-                 else
 
-                 {
 
-                     response.Item = e;
 
-                 }
 
-                 response.Status = StatusCode.OK;
 
-                 Logger.Send(LogType.Information, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] Save{3} Data=[{4}] Complete", request.Credentials.Platform, request.Credentials.Version,
 
-                         (int)DateTime.Now.Subtract(start).TotalMilliseconds, SimpleName(typeof(TEntity)), request.Item));
 
-                 CredentialsCache.Refresh(typeof(TEntity) == typeof(User));
 
-             }
 
-             catch (Exception err)
 
-             {
 
-                 response.Status = StatusCode.Error;
 
-                 response.Messages.Add(err.Message);
 
-                 Logger.Send(LogType.Error, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] Save{3} Failed: {4}\n\n{5} ", request.Credentials.Platform, request.Credentials.Version,
 
-                         (int)DateTime.Now.Subtract(start).TotalMilliseconds, SimpleName(typeof(TEntity)), err.Message, err.StackTrace));
 
-             }
 
-             GarbageCollection();
 
-             return response;
 
-         }
 
-         public static MultiSaveResponse<TEntity> MultiSave(MultiSaveRequest<TEntity> request)
 
-         {
 
-             var start = DateTime.Now;
 
-             var response = new MultiSaveResponse<TEntity>();
 
-             var userguid = ValidateRequest(request, out var userid);
 
-             if (userguid == Guid.Empty)
 
-                 return response.Status(StatusCode.Unauthenticated);
 
-             Logger.Send(LogType.Information, userid,
 
-                 string.Format("[{0} {1}] MultiSave{2}({3}) Data=[{4}]", request.Credentials.Platform, request.Credentials.Version,
 
-                     SimpleName(typeof(TEntity)), request.Items.Length,
 
-                     request.Items != null ? string.Join(", ", request.Items.Select(x => x.ToString())) : request + " (null)"));
 
-             try
 
-             {
 
-                 var originals = new Dictionary<TEntity, Dictionary<string, object>>();
 
-                 var es = request.Items;
 
-                 foreach (var e in es)
 
-                     originals[e] = BaseObjectExtensions.GetOriginaValues(e);
 
-                 var store = DbFactory.FindStore<TEntity>(userguid, userid, request.Credentials.Platform, request.Credentials.Version);
 
-                 store.Save(es, request.AuditNote);
 
-                 if (request.ReturnOnlyChanged)
 
-                 {                  
 
-                     for (int i = 0; i < es.Length; ++i)
 
-                     {
 
-                         var result = new Dictionary<string, object>();
 
-                         var e = es[i];
 
-                         var currentChanges = BaseObjectExtensions.GetOriginaValues(e);
 
-                         var preSaveChanges = originals[e];
 
-                         foreach (var (key, value) in currentChanges)
 
-                         {
 
-                             if (preSaveChanges.TryGetValue(key, out var oldValue))
 
-                             {
 
-                                 if (!Equals(value, oldValue))
 
-                                 {
 
-                                     result[key] = CoreUtils.GetPropertyValue(e, key);
 
-                                 }
 
-                             }
 
-                             else
 
-                             {
 
-                                 result[key] = CoreUtils.GetPropertyValue(e, key);
 
-                             }
 
-                         }
 
-                         response.ChangedValues.Add(result);
 
-                     }
 
-                 }
 
-                 else
 
-                 {
 
-                     response.Items = es;
 
-                 }
 
-                 response.Status = StatusCode.OK;
 
-                 Logger.Send(LogType.Information, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] MultiSave{3} Count=[{4}] Complete", request.Credentials.Platform, request.Credentials.Version,
 
-                         (int)DateTime.Now.Subtract(start).TotalMilliseconds, SimpleName(typeof(TEntity)), es.Length));
 
-                 CredentialsCache.Refresh(typeof(TEntity) == typeof(User));
 
-             }
 
-             catch (Exception err)
 
-             {
 
-                 response.Status = StatusCode.Error;
 
-                 response.Messages.Add(err.Message);
 
-                 Logger.Send(LogType.Error, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] MultiSave{3} Failed: {4}\n\n{5} ", request.Credentials.Platform, request.Credentials.Version,
 
-                         (int)DateTime.Now.Subtract(start).TotalMilliseconds, SimpleName(typeof(TEntity)), err.Message, err.StackTrace));
 
-             }
 
-             GarbageCollection();
 
-             return response;
 
-         }
 
-         public static DeleteResponse<TEntity> Delete(DeleteRequest<TEntity> request)
 
-         {
 
-             var start = DateTime.Now;
 
-             var response = new DeleteResponse<TEntity>();
 
-             var userguid = ValidateRequest(request, out var userid);
 
-             if (userguid == Guid.Empty)
 
-                 return response.Status(StatusCode.Unauthenticated);
 
-             Logger.Send(LogType.Information, userid,
 
-                 string.Format("[{0} {1}] Delete{2} Data=[{3}]", request.Credentials.Platform, request.Credentials.Version,
 
-                     SimpleName(typeof(TEntity)),
 
-                     request.Item));
 
-             try
 
-             {
 
-                 var store = DbFactory.FindStore<TEntity>(userguid, userid, request.Credentials.Platform, request.Credentials.Version);
 
-                 store.Delete(request.Item, request.AuditNote);
 
-                 response.Status = StatusCode.OK;
 
-                 Logger.Send(LogType.Information, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] Delete{3} Complete", request.Credentials.Platform, request.Credentials.Version,
 
-                         (int)DateTime.Now.Subtract(start).TotalMilliseconds, SimpleName(typeof(TEntity))));
 
-                 CredentialsCache.Refresh(typeof(TEntity) == typeof(User));
 
-             }
 
-             catch (Exception err)
 
-             {
 
-                 response.Status = StatusCode.Error;
 
-                 response.Messages.Add(err.Message);
 
-                 Logger.Send(LogType.Error, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] Delete{3} Failed: {4} ", request.Credentials.Platform, request.Credentials.Version,
 
-                         (int)DateTime.Now.Subtract(start).TotalMilliseconds, SimpleName(typeof(TEntity)), err.Message));
 
-             }
 
-             GarbageCollection();
 
-             return response;
 
-         }
 
-         public static MultiDeleteResponse<TEntity> MultiDelete(MultiDeleteRequest<TEntity> request)
 
-         {
 
-             var start = DateTime.Now;
 
-             var response = new MultiDeleteResponse<TEntity>();
 
-             var userguid = ValidateRequest(request, out var userid);
 
-             if (userguid == Guid.Empty)
 
-                 return response.Status(StatusCode.Unauthenticated);
 
-             Logger.Send(LogType.Information, userid,
 
-                 string.Format("[{0} {1}] MultiDelete{2}({3}) Data=[{4}]", request.Credentials.Platform, request.Credentials.Version,
 
-                     SimpleName(typeof(TEntity)), request.Items.Length,
 
-                     request.Items != null ? string.Join(", ", request.Items.Select(x => x.ToString())) : request + " (null)"));
 
-             try
 
-             {
 
-                 var es = request.Items;
 
-                 var store = DbFactory.FindStore<TEntity>(userguid, userid, request.Credentials.Platform, request.Credentials.Version);
 
-                 store.Delete(es, request.AuditNote);
 
-                 response.Status = StatusCode.OK;
 
-                 Logger.Send(LogType.Information, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] MultiDelete{3} Count=[{4}] Complete", request.Credentials.Platform, request.Credentials.Version,
 
-                         (int)DateTime.Now.Subtract(start).TotalMilliseconds, SimpleName(typeof(TEntity)), request.Items.Length));
 
-                 CredentialsCache.Refresh(typeof(TEntity) == typeof(User));
 
-             }
 
-             catch (Exception err)
 
-             {
 
-                 response.Status = StatusCode.Error;
 
-                 response.Messages.Add(err.Message);
 
-                 Logger.Send(LogType.Error, userid,
 
-                     string.Format("[{0} {1}] [{2:D8}] MultiDelete{3} Failed: {4}\n\n{5} ", request.Credentials.Platform, request.Credentials.Version,
 
-                         (int)DateTime.Now.Subtract(start).TotalMilliseconds, SimpleName(typeof(TEntity)), err.Message, err.StackTrace));
 
-             }
 
-             GarbageCollection();
 
-             return response;
 
-         }
 
-     }
 
- }
 
 
  |