1use crate::{
2 algorithms::Algorithm,
3 crypto::{SignFromKey, VerifyFromKey},
4 errors::Error,
5 log,
6 signer::sign,
7 verifier::verify,
8};
9use base64::{engine::general_purpose::STANDARD, Engine};
10use chrono::{DateTime, Utc};
11use serde::{de::DeserializeOwned, Deserialize, Serialize};
12use serde_json::Value;
13
14trait Base64Encode
15where
16 Self: Serialize + ToString,
17{
18 fn to_base64_encoded(&self) -> String {
19 STANDARD.encode(self.to_string())
20 }
21}
22
23trait FromBase64Encoded
24where
25 Self: DeserializeOwned,
26{
27 fn from_base64_encoded(base64_encoded_str: &str) -> Result<Self, Error> {
28 let base64_decoded = match STANDARD.decode(base64_encoded_str) {
29 Ok(val) => match String::from_utf8(val) {
30 Ok(val) => val,
31 Err(error) => {
32 log::error(error.to_string().as_str());
33 return Err(Error::JWT_UTF8_ERROR);
34 }
35 },
36 Err(error) => {
37 log::error(error.to_string().as_str());
38 return Err(Error::DECODING_ERROR);
39 }
40 };
41
42 match serde_json::from_str(base64_decoded.as_str()) {
43 Ok(val) => Ok(val),
44 Err(error) => {
45 log::error(error.to_string().as_str());
46 return Err(Error::JWT_HEADER_DESERIALIZING_ERROR);
47 }
48 }
49 }
50}
51
52#[derive(Serialize, Deserialize)]
53pub struct Header {
54 pub typ: String,
55 pub alg: Algorithm,
56 pub kid: String,
57}
58
59impl Header {
60 pub fn new(kid: String, alg: Algorithm) -> Self {
61 Header {
62 kid,
63 alg,
64 typ: String::from("JWT"),
65 }
66 }
67}
68
69impl ToString for Header {
70 fn to_string(&self) -> String {
71 match serde_json::to_string(self) {
72 Ok(val) => val,
73 Err(error) => {
74 log::error(error.to_string().as_str());
75 panic!()
76 }
77 }
78 }
79}
80
81impl FromBase64Encoded for Header {}
82impl Base64Encode for Header {}
83
84#[derive(Serialize, Deserialize)]
85pub struct Payload(pub Value);
86
87impl ToString for Payload {
88 fn to_string(&self) -> String {
89 match serde_json::to_string(self) {
90 Ok(val) => val,
91 Err(error) => {
92 log::error(error.to_string().as_str());
93 panic!()
94 }
95 }
96 }
97}
98
99impl FromBase64Encoded for Payload {}
100impl Base64Encode for Payload {}
101
102#[derive(Serialize, Deserialize, Clone)]
103pub struct Signature(String);
104
105impl ToString for Signature {
106 fn to_string(&self) -> String {
107 self.0.clone()
108 }
109}
110
111#[derive(Serialize, Deserialize)]
112pub struct JWT {
113 pub header: Header,
114 pub payload: Payload,
115 pub signature: Option<Signature>,
116}
117
118impl JWT {
119 pub fn to_token(&self) -> Result<String, Error> {
120 if self.signature.is_none() {
121 return Err(Error::JWT_TOKEN_NOT_SIGNED);
122 } else {
123 let sig = self.signature.as_ref().unwrap();
124 Ok(format!(
125 "{}.{}.{}",
126 self.header.to_base64_encoded(),
127 self.payload.to_base64_encoded(),
128 sig.to_string()
129 ))
130 }
131 }
132
133 pub fn sign(&mut self, private_key: impl SignFromKey) -> Result<(), Error> {
134 let content = format!(
135 "{}.{}",
136 self.header.to_base64_encoded(),
137 self.payload.to_base64_encoded()
138 );
139
140 match sign(content.clone(), private_key, self.header.alg) {
141 Ok(val) => {
142 self.signature = Some(Signature(val));
143 Ok(())
144 }
145 Err(error) => Err(error),
146 }
147 }
148
149 pub fn from_token(token: &str) -> Result<Self, Error> {
150 let token_content: Vec<&str> = token.split(".").collect();
151
152 let header = match Header::from_base64_encoded(token_content[0]) {
153 Ok(val) => val,
154 Err(error) => return Err(error),
155 };
156
157 let payload = match Payload::from_base64_encoded(token_content[1]) {
158 Ok(val) => val,
159 Err(error) => return Err(error),
160 };
161
162 let signature: Signature = Signature(String::from(token_content[2]));
163
164 Ok(JWT {
165 header,
166 payload,
167 signature: Some(signature),
168 })
169 }
170
171 fn check_if_expired(timestamp_secs: i64) -> Result<bool, Error> {
172 let now = Utc::now();
173 let exp_time = match DateTime::from_timestamp_millis(timestamp_secs * 1000) {
174 Some(val) => val,
175 None => {
176 return Err(Error::FAILED_TO_CONVERT_TIMESTAMP_TO_DATETTIME);
177 }
178 };
179
180 Ok(now < exp_time)
181 }
182
183 pub fn validate(&self, public_key: impl VerifyFromKey) -> Result<bool, Error> {
184 let algorithm = self.header.alg;
185
186 let signature = match &self.signature {
187 Some(val) => val.clone(),
188 None => return Err(Error::JWT_NO_SIGNATURE_FOUND),
189 };
190
191 let verified = match verify(
192 format!(
193 "{}.{}",
194 self.header.to_base64_encoded(),
195 self.payload.to_base64_encoded()
196 ),
197 signature.0,
198 public_key,
199 algorithm,
200 ) {
201 Ok(val) => val,
202 Err(error) => return Err(error),
203 };
204
205 if !verified {
206 return Ok(false);
207 }
208
209 let exp = match self.payload.0.get("exp") {
210 Some(val) => match val.as_i64() {
211 Some(val) => val,
212 None => return Err(Error::JWT_PAYLOAD_FIELD_EXP_IDENTIFICATION_ERROR),
213 },
214 None => return Err(Error::JWT_PAYLOAD_MISSING_FIELD_EXP),
215 };
216
217 Self::check_if_expired(exp)
218 }
219
220 pub fn validate_token(
221 token_str: &str,
222 public_key: impl VerifyFromKey,
223 ) -> Result<(Self, bool), Error> {
224 let token = match Self::from_token(token_str) {
225 Ok(val) => val,
226 Err(error) => return Err(error),
227 };
228
229 let verified = match token.validate(public_key) {
230 Ok(val) => val,
231 Err(error) => return Err(error),
232 };
233
234 Ok((token, verified))
235 }
236}