Audiofy – Musikwünsche für Partys
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>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user