"""Verify caller identity for /api/pipeline/* — Bearer JWTs and/or pipeline client headers.""" from __future__ import annotations from typing import Optional, Tuple import jwt from flask import request from ..config import Config from .mirofish_jwt import verify_mirofish_session_jwt def verify_supabase_user_jwt(token: str) -> Tuple[Optional[str], Optional[str]]: """ Returns (user_id, error_message). user_id is None on failure. """ if not token or not Config.SUPABASE_JWT_SECRET: return None, "JWT verification not configured" try: payload = jwt.decode( token, Config.SUPABASE_JWT_SECRET, algorithms=["HS256"], audience="authenticated", options={"verify_exp": True}, ) sub = payload.get("sub") if not sub: return None, "Invalid token: missing sub" return str(sub), None except jwt.ExpiredSignatureError: return None, "Token expired" except jwt.InvalidTokenError as e: return None, f"Invalid token: {e}" def extract_bearer_token() -> Optional[str]: h = request.headers.get("Authorization", "") if h.lower().startswith("bearer "): return h[7:].strip() return None def resolve_pipeline_user_id() -> Tuple[Optional[str], Optional[str]]: """ When Supabase sync is on: 1) Authorization: Bearer (optional / legacy). 2) Authorization: Bearer if SUPABASE_JWT_SECRET is set. 3) X-Mirofish-User-Id + X-Pipeline-Client-Secret matching PIPELINE_CLIENT_SECRET (Supabase public.User in browser + VITE_PIPELINE_CLIENT_SECRET). Returns (user_id_str, error_message). """ token = extract_bearer_token() if token: m_uid, m_hint = verify_mirofish_session_jwt(token) if m_uid: return m_uid, None if m_hint == "expired": return None, "Token expired" if Config.SUPABASE_JWT_SECRET: s_uid, s_err = verify_supabase_user_jwt(token) if s_uid: return s_uid, None return None, s_err or "Invalid token" return None, "Invalid token" uid = (request.headers.get("X-Mirofish-User-Id") or "").strip() key = (request.headers.get("X-Pipeline-Client-Secret") or "").strip() secret = (Config.PIPELINE_CLIENT_SECRET or "").strip() if uid and secret and key == secret: return uid, None if uid or key: return None, "Invalid pipeline client credentials" if not secret: return None, "Server PIPELINE_CLIENT_SECRET is not configured" return None, "Missing credentials"