livekit_api/
webhooks.rs

1// Copyright 2023 LiveKit, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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}