receipter-pro / backend /firebase_app.py
M8ion deploy
Deploy backend
45dc2a1
Raw History Blame Contribute Delete
2.56 kB
"""
Single shared firebase_admin App instance. backend/firestore_client.py (real Firestore
branch) and backend/auth.py (real token verification) both use this instead of each
initializing their own — firebase_admin.initialize_app() raises if called twice for the
same app name, so this is a real requirement, not just tidiness.
Only imported/called when LOCAL_MODE=false or REAL_AUTH_ENABLED=true — never during the
test suite (backend/tests/conftest.py forces both off), so tests never need real credentials.
"""
from __future__ import annotations
import json
import os
import re
import firebase_admin
from firebase_admin import credentials
_app: firebase_admin.App | None = None
_PEM_HEAD = "-----BEGIN PRIVATE KEY-----"
_PEM_TAIL = "-----END PRIVATE KEY-----"
_PEM = re.compile(r"-----BEGIN\s*PRIVATE\s*KEY-----(.*?)-----END\s*PRIVATE\s*KEY-----", re.S)
def service_account_info(raw: str) -> dict:
"""
Reads the key from the text of FIREBASE_SERVICE_ACCOUNT_JSON. Pasting a key into a host's
secret box often damages the line breaks inside "private_key" (they become the two characters
\\n, or spaces), and the key then cannot be read at all. Repair that here instead of failing.
"""
text = raw.strip()
if len(text) > 1 and text[0] == text[-1] and text[0] in "'\"":
text = text[1:-1]
info = json.loads(text, strict=False)
key = str(info.get("private_key", "")).replace("\\n", "\n")
# Rebuild the key from its body. The header may have lost its spaces too
# ("-----BEGINPRIVATEKEY-----") when every space was stripped from the pasted text.
found = _PEM.search(key)
if found:
body = "".join(found.group(1).split())
lines = [body[i:i + 64] for i in range(0, len(body), 64)]
key = "\n".join([_PEM_HEAD, *lines, _PEM_TAIL]) + "\n"
info["private_key"] = key
return info
def get_app() -> firebase_admin.App:
global _app
if _app is None:
# A host that only offers environment variables (the Hugging Face Space) passes the key's
# content in FIREBASE_SERVICE_ACCOUNT_JSON; a developer's machine points at the file.
key_json = os.getenv("FIREBASE_SERVICE_ACCOUNT_JSON", "").strip()
if key_json:
cred = credentials.Certificate(service_account_info(key_json))
else:
cred = credentials.Certificate(
os.getenv("GOOGLE_APPLICATION_CREDENTIALS", "./secrets/firebase-service-account.dev.json")
)
_app = firebase_admin.initialize_app(cred)
return _app