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
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user