Refactor app architecture and clean local artifacts

This commit is contained in:
AzuTear
2026-06-24 23:43:14 +02:00
parent 17134b3b82
commit fef1d36fe8
274 changed files with 37724 additions and 6065 deletions
@@ -0,0 +1,101 @@
using Backend.Common;
using Backend.Contracts;
using Backend.Data;
using Backend.Security;
using Backend.Services;
namespace Backend.Endpoints;
public static partial class AuthEndpoints
{
private const int MaxTwitchUserIdLength = 64;
private const int MaxDisplayNameLength = 80;
private static async Task<IResult> DevLogin(
HttpContext context,
IHostEnvironment environment,
LoginRequest request,
AwardsDbContext db,
IUserSessionService userSessionService,
IRiskFlagService riskFlagService,
IRiskRuleService riskRuleService)
{
if (!environment.IsDevelopment())
{
return Results.NotFound();
}
var normalizedTwitchUserId = request.TwitchUserId?.Trim() ?? string.Empty;
var normalizedDisplayName = request.DisplayName?.Trim() ?? string.Empty;
var normalizedRole = AdminRoles.Normalize(request.Role);
if (string.IsNullOrWhiteSpace(normalizedTwitchUserId) || normalizedTwitchUserId.Length > MaxTwitchUserIdLength)
{
return Results.BadRequest(new { message = $"Twitch user id is required and must stay below {MaxTwitchUserIdLength} characters." });
}
if (!normalizedTwitchUserId.All(value => char.IsLetterOrDigit(value) || value is '_' or '-'))
{
return Results.BadRequest(new { message = "Twitch user id contains unsupported characters." });
}
if (string.IsNullOrWhiteSpace(normalizedDisplayName) || normalizedDisplayName.Length > MaxDisplayNameLength)
{
return Results.BadRequest(new { message = $"Display name is required and must stay below {MaxDisplayNameLength} characters." });
}
if (!AdminRoles.IsKnownRole(request.Role))
{
return Results.BadRequest(new { message = "Role must be viewer, content_admin, admin or owner." });
}
var requestMetadata = RequestMetadataReader.Read(context);
var session = await userSessionService.CreateDevSessionAsync(
request with
{
TwitchUserId = normalizedTwitchUserId,
DisplayName = normalizedDisplayName,
Role = normalizedRole,
},
requestMetadata,
context.RequestAborted);
var rapidLoginRule = await riskRuleService.GetRuleAsync("rapid_login_ip", context.RequestAborted);
var recentSessionsFromIp = await userSessionService.CountRecentSessionsFromIpAsync(
requestMetadata.ClientIp,
DateTimeOffset.UtcNow.AddMinutes(-rapidLoginRule.WindowMinutes),
context.RequestAborted);
if (rapidLoginRule.Enabled && recentSessionsFromIp >= rapidLoginRule.Threshold)
{
await riskFlagService.AddIfMissingAsync(
null,
session.TwitchUserId,
"login",
"rapid_login_ip",
rapidLoginRule.Severity,
"Mehrere neue Sessions wurden in kurzer Zeit von derselben IP erzeugt.",
requestMetadata,
new
{
recentSessionsFromIp,
threshold = rapidLoginRule.Threshold,
windowMinutes = rapidLoginRule.WindowMinutes,
entityLinks = new[]
{
new
{
label = "Audit-Log öffnen",
entityType = "session",
entityId = session.TwitchUserId,
to = $"/admin/users-logs?query={Uri.EscapeDataString(session.TwitchUserId)}",
},
},
},
context.RequestAborted);
await db.SaveChangesAsync(context.RequestAborted);
}
return Results.Ok(ToAuthSessionDto(session));
}
}