Skip to content

Commit 0886064

Browse files
committed
docs: Neaten up docstrings
1 parent 66d54be commit 0886064

File tree

5 files changed

+133
-95
lines changed

5 files changed

+133
-95
lines changed

src/crypto/hmac.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//! Implementations of the [`JwtSigner`] and [`JwtVerifier`] traits for the
2+
//! HMAC family of algorithms.
3+
14
use base64::{engine::general_purpose::STANDARD, Engine};
25
use hmac::{Hmac, Mac};
36
use sha2::{Sha256, Sha384, Sha512};
@@ -12,8 +15,9 @@ type HmacSha256 = Hmac<Sha256>;
1215
type HmacSha384 = Hmac<Sha384>;
1316
type HmacSha512 = Hmac<Sha512>;
1417

18+
/// The shared secret used for the HMAC family of algorithms.
1519
#[derive(Debug)]
16-
pub(crate) struct HmacSecret(Vec<u8>);
20+
pub struct HmacSecret(Vec<u8>);
1721

1822
impl HmacSecret {
1923
/// If you're using an HMAC secret that is not base64, use that.

src/crypto/mod.rs

Lines changed: 7 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
//! The cryptography of the `jsonwebtoken` crate is decoupled behind
2+
//! [`JwtSigner`] and [`JwtVerifier`] traits. These make use of `RustCrypto`'s
3+
//! [`Signer`] and [`Verifier`] traits respectively.
4+
15
use crate::algorithms::Algorithm;
2-
// use crate::decoding::{DecodingKey, DecodingKeyKind};
3-
// use crate::encoding::EncodingKey;
4-
// use crate::errors::Result;
56

6-
pub(crate) mod ecdsa;
7-
pub(crate) mod eddsa;
7+
// pub(crate) mod ecdsa;
8+
// pub(crate) mod eddsa;
89
pub(crate) mod hmac;
9-
pub(crate) mod rsa;
10+
// pub(crate) mod rsa;
1011

1112
use signature::{Signer, Verifier};
1213

@@ -25,61 +26,3 @@ pub trait JwtVerifier: Verifier<Vec<u8>> {
2526
/// Return the [`Algorithm`] corresponding to the signing module.
2627
fn algorithm(&self) -> Algorithm;
2728
}
28-
29-
// /// Take the payload of a JWT, sign it using the algorithm given and return
30-
// /// the base64 url safe encoded of the result.
31-
// ///
32-
// /// If you just want to encode a JWT, use `encode` instead.
33-
// pub fn sign(message: &[u8], key: &EncodingKey, algorithm: Algorithm) -> Result<String> {
34-
// match algorithm {
35-
// Algorithm::ES256 | Algorithm::ES384 => ecdsa::sign(algorithm, key.inner(), message),
36-
// Algorithm::EdDSA => eddsa::sign(key.inner(), message),
37-
// Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => {
38-
// hmac::sign_hmac(algorithm, key.inner(), message)
39-
// }
40-
// Algorithm::RS256
41-
// | Algorithm::RS384
42-
// | Algorithm::RS512
43-
// | Algorithm::PS256
44-
// | Algorithm::PS384
45-
// | Algorithm::PS512 => rsa::sign(algorithm, key.inner(), message),
46-
// }
47-
// }
48-
49-
// /// Compares the signature given with a re-computed signature for HMAC or using the public key
50-
// /// for RSA/EC.
51-
// ///
52-
// /// If you just want to decode a JWT, use `decode` instead.
53-
// ///
54-
// /// `signature` is the signature part of a jwt (text after the second '.')
55-
// ///
56-
// /// `message` is base64(header) + "." + base64(claims)
57-
// pub fn verify(
58-
// signature: &str,
59-
// message: &[u8],
60-
// key: &DecodingKey,
61-
// algorithm: Algorithm,
62-
// ) -> Result<bool> {
63-
// match algorithm {
64-
// Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => {
65-
// hmac::hmac_verify(algorithm, signature, key.as_bytes(), message)
66-
// }
67-
// Algorithm::ES256 | Algorithm::ES384 => {
68-
// ecdsa::verify(algorithm, signature, message, key.as_bytes())
69-
// }
70-
// Algorithm::EdDSA => eddsa::verify(signature, message, key.as_bytes()),
71-
// Algorithm::RS256
72-
// | Algorithm::RS384
73-
// | Algorithm::RS512
74-
// | Algorithm::PS256
75-
// | Algorithm::PS384
76-
// | Algorithm::PS512 => match &key.kind {
77-
// DecodingKeyKind::SecretOrDer(bytes) => {
78-
// rsa::verify_der(algorithm, signature, message, bytes)
79-
// }
80-
// DecodingKeyKind::RsaModulusExponent { n, e } => {
81-
// rsa::verify_from_components(algorithm, signature, message, (n, e))
82-
// }
83-
// },
84-
// }
85-
// }

src/decoding.rs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -194,13 +194,6 @@ impl DecodingKey {
194194
}
195195
}
196196
}
197-
198-
pub(crate) fn as_bytes(&self) -> &[u8] {
199-
match &self.kind {
200-
DecodingKeyKind::SecretOrDer(b) => b,
201-
DecodingKeyKind::RsaModulusExponent { .. } => unreachable!(),
202-
}
203-
}
204197
}
205198

