Merge branch 'main' of https://git.innov.energy/Innovenergy/git_trunk
This commit is contained in:
commit
b0aebf6e7d
|
@ -3,6 +3,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Flurl.Http" Version="3.2.4" />
|
||||
<PackageReference Include="MailKit" Version="3.6.0" />
|
||||
<PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.3" />
|
||||
<PackageReference Include="Microsoft.AspNet.Identity.Owin" Version="2.2.3" />
|
||||
<PackageReference Include="Microsoft.AspNet.WebApi.Core" Version="5.2.9" />
|
||||
|
@ -26,14 +27,16 @@
|
|||
<ProjectReference Include="../../Lib/Utils/Utils.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Resources/s3cmd.py">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="Resources\urlAndKey.json">
|
||||
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -2,7 +2,6 @@ using InnovEnergy.App.Backend.Database;
|
|||
using InnovEnergy.App.Backend.DataTypes;
|
||||
using InnovEnergy.App.Backend.DataTypes.Methods;
|
||||
using InnovEnergy.App.Backend.Relations;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace InnovEnergy.App.Backend.Controllers;
|
||||
|
@ -17,11 +16,19 @@ public class Controller : ControllerBase
|
|||
public ActionResult<Session> Login(String username, String password)
|
||||
{
|
||||
var user = Db.GetUserByName(username);
|
||||
|
||||
if (user is null || !user.VerifyPassword(password))
|
||||
|
||||
if (user is null)
|
||||
return Unauthorized();
|
||||
|
||||
if (!(user.Password is null && user.MustResetPassword))
|
||||
{
|
||||
if (!user.VerifyPassword(password))
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
var session = new Session(user);
|
||||
|
||||
//TODO The Frontend should check for the MustResetPassword Flag
|
||||
|
||||
return Db.Create(session)
|
||||
? session
|
||||
|
@ -106,7 +113,7 @@ public class Controller : ControllerBase
|
|||
.Ancestors()
|
||||
.SelectMany(f => f.UsersWithDirectAccess()
|
||||
.Where(u => u.IsDescendantOf(user))
|
||||
.Select(u => new { folderId = f.Id, user = u }))
|
||||
.Select(u => new { folderId = f.Id, folderName = f.Name, user = u }))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
@ -144,7 +151,7 @@ public class Controller : ControllerBase
|
|||
.Ancestors()
|
||||
.SelectMany(f => f.UsersWithDirectAccess()
|
||||
.Where(u => u.IsDescendantOf(user))
|
||||
.Select(u => new { folderId = f.Id, user = u }))
|
||||
.Select(u => new { folderId = f.Id, folderName = f.Name, user = u }))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
@ -317,6 +324,18 @@ public class Controller : ControllerBase
|
|||
}
|
||||
|
||||
|
||||
[HttpPut(nameof(UpdatePassword))]
|
||||
public ActionResult<User> UpdatePassword(String newPassword, Token authToken)
|
||||
{
|
||||
var session = Db.GetSession(authToken);
|
||||
|
||||
return session.UpdatePassword(newPassword)
|
||||
? Ok()
|
||||
: Unauthorized();
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpPut(nameof(UpdateInstallation))]
|
||||
public ActionResult<Installation> UpdateInstallation(Installation installation, Token authToken)
|
||||
{
|
||||
|
@ -340,6 +359,26 @@ public class Controller : ControllerBase
|
|||
return folder;
|
||||
}
|
||||
|
||||
[HttpPut(nameof(MoveInstallation))]
|
||||
public ActionResult MoveInstallation(Int64 installationId,Int64 parentId, Token authToken)
|
||||
{
|
||||
var session = Db.GetSession(authToken);
|
||||
|
||||
return session.MoveInstallation(installationId, parentId)
|
||||
? Ok()
|
||||
: Unauthorized();
|
||||
}
|
||||
|
||||
[HttpPut(nameof(MoveFolder))]
|
||||
public ActionResult MoveFolder(Int64 folderId,Int64 parentId, Token authToken)
|
||||
{
|
||||
var session = Db.GetSession(authToken);
|
||||
|
||||
return session.MoveFolder(folderId, parentId)
|
||||
? Ok()
|
||||
: Unauthorized();
|
||||
}
|
||||
|
||||
[HttpDelete(nameof(DeleteUser))]
|
||||
public ActionResult DeleteUser(Int64 userId, Token authToken)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
namespace InnovEnergy.App.Backend.DataTypes;
|
||||
|
||||
public class DeletedFolder : TreeNode {}
|
||||
|
||||
//Deleted Things need to have AT LEAST every property that normal things have
|
||||
//Todo "Restore" Function? -k
|
|
@ -0,0 +1,19 @@
|
|||
namespace InnovEnergy.App.Backend.DataTypes;
|
||||
|
||||
//Deleted Things need to have AT LEAST every property that normal things have
|
||||
public class DeletedInstallation : TreeNode
|
||||
{
|
||||
public String Location { get; set; } = "";
|
||||
public String Region { get; set; } = "";
|
||||
public String Country { get; set; } = "";
|
||||
|
||||
// TODO: make relation
|
||||
public String OrderNumbers { get; set; } = "";
|
||||
|
||||
public Double Lat { get; set; }
|
||||
public Double Long { get; set; }
|
||||
|
||||
public String S3Bucket { get; set; } = "";
|
||||
public String S3Url { get; set; } = "";
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using SQLite;
|
||||
|
||||
namespace InnovEnergy.App.Backend.DataTypes;
|
||||
|
||||
|
||||
//Deleted Things need to have AT LEAST every property that normal things have
|
||||
|
||||
public class DeletedUser : TreeNode
|
||||
{
|
||||
public String Email { get; set; } = null!;
|
||||
public Boolean HasWriteAccess { get; set; } = false;
|
||||
public Boolean MustResetPassword { get; set; } = false;
|
||||
public String Language { get; set; } = null!;
|
||||
public String Password { get; set; } = null!;
|
||||
|
||||
[Unique]
|
||||
public override String Name { get; set; } = null!;
|
||||
|
||||
|
||||
|
||||
// TODO: must reset pwd
|
||||
}
|
|
@ -23,6 +23,17 @@ public static class FolderMethods
|
|||
.NotNull();
|
||||
}
|
||||
|
||||
public static DeletedFolder ToDeletedFolder(this Folder folder)
|
||||
{
|
||||
var deletedFolder = new DeletedFolder();
|
||||
foreach (var property in folder.GetType().GetProperties())
|
||||
{
|
||||
property.SetValue(deletedFolder,property.GetValue(folder));
|
||||
}
|
||||
|
||||
return deletedFolder;
|
||||
}
|
||||
|
||||
public static IEnumerable<User> UsersWithInheritedAccess(this Folder folder)
|
||||
{
|
||||
return folder
|
||||
|
|
|
@ -20,7 +20,8 @@ public static class InstallationMethods
|
|||
}
|
||||
|
||||
public static async Task<Boolean> RenewS3BucketUrl(this Installation installation, TimeSpan validity)
|
||||
{
|
||||
{
|
||||
installation.S3Url =
|
||||
installation.S3Url = await S3Access.ReadOnly.SignUrl(installation.BucketName(), validity);
|
||||
return Db.Update(installation);
|
||||
}
|
||||
|
@ -61,6 +62,17 @@ public static class InstallationMethods
|
|||
.SelectMany(f => f.UsersWithDirectAccess())
|
||||
.NotNull();
|
||||
}
|
||||
|
||||
public static DeletedInstallation ToDeletedInstallation(this Installation installation)
|
||||
{
|
||||
var deletedInstallation = new DeletedInstallation();
|
||||
foreach (var property in installation.GetType().GetProperties())
|
||||
{
|
||||
property.SetValue(deletedInstallation ,property.GetValue(installation));
|
||||
}
|
||||
|
||||
return deletedInstallation;
|
||||
}
|
||||
|
||||
public static IEnumerable<Folder> Ancestors(this Installation installation)
|
||||
{
|
||||
|
|
|
@ -32,6 +32,38 @@ public static class SessionMethods
|
|||
.WithParentOf(original) // prevent moving
|
||||
.Apply(Db.Update);
|
||||
}
|
||||
|
||||
public static Boolean MoveFolder(this Session? session, Int64 folderId, Int64 parentId)
|
||||
{
|
||||
var user = session?.User;
|
||||
var folder = Db.GetFolderById(folderId);
|
||||
var parent = Db.GetFolderById(parentId);
|
||||
|
||||
return user is not null
|
||||
&& folder is not null
|
||||
&& user.HasWriteAccess
|
||||
&& user.HasAccessTo(folder)
|
||||
&& user.HasAccessTo(parent)
|
||||
&& folder
|
||||
.Do(() => folder.ParentId = parentId)
|
||||
.Apply(Db.Update);
|
||||
}
|
||||
|
||||
public static Boolean MoveInstallation(this Session? session, Int64 installationId, Int64 parentId)
|
||||
{
|
||||
var user = session?.User;
|
||||
var installation = Db.GetInstallationById(installationId);
|
||||
var parent = Db.GetFolderById(parentId);
|
||||
|
||||
return user is not null
|
||||
&& installation is not null
|
||||
&& user.HasWriteAccess
|
||||
&& user.HasAccessTo(installation)
|
||||
&& user.HasAccessTo(parent)
|
||||
&& installation
|
||||
.Do(() => installation.ParentId = parentId)
|
||||
.Apply(Db.Update);
|
||||
}
|
||||
|
||||
public static Boolean Delete(this Session? session, Folder? folder)
|
||||
{
|
||||
|
@ -41,6 +73,7 @@ public static class SessionMethods
|
|||
&& folder is not null
|
||||
&& user.HasWriteAccess
|
||||
&& user.HasAccessTo(folder)
|
||||
&& Db.Create(folder.ToDeletedFolder())
|
||||
&& Db.Delete(folder);
|
||||
}
|
||||
|
||||
|
@ -84,21 +117,27 @@ public static class SessionMethods
|
|||
&& installation is not null
|
||||
&& user.HasWriteAccess
|
||||
&& user.HasAccessTo(installation)
|
||||
// && installation.DeleteBucket().Result // TODO
|
||||
&& Db.Create(installation.ToDeletedInstallation())
|
||||
// && installation.DeleteBucket().Result // TODO
|
||||
&& Db.Delete(installation);
|
||||
}
|
||||
|
||||
public static Boolean Create(this Session? session, User? newUser)
|
||||
{
|
||||
var sessionUser = session?.User;
|
||||
|
||||
return sessionUser is not null
|
||||
&& newUser is not null
|
||||
&& sessionUser.HasWriteAccess
|
||||
&& newUser
|
||||
.WithParent(sessionUser)
|
||||
.Do(() => newUser.Password = newUser.SaltAndHashPassword(newUser.Password))
|
||||
.Do(() => newUser.MustResetPassword = true)
|
||||
.Apply(Db.Create)
|
||||
&& Mailer.Mailer.SendVerificationMessage(newUser);
|
||||
|
||||
//Send Email to new user to verify email and set password
|
||||
|
||||
return sessionUser is not null
|
||||
&& newUser is not null
|
||||
&& sessionUser.HasWriteAccess
|
||||
&& newUser
|
||||
.WithParent(sessionUser)
|
||||
.Do(() => newUser.Password = newUser.SaltAndHashPassword(newUser.Password))
|
||||
.Apply(Db.Create);
|
||||
}
|
||||
|
||||
public static Boolean Update(this Session? session, User? editedUser)
|
||||
|
@ -116,6 +155,16 @@ public static class SessionMethods
|
|||
.WithPasswordOf(originalUser)
|
||||
.Apply(Db.Update);
|
||||
}
|
||||
|
||||
public static Boolean UpdatePassword(this Session? session, String? newPassword)
|
||||
{
|
||||
var sessionUser = session?.User;
|
||||
|
||||
return sessionUser is not null
|
||||
&& sessionUser
|
||||
.Do(() => sessionUser.Password = sessionUser.SaltAndHashPassword(newPassword))
|
||||
.Apply(Db.Update);
|
||||
}
|
||||
|
||||
public static Boolean Delete(this Session? session, User? userToDelete)
|
||||
{
|
||||
|
@ -124,7 +173,8 @@ public static class SessionMethods
|
|||
return sessionUser is not null
|
||||
&& userToDelete is not null
|
||||
&& sessionUser.HasWriteAccess
|
||||
&& sessionUser.HasAccessTo(userToDelete)
|
||||
&& sessionUser.HasAccessTo(userToDelete)
|
||||
&& Db.Create(sessionUser.ToDeletedUser())
|
||||
&& Db.Delete(userToDelete);
|
||||
}
|
||||
|
||||
|
|
|
@ -97,9 +97,10 @@ public static class UserMethods
|
|||
|
||||
public static Boolean VerifyPassword(this User user, String password)
|
||||
{
|
||||
return user.Password == user.SaltAndHashPassword(password);
|
||||
return Db.GetUserWithPasswordByName(user.Name)?.Password == user.SaltAndHashPassword(password);
|
||||
}
|
||||
|
||||
|
||||
public static String SaltAndHashPassword(this User user, String password)
|
||||
{
|
||||
var dataToHash = $"{password}{user.Salt()}";
|
||||
|
@ -183,10 +184,27 @@ public static class UserMethods
|
|||
user.Password = other.Password;
|
||||
return user;
|
||||
}
|
||||
|
||||
public static DeletedUser ToDeletedUser(this User user)
|
||||
{
|
||||
var deletedUser = new DeletedUser();
|
||||
foreach (var property in user.GetType().GetProperties())
|
||||
{
|
||||
property.SetValue(deletedUser,property.GetValue(user));
|
||||
}
|
||||
|
||||
return deletedUser;
|
||||
}
|
||||
|
||||
public static User? HidePassword(this User? user)
|
||||
{
|
||||
if(user is not null)
|
||||
user.Password = "";
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO?
|
||||
private static Boolean IsValidEmail(String email)
|
||||
{
|
||||
|
|
|
@ -6,11 +6,15 @@ public class User : TreeNode
|
|||
{
|
||||
public String Email { get; set; } = null!;
|
||||
public Boolean HasWriteAccess { get; set; } = false;
|
||||
public Boolean MustResetPassword { get; set; } = false;
|
||||
public String Language { get; set; } = null!;
|
||||
public String Password { get; set; } = null!;
|
||||
|
||||
[Unique]
|
||||
public override String Name { get; set; } = null!;
|
||||
|
||||
|
||||
|
||||
// TODO: must reset pwd
|
||||
|
||||
}
|
|
@ -13,15 +13,30 @@ public static partial class Db
|
|||
return Connection.Insert(installation) > 0;
|
||||
}
|
||||
|
||||
public static Boolean Create(DeletedInstallation installation)
|
||||
{
|
||||
return Connection.Insert(installation) > 0;
|
||||
}
|
||||
|
||||
public static Boolean Create(Folder folder)
|
||||
{
|
||||
return Connection.Insert(folder) > 0;
|
||||
}
|
||||
|
||||
public static Boolean Create(DeletedFolder folder)
|
||||
{
|
||||
return Connection.Insert(folder) > 0;
|
||||
}
|
||||
|
||||
public static Boolean Create(User user)
|
||||
{
|
||||
return Connection.Insert(user) > 0;
|
||||
}
|
||||
|
||||
public static Boolean Create(DeletedUser user)
|
||||
{
|
||||
return Connection.Insert(user) > 0;
|
||||
}
|
||||
|
||||
public static Boolean Create(Session session)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using InnovEnergy.App.Backend.DataTypes;
|
||||
using InnovEnergy.App.Backend.DataTypes.Methods;
|
||||
using InnovEnergy.App.Backend.Relations;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
|
||||
|
||||
namespace InnovEnergy.App.Backend.Database;
|
||||
|
@ -21,14 +23,25 @@ public static partial class Db
|
|||
|
||||
public static User? GetUserById(Int64? id)
|
||||
{
|
||||
//TODO Sanitize Password here
|
||||
return Users
|
||||
.FirstOrDefault(u => u.Id == id);
|
||||
.FirstOrDefault(u => u.Id == id)
|
||||
.HidePassword();
|
||||
}
|
||||
|
||||
public static User? GetUserByName(String userName)
|
||||
{
|
||||
//TODO Sanitize Password here
|
||||
return Users
|
||||
.FirstOrDefault(u => u.Name == userName);
|
||||
.FirstOrDefault(u => u.Name == userName)
|
||||
.HidePassword();
|
||||
}
|
||||
|
||||
public static User? GetUserWithPasswordByName(String userName)
|
||||
{
|
||||
//TODO Sanitize Password here
|
||||
return Users
|
||||
.FirstOrDefault(u => u.Name == userName);
|
||||
}
|
||||
|
||||
public static Session? GetSession(String token)
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using InnovEnergy.App.Backend.DataTypes;
|
||||
using MailKit.Net.Smtp;
|
||||
using MailKit;
|
||||
using MimeKit;
|
||||
|
||||
namespace InnovEnergy.App.Backend.Mailer;
|
||||
public static class Mailer
|
||||
{
|
||||
public static Boolean SendVerificationMessage (User emailRecipientUser)
|
||||
{
|
||||
var email = new MimeMessage();
|
||||
|
||||
email.From.Add(new MailboxAddress("InnovEnergy", "noreply@innov.energy"));
|
||||
email.To.Add(new MailboxAddress(emailRecipientUser.Name, "fern95@ethereal.email"));
|
||||
|
||||
email.Subject = "Create a new password for your Innovenergy-Account";
|
||||
email.Body = new TextPart(MimeKit.Text.TextFormat.Plain) {
|
||||
Text = "Dear " + emailRecipientUser.Name + "\n Please create a new password for your Innovenergy-account." +
|
||||
"\n To do this just login at https://HEEEEELP"
|
||||
};
|
||||
using (var smtp = new SmtpClient())
|
||||
{
|
||||
smtp.Connect("smtp.ethereal.email", 587, false);
|
||||
|
||||
// Todo put me into urlAndKey.json
|
||||
smtp.Authenticate("fern95@ethereal.email", "dYKVnc4RQNEFckHaNV");
|
||||
|
||||
smtp.Send(email);
|
||||
smtp.Disconnect(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"ReadOnlyS3Key": "EXO44d2979c8e570eae81ead564",
|
||||
"ReadOnlyS3Secret": "55MAqyO_FqUmh7O64VIO0egq50ERn_WIAWuc2QC44QU" ,
|
||||
"ReadWriteS3Key": "EXO87ca85e29dd412f1238f1cf0",
|
||||
"ReadWriteS3Secret": "-T9TAqy9a3-0-xj7HKsFFJOCcxfRpcnL6OW5oOrOcWU"
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
using static System.IO.File;
|
||||
using static System.Text.Json.JsonSerializer;
|
||||
|
||||
namespace InnovEnergy.App.Backend.S3;
|
||||
|
||||
public static class S3Access
|
||||
|
@ -6,16 +9,16 @@ public static class S3Access
|
|||
// there so they can be changed without recompiling
|
||||
// they should be read from disk on each use,
|
||||
// so the backend does not need to be restarted on change
|
||||
|
||||
|
||||
public static S3Cmd ReadOnly { get; } = new S3Cmd
|
||||
(
|
||||
key : "EXO44d2979c8e570eae81ead564",
|
||||
secret: "55MAqyO_FqUmh7O64VIO0egq50ERn_WIAWuc2QC44QU"
|
||||
key : Deserialize<Dictionary<String, String>>(OpenRead("./Resources/urlAndKey.json"))?["ReadOnlyS3Key"],
|
||||
secret: Deserialize<Dictionary<String, String>>(OpenRead("./Resources/urlAndKey.json"))?["ReadOnlyS3Secret"]
|
||||
);
|
||||
|
||||
public static S3Cmd ReadWrite { get; } = new S3Cmd
|
||||
(
|
||||
key : "EXO87ca85e29dd412f1238f1cf0",
|
||||
secret: "-T9TAqy9a3-0-xj7HKsFFJOCcxfRpcnL6OW5oOrOcWU"
|
||||
key : Deserialize<Dictionary<String, String>>(OpenRead("./Resources/urlAndKey.json"))?["ReadWriteS3Key"],
|
||||
secret: Deserialize<Dictionary<String, String>>(OpenRead("./Resources/urlAndKey.json"))?["ReadWriteS3Secret"]
|
||||
);
|
||||
}
|
|
@ -8,15 +8,15 @@ public class S3Cmd
|
|||
{
|
||||
private static readonly Command Python = Cli.Wrap("python3");
|
||||
|
||||
private const String S3CmdPath = "Resources/s3cmd.py";
|
||||
private const String? S3CmdPath = "Resources/s3cmd.py";
|
||||
private const String S3Prefix = "s3://";
|
||||
|
||||
private String[] DefaultArgs { get; }
|
||||
private String?[] DefaultArgs { get; }
|
||||
|
||||
// ReSharper disable StringLiteralTypo
|
||||
// ReSharper enable StringLiteralTypo
|
||||
|
||||
public S3Cmd(String key, String secret)
|
||||
public S3Cmd(String? key, String? secret)
|
||||
{
|
||||
DefaultArgs = new[]
|
||||
{
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue