fundamentum_sdk_mqtt/security/
mod.rs1use chrono::{Duration, Utc};
5use derive_builder::Builder;
6use jsonwebtoken::{EncodingKey, Header, encode};
7
8pub use jsonwebtoken::Algorithm;
9
10use crate::error;
11
12mod claims;
13use claims::Claims;
14
15mod fetcher;
16pub use fetcher::SecurityFetcher;
17pub use fetcher::SecurityFileFetcher;
18
19#[derive(Builder)]
21#[builder(pattern = "owned")]
22pub struct Security {
23 project_id: u64,
25 #[builder(setter(strip_option))]
27 fetcher: Option<Box<dyn SecurityFetcher + Send + Sync>>,
28 #[builder(default = "Duration::days(365)")]
30 expiration: Duration,
31 #[builder(default = "Algorithm::RS256")]
33 algorithm: Algorithm,
34}
35
36impl Default for Security {
37 fn default() -> Self {
38 Self {
39 project_id: Default::default(),
40 fetcher: Option::default(),
41 expiration: Duration::days(365),
42 algorithm: Algorithm::RS256,
43 }
44 }
45}
46
47impl Security {
48 pub async fn generate_token(&self) -> Result<Token, error::Error> {
59 #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
60 let iat = Utc::now().timestamp() as usize;
61
62 #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
63 let exp = (Utc::now() + self.expiration).timestamp() as usize;
64
65 let claims = Claims {
66 aud: Some(self.project_id.to_string()), iat: Some(iat), exp: Some(exp),
69 ..Default::default()
70 };
71
72 let header: Header = Header::new(self.algorithm);
73 let private_key = self
74 .fetcher
75 .as_ref()
76 .expect("must provide a fetcher")
77 .read_private_key()
78 .await?;
79 let encoding_key = EncodingKey::from_rsa_pem(&private_key)?;
80
81 let token = encode(&header, &claims, &encoding_key)?;
82 Ok(token)
83 }
84}
85
86pub type Token = String;