Files
Media-Server-Setup/jellyfin-plugin-vanguard/Jellyfin.Plugin.Vanguard/Services/AuthentikClient.cs

51 lines
2.7 KiB
C#

using System.Net.Http.Headers;
using System.Text.Json;
using MediaBrowser.Common.Net;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Plugin.Vanguard.Services;
/// <summary>Resolves an Authentik username to the Discord user id stored on their OAuth source connection.</summary>
public sealed class AuthentikClient
{
private readonly IHttpClientFactory _http;
private readonly ILogger<AuthentikClient> _log;
public AuthentikClient(IHttpClientFactory http, ILogger<AuthentikClient> log) { _http = http; _log = log; }
public async Task<string?> GetDiscordIdForUsernameAsync(string baseUrl, string token, string username, CancellationToken ct)
{
if (string.IsNullOrWhiteSpace(baseUrl) || string.IsNullOrWhiteSpace(token)) return null;
var c = _http.CreateClient(NamedClient.Default);
c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var b = baseUrl.TrimEnd('/');
try
{
using var u = await c.GetAsync($"{b}/api/v3/core/users/?username={Uri.EscapeDataString(username)}", ct).ConfigureAwait(false);
if (!u.IsSuccessStatusCode) { _log.LogWarning("Authentik users lookup {User}: {Status}", username, u.StatusCode); return null; }
using var ud = JsonDocument.Parse(await u.Content.ReadAsStringAsync(ct).ConfigureAwait(false));
var results = ud.RootElement.GetProperty("results");
if (results.GetArrayLength() == 0) return null;
var pk = results[0].GetProperty("pk").GetInt32();
using var cres = await c.GetAsync($"{b}/api/v3/sources/user_connections/oauth/?user={pk}", ct).ConfigureAwait(false);
if (!cres.IsSuccessStatusCode) { _log.LogWarning("Authentik connections lookup {User}: {Status}", username, cres.StatusCode); return null; }
using var cd = JsonDocument.Parse(await cres.Content.ReadAsStringAsync(ct).ConfigureAwait(false));
foreach (var conn in cd.RootElement.GetProperty("results").EnumerateArray())
{
var slug = conn.TryGetProperty("source", out var src) && src.ValueKind == JsonValueKind.Object && src.TryGetProperty("slug", out var sl) ? sl.GetString() : null;
var ident = conn.TryGetProperty("identifier", out var idp) ? idp.GetString() : null;
if (!string.IsNullOrEmpty(ident) && (slug is null || slug.Contains("discord", StringComparison.OrdinalIgnoreCase)))
{
return ident;
}
}
}
catch (Exception ex) when (ex is HttpRequestException or JsonException or TaskCanceledException)
{
_log.LogWarning(ex, "Authentik lookup failed for {User}", username);
}
return null;
}
}