Skip to content

Commit 6a41ba7

Browse files
committed
feat(decoder): Create decoder
1 parent a701547 commit 6a41ba7

File tree

4 files changed

+136
-10
lines changed

4 files changed

+136
-10
lines changed

src/builder.rs

Lines changed: 113 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22
//!
33
//! - Documentation
44
5-
use serde::Serialize;
5+
use serde::{de::DeserializeOwned, Serialize};
66

77
use crate::{
88
crypto::{
99
hmac::{HmacSecret, Hs256, Hs384},
10-
JwtSigner,
10+
JwtSigner, JwtVerifier,
1111
},
12-
errors::{new_error, Result},
13-
serialization::{b64_encode, b64_encode_part},
14-
Header,
12+
errors::{new_error, ErrorKind, Result},
13+
serialization::{b64_encode, b64_encode_part, DecodedJwtPartClaims},
14+
validation::validate,
15+
Header, TokenData, Validation,
1516
};
1617

1718
/// # Todo
@@ -44,13 +45,13 @@ impl JwtEncoder {
4445
/// # Todo
4546
///
4647
/// - Test the the error checking works
47-
pub fn with_header(mut self, header: Header) -> Result<Self> {
48+
pub fn with_header(mut self, header: &Header) -> Result<Self> {
4849
// Check that the header makes use of the correct algorithm
4950
if header.alg != self.signing_provider.algorithm() {
5051
return Err(new_error(crate::errors::ErrorKind::InvalidAlgorithm));
5152
}
5253

53-
self.header = header;
54+
self.header = header.clone();
5455
Ok(self)
5556
}
5657

@@ -84,6 +85,111 @@ impl JwtEncoder {
8485
}
8586
}
8687

88+
/// Takes the result of a rsplit and ensure we only get 2 parts
89+
/// Errors if we don't
90+
macro_rules! expect_two {
91+
($iter:expr) => {{
92+
let mut i = $iter;
93+
match (i.next(), i.next(), i.next()) {
94+
(Some(first), Some(second), None) => (first, second),
95+
_ => return Err(new_error(ErrorKind::InvalidToken)),
96+
}
97+
}};
98+
}
99+
100+
/// Todo
101+
pub struct JwtDecoder {
102+
verifying_provider: Box<dyn JwtVerifier>,
103+
validation: Validation,
104+
}
105+
106+
impl JwtDecoder {
107+
/// Todo
108+
pub fn from_verifier<V: JwtVerifier + 'static>(verifying_provider: V) -> Self {
109+
Self::from_boxed_verifiyer(Box::new(verifying_provider))
110+
}
111+
112+
/// Todo
113+
pub fn from_boxed_verifiyer(verifying_provider: Box<dyn JwtVerifier>) -> Self {
114+
let validation = Validation::new(verifying_provider.algorithm());
115+
116+
Self { verifying_provider, validation }
117+
}
118+
119+
/// Todo
120+
pub fn with_validation(mut self, validation: &Validation) -> Result<Self> {
121+
// Check that the validation contains the correct algorithm
122+
if !validation.algorithms.contains(&self.verifying_provider.algorithm()) {
123+
return Err(new_error(crate::errors::ErrorKind::InvalidAlgorithm));
124+
}
125+
126+
self.validation = validation.clone();
127+
Ok(self)
128+
}
129+
130+
/// Todo
131+
pub fn decode<T: DeserializeOwned>(&self, token: &str) -> Result<TokenData<T>> {
132+
let (header, claims) = self.verify_signature(token)?;
133+
134+
let decoded_claims = DecodedJwtPartClaims::from_jwt_part_claims(claims)?;
135+
let claims = decoded_claims.deserialize()?;
136+
validate(decoded_claims.deserialize()?, &self.validation)?;
137+
138+
Ok(TokenData { header, claims })
139+
}
140+
141+
/// Verify signature of a JWT, and return header object and raw payload
142+
///
143+
/// If the token or its signature is invalid, it will return an error.
144+
fn verify_signature<'a>(&self, token: &'a str) -> Result<(Header, &'a str)> {
145+
if self.validation.validate_signature && self.validation.algorithms.is_empty() {
146+
return Err(new_error(ErrorKind::MissingAlgorithm));
147+
}
148+
149+
// Todo: This behaviour is currently not captured anywhere.
150+
// if validation.validate_signature {
151+
// for alg in &validation.algorithms {
152+
// if key.family != alg.family() {
153+
// return Err(new_error(ErrorKind::InvalidAlgorithm));
154+
// }
155+
// }
156+
// }
157+
158+
let (signature, message) = expect_two!(token.rsplitn(2, '.'));
159+
let (payload, header) = expect_two!(message.rsplitn(2, '.'));
160+
let header = Header::from_encoded(header)?;
161+
162+
if self.validation.validate_signature && !self.validation.algorithms.contains(&header.alg) {
163+
return Err(new_error(ErrorKind::InvalidAlgorithm));
164+
}
165+
166+
if self.validation.validate_signature
167+
&& self
168+
.verifying_provider
169+
.verify(message.as_bytes(), &signature.as_bytes().to_vec())
170+
.is_err()
171+
{
172+
return Err(new_error(ErrorKind::InvalidSignature));
173+
}
174+
175+
Ok((header, payload))
176+
}
177+
178+
/// Create new [`JwtDecoder`] with the `HS256` algorithm.
179+
pub fn hs_256(secret: HmacSecret) -> Result<JwtDecoder> {
180+
let verifying_provider = Box::new(Hs256::new(secret)?);
181+
182+
Ok(JwtDecoder::from_boxed_verifiyer(verifying_provider))
183+
}
184+
185+
/// Create new [`JwtDecoder`] with the `HS384` algorithm.
186+
pub fn hs_384(secret: HmacSecret) -> Result<JwtDecoder> {
187+
let verifying_provider = Box::new(Hs384::new(secret)?);
188+
189+
Ok(JwtDecoder::from_boxed_verifiyer(verifying_provider))
190+
}
191+
}
192+
87193
#[cfg(test)]
88194
mod builder_tests {
89195

src/decoding.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use base64::{engine::general_purpose::STANDARD, Engine};
22
use serde::de::DeserializeOwned;
33

44
use crate::algorithms::AlgorithmFamily;
5+
use crate::builder::JwtDecoder;
56
use crate::crypto::verify;
67
use crate::errors::{new_error, ErrorKind, Result};
78
use crate::header::Header;
@@ -271,6 +272,25 @@ pub fn decode<T: DeserializeOwned>(
271272
}
272273
}
273274

