Add an Administrator (#14)
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				.NET Test Pipeline / build-and-test (push) Successful in 1m57s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	.NET Test Pipeline / build-and-test (push) Successful in 1m57s
				
			Reviewed-on: #14
This commit was merged in pull request #14.
	This commit is contained in:
		
							
								
								
									
										10
									
								
								Endpoint/Common/Model/Admin.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Endpoint/Common/Model/Admin.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -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; } | ||||||
|  | } | ||||||
| @@ -8,19 +8,23 @@ using Mirea.Api.Dto.Requests.Configuration; | |||||||
| using Mirea.Api.Endpoint.Common.Attributes; | using Mirea.Api.Endpoint.Common.Attributes; | ||||||
| using Mirea.Api.Endpoint.Common.Exceptions; | using Mirea.Api.Endpoint.Common.Exceptions; | ||||||
| using Mirea.Api.Endpoint.Common.Interfaces; | using Mirea.Api.Endpoint.Common.Interfaces; | ||||||
|  | using Mirea.Api.Endpoint.Common.Model; | ||||||
| using Mirea.Api.Endpoint.Common.Services; | using Mirea.Api.Endpoint.Common.Services; | ||||||
| using Mirea.Api.Endpoint.Configuration.General; | using Mirea.Api.Endpoint.Configuration.General; | ||||||
| using Mirea.Api.Endpoint.Configuration.General.Settings; | using Mirea.Api.Endpoint.Configuration.General.Settings; | ||||||
| using Mirea.Api.Endpoint.Configuration.General.Validators; | using Mirea.Api.Endpoint.Configuration.General.Validators; | ||||||
|  | using Mirea.Api.Security.Services; | ||||||
| using MySqlConnector; | using MySqlConnector; | ||||||
| using Npgsql; | using Npgsql; | ||||||
| using StackExchange.Redis; | using StackExchange.Redis; | ||||||
| using System; | using System; | ||||||
| using System.Data; | using System.Data; | ||||||
| using System.IO; | using System.IO; | ||||||
|  | using System.Net.Mail; | ||||||
| using System.Runtime.InteropServices; | using System.Runtime.InteropServices; | ||||||
| using System.Security.Cryptography; | using System.Security.Cryptography; | ||||||
| using System.Text.Json; | using System.Text.Json; | ||||||
|  | using System.Text.RegularExpressions; | ||||||
|  |  | ||||||
| namespace Mirea.Api.Endpoint.Controllers.Configuration; | namespace Mirea.Api.Endpoint.Controllers.Configuration; | ||||||
|  |  | ||||||
| @@ -28,7 +32,11 @@ namespace Mirea.Api.Endpoint.Controllers.Configuration; | |||||||
| [ApiController] | [ApiController] | ||||||
| [MaintenanceModeIgnore] | [MaintenanceModeIgnore] | ||||||
| [ApiExplorerSettings(IgnoreApi = true)] | [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 CacheGeneralKey = "config_general"; | ||||||
|     private const string CacheAdminKey = "config_admin"; |     private const string CacheAdminKey = "config_admin"; | ||||||
| @@ -199,8 +207,23 @@ public class SetupController(ISetupToken setupToken, IMaintenanceModeNotConfigur | |||||||
|     [BadRequestResponse] |     [BadRequestResponse] | ||||||
|     public ActionResult<string> CreateAdmin([FromBody] CreateUserRequest user) |     public ActionResult<string> CreateAdmin([FromBody] CreateUserRequest user) | ||||||
|     { |     { | ||||||
|         // todo: change CreateUserRequest to Domain entity |         if (user.Password.Length < 8 || !Regex.IsMatch(user.Password, "[A-Z]+") || !Regex.IsMatch(user.Password, "[!@#$%^&*]+")) | ||||||
|         cache.Set(CacheAdminKey, user); |             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); |         return Ok(true); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -290,14 +313,13 @@ public class SetupController(ISetupToken setupToken, IMaintenanceModeNotConfigur | |||||||
|         if (!new SettingsRequiredValidator(GeneralConfig).AreSettingsValid()) |         if (!new SettingsRequiredValidator(GeneralConfig).AreSettingsValid()) | ||||||
|             throw new ControllerArgumentException("The necessary data has not been configured."); |             throw new ControllerArgumentException("The necessary data has not been configured."); | ||||||
|  |  | ||||||
|         // todo: change CreateUserRequest to Domain entity |         if (!cache.TryGetValue(CacheAdminKey, out Admin? admin) || admin == null) | ||||||
|         if (!cache.TryGetValue(CacheAdminKey, out CreateUserRequest? user) || user == null) |  | ||||||
|             throw new ControllerArgumentException("The administrator's data was not set."); |             throw new ControllerArgumentException("The administrator's data was not set."); | ||||||
|  |  | ||||||
|         if (System.IO.File.Exists(PathBuilder.Combine(GeneralConfig.FilePath))) |         if (System.IO.File.Exists(PathBuilder.Combine(GeneralConfig.FilePath))) | ||||||
|             System.IO.File.Delete(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( |         System.IO.File.WriteAllText( | ||||||
|             PathBuilder.Combine(GeneralConfig.FilePath), |             PathBuilder.Combine(GeneralConfig.FilePath), | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user