1#[cfg(feature = "server")]
5pub mod builder;
6
7#[cfg(feature = "server")]
8use horfimbor_eventsource::model_key::ModelKey;
9
10#[cfg(feature = "server")]
11use jsonwebtoken::{DecodingKey, Validation, decode};
12
13use serde::{Deserialize, Serialize};
14use thiserror::Error;
15
16#[cfg(feature = "client")]
17use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
18#[cfg(feature = "client")]
19use jsonwebtoken::decode_header;
20#[cfg(not(feature = "server"))]
21use uuid::Uuid;
22
23#[cfg(not(feature = "server"))]
25#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq, Default, Hash)]
26pub struct ModelKey {
27 stream_name: String,
28 stream_id: Uuid,
29}
30
31#[derive(Debug, Serialize, Deserialize)]
32pub struct Claims {
33 #[serde(rename = "aud")]
34 audience: String,
35 #[serde(rename = "exp")]
36 expiration_at: u64,
37 #[serde(rename = "iat")]
38 issued_at: u64,
39 #[serde(rename = "iss")]
40 issuer: String,
41 #[serde(rename = "usr")]
42 user: ModelKey,
43 #[serde(rename = "acc")]
44 account: ModelKey,
45 #[serde(rename = "an")]
46 account_name: String,
47 #[serde(rename = "r")]
48 roles: Role,
49}
50
51#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
52pub enum Role {
53 #[serde(rename = "a")]
54 Admin,
55 #[serde(rename = "u")]
56 User,
57 #[serde(rename = "an")]
58 Anonymous,
59}
60
61#[derive(Error, Debug)]
62pub enum ClaimError {
63 #[error("jsonwebtoken")]
64 JWT(#[from] jsonwebtoken::errors::Error),
65
66 #[error("cannot get data `{0}`")]
67 Other(String),
68
69 #[error("no account when building claims")]
70 EmptyAccount,
71}
72
73impl Claims {
74 #[cfg(feature = "server")]
75 pub fn from_jwt(
81 token: &str,
82 secret: &str,
83 audience: &str,
84 issuer: &str,
85 ) -> Result<Self, ClaimError> {
86 let mut val = Validation::default();
87 val.set_audience(&[&audience]);
88 val.set_issuer(&[&issuer]);
89 val.set_required_spec_claims(&["exp", "iss", "aud"]);
90
91 let value = decode::<Self>(token, &DecodingKey::from_secret(secret.as_ref()), &val)
92 .map_err(ClaimError::JWT)?;
93
94 Ok(value.claims)
95 }
96
97 #[cfg(feature = "client")]
98 pub fn from_jwt_insecure(token: &str) -> Result<Self, ClaimError> {
104 match decode_header(token) {
105 Ok(_) => {
106 let mut parts = token.split('.');
107 parts.next();
108 let Some(content) = parts.next() else {
109 return Err(ClaimError::EmptyAccount);
110 };
111 let data = URL_SAFE_NO_PAD
112 .decode(content)
113 .map_err(|e| ClaimError::Other(e.to_string()))?;
114
115 Ok(serde_json::from_slice(&data).map_err(|e| ClaimError::Other(e.to_string()))?)
116 }
117 Err(e) => Err(ClaimError::JWT(e)),
118 }
119
120 }
130
131 #[must_use]
132 pub fn audience(&self) -> &str {
133 &self.audience
134 }
135
136 #[must_use]
137 pub const fn expiration_at(&self) -> u64 {
138 self.expiration_at
139 }
140
141 #[must_use]
142 pub const fn issued_at(&self) -> u64 {
143 self.issued_at
144 }
145
146 #[must_use]
147 pub fn issuer(&self) -> &str {
148 &self.issuer
149 }
150
151 #[must_use]
152 pub const fn user(&self) -> &ModelKey {
153 &self.user
154 }
155
156 #[must_use]
157 pub const fn roles(&self) -> &Role {
158 &self.roles
159 }
160
161 #[must_use]
162 pub const fn account(&self) -> &ModelKey {
163 &self.account
164 }
165 #[must_use]
166 pub fn account_name(&self) -> &str {
167 &self.account_name
168 }
169}