diff --git a/examples/gen_secret.rs b/examples/gen_secret.rs index d8c0878..527fc10 100644 --- a/examples/gen_secret.rs +++ b/examples/gen_secret.rs @@ -1,8 +1,7 @@ -#[cfg(not(feature = "gen_secret"))] -compile_error!("requires feature gen_secret"); - +#[cfg(all(feature = "gen_secret", feature = "otpauth"))] use totp_rs::{Secret, TOTP, Algorithm}; +#[cfg(all(feature = "gen_secret", feature = "otpauth"))] fn main () { let secret = Secret::generate_secret(); @@ -24,3 +23,6 @@ fn main () { totp.generate_current().unwrap() ) } + +#[cfg(not(all(feature = "gen_secret", feature = "otpauth")))] +fn main () {} \ No newline at end of file diff --git a/examples/rfc-6238.rs b/examples/rfc-6238.rs index 12a9d59..4e3975c 100644 --- a/examples/rfc-6238.rs +++ b/examples/rfc-6238.rs @@ -1,5 +1,6 @@ use totp_rs::{Rfc6238, TOTP}; +#[cfg(feature = "otpauth")] fn main () { let mut rfc = Rfc6238::with_defaults( "totp-sercret-123" @@ -15,3 +16,18 @@ fn main () { let code = totp.generate_current().unwrap(); println!("code: {}", code); } + +#[cfg(not(feature = "otpauth"))] +fn main () { + let mut rfc = Rfc6238::with_defaults( + "totp-sercret-123" + ).unwrap(); + + // optional, set digits, issuer, account_name + rfc.digits(8).unwrap(); + + // create a TOTP from rfc + let totp = TOTP::from_rfc6238(rfc).unwrap(); + let code = totp.generate_current().unwrap(); + println!("code: {}", code); +} \ No newline at end of file diff --git a/examples/secret.rs b/examples/secret.rs index 5ff7276..adf1eaa 100644 --- a/examples/secret.rs +++ b/examples/secret.rs @@ -1,5 +1,6 @@ use totp_rs::{Secret, TOTP, Algorithm}; +#[cfg(feature = "otpauth")] fn main () { // create TOTP from base32 secret let secret_b32 = Secret::Encoded(String::from("OBWGC2LOFVZXI4TJNZTS243FMNZGK5BNGEZDG")); @@ -9,8 +10,8 @@ fn main () { 1, 30, secret_b32.to_bytes().unwrap(), - None, - "account".to_string(), + Some("issuer".to_string()), + "user-account".to_string(), ).unwrap(); println!("base32 {} ; raw {}", secret_b32, secret_b32.to_raw().unwrap()); @@ -28,10 +29,43 @@ fn main () { 1, 30, secret_raw.to_bytes().unwrap(), - None, - "account".to_string(), + Some("issuer".to_string()), + "user-account".to_string(), ).unwrap(); println!("raw {} ; base32 {}", secret_raw, secret_raw.to_encoded()); println!("code from raw secret:\t{}", totp_raw.generate_current().unwrap()); } + +#[cfg(not(feature = "otpauth"))] +fn main () { + // create TOTP from base32 secret + let secret_b32 = Secret::Encoded(String::from("OBWGC2LOFVZXI4TJNZTS243FMNZGK5BNGEZDG")); + let totp_b32 = TOTP::new( + Algorithm::SHA1, + 6, + 1, + 30, + secret_b32.to_bytes().unwrap(), + ).unwrap(); + + println!("base32 {} ; raw {}", secret_b32, secret_b32.to_raw().unwrap()); + println!("code from base32:\t{}", totp_b32.generate_current().unwrap()); + + // create TOTP from raw binary value + let secret = [ + 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2d, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x73, 0x65, + 0x63, 0x72, 0x65, 0x74, 0x2d, 0x31, 0x32, 0x33, + ]; + let secret_raw = Secret::Raw(secret.to_vec()); + let totp_raw = TOTP::new( + Algorithm::SHA1, + 6, + 1, + 30, + secret_raw.to_bytes().unwrap(), + ).unwrap(); + + println!("raw {} ; base32 {}", secret_raw, secret_raw.to_encoded()); + println!("code from raw secret:\t{}", totp_raw.generate_current().unwrap()); +} \ No newline at end of file diff --git a/examples/ttl.rs b/examples/ttl.rs index 7554303..ec2c1a8 100644 --- a/examples/ttl.rs +++ b/examples/ttl.rs @@ -1,5 +1,6 @@ use totp_rs::{Algorithm, TOTP}; +#[cfg(not(feature = "otpauth"))] fn main() { let totp = TOTP::new( Algorithm::SHA1, @@ -7,8 +8,30 @@ fn main() { 1, 30, "my-secret".to_string(), - None, - "account".to_string(), + ).unwrap(); + + loop { + println!( + "code {}\t ttl {}\t valid until: {}", + totp.generate_current().unwrap(), + totp.ttl().unwrap(), + totp.next_step_current().unwrap() + ); + std::thread::sleep(std::time::Duration::from_secs(1)); + } +} + + +#[cfg(feature = "otpauth")] +fn main() { + let totp = TOTP::new( + Algorithm::SHA1, + 6, + 1, + 30, + "my-secret".to_string(), + Some("Github".to_string()), + "constantoine@github.com".to_string() ).unwrap(); loop { diff --git a/src/lib.rs b/src/lib.rs index c33e800..382585c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,20 +9,22 @@ //! # Examples //! //! ```rust +//! # #[cfg(feature = "otpauth")] { //! use std::time::SystemTime; -//! use totp_rs::{Algorithm, TOTP}; +//! use totp_rs::{Algorithm, TOTP, Secret}; //! //! let totp = TOTP::new( //! Algorithm::SHA1, //! 6, //! 1, //! 30, -//! "supersecret_topsecret", +//! Secret::Raw("TestSecretSuperSecret".as_bytes().to_vec()).to_bytes().unwrap(), //! Some("Github".to_string()), //! "constantoine@github.com".to_string(), //! ).unwrap(); //! let token = totp.generate_current().unwrap(); //! println!("{}", token); +//! # } //! ``` //! //! ```rust @@ -142,10 +144,12 @@ pub struct TOTP> { /// /// non-encoded value pub secret: T, + #[cfg(feature = "otpauth")] /// The "Github" part of "Github:constantoine@github.com". Must not contain a colon `:` /// For example, the name of your service/website. /// Not mandatory, but strongly recommended! pub issuer: Option, + #[cfg(feature = "otpauth")] /// The "constantoine@github.com" part of "Github:constantoine@github.com". Must not contain a colon `:` /// For example, the name of your user's account. pub account_name: String @@ -171,7 +175,23 @@ impl > PartialEq for TOTP { } } +#[cfg(all(feature = "gen_secret", not(feature = "otpauth")))] +impl Default for TOTP { + fn default() -> Self { + return TOTP::new(Algorithm::SHA1, 6, 1, 30, Secret::generate_secret().to_bytes().unwrap()).unwrap() + } +} + +#[cfg(all(feature = "gen_secret", feature = "otpauth"))] +impl Default for TOTP { + fn default() -> Self { + return TOTP::new(Algorithm::SHA1, 6, 1, 30, Secret::generate_secret().to_bytes().unwrap(), None, "".to_string()).unwrap() + } +} + impl> TOTP { + + #[cfg(feature = "otpauth")] /// Will create a new instance of TOTP with given parameters. See [the doc](struct.TOTP.html#fields) for reference as to how to choose those values /// /// # Description @@ -210,6 +230,35 @@ impl> TOTP { }) } + #[cfg(not(feature = "otpauth"))] + /// Will create a new instance of TOTP with given parameters. See [the doc](struct.TOTP.html#fields) for reference as to how to choose those values + /// + /// # Description + /// * `secret`: expect a non-encoded value, to pass in base32 string use `Secret::Encoded(String)` + /// + /// ```rust + /// use totp_rs::{Secret, TOTP, Algorithm}; + /// let secret = Secret::Encoded("OBWGC2LOFVZXI4TJNZTS243FMNZGK5BNGEZDG".to_string()); + /// let totp = TOTP::new(Algorithm::SHA1, 6, 1, 30, secret.to_bytes().unwrap()).unwrap(); + /// ``` + /// * `digits`: MUST be between 6 & 8 + /// * `secret`: Must have bitsize of at least 128 + /// + /// # Errors + /// + /// Will return an error in case issuer or label contain the character ':' + pub fn new(algorithm: Algorithm, digits: usize,skew: u8, step: u64, secret: T) -> Result, TotpUrlError> { + crate::rfc::assert_digits(&digits)?; + crate::rfc::assert_secret_length(secret.as_ref())?; + Ok(TOTP { + algorithm, + digits, + skew, + step, + secret, + }) + } + /// Will create a new instance of TOTP from the given [Rfc6238](struct.Rfc6238.html) struct /// /// # Errors @@ -462,6 +511,17 @@ mod tests { use super::*; #[test] + #[cfg(feature = "gen_secret")] + fn default_values() { + let totp = TOTP::default(); + assert_eq!(totp.algorithm, Algorithm::SHA1); + assert_eq!(totp.digits, 6); + assert_eq!(totp.skew, 1); + assert_eq!(totp.step, 30) + } + + #[test] + #[cfg(feature = "otpauth")] fn new_wrong_issuer() { let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github:".to_string()), "constantoine@github.com".to_string()); assert!(totp.is_err()); @@ -469,6 +529,7 @@ mod tests { } #[test] + #[cfg(feature = "otpauth")] fn new_wrong_account_name() { let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine:github.com".to_string()); assert!(totp.is_err()); @@ -476,6 +537,7 @@ mod tests { } #[test] + #[cfg(feature = "otpauth")] fn new_wrong_account_name_no_issuer() { let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", None, "constantoine:github.com".to_string()); assert!(totp.is_err()); @@ -483,6 +545,7 @@ mod tests { } #[test] + #[cfg(feature = "otpauth")] fn comparison_ok() { let reference = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); let test = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); @@ -490,37 +553,42 @@ mod tests { } #[test] + #[cfg(not(feature = "otpauth"))] fn comparison_different_algo() { - let reference = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); - let test = TOTP::new(Algorithm::SHA256, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let reference = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret").unwrap(); + let test = TOTP::new(Algorithm::SHA256, 6, 1, 1, "TestSecretSuperSecret").unwrap(); assert_ne!(reference, test); } #[test] + #[cfg(not(feature = "otpauth"))] fn comparison_different_digits() { - let reference = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); - let test = TOTP::new(Algorithm::SHA1, 8, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let reference = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret").unwrap(); + let test = TOTP::new(Algorithm::SHA1, 8, 1, 1, "TestSecretSuperSecret").unwrap(); assert_ne!(reference, test); } #[test] + #[cfg(not(feature = "otpauth"))] fn comparison_different_skew() { - let reference = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); - let test = TOTP::new(Algorithm::SHA1, 6, 0, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let reference = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret").unwrap(); + let test = TOTP::new(Algorithm::SHA1, 6, 0, 1, "TestSecretSuperSecret").unwrap(); assert_ne!(reference, test); } #[test] + #[cfg(not(feature = "otpauth"))] fn comparison_different_step() { - let reference = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); - let test = TOTP::new(Algorithm::SHA1, 6, 1, 30, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let reference = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret").unwrap(); + let test = TOTP::new(Algorithm::SHA1, 6, 1, 30, "TestSecretSuperSecret").unwrap(); assert_ne!(reference, test); } #[test] + #[cfg(not(feature = "otpauth"))] fn comparison_different_secret() { - let reference = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); - let test = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretDifferentSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let reference = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret").unwrap(); + let test = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretDifferentSecret").unwrap(); assert_ne!(reference, test); } @@ -557,20 +625,23 @@ mod tests { } #[test] + #[cfg(not(feature = "otpauth"))] fn returns_base32() { - let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret").unwrap(); assert_eq!(totp.get_secret_base32().as_str(), "KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ"); } #[test] + #[cfg(not(feature = "otpauth"))] fn generate_token() { - let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret").unwrap(); assert_eq!(totp.generate(1000).as_str(), "659761"); } #[test] + #[cfg(not(feature = "otpauth"))] fn generate_token_current() { - let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret").unwrap(); let time = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH).unwrap() .as_secs(); @@ -578,49 +649,56 @@ mod tests { } #[test] + #[cfg(not(feature = "otpauth"))] fn generates_token_sha256() { - let totp = TOTP::new(Algorithm::SHA256, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let totp = TOTP::new(Algorithm::SHA256, 6, 1, 1, "TestSecretSuperSecret").unwrap(); assert_eq!(totp.generate(1000).as_str(), "076417"); } #[test] + #[cfg(not(feature = "otpauth"))] fn generates_token_sha512() { - let totp = TOTP::new(Algorithm::SHA512, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let totp = TOTP::new(Algorithm::SHA512, 6, 1, 1, "TestSecretSuperSecret").unwrap(); assert_eq!(totp.generate(1000).as_str(), "473536"); } #[test] + #[cfg(not(feature = "otpauth"))] fn checks_token() { - let totp = TOTP::new(Algorithm::SHA1, 6, 0, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let totp = TOTP::new(Algorithm::SHA1, 6, 0, 1, "TestSecretSuperSecret").unwrap(); assert!(totp.check("659761", 1000)); } #[test] + #[cfg(not(feature = "otpauth"))] fn checks_token_current() { - let totp = TOTP::new(Algorithm::SHA1, 6, 0, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let totp = TOTP::new(Algorithm::SHA1, 6, 0, 1, "TestSecretSuperSecret").unwrap(); assert!(totp.check_current(&totp.generate_current().unwrap()).unwrap()); assert!(!totp.check_current("bogus").unwrap()); } #[test] + #[cfg(not(feature = "otpauth"))] fn checks_token_with_skew() { - let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret").unwrap(); assert!( totp.check("174269", 1000) && totp.check("659761", 1000) && totp.check("260393", 1000) ); } #[test] + #[cfg(not(feature = "otpauth"))] fn next_step() { - let totp = TOTP::new(Algorithm::SHA1, 6, 1, 30, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let totp = TOTP::new(Algorithm::SHA1, 6, 1, 30, "TestSecretSuperSecret").unwrap(); assert!(totp.next_step(0) == 30); assert!(totp.next_step(29) == 30); assert!(totp.next_step(30) == 60); } #[test] + #[cfg(not(feature = "otpauth"))] fn next_step_current() { - let totp = TOTP::new(Algorithm::SHA1, 6, 1, 30, "TestSecretSuperSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap(); + let totp = TOTP::new(Algorithm::SHA1, 6, 1, 30, "TestSecretSuperSecret").unwrap(); let t = system_time().unwrap(); assert!(totp.next_step_current().unwrap() == totp.next_step(t)); } @@ -689,7 +767,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn from_url_query_different_issuers() { - let totp = TOTP::>::from_url("otpauth://totp/GitHub:test?issuer=Gitlab&secret=TestSecretSuperSecret&digits=8&period=60&algorithm=SHA256"); + let totp = TOTP::>::from_url("otpauth://totp/GitHub:test?issuer=Gitlab&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=SHA256"); assert!(totp.is_err()); assert!(matches!(totp.unwrap_err(), TotpUrlError::IssuerMistmatch(_, _))); } diff --git a/src/rfc.rs b/src/rfc.rs index 808a1e2..f5f763c 100644 --- a/src/rfc.rs +++ b/src/rfc.rs @@ -59,8 +59,6 @@ pub fn assert_secret_length(secret: &[u8]) -> Result<(), Rfc6238Error> { /// /// // optional, set digits, issuer, account_name /// rfc.digits(8).unwrap(); -/// rfc.issuer("issuer".to_string()); -/// rfc.account_name("user-account".to_string()); /// /// let totp = TOTP::from_rfc6238(rfc).unwrap(); /// ``` @@ -77,10 +75,12 @@ pub struct Rfc6238> { step: u64, /// As per [rfc-4226](https://tools.ietf.org/html/rfc4226#section-4) the secret should come from a strong source, most likely a CSPRNG. It should be at least 128 bits, but 160 are recommended secret: T, + #[cfg(feature = "otpauth")] /// The "Github" part of "Github:constantoine@github.com". Must not contain a colon `:` /// For example, the name of your service/website. /// Not mandatory, but strongly recommended! issuer: Option, + #[cfg(feature = "otpauth")] /// The "constantoine@github.com" part of "Github:constantoine@github.com". Must not contain a colon `:` /// For example, the name of your user's account. account_name: String, @@ -94,6 +94,7 @@ impl> Rfc6238 { /// will return a [Rfc6238Error](enum.Rfc6238Error.html) when /// - `digits` is lower than 6 or higher than 8 /// - `secret` is smaller than 128 bits (16 characters) + #[cfg(feature = "otpauth")] pub fn new( digits: usize, secret: T, @@ -113,6 +114,22 @@ impl> Rfc6238 { account_name, }) } + #[cfg(not(feature = "otpauth"))] + pub fn new( + digits: usize, + secret: T, + ) -> Result, Rfc6238Error> { + assert_digits(&digits)?; + assert_secret_length(secret.as_ref())?; + + Ok(Rfc6238 { + algorithm: Algorithm::SHA1, + digits, + skew: 1, + step: 30, + secret, + }) + } /// Create an [rfc-6238](https://tools.ietf.org/html/rfc6238) compliant set of options that can be turned into a [TOTP](struct.TOTP.html), /// with a default value of 6 for `digits`, None `issuer` and an empty account @@ -122,8 +139,14 @@ impl> Rfc6238 { /// will return a [Rfc6238Error](enum.Rfc6238Error.html) when /// - `digits` is lower than 6 or higher than 8 /// - `secret` is smaller than 128 bits (16 characters) + #[cfg(feature = "otpauth")] pub fn with_defaults(secret: T) -> Result, Rfc6238Error> { - Rfc6238::new(6, secret, None, "".to_string()) + Rfc6238::new(6, secret, Some("".to_string()), "".to_string()) + } + + #[cfg(not(feature = "otpauth"))] + pub fn with_defaults(secret: T) -> Result, Rfc6238Error> { + Rfc6238::new(6, secret) } /// Set the `digits` @@ -133,17 +156,36 @@ impl> Rfc6238 { Ok(()) } + #[cfg(feature = "otpauth")] /// Set the `issuer` pub fn issuer(&mut self, value: String) { self.issuer = Some(value); } - /// Seet the `account_name` + #[cfg(feature = "otpauth")] + /// Set the `account_name` pub fn account_name(&mut self, value: String) { self.account_name = value; } } +#[cfg(not(feature = "otpauth"))] +impl> TryFrom> for TOTP { + type Error = TotpUrlError; + + /// Try to create a [TOTP](struct.TOTP.html) from a [Rfc6238](struct.Rfc6238.html) config + fn try_from(rfc: Rfc6238) -> Result { + TOTP::new( + rfc.algorithm, + rfc.digits, + rfc.skew, + rfc.step, + rfc.secret, + ) + } +} + +#[cfg(feature = "otpauth")] impl> TryFrom> for TOTP { type Error = TotpUrlError; @@ -156,30 +198,39 @@ impl> TryFrom> for TOTP { rfc.step, rfc.secret, rfc.issuer, - rfc.account_name, + rfc.account_name ) } } #[cfg(test)] mod tests { + #[cfg(feature = "otpauth")] use crate::TotpUrlError; - use super::{Rfc6238, Rfc6238Error, TOTP}; + use super::{Rfc6238, TOTP}; + + #[cfg(not(feature = "otpauth"))] + use super::Rfc6238Error; + + #[cfg(not(feature = "otpauth"))] + use crate::Secret; const GOOD_SECRET: &str = "01234567890123456789"; + #[cfg(feature = "otpauth")] const ISSUER: Option<&str> = None; + #[cfg(feature = "otpauth")] const ACCOUNT: &str = "valid-account"; + #[cfg(feature = "otpauth")] const INVALID_ACCOUNT: &str = ":invalid-account"; #[test] + #[cfg(not(feature = "otpauth"))] fn new_rfc_digits() { for x in 0..=20 { let rfc = Rfc6238::new( x, GOOD_SECRET.to_string(), - ISSUER.map(str::to_string), - ACCOUNT.to_string(), ); if !(6..=8).contains(&x) { assert!(rfc.is_err()); @@ -191,6 +242,7 @@ mod tests { } #[test] + #[cfg(not(feature = "otpauth"))] fn new_rfc_secret() { let mut secret = String::from(""); for _ in 0..=20 { @@ -198,8 +250,6 @@ mod tests { let rfc = Rfc6238::new( 6, secret.clone(), - ISSUER.map(str::to_string), - ACCOUNT.to_string(), ); let rfc_default = Rfc6238::with_defaults(secret.clone()); if secret.len() < 16 { @@ -215,12 +265,11 @@ mod tests { } #[test] + #[cfg(not(feature = "otpauth"))] fn rfc_to_totp_ok() { let rfc = Rfc6238::new( 8, GOOD_SECRET.to_string(), - ISSUER.map(str::to_string), - ACCOUNT.to_string(), ) .unwrap(); let totp = TOTP::try_from(rfc); @@ -228,14 +277,29 @@ mod tests { let otp = totp.unwrap(); assert_eq!(&otp.secret, GOOD_SECRET); assert_eq!(otp.algorithm, crate::Algorithm::SHA1); - assert_eq!(&otp.account_name, ACCOUNT); assert_eq!(otp.digits, 8); - assert_eq!(otp.issuer, ISSUER.map(str::to_string)); assert_eq!(otp.skew, 1); assert_eq!(otp.step, 30) } #[test] + #[cfg(not(feature = "otpauth"))] + fn rfc_to_totp_ok_2() { + let rfc = Rfc6238::with_defaults( + Secret::Encoded("KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ".to_string()).to_bytes().unwrap(), + ) + .unwrap(); + let totp = TOTP::try_from(rfc); + assert!(totp.is_ok()); + let otp = totp.unwrap(); + assert_eq!(otp.algorithm, crate::Algorithm::SHA1); + assert_eq!(otp.digits, 6); + assert_eq!(otp.skew, 1); + assert_eq!(otp.step, 30) + } + + #[test] + #[cfg(feature = "otpauth")] fn rfc_to_totp_fail() { let rfc = Rfc6238::new( 8, @@ -250,14 +314,23 @@ mod tests { } #[test] + #[cfg(feature = "otpauth")] + fn rfc_to_totp_ok() { + let rfc = Rfc6238::new( + 8, + GOOD_SECRET.to_string(), + ISSUER.map(str::to_string), + ACCOUNT.to_string(), + ) + .unwrap(); + let totp = TOTP::try_from(rfc); + assert!(!totp.is_err()); + } + + #[test] + #[cfg(not(feature = "otpauth"))] fn rfc_with_default_set_values() { - let new_account = "new-account"; - let new_issuer = String::from("new-issuer"); let mut rfc = Rfc6238::with_defaults(GOOD_SECRET.to_string()).unwrap(); - rfc.issuer(new_issuer.clone()); - assert_eq!(rfc.issuer, Some(new_issuer)); - rfc.account_name(new_account.to_string()); - assert_eq!(rfc.account_name, new_account.to_string()); let fail = rfc.digits(4); assert!(fail.is_err()); assert!(matches!(fail.unwrap_err(), Rfc6238Error::InvalidDigits(_)));