From 8fa7bb30b27b60fb30008f0348d4c3659dd1f6bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9o=20Rebert?= Date: Tue, 12 Mar 2024 16:22:01 +0100 Subject: [PATCH 1/4] rename get -> to MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cléo Rebert --- README.md | 12 +++---- src/custom_providers.rs | 2 +- src/lib.rs | 78 +++++++++++++++++++++++++++++------------ 3 files changed, 63 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index dcdfc06..8fea9da 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ fn main() { Add it to your `Cargo.toml`: ```toml [dependencies.totp-rs] -version = "^5.3" +version = "^5.6" features = ["qr"] ``` You can then do something like: @@ -109,7 +109,7 @@ fn main() { Some("Github".to_string()), "constantoine@github.com".to_string(), ).unwrap(); - let qr_code = totp.get_qr_base64()?; + let qr_code = totp.to_qr_base64()?; println!("{}", qr_code); } ``` @@ -128,7 +128,7 @@ features = ["serde_support"] Add it to your `Cargo.toml`: ```toml [dependencies.totp-rs] -version = "^5.0" +version = "^5.6" features = ["otpauth"] ``` You can then do something like: @@ -147,7 +147,7 @@ fn main() { Add it to your `Cargo.toml`: ```toml [dependencies.totp-rs] -version = "^5.3" +version = "^5.6" features = ["gen_secret"] ``` You can then do something like: @@ -164,7 +164,7 @@ fn main() { Some("Github".to_string()), "constantoine@github.com".to_string(), ).unwrap(); - let qr_code = totp.get_qr_base64()?; + let qr_code = totp.to_qr_base64()?; println!("{}", qr_code); } ``` @@ -182,7 +182,7 @@ fn main() { Some("Github".to_string()), "constantoine@github.com".to_string(), ).unwrap(); - let qr_code = totp.get_qr_base64()?; + let qr_code = totp.to_qr_base64()?; println!("{}", qr_code); } ``` diff --git a/src/custom_providers.rs b/src/custom_providers.rs index 86750b1..3696bc2 100644 --- a/src/custom_providers.rs +++ b/src/custom_providers.rs @@ -56,7 +56,7 @@ mod test { #[cfg(feature = "otpauth")] fn get_url_steam() { let totp = TOTP::new_steam("TestSecretSuperSecret".into(), "constantoine".into()); - let url = totp.get_url(); + let url = totp.to_url(); assert_eq!(url.as_str(), "otpauth://steam/Steam:constantoine?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=5&algorithm=SHA1&issuer=Steam"); } } diff --git a/src/lib.rs b/src/lib.rs index 9976977..776bafd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -280,8 +280,8 @@ impl TOTP { issuer: Option, account_name: String, ) -> Result { - crate::rfc::assert_digits(&digits)?; - crate::rfc::assert_secret_length(secret.as_ref())?; + rfc::assert_digits(&digits)?; + rfc::assert_secret_length(secret.as_ref())?; if issuer.is_some() && issuer.as_ref().unwrap().contains(':') { return Err(TotpUrlError::Issuer(issuer.as_ref().unwrap().to_string())); } @@ -484,13 +484,21 @@ impl TOTP { } /// Will return the base32 representation of the secret, which might be useful when users want to manually add the secret to their authenticator - pub fn get_secret_base32(&self) -> String { + pub fn to_secret_base32(&self) -> String { base32::encode( base32::Alphabet::RFC4648 { padding: false }, self.secret.as_ref(), ) } + #[deprecated( + since = "5.6.0", + note = "get_secret_base32 has non-conventionnal name. Use to_secret_base32 instead. Will disappear in 6.0." + )] + pub fn get_secret_base32(&self) -> String { + self.to_secret_base32() + } + /// Generate a TOTP from the standard otpauth URL #[cfg(feature = "otpauth")] #[cfg_attr(docsrs, doc(cfg(feature = "otpauth")))] @@ -629,13 +637,23 @@ impl TOTP { Ok((algorithm, digits, 1, step, secret, issuer, account_name)) } + #[cfg(feature = "otpauth")] + #[cfg_attr(docsrs, doc(cfg(feature = "otpauth")))] + #[deprecated( + since = "5.6.0", + note = "get_url has non-conventionnal name. Use to_url instead. Will disappear in 6.0." + )] + pub fn get_url(&self) -> String { + self.to_url() + } + /// Will generate a standard URL used to automatically add TOTP auths. Usually used with qr codes /// /// Label and issuer will be URL-encoded if needed be /// Secret will be base 32'd without padding, as per RFC. #[cfg(feature = "otpauth")] #[cfg_attr(docsrs, doc(cfg(feature = "otpauth")))] - pub fn get_url(&self) -> String { + pub fn to_url(&self) -> String { #[allow(unused_mut)] let mut host = "totp"; #[cfg(feature = "steam")] @@ -643,7 +661,7 @@ impl TOTP { host = "steam"; } let account_name = urlencoding::encode(self.account_name.as_str()).to_string(); - let mut params = vec![format!("secret={}", self.get_secret_base32())]; + let mut params = vec![format!("secret={}", self.to_secret_base32())]; if self.digits != 6 { params.push(format!("digits={}", self.digits)); } @@ -670,13 +688,21 @@ impl TOTP { impl TOTP { #[deprecated( since = "5.3.0", - note = "get_qr was forcing the use of png as a base64. Use get_qr_base64 or get_qr_png instead. Will disappear in 6.0." + note = "get_qr was forcing the use of png as a base64. Use to_qr_base64 or to_qr_png instead. Will disappear in 6.0." )] pub fn get_qr(&self) -> Result { - let url = self.get_url(); + let url = self.to_url(); qrcodegen_image::draw_base64(&url) } + #[deprecated( + since = "5.6.0", + note = "get_qr_base64 has non-conventionnal name. Use to_qr_base64 instead. Will disappear in 6.0." + )] + pub fn get_qr_base64(&self) -> Result { + self.to_qr_base64() + } + /// Will return a qrcode to automatically add a TOTP as a base64 string. Needs feature `qr` to be enabled! /// Result will be in the form of a string containing a base64-encoded png, which you can embed in HTML without needing /// To store the png as a file. @@ -689,11 +715,19 @@ impl TOTP { /// /// It will also return an error in case it can't encode the qr into a png. /// This shouldn't happen unless either the qrcode library returns malformed data, or the image library doesn't encode the data correctly - pub fn get_qr_base64(&self) -> Result { - let url = self.get_url(); + pub fn to_qr_base64(&self) -> Result { + let url = self.to_url(); qrcodegen_image::draw_base64(&url) } + #[deprecated( + since = "5.6.0", + note = "get_qr_png has non-conventionnal name. Use to_qr_png instead. Will disappear in 6.0." + )] + pub fn get_qr_png(&self) -> Result, String> { + self.to_qr_png() + } + /// Will return a qrcode to automatically add a TOTP as a byte array. Needs feature `qr` to be enabled! /// Result will be in the form of a png file as bytes. /// @@ -705,8 +739,8 @@ impl TOTP { /// /// It will also return an error in case it can't encode the qr into a png. /// This shouldn't happen unless either the qrcode library returns malformed data, or the image library doesn't encode the data correctly - pub fn get_qr_png(&self) -> Result, String> { - let url = self.get_url(); + pub fn to_qr_png(&self) -> Result, String> { + let url = self.to_url(); qrcodegen_image::draw_png(&url) } } @@ -857,7 +891,7 @@ mod tests { "constantoine@github.com".to_string(), ) .unwrap(); - let url = totp.get_url(); + let url = totp.to_url(); assert_eq!( url.as_str(), "otpauth://totp/constantoine%40github.com?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ" @@ -877,7 +911,7 @@ mod tests { "constantoine@github.com".to_string(), ) .unwrap(); - let url = totp.get_url(); + let url = totp.to_url(); assert_eq!(url.as_str(), "otpauth://totp/Github:constantoine%40github.com?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&issuer=Github"); } @@ -894,7 +928,7 @@ mod tests { "constantoine@github.com".to_string(), ) .unwrap(); - let url = totp.get_url(); + let url = totp.to_url(); assert_eq!(url.as_str(), "otpauth://totp/Github:constantoine%40github.com?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&algorithm=SHA256&issuer=Github"); } @@ -911,7 +945,7 @@ mod tests { "constantoine@github.com".to_string(), ) .unwrap(); - let url = totp.get_url(); + let url = totp.to_url(); assert_eq!(url.as_str(), "otpauth://totp/Github:constantoine%40github.com?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&algorithm=SHA512&issuer=Github"); } @@ -1117,7 +1151,7 @@ mod tests { "constantoine@github.com".to_string(), ) .unwrap(); - assert_eq!(totp.get_url(), totp_bis.get_url()); + assert_eq!(totp.to_url(), totp_bis.to_url()); } #[test] @@ -1152,7 +1186,7 @@ mod tests { "constantoine@github.com".to_string(), ) .unwrap(); - assert_eq!(totp.get_url(), totp_bis.get_url()); + assert_eq!(totp.to_url(), totp_bis.to_url()); assert_eq!(totp.issuer.as_ref().unwrap(), "Github@"); } @@ -1170,7 +1204,7 @@ mod tests { "constantoine".to_string(), ) .unwrap(); - assert_eq!(totp.get_url(), totp_bis.get_url()); + assert_eq!(totp.to_url(), totp_bis.to_url()); assert_eq!(totp.account_name, "constantoine"); assert_eq!(totp.issuer.as_ref().unwrap(), "Github"); } @@ -1189,7 +1223,7 @@ mod tests { "constantoine".to_string(), ) .unwrap(); - assert_eq!(totp.get_url(), totp_bis.get_url()); + assert_eq!(totp.to_url(), totp_bis.to_url()); assert_eq!(totp.account_name, "constantoine"); assert_eq!(totp.issuer.as_ref().unwrap(), "Github"); } @@ -1258,7 +1292,7 @@ mod tests { "constantoine@github.com".to_string(), ) .unwrap(); - let url = totp.get_url(); + let url = totp.to_url(); let qr = qrcodegen::QrCode::encode_text(&url, qrcodegen::QrCodeEcc::Medium) .expect("could not generate qr"); let data = qrcodegen_image::draw_canvas(qr).into_raw(); @@ -1284,7 +1318,7 @@ mod tests { "constantoine@github.com".to_string(), ) .unwrap(); - let qr = totp.get_qr_base64(); + let qr = totp.to_qr_base64(); assert!(qr.is_ok()); } @@ -1301,7 +1335,7 @@ mod tests { "constantoine@github.com".to_string(), ) .unwrap(); - let qr = totp.get_qr_png(); + let qr = totp.to_qr_png(); assert!(qr.is_ok()); } } From 85b54704c6f86c694d693dbb8d303bba679792d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9o=20Rebert?= Date: Tue, 12 Mar 2024 16:24:19 +0100 Subject: [PATCH 2/4] Bump version to v5.6.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cléo Rebert --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index eeda56e..f91d6fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "totp-rs" -version = "5.5.1" +version = "5.6.0" authors = ["Cleo Rebert "] rust-version = "1.61" edition = "2021" From 5517d42f3e444984c46b9a8807ef59323e806c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9o=20Rebert?= Date: Mon, 10 Jun 2024 15:24:06 +0200 Subject: [PATCH 3/4] Update CHANGELOG and add cargo-semver-checks to CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cléo Rebert --- .github/workflows/rust.yml | 6 ++++++ CHANGELOG.md | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 51bdf83..90720ef 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -39,6 +39,12 @@ jobs: run: CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' LLVM_PROFILE_FILE='cargo-test-%p-%m.profraw' cargo test --features=gen_secret - name: otpauth+gensecret feature run: CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' LLVM_PROFILE_FILE='cargo-test-%p-%m.profraw' cargo test --features=gen_secret,otpauth + - name: Check for breaking changes + uses: obi1kenobi/cargo-semver-checks-action@v2 + with: + feature-group: all-features + verbose: true + continue-on-error: true - name: Create coverage file run: ./grcov . --binary-path ./target/debug/deps/ -s . -t cobertura --branch --ignore-not-existing --ignore '../*' --ignore "/*" -o target/coverage/cobertura.xml - name: Upload to codecov.io diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f6de61..0f957d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +# [5.6.0](https://github.com/constantoine/totp-rs/releases/tag/v5.6.0) (10/06/2024) +### Changes +- Deprecated `get_qr_base64` in favor of `to_qr_base64`. +- Deprecated `get_qr_png` in favor of `to_qr_png`. +- Deprecated `get_url` in favor of `to_url`. +- Deprecated `get_secret_base32` in favor of `to_secret_base32`. + +### Notes +- Deprecated methods will disappear with `6.0.0`. +- Added `cargo-semver-checks` as part of the CI. + +### Special thanks +* [@virtualritz](https://github.com/virtualritz) for bringing my attention to #65. + # [5.5.0](https://github.com/constantoine/totp-rs/releases/tag/v5.5.0) (19/01/2024) ### Changes - Documentation now indicates required feature. From 4d31fe8ff1c41a2adbd633d660f877e6db88eada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9o=20Rebert?= Date: Mon, 10 Jun 2024 15:38:36 +0200 Subject: [PATCH 4/4] Rename TOTP to Totp, add alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cléo Rebert --- README.md | 52 +++++------ examples/gen_secret.rs | 4 +- examples/rfc-6238.rs | 6 +- examples/secret.rs | 10 +-- examples/steam.rs | 6 +- examples/ttl.rs | 6 +- src/custom_providers.rs | 18 ++-- src/lib.rs | 191 +++++++++++++++++++++------------------- src/rfc.rs | 24 ++--- src/secret.rs | 16 ++-- 10 files changed, 172 insertions(+), 161 deletions(-) diff --git a/README.md b/README.md index 8fea9da..7d0f53a 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ Be aware that some authenticator apps will accept the `SHA256` and `SHA512` algo ### qr With optional feature "qr", you can use it to generate a base64 png qrcode. This will enable feature `otpauth`. ### otpauth -With optional feature "otpauth", support parsing the TOTP parameters from an `otpauth` URL, and generating an `otpauth` URL. It adds 2 fields to `TOTP`. +With optional feature "otpauth", support parsing the TOTP parameters from an `otpauth` URL, and generating an `otpauth` URL. It adds 2 fields to `Totp`. ### serde_support -With optional feature "serde_support", library-defined types `TOTP` and `Algorithm` and will be Deserialize-able and Serialize-able. +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. +Securely zero secret information when the `Totp` struct is dropped. ### steam Add support for Steam TOTP tokens. @@ -34,7 +34,7 @@ Add support for Steam TOTP tokens. 4. [Enable otpauth url support](#with-otpauth-url-support) 5. [Enable gen_secret support](#with-gensecret) 6. [With RFC-6238 compliant default](#with-rfc-6238-compliant-default) -7. [New TOTP from steam secret](#new-totp-from-steam-secret) +7. [New Totp from steam secret](#new-totp-from-steam-secret) ### Understanding Secret --- @@ -51,15 +51,15 @@ Secret::Encoded("KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ".to_string()) Add it to your `Cargo.toml`: ```toml [dependencies] -totp-rs = "^5.0" +totp-rs = "^5.6" ``` You can then do something like: ```Rust use std::time::SystemTime; -use totp_rs::{Algorithm, TOTP, Secret}; +use totp_rs::{Algorithm, Totp, Secret}; fn main() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, @@ -73,10 +73,10 @@ fn main() { Which is equivalent to: ```Rust use std::time::SystemTime; -use totp_rs::{Algorithm, TOTP, Secret}; +use totp_rs::{Algorithm, Totp, Secret}; fn main() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, @@ -97,10 +97,10 @@ features = ["qr"] ``` You can then do something like: ```Rust -use totp_rs::{Algorithm, TOTP, Secret}; +use totp_rs::{Algorithm, Totp, Secret}; fn main() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, @@ -133,11 +133,11 @@ features = ["otpauth"] ``` You can then do something like: ```Rust -use totp_rs::TOTP; +use totp_rs::Totp; fn main() { let otpauth = "otpauth://totp/GitHub:constantoine@github.com?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&issuer=GitHub"; - let totp = TOTP::from_url(otpauth).unwrap(); + let totp = Totp::from_url(otpauth).unwrap(); println!("{}", totp.generate_current().unwrap()); } ``` @@ -152,10 +152,10 @@ features = ["gen_secret"] ``` You can then do something like: ```Rust -use totp_rs::{Algorithm, TOTP, Secret}; +use totp_rs::{Algorithm, Totp, Secret}; fn main() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, @@ -170,10 +170,10 @@ fn main() { ``` Which is equivalent to ```Rust -use totp_rs::{Algorithm, TOTP, Secret}; +use totp_rs::{Algorithm, Totp, Secret}; fn main() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, @@ -191,7 +191,7 @@ fn main() { --- You can do something like this ```Rust -use totp_rs::{Algorithm, TOTP, Secret, Rfc6238}; +use totp_rs::{Algorithm, Totp, Secret, Rfc6238}; fn main () { let mut rfc = Rfc6238::with_defaults( @@ -202,37 +202,37 @@ fn main () { // optional, set digits rfc.digits(8).unwrap(); - // create a TOTP from rfc - let totp = TOTP::from_rfc6238(rfc).unwrap(); + // create a Totp from rfc + let totp = Totp::from_rfc6238(rfc).unwrap(); let code = totp.generate_current().unwrap(); println!("code: {}", code); } ``` With `gen_secret` feature, you can go even further and have all values by default and a secure secret. -Note: With `otpauth` feature, `TOTP.issuer` will be `None`, and `TOTP.account_name` will be `""`. Be sure to set those fields before generating an URL/QRCode +Note: With `otpauth` feature, `Totp.issuer` will be `None`, and `Totp.account_name` will be `""`. Be sure to set those fields before generating an URL/QRCode ```Rust fn main() { - let totp = TOTP::default(); + let totp = Totp::default(); let code = totp.generate_current().unwrap(); println!("code: {}", code); } ``` -### New TOTP from steam secret +### New Totp from steam secret --- Add it to your `Cargo.toml`: ```toml [dependencies.totp-rs] -version = "^5.3" +version = "^5.6" features = ["steam"] ``` You can then do something like: ```Rust -use totp_rs::{TOTP, Secret}; +use totp_rs::{Totp, Secret}; fn main() { - let totp = TOTP::new_steam( + let totp = Totp::new_steam( Secret::Encoded("KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ".to_string()).to_bytes().unwrap(), ).unwrap(); let code = totp.generate_current().unwrap(); diff --git a/examples/gen_secret.rs b/examples/gen_secret.rs index a536b20..1959d94 100644 --- a/examples/gen_secret.rs +++ b/examples/gen_secret.rs @@ -1,11 +1,11 @@ #[cfg(all(feature = "gen_secret", feature = "otpauth"))] -use totp_rs::{Algorithm, Secret, TOTP}; +use totp_rs::{Algorithm, Secret, Totp}; #[cfg(all(feature = "gen_secret", feature = "otpauth"))] fn main() { let secret = Secret::generate_secret(); - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, diff --git a/examples/rfc-6238.rs b/examples/rfc-6238.rs index ba4ef40..5c52cf7 100644 --- a/examples/rfc-6238.rs +++ b/examples/rfc-6238.rs @@ -1,4 +1,4 @@ -use totp_rs::{Rfc6238, TOTP}; +use totp_rs::{Rfc6238, Totp}; #[cfg(feature = "otpauth")] fn main() { @@ -10,7 +10,7 @@ fn main() { rfc.account_name("user-account".to_string()); // create a TOTP from rfc - let totp = TOTP::from_rfc6238(rfc).unwrap(); + let totp = Totp::from_rfc6238(rfc).unwrap(); let code = totp.generate_current().unwrap(); println!("code: {}", code); } @@ -23,7 +23,7 @@ fn main() { rfc.digits(8).unwrap(); // create a TOTP from rfc - let totp = TOTP::from_rfc6238(rfc).unwrap(); + let totp = Totp::from_rfc6238(rfc).unwrap(); let code = totp.generate_current().unwrap(); println!("code: {}", code); } diff --git a/examples/secret.rs b/examples/secret.rs index a5bb2a7..62402d1 100644 --- a/examples/secret.rs +++ b/examples/secret.rs @@ -1,10 +1,10 @@ -use totp_rs::{Algorithm, Secret, TOTP}; +use totp_rs::{Algorithm, Secret, Totp}; #[cfg(feature = "otpauth")] fn main() { // create TOTP from base32 secret let secret_b32 = Secret::Encoded(String::from("OBWGC2LOFVZXI4TJNZTS243FMNZGK5BNGEZDG")); - let totp_b32 = TOTP::new( + let totp_b32 = Totp::new( Algorithm::SHA1, 6, 1, @@ -31,7 +31,7 @@ fn main() { 0x63, 0x72, 0x65, 0x74, 0x2d, 0x31, 0x32, 0x33, ]; let secret_raw = Secret::Raw(secret.to_vec()); - let totp_raw = TOTP::new( + let totp_raw = Totp::new( Algorithm::SHA1, 6, 1, @@ -53,7 +53,7 @@ fn main() { 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(); + let totp_b32 = Totp::new(Algorithm::SHA1, 6, 1, 30, secret_b32.to_bytes().unwrap()).unwrap(); println!( "base32 {} ; raw {}", @@ -71,7 +71,7 @@ fn main() { 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(); + 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!( diff --git a/examples/steam.rs b/examples/steam.rs index 5c2d20a..f9d5dc8 100644 --- a/examples/steam.rs +++ b/examples/steam.rs @@ -1,12 +1,12 @@ #[cfg(feature = "steam")] -use totp_rs::{Secret, TOTP}; +use totp_rs::{Secret, Totp}; #[cfg(feature = "steam")] #[cfg(feature = "otpauth")] fn main() { // create TOTP from base32 secret let secret_b32 = Secret::Encoded(String::from("OBWGC2LOFVZXI4TJNZTS243FMNZGK5BNGEZDG")); - let totp_b32 = TOTP::new_steam(secret_b32.to_bytes().unwrap(), "user-account".to_string()); + let totp_b32 = Totp::new_steam(secret_b32.to_bytes().unwrap(), "user-account".to_string()); println!( "base32 {} ; raw {}", @@ -24,7 +24,7 @@ fn main() { fn main() { // create TOTP from base32 secret let secret_b32 = Secret::Encoded(String::from("OBWGC2LOFVZXI4TJNZTS243FMNZGK5BNGEZDG")); - let totp_b32 = TOTP::new_steam(secret_b32.to_bytes().unwrap()); + let totp_b32 = Totp::new_steam(secret_b32.to_bytes().unwrap()); println!( "base32 {} ; raw {}", diff --git a/examples/ttl.rs b/examples/ttl.rs index 806f6c4..dab2525 100644 --- a/examples/ttl.rs +++ b/examples/ttl.rs @@ -1,8 +1,8 @@ -use totp_rs::{Algorithm, TOTP}; +use totp_rs::{Algorithm, Totp}; #[cfg(not(feature = "otpauth"))] fn main() { - let totp = TOTP::new(Algorithm::SHA1, 6, 1, 30, "my-secret".as_bytes().to_vec()).unwrap(); + let totp = Totp::new(Algorithm::SHA1, 6, 1, 30, "my-secret".as_bytes().to_vec()).unwrap(); loop { println!( @@ -17,7 +17,7 @@ fn main() { #[cfg(feature = "otpauth")] fn main() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, diff --git a/src/custom_providers.rs b/src/custom_providers.rs index 3696bc2..93b5c79 100644 --- a/src/custom_providers.rs +++ b/src/custom_providers.rs @@ -1,9 +1,9 @@ #[cfg(feature = "steam")] -use crate::{Algorithm, TOTP}; +use crate::{Algorithm, Totp}; #[cfg(feature = "steam")] #[cfg_attr(docsrs, doc(cfg(feature = "steam")))] -impl TOTP { +impl Totp { #[cfg(feature = "otpauth")] /// Will create a new instance of TOTP using the Steam algorithm with given parameters. See [the doc](struct.TOTP.html#fields) for reference as to how to choose those values /// @@ -13,11 +13,11 @@ impl TOTP { /// # Example /// /// ```rust - /// use totp_rs::{Secret, TOTP}; + /// use totp_rs::{Secret, Totp}; /// let secret = Secret::Encoded("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".into()); - /// let totp = TOTP::new_steam(secret.to_bytes().unwrap(), "username".into()); + /// let totp = Totp::new_steam(secret.to_bytes().unwrap(), "username".into()); /// ``` - pub fn new_steam(secret: Vec, account_name: String) -> TOTP { + pub fn new_steam(secret: Vec, account_name: String) -> Totp { Self::new_unchecked( Algorithm::Steam, 5, @@ -38,11 +38,11 @@ impl TOTP { /// # Example /// /// ```rust - /// use totp_rs::{Secret, TOTP}; + /// use totp_rs::{Secret, Totp}; /// let secret = Secret::Encoded("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".to_string()); - /// let totp = TOTP::new_steam(secret.to_bytes().unwrap()); + /// let totp = Totp::new_steam(secret.to_bytes().unwrap()); /// ``` - pub fn new_steam(secret: Vec) -> TOTP { + pub fn new_steam(secret: Vec) -> Totp { Self::new_unchecked(Algorithm::Steam, 5, 1, 30, secret) } } @@ -55,7 +55,7 @@ mod test { #[test] #[cfg(feature = "otpauth")] fn get_url_steam() { - let totp = TOTP::new_steam("TestSecretSuperSecret".into(), "constantoine".into()); + let totp = Totp::new_steam("TestSecretSuperSecret".into(), "constantoine".into()); let url = totp.to_url(); assert_eq!(url.as_str(), "otpauth://steam/Steam:constantoine?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=5&algorithm=SHA1&issuer=Steam"); } diff --git a/src/lib.rs b/src/lib.rs index 776bafd..0ce80e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,9 +11,9 @@ //! ```rust //! # #[cfg(feature = "otpauth")] { //! use std::time::SystemTime; -//! use totp_rs::{Algorithm, TOTP, Secret}; +//! use totp_rs::{Algorithm, Totp, Secret}; //! -//! let totp = TOTP::new( +//! let totp = Totp::new( //! Algorithm::SHA1, //! 6, //! 1, @@ -29,9 +29,9 @@ //! //! ```rust //! # #[cfg(feature = "qr")] { -//! use totp_rs::{Algorithm, TOTP}; +//! use totp_rs::{Algorithm, Totp}; //! -//! let totp = TOTP::new( +//! let totp = Totp::new( //! Algorithm::SHA1, //! 6, //! 1, @@ -139,11 +139,17 @@ fn system_time() -> Result { Ok(t) } +#[deprecated( + since = "5.6.0", + note = "TOTP has non-conventionnal name. Use Totp instead. Will disappear in 6.0." +)] +pub type TOTP = Totp; + /// 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))] #[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))] -pub struct TOTP { +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, @@ -170,7 +176,7 @@ pub struct TOTP { pub account_name: String, } -impl PartialEq for TOTP { +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 { @@ -191,7 +197,7 @@ impl PartialEq for TOTP { } #[cfg(feature = "otpauth")] -impl core::fmt::Display for TOTP { +impl core::fmt::Display for Totp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, @@ -206,7 +212,7 @@ impl core::fmt::Display for TOTP { } #[cfg(not(feature = "otpauth"))] -impl core::fmt::Display for TOTP { +impl core::fmt::Display for Totp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, @@ -219,9 +225,9 @@ impl core::fmt::Display for TOTP { #[cfg(all(feature = "gen_secret", not(feature = "otpauth")))] // because `Default` is implemented regardless of `otpauth` feature we don't specify it here #[cfg_attr(docsrs, doc(cfg(feature = "gen_secret")))] -impl Default for TOTP { +impl Default for Totp { fn default() -> Self { - return TOTP::new( + return Totp::new( Algorithm::SHA1, 6, 1, @@ -234,9 +240,9 @@ impl Default for TOTP { #[cfg(all(feature = "gen_secret", feature = "otpauth"))] #[cfg_attr(docsrs, doc(cfg(feature = "gen_secret")))] -impl Default for TOTP { +impl Default for Totp { fn default() -> Self { - TOTP::new( + Totp::new( Algorithm::SHA1, 6, 1, @@ -249,7 +255,7 @@ impl Default for TOTP { } } -impl TOTP { +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 /// @@ -263,9 +269,9 @@ impl TOTP { /// # Example /// /// ```rust - /// use totp_rs::{Secret, TOTP, Algorithm}; + /// 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(), None, "".to_string()).unwrap(); + /// let totp = Totp::new(Algorithm::SHA1, 6, 1, 30, secret.to_bytes().unwrap(), None, "".to_string()).unwrap(); /// ``` /// /// # Errors @@ -279,7 +285,7 @@ impl TOTP { secret: Vec, issuer: Option, account_name: String, - ) -> Result { + ) -> Result { rfc::assert_digits(&digits)?; rfc::assert_secret_length(secret.as_ref())?; if issuer.is_some() && issuer.as_ref().unwrap().contains(':') { @@ -308,9 +314,9 @@ impl TOTP { /// # Example /// /// ```rust - /// use totp_rs::{Secret, TOTP, Algorithm}; + /// use totp_rs::{Secret, Totp, Algorithm}; /// let secret = Secret::Encoded("OBWGC2LOFVZXI4TJNZTS243FMNZGK5BNGEZDG".to_string()); - /// let totp = TOTP::new_unchecked(Algorithm::SHA1, 6, 1, 30, secret.to_bytes().unwrap(), None, "".to_string()); + /// let totp = Totp::new_unchecked(Algorithm::SHA1, 6, 1, 30, secret.to_bytes().unwrap(), None, "".to_string()); /// ``` pub fn new_unchecked( algorithm: Algorithm, @@ -320,8 +326,8 @@ impl TOTP { secret: Vec, issuer: Option, account_name: String, - ) -> TOTP { - TOTP { + ) -> Totp { + Totp { algorithm, digits, skew, @@ -343,9 +349,9 @@ impl TOTP { /// # Example /// /// ```rust - /// use totp_rs::{Secret, TOTP, Algorithm}; + /// 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(); + /// let totp = Totp::new(Algorithm::SHA1, 6, 1, 30, secret.to_bytes().unwrap()).unwrap(); /// ``` /// /// # Errors @@ -357,7 +363,7 @@ impl TOTP { skew: u8, step: u64, secret: Vec, - ) -> Result { + ) -> Result { crate::rfc::assert_digits(&digits)?; crate::rfc::assert_secret_length(secret.as_ref())?; Ok(Self::new_unchecked(algorithm, digits, skew, step, secret)) @@ -372,9 +378,9 @@ impl TOTP { /// # Example /// /// ```rust - /// use totp_rs::{Secret, TOTP, Algorithm}; + /// use totp_rs::{Secret, Totp, Algorithm}; /// let secret = Secret::Encoded("OBWGC2LOFVZXI4TJNZTS243FMNZGK5BNGEZDG".to_string()); - /// let totp = TOTP::new_unchecked(Algorithm::SHA1, 6, 1, 30, secret.to_bytes().unwrap()); + /// let totp = Totp::new_unchecked(Algorithm::SHA1, 6, 1, 30, secret.to_bytes().unwrap()); /// ``` pub fn new_unchecked( algorithm: Algorithm, @@ -382,8 +388,8 @@ impl TOTP { skew: u8, step: u64, secret: Vec, - ) -> TOTP { - TOTP { + ) -> Totp { + Totp { algorithm, digits, skew, @@ -397,8 +403,8 @@ impl TOTP { /// # Errors /// /// Will return an error in case issuer or label contain the character ':' - pub fn from_rfc6238(rfc: Rfc6238) -> Result { - TOTP::try_from(rfc) + pub fn from_rfc6238(rfc: Rfc6238) -> Result { + Totp::try_from(rfc) } /// Will sign the given timestamp @@ -495,6 +501,7 @@ impl TOTP { since = "5.6.0", note = "get_secret_base32 has non-conventionnal name. Use to_secret_base32 instead. Will disappear in 6.0." )] + #[inline(always)] pub fn get_secret_base32(&self) -> String { self.to_secret_base32() } @@ -502,19 +509,19 @@ impl TOTP { /// Generate a TOTP from the standard otpauth URL #[cfg(feature = "otpauth")] #[cfg_attr(docsrs, doc(cfg(feature = "otpauth")))] - pub fn from_url>(url: S) -> Result { + pub fn from_url>(url: S) -> Result { let (algorithm, digits, skew, step, secret, issuer, account_name) = Self::parts_from_url(url)?; - TOTP::new(algorithm, digits, skew, step, secret, issuer, account_name) + Totp::new(algorithm, digits, skew, step, secret, issuer, account_name) } /// Generate a TOTP from the standard otpauth URL, using `TOTP::new_unchecked` internally #[cfg(feature = "otpauth")] #[cfg_attr(docsrs, doc(cfg(feature = "otpauth")))] - pub fn from_url_unchecked>(url: S) -> Result { + pub fn from_url_unchecked>(url: S) -> Result { let (algorithm, digits, skew, step, secret, issuer, account_name) = Self::parts_from_url(url)?; - Ok(TOTP::new_unchecked( + Ok(Totp::new_unchecked( algorithm, digits, skew, @@ -643,6 +650,7 @@ impl TOTP { since = "5.6.0", note = "get_url has non-conventionnal name. Use to_url instead. Will disappear in 6.0." )] + #[inline(always)] pub fn get_url(&self) -> String { self.to_url() } @@ -685,11 +693,12 @@ impl TOTP { #[cfg(feature = "qr")] #[cfg_attr(docsrs, doc(cfg(feature = "qr")))] -impl TOTP { +impl Totp { #[deprecated( since = "5.3.0", note = "get_qr was forcing the use of png as a base64. Use to_qr_base64 or to_qr_png instead. Will disappear in 6.0." )] + #[inline(always)] pub fn get_qr(&self) -> Result { let url = self.to_url(); qrcodegen_image::draw_base64(&url) @@ -699,6 +708,7 @@ impl TOTP { since = "5.6.0", note = "get_qr_base64 has non-conventionnal name. Use to_qr_base64 instead. Will disappear in 6.0." )] + #[inline(always)] pub fn get_qr_base64(&self) -> Result { self.to_qr_base64() } @@ -724,6 +734,7 @@ impl TOTP { since = "5.6.0", note = "get_qr_png has non-conventionnal name. Use to_qr_png instead. Will disappear in 6.0." )] + #[inline(always)] pub fn get_qr_png(&self) -> Result, String> { self.to_qr_png() } @@ -752,7 +763,7 @@ mod tests { #[test] #[cfg(feature = "gen_secret")] fn default_values() { - let totp = TOTP::default(); + let totp = Totp::default(); assert_eq!(totp.algorithm, Algorithm::SHA1); assert_eq!(totp.digits, 6); assert_eq!(totp.skew, 1); @@ -762,7 +773,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn new_wrong_issuer() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, @@ -778,7 +789,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn new_wrong_account_name() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, @@ -794,7 +805,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn new_wrong_account_name_no_issuer() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, @@ -810,7 +821,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn comparison_ok() { - let reference = TOTP::new( + let reference = Totp::new( Algorithm::SHA1, 6, 1, @@ -820,7 +831,7 @@ mod tests { "constantoine@github.com".to_string(), ) .unwrap(); - let test = TOTP::new( + let test = Totp::new( Algorithm::SHA1, 6, 1, @@ -837,8 +848,8 @@ mod tests { #[cfg(not(feature = "otpauth"))] fn comparison_different_algo() { let reference = - TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); - let test = TOTP::new(Algorithm::SHA256, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); + Totp::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); + let test = Totp::new(Algorithm::SHA256, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); assert_ne!(reference, test); } @@ -846,8 +857,8 @@ mod tests { #[cfg(not(feature = "otpauth"))] fn comparison_different_digits() { let reference = - TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); - let test = TOTP::new(Algorithm::SHA1, 8, 1, 1, "TestSecretSuperSecret".into()).unwrap(); + Totp::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); + let test = Totp::new(Algorithm::SHA1, 8, 1, 1, "TestSecretSuperSecret".into()).unwrap(); assert_ne!(reference, test); } @@ -855,8 +866,8 @@ mod tests { #[cfg(not(feature = "otpauth"))] fn comparison_different_skew() { let reference = - TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); - let test = TOTP::new(Algorithm::SHA1, 6, 0, 1, "TestSecretSuperSecret".into()).unwrap(); + Totp::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); + let test = Totp::new(Algorithm::SHA1, 6, 0, 1, "TestSecretSuperSecret".into()).unwrap(); assert_ne!(reference, test); } @@ -864,8 +875,8 @@ mod tests { #[cfg(not(feature = "otpauth"))] fn comparison_different_step() { let reference = - TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); - let test = TOTP::new(Algorithm::SHA1, 6, 1, 30, "TestSecretSuperSecret".into()).unwrap(); + Totp::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); + let test = Totp::new(Algorithm::SHA1, 6, 1, 30, "TestSecretSuperSecret".into()).unwrap(); assert_ne!(reference, test); } @@ -873,15 +884,15 @@ mod tests { #[cfg(not(feature = "otpauth"))] fn comparison_different_secret() { let reference = - TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); - let test = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretDifferentSecret".into()).unwrap(); + Totp::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); + let test = Totp::new(Algorithm::SHA1, 6, 1, 1, "TestSecretDifferentSecret".into()).unwrap(); assert_ne!(reference, test); } #[test] #[cfg(feature = "otpauth")] fn url_for_secret_matches_sha1_without_issuer() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, @@ -901,7 +912,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn url_for_secret_matches_sha1() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, @@ -918,7 +929,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn url_for_secret_matches_sha256() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA256, 6, 1, @@ -935,7 +946,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn url_for_secret_matches_sha512() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA512, 6, 1, @@ -954,14 +965,14 @@ mod tests { fn ttl() { let secret = Secret::default(); let totp_rfc = Rfc6238::with_defaults(secret.to_bytes().unwrap()).unwrap(); - let totp = TOTP::from_rfc6238(totp_rfc); + let totp = Totp::from_rfc6238(totp_rfc); assert!(totp.is_ok()); } #[test] #[cfg(feature = "otpauth")] fn ttl_ok() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA512, 6, 1, @@ -977,7 +988,7 @@ mod tests { #[test] #[cfg(not(feature = "otpauth"))] fn returns_base32() { - let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); + let totp = Totp::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); assert_eq!( totp.get_secret_base32().as_str(), "KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ" @@ -987,14 +998,14 @@ mod tests { #[test] #[cfg(not(feature = "otpauth"))] fn generate_token() { - let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); + let totp = Totp::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).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".into()).unwrap(); + let totp = Totp::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); let time = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .unwrap() @@ -1008,35 +1019,35 @@ mod tests { #[test] #[cfg(not(feature = "otpauth"))] fn generates_token_sha256() { - let totp = TOTP::new(Algorithm::SHA256, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); + let totp = Totp::new(Algorithm::SHA256, 6, 1, 1, "TestSecretSuperSecret".into()).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".into()).unwrap(); + let totp = Totp::new(Algorithm::SHA512, 6, 1, 1, "TestSecretSuperSecret".into()).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".into()).unwrap(); + let totp = Totp::new(Algorithm::SHA1, 6, 0, 1, "TestSecretSuperSecret".into()).unwrap(); assert!(totp.check("659761", 1000)); } #[test] #[cfg(not(feature = "otpauth"))] fn checks_token_big_skew() { - let totp = TOTP::new(Algorithm::SHA1, 6, 255, 1, "TestSecretSuperSecret".into()).unwrap(); + let totp = Totp::new(Algorithm::SHA1, 6, 255, 1, "TestSecretSuperSecret".into()).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".into()).unwrap(); + let totp = Totp::new(Algorithm::SHA1, 6, 0, 1, "TestSecretSuperSecret".into()).unwrap(); assert!(totp .check_current(&totp.generate_current().unwrap()) .unwrap()); @@ -1046,7 +1057,7 @@ mod tests { #[test] #[cfg(not(feature = "otpauth"))] fn checks_token_with_skew() { - let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); + let totp = Totp::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret".into()).unwrap(); assert!( totp.check("174269", 1000) && totp.check("659761", 1000) && totp.check("260393", 1000) ); @@ -1055,7 +1066,7 @@ mod tests { #[test] #[cfg(not(feature = "otpauth"))] fn next_step() { - let totp = TOTP::new(Algorithm::SHA1, 6, 1, 30, "TestSecretSuperSecret".into()).unwrap(); + let totp = Totp::new(Algorithm::SHA1, 6, 1, 30, "TestSecretSuperSecret".into()).unwrap(); assert!(totp.next_step(0) == 30); assert!(totp.next_step(29) == 30); assert!(totp.next_step(30) == 60); @@ -1064,7 +1075,7 @@ mod tests { #[test] #[cfg(not(feature = "otpauth"))] fn next_step_current() { - let totp = TOTP::new(Algorithm::SHA1, 6, 1, 30, "TestSecretSuperSecret".into()).unwrap(); + let totp = Totp::new(Algorithm::SHA1, 6, 1, 30, "TestSecretSuperSecret".into()).unwrap(); let t = system_time().unwrap(); assert!(totp.next_step_current().unwrap() == totp.next_step(t)); } @@ -1072,20 +1083,20 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn from_url_err() { - assert!(TOTP::from_url("otpauth://hotp/123").is_err()); - assert!(TOTP::from_url("otpauth://totp/GitHub:test").is_err()); - assert!(TOTP::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::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::from_url("otpauth://totp/GitHub:test?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ") + Totp::from_url("otpauth://totp/GitHub:test?secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ") .unwrap(); assert_eq!( totp.secret, @@ -1104,7 +1115,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn from_url_query() { - let totp = TOTP::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( @@ -1122,7 +1133,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn from_url_query_sha512() { - let totp = TOTP::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( @@ -1140,8 +1151,8 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn from_url_to_url() { - 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( + 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, @@ -1157,7 +1168,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn from_url_unknown_param() { - let totp = TOTP::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( @@ -1175,8 +1186,8 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn from_url_issuer_special() { - 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( + 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, @@ -1193,8 +1204,8 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn from_url_account_name_issuer() { - let totp = TOTP::from_url("otpauth://totp/Github:constantoine?issuer=Github&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=6&algorithm=SHA1").unwrap(); - let totp_bis = TOTP::new( + let totp = Totp::from_url("otpauth://totp/Github:constantoine?issuer=Github&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=6&algorithm=SHA1").unwrap(); + let totp_bis = Totp::new( Algorithm::SHA1, 6, 1, @@ -1212,8 +1223,8 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn from_url_account_name_issuer_encoded() { - let totp = TOTP::from_url("otpauth://totp/Github%3Aconstantoine?issuer=Github&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=6&algorithm=SHA1").unwrap(); - let totp_bis = TOTP::new( + let totp = Totp::from_url("otpauth://totp/Github%3Aconstantoine?issuer=Github&secret=KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ&digits=6&algorithm=SHA1").unwrap(); + let totp_bis = Totp::new( Algorithm::SHA1, 6, 1, @@ -1231,7 +1242,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn from_url_query_issuer() { - let totp = TOTP::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( @@ -1250,7 +1261,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn from_url_wrong_scheme() { - let totp = TOTP::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(_))); @@ -1259,7 +1270,7 @@ mod tests { #[test] #[cfg(feature = "otpauth")] fn from_url_wrong_algo() { - let totp = TOTP::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(_))); @@ -1268,7 +1279,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=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(), @@ -1282,7 +1293,7 @@ mod tests { use qrcodegen_image::qrcodegen; use sha2::{Digest, Sha512}; - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, @@ -1308,7 +1319,7 @@ mod tests { #[test] #[cfg(feature = "qr")] fn generates_qr_base64_ok() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, @@ -1325,7 +1336,7 @@ mod tests { #[test] #[cfg(feature = "qr")] fn generates_qr_png_ok() { - let totp = TOTP::new( + let totp = Totp::new( Algorithm::SHA1, 6, 1, diff --git a/src/rfc.rs b/src/rfc.rs index f1457cb..5e233e7 100644 --- a/src/rfc.rs +++ b/src/rfc.rs @@ -1,6 +1,6 @@ use crate::Algorithm; use crate::TotpUrlError; -use crate::TOTP; +use crate::Totp; #[cfg(feature = "serde_support")] use serde::{Deserialize, Serialize}; @@ -53,7 +53,7 @@ pub fn assert_secret_length(secret: &[u8]) -> Result<(), Rfc6238Error> { /// /// # Example /// ``` -/// use totp_rs::{Rfc6238, TOTP}; +/// use totp_rs::{Rfc6238, Totp}; /// /// let mut rfc = Rfc6238::with_defaults( /// "totp-sercret-123".as_bytes().to_vec() @@ -62,7 +62,7 @@ pub fn assert_secret_length(secret: &[u8]) -> Result<(), Rfc6238Error> { /// // optional, set digits, issuer, account_name /// rfc.digits(8).unwrap(); /// -/// let totp = TOTP::from_rfc6238(rfc).unwrap(); +/// let totp = Totp::from_rfc6238(rfc).unwrap(); /// ``` #[derive(Debug, Clone)] #[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] @@ -173,22 +173,22 @@ impl Rfc6238 { } #[cfg(not(feature = "otpauth"))] -impl TryFrom for TOTP { +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) + Totp::new(rfc.algorithm, rfc.digits, rfc.skew, rfc.step, rfc.secret) } } #[cfg(feature = "otpauth")] -impl TryFrom for TOTP { +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( + Totp::new( rfc.algorithm, rfc.digits, rfc.skew, @@ -205,7 +205,7 @@ mod tests { #[cfg(feature = "otpauth")] use crate::TotpUrlError; - use super::{Rfc6238, TOTP}; + use super::{Rfc6238, Totp}; #[cfg(not(feature = "otpauth"))] use super::Rfc6238Error; @@ -262,7 +262,7 @@ mod tests { #[cfg(not(feature = "otpauth"))] fn rfc_to_totp_ok() { let rfc = Rfc6238::new(8, GOOD_SECRET.into()).unwrap(); - let totp = TOTP::try_from(rfc); + let totp = Totp::try_from(rfc); assert!(totp.is_ok()); let otp = totp.unwrap(); assert_eq!(&otp.secret, GOOD_SECRET.as_bytes()); @@ -281,7 +281,7 @@ mod tests { .unwrap(), ) .unwrap(); - let totp = TOTP::try_from(rfc); + let totp = Totp::try_from(rfc); assert!(totp.is_ok()); let otp = totp.unwrap(); assert_eq!(otp.algorithm, crate::Algorithm::SHA1); @@ -300,7 +300,7 @@ mod tests { INVALID_ACCOUNT.to_string(), ) .unwrap(); - let totp = TOTP::try_from(rfc); + let totp = Totp::try_from(rfc); assert!(totp.is_err()); assert!(matches!(totp.unwrap_err(), TotpUrlError::AccountName(_))) } @@ -315,7 +315,7 @@ mod tests { ACCOUNT.to_string(), ) .unwrap(); - let totp = TOTP::try_from(rfc); + let totp = Totp::try_from(rfc); assert!(totp.is_ok()); } diff --git a/src/secret.rs b/src/secret.rs index aea6c88..3a5666d 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -5,14 +5,14 @@ //! - Create a TOTP from a "raw" secret //! ``` //! # #[cfg(not(feature = "otpauth"))] { -//! use totp_rs::{Secret, TOTP, Algorithm}; +//! use totp_rs::{Secret, Totp, Algorithm}; //! //! 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( +//! let totp_raw = Totp::new( //! Algorithm::SHA1, //! 6, //! 1, @@ -27,10 +27,10 @@ //! - Create a TOTP from a base32 encoded secret //! ``` //! # #[cfg(not(feature = "otpauth"))] { -//! use totp_rs::{Secret, TOTP, Algorithm}; +//! use totp_rs::{Secret, Totp, Algorithm}; //! //! let secret_b32 = Secret::Encoded(String::from("OBWGC2LOFVZXI4TJNZTS243FMNZGK5BNGEZDG")); -//! let totp_b32 = TOTP::new( +//! let totp_b32 = Totp::new( //! Algorithm::SHA1, //! 6, //! 1, @@ -45,10 +45,10 @@ //! - Create a TOTP from a Generated Secret //! ``` //! # #[cfg(all(feature = "gen_secret", not(feature = "otpauth")))] { -//! use totp_rs::{Secret, TOTP, Algorithm}; +//! use totp_rs::{Secret, Totp, Algorithm}; //! //! let secret_b32 = Secret::default(); -//! let totp_b32 = TOTP::new( +//! let totp_b32 = Totp::new( //! Algorithm::SHA1, //! 6, //! 1, @@ -62,10 +62,10 @@ //! - Create a TOTP from a Generated Secret 2 //! ``` //! # #[cfg(all(feature = "gen_secret", not(feature = "otpauth")))] { -//! use totp_rs::{Secret, TOTP, Algorithm}; +//! use totp_rs::{Secret, Totp, Algorithm}; //! //! let secret_b32 = Secret::generate_secret(); -//! let totp_b32 = TOTP::new( +//! let totp_b32 = Totp::new( //! Algorithm::SHA1, //! 6, //! 1,