import os import json from typing import Optional try: import firebase_admin from firebase_admin import credentials, auth # App Check verification is available in newer firebase_admin versions try: from firebase_admin import app_check except ImportError: app_check = None except ImportError: firebase_admin = None credentials = None auth = None app_check = None _initialized = False def initialize_firebase() -> bool: """Initialize Firebase Admin SDK from env. Supports two ways to provide credentials: 1. FIREBASE_CREDENTIALS_JSON: Full JSON content as string 2. FIREBASE_CREDENTIALS: Path to service account JSON file Optional: FIREBASE_PROJECT_ID to override project ID """ global _initialized if _initialized: return True if firebase_admin is None or credentials is None: return False # Skip if already has a default app if firebase_admin._apps: _initialized = True return True # Try JSON content first (for Hugging Face secrets) cred_json = os.getenv("FIREBASE_CREDENTIALS_JSON") if cred_json: try: cred_dict = json.loads(cred_json) cred = credentials.Certificate(cred_dict) firebase_admin.initialize_app(cred, { "projectId": os.getenv("FIREBASE_PROJECT_ID") or cred_dict.get("project_id") }) _initialized = True return True except Exception as e: print(f"Warning: Failed to initialize Firebase from JSON: {e}") # Fallback to file path cred_path = os.getenv("FIREBASE_CREDENTIALS") if cred_path and os.path.exists(cred_path): try: cred = credentials.Certificate(cred_path) firebase_admin.initialize_app(cred, { "projectId": os.getenv("FIREBASE_PROJECT_ID") }) _initialized = True return True except Exception as e: print(f"Warning: Failed to initialize Firebase from file: {e}") return False def verify_app_check_token(token: Optional[str]) -> bool: """Verify Firebase App Check token. Returns True if verification succeeds. If App Check is not available or not initialized, returns False to indicate verification not possible. """ if not token: return False # If App Check module is not available, skip verification if app_check is None: print("Warning: Firebase App Check module not available") return False if not initialize_firebase(): print("Warning: Firebase not initialized, skipping App Check verification") return False try: # Verify the App Check token # Note: verify_token() returns decoded token claims if valid, raises exception if invalid decoded_token = app_check.verify_token(token) return decoded_token is not None except Exception as e: print(f"Warning: App Check token verification failed: {e}") return False def verify_firebase_id_token(id_token: Optional[str]) -> Optional[dict]: """Verify Firebase ID token and return decoded claims. Returns: dict: Decoded token claims (user info) if valid, None if invalid/not available """ if not id_token: return None if auth is None: return None if not initialize_firebase(): return None try: # Verify the ID token decoded_token = auth.verify_id_token(id_token) return decoded_token except Exception as e: print(f"Warning: Firebase ID token verification failed: {e}") return None