use crate::errors::CheckpwnError;
use sha1::{Digest, Sha1};
use ureq::Body;
pub enum CheckableChoices {
Acc,
Pass,
Paste,
}
impl CheckableChoices {
fn get_api_route(&self, search_term: &str) -> String {
match self {
CheckableChoices::Acc => format!(
"https://haveibeenpwned.com/api/v3/breachedaccount/{}",
search_term
),
CheckableChoices::Pass => {
format!("https://api.pwnedpasswords.com/range/{}", search_term)
}
CheckableChoices::Paste => format!(
"https://haveibeenpwned.com/api/v3/pasteaccount/{}",
search_term
),
}
}
}
pub fn arg_to_api_route(arg: &CheckableChoices, input_data: &str) -> String {
match arg {
CheckableChoices::Pass => arg.get_api_route(
&input_data[..5],
),
_ => arg.get_api_route(input_data),
}
}
pub fn search_in_range(password_range_response: &str, hashed_key: &str) -> bool {
for line in password_range_response.lines() {
let pair: Vec<_> = line.split(':').collect();
if *pair.get(1).unwrap() == "0" {
continue;
}
if *pair.first().unwrap() == &hashed_key[5..] {
return true;
}
}
false
}
pub fn response_to_status_codes(
response: &Result<ureq::http::Response<Body>, ureq::Error>,
) -> Result<u16, CheckpwnError> {
match response {
Ok(resp) => Ok(resp.status().as_u16()),
Err(ureq::Error::StatusCode(code)) => Ok(*code),
Err(_) => Err(CheckpwnError::Network),
}
}
pub fn evaluate_acc_breach_statuscodes(
acc_stat: u16,
paste_stat: u16,
) -> Result<bool, CheckpwnError> {
match (acc_stat, paste_stat) {
(401, 401) => Err(CheckpwnError::InvalidApiKey),
(404, 404) => Ok(false),
(404, 400) => Ok(false),
(400, 400) => Err(CheckpwnError::BadResponse),
(400, 404) => Err(CheckpwnError::BadResponse),
(400, 200) => Err(CheckpwnError::BadResponse),
_ => Ok(true),
}
}
pub fn hash_password(password: &str) -> String {
let mut sha_digest = Sha1::default();
sha_digest.update(password.as_bytes());
hex::encode(sha_digest.finalize()).to_uppercase()
}
#[test]
fn test_sha1() {
let hash = hash_password("qwerty");
assert_eq!(
hash,
"b1b3773a05c0ed0176787a4f1574ff0075f7521e".to_uppercase()
);
}
#[test]
fn test_make_req_and_arg_to_route() {
let path = CheckableChoices::Acc.get_api_route("test@example.com");
assert_eq!(
path,
"https://haveibeenpwned.com/api/v3/breachedaccount/test@example.com"
);
assert_eq!(
"https://api.pwnedpasswords.com/range/B1B37",
arg_to_api_route(&CheckableChoices::Pass, &hash_password("qwerty"))
);
assert_eq!(
"https://haveibeenpwned.com/api/v3/pasteaccount/test@example.com",
arg_to_api_route(&CheckableChoices::Paste, "test@example.com")
);
}
#[test]
fn test_good_argument() {
let option_arg = CheckableChoices::Acc;
let data_search = String::from("test@example.com");
arg_to_api_route(&option_arg, &data_search);
}
#[test]
fn test_search_success_and_failure() {
let contains_pass = String::from(
"73678F196DE938F721CD408ED190330F5DB:3
7377BA15B8D5E12FCCBA32B074D45503D67:2
7387376AFD1B3DAB553D439C8A7D7CDDED1:2
73A05C0ED0176787A4F1574FF0075F7521E:3752262
748186F058DA83745B80E70B66D36B216A4:4
75FEC591927A596B6114ED5DAC4E4C22E04:10
76004E5282C5384DE32AFC2148BAD032450:2
769A96DED7A904FBE8F130508B2BFDDAEB1:3
76B8A2A14A15A8C22A49EC451DE9778581A:2
76C507D6248060841D4B4A4D444947E28A8:11
782C978C9120CF75BE0D93BE1330C2705E5:2
783F271CECC5F9BBC1E56B0585568C80248:5
7855E6B64AF9544B2B915CB09ADF44B507E:1",
);
let no_pass = String::from(
"7EC6529B5FFD62972B78F961DA68CCC1B0E:1
7ECD0E2C0152DB98585B54B0161E05D5823:2
7ED83795FEA81B716B31648AE233AB392B6:1
7F14F4258243863575CBF33215358357C61:4
7FF32ECF384A7DBD7F1325F2AA9421747D8:6
7FFDB37B4ACDBAD365DE51962CAFFEE7412:1
801EEE3EB6CE29DB12AB39D4E4C1E579372:3
80BADE9877A506510B46A393706CE0E554F:9
818D08C77BAAD2270478CE11D97F2E64CEA:1",
);
let hashed_password = hash_password("qwerty");
assert!(search_in_range(&contains_pass, &hashed_password));
assert!(!search_in_range(&no_pass, &hashed_password));
}
#[test]
fn test_evaluate_breach_good() {
let ok_ok = evaluate_acc_breach_statuscodes(200, 200).unwrap();
let ok_notfound = evaluate_acc_breach_statuscodes(200, 404).unwrap();
let notfound_ok = evaluate_acc_breach_statuscodes(404, 200).unwrap();
let ok_badrequest = evaluate_acc_breach_statuscodes(200, 400).unwrap();
let notfound_badrequest = evaluate_acc_breach_statuscodes(404, 400).unwrap();
let notfound_notfound = evaluate_acc_breach_statuscodes(404, 404).unwrap();
assert!(ok_ok);
assert!(ok_notfound);
assert!(notfound_ok);
assert!(ok_badrequest);
assert!(!notfound_badrequest);
assert!(!notfound_notfound);
assert!(evaluate_acc_breach_statuscodes(400, 400).is_err()); assert!(evaluate_acc_breach_statuscodes(400, 404).is_err()); assert!(evaluate_acc_breach_statuscodes(400, 200).is_err()); }