diff --git a/csharp/.idea/.idea.InnovEnergy/.idea/dataSources.local.xml b/csharp/.idea/.idea.InnovEnergy/.idea/dataSources.local.xml index a62517f8c..b4bb05128 100644 --- a/csharp/.idea/.idea.InnovEnergy/.idea/dataSources.local.xml +++ b/csharp/.idea/.idea.InnovEnergy/.idea/dataSources.local.xml @@ -14,17 +14,5 @@ - - - " - - - no-auth - - - - - - \ No newline at end of file diff --git a/csharp/.idea/.idea.InnovEnergy/.idea/dataSources.xml b/csharp/.idea/.idea.InnovEnergy/.idea/dataSources.xml index 4813994e8..05388d9aa 100644 --- a/csharp/.idea/.idea.InnovEnergy/.idea/dataSources.xml +++ b/csharp/.idea/.idea.InnovEnergy/.idea/dataSources.xml @@ -8,17 +8,5 @@ jdbc:sqlite:$PROJECT_DIR$/app/Backend/db.sqlite $ProjectFileDir$ - - sqlite.xerial - true - org.sqlite.JDBC - jdbc:sqlite:$PROJECT_DIR$/app/Backend/db.sqlite-original - $ProjectFileDir$ - - - file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.39.2/sqlite-jdbc-3.39.2.jar - - - \ No newline at end of file diff --git a/csharp/app/Backend/Controllers/Controller.cs b/csharp/app/Backend/Controllers/Controller.cs index 2c4187801..32b53084e 100644 --- a/csharp/app/Backend/Controllers/Controller.cs +++ b/csharp/app/Backend/Controllers/Controller.cs @@ -6,10 +6,10 @@ using Backend.Model; using Backend.Model.Relations; using Backend.Utils; using Microsoft.AspNetCore.Mvc; +using HttpContextAccessor = Microsoft.AspNetCore.Http.HttpContextAccessor; namespace Backend.Controllers; - [ApiController] [Route("api/")] public class Controller @@ -17,31 +17,35 @@ public class Controller [ProducesResponseType(200)] [ProducesResponseType(401)] [HttpPost($"{nameof(Login)}")] - public Object Login(JsonElement usernamepass) + public Object Login(Credentials credentials) { - usernamepass.TryGetProperty("username", out var usr); - usernamepass.TryGetProperty("password", out var pwd); - var username = usr.ToString(); - var password = pwd.ToString(); - - if (username is null || username == "" || password == "" || password is null) + if (String.IsNullOrWhiteSpace(credentials.Username) || + String.IsNullOrWhiteSpace(credentials.Password)) return new HttpResponseMessage(HttpStatusCode.BadRequest); using var db = Db.Connect(); - var user = db.GetUserByEmail(username); - - var hashedPassword = Crypto.ComputeHash(Encoding.UTF8.GetBytes(password), - Encoding.UTF8.GetBytes(user.Salt + "innovEnergy")); + var user = db.GetUserByEmail(credentials.Username); - //Same error as to not communicate if a user exists or not - if (user is null || user.Password != hashedPassword) + if (user is null) return new HttpResponseMessage(HttpStatusCode.Unauthorized); + + // if (!VerifyPassword(password, user)) + // return new HttpResponseMessage(HttpStatusCode.Unauthorized); var ses = new Session(user); db.NewSession(ses); return ses.Token; } - + + private static Boolean VerifyPassword(String password, User user) + { + var pwdBytes = Encoding.UTF8.GetBytes(password); + var saltBytes = Encoding.UTF8.GetBytes(user.Salt + "innovEnergy"); + var pwdHash = Crypto.ComputeHash(pwdBytes, saltBytes); + + return user.Password == pwdHash; + } + [ProducesResponseType(200)] [ProducesResponseType(401)] [HttpPost($"{nameof(Logout)}")] @@ -72,7 +76,7 @@ public class Controller } - [ProducesResponseType(200)] + [ProducesResponseType(typeof(User), 200)] [ProducesResponseType(401)] [HttpGet($"{nameof(GetUserById)}")] public Object GetUserById(Int64 id) @@ -88,9 +92,9 @@ public class Controller return new HttpResponseMessage(HttpStatusCode.Unauthorized); return viewedUser; - } - - [ProducesResponseType(200)] + } + + [ProducesResponseType(typeof(Installation), 200)] [ProducesResponseType(401)] [HttpGet($"{nameof(GetInstallationById)}")] public Object GetInstallationById(Int64 id) @@ -99,17 +103,21 @@ public class Controller var ctx = ctxAccessor.HttpContext; using var db = Db.Connect(); var currentUser = (User)ctx.Items["User"]; - var installation = db.GetInstallationById(id); - if(currentUser==null - || db.GetAllAccessibleInstallationIds(currentUser).ToList().Contains(id)) - return installation == null ? new HttpResponseMessage(HttpStatusCode.NotFound) - : installation; + if (currentUser == null) + return new HttpResponseMessage(HttpStatusCode.Unauthorized); + + var installation = db + .GetAllAccessibleInstallations(currentUser) + .FirstOrDefault(i => i.Id == id); - return new HttpResponseMessage(HttpStatusCode.Unauthorized); + if (installation is null) + return new HttpResponseMessage(HttpStatusCode.NotFound); + + return installation; } - - [ProducesResponseType(200)] + + [ProducesResponseType(typeof(Folder), 200)] [ProducesResponseType(401)] [HttpGet($"{nameof(GetFolderById)}")] public Object GetFolderById(Int64 id) @@ -118,14 +126,15 @@ public class Controller var ctx = ctxAccessor.HttpContext; using var db = Db.Connect(); var currentUser = (User)ctx.Items["User"]; - var folder = db.GetFolderById(id); - - if(currentUser==null - || db.GetAllAccessibleFolderIds(currentUser).ToList().Contains(id)) - return folder == null ? new HttpResponseMessage(HttpStatusCode.NotFound) - : folder; - return new HttpResponseMessage(HttpStatusCode.Unauthorized); + var folder = db + .GetAllAccessibleFolders(currentUser!) + .FirstOrDefault(f => f.Id == id); + + if(folder is null) + return new HttpResponseMessage(HttpStatusCode.NotFound); + + return folder; } [ProducesResponseType(200)] @@ -137,10 +146,11 @@ public class Controller var ctx = ctxAccessor.HttpContext; using var db = Db.Connect(); var user = (User)ctx.Items["User"]; + + if (user == null) + return new HttpResponseMessage(HttpStatusCode.Unauthorized); - if (user != null) return db.GetAllAccessibleInstallations(user).ToList(); - - return new HttpResponseMessage(HttpStatusCode.Unauthorized); + return db.GetAllAccessibleInstallations(user).ToList(); } [ProducesResponseType(200)] @@ -149,13 +159,15 @@ public class Controller public Object GetAllFolders() { var ctxAccessor = new HttpContextAccessor(); - var ctx = ctxAccessor.HttpContext; - using var db = Db.Connect(); + var ctx = ctxAccessor.HttpContext; var user = (User)ctx.Items["User"]; - if (user != null) return db.GetAllAccessibleFolders(user).ToList(); + using var db = Db.Connect(); + + if (user == null) + return new HttpResponseMessage(HttpStatusCode.Unauthorized); - return new HttpResponseMessage(HttpStatusCode.Unauthorized); + return db.GetAllAccessibleFolders(user).ToList(); } [ProducesResponseType(200)] @@ -181,21 +193,26 @@ public class Controller { var ctxAccessor = new HttpContextAccessor(); var ctx = ctxAccessor.HttpContext; - using var db = Db.Connect(); + var currentUser = (User)ctx.Items["User"]; if (currentUser == null || !currentUser.HasWriteAccess) return new HttpResponseMessage(HttpStatusCode.Unauthorized); + + using var db = Db.Connect(); - if(db.GetAllAccessibleInstallationIds(currentUser).ToList().Contains(updatedInstallation.Id)) - return db.GetInstallationById(updatedInstallation.Id) == null - ? new HttpResponseMessage(HttpStatusCode.Unauthorized) - : db.UpdateInstallation(updatedInstallation); + var hasAccess = db.GetAllAccessibleInstallations(currentUser) + .Any(i => i.Id == updatedInstallation.Id); + if (!hasAccess) + return new HttpResponseMessage(HttpStatusCode.Unauthorized); + + // TODO: accessibility by other users etc + // TODO: sanity check changes - db.AddToAccessibleInstallations(currentUser.Id, updatedInstallation.Id); - return db.CreateInstallation(updatedInstallation); + return db.UpdateInstallation(updatedInstallation); } + [ProducesResponseType(200)] [ProducesResponseType(401)] [HttpPut($"{nameof(UpdateFolder)}/")] @@ -209,13 +226,16 @@ public class Controller if (currentUser == null || !currentUser.HasWriteAccess) return new HttpResponseMessage(HttpStatusCode.Unauthorized); - if(db.GetAllAccessibleFolderIds(currentUser).ToList().Contains(updatedFolder.Id)) - return db.GetFolderById(updatedFolder.Id) == null - ? new HttpResponseMessage(HttpStatusCode.Unauthorized) - : db.UpdateFolder(updatedFolder); + var hasAccess = db.GetAllAccessibleFolders(currentUser) + .Any(f => f.Id == updatedFolder.Id); + + if (!hasAccess) + return new HttpResponseMessage(HttpStatusCode.Unauthorized); - db.AddToAccessibleFolders(currentUser.Id, updatedFolder.Id); - return db.CreateFolder(updatedFolder); + // TODO: accessibility by other users etc + // TODO: sanity check changes + + return db.UpdateFolder(updatedFolder); } [ProducesResponseType(200)] @@ -241,18 +261,18 @@ public class Controller [ProducesResponseType(200)] [ProducesResponseType(401)] [HttpDelete($"{nameof(DeleteInstallation)}/")] - public Object DeleteInstallation(Int64 installationId) + public Object DeleteInstallation(Int64 idOfInstallationToBeDeleted) { var ctxAccessor = new HttpContextAccessor(); var ctx = ctxAccessor.HttpContext; using var db = Db.Connect(); var currentUser = (User)ctx.Items["User"]; - var installationToBeDeleted = db.GetInstallationById(installationId); + + var installationToBeDeleted = db + .GetAllAccessibleInstallations(currentUser!) + .FirstOrDefault(i => i.Id == idOfInstallationToBeDeleted); - if (currentUser == null - || installationToBeDeleted == null - || !currentUser.HasWriteAccess - || !db.GetAllAccessibleInstallationIds(currentUser).ToList().Contains(installationToBeDeleted.Id)) + if (installationToBeDeleted is null) return new HttpResponseMessage(HttpStatusCode.Unauthorized); return db.DeleteInstallation(installationToBeDeleted); @@ -267,15 +287,15 @@ public class Controller var ctx = ctxAccessor.HttpContext; using var db = Db.Connect(); var currentUser = (User)ctx.Items["User"]; - var folderToBeDeleted = db.GetFolderById(folderId); + + var folderToDelete = db + .GetAllAccessibleFolders(currentUser!) + .FirstOrDefault(f => f.Id == folderId); - if (currentUser == null - || folderToBeDeleted == null - || !currentUser.HasWriteAccess - || !db.GetAllAccessibleFolderIds(currentUser).ToList().Contains(folderToBeDeleted.Id)) + if (folderToDelete is null) return new HttpResponseMessage(HttpStatusCode.Unauthorized); - return db.DeleteFolder(folderToBeDeleted); + return db.DeleteFolder(folderToDelete); } diff --git a/csharp/app/Backend/Controllers/Credentials.cs b/csharp/app/Backend/Controllers/Credentials.cs new file mode 100644 index 000000000..43c86a811 --- /dev/null +++ b/csharp/app/Backend/Controllers/Credentials.cs @@ -0,0 +1,3 @@ +namespace Backend.Controllers; + +public record Credentials(String Username, String Password); \ No newline at end of file diff --git a/csharp/app/Backend/Database/Db.cs b/csharp/app/Backend/Database/Db.cs index e679d9eaa..92d31ca84 100644 --- a/csharp/app/Backend/Database/Db.cs +++ b/csharp/app/Backend/Database/Db.cs @@ -97,29 +97,14 @@ public partial class Db : IDisposable return direct.Concat(fromFolders); } - public IEnumerable GetAllAccessibleInstallationIds(User user) - { - var direct = GetDirectlyAccessibleInstallationIds(user); - var fromFolders = GetAllAccessibleFolders(user) - .SelectMany(GetChildInstallations) - .Select(installation => installation.Id); - - return direct.Concat(fromFolders); - } - + public IEnumerable GetAllAccessibleFolders(User user) { return GetDirectlyAccessibleFolders(user) .SelectMany(GetDescendantFolders); } - public IEnumerable GetAllAccessibleFolderIds(User user) - { - return GetDirectlyAccessibleFolders(user) - .SelectMany(GetDescendantFolders) - .Select(folder => folder.Id ); - } - + public IEnumerable GetDirectlyAccessibleInstallations(User user) { return User2Installation @@ -129,14 +114,6 @@ public partial class Db : IDisposable .NotNull(); } - public IEnumerable GetDirectlyAccessibleInstallationIds(User user) - { - return User2Installation - .Where(r => r.UserId == user.Id) - .Select(r => r.InstallationId) - .NotNull(); - } - public IEnumerable GetDirectlyAccessibleFolders(User user) { return User2Folder @@ -148,10 +125,12 @@ public partial class Db : IDisposable public Result AddToAccessibleInstallations(Int64 userId, Int64 updatedInstallationId) { - var con = new User2Installation(); - con.UserId = userId; - con.InstallationId = updatedInstallationId; - + var con = new User2Installation + { + UserId = userId, + InstallationId = updatedInstallationId + }; + try { _Db.InsertOrReplace(con); @@ -166,10 +145,12 @@ public partial class Db : IDisposable public Result AddToAccessibleFolders(Int64 userId, Int64 updatedFolderId) { - var con = new User2Folder(); - con.UserId = userId; - con.FolderId = updatedFolderId; - + var con = new User2Folder + { + UserId = userId, + FolderId = updatedFolderId + }; + try { _Db.InsertOrReplace(con); @@ -213,9 +194,7 @@ public partial class Db : IDisposable { try { - Sessions - .Where(u => u.UserId == id) - .Delete(); + Sessions.Delete(u => u.UserId == id); } catch (Exception e) { diff --git a/csharp/app/Backend/Database/Fake.cs b/csharp/app/Backend/Database/Fake.cs index 582115ef6..94325df6d 100644 --- a/csharp/app/Backend/Database/Fake.cs +++ b/csharp/app/Backend/Database/Fake.cs @@ -65,9 +65,10 @@ public partial class Db _Db.Delete(uf); var nFolders = NbFolders; + var nUsers = NbUsers; foreach (var user in Users) - while (Random.Shared.Next(5) != 0) + while (Random.Shared.Next((Int32)(nUsers - user.Id + 1)) != 0) { var relation = new User2Folder { diff --git a/csharp/app/Backend/Database/Folder.cs b/csharp/app/Backend/Database/Folder.cs index 14057f4ce..f7411e017 100644 --- a/csharp/app/Backend/Database/Folder.cs +++ b/csharp/app/Backend/Database/Folder.cs @@ -21,19 +21,20 @@ public partial class Db //return PopulateDescendants(folder); } - public IEnumerable GetChildFolders(Folder folder) + public IEnumerable GetChildFolders(Folder parent) { - return Folders.Where(f => f.ParentId == f.Id); + return Folders.Where(f => f.ParentId == parent.Id); } - public IEnumerable GetDescendantFolders(Folder folder) + + public IEnumerable GetDescendantFolders(Folder parent) { - return folder.Traverse(GetChildFolders); + return parent.Traverse(GetChildFolders); } - public IEnumerable GetChildInstallations(Folder folder) + public IEnumerable GetChildInstallations(Folder parent) { - return Installations.Where(f => f.ParentId == f.Id); + return Installations.Where(f => f.ParentId == parent.Id); } @@ -63,18 +64,14 @@ public partial class Db public Result DeleteFolder(Folder folder) { - - User2Folder - .Where(f => f.FolderId == folder.Id) - .Delete(); + // Delete direct children + User2Folder .Delete(f => f.FolderId == folder.Id); + Installations.Delete(i => i.ParentId == folder.Id); + + // recursion + Folders.Where(f => f.ParentId == folder.Id) + .ForEach(DeleteFolder); - // TODO: delete descendants? Here they are just adopted one level up - foreach (var l in Installations - .Where(i => i.ParentId == folder.Id)) - { - ChangeParent(l, folder.ParentId); - } - return Delete(folder); } diff --git a/csharp/app/Backend/Database/Installation.cs b/csharp/app/Backend/Database/Installation.cs index 0e6fdf2db..5473892af 100644 --- a/csharp/app/Backend/Database/Installation.cs +++ b/csharp/app/Backend/Database/Installation.cs @@ -24,11 +24,10 @@ public partial class Db return Update(installation); } + public Result DeleteInstallation(Installation installation) { - User2Installation - .Where(i => i.InstallationId == installation.Id) - .Delete(); + User2Installation.Delete(i => i.InstallationId == installation.Id); return Delete(installation); } diff --git a/csharp/app/Backend/Database/User.cs b/csharp/app/Backend/Database/User.cs index 01c9e6daf..cda467968 100644 --- a/csharp/app/Backend/Database/User.cs +++ b/csharp/app/Backend/Database/User.cs @@ -107,24 +107,24 @@ public partial class Db return Result.Error("User doesn't exist"); //Checking for unchangeable things - user.Id = oldUser.Id; + // TODO: depends on privileges of caller + + user.Id = oldUser.Id; user.ParentId = oldUser.ParentId; - user.Email = oldUser.Email; + user.Email = oldUser.Email; return Update(user); } public Result DeleteUser(User user) { - User2Folder - .Where(u => u.UserId == user.Id) - .Delete(); - User2Installation - .Where(u => u.UserId == user.Id) - .Delete(); + User2Folder .Delete(u => u.UserId == user.Id); + User2Installation.Delete(u => u.UserId == user.Id); //Todo check for orphaned Installations/Folders + // GetChildUsers() + return Delete(user); } diff --git a/csharp/app/Backend/NewFile1.txt b/csharp/app/Backend/NewFile1.txt deleted file mode 100644 index 65994019c..000000000 --- a/csharp/app/Backend/NewFile1.txt +++ /dev/null @@ -1 +0,0 @@ -Backend.csproj Controllers/Controller.cs Controllers/DatabaseHandler.cs Models/Folder.cs Models/Installation.cs Models/Token.cs Models/User.cs Program.cs Properties/launchSettings.json ServerFunctions/RequestJsonGetters.cs ServerFunctions/ServerFunctions.cs appsettings.Development.json appsettings.json identifier.sqlite \ No newline at end of file diff --git a/csharp/app/Backend/db.sqlite b/csharp/app/Backend/db.sqlite index 262924b5a..da6dc625a 100644 Binary files a/csharp/app/Backend/db.sqlite and b/csharp/app/Backend/db.sqlite differ