Commit c36b3a9507b8b256c450fb01fd32472b4fa5a678

Cléo Rebert 2022-10-10T11:20:01

Merge pull request #39 from constantoine/add_test_coverage Add coverage for rfc.rs

diff --git a/Cargo.toml b/Cargo.toml
index ec56a91..6a25c01 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,7 +15,7 @@ categories = ["authentication", "web-programming"]
 features = [ "qr", "serde_support", "otpauth" ]
 
 [features]
-default = []
+default = ["qr", "gen_secret"]
 otpauth = ["url", "urlencoding"]
 qr = ["qrcodegen", "image", "base64", "otpauth"]
 serde_support = ["serde"]
diff --git a/src/lib.rs b/src/lib.rs
index 74b5c40..329002d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -751,6 +751,31 @@ mod tests {
     }
 
     #[test]
+    #[cfg(all(feature = "otpauth", feature = "gen_secret"))]
+    fn ttl() {
+        let secret = Secret::default();
+        let totp_rfc = Rfc6238::with_defaults(secret.to_bytes().unwrap()).unwrap();
+        let totp = TOTP::from_rfc6238(totp_rfc);
+        assert!(totp.is_ok());
+    }
+
+    #[test]
+    #[cfg(feature = "otpauth")]
+    fn ttl_ok() {
+        let totp = TOTP::new(
+            Algorithm::SHA512,
+            6,
+            1,
+            1,
+            "TestSecretSuperSecret",
+            Some("Github".to_string()),
+            "constantoine@github.com".to_string(),
+        )
+        .unwrap();
+        assert!(totp.ttl().is_ok());
+    }
+
+    #[test]
     #[cfg(not(feature = "otpauth"))]
     fn returns_base32() {
         let totp = TOTP::new(Algorithm::SHA1, 6, 1, 1, "TestSecretSuperSecret").unwrap();
@@ -891,6 +916,24 @@ 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();
+        assert_eq!(
+            totp.secret,
+            base32::decode(
+                base32::Alphabet::RFC4648 { padding: false },
+                "KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ"
+            )
+            .unwrap()
+        );
+        assert_eq!(totp.algorithm, Algorithm::SHA512);
+        assert_eq!(totp.digits, 8);
+        assert_eq!(totp.skew, 1);
+        assert_eq!(totp.step, 60);
+    }
+
+    #[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_bis = TOTP::new(
@@ -908,6 +951,24 @@ 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();
+        assert_eq!(
+            totp.secret,
+            base32::decode(
+                base32::Alphabet::RFC4648 { padding: false },
+                "KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ"
+            )
+            .unwrap()
+        );
+        assert_eq!(totp.algorithm, Algorithm::SHA256);
+        assert_eq!(totp.digits, 8);
+        assert_eq!(totp.skew, 1);
+        assert_eq!(totp.step, 60);
+    }
+
+    #[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_bis = TOTP::new(
@@ -945,6 +1006,24 @@ mod tests {
 
     #[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");
+        assert!(totp.is_err());
+        let err = totp.unwrap_err();
+        assert!(matches!(err, TotpUrlError::Scheme(_)));
+    }
+
+    #[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");
+        assert!(totp.is_err());
+        let err = totp.unwrap_err();
+        assert!(matches!(err, TotpUrlError::Algorithm(_)));
+    }
+
+    #[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");
         assert!(totp.is_err());
@@ -981,4 +1060,21 @@ mod tests {
             "025809c9db9c2c918930e018549c90929a083ee757156737812bad40ded64312c1526c73d8f2f59d5c203b97141ddfc331b1192e234f4f43257f50a6d05e382f"
         );
     }
+
+    #[test]
+    #[cfg(feature = "qr")]
+    fn generates_qr_ok() {
+        let totp = TOTP::new(
+            Algorithm::SHA1,
+            6,
+            1,
+            1,
+            "TestSecretSuperSecret",
+            Some("Github".to_string()),
+            "constantoine@github.com".to_string(),
+        )
+        .unwrap();
+        let qr = totp.get_qr();
+        assert!(qr.is_ok());
+    }
 }
diff --git a/src/rfc.rs b/src/rfc.rs
index 94dda8b..34204a7 100644
--- a/src/rfc.rs
+++ b/src/rfc.rs
@@ -314,6 +314,21 @@ mod tests {
     }
 
     #[test]
+    #[cfg(feature = "otpauth")]
+    fn rfc_with_default_set_values() {
+        let mut rfc = Rfc6238::with_defaults(GOOD_SECRET.to_string()).unwrap();
+        let ok = rfc.digits(8);
+        assert!(ok.is_ok());
+        assert_eq!(rfc.account_name, "");
+        assert_eq!(rfc.issuer, Some("".to_string()));
+        rfc.issuer("Github".to_string());
+        rfc.account_name("constantoine".to_string());
+        assert_eq!(rfc.account_name, "constantoine");
+        assert_eq!(rfc.issuer, Some("Github".to_string()));
+        assert_eq!(rfc.digits, 8)
+    }
+
+    #[test]
     #[cfg(not(feature = "otpauth"))]
     fn rfc_with_default_set_values() {
         let mut rfc = Rfc6238::with_defaults(GOOD_SECRET.to_string()).unwrap();
@@ -325,4 +340,25 @@ mod tests {
         assert!(ok.is_ok());
         assert_eq!(rfc.digits, 8)
     }
+
+    #[test]
+    #[cfg(not(feature = "otpauth"))]
+    fn digits_error() {
+        let error = crate::Rfc6238Error::InvalidDigits(9);
+        assert_eq!(
+            error.to_string(),
+            "Implementations MUST extract a 6-digit code at a minimum and possibly 7 and 8-digit code. 9 digits is not allowed".to_string()
+        )
+    }
+
+    #[test]
+    #[cfg(not(feature = "otpauth"))]
+    fn secret_length_error() {
+        let error = Rfc6238Error::SecretTooSmall(120);
+        assert_eq!(
+            error.to_string(),
+            "The length of the shared secret MUST be at least 128 bits. 120 bits is not enough"
+                .to_string()
+        )
+    }
 }
diff --git a/src/secret.rs b/src/secret.rs
index 115566e..6edde97 100644
--- a/src/secret.rs
+++ b/src/secret.rs
@@ -237,9 +237,33 @@ mod tests {
     #[test]
     #[cfg(feature = "gen_secret")]
     fn secret_gen_secret() {
-        match Secret::generate_secret() {
-            Secret::Raw(secret) => assert_eq!(secret.len(), 20),
-            Secret::Encoded(_) => panic!("should be raw"),
-        }
+        let sec = Secret::generate_secret();
+
+        assert!(matches!(sec, Secret::Raw(_)));
+        assert_eq!(sec.to_bytes().unwrap().len(), 20);
+    }
+
+    #[test]
+    #[cfg(feature = "gen_secret")]
+    fn secret_gen_default() {
+        let sec = Secret::default();
+
+        assert!(matches!(sec, Secret::Raw(_)));
+        assert_eq!(sec.to_bytes().unwrap().len(), 20);
+    }
+
+    #[test]
+    #[cfg(feature = "gen_secret")]
+    fn secret_empty() {
+        let non_ascii = vec![240, 159, 146, 150];
+        let sec = Secret::Encoded(std::str::from_utf8(&non_ascii).unwrap().to_owned());
+
+        let to_r = sec.to_raw();
+
+        assert!(to_r.is_err());
+
+        let to_b = sec.to_bytes();
+
+        assert!(to_b.is_err());
     }
 }