Commit ff6f562ab733c46c3327fd74fa7f3aeb7716478d

constantoine 2022-05-20T15:00:12

The return of otpauth Signed-off-by: constantoine <cleo.rebert@gmail.com>

diff --git a/Cargo.toml b/Cargo.toml
index e150eee..93bd8bc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,7 +16,8 @@ features = [ "qr", "serde_support" ]
 
 [features]
 default = []
-qr = ["qrcodegen", "image", "base64"]
+otpauth = ["url"]
+qr = ["qrcodegen", "image", "base64", "otpauth"]
 serde_support = ["serde"]
 
 [dependencies]
@@ -25,7 +26,7 @@ sha2 = "~0.10.2"
 sha-1 = "~0.10.0"
 hmac = "~0.12.1"
 base32 = "~0.4"
-url = "2.2.2"
+url = { version = "2.2.2", optional = true } 
 constant_time_eq = "~0.2.1"
 qrcodegen = { version = "~1.8", optional = true }
 image = { version = "~0.24.2", features = ["png"], optional = true, default-features = false}
diff --git a/README.md b/README.md
index 4f6ee51..8ef67f5 100644
--- a/README.md
+++ b/README.md
@@ -10,9 +10,11 @@ Be aware that some authenticator apps will accept the `SHA256` and `SHA512` algo
 ## Features
 ---
 ### qr
-With optional feature "qr", you can use it to generate a base64 png qrcode
+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
 ### serde_support
-With optional feature "serde_support", library-defined types 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
 
 ## How to use
 ---
@@ -36,8 +38,6 @@ fn main() {
         Some("Github".to_string()),
         "constantoine@github.com".to_string(),
     ).unwrap();
-    let url = totp.get_url();
-    println!("{}", url);
     let token = totp.generate_current().unwrap();
     println!("{}", token);   
 }
@@ -82,8 +82,9 @@ features = ["serde_support"]
 
 Add it to your `Cargo.toml`:
 ```toml
-[dependencies]
-totp-rs = "^2.0"
+[dependencies.totp-rs]
+version = "^2.0"
+features = ["otpauth"]
 ```
 You can then do something like:
 ```Rust
diff --git a/src/lib.rs b/src/lib.rs
index 4dd8d5d..92fce39 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -21,8 +21,6 @@
 //!     Some("Github".to_string()),
 //!     "constantoine@github.com".to_string(),
 //! ).unwrap();
-//! let url = totp.get_url();
-//! println!("{}", url);
 //! let token = totp.generate_current().unwrap();
 //! println!("{}", token);
 //! ```
@@ -40,6 +38,8 @@
 //!     Some("Github".to_string()),
 //!     "constantoine@github.com".to_string(),
 //! ).unwrap();
+//! let url = totp.get_url();
+//! println!("{}", url);
 //! let code = totp.get_qr().unwrap();
 //! println!("{}", code);
 //! # }
@@ -55,6 +55,7 @@ use core::fmt;
 #[cfg(feature = "qr")]
 use {base64, image::Luma, qrcodegen};
 
+#[cfg(feature = "otpauth")]
 use url::{Host, ParseError, Url};
 
 use hmac::Mac;
@@ -116,6 +117,7 @@ fn system_time() -> Result<u64, SystemTimeError> {
 
 #[derive(Debug, Eq, PartialEq)]
 pub enum TotpUrlError {
+    #[cfg(feature = "otpauth")]
     Url(ParseError),
     Scheme,
     Host,
@@ -248,6 +250,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> {
         let url = Url::parse(url.as_ref()).map_err(|err| TotpUrlError::Url(err))?;
         if url.scheme() != "otpauth" {
@@ -322,6 +325,7 @@ impl<T: AsRef<[u8]>> TOTP<T> {
     /// 
     /// Label and issuer will be URL-encoded if needed be
     /// Secret will be base 32'd without padding, as per RFC.
+    #[cfg(feature = "otpauth")]
     pub fn get_url(&self) -> String {
         let label: String;
         let account_name: String = url::form_urlencoded::byte_serialize(self.account_name.as_bytes()).collect();
@@ -481,6 +485,7 @@ mod tests {
     }
 
     #[test]
+    #[cfg(feature = "otpauth")]
     fn url_for_secret_matches_sha1_without_issuer() {
         let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecret", None, "constantoine@github.com".to_string()).unwrap();
         let url = totp.get_url();
@@ -488,6 +493,7 @@ mod tests {
     }
 
     #[test]
+    #[cfg(feature = "otpauth")]
     fn url_for_secret_matches_sha1() {
         let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap();
         let url = totp.get_url();
@@ -495,6 +501,7 @@ mod tests {
     }
 
     #[test]
+    #[cfg(feature = "otpauth")]
     fn url_for_secret_matches_sha256() {
         let totp = TOTP::new(Algorithm::SHA256, 6, 1, 1, "TestSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap();
         let url = totp.get_url();
@@ -502,6 +509,7 @@ mod tests {
     }
 
     #[test]
+    #[cfg(feature = "otpauth")]
     fn url_for_secret_matches_sha512() {
         let totp = TOTP::new(Algorithm::SHA512, 6, 1, 1, "TestSecret", Some("Github".to_string()), "constantoine@github.com".to_string()).unwrap();
         let url = totp.get_url();
@@ -566,6 +574,7 @@ 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());
@@ -573,6 +582,7 @@ mod tests {
     }
 
     #[test]
+    #[cfg(feature = "otpauth")]
     fn from_url_default() {
         let totp = TOTP::<Vec<u8>>::from_url("otpauth://totp/GitHub:test?secret=ABC").unwrap();
         assert_eq!(totp.secret, base32::decode(base32::Alphabet::RFC4648 { padding: false }, "ABC").unwrap());
@@ -583,6 +593,7 @@ mod tests {
     }
 
     #[test]
+    #[cfg(feature = "otpauth")]
     fn from_url_query() {
         let totp = TOTP::<Vec<u8>>::from_url("otpauth://totp/GitHub:test?secret=ABC&digits=8&period=60&algorithm=SHA256").unwrap();
         assert_eq!(totp.secret, base32::decode(base32::Alphabet::RFC4648 { padding: false }, "ABC").unwrap());
@@ -593,6 +604,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=ABC&digits=8&period=60&algorithm=SHA256");
         assert_eq!(totp.is_err(), true);