1use base64::Engine;
16use livekit_protocol as proto;
17use sha2::{Digest, Sha256};
18use thiserror::Error;
19
20use crate::access_token::{AccessTokenError, TokenVerifier};
21
22#[derive(Debug, Error)]
23pub enum WebhookError {
24 #[error("invalid signature")]
25 InvalidSignature,
26 #[error("invalid base64")]
27 InvalidBase64(#[from] base64::DecodeError),
28 #[error("failed to verify the authorization: {0}")]
29 InvalidAuth(#[from] AccessTokenError),
30 #[error("invalid body, failed to decode: {0}")]
31 InvalidData(#[from] serde_json::Error),
32}
33
34#[derive(Clone, Debug)]
35pub struct WebhookReceiver {
36 token_verifier: TokenVerifier,
37}
38
39impl WebhookReceiver {
40 pub fn new(token_verifier: TokenVerifier) -> Self {
41 Self { token_verifier }
42 }
43
44 pub fn receive(
45 &self,
46 body: &str,
47 auth_token: &str,
48 ) -> Result<proto::WebhookEvent, WebhookError> {
49 let claims = self.token_verifier.verify(auth_token)?;
50
51 let mut hasher = Sha256::new();
52 hasher.update(body);
53 let hash = hasher.finalize();
54
55 let claim_hash = base64::engine::general_purpose::STANDARD.decode(claims.sha256)?;
56 if claim_hash[..] != hash[..] {
57 return Err(WebhookError::InvalidSignature);
58 }
59
60 Ok(serde_json::from_str(body)?)
61 }
62}