Files
vtuber-awards/Backend/Endpoints/AuthDevelopmentLoginEndpoints.cs
T

102 lines
3.9 KiB
C#

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));
}
}