From ddbf8114ba884665a10b640318d58f4ad323b1ed Mon Sep 17 00:00:00 2001 From: Alex Bezdieniezhnykh Date: Tue, 12 Nov 2024 22:16:50 +0200 Subject: [PATCH] db works, upload works --- .gitignore | 4 ++- Azaion.Api/Program.cs | 21 +++++++++----- Azaion.Common/Azaion.Common.csproj | 1 + Azaion.Common/BusinessException.cs | 3 +- Azaion.Common/Database/AzaionDbShemaHolder.cs | 9 ++++-- Azaion.Common/Entities/ResourceEnum.cs | 2 +- Azaion.Common/Entities/RoleEnum.cs | 11 +++---- Azaion.Common/Entities/User.cs | 2 +- Azaion.Common/Requests/GetResourceRequest.cs | 6 ---- Azaion.Services/AuthService.cs | 2 +- Azaion.Services/Azaion.Services.csproj | 2 ++ Azaion.Services/ResourcesService.cs | 15 ++++++---- Azaion.Services/UserService.cs | 9 +++--- env/02_db_structure.sql | 13 +++++++++ env/azaion-db.sql | 29 ------------------- 15 files changed, 66 insertions(+), 63 deletions(-) create mode 100644 env/02_db_structure.sql delete mode 100644 env/azaion-db.sql diff --git a/.gitignore b/.gitignore index e17a24d..ae8e9cc 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ obj *.DotSettings* *.user log* -*.cmd \ No newline at end of file +*.cmd +*permissions.sql +Content/ \ No newline at end of file diff --git a/Azaion.Api/Program.cs b/Azaion.Api/Program.cs index 869cde8..50bc8c0 100644 --- a/Azaion.Api/Program.cs +++ b/Azaion.Api/Program.cs @@ -7,10 +7,12 @@ using Azaion.Common.Requests; using Azaion.Services; using FluentValidation; using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; var builder = WebApplication.CreateBuilder(args); +builder.WebHost.ConfigureKestrel(o => o.Limits.MaxRequestBodySize = 209715200); //increase upload limit up to 200mb var jwtConfig = builder.Configuration.GetSection(nameof(JwtConfig)).Get(); if (jwtConfig == null) @@ -31,7 +33,10 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) IssuerSigningKey = signingKey }; }); -builder.Services.AddAuthorization(); + +var apiAdminPolicy = new AuthorizationPolicyBuilder().RequireRole(RoleEnum.ApiAdmin.ToString()).Build(); +builder.Services.AddAuthorization(o => o.AddPolicy("apiAdminPolicy", apiAdminPolicy)); + builder.Services.AddHttpContextAccessor(); builder.Services.AddEndpointsApiExplorer(); @@ -87,21 +92,23 @@ app.UseAuthentication(); app.UseAuthorization(); app.MapPost("/login", - async (string username, string password, IUserService userService, IAuthService authService, CancellationToken cancellationToken) => + async (LoginRequest request, IUserService userService, IAuthService authService, CancellationToken cancellationToken) => { - var user = await userService.ValidateUser(username, password, cancellationToken: cancellationToken); + var user = await userService.ValidateUser(request, cancellationToken: cancellationToken); return Results.Ok(new { Token = authService.CreateToken(user)}); }); app.MapPost("/register-user", async (RegisterUserRequest registerUserRequest, IUserService userService, CancellationToken cancellationToken) => await userService.RegisterUser(registerUserRequest, cancellationToken)) - .RequireAuthorization(p => p.RequireRole(RoleEnum.ApiAdmin.ToString())); + .RequireAuthorization(apiAdminPolicy); app.MapPost("/resources", - async (UploadResourceRequest uploadResourceRequest, IResourcesService resourceService, CancellationToken cancellationToken) - => await resourceService.SaveResource(uploadResourceRequest, cancellationToken)) - .RequireAuthorization(p => p.RequireRole(RoleEnum.ApiAdmin.ToString())); + async (ResourceEnum resourceEnum, IFormFile data, IResourcesService resourceService, CancellationToken cancellationToken) + => await resourceService.SaveResource(resourceEnum, data, cancellationToken)) + .Accepts("multipart/form-data") + .RequireAuthorization(apiAdminPolicy) + .DisableAntiforgery(); app.MapPost("/resources/get", async (GetResourceRequest request, IAuthService authService, IUserService userService, IResourcesService resourcesService, CancellationToken cancellationToken) => diff --git a/Azaion.Common/Azaion.Common.csproj b/Azaion.Common/Azaion.Common.csproj index d0dcc4e..466dfac 100644 --- a/Azaion.Common/Azaion.Common.csproj +++ b/Azaion.Common/Azaion.Common.csproj @@ -9,6 +9,7 @@ + diff --git a/Azaion.Common/BusinessException.cs b/Azaion.Common/BusinessException.cs index 3c32844..47eb561 100644 --- a/Azaion.Common/BusinessException.cs +++ b/Azaion.Common/BusinessException.cs @@ -15,5 +15,6 @@ public enum ExceptionEnum WrongEmail = 35, PasswordLengthIncorrect = 37, HardwareIdMismatch = 40, - WrongResourceType = 50 + WrongResourceType = 50, + NoFile = 60 } \ No newline at end of file diff --git a/Azaion.Common/Database/AzaionDbShemaHolder.cs b/Azaion.Common/Database/AzaionDbShemaHolder.cs index ee4b166..fc73975 100644 --- a/Azaion.Common/Database/AzaionDbShemaHolder.cs +++ b/Azaion.Common/Database/AzaionDbShemaHolder.cs @@ -1,4 +1,5 @@ using Azaion.Common.Entities; +using LinqToDB; using LinqToDB.Mapping; namespace Azaion.Common.Database; @@ -21,8 +22,12 @@ public static class AzaionDbSchemaHolder builder.Entity() .HasTableName("users") - .HasIdentity(x => x.Id) - .Property(x => x.Role).HasConversion(v => v.ToString(), v => (RoleEnum)Enum.Parse(typeof(RoleEnum), v)); + .Property(x => x.Id) + .IsPrimaryKey() + .HasDataType(DataType.Guid) + .Property(x => x.Role) + .HasDataType(DataType.Text) + .HasConversion(v => v.ToString(), v => (RoleEnum)Enum.Parse(typeof(RoleEnum), v)); builder.Build(); } diff --git a/Azaion.Common/Entities/ResourceEnum.cs b/Azaion.Common/Entities/ResourceEnum.cs index 858667c..682d4ab 100644 --- a/Azaion.Common/Entities/ResourceEnum.cs +++ b/Azaion.Common/Entities/ResourceEnum.cs @@ -4,5 +4,5 @@ public enum ResourceEnum { AnnotatorDll = 10, AIModelRKNN = 20, - AIModelONNX = 20, + AIModelONNX = 30, } \ No newline at end of file diff --git a/Azaion.Common/Entities/RoleEnum.cs b/Azaion.Common/Entities/RoleEnum.cs index 7c0f4ab..ec9ce7b 100644 --- a/Azaion.Common/Entities/RoleEnum.cs +++ b/Azaion.Common/Entities/RoleEnum.cs @@ -2,9 +2,10 @@ public enum RoleEnum { - Operator, - Validator, - CompanionPC, - Admin, - ApiAdmin + None = 0, + Operator = 10, + Validator = 20, + CompanionPC = 30, + Admin = 40, + ApiAdmin = 1000 } diff --git a/Azaion.Common/Entities/User.cs b/Azaion.Common/Entities/User.cs index 69df6fd..1183e70 100644 --- a/Azaion.Common/Entities/User.cs +++ b/Azaion.Common/Entities/User.cs @@ -3,7 +3,7 @@ public class User { public Guid Id { get; set; } - public string Email { get; set; } = null!; + public string Email { get; set; } = null!; public string PasswordHash { get; set; } = null!; public string HardwareId { get; set; } = null!; public RoleEnum Role { get; set; } diff --git a/Azaion.Common/Requests/GetResourceRequest.cs b/Azaion.Common/Requests/GetResourceRequest.cs index 6591ad6..3889648 100644 --- a/Azaion.Common/Requests/GetResourceRequest.cs +++ b/Azaion.Common/Requests/GetResourceRequest.cs @@ -7,10 +7,4 @@ public class GetResourceRequest public string Password { get; set; } = null!; public string HardwareId { get; set; } = null!; public ResourceEnum ResourceEnum { get; set; } -} - -public class UploadResourceRequest -{ - public ResourceEnum ResourceEnum { get; set; } - public Stream Data { get; set; } = null!; } \ No newline at end of file diff --git a/Azaion.Services/AuthService.cs b/Azaion.Services/AuthService.cs index 8e54a18..e40809c 100644 --- a/Azaion.Services/AuthService.cs +++ b/Azaion.Services/AuthService.cs @@ -49,7 +49,7 @@ public class AuthService(IHttpContextAccessor httpContextAccessor, IOptions C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.8\Microsoft.AspNetCore.Http.Abstractions.dll + C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.8\Microsoft.Extensions.Options.dll + diff --git a/Azaion.Services/ResourcesService.cs b/Azaion.Services/ResourcesService.cs index 2ecb6e6..68536ff 100644 --- a/Azaion.Services/ResourcesService.cs +++ b/Azaion.Services/ResourcesService.cs @@ -1,7 +1,7 @@ using Azaion.Common; using Azaion.Common.Configs; using Azaion.Common.Entities; -using Azaion.Common.Requests; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; namespace Azaion.Services; @@ -9,7 +9,7 @@ namespace Azaion.Services; public interface IResourcesService { Task GetEncryptedResource(ResourceEnum resource, string key, Stream outputStream, CancellationToken cancellationToken = default); - Task SaveResource(UploadResourceRequest request, CancellationToken cancellationToken = default); + Task SaveResource(ResourceEnum resourceEnum, IFormFile data, CancellationToken cancellationToken = default); } public class ResourcesService(IOptions resourcesConfig) : IResourcesService @@ -20,10 +20,15 @@ public class ResourcesService(IOptions resourcesConfig) : IReso await fileStream.EncryptTo(outputStream, key, cancellationToken); } - public async Task SaveResource(UploadResourceRequest request, CancellationToken cancellationToken = default) + public async Task SaveResource(ResourceEnum resourceEnum, IFormFile data, CancellationToken cancellationToken = default) { - await using var fileStream = new FileStream(GetResourcePath(request.ResourceEnum), FileMode.OpenOrCreate, FileAccess.ReadWrite); - await request.Data.CopyToAsync(fileStream, cancellationToken); + if (data == null) + throw new BusinessException(ExceptionEnum.NoFile, "No file provided!"); + if (!Directory.Exists(resourcesConfig.Value.ResourcesFolder)) + Directory.CreateDirectory(resourcesConfig.Value.ResourcesFolder); + + await using var fileStream = new FileStream(GetResourcePath(resourceEnum), FileMode.OpenOrCreate, FileAccess.ReadWrite); + await data.CopyToAsync(fileStream, cancellationToken); } private string GetResourcePath(ResourceEnum resourceEnum) diff --git a/Azaion.Services/UserService.cs b/Azaion.Services/UserService.cs index fc19292..07b2ff8 100644 --- a/Azaion.Services/UserService.cs +++ b/Azaion.Services/UserService.cs @@ -9,7 +9,7 @@ namespace Azaion.Services; public interface IUserService { Task RegisterUser(RegisterUserRequest request, CancellationToken cancellationToken = default); - Task ValidateUser(string username, string password, string? hardwareId = null, CancellationToken cancellationToken = default); + Task ValidateUser(LoginRequest request, string? hardwareId = null, CancellationToken cancellationToken = default); Task UpdateHardwareId(string username, string hardwareId, CancellationToken cancellationToken = default); } @@ -25,6 +25,7 @@ public class UserService(IDbFactory dbFactory) : IUserService await db.InsertAsync(new User { + Id = Guid.NewGuid(), Email = request.Email, PasswordHash = request.Password.ToHash(), Role = request.Role @@ -32,14 +33,14 @@ public class UserService(IDbFactory dbFactory) : IUserService }); } - public async Task ValidateUser(string username, string password, string? hardwareId = null, CancellationToken cancellationToken = default) => + public async Task ValidateUser(LoginRequest request, string? hardwareId = null, CancellationToken cancellationToken = default) => await dbFactory.Run(async db => { - var user = await db.Users.FirstOrDefaultAsync(x => x.Email == username, token: cancellationToken); + var user = await db.Users.FirstOrDefaultAsync(x => x.Email == request.Email, token: cancellationToken); if (user == null) throw new BusinessException(ExceptionEnum.NoUserFound, "No user found"); - if (password.ToHash() != user.PasswordHash) + if (request.Password.ToHash() != user.PasswordHash) throw new BusinessException(ExceptionEnum.PasswordIncorrect, "Passwords do not match"); if (user.Role == RoleEnum.ApiAdmin) diff --git a/env/02_db_structure.sql b/env/02_db_structure.sql new file mode 100644 index 0000000..5d6415c --- /dev/null +++ b/env/02_db_structure.sql @@ -0,0 +1,13 @@ +-- users table +drop table users; +create table users +( + id uuid primary key, + email varchar(160) not null, + password_hash varchar(255) not null, + hardware_id varchar(120) null, + role varchar(20) not null +); +grant select, insert, update, delete on public.users to azaion_admin; +grant select on table public.users to azaion_reader; + diff --git a/env/azaion-db.sql b/env/azaion-db.sql deleted file mode 100644 index 3a54e78..0000000 --- a/env/azaion-db.sql +++ /dev/null @@ -1,29 +0,0 @@ -create database azaion; --- make sure you connect to azaion db - ---superadmin user -create role azaion_superadmin with login password 'superadmin_pass'; -grant all privileges on all tables in schema public to azaion_superadmin; - ---writer user -create role azaion_admin with login password 'admin_pass'; -grant connect on database azaion to azaion_admin; -grant usage on schema public to azaion_admin; - ---readonly user -create role azaion_reader with login password 'reader_pass'; -grant connect on database azaion to azaion_reader; -grant usage on schema public to azaion_reader; - - --- users table -create table users -( - id uuid primary key, - email varchar(160) not null, - password_hash varchar(255) not null, - hardware_id varchar(120) not null, - role varchar(20) not null -); -grant select, insert, update, delete on public.users to azaion_admin; -grant select on table public.users to azaion_reader;