token.rs

 1use anyhow::{anyhow, Result};
 2use hmac::{Hmac, Mac};
 3use jwt::SignWithKey;
 4use serde::Serialize;
 5use sha2::Sha256;
 6use std::{
 7    ops::Add,
 8    time::{Duration, SystemTime, UNIX_EPOCH},
 9};
10
11static DEFAULT_TTL: Duration = Duration::from_secs(6 * 60 * 60); // 6 hours
12
13#[derive(Default, Serialize)]
14#[serde(rename_all = "camelCase")]
15struct ClaimGrants<'a> {
16    iss: &'a str,
17    sub: Option<&'a str>,
18    iat: u64,
19    exp: u64,
20    nbf: u64,
21    jwtid: Option<&'a str>,
22    video: VideoGrant<'a>,
23}
24
25#[derive(Default, Serialize)]
26#[serde(rename_all = "camelCase")]
27pub struct VideoGrant<'a> {
28    pub room_create: Option<bool>,
29    pub room_join: Option<bool>,
30    pub room_list: Option<bool>,
31    pub room_record: Option<bool>,
32    pub room_admin: Option<bool>,
33    pub room: Option<&'a str>,
34    pub can_publish: Option<bool>,
35    pub can_subscribe: Option<bool>,
36    pub can_publish_data: Option<bool>,
37    pub hidden: Option<bool>,
38    pub recorder: Option<bool>,
39}
40
41impl<'a> VideoGrant<'a> {
42    pub fn to_join(room: &'a str) -> Self {
43        Self {
44            room: Some(room),
45            room_join: Some(true),
46            can_publish: Some(true),
47            can_subscribe: Some(true),
48            ..Default::default()
49        }
50    }
51}
52
53pub fn create(
54    api_key: &str,
55    secret_key: &str,
56    identity: Option<&str>,
57    video_grant: VideoGrant,
58) -> Result<String> {
59    if video_grant.room_join.is_some() && identity.is_none() {
60        Err(anyhow!(
61            "identity is required for room_join grant, but it is none"
62        ))?;
63    }
64
65    let secret_key: Hmac<Sha256> = Hmac::new_from_slice(secret_key.as_bytes())?;
66
67    let now = SystemTime::now();
68
69    let claims = ClaimGrants {
70        iss: api_key,
71        sub: identity,
72        iat: now.duration_since(UNIX_EPOCH).unwrap().as_secs(),
73        exp: now
74            .add(DEFAULT_TTL)
75            .duration_since(UNIX_EPOCH)
76            .unwrap()
77            .as_secs(),
78        nbf: 0,
79        jwtid: identity,
80        video: video_grant,
81    };
82    Ok(claims.sign_with_key(&secret_key)?)
83}