102 lines
3.9 KiB
C#
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));
|
|
}
|
|
}
|