mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-21 12:49:06 +00:00
76 lines
2.0 KiB
Python
76 lines
2.0 KiB
Python
import hmac
|
|
import json
|
|
import re
|
|
import time
|
|
from datetime import datetime
|
|
from hashlib import sha256
|
|
|
|
from fastapi import APIRouter, HTTPException, Request
|
|
from pydantic import BaseModel
|
|
|
|
from reflector.db.meetings import meetings_controller
|
|
from reflector.settings import settings
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class WherebyWebhookEvent(BaseModel):
|
|
apiVersion: str
|
|
id: str
|
|
createdAt: datetime
|
|
type: str
|
|
data: dict
|
|
|
|
|
|
MAX_ELAPSED_TIME = 60 * 1000 # 1 minute in milliseconds
|
|
|
|
|
|
def is_webhook_event_valid(body: dict, signature: str) -> bool:
|
|
"""Validate Whereby webhook signature and timestamp."""
|
|
if not signature:
|
|
return False
|
|
|
|
matches = re.match(r"t=(.*),v1=(.*)", signature)
|
|
if not matches:
|
|
return False
|
|
|
|
timestamp, signature = matches.groups()
|
|
|
|
current_time = int(time.time() * 1000)
|
|
diff_time = current_time - int(timestamp) * 1000
|
|
if diff_time >= MAX_ELAPSED_TIME:
|
|
return False
|
|
|
|
signed_payload = f"{timestamp}.{json.dumps(body, separators=(',', ':'))}"
|
|
hmac_obj = hmac.new(
|
|
settings.WHEREBY_WEBHOOK_SECRET.encode("utf-8"),
|
|
signed_payload.encode("utf-8"),
|
|
sha256,
|
|
)
|
|
expected_signature = hmac_obj.hexdigest()
|
|
try:
|
|
return hmac.compare_digest(
|
|
expected_signature.encode("utf-8"), signature.encode("utf-8")
|
|
)
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
@router.post("/whereby")
|
|
async def whereby_webhook(event: WherebyWebhookEvent, request: Request):
|
|
if not is_webhook_event_valid(
|
|
await request.json(), request.headers["whereby-signature"]
|
|
):
|
|
raise HTTPException(status_code=401, detail="Invalid webhook signature")
|
|
|
|
meeting = await meetings_controller.get_by_id(event.data["meetingId"])
|
|
if not meeting:
|
|
raise HTTPException(status_code=404, detail="Meeting not found")
|
|
|
|
if event.type in ["room.client.joined", "room.client.left"]:
|
|
await meetings_controller.update_meeting(
|
|
meeting.id, num_clients=event.data["numClients"]
|
|
)
|
|
|
|
return {"status": "ok"}
|