Skip to content

Commit 4d1f8f5

Browse files
committed
Refactor to use convert_otp_algorithm and test it
1 parent 8f73166 commit 4d1f8f5

File tree

1 file changed

+63
-5
lines changed
  • crates/bitwarden-exporters/src/cxf

1 file changed

+63
-5
lines changed

crates/bitwarden-exporters/src/cxf/login.rs

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,23 @@ use crate::{Fido2Credential, Field, Login, LoginUri};
1919
/// Prefix that indicates the URL is an Android app scheme.
2020
const ANDROID_APP_SCHEME: &str = "androidapp://";
2121

22-
/// Convert CXF TotpCredential to Bitwarden's Totp struct
23-
/// This ensures we use the exact same encoding and formatting as Bitwarden's core implementation
24-
fn totp_credential_to_totp(cxf_totp: &TotpCredential) -> Totp {
25-
let algorithm = match cxf_totp.algorithm {
22+
/// Convert CXF OTPHashAlgorithm to Bitwarden's TotpAlgorithm
23+
/// Handles standard algorithms and special cases like Steam
24+
fn convert_otp_algorithm(algorithm: &OTPHashAlgorithm) -> TotpAlgorithm {
25+
match algorithm {
2626
OTPHashAlgorithm::Sha1 => TotpAlgorithm::Sha1,
2727
OTPHashAlgorithm::Sha256 => TotpAlgorithm::Sha256,
2828
OTPHashAlgorithm::Sha512 => TotpAlgorithm::Sha512,
2929
OTPHashAlgorithm::Unknown(ref algo) if algo == "steam" => TotpAlgorithm::Steam,
3030
OTPHashAlgorithm::Unknown(_) | _ => TotpAlgorithm::Sha1, /* Default to SHA1 for unknown
3131
* algorithms */
32-
};
32+
}
33+
}
34+
35+
/// Convert CXF TotpCredential to Bitwarden's Totp struct
36+
/// This ensures we use the exact same encoding and formatting as Bitwarden's core implementation
37+
fn totp_credential_to_totp(cxf_totp: &TotpCredential) -> Totp {
38+
let algorithm = convert_otp_algorithm(&cxf_totp.algorithm);
3339

3440
let secret_bytes: Vec<u8> = cxf_totp.secret.clone().into();
3541

@@ -543,4 +549,56 @@ mod tests {
543549
assert!(otpauth.contains("&digits=8"));
544550
assert!(otpauth.contains("&algorithm=SHA256"));
545551
}
552+
553+
// Algorithm conversion tests
554+
#[test]
555+
fn test_convert_otp_algorithm_sha1() {
556+
let result = convert_otp_algorithm(&OTPHashAlgorithm::Sha1);
557+
assert_eq!(result, TotpAlgorithm::Sha1);
558+
}
559+
560+
#[test]
561+
fn test_convert_otp_algorithm_sha256() {
562+
let result = convert_otp_algorithm(&OTPHashAlgorithm::Sha256);
563+
assert_eq!(result, TotpAlgorithm::Sha256);
564+
}
565+
566+
#[test]
567+
fn test_convert_otp_algorithm_sha512() {
568+
let result = convert_otp_algorithm(&OTPHashAlgorithm::Sha512);
569+
assert_eq!(result, TotpAlgorithm::Sha512);
570+
}
571+
572+
#[test]
573+
fn test_convert_otp_algorithm_steam() {
574+
let result = convert_otp_algorithm(&OTPHashAlgorithm::Unknown("steam".to_string()));
575+
assert_eq!(result, TotpAlgorithm::Steam);
576+
}
577+
578+
#[test]
579+
fn test_convert_otp_algorithm_steam_case_sensitive() {
580+
// Test that "steam" is case-sensitive
581+
let result = convert_otp_algorithm(&OTPHashAlgorithm::Unknown("Steam".to_string()));
582+
assert_eq!(result, TotpAlgorithm::Sha1); // will default to SHA1
583+
}
584+
585+
#[test]
586+
fn test_convert_otp_algorithm_unknown_empty() {
587+
let result = convert_otp_algorithm(&OTPHashAlgorithm::Unknown("".to_string()));
588+
assert_eq!(result, TotpAlgorithm::Sha1); // will default to SHA1
589+
}
590+
591+
#[test]
592+
fn test_convert_otp_algorithm_unknown_md5() {
593+
// Test an algorithm that might exist in other systems but isn't supported
594+
let result = convert_otp_algorithm(&OTPHashAlgorithm::Unknown("md5".to_string()));
595+
assert_eq!(result, TotpAlgorithm::Sha1); // will default to SHA1
596+
}
597+
598+
#[test]
599+
fn test_convert_otp_algorithm_unknown_whitespace() {
600+
// Test steam with whitespace (will not match)
601+
let result = convert_otp_algorithm(&OTPHashAlgorithm::Unknown(" steam ".to_string()));
602+
assert_eq!(result, TotpAlgorithm::Sha1); // will default to SHA1
603+
}
546604
}

0 commit comments

Comments
 (0)