Support zeroize feature.
This commit is contained in:
parent
c36b3a9507
commit
28ebb0e97c
|
@ -20,6 +20,7 @@ otpauth = ["url", "urlencoding"]
|
|||
qr = ["qrcodegen", "image", "base64", "otpauth"]
|
||||
serde_support = ["serde"]
|
||||
gen_secret = ["rand"]
|
||||
zeroize = ["dep:zeroize"]
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||
|
@ -33,4 +34,5 @@ constant_time_eq = "~0.2.1"
|
|||
qrcodegen = { version = "~1.8", optional = true }
|
||||
image = { version = "~0.24.2", features = ["png"], optional = true, default-features = false}
|
||||
base64 = { version = "~0.13", optional = true }
|
||||
rand = { version = "~0.8.5", features = ["std_rng", "std"], optional = true, default-features = false }
|
||||
rand = { version = "~0.8.5", features = ["std_rng", "std"], optional = true, default-features = false }
|
||||
zeroize = { version = "1.5.7", features = ["alloc", "derive"], optional = true }
|
|
@ -17,6 +17,8 @@ With optional feature "otpauth", support parsing the TOTP parameters from an `ot
|
|||
With optional feature "serde_support", library-defined types `TOTP` and `Algorithm` and will be Deserialize-able and Serialize-able.
|
||||
### gen_secret
|
||||
With optional feature "gen_secret", a secret will be generated for you to store in database.
|
||||
### zeroize
|
||||
Securely zero secret information when the TOTP struct is dropped.
|
||||
|
||||
|
||||
# Examples
|
||||
|
|
|
@ -2,7 +2,7 @@ use totp_rs::{Rfc6238, TOTP};
|
|||
|
||||
#[cfg(feature = "otpauth")]
|
||||
fn main() {
|
||||
let mut rfc = Rfc6238::with_defaults("totp-sercret-123").unwrap();
|
||||
let mut rfc = Rfc6238::with_defaults("totp-sercret-123".as_bytes().to_vec()).unwrap();
|
||||
|
||||
// optional, set digits, issuer, account_name
|
||||
rfc.digits(8).unwrap();
|
||||
|
|
|
@ -2,7 +2,7 @@ use totp_rs::{Algorithm, TOTP};
|
|||
|
||||
#[cfg(not(feature = "otpauth"))]
|
||||
fn main() {
|
||||
let totp = TOTP::new(Algorithm::SHA1, 6, 1, 30, "my-secret".to_string()).unwrap();
|
||||
let totp = TOTP::new(Algorithm::SHA1, 6, 1, 30, "my-secret".as_bytes().to_vec()).unwrap();
|
||||
|
||||
loop {
|
||||
println!(
|
||||
|
@ -22,7 +22,7 @@ fn main() {
|
|||
6,
|
||||
1,
|
||||
30,
|
||||
"my-secret".to_string(),
|
||||
"my-secret".as_bytes().to_vec(),
|
||||
Some("Github".to_string()),
|
||||
"constantoine@github.com".to_string(),
|
||||
)
|
||||
|
|
80
src/lib.rs
80
src/lib.rs
|
@ -36,7 +36,7 @@
|
|||
//! 6,
|
||||
//! 1,
|
||||
//! 30,
|
||||
//! "supersecret_topsecret",
|
||||
//! "supersecret_topsecret".as_bytes().to_vec(),
|
||||
//! Some("Github".to_string()),
|
||||
//! "constantoine@github.com".to_string(),
|
||||
//! ).unwrap();
|
||||
|
@ -126,8 +126,10 @@ fn system_time() -> Result<u64, SystemTimeError> {
|
|||
/// TOTP holds informations as to how to generate an auth code and validate it. Its [secret](struct.TOTP.html#structfield.secret) field is sensitive data, treat it accordingly
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
|
||||
pub struct TOTP<T = Vec<u8>> {
|
||||
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
|
||||
pub struct TOTP {
|
||||
/// SHA-1 is the most widespread algorithm used, and for totp pursposes, SHA-1 hash collisions are [not a problem](https://tools.ietf.org/html/rfc4226#appendix-B.2) as HMAC-SHA-1 is not impacted. It's also the main one cited in [rfc-6238](https://tools.ietf.org/html/rfc6238#section-3) even though the [reference implementation](https://tools.ietf.org/html/rfc6238#appendix-A) permits the use of SHA-1, SHA-256 and SHA-512. Not all clients support other algorithms then SHA-1
|
||||
#[cfg_attr(feature = "zeroize", zeroize(skip))]
|
||||
pub algorithm: Algorithm,
|
||||
/// The number of digits composing the auth code. Per [rfc-4226](https://tools.ietf.org/html/rfc4226#section-5.3), this can oscilate between 6 and 8 digits
|
||||
pub digits: usize,
|
||||
|
@ -138,7 +140,7 @@ pub struct TOTP<T = Vec<u8>> {
|
|||
/// 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
|
||||
///
|
||||
/// non-encoded value
|
||||
pub secret: T,
|
||||
pub secret: Vec<u8>,
|
||||
#[cfg(feature = "otpauth")]
|
||||
/// The "Github" part of "Github:constantoine@github.com". Must not contain a colon `:`
|
||||
/// For example, the name of your service/website.
|
||||
|
@ -150,7 +152,7 @@ pub struct TOTP<T = Vec<u8>> {
|
|||
pub account_name: String,
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> PartialEq for TOTP<T> {
|
||||
impl PartialEq for TOTP {
|
||||
/// Will not check for issuer and account_name equality
|
||||
/// As they aren't taken in account for token generation/token checking
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
|
@ -200,7 +202,7 @@ impl Default for TOTP {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> TOTP<T> {
|
||||
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
|
||||
///
|
||||
|
@ -225,10 +227,10 @@ impl<T: AsRef<[u8]>> TOTP<T> {
|
|||
digits: usize,
|
||||
skew: u8,
|
||||
step: u64,
|
||||
secret: T,
|
||||
secret: Vec<u8>,
|
||||
issuer: Option<String>,
|
||||
account_name: String,
|
||||
) -> Result<TOTP<T>, TotpUrlError> {
|
||||
) -> Result<TOTP, TotpUrlError> {
|
||||
crate::rfc::assert_digits(&digits)?;
|
||||
crate::rfc::assert_secret_length(secret.as_ref())?;
|
||||
if issuer.is_some() && issuer.as_ref().unwrap().contains(':') {
|
||||
|
@ -288,7 +290,7 @@ impl<T: AsRef<[u8]>> TOTP<T> {
|
|||
/// # Errors
|
||||
///
|
||||
/// Will return an error in case issuer or label contain the character ':'
|
||||
pub fn from_rfc6238(rfc: Rfc6238<T>) -> Result<TOTP<T>, TotpUrlError> {
|
||||
pub fn from_rfc6238(rfc: Rfc6238) -> Result<TOTP, TotpUrlError> {
|
||||
TOTP::try_from(rfc)
|
||||
}
|
||||
|
||||
|
@ -369,7 +371,7 @@ impl<T: AsRef<[u8]>> TOTP<T> {
|
|||
|
||||
/// Generate a TOTP from the standard otpauth URL
|
||||
#[cfg(feature = "otpauth")]
|
||||
pub fn from_url<S: AsRef<str>>(url: S) -> Result<TOTP<Vec<u8>>, TotpUrlError> {
|
||||
pub fn from_url<S: AsRef<str>>(url: S) -> Result<TOTP, TotpUrlError> {
|
||||
let url = Url::parse(url.as_ref()).map_err(TotpUrlError::Url)?;
|
||||
if url.scheme() != "otpauth" {
|
||||
return Err(TotpUrlError::Scheme(url.scheme().to_string()));
|
||||
|
@ -576,7 +578,7 @@ mod tests {
|
|||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
Some("Github:".to_string()),
|
||||
"constantoine@github.com".to_string(),
|
||||
);
|
||||
|
@ -592,7 +594,7 @@ mod tests {
|
|||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
Some("Github".to_string()),
|
||||
"constantoine:github.com".to_string(),
|
||||
);
|
||||
|
@ -608,7 +610,7 @@ mod tests {
|
|||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
None,
|
||||
"constantoine:github.com".to_string(),
|
||||
);
|
||||
|
@ -624,7 +626,7 @@ mod tests {
|
|||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
Some("Github".to_string()),
|
||||
"constantoine@github.com".to_string(),
|
||||
)
|
||||
|
@ -634,7 +636,7 @@ mod tests {
|
|||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
Some("Github".to_string()),
|
||||
"constantoine@github.com".to_string(),
|
||||
)
|
||||
|
@ -690,7 +692,7 @@ mod tests {
|
|||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
None,
|
||||
"constantoine@github.com".to_string(),
|
||||
)
|
||||
|
@ -707,7 +709,7 @@ mod tests {
|
|||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
Some("Github".to_string()),
|
||||
"constantoine@github.com".to_string(),
|
||||
)
|
||||
|
@ -724,7 +726,7 @@ mod tests {
|
|||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
Some("Github".to_string()),
|
||||
"constantoine@github.com".to_string(),
|
||||
)
|
||||
|
@ -741,7 +743,7 @@ mod tests {
|
|||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
Some("Github".to_string()),
|
||||
"constantoine@github.com".to_string(),
|
||||
)
|
||||
|
@ -767,7 +769,7 @@ mod tests {
|
|||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
Some("Github".to_string()),
|
||||
"constantoine@github.com".to_string(),
|
||||
)
|
||||
|
@ -866,19 +868,19 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "otpauth")]
|
||||
fn from_url_err() {
|
||||
assert!(TOTP::<Vec<u8>>::from_url("otpauth://hotp/123").is_err());
|
||||
assert!(TOTP::<Vec<u8>>::from_url("otpauth://totp/GitHub:test").is_err());
|
||||
assert!(TOTP::<Vec<u8>>::from_url(
|
||||
assert!(TOTP::from_url("otpauth://hotp/123").is_err());
|
||||
assert!(TOTP::from_url("otpauth://totp/GitHub:test").is_err());
|
||||
assert!(TOTP::from_url(
|
||||
"otpauth://totp/GitHub:test:?secret=ABC&digits=8&period=60&algorithm=SHA256"
|
||||
)
|
||||
.is_err());
|
||||
assert!(TOTP::<Vec<u8>>::from_url("otpauth://totp/Github:constantoine%40github.com?issuer=GitHub&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=6&algorithm=SHA1").is_err())
|
||||
assert!(TOTP::from_url("otpauth://totp/Github:constantoine%40github.com?issuer=GitHub&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=6&algorithm=SHA1").is_err())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "otpauth")]
|
||||
fn from_url_default() {
|
||||
let totp = TOTP::<Vec<u8>>::from_url(
|
||||
let totp = TOTP::from_url(
|
||||
"otpauth://totp/GitHub:test?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ",
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -899,7 +901,7 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "otpauth")]
|
||||
fn from_url_query() {
|
||||
let totp = TOTP::<Vec<u8>>::from_url("otpauth://totp/GitHub:test?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=SHA256").unwrap();
|
||||
let totp = TOTP::from_url("otpauth://totp/GitHub:test?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=SHA256").unwrap();
|
||||
assert_eq!(
|
||||
totp.secret,
|
||||
base32::decode(
|
||||
|
@ -917,7 +919,7 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "otpauth")]
|
||||
fn from_url_query_sha512() {
|
||||
let totp = TOTP::<Vec<u8>>::from_url("otpauth://totp/GitHub:test?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=SHA512").unwrap();
|
||||
let totp = TOTP::from_url("otpauth://totp/GitHub:test?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=SHA512").unwrap();
|
||||
assert_eq!(
|
||||
totp.secret,
|
||||
base32::decode(
|
||||
|
@ -935,13 +937,13 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "otpauth")]
|
||||
fn from_url_to_url() {
|
||||
let totp = TOTP::<Vec<u8>>::from_url("otpauth://totp/Github:constantoine%40github.com?issuer=Github&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=6&algorithm=SHA1").unwrap();
|
||||
let totp = TOTP::from_url("otpauth://totp/Github:constantoine%40github.com?issuer=Github&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=6&algorithm=SHA1").unwrap();
|
||||
let totp_bis = TOTP::new(
|
||||
Algorithm::SHA1,
|
||||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
Some("Github".to_string()),
|
||||
"constantoine@github.com".to_string(),
|
||||
)
|
||||
|
@ -952,7 +954,7 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "otpauth")]
|
||||
fn from_url_unknown_param() {
|
||||
let totp = TOTP::<Vec<u8>>::from_url("otpauth://totp/GitHub:test?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=SHA256&foo=bar").unwrap();
|
||||
let totp = TOTP::from_url("otpauth://totp/GitHub:test?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=SHA256&foo=bar").unwrap();
|
||||
assert_eq!(
|
||||
totp.secret,
|
||||
base32::decode(
|
||||
|
@ -970,25 +972,25 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "otpauth")]
|
||||
fn from_url_issuer_special() {
|
||||
let totp = TOTP::<Vec<u8>>::from_url("otpauth://totp/Github%40:constantoine%40github.com?issuer=Github%40&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=6&algorithm=SHA1").unwrap();
|
||||
let totp = TOTP::from_url("otpauth://totp/Github%40:constantoine%40github.com?issuer=Github%40&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=6&algorithm=SHA1").unwrap();
|
||||
let totp_bis = TOTP::new(
|
||||
Algorithm::SHA1,
|
||||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
Some("Github@".to_string()),
|
||||
"constantoine@github.com".to_string(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(totp.get_url(), totp_bis.get_url());
|
||||
assert_eq!(totp.issuer.unwrap(), "Github@");
|
||||
assert_eq!(totp.issuer.as_ref().unwrap(), "Github@");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "otpauth")]
|
||||
fn from_url_query_issuer() {
|
||||
let totp = TOTP::<Vec<u8>>::from_url("otpauth://totp/GitHub:test?issuer=GitHub&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=SHA256").unwrap();
|
||||
let totp = TOTP::from_url("otpauth://totp/GitHub:test?issuer=GitHub&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=SHA256").unwrap();
|
||||
assert_eq!(
|
||||
totp.secret,
|
||||
base32::decode(
|
||||
|
@ -1001,13 +1003,13 @@ mod tests {
|
|||
assert_eq!(totp.digits, 8);
|
||||
assert_eq!(totp.skew, 1);
|
||||
assert_eq!(totp.step, 60);
|
||||
assert_eq!(totp.issuer.unwrap(), "GitHub");
|
||||
assert_eq!(totp.issuer.as_ref().unwrap(), "GitHub");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "otpauth")]
|
||||
fn from_url_wrong_scheme() {
|
||||
let totp = TOTP::<Vec<u8>>::from_url("http://totp/GitHub:test?issuer=GitHub&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=SHA256");
|
||||
let totp = TOTP::from_url("http://totp/GitHub:test?issuer=GitHub&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=SHA256");
|
||||
assert!(totp.is_err());
|
||||
let err = totp.unwrap_err();
|
||||
assert!(matches!(err, TotpUrlError::Scheme(_)));
|
||||
|
@ -1016,7 +1018,7 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "otpauth")]
|
||||
fn from_url_wrong_algo() {
|
||||
let totp = TOTP::<Vec<u8>>::from_url("otpauth://totp/GitHub:test?issuer=GitHub&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=MD5");
|
||||
let totp = TOTP::from_url("otpauth://totp/GitHub:test?issuer=GitHub&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=8&period=60&algorithm=MD5");
|
||||
assert!(totp.is_err());
|
||||
let err = totp.unwrap_err();
|
||||
assert!(matches!(err, TotpUrlError::Algorithm(_)));
|
||||
|
@ -1025,7 +1027,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=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&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(),
|
||||
|
@ -1043,7 +1045,7 @@ mod tests {
|
|||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
Some("Github".to_string()),
|
||||
"constantoine@github.com".to_string(),
|
||||
)
|
||||
|
@ -1069,7 +1071,7 @@ mod tests {
|
|||
6,
|
||||
1,
|
||||
1,
|
||||
"TestSecretSuperSecret",
|
||||
"TestSecretSuperSecret".as_bytes().to_vec(),
|
||||
Some("Github".to_string()),
|
||||
"constantoine@github.com".to_string(),
|
||||
)
|
||||
|
|
26
src/rfc.rs
26
src/rfc.rs
|
@ -54,7 +54,7 @@ pub fn assert_secret_length(secret: &[u8]) -> Result<(), Rfc6238Error> {
|
|||
/// use totp_rs::{Rfc6238, TOTP};
|
||||
///
|
||||
/// let mut rfc = Rfc6238::with_defaults(
|
||||
/// "totp-sercret-123"
|
||||
/// "totp-sercret-123".as_bytes().to_vec()
|
||||
/// ).unwrap();
|
||||
///
|
||||
/// // optional, set digits, issuer, account_name
|
||||
|
@ -64,7 +64,7 @@ pub fn assert_secret_length(secret: &[u8]) -> Result<(), Rfc6238Error> {
|
|||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
|
||||
pub struct Rfc6238<T = Vec<u8>> {
|
||||
pub struct Rfc6238 {
|
||||
/// SHA-1
|
||||
algorithm: Algorithm,
|
||||
/// The number of digits composing the auth code. Per [rfc-4226](https://tools.ietf.org/html/rfc4226#section-5.3), this can oscilate between 6 and 8 digits
|
||||
|
@ -74,7 +74,7 @@ pub struct Rfc6238<T = Vec<u8>> {
|
|||
/// The recommended value per [rfc-6238](https://tools.ietf.org/html/rfc6238#section-5.2) is 30 seconds
|
||||
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,
|
||||
secret: Vec<u8>,
|
||||
#[cfg(feature = "otpauth")]
|
||||
/// The "Github" part of "Github:constantoine@github.com". Must not contain a colon `:`
|
||||
/// For example, the name of your service/website.
|
||||
|
@ -86,7 +86,7 @@ pub struct Rfc6238<T = Vec<u8>> {
|
|||
account_name: String,
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> Rfc6238<T> {
|
||||
impl Rfc6238 {
|
||||
/// Create an [rfc-6238](https://tools.ietf.org/html/rfc6238) compliant set of options that can be turned into a [TOTP](struct.TOTP.html)
|
||||
///
|
||||
/// # Errors
|
||||
|
@ -97,10 +97,10 @@ impl<T: AsRef<[u8]>> Rfc6238<T> {
|
|||
#[cfg(feature = "otpauth")]
|
||||
pub fn new(
|
||||
digits: usize,
|
||||
secret: T,
|
||||
secret: Vec<u8>,
|
||||
issuer: Option<String>,
|
||||
account_name: String,
|
||||
) -> Result<Rfc6238<T>, Rfc6238Error> {
|
||||
) -> Result<Rfc6238, Rfc6238Error> {
|
||||
assert_digits(&digits)?;
|
||||
assert_secret_length(secret.as_ref())?;
|
||||
|
||||
|
@ -137,7 +137,7 @@ impl<T: AsRef<[u8]>> Rfc6238<T> {
|
|||
/// - `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> {
|
||||
pub fn with_defaults(secret: Vec<u8>) -> Result<Rfc6238, Rfc6238Error> {
|
||||
Rfc6238::new(6, secret, Some("".to_string()), "".to_string())
|
||||
}
|
||||
|
||||
|
@ -177,11 +177,11 @@ impl<T: AsRef<[u8]>> TryFrom<Rfc6238<T>> for TOTP<T> {
|
|||
}
|
||||
|
||||
#[cfg(feature = "otpauth")]
|
||||
impl<T: AsRef<[u8]>> TryFrom<Rfc6238<T>> for TOTP<T> {
|
||||
impl TryFrom<Rfc6238> 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<T>) -> Result<Self, Self::Error> {
|
||||
fn try_from(rfc: Rfc6238) -> Result<Self, Self::Error> {
|
||||
TOTP::new(
|
||||
rfc.algorithm,
|
||||
rfc.digits,
|
||||
|
@ -289,7 +289,7 @@ mod tests {
|
|||
fn rfc_to_totp_fail() {
|
||||
let rfc = Rfc6238::new(
|
||||
8,
|
||||
GOOD_SECRET.to_string(),
|
||||
GOOD_SECRET.as_bytes().to_vec(),
|
||||
ISSUER.map(str::to_string),
|
||||
INVALID_ACCOUNT.to_string(),
|
||||
)
|
||||
|
@ -304,7 +304,7 @@ mod tests {
|
|||
fn rfc_to_totp_ok() {
|
||||
let rfc = Rfc6238::new(
|
||||
8,
|
||||
GOOD_SECRET.to_string(),
|
||||
GOOD_SECRET.as_bytes().to_vec(),
|
||||
ISSUER.map(str::to_string),
|
||||
ACCOUNT.to_string(),
|
||||
)
|
||||
|
@ -316,7 +316,7 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "otpauth")]
|
||||
fn rfc_with_default_set_values() {
|
||||
let mut rfc = Rfc6238::with_defaults(GOOD_SECRET.to_string()).unwrap();
|
||||
let mut rfc = Rfc6238::with_defaults(GOOD_SECRET.as_bytes().to_vec()).unwrap();
|
||||
let ok = rfc.digits(8);
|
||||
assert!(ok.is_ok());
|
||||
assert_eq!(rfc.account_name, "");
|
||||
|
@ -331,7 +331,7 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(not(feature = "otpauth"))]
|
||||
fn rfc_with_default_set_values() {
|
||||
let mut rfc = Rfc6238::with_defaults(GOOD_SECRET.to_string()).unwrap();
|
||||
let mut rfc = Rfc6238::with_defaults(GOOD_SECRET.as_bytes().to_vec()).unwrap();
|
||||
let fail = rfc.digits(4);
|
||||
assert!(fail.is_err());
|
||||
assert!(matches!(fail.unwrap_err(), Rfc6238Error::InvalidDigits(_)));
|
||||
|
|
Loading…
Reference in New Issue