127 lines
5.4 KiB
Python
127 lines
5.4 KiB
Python
import urllib.request
|
|
import ssl
|
|
import json
|
|
import sys
|
|
|
|
sys.stdout.reconfigure(encoding='utf-8')
|
|
|
|
ctx = ssl.create_default_context()
|
|
ctx.check_hostname = False
|
|
ctx.verify_mode = ssl.CERT_NONE
|
|
|
|
token = "SnarfNetPermanentAutomationToken2026"
|
|
headers = {
|
|
"Authorization": f"Bearer {token}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
def api_call(url, method="GET", payload=None):
|
|
data = json.dumps(payload).encode('utf-8') if payload else None
|
|
req = urllib.request.Request(url, headers=headers, data=data, method=method)
|
|
try:
|
|
with urllib.request.urlopen(req, context=ctx, timeout=8) as resp:
|
|
return json.loads(resp.read().decode('utf-8'))
|
|
except urllib.error.HTTPError as e:
|
|
err = e.read().decode('utf-8')
|
|
print(f"API Error {e.code} on {method} {url}: {err}")
|
|
return None
|
|
|
|
print("1. Updating OAuth2 Provider 23 (Technitium)...")
|
|
p23_payload = {
|
|
"name": "Technitium DNS SSO",
|
|
"redirect_uris": [
|
|
{"url": "https://dns1.snarfnet.net/sso/callback", "matching_mode": "strict"},
|
|
{"url": "https://dns2.snarfnet.net/sso/callback", "matching_mode": "strict"},
|
|
{"url": "https://dns1.snarfnet.net/", "matching_mode": "strict"},
|
|
{"url": "https://dns2.snarfnet.net/", "matching_mode": "strict"},
|
|
{"url": "https://dns.*\\.snarfnet\\.net.*", "matching_mode": "regex"}
|
|
]
|
|
}
|
|
api_call("https://authentik.snarfnet.net/api/v3/providers/oauth2/23/", method="PATCH", payload=p23_payload)
|
|
print("Updated Provider 23 redirect URIs.")
|
|
|
|
print("\n2. Updating Applications in Authentik App Library...")
|
|
|
|
# Target applications definition:
|
|
apps_target = [
|
|
{
|
|
"name": "Pi-hole 1 (Aerodrome)",
|
|
"slug": "pihole1",
|
|
"provider": 24,
|
|
"group": "Networking & Edge",
|
|
"meta_launch_url": "https://pihole1.snarfnet.net",
|
|
"meta_description": "Network-wide Ad & Tracker Blocking (Aerodrome Primary)",
|
|
"meta_icon": "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/pi-hole.png",
|
|
"open_in_new_tab": True
|
|
},
|
|
{
|
|
"name": "Pi-hole 2 (Spaceport)",
|
|
"slug": "pihole2",
|
|
"provider": 12,
|
|
"group": "Networking & Edge",
|
|
"meta_launch_url": "https://pihole2.snarfnet.net",
|
|
"meta_description": "Network-wide Ad & Tracker Blocking (Spaceport Secondary)",
|
|
"meta_icon": "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/pi-hole.png",
|
|
"open_in_new_tab": True
|
|
},
|
|
{
|
|
"name": "Technitium DNS 1 (Aerodrome)",
|
|
"slug": "dns1",
|
|
"provider": 23,
|
|
"group": "Networking & Edge",
|
|
"meta_launch_url": "https://dns1.snarfnet.net",
|
|
"meta_description": "Authoritative & Recursive DNS Server with DoH & Local Resolution (Aerodrome Primary)",
|
|
"meta_icon": "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/technitium.png",
|
|
"open_in_new_tab": True
|
|
},
|
|
{
|
|
"name": "Technitium DNS 2 (Spaceport)",
|
|
"slug": "dns2",
|
|
"provider": 23,
|
|
"group": "Networking & Edge",
|
|
"meta_launch_url": "https://dns2.snarfnet.net",
|
|
"meta_description": "Authoritative & Recursive DNS Server with DoH & Local Resolution (Spaceport Secondary)",
|
|
"meta_icon": "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/technitium.png",
|
|
"open_in_new_tab": True
|
|
}
|
|
]
|
|
|
|
# Fetch current applications
|
|
current_apps = api_call("https://authentik.snarfnet.net/api/v3/core/applications/?page_size=100")
|
|
current_slugs = {a['slug']: a for a in current_apps.get('results', [])}
|
|
|
|
# Delete obsolete slugs if they exist (e.g., 'technitium' or old 'pihole' if we recreate as 'pihole2')
|
|
if 'technitium' in current_slugs and 'dns1' not in current_slugs:
|
|
print("Renaming app 'technitium' to 'dns1'...")
|
|
api_call("https://authentik.snarfnet.net/api/v3/core/applications/technitium/", method="PATCH", payload=apps_target[2])
|
|
elif 'technitium' in current_slugs:
|
|
print("Removing obsolete 'technitium' app...")
|
|
api_call("https://authentik.snarfnet.net/api/v3/core/applications/technitium/", method="DELETE")
|
|
|
|
if 'pihole' in current_slugs:
|
|
print("Renaming app 'pihole' to 'pihole2'...")
|
|
api_call("https://authentik.snarfnet.net/api/v3/core/applications/pihole/", method="PATCH", payload=apps_target[1])
|
|
|
|
# Refresh apps list
|
|
current_apps = api_call("https://authentik.snarfnet.net/api/v3/core/applications/?page_size=100")
|
|
current_slugs = {a['slug']: a for a in current_apps.get('results', [])}
|
|
|
|
for target in apps_target:
|
|
slug = target['slug']
|
|
if slug in current_slugs:
|
|
print(f"Updating app '{target['name']}' ({slug})...")
|
|
res = api_call(f"https://authentik.snarfnet.net/api/v3/core/applications/{slug}/", method="PATCH", payload=target)
|
|
if res: print(f" ✓ Updated {slug}")
|
|
else:
|
|
print(f"Creating app '{target['name']}' ({slug})...")
|
|
res = api_call("https://authentik.snarfnet.net/api/v3/core/applications/", method="POST", payload=target)
|
|
if res: print(f" ✓ Created {slug}")
|
|
|
|
print("\n3. Verifying final state in Authentik App Library...")
|
|
final_apps = api_call("https://authentik.snarfnet.net/api/v3/core/applications/?page_size=100")
|
|
for a in sorted(final_apps.get('results', []), key=lambda x: x['name']):
|
|
if a['slug'] in ['pihole1', 'pihole2', 'dns1', 'dns2', 'pihole', 'technitium']:
|
|
print(f" [{a['group']}] {a['name']}")
|
|
print(f" Slug: {a['slug']} | URL: {a['meta_launch_url']} | Provider PK: {a['provider']}")
|
|
|