< Summary

Information
Class: Api.Auth.Endpoints.LoginEndpoints.LoginDTO
Assembly: Api
File(s): /home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Auth/Endpoints/LoginEndpoints.cs
Line coverage
100%
Covered lines: 1
Uncovered lines: 0
Coverable lines: 1
Total lines: 68
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%

File(s)

/home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Auth/Endpoints/LoginEndpoints.cs

#LineLine coverage
 1// SPDX-FileCopyrightText: 2026 Alper Çelik <alper@alper-celik.dev>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5using System.Text;
 6
 7using Api.Auth.Utils;
 8using Api.Database;
 9
 10using FluentValidation;
 11
 12using Geralt;
 13
 14using Microsoft.AspNetCore.Authorization;
 15using Microsoft.AspNetCore.Http.HttpResults;
 16using Microsoft.AspNetCore.Mvc;
 17using Microsoft.EntityFrameworkCore;
 18
 19namespace Api.Auth.Endpoints;
 20
 21public static class LoginEndpoints
 22{
 23    public static void Map(IEndpointRouteBuilder route)
 24    {
 25        route.MapPost("login", Login);
 26    }
 27
 28    [AllowAnonymous]
 29    public static async Task<
 30    Results<
 31        Ok<LoginUtils.LoginResultDTO>,
 32        ForbidHttpResult
 33    >> Login(
 34            HttpContext ctx,
 35            [FromServices] PGContext db,
 36            [FromHeader(Name = "user-agent")] string? userAgent,
 37            [FromBody] LoginDTO loginDTO
 38            )
 39    {
 40        userAgent ??= "unknown";
 41        Guid? userId = null;
 42        string hash = string.Empty;
 43
 44        if (loginDTO.UserEmail is not null)
 45        {
 46            var user = await db.Users
 47                .Where(u => u.Email == loginDTO.UserEmail)
 48                .Select(u => new { u.Id, u.PasswordHash })
 49                .FirstAsync();
 50            userId = user.Id;
 51            hash = user.PasswordHash;
 52        }
 53
 54        var password = Encoding.UTF8.GetBytes(loginDTO.Password.Normalize());
 55        if (userId is not null &&
 56                Argon2id.VerifyHash(hash, password))
 57        {
 58            var token = await LoginUtils.CreateUserSession(userId.Value, userAgent, db);
 59            await db.SaveChangesAsync();
 60
 61            return LoginUtils.LogUserIn(ctx, token);
 62        }
 63        return TypedResults.Forbid();
 64    }
 65
 66
 167    public record LoginDTO(string UserEmail, string Password);
 68}

Methods/Properties

.ctor(string, string)