using System.Security.Cryptography; using ErsatzTV.Core; namespace ErsatzTV.Application.Auth; internal static class LocalAdminHelpers { public const int MaxUsernameLength = 256; // Upper bound so an absurdly long password can't burn CPU in PBKDF2 (the request body is also capped // by Kestrel, #283; this is defense-in-depth on the field itself). public const int MaxPasswordLength = 1024; /// 128 bits of random, lowercase hex. Rotated on every password change to revoke sessions. public static string NewSecurityStamp() => Convert.ToHexString(RandomNumberGenerator.GetBytes(16)).ToLowerInvariant(); /// Validates a new username + password. Returns the error, or None if valid. public static Option ValidateNewCredentials(string username, string password) { string trimmed = (username ?? string.Empty).Trim(); if (trimmed.Length == 0) { return BaseError.New("Username is required"); } if (trimmed.Length > MaxUsernameLength) { return BaseError.New("Username is too long"); } return ValidatePassword(password); } public static Option ValidatePassword(string password) { if (string.IsNullOrEmpty(password) || password.Length < AuthConstants.MinPasswordLength) { return BaseError.New($"Password must be at least {AuthConstants.MinPasswordLength} characters"); } if (password.Length > MaxPasswordLength) { return BaseError.New($"Password must be at most {MaxPasswordLength} characters"); } return Option.None; } }