#!/usr/bin/env python3 """Freigabe des Marketing-Dashboards für Kollegen. Derselbe Server wie serve.py, aber für den Weg nach draußen über einen Cloudflare-Tunnel. Gestartet wird alles zusammen mit ./freigabe.sh. - jede Anfrage braucht das Passwort, der Name ist egal - nur lesen: kein Status setzen, kein Export, nichts öffnen - nichts, was mit einem Punkt beginnt, also weder .git noch .DS_Store - keine Ordnerlisten Das Passwort steht in .freigabe-passwort. Fehlt die Datei, wird beim ersten Start eins erzeugt. Zum Wechseln die Datei löschen und neu starten. Anleitung zum Starten, Prüfen und Beenden: .docs/Freigabe.md """ import base64 import hmac import secrets import sys import urllib.parse import serve PORT = 4330 PASSWORTDATEI = serve.HUB / ".freigabe-passwort" def passwort(): if PASSWORTDATEI.exists(): return PASSWORTDATEI.read_text(encoding="utf-8").strip() neu = secrets.token_urlsafe(12) PASSWORTDATEI.write_text(neu + "\n", encoding="utf-8") PASSWORTDATEI.chmod(0o600) return neu PASSWORT = passwort() class Handler(serve.Handler): def _erlaubt(self): kopf = self.headers.get("Authorization", "") if kopf.startswith("Basic "): try: _, _, pw = base64.b64decode(kopf[6:]).decode("utf-8").partition(":") except Exception: pw = "" if hmac.compare_digest(pw.encode("utf-8"), PASSWORT.encode("utf-8")): return True self.send_response(401) self.send_header("WWW-Authenticate", 'Basic realm="HiveGrid Marketing", charset="UTF-8"') self.send_header("Content-Length", "0") self.end_headers() return False def _versteckt(self): pfad = urllib.parse.unquote(urllib.parse.urlparse(self.path).path) if any(t.startswith(".") for t in pfad.split("/") if t): self.send_error(404) return True return False def do_GET(self): if self._erlaubt() and not self._versteckt(): super().do_GET() def do_HEAD(self): if self._erlaubt() and not self._versteckt(): super().do_HEAD() def do_POST(self): # Das Dashboard zeigt "fehler" unten als Meldung an. if self._erlaubt(): self._json(403, {"fehler": "In der Freigabe lässt sich nichts ändern."}) def list_directory(self, path): # Ordner ohne index.html. Eine Liste würde auch versteckte Dateien und # alles zeigen, was nicht für die Kollegen gedacht ist. self.send_error(404) return None if __name__ == "__main__": try: server = serve.Server(("127.0.0.1", PORT), Handler) except OSError: print("Port %d ist belegt. Läuft die Freigabe schon?" % PORT, flush=True) sys.exit(1) print("Freigabe läuft auf http://127.0.0.1:%d/" % PORT, flush=True) print("Passwort für die Kollegen: %s (Name egal)" % PASSWORT, flush=True) with server: try: server.serve_forever() except KeyboardInterrupt: pass