import base64 from typing import Any from fansifter_common.adapters.db.base import Database from mypy_boto3_kms import KMSClient from twilio.request_validator import RequestValidator as TwilioRequestValidator from app.adapters.db.twilio.repositories import TwilioAccountRepository from app.exceptions import RequestValidationError class RequestValidator: def __init__( self, db: Database, accounts_repository: TwilioAccountRepository, kms_client: KMSClient, kms_key_id: str, ) -> None: self.db = db self.accounts_repository = accounts_repository self.kms_client = kms_client self.kms_key_id = kms_key_id self.validators: dict[str, TwilioRequestValidator] = {} def validate(self, url: str, request: dict[str, Any], signature: str) -> None: validator = self.get_validator(request.get("AccountSid")) validation_passed = validator.validate(url, request, signature) if not validation_passed: raise RequestValidationError("Request validation failed") def get_validator(self, account_sid: str | None) -> TwilioRequestValidator: if not account_sid: raise ValueError("AccountSid is required") if account_sid not in self.validators: auth_token = self.get_auth_token(account_sid) self.validators[account_sid] = TwilioRequestValidator(auth_token) return self.validators[account_sid] def get_auth_token(self, account_sid: str) -> str: with self.db.session_factory(): account = self.accounts_repository.get_by_account_sid(account_sid) if account: response = self.kms_client.decrypt( CiphertextBlob=base64.b64decode(account.auth_token), KeyId=self.kms_key_id, ) return response.get("Plaintext").decode("utf-8") raise ValueError("Account not found")