Server (Website, Admin-Bereich, Player-API) und Player (raspotify + Controller) mit Install-Skripten für Debian-Systeme. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
72 lines
2.8 KiB
Python
72 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
||
"""Audiofy-Web – Verwaltung auf der Kommandozeile.
|
||
|
||
geheimnisse SESSION_SECRET und PLAYER_API_TOKEN erzeugen (nur falls noch nicht vorhanden)
|
||
passwort Admin-Passwort setzen (verdeckte Eingabe, gespeichert wird nur der argon2-Hash)
|
||
turnstile Cloudflare-Turnstile-Schlüssel setzen (Secret-Key verdeckt)
|
||
|
||
Auf dem Server als Dienst-Benutzer ausführen, damit die .env ihm gehört:
|
||
sudo -u audiofy /opt/audiofy/.venv/bin/python /opt/audiofy/app/verwaltung.py passwort
|
||
"""
|
||
|
||
import argparse
|
||
import getpass
|
||
import os
|
||
import secrets
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
from argon2 import PasswordHasher
|
||
|
||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||
from app.config import env_lesen, env_wert_setzen # noqa: E402
|
||
|
||
MIN_LAENGE = 12
|
||
|
||
|
||
def geheimnisse(env: Path) -> None:
|
||
werte = env_lesen(env) if env.is_file() else {}
|
||
if werte.get("PI_API_TOKEN") and not werte.get("PLAYER_API_TOKEN"):
|
||
# alten Namen übernehmen, damit ein bereits eingerichteter Player weiterläuft
|
||
env_wert_setzen(env, "PLAYER_API_TOKEN", werte["PI_API_TOKEN"])
|
||
werte["PLAYER_API_TOKEN"] = werte["PI_API_TOKEN"]
|
||
print("PLAYER_API_TOKEN: aus PI_API_TOKEN übernommen")
|
||
for key in ("SESSION_SECRET", "PLAYER_API_TOKEN"):
|
||
if werte.get(key):
|
||
print(f"{key}: schon vorhanden – unverändert")
|
||
else:
|
||
env_wert_setzen(env, key, secrets.token_urlsafe(48))
|
||
print(f"{key}: neu erzeugt")
|
||
|
||
|
||
def passwort(env: Path) -> None:
|
||
erstes = getpass.getpass("Neues Admin-Passwort: ")
|
||
if len(erstes) < MIN_LAENGE:
|
||
sys.exit(f"Zu kurz – mindestens {MIN_LAENGE} Zeichen.")
|
||
if getpass.getpass("Wiederholen: ") != erstes:
|
||
sys.exit("Die Eingaben stimmen nicht überein.")
|
||
env_wert_setzen(env, "ADMIN_PASSWORD_HASH", PasswordHasher().hash(erstes))
|
||
print(f"Passwort-Hash in {env} gespeichert. Bitte den Dienst neu starten (audiofy-web.service).")
|
||
|
||
|
||
def turnstile(env: Path) -> None:
|
||
site_key = input("Turnstile Site-Key (öffentlich): ").strip()
|
||
secret = getpass.getpass("Turnstile Secret-Key (verdeckt): ").strip()
|
||
if not site_key or not secret:
|
||
sys.exit("Beide Schlüssel sind nötig.")
|
||
env_wert_setzen(env, "TURNSTILE_SITE_KEY", site_key)
|
||
env_wert_setzen(env, "TURNSTILE_SECRET_KEY", secret)
|
||
print(f"Turnstile-Schlüssel in {env} gespeichert. Bitte den Dienst neu starten (audiofy-web.service).")
|
||
|
||
|
||
def main() -> None:
|
||
parser = argparse.ArgumentParser(description="Audiofy-Web – Verwaltung")
|
||
parser.add_argument("aktion", choices=("geheimnisse", "passwort", "turnstile"))
|
||
parser.add_argument("--env", type=Path, default=Path(os.environ.get("AUDIOFY_ENV", "/opt/audiofy/.env")))
|
||
args = parser.parse_args()
|
||
{"geheimnisse": geheimnisse, "passwort": passwort, "turnstile": turnstile}[args.aktion](args.env)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|