Make otpauth fields only appear with otpauth feature

Signed-off-by: constantoine <cleo.rebert-ext@treezor.com>
This commit is contained in:
constantoine 2022-08-09 11:05:36 +02:00
parent 0103e7a6e5
commit cd903afbd7
No known key found for this signature in database
GPG Key ID: 0FA097951CF65367
6 changed files with 278 additions and 52 deletions

View File

@ -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 () {}

View File

@ -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);
}

View File

@ -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());
}

View File

@ -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 {

View File

@ -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<T = Vec<u8>> {
///
/// 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<String>,
#[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 <T: AsRef<[u8]>> PartialEq for TOTP<T> {
}
}
#[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<T: AsRef<[u8]>> TOTP<T> {
#[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<T: AsRef<[u8]>> TOTP<T> {
})
}
#[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<TOTP<T>, 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::<Vec<u8>>::from_url("otpauth://totp/GitHub:test?issuer=Gitlab&secret=TestSecretSuperSecret&digits=8&period=60&algorithm=SHA256");
let totp = TOTP::<Vec<u8>>::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(_, _)));
}

View File

@ -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<T = Vec<u8>> {
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<String>,
#[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<T: AsRef<[u8]>> Rfc6238<T> {
/// 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<T: AsRef<[u8]>> Rfc6238<T> {
account_name,
})
}
#[cfg(not(feature = "otpauth"))]
pub fn new(
digits: usize,
secret: T,
) -> Result<Rfc6238<T>, 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<T: AsRef<[u8]>> Rfc6238<T> {
/// 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<Rfc6238<T>, 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<Rfc6238<T>, Rfc6238Error> {
Rfc6238::new(6, secret)
}
/// Set the `digits`
@ -133,17 +156,36 @@ impl<T: AsRef<[u8]>> Rfc6238<T> {
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<T: AsRef<[u8]>> TryFrom<Rfc6238<T>> for TOTP<T> {
type Error = TotpUrlError;
/// Try to create a [TOTP](struct.TOTP.html) from a [Rfc6238](struct.Rfc6238.html) config
fn try_from(rfc: Rfc6238<T>) -> Result<Self, Self::Error> {
TOTP::new(
rfc.algorithm,
rfc.digits,
rfc.skew,
rfc.step,
rfc.secret,
)
}
}
#[cfg(feature = "otpauth")]
impl<T: AsRef<[u8]>> TryFrom<Rfc6238<T>> for TOTP<T> {
type Error = TotpUrlError;
@ -156,30 +198,39 @@ impl<T: AsRef<[u8]>> TryFrom<Rfc6238<T>> for TOTP<T> {
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(_)));