Files
NexaMFA/backend/app/services/push.py
T
nessi f925009977 chore: initial project setup with backend, frontend, Android app, and CI/CD
Add complete NexaMFA push MFA system with:
- FastAPI backend with PostgreSQL, Redis, OIDC provider, and Prometheus metrics
- React TypeScript admin console
- Android Kotlin/Jetpack Compose app with biometric authentication
- Docker Compose deployment configuration
- Gitea CI workflow for backend, frontend, and Android builds
- Environment configuration template with security settings
- Documentation for security model, deployment
2026-06-28 09:37:51 +02:00

45 lines
1.7 KiB
Python

import json
import logging
from google.oauth2 import service_account
from google.auth.transport.requests import Request as GoogleAuthRequest
import httpx
from app.core.config import Settings
logger = logging.getLogger(__name__)
class PushService:
def __init__(self, settings: Settings):
self.settings = settings
async def send_challenge(self, fcm_token: str | None, challenge_id: str) -> None:
if not fcm_token:
logger.info("Skipping push: device has no FCM token for challenge %s", challenge_id)
return
if not self.settings.fcm_project_id or not self.settings.fcm_service_account_json:
logger.info("Skipping push: FCM credentials not configured for challenge %s", challenge_id)
return
credentials = service_account.Credentials.from_service_account_info(
json.loads(self.settings.fcm_service_account_json),
scopes=["https://www.googleapis.com/auth/firebase.messaging"],
)
credentials.refresh(GoogleAuthRequest())
payload = {
"message": {
"token": fcm_token,
"data": {"challenge_id": challenge_id},
"android": {"priority": "high"},
}
}
logger.debug("Prepared FCM payload: %s", json.dumps(payload))
async with httpx.AsyncClient(timeout=10) as client:
response = await client.post(
f"https://fcm.googleapis.com/v1/projects/{self.settings.fcm_project_id}/messages:send",
json=payload,
headers={"Authorization": f"Bearer {credentials.token}"},
)
response.raise_for_status()