241 lines
7.6 KiB
C#
241 lines
7.6 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
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 Flurl.Http;
|
|
using InnovEnergy.App.Backend.Model;
|
|
using InnovEnergy.App.Backend.Utils;
|
|
using InnovEnergy.Lib.Utils;
|
|
using SQLite;
|
|
using ResponseExtensions = Flurl.Http.ResponseExtensions;
|
|
|
|
#pragma warning disable CS0472
|
|
#pragma warning disable CS8602
|
|
|
|
namespace InnovEnergy.App.Backend.Database;
|
|
|
|
public partial class Db
|
|
{
|
|
private TableQuery<User> Users => _Db.Table<User>();
|
|
|
|
public Int32 NbUsers => Users.Count();
|
|
|
|
public User? GetUserById(Int64 id)
|
|
{
|
|
return Users.FirstOrDefault(u => u.Id == id);
|
|
}
|
|
|
|
public Boolean IsParentOfChild(Int64 parentId, User child)
|
|
{
|
|
return Ancestors(child)
|
|
.Any(u => u.Id == parentId);
|
|
}
|
|
|
|
private IEnumerable<User> Ancestors(User child)
|
|
{
|
|
return child.Unfold(GetParent);
|
|
}
|
|
|
|
public User? GetParent(User u)
|
|
{
|
|
return IsRoot(u)
|
|
? null
|
|
: GetUserById(u.ParentId);
|
|
}
|
|
|
|
public static Boolean IsRoot(User u)
|
|
{
|
|
return u.ParentId == 0; // root has ParentId 0 by definition
|
|
}
|
|
|
|
public User? GetUserByEmail(String email) => Users.FirstOrDefault(u => u.Email == email);
|
|
|
|
public Result CreateUser(User user)
|
|
{
|
|
if (GetUserByEmail(user.Email) is not null)
|
|
return Result.Error("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);
|
|
|
|
var bytes = cryptographer.ComputeHash(messageBytes);
|
|
return bytes;
|
|
}
|
|
|
|
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 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 Result UpdateUser(User user)
|
|
{
|
|
var oldUser = GetUserById(user.Id);
|
|
if (oldUser == null)
|
|
return Result.Error("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 Result 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;
|
|
}
|
|
} |