206199
/// Decode and validate a JWT
@@ -238,6 +231,7 @@ pub fn decode<T: DeserializeOwned>(
238231
decoder.decode(token)
239232
}
240233

234+
/// Return the correct decoder based on the `algorithm`.
241235
fn decoder_factory(algorithm: &Algorithm, key: &DecodingKey) -> Result<JwtDecoder> {
242236
let jwt_encoder = match algorithm {
243237
Algorithm::HS256 => JwtDecoder::hs_256(key.try_into()?)?,
@@ -287,26 +281,64 @@ pub fn decode_header(token: &str) -> Result<Header> {
287281
Header::from_encoded(header)
288282
}
289283

290-
/// Todo
284+
/// A builder style JWT decoder
285+
///
286+
/// # Examples
287+
///
288+
/// ```
289+
/// use jsonwebtoken::{JwtDecoder, HmacSecret};
290+
/// use serde::{Serialize, Deserialize};
291+
///
292+
/// #[derive(Debug, Serialize, Deserialize)]
293+
/// struct Claims {
294+
/// sub: String,
295+
/// company: String,
296+
/// exp: usize,
297+
/// }
298+
///
299+
/// let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.9r56oF7ZliOBlOAyiOFperTGxBtPykRQiWNFxhDCW98";
300+
///
301+
/// let hmac_secret = HmacSecret::from_secret(b"secret");
302+
///
303+
/// let claims = JwtDecoder::hs_256(hmac_secret)
304+
/// .unwrap()
305+
/// .decode::<Claims>(&token)
306+
/// .unwrap();
307+
/// ```
291308
pub struct JwtDecoder {
292309
verifying_provider: Box<dyn JwtVerifier>,
293310
validation: Validation,
294311
}
295312

296313
impl JwtDecoder {
297-
/// Todo
314+
/// Create a new [`JwtDecoder`] with any `verifying_provider` that implements the [`JwtVerifier`] trait.
298315
pub fn from_verifier<V: JwtVerifier + 'static>(verifying_provider: V) -> Self {
299316
Self::from_boxed_verifiyer(Box::new(verifying_provider))
300317
}
301318

302-
/// Todo
319+
/// Create a new [`JwtDecoder`] with any `verifying_provider` implements the [`JwtVerifier`] trait.
303320
pub fn from_boxed_verifiyer(verifying_provider: Box<dyn JwtVerifier>) -> Self {
304321
let validation = Validation::new(verifying_provider.algorithm());
305322

306323
Self { verifying_provider, validation }
307324
}
308325

309-
/// Todo
326+
/// Provide custom a custom validation configuration.
327+
///
328+
/// # Examples
329+
///
330+
/// ```
331+
/// use jsonwebtoken::{JwtDecoder, HmacSecret, Validation, Algorithm};
332+
///
333+
/// let hmac_secret = HmacSecret::from_secret(b"secret");
334+
/// let mut validation = Validation::new(Algorithm::HS256);
335+
/// validation.leeway = 5;
336+
///
337+
/// let jwt_decoder = JwtDecoder::hs_256(hmac_secret)
338+
/// .unwrap()
339+
/// .with_validation(&validation)
340+
/// .unwrap();
341+
/// ```
310342
pub fn with_validation(mut self, validation: &Validation) -> Result<Self> {
311343
// Check that the validation contains the correct algorithm
312344
if validation.validate_signature
@@ -319,7 +351,7 @@ impl JwtDecoder {
319351
Ok(self)
320352
}
321353

322-
/// Todo
354+
/// Decode and verify a JWT `token` using the `verifying_provider` and `validation` of the [`JwtDecoder`]
323355
pub fn decode<T: DeserializeOwned>(&self, token: &str) -> Result<TokenData<T>> {
324356
let (header, claims) = self.verify_signature(token)?;
325357

src/encoding.rs

Lines changed: 74 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use base64::{engine::general_purpose::STANDARD, Engine};
22
use serde::ser::Serialize;
33

44
use crate::algorithms::AlgorithmFamily;
5-
use crate::crypto::hmac::{HmacSecret, Hs256, Hs384};
5+
use crate::crypto::hmac::{HmacSecret, Hs256, Hs384, Hs512};
66
use crate::crypto::JwtSigner;
77
use crate::errors::{new_error, ErrorKind, Result};
88
use crate::header::Header;
@@ -130,12 +130,12 @@ pub fn encode<T: Serialize>(header: &Header, claims: &T, key: &EncodingKey) -> R
130130
jwt_encoder.encode(claims)
131131
}
132132

133+
/// Return the correct [`JwtEncoder`] based on the `algorithm`.
133134
fn encoder_factory(algorithm: &Algorithm, key: &EncodingKey) -> Result<JwtEncoder> {
134135
let jwt_encoder = match algorithm {
135-
// Todo: Need to implement `TryInto<HmacSecret> for &EncodingKey`
136-
Algorithm::HS256 => JwtEncoder::hs_256(HmacSecret::from_secret(&key.content))?,
137-
Algorithm::HS384 => JwtEncoder::hs_384(HmacSecret::from_secret(&key.content))?,
138-
Algorithm::HS512 => todo!(),
136+
Algorithm::HS256 => JwtEncoder::hs_256(key.into())?,
137+
Algorithm::HS384 => JwtEncoder::hs_384(key.into())?,
138+
Algorithm::HS512 => JwtEncoder::hs_512(key.into())?,
139139
Algorithm::ES256 => todo!(),
140140
Algorithm::ES384 => todo!(),
141141
Algorithm::RS256 => todo!(),
@@ -150,21 +150,51 @@ fn encoder_factory(algorithm: &Algorithm, key: &EncodingKey) -> Result<JwtEncode
150150
Ok(jwt_encoder)
151151
}
152152

153-
/// # Todo
153+
/// Convert an [`&EncodingKey`] to an [`HmacSecret`].
154+
impl From<&EncodingKey> for HmacSecret {
155+
fn from(key: &EncodingKey) -> Self {
156+
HmacSecret::from_secret(&key.content)
157+
}
158+
}
159+
160+
/// A builder style JWT encoder.
161+
///
162+
/// # Examples
163+
///
164+
/// ```
165+
/// use serde::{Deserialize, Serialize};
166+
/// use jsonwebtoken::{JwtEncoder, HmacSecret};
167+
///
168+
/// #[derive(Debug, Serialize, Deserialize)]
169+
/// struct Claims {
170+
/// sub: String,
171+
/// company: String
172+
/// }
173+
///
174+
/// let my_claims = Claims {
175+
/// sub: "b@b.com".to_owned(),
176+
/// company: "ACME".to_owned()
177+
/// };
154178
///
155-
/// - Documentation
179+
/// let hmac_secret = HmacSecret::from_secret(b"secret");
180+
///
181+
/// let token = JwtEncoder::hs_256(hmac_secret)
182+
/// .unwrap()
183+
/// .encode(&my_claims)
184+
/// .unwrap();
185+
/// ```
156186
pub struct JwtEncoder {
157187
signing_provider: Box<dyn JwtSigner>,
158188
header: Header,
159189
}
160190

161191
impl JwtEncoder {
162-
/// Todo
192+
/// Create a new [`JwtEncoder`] with any `signing_provider` that implements the [`JwtSigner`] trait.
163193
pub fn from_signer<S: JwtSigner + 'static>(signing_provider: S) -> Self {
164194
Self::from_boxed_signer(Box::new(signing_provider))
165195
}
166196

167-
/// Create a new [`JwtEncoder`] with any crypto provider that implements the [`CryptoProvider`] trait.
197+
/// Create a new [`JwtEncoder`] with any `signing_provider` that implements the [`JwtSigner`] trait.
168198
pub fn from_boxed_signer(signing_provider: Box<dyn JwtSigner>) -> Self {
169199
// Determine a default header
170200
let mut header = Header::new(signing_provider.algorithm());
@@ -177,9 +207,34 @@ impl JwtEncoder {
177207
///
178208
/// This would be used in the rare cases that fields other than `algorithm` and `type` need to be populated.
179209
///
180-
/// # Todo
210+
/// # Examples
211+
///
212+
/// ```
213+
/// use serde::{Deserialize, Serialize};
214+
/// use jsonwebtoken::{JwtEncoder, HmacSecret, Header, Algorithm};
215+
///
216+
/// #[derive(Debug, Serialize, Deserialize)]
217+
/// struct Claims {
218+
/// sub: String,
219+
/// company: String
220+
/// }
221+
///
222+
/// let my_claims = Claims {
223+
/// sub: "b@b.com".to_owned(),
224+
/// company: "ACME".to_owned()
225+
/// };
181226
///
182-
/// - Test the the error checking works
227+
/// let hmac_secret = HmacSecret::from_secret(b"secret");
228+
/// let mut header = Header::new(Algorithm::HS256);
229+
/// header.cty = Some("content-type".to_owned());
230+
///
231+
/// let token = JwtEncoder::hs_256(hmac_secret)
232+
/// .unwrap()
233+
/// .with_header(&header)
234+
/// .unwrap()
235+
/// .encode(&my_claims)
236+
/// .unwrap();
237+
/// ```
183238
pub fn with_header(mut self, header: &Header) -> Result<Self> {
184239
// Check that the header makes use of the correct algorithm
185240
if header.alg != self.signing_provider.algorithm() {
@@ -190,11 +245,7 @@ impl JwtEncoder {
190245
Ok(self)
191246
}
192247

193-
/// Encode and sign the `claims` as a JWT.
194-
///
195-
/// # Todo
196-
///
197-
/// - Put in example usage.
248+
/// Encode and sign the `claims` as a JWT using the `signing_provider` of the [`JwtEncoder`].
198249
pub fn encode<T: Serialize>(&self, claims: &T) -> Result<String> {
199250
let encoded_header = b64_encode_part(&self.header)?;
200251
let encoded_claims = b64_encode_part(claims)?;
@@ -218,4 +269,11 @@ impl JwtEncoder {
218269

219270
Ok(JwtEncoder::from_boxed_signer(signing_provider))
220271
}
272+
273+
/// Create new [`JwtEncoder`] with the `HS512` algorithm.
274+
pub fn hs_512(secret: HmacSecret) -> Result<JwtEncoder> {
275+
let signing_provider = Box::new(Hs512::new(secret)?);
276+
277+
Ok(JwtEncoder::from_boxed_signer(signing_provider))
278+
}
221279
}

src/lib.rs

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

66
pub use algorithms::Algorithm;
7-
pub use decoding::{decode, decode_header, DecodingKey, TokenData};
8-
pub use encoding::{encode, EncodingKey};
7+
pub use crypto::hmac::HmacSecret;
8+
pub use decoding::{decode, decode_header, DecodingKey, JwtDecoder, TokenData};
9+
pub use encoding::{encode, EncodingKey, JwtEncoder};
910
pub use header::Header;
1011
pub use validation::{get_current_timestamp, Validation};
1112

0 commit comments

Comments
 (0)