From a1b6f61e8c5594aaafc90441ca6658728d767768 Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Wed, 25 Jan 2023 11:22:28 +0100 Subject: [PATCH 1/8] Add models and interfaces for auth --- .../Database/UserDatabaseContext.cs | 10 ++++ .../Elektrifikatsiya/Elektrifikatsiya.csproj | 6 +++ .../Elektrifikatsiya/Models/Role.cs | 7 +++ .../Elektrifikatsiya/Models/User.cs | 22 ++++++++ .../Elektrifikatsiya/Program.cs | 8 +-- .../Services/IAuthenticationService.cs | 53 +++++++++++++++++++ .../Services/IAuthorizationService.cs | 13 +++++ 7 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Database/UserDatabaseContext.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Models/Role.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Models/User.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthenticationService.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthorizationService.cs diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Database/UserDatabaseContext.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Database/UserDatabaseContext.cs new file mode 100644 index 0000000..917764f --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Database/UserDatabaseContext.cs @@ -0,0 +1,10 @@ +using Elektrifikatsiya.Models; + +using Microsoft.EntityFrameworkCore; + +namespace Elektrifikatsiya.Database; + +public class UserDatabaseContext : DbContext +{ + public DbSet Users { get; set; } +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj b/src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj index 6b1a00c..e04bc06 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj @@ -20,7 +20,13 @@ + + + + + + diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Models/Role.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Models/Role.cs new file mode 100644 index 0000000..f2afd89 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Models/Role.cs @@ -0,0 +1,7 @@ +namespace Elektrifikatsiya.Models; + +public enum Role +{ + Admin, + User +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Models/User.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Models/User.cs new file mode 100644 index 0000000..99fc256 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Models/User.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Elektrifikatsiya.Models; + +public class User +{ + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [Key] + public int Id { get; private set; } + + public string Name { get; private set; } + public string PasswordHash { get; private set; } + public string? SessionToken { get; set; } + public DateTime LastLoginDate { get; set; } + + public User(string name, string passwordHash) + { + Name = name; + PasswordHash = passwordHash; + } +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs index 44ecc11..d9004c1 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs @@ -25,12 +25,8 @@ app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); - -app.UseEndpoints(endpoints => -{ - _ = endpoints.MapBlazorHub(); - _ = endpoints.MapFallbackToPage("/_Host"); -}); +app.MapBlazorHub(); +app.MapFallbackToPage("/_Host"); app.Run(); diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthenticationService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthenticationService.cs new file mode 100644 index 0000000..ac34b36 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthenticationService.cs @@ -0,0 +1,53 @@ +using Elektrifikatsiya.Models; + +namespace Elektrifikatsiya.Services; + +public interface IAuthenticationService +{ + /// + /// Gets the current user. + /// + /// to and the currently authenticated user. + Task GetUserAsync(); + + /// + /// Registers a new user. + /// + /// The E-mail address of the user. + /// A to . + + Task RegisterUserAsync(string name, string password); + + /// + /// Logs a user in. + /// + /// The E-mail address of the user. + /// A to . + Task<(bool Success, string? Message)> LoginUserAsync(string name, string password); + + /// + /// Logs the user out. + /// + /// A to . + Task LogoutUserAsync(); + + /// + /// Deletes the current user. + /// + /// The deletion token. + /// A to and a that indicates if the operation was successful. + Task DeleteUserAsync(string deletionToken); + + /// + /// Checks if a user exists. + /// + /// The E-mail address of the user. + /// A to and a that indicates if the user exists. + Task UserExistsAsync(string name); + + /// + /// Check if the current user is authenticated. + /// + /// A to and a that indicates if the user is authenticated. + Task IsAuthenticated(); +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthorizationService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthorizationService.cs new file mode 100644 index 0000000..223d9c8 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthorizationService.cs @@ -0,0 +1,13 @@ +using Elektrifikatsiya.Models; + +namespace Elektrifikatsiya.Services; + +public interface IAuthorizationService +{ + /// + /// Check if the current user is authorized. + /// + /// The minimum required role. + /// A to and a that indicates if the user is authorized. + Task IsAuthorized(Role requiredRole); +} \ No newline at end of file From 85cc9d56ba8b060e3888afcac557ddb6a4825e88 Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Thu, 26 Jan 2023 16:43:37 +0100 Subject: [PATCH 2/8] Implement auth services --- .../Elektrifikatsiya/Models/Role.cs | 2 + .../Elektrifikatsiya/Models/User.cs | 4 +- .../Services/IAuthenticationService.cs | 16 ++++--- .../Services/IAuthorizationService.cs | 4 +- .../Implementations/AuthenticationService.cs | 43 +++++++++++++++++++ .../Implementations/AuthorizationService.cs | 29 +++++++++++++ 6 files changed, 89 insertions(+), 9 deletions(-) create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthenticationService.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthorizationService.cs diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Models/Role.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Models/Role.cs index f2afd89..08e4fb4 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Models/Role.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Models/Role.cs @@ -1,5 +1,7 @@ namespace Elektrifikatsiya.Models; +// Higher up = Higher permission +// Or you can set the priority manually = public enum Role { Admin, diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Models/User.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Models/User.cs index 99fc256..175c25d 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Models/User.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Models/User.cs @@ -13,10 +13,12 @@ public class User public string PasswordHash { get; private set; } public string? SessionToken { get; set; } public DateTime LastLoginDate { get; set; } + public Role Role { get; set; } - public User(string name, string passwordHash) + public User(string name, string passwordHash, Role role) { Name = name; PasswordHash = passwordHash; + Role = role; } } \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthenticationService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthenticationService.cs index ac34b36..84b1adf 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthenticationService.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthenticationService.cs @@ -1,5 +1,7 @@ using Elektrifikatsiya.Models; +using FluentResults; + namespace Elektrifikatsiya.Services; public interface IAuthenticationService @@ -8,7 +10,7 @@ public interface IAuthenticationService /// Gets the current user. /// /// to and the currently authenticated user. - Task GetUserAsync(); + Task> GetUserAsync(); /// /// Registers a new user. @@ -16,38 +18,38 @@ public interface IAuthenticationService /// The E-mail address of the user. /// A to . - Task RegisterUserAsync(string name, string password); + Task RegisterUserAsync(string name, string password); /// /// Logs a user in. /// /// The E-mail address of the user. /// A to . - Task<(bool Success, string? Message)> LoginUserAsync(string name, string password); + Task LoginUserAsync(string name, string password); /// /// Logs the user out. /// /// A to . - Task LogoutUserAsync(); + Task LogoutUserAsync(); /// /// Deletes the current user. /// /// The deletion token. /// A to and a that indicates if the operation was successful. - Task DeleteUserAsync(string deletionToken); + Task DeleteUserAsync(string deletionToken); /// /// Checks if a user exists. /// /// The E-mail address of the user. /// A to and a that indicates if the user exists. - Task UserExistsAsync(string name); + Task> UserExistsAsync(string name); /// /// Check if the current user is authenticated. /// /// A to and a that indicates if the user is authenticated. - Task IsAuthenticated(); + Task> IsAuthenticated(); } \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthorizationService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthorizationService.cs index 223d9c8..30be3d0 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthorizationService.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthorizationService.cs @@ -1,5 +1,7 @@ using Elektrifikatsiya.Models; +using FluentResults; + namespace Elektrifikatsiya.Services; public interface IAuthorizationService @@ -9,5 +11,5 @@ public interface IAuthorizationService /// /// The minimum required role. /// A to and a that indicates if the user is authorized. - Task IsAuthorized(Role requiredRole); + Task> IsAuthorized(Role requiredRole); } \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthenticationService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthenticationService.cs new file mode 100644 index 0000000..1a3c2ae --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthenticationService.cs @@ -0,0 +1,43 @@ +using Elektrifikatsiya.Models; + +using FluentResults; + +namespace Elektrifikatsiya.Services.Implementations; + +public class AuthenticationService : IAuthenticationService +{ + public Task DeleteUserAsync(string deletionToken) + { + throw new NotImplementedException(); + } + + public Task> GetUserAsync() + { + throw new NotImplementedException(); + } + + public Task> IsAuthenticated() + { + throw new NotImplementedException(); + } + + public Task LoginUserAsync(string name, string password) + { + throw new NotImplementedException(); + } + + public Task LogoutUserAsync() + { + throw new NotImplementedException(); + } + + public Task RegisterUserAsync(string name, string password) + { + throw new NotImplementedException(); + } + + public Task> UserExistsAsync(string name) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthorizationService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthorizationService.cs new file mode 100644 index 0000000..3a2f4c4 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthorizationService.cs @@ -0,0 +1,29 @@ +using Elektrifikatsiya.Models; + +using FluentResults; + +namespace Elektrifikatsiya.Services.Implementations; + +public class AuthorizationService : IAuthorizationService +{ + private readonly IAuthenticationService authenticationService; + + public AuthorizationService(IAuthenticationService authenticationService) + { + this.authenticationService = authenticationService; + } + + public async Task> IsAuthorized(Role requiredRole) + { + Result userResult = await authenticationService.GetUserAsync(); + + if (userResult.IsSuccess && userResult.Value.Role <= requiredRole) + { + return Result.Ok(true); + } + else + { + return Result.Fail("Use doesn't have the required role!"); + } + } +} \ No newline at end of file From 96a0d710c43c0b18a0ce3e1b9248863b266b81cb Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Thu, 26 Jan 2023 16:44:53 +0100 Subject: [PATCH 3/8] Add FluentResults NuGet --- src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj b/src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj index e04bc06..4272c7b 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj @@ -20,6 +20,7 @@ + From 5d6db0b5c1490512bc6218d850d07c8844214f4c Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Wed, 1 Feb 2023 10:17:53 +0100 Subject: [PATCH 4/8] =?UTF-8?q?=F0=9F=94=91=20Login=20Stuff=20ya'=20know?= =?UTF-8?q?=20=F0=9F=94=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Database/UserDatabaseContext.cs | 4 + .../Elektrifikatsiya/Program.cs | 5 + .../Services/IAuthenticationService.cs | 4 +- .../Services/ICookieService.cs | 13 ++ .../Implementations/AuthenticationService.cs | 119 +++++++++++++++--- .../Implementations/AuthorizationService.cs | 2 +- .../Services/Implementations/CookieService.cs | 18 +++ .../Utilities/SecureStringGenerator.cs | 20 +++ .../Utilities/TokenGenerator.cs | 19 +++ 9 files changed, 187 insertions(+), 17 deletions(-) create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/ICookieService.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/CookieService.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Utilities/SecureStringGenerator.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Utilities/TokenGenerator.cs diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Database/UserDatabaseContext.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Database/UserDatabaseContext.cs index 917764f..b3a6730 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Database/UserDatabaseContext.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Database/UserDatabaseContext.cs @@ -6,5 +6,9 @@ namespace Elektrifikatsiya.Database; public class UserDatabaseContext : DbContext { + public UserDatabaseContext(DbContextOptions dbContextOptions) : base(dbContextOptions) + { + } + public DbSet Users { get; set; } } \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs index d9004c1..fb58465 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs @@ -2,11 +2,16 @@ using Blazorise; using Blazorise.Icons.Material; using Blazorise.Material; +using Elektrifikatsiya.Database; + +using Microsoft.EntityFrameworkCore; + WebApplicationBuilder builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); +builder.Services.AddDbContext(options => options.UseSqlite("/host/UserDatabase.sqlite")); AddBlazorise(builder.Services); diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthenticationService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthenticationService.cs index 84b1adf..2ccc8ec 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthenticationService.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IAuthenticationService.cs @@ -18,7 +18,7 @@ public interface IAuthenticationService /// The E-mail address of the user. /// A to . - Task RegisterUserAsync(string name, string password); + Task RegisterUserAsync(string name, string password, Role role); /// /// Logs a user in. @@ -38,7 +38,7 @@ public interface IAuthenticationService /// /// The deletion token. /// A to and a that indicates if the operation was successful. - Task DeleteUserAsync(string deletionToken); + Task DeleteUserAsync(); /// /// Checks if a user exists. diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/ICookieService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/ICookieService.cs new file mode 100644 index 0000000..a954ea8 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/ICookieService.cs @@ -0,0 +1,13 @@ +namespace Elektrifikatsiya.Services; + +public interface ICookieService +{ + /// + /// Writes a cookie. + /// + /// The name of the cookie. + /// The value of the cookie. + /// Indicates the maximum lifetime of the cookie. + /// + Task WriteCookieAsync(string name, string value, int days); +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthenticationService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthenticationService.cs index 1a3c2ae..36ce68e 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthenticationService.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthenticationService.cs @@ -1,43 +1,134 @@ -using Elektrifikatsiya.Models; +using Elektrifikatsiya.Database; +using Elektrifikatsiya.Models; +using Elektrifikatsiya.Utilities; using FluentResults; +using Microsoft.EntityFrameworkCore; + +using BC = BCrypt.Net.BCrypt; + namespace Elektrifikatsiya.Services.Implementations; public class AuthenticationService : IAuthenticationService { - public Task DeleteUserAsync(string deletionToken) + private readonly UserDatabaseContext userDatabaseContext; + private readonly IHttpContextAccessor httpContextAccessor; + private readonly ICookieService cookieService; + + public AuthenticationService(UserDatabaseContext userDatabaseContext, IHttpContextAccessor httpContextAccessor, ICookieService cookieService) { - throw new NotImplementedException(); + this.userDatabaseContext = userDatabaseContext; + this.httpContextAccessor = httpContextAccessor; + this.cookieService = cookieService; } - public Task> GetUserAsync() + public async Task DeleteUserAsync() { - throw new NotImplementedException(); + Result getUserResult = await GetUserAsync(); + + if (getUserResult.IsFailed) + { + return getUserResult.ToResult(); + } + + _ = userDatabaseContext.Users.Remove(getUserResult.Value); + return (await Result.Try(() => userDatabaseContext.SaveChangesAsync())).ToResult(); } - public Task> IsAuthenticated() + public async Task> GetUserAsync() { - throw new NotImplementedException(); + string? token = httpContextAccessor.HttpContext?.Request.Cookies["token"]?.ToString(); + + if (!TokenGenerator.ValidateToken(token, "auth")) + { + return Result.Fail("Token is not valid!"); + } + + User? user = await userDatabaseContext.Users.FirstOrDefaultAsync(u => u.SessionToken == token); + + if (user is null || DateTime.UtcNow - user.LastLoginDate > TimeSpan.FromDays(7)) + { + return Result.Fail("Token is not valid or expired!"); + } + + return user; } - public Task LoginUserAsync(string name, string password) + public async Task> IsAuthenticated() { - throw new NotImplementedException(); + return (await GetUserAsync()).IsSuccess; } - public Task LogoutUserAsync() + public async Task LoginUserAsync(string name, string password) { - throw new NotImplementedException(); + User? user = await userDatabaseContext.Users.FirstOrDefaultAsync(u => u.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)); + + if (user is null) + { + return Result.Fail("User does not exist!"); + } + + if (!BC.Verify(password, user.PasswordHash)) + { + return Result.Fail("Invalid credentials!"); + } + + string newToken = TokenGenerator.GenerateToken("auth", user.Id); + + user.LastLoginDate = DateTime.UtcNow; + user.SessionToken = newToken; + + _ = await userDatabaseContext.SaveChangesAsync(); + + await cookieService.WriteCookieAsync("token", newToken, 7); + + return Result.Ok(); } - public Task RegisterUserAsync(string name, string password) + public async Task LogoutUserAsync() { - throw new NotImplementedException(); + string? token = httpContextAccessor.HttpContext?.Request.Cookies["token"]?.ToString(); + + await cookieService.WriteCookieAsync("token", string.Empty, 0); + + if (!TokenGenerator.ValidateToken(token, "auth")) + { + return Result.Ok(); + } + + User? user = await userDatabaseContext.Users.FirstOrDefaultAsync(u => u.SessionToken == token); + + if (user is null) + { + return Result.Ok(); + } + + user.SessionToken = null; + + _ = await userDatabaseContext.SaveChangesAsync(); + + return Result.Ok(); + } + + public async Task RegisterUserAsync(string name, string password, Role role) + { + Result userExistsResult = await UserExistsAsync(name); + + if (userExistsResult.IsFailed || userExistsResult.Value) + { + return Result.Fail("User name already exists!"); + } + + User user = new User(name, BC.HashPassword(password), role); + _ = userDatabaseContext.Users.Add(user); + + return (await Result.Try(() => userDatabaseContext.SaveChangesAsync())).ToResult(); } public Task> UserExistsAsync(string name) { - throw new NotImplementedException(); + return Result.Try(() => + userDatabaseContext.Users.AnyAsync(u => u.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))); } } \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthorizationService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthorizationService.cs index 3a2f4c4..e62b137 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthorizationService.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/AuthorizationService.cs @@ -23,7 +23,7 @@ public class AuthorizationService : IAuthorizationService } else { - return Result.Fail("Use doesn't have the required role!"); + return Result.Fail("User doesn't have the required role!"); } } } \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/CookieService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/CookieService.cs new file mode 100644 index 0000000..d654fdc --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/CookieService.cs @@ -0,0 +1,18 @@ +using Microsoft.JSInterop; + +namespace Elektrifikatsiya.Services.Implementations; + +public class CookieService : ICookieService +{ + private readonly IJSRuntime jsRuntime; + + public CookieService(IJSRuntime jsRuntime) + { + this.jsRuntime = jsRuntime; + } + + public async Task WriteCookieAsync(string name, string value, int days) + { + _ = await jsRuntime.InvokeAsync("blazorExtensions.WriteCookie", name, value, days); + } +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/SecureStringGenerator.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/SecureStringGenerator.cs new file mode 100644 index 0000000..a37cb29 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/SecureStringGenerator.cs @@ -0,0 +1,20 @@ +using System.Security.Cryptography; + +namespace Elektrifikatsiya.Utilities; + +public static class SecureStringGenerator +{ + public static string CreateCryptographicRandomString(int count) + { + return Convert.ToBase64String(RandomNumberGenerator.GetBytes(count)); + } + + public static string CreateCryptographicRandomString(int count, int uid) + { + List bytes = RandomNumberGenerator.GetBytes(count).ToList(); + + bytes.AddRange(BitConverter.GetBytes(uid)); + + return Convert.ToBase64String(bytes.ToArray()); + } +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/TokenGenerator.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/TokenGenerator.cs new file mode 100644 index 0000000..99faf60 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/TokenGenerator.cs @@ -0,0 +1,19 @@ +namespace Elektrifikatsiya.Utilities; + +public static class TokenGenerator +{ + public static string GenerateToken(string tokenType, int uid = 0, int length = 128) + { + return tokenType + "-" + SecureStringGenerator.CreateCryptographicRandomString(length, uid); + } + + public static bool ValidateToken(string? token, string tokenType) + { + if (token is null) + { + return false; + } + + return token.StartsWith(tokenType + "-"); + } +} \ No newline at end of file From 44ffa1d7b2be79af91aa86d598b4d7ca3f03810c Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Wed, 1 Feb 2023 11:30:02 +0100 Subject: [PATCH 5/8] Visual studio dumb --- src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj b/src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj index 4272c7b..be8b6d4 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Elektrifikatsiya.csproj @@ -17,6 +17,7 @@ + From af673b65727c493e469ada2a4d1d9656240e1605 Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Thu, 2 Feb 2023 16:38:55 +0100 Subject: [PATCH 6/8] Add user database setup --- src/Elektrifikatsiya/Elektrifikatsiya/Program.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs index fb58465..f600e2f 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs @@ -11,7 +11,7 @@ WebApplicationBuilder builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); -builder.Services.AddDbContext(options => options.UseSqlite("/host/UserDatabase.sqlite")); +builder.Services.AddDbContext(options => options.UseSqlite("Data Source=./UserDatabase.sqlite")); AddBlazorise(builder.Services); @@ -33,6 +33,9 @@ app.UseRouting(); app.MapBlazorHub(); app.MapFallbackToPage("/_Host"); +IServiceScope serviceScope = app.Services.GetRequiredService().CreateScope(); +serviceScope.ServiceProvider.GetRequiredService().Database.EnsureCreated(); + app.Run(); void AddBlazorise(IServiceCollection services) From 756dc21c5f89def78878ac170f6b94141f309622 Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Thu, 2 Feb 2023 16:39:15 +0100 Subject: [PATCH 7/8] Fix dockerfile --- .../Elektrifikatsiya/Properties/launchSettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Properties/launchSettings.json b/src/Elektrifikatsiya/Elektrifikatsiya/Properties/launchSettings.json index 7111a52..71c02c5 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Properties/launchSettings.json +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Properties/launchSettings.json @@ -19,7 +19,7 @@ "Docker": { "commandName": "Docker", "launchBrowser": true, - "launchUrl": "{Scheme}://{IPAdress}:{ServicePort}", + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}", "publishAllPorts": true, "useSSL": true, "DockerfileRunArguments": "-p 80:80 -p 443:443" From ab159df6a94ce4919d418ae6d84e530f504537d6 Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Wed, 8 Feb 2023 08:18:39 +0100 Subject: [PATCH 8/8] Add cookie script --- .../Elektrifikatsiya/Pages/_Layout.cshtml | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/_Layout.cshtml b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/_Layout.cshtml index a689909..d698356 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/_Layout.cshtml +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/_Layout.cshtml @@ -40,5 +40,34 @@ + +