autopush_common/
endpoint.rs

1use crate::errors::{ApcErrorKind, Result};
2use crate::util::b64_decode_url;
3
4use fernet::MultiFernet;
5use openssl::hash;
6use url::Url;
7use uuid::Uuid;
8
9/// Create an v1 or v2 WebPush endpoint from the identifiers
10///
11/// Both endpoints use bytes instead of hex to reduce ID length.
12//  v1 is the uaid + chid
13//  v2 is the uaid + chid + sha256(key).bytes
14pub fn make_endpoint(
15    uaid: &Uuid,
16    chid: &Uuid,
17    key: Option<&str>,
18    endpoint_url: &str,
19    fernet: &MultiFernet,
20) -> Result<String> {
21    let root = Url::parse(endpoint_url)?.join("wpush/")?;
22    let mut base = uaid.as_bytes().to_vec();
23    base.extend(chid.as_bytes());
24
25    if let Some(k) = key {
26        let raw_key = b64_decode_url(k).map_err(|e| {
27            warn!("Payload: error decoding user provided VAPID key:{:?}", e);
28            ApcErrorKind::PayloadError("Error decoding VAPID key".to_owned())
29        })?;
30        let key_digest = hash::hash(hash::MessageDigest::sha256(), &raw_key).map_err(|e| {
31            warn!("Payload: Error creating digest for VAPID key: {:?}", e);
32            ApcErrorKind::PayloadError("Error creating message digest for key".to_owned())
33        })?;
34        base.extend(key_digest.iter());
35        let encrypted = fernet.encrypt(&base).trim_matches('=').to_string();
36        let final_url = root.join(&format!("v2/{encrypted}")).map_err(|e| {
37            ApcErrorKind::GeneralError(format!("Encrypted endpoint data is not URL-safe {e:?}"))
38        })?;
39        Ok(final_url.to_string())
40    } else {
41        let encrypted = fernet.encrypt(&base).trim_matches('=').to_string();
42        let final_url = root.join(&format!("v1/{encrypted}")).map_err(|e| {
43            ApcErrorKind::GeneralError(format!("Encrypted endpoint data is not URL-safe {e:?}"))
44        })?;
45        Ok(final_url.to_string())
46    }
47}