275+
fn decoder_factory(algorithm: &Algorithm, key: &DecodingKey) -> Result<JwtDecoder> {
276+
let jwt_encoder = match algorithm {
277+
Algorithm::HS256 => JwtDecoder::hs_256(HmacSecret::from_secret(&key.content))?,
278+
Algorithm::HS384 => JwtDecoder::hs_384(HmacSecret::from_secret(&key.content))?,
279+
Algorithm::HS512 => todo!(),
280+
Algorithm::ES256 => todo!(),
281+
Algorithm::ES384 => todo!(),
282+
Algorithm::RS256 => todo!(),
283+
Algorithm::RS384 => todo!(),
284+
Algorithm::RS512 => todo!(),
285+
Algorithm::PS256 => todo!(),
286+
Algorithm::PS384 => todo!(),
287+
Algorithm::PS512 => todo!(),
288+
Algorithm::EdDSA => todo!(),
289+
};
290+
291+
Ok(jwt_encoder)
292+
}
293+
274294
/// Decode a JWT without any signature verification/validations and return its [Header](struct.Header.html).
275295
///
276296
/// If the token has an invalid format (ie 3 parts separated by a `.`), it will return an error.

src/encoding.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ pub fn encode<T: Serialize>(header: &Header, claims: &T, key: &EncodingKey) -> R
126126
return Err(new_error(ErrorKind::InvalidAlgorithm));
127127
}
128128

129-
let jwt_encoder = encoder_factory(&header.alg, key)?;
129+
let jwt_encoder = encoder_factory(&header.alg, key)?.with_header(header)?;
130130

131131
jwt_encoder.encode(claims)
132132
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#![deny(missing_docs)]
55

66
pub use algorithms::Algorithm;
7-
// pub use decoding::{decode, decode_header, DecodingKey, TokenData};
7+
pub use decoding::{decode, decode_header, DecodingKey, TokenData};
88
pub use encoding::{encode, EncodingKey};
99
pub use header::Header;
1010
pub use validation::{get_current_timestamp, Validation};
@@ -13,7 +13,7 @@ mod algorithms;
1313
pub mod builder;
1414
/// Lower level functions, if you want to do something other than JWTs
1515
pub mod crypto;
16-
// mod decoding;
16+
mod decoding;
1717
mod encoding;
1818
/// All the errors that can be encountered while encoding/decoding JWTs
1919
pub mod errors;

0 commit comments

Comments
 (0)