#!/usr/bin/env python3
"""JellyShip auth proxy for nginx auth_request.
Validates Jellyfin session via multiple methods:
1. X-Jellyfin-Token header
2. Authorization header (MediaBrowser Token="...")
3. jellyfin_token cookie (set by our login page)
4. Basic auth (username:password against Jellyfin API)
Checks IsAdministrator policy.
Listens on 127.0.0.1:9199.
"""
import http.server, urllib.request, urllib.parse, json, base64

JELLYFIN = "http://127.0.0.1:8096"

class AuthHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        # Try token from various sources
        token = self._get_token()
        if token:
            if self._check_admin(token):
                self.send_response(200)
                self.end_headers()
                return

        # Try Basic auth → authenticate against Jellyfin
        basic = self.headers.get("Authorization", "")
        if basic.startswith("Basic "):
            try:
                decoded = base64.b64decode(basic[6:]).decode()
                user, pw = decoded.split(":", 1)
                token = self._authenticate(user, pw)
                if token and self._check_admin(token):
                    self.send_response(200)
                    # Set cookie for subsequent requests
                    self.send_header("Set-Cookie", f"jellyfin_token={token}; Path=/; HttpOnly")
                    self.end_headers()
                    return
            except Exception:
                pass

        # No valid auth — return 401 to trigger browser Basic auth prompt
        self.send_response(401)
        self.send_header("WWW-Authenticate", 'Basic realm="JellyShip Admin"')
        self.end_headers()

    def _get_token(self):
        # Header
        token = self.headers.get("X-Jellyfin-Token", "")
        if token:
            return token
        # Authorization header
        auth = self.headers.get("Authorization", "")
        if "Token=" in auth:
            try:
                return auth.split('Token="')[1].split('"')[0]
            except Exception:
                pass
        # Cookie
        cookies = self.headers.get("Cookie", "")
        for c in cookies.split(";"):
            c = c.strip()
            if c.startswith("jellyfin_token="):
                return c.split("=", 1)[1]
        return ""

    def _authenticate(self, username, password):
        """Authenticate user against Jellyfin and return access token."""
        try:
            data = json.dumps({"Username": username, "Pw": password}).encode()
            req = urllib.request.Request(
                f"{JELLYFIN}/Users/AuthenticateByName",
                data=data,
                headers={
                    "Content-Type": "application/json",
                    "X-Emby-Authorization": 'MediaBrowser Client="JellyShip", Device="Auth", DeviceId="jellyship-auth", Version="1.0.0"'
                },
                method="POST"
            )
            resp = urllib.request.urlopen(req, timeout=5)
            result = json.loads(resp.read())
            return result.get("AccessToken", "")
        except Exception:
            return ""

    def _check_admin(self, token):
        """Check if token belongs to an admin user."""
        try:
            req = urllib.request.Request(
                f"{JELLYFIN}/Users/Me",
                headers={"X-MediaBrowser-Token": token}
            )
            resp = urllib.request.urlopen(req, timeout=5)
            user = json.loads(resp.read())
            return user.get("Policy", {}).get("IsAdministrator", False)
        except Exception:
            return False

    def log_message(self, fmt, *args):
        pass

http.server.HTTPServer(("127.0.0.1", 9199), AuthHandler).serve_forever()
