diff --git a/Endpoint/Common/Model/Admin.cs b/Endpoint/Common/Model/Admin.cs new file mode 100644 index 0000000..59e4b60 --- /dev/null +++ b/Endpoint/Common/Model/Admin.cs @@ -0,0 +1,10 @@ +namespace Mirea.Api.Endpoint.Common.Model; + +public class Admin +{ + public const string PathToSave = "admin.json"; + public required string Username { get; set; } + public required string Email { get; set; } + public required string PasswordHash { get; set; } + public required string Salt { get; set; } +} \ No newline at end of file diff --git a/Endpoint/Controllers/Configuration/SetupController.cs b/Endpoint/Controllers/Configuration/SetupController.cs index 1c9d275..9bda318 100644 --- a/Endpoint/Controllers/Configuration/SetupController.cs +++ b/Endpoint/Controllers/Configuration/SetupController.cs @@ -8,19 +8,23 @@ using Mirea.Api.Dto.Requests.Configuration; using Mirea.Api.Endpoint.Common.Attributes; using Mirea.Api.Endpoint.Common.Exceptions; using Mirea.Api.Endpoint.Common.Interfaces; +using Mirea.Api.Endpoint.Common.Model; using Mirea.Api.Endpoint.Common.Services; using Mirea.Api.Endpoint.Configuration.General; using Mirea.Api.Endpoint.Configuration.General.Settings; using Mirea.Api.Endpoint.Configuration.General.Validators; +using Mirea.Api.Security.Services; using MySqlConnector; using Npgsql; using StackExchange.Redis; using System; using System.Data; using System.IO; +using System.Net.Mail; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text.Json; +using System.Text.RegularExpressions; namespace Mirea.Api.Endpoint.Controllers.Configuration; @@ -28,7 +32,11 @@ namespace Mirea.Api.Endpoint.Controllers.Configuration; [ApiController] [MaintenanceModeIgnore] [ApiExplorerSettings(IgnoreApi = true)] -public class SetupController(ISetupToken setupToken, IMaintenanceModeNotConfigureService notConfigureService, IMemoryCache cache) : BaseController +public class SetupController( + ISetupToken setupToken, + IMaintenanceModeNotConfigureService notConfigureService, + IMemoryCache cache, + PasswordHashService passwordHashService) : BaseController { private const string CacheGeneralKey = "config_general"; private const string CacheAdminKey = "config_admin"; @@ -199,8 +207,23 @@ public class SetupController(ISetupToken setupToken, IMaintenanceModeNotConfigur [BadRequestResponse] public ActionResult CreateAdmin([FromBody] CreateUserRequest user) { - // todo: change CreateUserRequest to Domain entity - cache.Set(CacheAdminKey, user); + if (user.Password.Length < 8 || !Regex.IsMatch(user.Password, "[A-Z]+") || !Regex.IsMatch(user.Password, "[!@#$%^&*]+")) + throw new ControllerArgumentException("The password must be at least 8 characters long and contain at least one uppercase letter and one special character."); + + if (!MailAddress.TryCreate(user.Email, out _)) + throw new ControllerArgumentException("The email address is incorrect."); + + var (salt, hash) = passwordHashService.HashPassword(user.Password); + + var admin = new Admin + { + Username = user.Username, + Email = user.Email, + PasswordHash = hash, + Salt = salt + }; + + cache.Set(CacheAdminKey, admin); return Ok(true); } @@ -290,14 +313,13 @@ public class SetupController(ISetupToken setupToken, IMaintenanceModeNotConfigur if (!new SettingsRequiredValidator(GeneralConfig).AreSettingsValid()) throw new ControllerArgumentException("The necessary data has not been configured."); - // todo: change CreateUserRequest to Domain entity - if (!cache.TryGetValue(CacheAdminKey, out CreateUserRequest? user) || user == null) + if (!cache.TryGetValue(CacheAdminKey, out Admin? admin) || admin == null) throw new ControllerArgumentException("The administrator's data was not set."); if (System.IO.File.Exists(PathBuilder.Combine(GeneralConfig.FilePath))) System.IO.File.Delete(PathBuilder.Combine(GeneralConfig.FilePath)); - System.IO.File.WriteAllText(PathBuilder.Combine("admin.json"), JsonSerializer.Serialize(user)); + System.IO.File.WriteAllText(PathBuilder.Combine(Admin.PathToSave), JsonSerializer.Serialize(admin)); System.IO.File.WriteAllText( PathBuilder.Combine(GeneralConfig.FilePath),