From 2c2c2b805c6be7eedc39b5f79f7e290ef213b717 Mon Sep 17 00:00:00 2001
From: Artemy <109195690+stalcker2288969@users.noreply.github.com>
Date: Wed, 18 Jun 2025 12:08:21 +0700
Subject: [PATCH] AuthSystem
---
Govor.API.Tests/Govor.API.Tests.csproj | 2 +-
.../UnitTests/Services/PasswordHasherTests.cs | 51 +++++++++++++
Govor.API/Controllers/AuthController.cs | 72 +++++++++++++++++++
Govor.API/Controllers/InviteController.cs | 31 ++++++++
Govor.API/Govor.API.csproj | 6 +-
.../Services/Authentication/AuthService.cs | 33 +++++++++
Govor.API/Services/PasswordHasher.cs | 16 +++++
Govor.Core/DTOs/UserDto.cs | 3 +
Govor.Core/Govor.Core.csproj | 4 --
.../Extensions/IPasswordHasher.cs | 7 ++
Govor.Core/Services/IAuthService.cs | 7 ++
Govor.Core/Services/IGroupService.cs | 8 +++
12 files changed, 230 insertions(+), 10 deletions(-)
create mode 100644 Govor.API.Tests/UnitTests/Services/PasswordHasherTests.cs
create mode 100644 Govor.API/Controllers/AuthController.cs
create mode 100644 Govor.API/Controllers/InviteController.cs
create mode 100644 Govor.API/Services/Authentication/AuthService.cs
create mode 100644 Govor.API/Services/PasswordHasher.cs
create mode 100644 Govor.Core/DTOs/UserDto.cs
create mode 100644 Govor.Core/Infrastructure/Extensions/IPasswordHasher.cs
create mode 100644 Govor.Core/Services/IAuthService.cs
create mode 100644 Govor.Core/Services/IGroupService.cs
diff --git a/Govor.API.Tests/Govor.API.Tests.csproj b/Govor.API.Tests/Govor.API.Tests.csproj
index 50de971..3a4ca0b 100644
--- a/Govor.API.Tests/Govor.API.Tests.csproj
+++ b/Govor.API.Tests/Govor.API.Tests.csproj
@@ -26,10 +26,10 @@
-
+
diff --git a/Govor.API.Tests/UnitTests/Services/PasswordHasherTests.cs b/Govor.API.Tests/UnitTests/Services/PasswordHasherTests.cs
new file mode 100644
index 0000000..4326528
--- /dev/null
+++ b/Govor.API.Tests/UnitTests/Services/PasswordHasherTests.cs
@@ -0,0 +1,51 @@
+using AutoFixture;
+using Govor.API.Services;
+using Govor.Core.Infrastructure.Extensions;
+
+namespace Govor.API.Tests.UnitTests.Services;
+
+[TestFixture]
+public class PasswordHasherTests
+{
+ private IPasswordHasher _passwordHasher;
+ private Fixture _fixture;
+
+ [SetUp]
+ public void StarUp()
+ {
+ _fixture = new Fixture();
+ _passwordHasher = new PasswordHasher();
+ }
+
+ [Test]
+ public void Given_Password_When_Hash_Then_Hash_And_Verify_Then_Result_Should_Be_True()
+ {
+ // Arrange
+ string password = _fixture.Create();
+
+ // Act
+ string hash = _passwordHasher.Hash(password);
+
+ var result = _passwordHasher.Verify(password, hash);
+
+ // Assert
+ Assert.That(hash, Is.Not.EqualTo(password));
+ Assert.That(result, Is.True);
+ }
+
+ [Test]
+ public void Given_Password_NotPassword_When_Hash_Should_Not_Be_True_Then_Result_Should_Be_False()
+ {
+ // Arrange
+ string password = _fixture.Create();
+ string notPassword = _fixture.Create();
+
+ // Act
+ string hash = _passwordHasher.Hash(password);
+
+ var result = _passwordHasher.Verify(notPassword, hash);
+
+ // Assert
+ Assert.That(result, Is.False);
+ }
+}
\ No newline at end of file
diff --git a/Govor.API/Controllers/AuthController.cs b/Govor.API/Controllers/AuthController.cs
new file mode 100644
index 0000000..a72284e
--- /dev/null
+++ b/Govor.API/Controllers/AuthController.cs
@@ -0,0 +1,72 @@
+using Govor.API.Services.Authentication;
+using Govor.Core.DTOs;
+using Govor.Core.Services;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Govor.API.Controllers;
+
+[ApiController]
+[Route("[controller]")]
+public class AuthController : Controller
+{
+ private IAccountService _accountService;
+ private ILogger _logger;
+
+ public AuthController(IAccountService accountService, ILogger logger)
+ {
+ _accountService = accountService;
+ _logger = logger;
+ }
+
+ [HttpPost("register")]
+ [RequireHttps]
+ public async Task Register([FromBody] UserDto userDto)
+ {
+ try
+ {
+ if (!ModelState.IsValid)
+ {
+ return BadRequest(ModelState);
+ }
+
+ await _accountService.RegistrationAsync(userDto.Name, userDto.Password);
+ return Ok(new { Message = "User registered successfully" });
+ }
+ catch (UserAlreadyExistException ex)
+ {
+ _logger.LogWarning(ex, $"Registration failed for user {userDto.Name}");
+ return BadRequest("Registration failed: user already exists.");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Unexpected error during registration for user {Name}", userDto.Name);
+ return StatusCode(500, "An unexpected error occurred. Please try again later.");
+ }
+ }
+
+ [HttpPost("login")]
+ [RequireHttps]
+ public async Task Login([FromBody] UserDto userDto)
+ {
+ try
+ {
+ if (!ModelState.IsValid)
+ {
+ return BadRequest(ModelState);
+ }
+
+ await _accountService.LoginAsync(userDto.Name, userDto.Password);
+ return Ok(new { Message = "User login successfully" });
+ }
+ catch (UserNotRegisteredException ex)
+ {
+ _logger.LogWarning(ex, "Login failed for user {Name}", userDto.Name);
+ return BadRequest("Login failed: user does not exist.");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Unexpected error during login for user {Name}", userDto.Name);
+ return StatusCode(500, "An unexpected error occurred. Please try again later.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/Govor.API/Controllers/InviteController.cs b/Govor.API/Controllers/InviteController.cs
new file mode 100644
index 0000000..f56d75e
--- /dev/null
+++ b/Govor.API/Controllers/InviteController.cs
@@ -0,0 +1,31 @@
+using Govor.Core.Services;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Govor.API.Controllers;
+
+[ApiController]
+[Route("invite")]
+public class InviteController : ControllerBase
+{
+ private readonly IGroupService _groupService;
+
+ public InviteController(IGroupService groupService)
+ {
+ _groupService = groupService;
+ }
+
+ [HttpGet("{code}")]
+ public IActionResult JoinGroup(string code)
+ {
+ var group = _groupService.GetGroupByInvite(code);
+ if (group == null) return NotFound();
+
+ // Вернуть инфу, которая откроется в MAUI-клиенте
+ return Ok(new
+ {
+ groupId = group.Id,
+ name = group.Name,
+ isChannel = group.IsChannel
+ });
+ }
+}
diff --git a/Govor.API/Govor.API.csproj b/Govor.API/Govor.API.csproj
index 9c0771d..96dd6da 100644
--- a/Govor.API/Govor.API.csproj
+++ b/Govor.API/Govor.API.csproj
@@ -7,6 +7,7 @@
+
@@ -21,9 +22,4 @@
-
-
-
-
-
diff --git a/Govor.API/Services/Authentication/AuthService.cs b/Govor.API/Services/Authentication/AuthService.cs
new file mode 100644
index 0000000..ea7bdf6
--- /dev/null
+++ b/Govor.API/Services/Authentication/AuthService.cs
@@ -0,0 +1,33 @@
+using Govor.Core.Infrastructure.Extensions;
+using Govor.Core.Repositories;
+using Govor.Core.Services;
+
+namespace Govor.API.Services.Authentication;
+
+public class AuthService : IAccountService
+{
+ private readonly IPasswordHasher _passwordHasher;
+ private readonly IUsersRepository _usersRepository;
+
+ public AuthService(IUsersRepository usersRepository, IPasswordHasher passwordHasher)
+ {
+ _usersRepository = usersRepository;
+ _passwordHasher = passwordHasher;
+ }
+ public Task RegistrationAsync(string name, string password)
+ {
+ throw new NotImplementedException();
+ }
+
+ public async Task LoginAsync(string name, string password)
+ {
+ if (await _usersRepository.ExistsUsernameAsync(name) == false)
+ throw new UserNotRegisteredException(name);
+
+ throw new NotImplementedException();
+ }
+}
+
+public class UserAlreadyExistException(string username) : Exception($"{username} is already exists!") { }
+
+public class UserNotRegisteredException(string username) : Exception($"{username} is not registered!") { }
\ No newline at end of file
diff --git a/Govor.API/Services/PasswordHasher.cs b/Govor.API/Services/PasswordHasher.cs
new file mode 100644
index 0000000..4976236
--- /dev/null
+++ b/Govor.API/Services/PasswordHasher.cs
@@ -0,0 +1,16 @@
+using Govor.Core.Infrastructure.Extensions;
+
+namespace Govor.API.Services;
+
+public class PasswordHasher : IPasswordHasher
+{
+ public string Hash(string password)
+ {
+ return BCrypt.Net.BCrypt.HashPassword(password);
+ }
+
+ public bool Verify(string hashedPassword, string providedPassword)
+ {
+ return BCrypt.Net.BCrypt.Verify(hashedPassword, providedPassword);
+ }
+}
\ No newline at end of file
diff --git a/Govor.Core/DTOs/UserDto.cs b/Govor.Core/DTOs/UserDto.cs
new file mode 100644
index 0000000..7a5032d
--- /dev/null
+++ b/Govor.Core/DTOs/UserDto.cs
@@ -0,0 +1,3 @@
+namespace Govor.Core.DTOs;
+
+public record UserDto(string Password, string Name);
\ No newline at end of file
diff --git a/Govor.Core/Govor.Core.csproj b/Govor.Core/Govor.Core.csproj
index 71fa877..1f027dd 100644
--- a/Govor.Core/Govor.Core.csproj
+++ b/Govor.Core/Govor.Core.csproj
@@ -6,10 +6,6 @@
enable
-
-
-
-
diff --git a/Govor.Core/Infrastructure/Extensions/IPasswordHasher.cs b/Govor.Core/Infrastructure/Extensions/IPasswordHasher.cs
new file mode 100644
index 0000000..c6253c9
--- /dev/null
+++ b/Govor.Core/Infrastructure/Extensions/IPasswordHasher.cs
@@ -0,0 +1,7 @@
+namespace Govor.Core.Infrastructure.Extensions;
+
+public interface IPasswordHasher
+{
+ string Hash(string password);
+ bool Verify(string hashedPassword, string providedPassword);
+}
\ No newline at end of file
diff --git a/Govor.Core/Services/IAuthService.cs b/Govor.Core/Services/IAuthService.cs
new file mode 100644
index 0000000..25d3697
--- /dev/null
+++ b/Govor.Core/Services/IAuthService.cs
@@ -0,0 +1,7 @@
+namespace Govor.Core.Services;
+
+public interface IAccountService
+{
+ public Task RegistrationAsync(string name, string password);
+ public Task LoginAsync(string name, string password);
+}
\ No newline at end of file
diff --git a/Govor.Core/Services/IGroupService.cs b/Govor.Core/Services/IGroupService.cs
new file mode 100644
index 0000000..d3a5d42
--- /dev/null
+++ b/Govor.Core/Services/IGroupService.cs
@@ -0,0 +1,8 @@
+using Govor.Core.Models;
+
+namespace Govor.Core.Services;
+
+public interface IGroupService
+{
+ ChatGroup GetGroupByInvite(string code);
+}
\ No newline at end of file