Vanguard media stack: ingest, copyparty, Syncthing, normalize sweep, Authentik, Jellyfin + Vanguard Metadata plugin, MariaDB, Gitea, bot runtime
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user