1use std::collections::BTreeMap;
2
3use http::uri::Uri;
4use jwt_simple::prelude::*;
5use serde_json::Value;
6
7use crate::{error::WebPushError, vapid::VapidKey};
8
9#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
12pub struct VapidSignature {
13 pub auth_t: String,
15 pub auth_k: Vec<u8>,
17}
18
19pub type Claims = JWTClaims<BTreeMap<String , Value>>;
21
22pub struct VapidSigner {}
23
24impl VapidSigner {
25 pub fn sign(key: VapidKey, endpoint: &Uri, mut claims: Claims) -> Result<VapidSignature, WebPushError> {
29 if !claims.custom.contains_key("aud") {
30 let audience = format!("{}://{}", endpoint.scheme_str().unwrap(), endpoint.host().unwrap());
32 claims = claims.with_audience(audience);
33 } else {
34 let aud = claims.custom.get("aud").unwrap().clone();
36 claims = claims.with_audience(aud.as_str().ok_or(WebPushError::InvalidClaims)?);
38 claims.custom.remove("aud");
39 }
40
41 if claims.custom.contains_key("exp") {
44 let exp = claims.custom.get("exp").unwrap().clone();
45 claims.expires_at = Some(Duration::from_secs(exp.as_u64().ok_or(WebPushError::InvalidClaims)?));
46 claims.custom.remove("exp");
47 }
48
49 if !claims.custom.contains_key("sub") {
51 claims = claims.with_subject("mailto:example@example.com".to_string());
52 }
53
54 log::trace!("Using jwt: {:?}", claims);
55
56 let auth_k = key.public_key();
57
58 let auth_t = key.0.sign(claims).map_err(|_| WebPushError::InvalidClaims)?;
60
61 Ok(VapidSignature { auth_t, auth_k })
62 }
63}
64
65#[cfg(test)]
66mod tests {}