From f9cb419da0f7b9d51cbc9d93beb18c1babe47c25 Mon Sep 17 00:00:00 2001 From: ig Date: Thu, 16 Mar 2023 08:49:01 +0100 Subject: [PATCH 1/6] store session under "Session" header --- csharp/App/Backend/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/App/Backend/Program.cs b/csharp/App/Backend/Program.cs index d49fa856c..d32326b7a 100644 --- a/csharp/App/Backend/Program.cs +++ b/csharp/App/Backend/Program.cs @@ -57,7 +57,7 @@ public static class Program var session = Db.GetSession(token); if (session is not null) - ctx.Items["User"] = session; + ctx.Items["Session"] = session; } await next(ctx); From 96018a5867f21f207a87aad72641a9861fe30749 Mon Sep 17 00:00:00 2001 From: ig Date: Thu, 16 Mar 2023 09:15:59 +0100 Subject: [PATCH 2/6] add Create User2Installation and User2Folder to Db --- csharp/App/Backend/Controllers/Controller.cs | 1 - csharp/App/Backend/Database/Create.cs | 10 ++++- csharp/App/Backend/Database/Db.cs | 43 +------------------- 3 files changed, 10 insertions(+), 44 deletions(-) diff --git a/csharp/App/Backend/Controllers/Controller.cs b/csharp/App/Backend/Controllers/Controller.cs index 322242871..2cb2ba46f 100644 --- a/csharp/App/Backend/Controllers/Controller.cs +++ b/csharp/App/Backend/Controllers/Controller.cs @@ -4,7 +4,6 @@ using InnovEnergy.App.Backend.DataTypes.Methods; using InnovEnergy.App.Backend.Relations; using Microsoft.AspNetCore.Mvc; using static System.Net.HttpStatusCode; -using static System.String; using Folder = InnovEnergy.App.Backend.DataTypes.Folder; using Installation = InnovEnergy.App.Backend.DataTypes.Installation; using Object = System.Object; diff --git a/csharp/App/Backend/Database/Create.cs b/csharp/App/Backend/Database/Create.cs index 875b5ddef..4eb630a82 100644 --- a/csharp/App/Backend/Database/Create.cs +++ b/csharp/App/Backend/Database/Create.cs @@ -29,10 +29,18 @@ public static partial class Db return Connection.Insert(user) > 0; } - public static Boolean Create(Session session) { return Connection.Insert(session) > 0; } + public static Boolean Create(User2Installation user2Installation) + { + return Connection.Insert(user2Installation) > 0; + } + + public static Boolean Create(User2Folder user2Folder) + { + return Connection.Insert(user2Folder) > 0; + } } \ No newline at end of file diff --git a/csharp/App/Backend/Database/Db.cs b/csharp/App/Backend/Database/Db.cs index 3e2fd815c..07bae933f 100644 --- a/csharp/App/Backend/Database/Db.cs +++ b/csharp/App/Backend/Database/Db.cs @@ -1,6 +1,5 @@ using System.Reactive.Linq; using InnovEnergy.App.Backend.DataTypes; -using InnovEnergy.App.Backend.DataTypes.Methods; using InnovEnergy.App.Backend.Relations; using InnovEnergy.Lib.Utils; using SQLite; @@ -39,10 +38,6 @@ public static partial class Db }); - var installation = Installations.First(); - UserMethods.CreateAndSaveInstallationS3ApiKey(installation); - - Observable.Interval(TimeSpan.FromDays(1)) .StartWith(0) // Do it right away (on startup) .Subscribe(Cleanup); // and then daily @@ -72,43 +67,7 @@ public static partial class Db - public static Boolean AddToAccessibleInstallations(Int64 userId, Int64 updatedInstallationId) - { - var con = new User2Installation - { - UserId = userId, - InstallationId = updatedInstallationId - }; - - try - { - Connection.Insert(con); - return true; - } - catch (Exception e) - { - return false; - } - } - - public static Boolean AddToAccessibleFolders(Int64 userId, Int64 updatedFolderId) - { - var con = new User2Folder - { - UserId = userId, - FolderId = updatedFolderId - }; - - try - { - Connection.Insert(con); - return true; - } - catch (Exception e) - { - return false; - } - } + private static void Cleanup(Int64 _) From 405308d7d663cbe2f66d50d45f0c5a62a956d654 Mon Sep 17 00:00:00 2001 From: ig Date: Thu, 16 Mar 2023 09:18:39 +0100 Subject: [PATCH 3/6] make Ancestors exclude self --- csharp/App/Backend/DataTypes/Methods/Folder.cs | 4 +++- .../App/Backend/DataTypes/Methods/Installation.cs | 9 ++++++--- csharp/App/Backend/DataTypes/Methods/User.cs | 13 ++++++------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/csharp/App/Backend/DataTypes/Methods/Folder.cs b/csharp/App/Backend/DataTypes/Methods/Folder.cs index 274574a4f..321aca9eb 100644 --- a/csharp/App/Backend/DataTypes/Methods/Folder.cs +++ b/csharp/App/Backend/DataTypes/Methods/Folder.cs @@ -33,7 +33,9 @@ public static class FolderMethods public static IEnumerable Ancestors(this Folder folder) { - return folder.Unfold(Parent); + return folder + .Unfold(Parent) + .Skip(1); // skip self } public static Folder? Parent(this Folder folder) diff --git a/csharp/App/Backend/DataTypes/Methods/Installation.cs b/csharp/App/Backend/DataTypes/Methods/Installation.cs index 795e8a1dc..dafcf2bd0 100644 --- a/csharp/App/Backend/DataTypes/Methods/Installation.cs +++ b/csharp/App/Backend/DataTypes/Methods/Installation.cs @@ -9,9 +9,12 @@ public static class InstallationMethods { var parentFolder = Parent(installation); - return parentFolder is null - ? Enumerable.Empty() - : parentFolder.Ancestors(); + if (parentFolder is null) + return Enumerable.Empty(); + + return parentFolder + .Ancestors() + .Prepend(parentFolder); } public static Folder? Parent(this Installation installation) diff --git a/csharp/App/Backend/DataTypes/Methods/User.cs b/csharp/App/Backend/DataTypes/Methods/User.cs index 99988f7e8..7f4796db7 100644 --- a/csharp/App/Backend/DataTypes/Methods/User.cs +++ b/csharp/App/Backend/DataTypes/Methods/User.cs @@ -1,8 +1,5 @@ -using System.Net.Http.Headers; using System.Net.Mail; using System.Security.Cryptography; -using System.Text.Json.Nodes; -using System.Text.RegularExpressions; using InnovEnergy.App.Backend.Database; using InnovEnergy.Lib.Utils; using Convert = System.Convert; @@ -88,7 +85,9 @@ public static class UserMethods private static IEnumerable Ancestors(this User user) { - return user.Unfold(Parent); + return user + .Unfold(Parent) + .Skip(1); // skip self } public static Boolean VerifyPassword(this User user, String password) @@ -135,7 +134,8 @@ public static class UserMethods if (folder is null) return false; - return folder + return user.HasDirectAccessTo(folder) + || folder .Ancestors() .Any(user.HasDirectAccessTo); } @@ -144,7 +144,7 @@ public static class UserMethods { return Db .User2Installation - .Any(r => r.InstallationId == installation.Id && r.UserId == user.Id); + .Any(r => r.UserId == user.Id && r.InstallationId == installation.Id); } public static Boolean HasAccessTo(this User user, Installation? installation) @@ -163,7 +163,6 @@ public static class UserMethods return other .Ancestors() - .Skip(1) // Important! skip self, user cannot delete or edit himself .Contains(user); } From 7cf27a78bc35ebb3976ec1f53048e939ab289302 Mon Sep 17 00:00:00 2001 From: ig Date: Thu, 16 Mar 2023 09:19:23 +0100 Subject: [PATCH 4/6] remove S3 signature building stuff --- csharp/App/Backend/DataTypes/Methods/User.cs | 147 ------------------- 1 file changed, 147 deletions(-) diff --git a/csharp/App/Backend/DataTypes/Methods/User.cs b/csharp/App/Backend/DataTypes/Methods/User.cs index 7f4796db7..e0b47f0a6 100644 --- a/csharp/App/Backend/DataTypes/Methods/User.cs +++ b/csharp/App/Backend/DataTypes/Methods/User.cs @@ -175,154 +175,7 @@ public static class UserMethods } - private static Byte[] HmacSha256Digest(String message, String secret) - { - // var encoding = new UTF8Encoding(); - // var keyBytes = encoding.GetBytes(secret); - // var messageBytes = encoding.GetBytes(message); - // var cryptographer = new HMACSHA256(keyBytes); - // return cryptographer.ComputeHash(messageBytes); - - var keyBytes = UTF8.GetBytes(secret); - var messageBytes = UTF8.GetBytes(message); - return HMACSHA256.HashData(keyBytes, messageBytes); - } - - private static String BuildSignature(String method, String path, String data, Int64 time, String secret) - { - var messageToSign = ""; - messageToSign += method + " /v2/" + path + "\n"; - messageToSign += data + "\n"; - - // query strings - messageToSign += "\n"; - // headers - messageToSign += "\n"; - - messageToSign += time; - - Console.WriteLine("Message to sign:\n" + messageToSign); - - var hmac = HmacSha256Digest(messageToSign, secret); - return Convert.ToBase64String(hmac); - } - - // public Object CreateAndSaveUserS3ApiKey(User user) - // { - // //EXOSCALE API URL - // const String url = "https://api-ch-dk-2.exoscale.com/v2/"; - // const String path = "access-key"; - // - // //TODO HIDE ME - // const String secret = "S2K1okphiCSNK4mzqr4swguFzngWAMb1OoSlZsJa9F0"; - // const String apiKey = "EXOb98ec9008e3ec16e19d7b593"; - // - // var installationList = User2Installation - // .Where(i => i.UserId == user.Id) - // .SelectMany(i => Installations.Where(f => i.InstallationId == f.Id)) - // .ToList(); - // - // - // var instList = new JsonArray(); - // - // foreach (var installation in installationList) - // { - // instList.Add(new JsonObject {["domain"] = "sos",["resource-name"] = installation.Name,["resource-type"] = "bucket"}); - // } - // - // var jsonPayload = new JsonObject { ["name"] = user.Email, ["operations"] = new JsonArray{ "list-sos-bucket", "get-sos-object" }, ["content"] = instList}; - // var stringPayload = jsonPayload.ToJsonString(); - // - // var unixExpiration = DateTimeOffset.UtcNow.ToUnixTimeSeconds()+60; - // var signature = BuildSignature("POST", path, stringPayload, unixExpiration , secret); - // - // var authHeader = "credential="+apiKey+",expires="+unixExpiration+",signature="+signature; - // - // var client = new HttpClient(); - // client.DefaultRequestHeaders.Authorization = - // new AuthenticationHeaderValue("EXO2-HMAC-SHA256", authHeader); - // - // var content = new StringContent(stringPayload, Encoding.UTF8, "application/json"); - // - // - // var response = client.PostAsync(url+path, content).Result; - // - // if (response.StatusCode.ToString() != "OK") - // { - // return response; - // } - // - // var responseString = response.Content.ReadAsStringAsync().Result; - // return Enumerable.Last(Regex.Match(responseString, "key\\\":\\\"([A-Z])\\w+").ToString().Split('"')); - // // return SetUserS3ApiKey(user, newKey); - // - // } - - public static Object CreateAndSaveInstallationS3ApiKey(Installation installation) - { - //EXOSCALE API URL - const String url = "https://api-ch-dk-2.exoscale.com/v2/"; - const String path = "access-key"; - - //TODO HIDE ME - const String secret = "S2K1okphiCSNK4mzqr4swguFzngWAMb1OoSlZsJa9F0"; - const String apiKey = "EXOb98ec9008e3ec16e19d7b593"; - - - var jsonPayload = new JsonObject - { - ["name"] = installation.Id, - ["operations"] = new JsonArray - { - "list-sos-bucket", - "get-sos-object" - }, - ["content"] = new JsonArray - { - new JsonObject - { - ["domain"] = "sos", - ["resource-name"] = installation.Name, - ["resource-type"] = "bucket" - } - } - }; - - var stringPayload = jsonPayload.ToJsonString(); - - var unixExpiration = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 60; - - var signature = BuildSignature("POST", path, stringPayload, unixExpiration, secret); - - var authHeader = "credential=" + apiKey + ",expires=" + unixExpiration + ",signature=" + signature; - - var client = new HttpClient(); - - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("EXO2-HMAC-SHA256", authHeader); - - var content = new StringContent(stringPayload, UTF8, "application/json"); - - var response = client.PostAsync(url + path, content).Result; - - if (response.StatusCode.ToString() != "OK") - { - return response; - } - - var responseString = response.Content.ReadAsStringAsync().Result; - var newKey = Regex - .Match(responseString, "key\\\":\\\"([A-Z])\\w+") - .ToString() - .Split('"') - .Last(); - - installation.S3Key = newKey; - Db.Update(installation); - return newKey; - } - - // TODO private static Boolean IsValidEmail(String email) From 2cb3701faecbafda1b349e4c79c460055375194e Mon Sep 17 00:00:00 2001 From: ig Date: Thu, 16 Mar 2023 09:25:36 +0100 Subject: [PATCH 5/6] rename User2Folder to FolderAccess, rename User2Installation to InstallationAccess --- csharp/App/Backend/Database/Create.cs | 8 ++++---- csharp/App/Backend/Database/Db.cs | 8 ++++---- csharp/App/Backend/Database/Fake.cs | 4 ++-- .../Backend/Relations/{User2Folder.cs => FolderAccess.cs} | 2 +- .../{User2Installation.cs => InstallationAccess.cs} | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) rename csharp/App/Backend/Relations/{User2Folder.cs => FolderAccess.cs} (80%) rename csharp/App/Backend/Relations/{User2Installation.cs => InstallationAccess.cs} (79%) diff --git a/csharp/App/Backend/Database/Create.cs b/csharp/App/Backend/Database/Create.cs index 4eb630a82..537192476 100644 --- a/csharp/App/Backend/Database/Create.cs +++ b/csharp/App/Backend/Database/Create.cs @@ -34,13 +34,13 @@ public static partial class Db return Connection.Insert(session) > 0; } - public static Boolean Create(User2Installation user2Installation) + public static Boolean Create(InstallationAccess installationAccess) { - return Connection.Insert(user2Installation) > 0; + return Connection.Insert(installationAccess) > 0; } - public static Boolean Create(User2Folder user2Folder) + public static Boolean Create(FolderAccess folderAccess) { - return Connection.Insert(user2Folder) > 0; + return Connection.Insert(folderAccess) > 0; } } \ No newline at end of file diff --git a/csharp/App/Backend/Database/Db.cs b/csharp/App/Backend/Database/Db.cs index 07bae933f..c543967e9 100644 --- a/csharp/App/Backend/Database/Db.cs +++ b/csharp/App/Backend/Database/Db.cs @@ -19,8 +19,8 @@ public static partial class Db public static TableQuery Folders => Connection.Table(); public static TableQuery Installations => Connection.Table(); public static TableQuery Users => Connection.Table(); - public static TableQuery User2Folder => Connection.Table(); - public static TableQuery User2Installation => Connection.Table(); + public static TableQuery User2Folder => Connection.Table(); + public static TableQuery User2Installation => Connection.Table(); static Db() @@ -32,8 +32,8 @@ public static partial class Db Connection.CreateTable(); Connection.CreateTable(); Connection.CreateTable(); - Connection.CreateTable(); - Connection.CreateTable(); + Connection.CreateTable(); + Connection.CreateTable(); Connection.CreateTable(); }); diff --git a/csharp/App/Backend/Database/Fake.cs b/csharp/App/Backend/Database/Fake.cs index ab144c11d..ce00e87a4 100644 --- a/csharp/App/Backend/Database/Fake.cs +++ b/csharp/App/Backend/Database/Fake.cs @@ -70,7 +70,7 @@ public static partial class Db foreach (var user in Users) while (Random.Shared.Next((Int32)(nUsers - user.Id + 1)) != 0) { - var relation = new User2Folder + var relation = new FolderAccess { UserId = user.Id, FolderId = Random.Shared.Next(nFolders) + 1 @@ -89,7 +89,7 @@ public static partial class Db foreach (var user in Users) while (Random.Shared.Next(5) != 0) { - var relation = new User2Installation + var relation = new InstallationAccess { UserId = user.Id, InstallationId = Random.Shared.Next(nbInstallations) + 1 diff --git a/csharp/App/Backend/Relations/User2Folder.cs b/csharp/App/Backend/Relations/FolderAccess.cs similarity index 80% rename from csharp/App/Backend/Relations/User2Folder.cs rename to csharp/App/Backend/Relations/FolderAccess.cs index 0cd1fa191..545647a46 100644 --- a/csharp/App/Backend/Relations/User2Folder.cs +++ b/csharp/App/Backend/Relations/FolderAccess.cs @@ -2,7 +2,7 @@ using SQLite; namespace InnovEnergy.App.Backend.Relations; -public class User2Folder : Relation +public class FolderAccess : Relation { [Indexed] public Int64 UserId { get => Left ; init => Left = value;} [Indexed] public Int64 FolderId { get => Right; init => Right = value;} diff --git a/csharp/App/Backend/Relations/User2Installation.cs b/csharp/App/Backend/Relations/InstallationAccess.cs similarity index 79% rename from csharp/App/Backend/Relations/User2Installation.cs rename to csharp/App/Backend/Relations/InstallationAccess.cs index f898253db..c233ca953 100644 --- a/csharp/App/Backend/Relations/User2Installation.cs +++ b/csharp/App/Backend/Relations/InstallationAccess.cs @@ -2,7 +2,7 @@ using SQLite; namespace InnovEnergy.App.Backend.Relations; -public class User2Installation : Relation +public class InstallationAccess : Relation { [Indexed] public Int64 UserId { get => Left ; init => Left = value;} [Indexed] public Int64 InstallationId { get => Right; init => Right = value;} From 4c87fcb5ea63c1114d74402ea2504087c5e8b1b4 Mon Sep 17 00:00:00 2001 From: ig Date: Thu, 16 Mar 2023 09:33:54 +0100 Subject: [PATCH 6/6] implement GrantUserAccessTo for folders and installations --- .../App/Backend/DataTypes/Methods/Session.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/csharp/App/Backend/DataTypes/Methods/Session.cs b/csharp/App/Backend/DataTypes/Methods/Session.cs index fc66f90d1..86960dab2 100644 --- a/csharp/App/Backend/DataTypes/Methods/Session.cs +++ b/csharp/App/Backend/DataTypes/Methods/Session.cs @@ -110,6 +110,34 @@ public static class SessionMethods && Db.Delete(userToDelete); } + + public static Boolean GrantUserAccessTo(this Session? session, User? user, Installation? installation) + { + var sessionUser = session?.User; + + return sessionUser is not null + && user is not null + && installation is not null + && user.IsDescendantOf(sessionUser) + && sessionUser.HasAccessTo(installation) + && !user.HasAccessTo(installation) + && Db.Create(new InstallationAccess { UserId = user.Id, InstallationId = installation.Id }); + + } + + public static Boolean GrantUserAccessTo(this Session? session, User? user, Folder? folder) + { + var sessionUser = session?.User; + + return sessionUser is not null + && user is not null + && folder is not null + && user.IsDescendantOf(sessionUser) + && sessionUser.HasAccessTo(folder) + && !user.HasAccessTo(folder) + && Db.Create(new FolderAccess { UserId = user.Id, FolderId = folder.Id }); + } + public static Boolean Logout(this Session? session) { return session is not null