using System.Net; using System.Net.Http.Headers; using System.Text.Json; using System.Text.Json.Serialization; using Nebula.Shared.Models.Auth; using Nebula.Shared.Utils; namespace Nebula.Shared.Services; [ServiceRegister] public class AuthService( RestService restService, DebugService debugService, CancellationService cancellationService) { private readonly HttpClient _httpClient = new(); public CurrentAuthInfo? SelectedAuth { get; private set; } public async Task Auth(AuthLoginPassword authLoginPassword, string? code = null) { var authServer = authLoginPassword.AuthServer; var login = authLoginPassword.Login; var password = authLoginPassword.Password; debugService.Debug($"Auth to {authServer}api/auth/authenticate {login}"); var authUrl = new Uri($"{authServer}api/auth/authenticate"); try { var result = await restService.PostAsync( new AuthenticateRequest(login, null, password, code), authUrl, cancellationService.Token); SelectedAuth = new CurrentAuthInfo(result.UserId, new LoginToken(result.Token, result.ExpireTime), authLoginPassword.Login, authLoginPassword.AuthServer); } catch (RestRequestException e) { Console.WriteLine(e.Content); if (e.StatusCode != HttpStatusCode.Unauthorized) throw; var err = await e.Content.AsJson(); if (err is null) throw; throw new AuthException(err); } } public void ClearAuth() { SelectedAuth = null; } public async Task SetAuth(CurrentAuthInfo info) { SelectedAuth = info; return await EnsureToken(); } public async Task EnsureToken() { if (SelectedAuth is null) return false; var authUrl = new Uri($"{SelectedAuth.AuthServer}api/auth/ping"); using var requestMessage = new HttpRequestMessage(HttpMethod.Get, authUrl); requestMessage.Headers.Authorization = new AuthenticationHeaderValue("SS14Auth", SelectedAuth.Token.Token); using var resp = await _httpClient.SendAsync(requestMessage, cancellationService.Token); if (!resp.IsSuccessStatusCode) SelectedAuth = null; return resp.IsSuccessStatusCode; } } public sealed record CurrentAuthInfo(Guid UserId, LoginToken Token, string Login, string AuthServer); public record AuthLoginPassword(string Login, string Password, string AuthServer); public sealed record AuthDenyError(string[] Errors, AuthenticateDenyCode Code); public sealed class AuthException(AuthDenyError error) : Exception { public AuthDenyError Error { get; } = error; } [JsonConverter(typeof(JsonStringEnumConverter))] public enum AuthenticateDenyCode { None = 0, InvalidCredentials = 1, AccountUnconfirmed = 2, TfaRequired = 3, TfaInvalid = 4, AccountLocked = 5, }