using System.Net.Http.Headers; using System.Net.Mail; using System.Security.Cryptography; using System.Text; using System.Text.Json.Nodes; using System.Text.RegularExpressions; using InnovEnergy.App.Backend.Model; using InnovEnergy.App.Backend.Utils; using InnovEnergy.Lib.Utils; namespace InnovEnergy.App.Backend.Database; public static partial class Db { public static IEnumerable GetChildUsers(this User parent) { return Users .Where(f => f.ParentId == parent.Id); } public static IEnumerable GetDescendantUsers(this User parent) { return parent.Traverse(GetChildUsers); } public static Boolean IsDescendantOf(this User user, User ancestor) { return Ancestors(user) .Any(u => u.Id == ancestor.Id); } private static IEnumerable Ancestors(this User child) { return child.Unfold(GetParent); } public static User? GetParent(this User u) { return IsRoot(u) ? null : GetUserById(u.ParentId); } public static Boolean IsRoot(this User u) { return u.ParentId == 0; // root has ParentId 0 by definition } public static Boolean HasDirectAccessToFolder(this User user, Folder folder) { return HasDirectAccessToFolder(user, folder.Id); } public static Boolean HasDirectAccessToFolder(this User user, Int64 folderId) { return User2Folder.Any(r => r.FolderId == folderId && r.UserId == user.Id); } public static Boolean HasAccessToFolder(this User user, Int64 folderId) { var folder = GetFolderById(folderId); if (folder is null) return false; return Ancestors(folder).Any(f => HasDirectAccessToFolder(user, f)); } public static User? GetUserByEmail(String email) => Users.FirstOrDefault(u => u.Email == email); public static Int64 CreateUser(User user) { if (GetUserByEmail(user.Email) is not null) return -1; // TODO: User with that email already exists //Salting and Hashing password var salt = Crypto.GenerateSalt(); var hashedPassword = Crypto.ComputeHash(Encoding.UTF8.GetBytes(user.Password), Encoding.UTF8.GetBytes(salt + "innovEnergy")); user.Salt = salt; user.Password = hashedPassword; return Create(user); } 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); } 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 instList = new JsonArray(); instList.Add(new JsonObject {["domain"] = "sos",["resource-name"] = installation.Name,["resource-type"] = "bucket"}); var jsonPayload = new JsonObject { ["name"] = installation.Id, ["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; var newKey = Enumerable.Last(Regex.Match(responseString, "key\\\":\\\"([A-Z])\\w+").ToString().Split('"')); installation.S3Key = newKey; UpdateInstallation(installation); return newKey; } public static Boolean UpdateUser(User user) { var oldUser = GetUserById(user.Id); if (oldUser == null) return false; // TODO: "User doesn't exist" //Checking for unchangeable things // TODO: depends on privileges of caller user.Id = oldUser.Id; user.ParentId = oldUser.ParentId; user.Email = oldUser.Email; return Update(user); } public static Boolean DeleteUser(User user) { User2Folder.Delete(u => u.UserId == user.Id); User2Installation.Delete(u => u.UserId == user.Id); //Todo check for orphaned Installations/Folders // GetChildUsers() return Delete(user); } // TODO private static Boolean IsValidEmail(String email) { try { var emailAddress = new MailAddress(email); } catch { return false; } return true; } }