diff --git a/Cargo.toml b/Cargo.toml index d59ed82..e01df2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,23 +2,24 @@ authors = ["Thomas Gideon "] categories = ["cryptography", "authentication", "web-programming", "data-structures"] description = "JWT library for rust using serde, serde_json and openssl" -documentation = "https://commandline.github.io/medallion/" -homepage = "http://github.com/commandline/medallion" +documentation = "https://cmdln.github.io/medallion/" +homepage = "http://github.com/cmdln/medallion" keywords = ["JWT", "token", "web", "JSON", "RSA"] license = "MIT" name = "medallion" readme = "README.md" -repository = "http://github.com/commandline/medallion" -version = "2.2.3" +repository = "http://github.com/cmdn/medallion" +version = "2.3.0" [badges] [badges.travis-ci] branch = "master" -repository = "https://travis-ci.org/commandline/medallion" +repository = "https://travis-ci.org/cmdln/medallion" [dependencies] -base64 = "0.9" -openssl = "0.10" -serde = "1.0" -serde_derive = "1.0" -serde_json = "1.0" -time = "0.1" +base64 = "~0.10.0" +failure = "~0.1.3" +openssl = "~0.10.15" +serde = "^1.0.80" +serde_derive = "^1.0.80" +serde_json = "^1.0.33" +time = "~0.1.40" diff --git a/src/crypt.rs b/src/crypt.rs index 99c0d45..dffbe2a 100644 --- a/src/crypt.rs +++ b/src/crypt.rs @@ -1,10 +1,13 @@ use base64::{decode_config, encode_config, URL_SAFE_NO_PAD}; use header::Algorithm; -use openssl::hash::MessageDigest; -use openssl::memcmp; -use openssl::pkey::PKey; -use openssl::rsa::Rsa; -use openssl::sign::{Signer, Verifier}; +use openssl::{ + hash::MessageDigest, + memcmp, + pkey::PKey, + rsa::Rsa, + sign::{Signer, Verifier}, +}; + use super::Result; pub fn sign(data: &str, key: &[u8], algorithm: &Algorithm) -> Result { @@ -72,9 +75,9 @@ fn verify_rsa(signature: &str, data: &str, key: &[u8], digest: MessageDigest) -> #[cfg(test)] pub mod tests { + use super::{sign, verify}; use header::Algorithm; use openssl; - use super::{sign, verify}; #[test] pub fn sign_data_hmac() { @@ -83,7 +86,7 @@ pub mod tests { let real_sig = "TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"; let data = format!("{}.{}", header, claims); - let sig = sign(&*data, "secret".as_bytes(), &Algorithm::HS256); + let sig = sign(&*data, b"secret", &Algorithm::HS256); assert_eq!(sig.unwrap(), real_sig); } @@ -120,6 +123,6 @@ pub mod tests { let target = "TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"; let data = format!("{}.{}", header, claims); - assert!(verify(target, &*data, "secret".as_bytes(), &Algorithm::HS256).unwrap()); + assert!(verify(target, &*data, b"secret", &Algorithm::HS256).unwrap()); } } diff --git a/src/error.rs b/src/error.rs index 5021290..b508e3e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,67 +1,3 @@ -use base64::DecodeError; -use serde_json; -use std::error; -use std::fmt; -use std::string::FromUtf8Error; -use openssl::error::ErrorStack; +use failure::Error; -#[derive(Debug)] -pub enum Error { - /// Custom, Medallion specific errors. - Custom(String), - /// String encoding errors. - Utf8(FromUtf8Error), - /// Base64 encoding or decoding errors. - Base64(DecodeError), - /// JSON parsing or stringifying errors. - JSON(serde_json::Error), - /// Errors from RSA operations. - Crypto(ErrorStack), -} - -impl error::Error for Error { - fn description(&self) -> &str { - match *self { - Error::Custom(ref message) => message, - Error::Utf8(ref err) => err.description(), - Error::Base64(ref err) => err.description(), - Error::JSON(ref err) => err.description(), - Error::Crypto(ref err) => err.description(), - } - } - - fn cause(&self) -> Option<&error::Error> { - match *self { - Error::Custom(_) => None, - Error::Utf8(ref err) => Some(err), - Error::Base64(ref err) => Some(err), - Error::JSON(ref err) => Some(err), - Error::Crypto(ref err) => Some(err), - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Custom(ref message) => f.write_str(message), - Error::Utf8(ref err) => err.fmt(f), - Error::Base64(ref err) => err.fmt(f), - Error::JSON(ref err) => err.fmt(f), - Error::Crypto(ref err) => err.fmt(f), - } - } -} - -macro_rules! error_wrap { - ($f: ty, $e: expr) => { - impl From<$f> for Error { - fn from(f: $f) -> Error { $e(f) } - } - } -} - -error_wrap!(FromUtf8Error, Error::Utf8); -error_wrap!(DecodeError, Error::Base64); -error_wrap!(serde_json::Error, Error::JSON); -error_wrap!(ErrorStack, Error::Crypto); +pub type Result = std::result::Result; diff --git a/src/header.rs b/src/header.rs index a635a00..a49942b 100644 --- a/src/header.rs +++ b/src/header.rs @@ -1,10 +1,7 @@ use base64::{decode_config, encode_config, URL_SAFE_NO_PAD}; -use serde::de::DeserializeOwned; -use serde::Serialize; +use serde::{de::DeserializeOwned, Serialize}; use serde_json::{self, Value}; -use std::default::Default; -use super::error::Error; use super::Result; /// An extensible Header that provides only algorithm field and allows for additional fields to be @@ -55,9 +52,7 @@ impl Header { let enc = encode_config((&*s).as_bytes(), URL_SAFE_NO_PAD); Ok(enc) } else { - Err(Error::Custom( - "Could not access additional headers.".to_owned(), - )) + Err(format_err!("Could not access additional headers.")) } } None => { @@ -67,7 +62,7 @@ impl Header { } } } else { - Err(Error::Custom("Could not access default header.".to_owned())) + Err(format_err!("Could not access default header.")) } } } @@ -113,7 +108,7 @@ mod tests { #[test] fn to_base64() { let enc = "eyJhbGciOiJIUzI1NiJ9"; - let header: Header<()> = Default::default(); + let header: Header<()> = Header::default(); assert_eq!(enc, header.to_base64().unwrap()); } @@ -126,7 +121,7 @@ mod tests { kid: "1KSF3g".into(), typ: "JWT".into(), }), - ..Default::default() + ..Header::default() }; assert_eq!(enc, header.to_base64().unwrap()); @@ -134,7 +129,7 @@ mod tests { #[test] fn roundtrip() { - let header: Header<()> = Default::default(); + let header: Header<()> = Header::default(); let enc = header.to_base64().unwrap(); assert_eq!(header, Header::from_base64(&*enc).unwrap()); } diff --git a/src/lib.rs b/src/lib.rs index 0aefd51..4ca05ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,8 @@ ///! Tries to support the standard uses for JWTs while providing reasonable ways to extend, ///! primarily by adding custom headers and claims to tokens. extern crate base64; +#[macro_use] +extern crate failure; extern crate openssl; extern crate serde; #[macro_use] @@ -14,19 +16,16 @@ extern crate serde_derive; extern crate serde_json; extern crate time; -pub use error::Error; -pub use header::Algorithm; -pub use header::Header; +pub use header::{Algorithm, Header}; pub use payload::{DefaultPayload, Payload}; -use serde::de::DeserializeOwned; -use serde::Serialize; +use serde::{de::DeserializeOwned, Serialize}; mod crypt; -pub mod error; +mod error; mod header; mod payload; -pub type Result = std::result::Result; +pub use error::Result; /// A convenient type that binds the same type parameter for the custom claims, an empty tuple, as /// `DefaultPayload` so that the two aliases may be used together to reduce boilerplate when no @@ -118,7 +117,7 @@ mod tests { let token = DefaultToken::<()>::parse(raw).unwrap(); assert_eq!(token.header.alg, HS256); - assert!(token.verify("secret".as_bytes()).unwrap()); + assert!(token.verify(b"secret").unwrap()); } #[test] @@ -131,7 +130,7 @@ mod tests { ..DefaultPayload::default() }; let token = Token::new(header, payload); - let key = "secret".as_bytes(); + let key = b"secret"; let raw = token.sign(key).unwrap(); let same = Token::parse(&*raw).unwrap(); @@ -143,7 +142,7 @@ mod tests { pub fn roundtrip_expired() { let now = time::now(); let token = create_for_range(now, now + Duration::minutes(-5)); - let key = "secret".as_bytes(); + let key = b"secret"; let raw = token.sign(key).unwrap(); let same = Token::parse(&*raw).unwrap(); @@ -155,7 +154,7 @@ mod tests { pub fn roundtrip_not_yet_valid() { let now = time::now(); let token = create_for_range(now + Duration::minutes(5), now + Duration::minutes(10)); - let key = "secret".as_bytes(); + let key = b"secret"; let raw = token.sign(key).unwrap(); let same = Token::parse(&*raw).unwrap(); @@ -171,7 +170,7 @@ mod tests { ..Header::default() }; let token = DefaultToken { - header: header, + header, ..Token::default() }; let raw = token diff --git a/src/payload.rs b/src/payload.rs index 09d33e7..dfaf181 100644 --- a/src/payload.rs +++ b/src/payload.rs @@ -1,6 +1,5 @@ use super::Result; use base64::{decode_config, encode_config, URL_SAFE_NO_PAD}; -use error::Error; use serde::de::DeserializeOwned; use serde::Serialize; use serde_json; @@ -68,7 +67,7 @@ impl Payload { let enc = encode_config((&*s).as_bytes(), URL_SAFE_NO_PAD); Ok(enc) } else { - Err(Error::Custom("Could not access custom claims.".to_owned())) + Err(format_err!("Could not access custom claims.")) } } None => { @@ -78,9 +77,7 @@ impl Payload { } } } else { - Err(Error::Custom( - "Could not access standard claims.".to_owned(), - )) + Err(format_err!("Could not access standard claims.",)) } } @@ -234,10 +231,10 @@ mod tests { fn create_default() -> DefaultPayload { DefaultPayload { aud: Some("login_service".into()), - iat: Some(1302317100), + iat: Some(1_302_317_100), iss: Some("example.com".into()), - exp: Some(1302319100), - nbf: Some(1302317100), + exp: Some(1_302_319_100), + nbf: Some(1_302_317_100), sub: Some("Random User".into()), ..Default::default() } @@ -246,8 +243,8 @@ mod tests { fn create_custom() -> Payload { Payload { iss: Some("example.com".into()), - iat: Some(1302317100), - exp: Some(1302319100), + iat: Some(1_302_317_100), + exp: Some(1_302_319_100), claims: Some(CustomClaims { user_id: "123456".into(), is_admin: false,