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:
2026-10-30 15:43:30 -05:00
commit c602a6ff52
66 changed files with 4229 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
# Authentik expression policy: allow Discord logins only for members of one Discord server (guild).
# Paste into: Customization -> Policies -> Create -> Expression Policy (name: discord-guild-member)
# Bind to BOTH flows: default-source-enrollment and default-source-authentication
# (Flows & Stages -> Flows -> <flow> -> Policy / Group / User Bindings -> Bind existing policy)
# Requires the "guilds" scope on the Discord source (source -> Protocol settings -> Scopes: guilds).
#
# Server ID: Discord -> User Settings -> Advanced -> Developer Mode on; right-click the server -> Copy Server ID.
ACCEPTED_GUILD_ID = "1387203044084551690" # <- your Discord server ID
GUILD_NAME = "Vanguard" # <- shown in the denial message
GUILD_API_URL = "https://discord.com/api/users/@me/guilds"
# Only act on logins that came through the Discord source; let everything else (akadmin password login) pass.
source = context.get("source")
if not source or getattr(source, "provider_type", "") != "discord":
return True
connection = context.get("goauthentik.io/sources/connection")
if not connection:
ak_message("No Discord connection in context.")
return False
resp = requests.get(GUILD_API_URL, headers={"Authorization": f"Bearer {connection.access_token}"}, timeout=10)
if resp.status_code != 200:
ak_message(f"Could not read Discord server list ({resp.status_code}). Try again.")
return False
is_member = any(g.get("id") == ACCEPTED_GUILD_ID for g in resp.json())
if not is_member:
ak_message(f"You must be a member of the {GUILD_NAME} Discord server to log in.")
return is_member