Привет! Помоги решить ошибку: [
An unexpected error occurred. Please try again. System.ArgumentOutOfRangeException: IDX10720: Unable to create KeyedHashAlgorithm for algorithm 'HS256', the key size must be greater than: '256' bits, key has '184' bits. (Parameter 'keyBytes')
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.ValidateKeySize(Byte[] keyBytes, String algorithm, Int32 expectedNumberOfBytes)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateKeyedHashAlgorithm(Byte[] keyBytes, String algorithm)
   at Microsoft.IdentityModel.Tokens.SymmetricSignatureProvider.CreateKeyedHashAlgorithm()
   at Microsoft.IdentityModel.Tokens.DisposableObjectPool`1.CreateInstance()
   at Microsoft.IdentityModel.Tokens.DisposableObjectPool`1.Allocate()
   at Microsoft.IdentityModel.Tokens.SymmetricSignatureProvider.GetKeyedHashAlgorithm(Byte[] keyBytes, String algorithm)
   at Microsoft.IdentityModel.Tokens.SymmetricSignatureProvider.Sign(Byte[] input)
   at Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.CreateEncodedSignature(String input, SigningCredentials signingCredentials)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.WriteToken(SecurityToken token)
   at EaseMoney.API.Controllers.AuthController.GenerateJwtToken(String username) in /app/src/API/Controllers/AuthController.cs:line 104
   at EaseMoney.API.Controllers.AuthController.Verify(VerifyUserDto model) in /app/src/API/Controllers/AuthController.cs:line 57
]



Вот код: [/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/Dockerfile: [﻿# Stage: Base (Runtime Image)
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER $APP_UID
WORKDIR /app
EXPOSE 8080
EXPOSE 8081

# Stage: Build (SDK Image)
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
# Копируем только проектный файл, чтобы сначала восстановить зависимости
COPY EaseMoney.csproj ./
RUN dotnet restore "EaseMoney.csproj"

# Копируем весь оставшийся код
COPY . .

# Выполняем сборку проекта
WORKDIR "/src"
RUN dotnet build "EaseMoney.csproj" -c $BUILD_CONFIGURATION -o /app/build

# Stage: Publish
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
# Применяем миграции
# Выполняем публикацию проекта
RUN dotnet publish "EaseMoney.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

# Stage: Final (Runtime Image)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "EaseMoney.dll"]]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/Makefile: [test:
	ls
	]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/appsettings.json: [{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "DefaultConnection": "Server=db;Port=5432;Database=easemoney_db;Username=postgres;Password=yourpassword"
  },
  "JwtSettings": {
    "SecretKey": "YourSuperSecretKey12345",
    "Issuer": "EaseMoneyAPI",
    "Audience": "EaseMoneyClient",
    "ExpiryMinutes": 60
  }
}
]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/EaseMoney.http: [@EaseMoney_HostAddress = http://localhost:5185

GET {{EaseMoney_HostAddress}}/weatherforecast/
Accept: application/json

###
]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/docker-compose.yml: [﻿version: '3.3'

services:
  easemoney-app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8090:8080"
      - "8091:8091"
    depends_on:
      - db
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ConnectionStrings__DefaultConnection=Server=db;Port=5432;Database=easemoney_db;User Id=postgres;Password=yourpassword
      - ASPNETCORE_URLS=http://+:8080
    networks:
      - easemoney-net

  db:
    image: postgres:14
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: yourpassword
      POSTGRES_DB: easemoney_db
    ports:
      - "5432:5432"
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - easemoney-net

  migrate:
    image: mcr.microsoft.com/dotnet/sdk:8.0
    depends_on:
      - db
    working_dir: /app
    volumes:
      - ./:/app
#    command: >
#      bash -c "
#      echo 'Current directory:' &&
#      pwd &&
#      echo 'Contents of /app:' &&
#      ls -la /app &&
#      echo 'Contents of /app/EaseMoney:' &&
#      ls -la /app/EaseMoney &&
#      dotnet tool install --global dotnet-ef &&
#      export PATH=\$PATH:/root/.dotnet/tools &&
#      dotnet ef database update
#      "
    command: >
      bash -c "
      dotnet tool install --global dotnet-ef &&
      export PATH=\$PATH:/root/.dotnet/tools &&
      dotnet ef database update
      "
      
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ConnectionStrings__DefaultConnection=Server=db;Port=5432;Database=easemoney_db;User Id=postgres;Password=yourpassword
    networks:
      - easemoney-net

volumes:
  postgres-data:

networks:
  easemoney-net:]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/appsettings.Development.json: [{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "ConnectionStrings": {
    "DefaultConnection": "Server=db;Port=5432;Database=easemoney_db;Username=postgres;Password=yourpassword"
  }
}
]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/EaseMoney.csproj: [<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
        <InvariantGlobalization>true</InvariantGlobalization>
        <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.1" />
        <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.8" />
        <PackageReference Include="Microsoft.AspNetCore.Cors" Version="2.2.0" />
        <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.1" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
          <PrivateAssets>all</PrivateAssets>
        </PackageReference>
        <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
        <PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.3" />
        <PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.7.3" />
        <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.7.3" />
    </ItemGroup>

    <ItemGroup>
      <Content Include="..\.dockerignore">
        <Link>.dockerignore</Link>
      </Content>
    </ItemGroup>

    <ItemGroup>
      <Folder Include="src\Infrastructure\Persistence\Migrations\" />
    </ItemGroup>

</Project>
]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/Program.cs: [using System.Text;
using EaseMoney.Application.Services;
using EaseMoney.Core.Ports;
using EaseMoney.Infrastructure.Persistence;
using EaseMoney.Infrastructure.Persistence.Repositories;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;

var builder = WebApplication.CreateBuilder(args);

// Добавление настроек JWT из конфигурации
var jwtSettings = builder.Configuration.GetSection("JwtSettings");
var secretKey = jwtSettings.GetValue<string>("SecretKey");
var issuer = jwtSettings.GetValue<string>("Issuer");
var audience = jwtSettings.GetValue<string>("Audience");

// Подключение базы данных
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

// Регистрация портов и адаптеров
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<IUserService, UserService>();

// Регистрация сервисов
builder.Services.AddScoped<UserService>();

// Добавление CORS
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowSpecificOrigin", builder =>
    {
        builder.WithOrigins("http://localhost:4200")
            .AllowAnyHeader()
            .AllowAnyMethod()
            .AllowCredentials(); // Если используете куки или авторизацию
    });
});


