diff --git a/Cargo.lock b/Cargo.lock index 0c30a92..8af5142 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + [[package]] name = "ansi_term" version = "0.11.0" @@ -938,6 +947,8 @@ version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", ] @@ -1278,8 +1289,10 @@ dependencies = [ "clap", "cookie", "hmac-sha1", + "lazy_static 1.4.0", "log", "rand 0.7.3", + "regex", "reqwest", "rpassword", "rsa", diff --git a/Cargo.toml b/Cargo.toml index 1c92f00..3e2d098 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,6 @@ standback = "0.2.17" # required to fix a compilation error on a transient depend clap = "2.33.3" log = "0.4.14" stderrlog = "0.4" -cookie = "0.14" \ No newline at end of file +cookie = "0.14" +regex = "1" +lazy_static = "1.4.0" diff --git a/src/main.rs b/src/main.rs index 2bf7370..4db61a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,9 +7,16 @@ use text_io::read; use std::{io::stdin, path::Path}; use clap::{App, Arg, crate_version}; use log::*; +use regex::Regex; +#[macro_use] +extern crate lazy_static; mod accountmanager; +lazy_static! { + static ref CAPTCHA_VALID_CHARS: Regex = Regex::new("^([A-H]|[J-N]|[P-R]|[T-Z]|[2-4]|[7-9]|[@%&])+$").unwrap(); +} + fn main() { let matches = App::new("steamguard-cli") .version(crate_version!()) @@ -121,17 +128,7 @@ fn main() { login.twofactor_code = account.generate_code(server_time); } steamapi::LoginResult::NeedCaptcha{ captcha_gid } => { - // example captchas: - // - 3982844815370620954 - // - 3982844815370767244 - // - 3982844815370804220 - // - 3982844815370819607 - println!("Captcha required. Open this link in your web browser: https://steamcommunity.com/public/captcha.php?gid={}", captcha_gid); - print!("Enter captcha text: "); - let _ = std::io::stdout().flush(); - let mut captcha_text = String::new(); - stdin().read_line(&mut captcha_text).expect("Did not enter a correct string"); - login.captcha_text = String::from(captcha_text.strip_suffix('\n').unwrap()); + login.captcha_text = prompt_captcha_text(&captcha_gid); } r => { error!("Fatal login result: {:?}", r); @@ -154,3 +151,47 @@ fn main() { } } } + +fn validate_captcha_text(text: &String) -> bool { + return CAPTCHA_VALID_CHARS.is_match(text); +} + +#[test] +fn test_validate_captcha_text() { + assert!(validate_captcha_text(&String::from("2WWUA@"))); + assert!(validate_captcha_text(&String::from("3G8HT2"))); + assert!(validate_captcha_text(&String::from("3J%@X3"))); + assert!(validate_captcha_text(&String::from("2GCZ4A"))); + assert!(validate_captcha_text(&String::from("3G8HT2"))); + assert!(!validate_captcha_text(&String::from("asd823"))); + assert!(!validate_captcha_text(&String::from("!PQ4RD"))); + assert!(!validate_captcha_text(&String::from("1GQ4XZ"))); + assert!(!validate_captcha_text(&String::from("8GO4XZ"))); + assert!(!validate_captcha_text(&String::from("IPQ4RD"))); + assert!(!validate_captcha_text(&String::from("0PT4RD"))); + assert!(!validate_captcha_text(&String::from("APTSRD"))); + assert!(!validate_captcha_text(&String::from("AP5TRD"))); + assert!(!validate_captcha_text(&String::from("AP6TRD"))); +} + +/// Prompt the user for text input. +fn prompt() -> String { + let mut text = String::new(); + let _ = std::io::stdout().flush(); + stdin().read_line(&mut text).expect("Did not enter a correct string"); + return String::from(text.strip_suffix('\n').unwrap()); +} + +fn prompt_captcha_text(captcha_gid: &String) -> String { + println!("Captcha required. Open this link in your web browser: https://steamcommunity.com/public/captcha.php?gid={}", captcha_gid); + let mut captcha_text; + loop { + print!("Enter captcha text: "); + captcha_text = prompt(); + if captcha_text.len() > 0 && validate_captcha_text(&captcha_text) { + break; + } + warn!("Invalid chars for captcha text found in user's input. Prompting again..."); + } + return captcha_text; +}