// Добавление аутентификации JWT
builder.Services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = issuer,
            ValidAudience = audience,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)),
            ClockSkew = TimeSpan.Zero // TODO: Можно настроить для продакшена
        };
    });

builder.Services.AddAuthorization();

// Подключение контроллеров и Swagger
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Поддержка Swagger
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
        c.RoutePrefix = "swagger";
    });
}

// Важно: вызов CORS перед другими middleware
app.UseCors("AllowSpecificOrigin");

// Вызов аутентификации и авторизации
app.UseAuthentication();
app.UseAuthorization();

app.UseHttpsRedirection();

app.MapControllers();

// Дополнительные заголовки безопасности
app.Use(async (context, next) =>
{
    context.Response.Headers.Add("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload");
    await next();
});

app.Run();]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/EaseMoney/a.txt: []

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/Properties/launchSettings.json: [﻿{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:25779",
      "sslPort": 44339
    }
  },
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "http://localhost:5185",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "https://localhost:7010;http://localhost:5185",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}
]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Core/Ports/IUserService.cs: [using EaseMoney.Application.DTOs;

namespace EaseMoney.Core.Ports;

public interface IUserService
{
    Task<bool> RegisterUserAsync(RegisterUserDto model);
    Task<(bool IsVerified, bool IsError)> VerifyUserAsync(VerifyUserDto model);
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Core/Ports/IUserRepository.cs: [using EaseMoney.Core.Entities;

namespace EaseMoney.Core.Ports;

public interface IUserRepository
{
    Task<User> GetUserByUsernameAsync(string username);
    Task AddUserAsync(User user);
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Core/Entities/Transaction.cs: [namespace EaseMoney.Core.Entities;

public class Transaction
{
    public int Id { get; set; }
    public Guid UserId { get; set; }
    public decimal Amount { get; set; }
    public DateTime TransactionDate { get; set; } = DateTime.Now;
    public string Description { get; set; }
    public bool IsRecurring { get; set; } = false;
    public DateTime CreatedAt { get; set; } = DateTime.Now;
    
    public User User { get; set; }
    public IncomeTransaction IncomeTransaction { get; set; }
    public ExpenseTransaction ExpenseTransaction { get; set; }
    public Reminder Reminder { get; set; }


}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Core/Entities/Budget.cs: [namespace EaseMoney.Core.Entities;

public class Budget
{
    public int Id { get; set; }
    public Guid UserId { get; set; }
    public string Name { get; set; }
    public decimal TotalAmount { get; set; }
    public decimal GoalAmount { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public DateTime CreatedAt { get; set; }
    
    public User User { get; set; }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Core/Entities/ExpenseCategory.cs: [namespace EaseMoney.Core.Entities;

public class ExpenseCategory
{
    public int Id { get; set; }
    public Guid UserId { get; set; }
    public string Name { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.Now;
    
    public User User { get; set; }
    public ICollection<ExpenseTransaction> ExpenseTransaction { get; set; }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Core/Entities/User.cs: [using System.ComponentModel.DataAnnotations;

namespace EaseMoney.Core.Entities;

public class User
{
    public int Id { get; set; }
    public string Username { get; set; }
    public string PasswordHash { get; set; }
    
    public ICollection<IncomeCategory> IncomeCategories { get; set; }
    public ICollection<ExpenseCategory> ExpenseCategories { get; set; }
    public ICollection<Transaction> Transactions { get; set; }
    public ICollection<Budget> Budgets { get; set; }
    public ICollection<Loan> Loans { get; set; }
    public ICollection<Reminder> Reminders { get; set; }
    
    
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Core/Entities/IncomeTransaction.cs: [namespace EaseMoney.Core.Entities;

public class IncomeTransaction
{
    public int Id { get; set; }
    public int TransactionId { get; set; }
    public int CategoryId { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;

    public Transaction Transaction { get; set; }
    public IncomeCategory IncomeCategory { get; set; }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Core/Entities/IncomeCategory.cs: [namespace EaseMoney.Core.Entities;

public class IncomeCategory
{
    public int Id { get; set; }
    public Guid UserId { get; set; }
    public string Name { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.Now;
    
    public User User { get; set; }
    public ICollection<IncomeTransaction> IncomeTransaction { get; set; }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Core/Entities/Payment.cs: [namespace EaseMoney.Core.Entities;

public class Payment
{
    public int Id { get; set; }
    public int LoanId { get; set; }
    public int PaymentNumber { get; set; }
    public DateTime PaymentDate { get; set; }
    public decimal Amount { get; set; }
    public string Status { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;

    public Loan Loan { get; set; }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Core/Entities/ExpenseTransaction.cs: [namespace EaseMoney.Core.Entities;

public class ExpenseTransaction
{
    public int Id { get; set; }
    public int TransactionId { get; set; }
    public int CategoryId { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;

    public Transaction Transaction { get; set; }
    public ExpenseCategory ExpenseCategory { get; set; }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Core/Entities/Reminder.cs: [namespace EaseMoney.Core.Entities;

public class Reminder
{
    public int Id { get; set; }
    public Guid UserId { get; set; }
    public int TransactionId { get; set; }
    public DateTime ReminderDate { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;

    public User User { get; set; }
    public Transaction Transaction { get; set; }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Core/Entities/Loan.cs: [namespace EaseMoney.Core.Entities;

public class Loan
{
    public int Id { get; set; }
    public Guid UserdId { get; set; }
    public string BankName { get; set; }
    public decimal LoanAmount { get; set; }
    public decimal TotalAmount { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.Now;

    public User User { get; set; }
    public ICollection<Payment> Payments { get; set; }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/API/Controllers/AuthController.cs: [using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using EaseMoney.Application.DTOs;
using EaseMoney.Application.Services;
using EaseMoney.Core.Ports;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;

namespace EaseMoney.API.Controllers;

[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
    private readonly IUserService _userService;
    private readonly IConfiguration _configuration;

    public AuthController(IUserService userService, IConfiguration configuration)
    {
        _userService = userService;
        _configuration = configuration;
    }
    
    [HttpPost("register")]
    public async Task<IActionResult> Register([FromBody] RegisterUserDto model)
    {
        try
        {
            var result = await _userService.RegisterUserAsync(model);
            
            if (result)
            {
                return Ok(new { Message = "User registered successfully" });
            }
            else
            {
                return BadRequest(new { Message = "User registration failed. User may already exist or there was an error." });
            }
        }
        catch (Exception e)
        {
            return StatusCode(500, "An unexpected error occurred. Please try again.");
        }
    }
    
    [HttpPost("verify")]
    public async Task<IActionResult> Verify([FromBody] VerifyUserDto model)
    {
        try
        {
            var (isValid, isError) = await _userService.VerifyUserAsync(model);
            
            // If there is no error and user is valid
            if (!isError && isValid)
            {
                var token = GenerateJwtToken(model.Username);
                return Ok(new { Message = "Verification successful", Token = token });
            }
            else if (isError)
            {
                // Return generic error message
                return StatusCode(500, "An unexpected error occurred. Please try qweqwe.");
            }
            else
            {
                return Unauthorized("Invalid credentials.");
            }
        }
        catch (Exception e)
        {
            return StatusCode(500, $"An unexpected error occurred. Please try again. {e}");
        }
    }
    
    
    private string GenerateJwtToken(string username)
    {
        var jwtSettings = _configuration.GetSection("JwtSettings");
        var secretKey = jwtSettings.GetValue<string>("SecretKey");
        var issuer = jwtSettings.GetValue<string>("Issuer");
        var audience = jwtSettings.GetValue<string>("Audience");
        var expiryMinutes = jwtSettings.GetValue<int>("ExpiryMinutes");

        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        // Добавляем утверждения (claims)
        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, username),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
            // Можно добавить дополнительные claims, например, роли пользователя
        };

        var token = new JwtSecurityToken(
            issuer: issuer,
            audience: audience,
            claims: claims,
            expires: DateTime.UtcNow.AddMinutes(expiryMinutes),
            signingCredentials: credentials
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Application/DTOs/RegisterUserDto.cs: [using System.ComponentModel.DataAnnotations;

namespace EaseMoney.Application.DTOs;

public class RegisterUserDto
{
    
    [Required]
    [MinLength(4, ErrorMessage = "Minimum length is 4")]
    [RegularExpression(@"^[a-zA-Z]+$", ErrorMessage = "Only english letters are allowed.")]
    public required string Username { get; set; }
    
    [Required]
    [MinLength(8, ErrorMessage = "Minimum length is 8")]
    [RegularExpression(@"^[a-zA-Z0-9!@#$%^&*()]+$", ErrorMessage = "Only English letters, numbers, and special characters are allowed.")]
    public required string Password { get; set; }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Application/DTOs/VerifyUserDto.cs: [using System.ComponentModel.DataAnnotations;

namespace EaseMoney.Application.DTOs;

public class VerifyUserDto
{
    [Required]
    [MinLength(4, ErrorMessage = "Minimum length is 4")]
    [RegularExpression(@"^[a-zA-Z]+$", ErrorMessage = "Only english letters are allowed.")]
    public required string Username { get; set; }
    
    [Required]
    [MinLength(8, ErrorMessage = "Minimum length is 8")]
    [RegularExpression(@"^[a-zA-Z0-9!@#$%^&*()]+$", ErrorMessage = "Only English letters, numbers, and special characters are allowed.")]
    public required string Password { get; set; }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Application/Services/UserService.cs: [using System.Security.Cryptography;
using System.Text;
using EaseMoney.Application.DTOs;
using EaseMoney.Core.Entities;
using EaseMoney.Core.Ports;
using Konscious.Security.Cryptography;

namespace EaseMoney.Application.Services;

public class UserService : IUserService
{
    private readonly IUserRepository _userRepository;

        public UserService(IUserRepository userRepository)
        {
            _userRepository = userRepository;
        }

        public async Task<bool> RegisterUserAsync(RegisterUserDto registerUserDto)
        {
            try
            {
                var existingUser = await _userRepository.GetUserByUsernameAsync(registerUserDto.Username);
            
                if (existingUser != null)
                {
                    return false; // Пользователь уже существует
                }

                // Создаем нового пользователя
                var newUser = new User
                {
                    Username = registerUserDto.Username,
                    PasswordHash = HashPasswordWithArgon2(registerUserDto.Password) // Хешируем пароль с Argon2
                };

                await _userRepository.AddUserAsync(newUser);
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }
        
        
        public async Task<(bool IsVerified, bool IsError)> VerifyUserAsync(VerifyUserDto verifyUserDto)
        {
            try
            {
                var user = await _userRepository.GetUserByUsernameAsync(verifyUserDto.Username);
                if (user == null)
                {
                    return (false, false);
                }
        
                return (VerifyPassword(verifyUserDto.Password, user.PasswordHash), false);
            }
            catch (Exception ex)
            {
                return (false, true);
            }
        }

        public bool VerifyPassword(string enteredPassword, string storedHash)
        {
            return VerifyPasswordWithArgon2(enteredPassword, storedHash);
        }

        private string HashPasswordWithArgon2(string password)
        {
            // Настройка Argon2
            var salt = GenerateSalt();
            var argon2 = new Argon2id(Encoding.UTF8.GetBytes(password))
            {
                Salt = salt,
                DegreeOfParallelism = 8, // Количество параллельных потоков
                Iterations = 4,          // Количество итераций
                MemorySize = 65536       // Размер памяти в KB (64 MB)
            };

            var hash = argon2.GetBytes(32); // Получаем 32-байтный хеш
            return $"{Convert.ToBase64String(salt)}:{Convert.ToBase64String(hash)}"; // Возвращаем хеш с солью
        }

        private bool VerifyPasswordWithArgon2(string password, string storedHash)
        {
            var parts = storedHash.Split(':');
            if (parts.Length != 2)
                return false;

            var salt = Convert.FromBase64String(parts[0]);
            var storedPasswordHash = Convert.FromBase64String(parts[1]);

            var argon2 = new Argon2id(Encoding.UTF8.GetBytes(password))
            {
                Salt = salt,
                DegreeOfParallelism = 8,
                Iterations = 4,
                MemorySize = 65536
            };

            var hash = argon2.GetBytes(32);

            // Сравниваем хеши
            return hash.SequenceEqual(storedPasswordHash);
        }

        private byte[] GenerateSalt()
        {
            var salt = new byte[16];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(salt);
            }
            return salt;
        }
}
]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Infrastructure/Persistence/ApplicationDbContext.cs: [using EaseMoney.Core.Entities;
using EaseMoney.Infrastructure.Persistence.Configurations;
using Microsoft.EntityFrameworkCore;

namespace EaseMoney.Infrastructure.Persistence;

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }

    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfiguration(new UserConfiguration());
    }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Infrastructure/Persistence/Configurations/UserConfiguration.cs: [using EaseMoney.Core.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace EaseMoney.Infrastructure.Persistence.Configurations;

public class UserConfiguration : IEntityTypeConfiguration<User>
{
    public void Configure(EntityTypeBuilder<User> builder)
    {
        builder.HasKey(u => u.Id);
        builder.Property(u => u.Username).IsRequired().HasMaxLength(100);
        builder.Property(u => u.PasswordHash).IsRequired();
    }
}]

/Users/sergeilogachev/RiderProjects/EaseMoney/EaseMoney/src/Infrastructure/Persistence/Repositories/UserRepository.cs: [using EaseMoney.Core.Entities;
using EaseMoney.Core.Ports;
using Microsoft.EntityFrameworkCore;

namespace EaseMoney.Infrastructure.Persistence.Repositories;

public class UserRepository : IUserRepository
{
    private readonly ApplicationDbContext _context;

    public UserRepository(ApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<User> GetUserByUsernameAsync(string username)
    {
        if (string.IsNullOrEmpty(username))
            throw new ArgumentNullException(nameof(username), "Username cannot be null or empty.");

        try
        {
            return await _context.Users.SingleOrDefaultAsync(u => u.Username == username);
        }
        catch (InvalidOperationException)
        {
            throw new InvalidOperationException("More than one user with the same username exists in the database.");
        }
    }

    public async Task AddUserAsync(User user)
    {
        if (user == null)
            throw new ArgumentNullException(nameof(user), "user can not be null");

        _context.Users.Add(user);
        await _context.SaveChangesAsync();
    }
}]

]