commit 82497e8b61673f3cebe6e4e1d7443ad86c04b859
parent 67b4d54f6b232d2ec0b0b6fc52677dff3fbe2eca
Author: Strange <StrangeGuy6228@protonmail.com>
Date: Mon, 24 Jun 2024 16:21:07 +0530
fixed -m for both png/gif capcha MIMEtype + --sxiv to display captcha in sxiv window
Diffstat:
2 files changed, 94 insertions(+), 30 deletions(-)
diff --git a/src/lechatphp/mod.rs b/src/lechatphp/mod.rs
@@ -1,15 +1,19 @@
-use std::{error, fs, io, thread};
-use std::fmt::{Display, Formatter};
-use std::io::Write;
-use std::time::Duration;
-use base64::Engine;
+use crate::{
+ trim_newline, CAPTCHA_FAILED_SOLVE_ERR, CAPTCHA_USED_ERR, CAPTCHA_WG_ERR, KICKED_ERR, LANG,
+ NICKNAME_ERR, REG_ERR, SERVER_DOWN_500_ERR, SERVER_DOWN_ERR, SESSION_RGX, UNKNOWN_ERR,
+};
use base64::engine::general_purpose;
+use base64::Engine;
use http::StatusCode;
use regex::Regex;
use reqwest::blocking::Client;
use select::document::Document;
use select::predicate::{And, Attr, Name};
-use crate::{CAPTCHA_FAILED_SOLVE_ERR, CAPTCHA_USED_ERR, CAPTCHA_WG_ERR, KICKED_ERR, LANG, NICKNAME_ERR, REG_ERR, SERVER_DOWN_500_ERR, SERVER_DOWN_ERR, SESSION_RGX, trim_newline, UNKNOWN_ERR};
+use std::fmt::{Display, Formatter};
+use std::io::Write;
+use std::process::{Command, Stdio};
+use std::time::Duration;
+use std::{error, fs, io, thread};
pub mod captcha;
@@ -60,8 +64,9 @@ pub fn login(
username: &str,
password: &str,
color: &str,
- manual_captcha: bool) -> Result<String, LoginErr>
-{
+ manual_captcha: bool,
+ sxiv: bool,
+) -> Result<String, LoginErr> {
// Get login page
let login_url = format!("{}/{}", &base_url, &page_php);
let resp = client.get(&login_url).send()?;
@@ -80,14 +85,33 @@ pub fn login(
("colour", color.to_owned()),
];
- if let Some(captcha_node) = doc.find(And(Name("input"), Attr("name", "challenge"))).next() {
+ if let Some(captcha_node) = doc
+ .find(And(Name("input"), Attr("name", "challenge")))
+ .next()
+ {
let captcha_value = captcha_node.attr("value").unwrap();
let captcha_img = doc.find(Name("img")).next().unwrap().attr("src").unwrap();
let mut captcha_input = String::new();
if manual_captcha {
// Otherwise, save the captcha on disk and prompt user for answer
- let img_decoded = general_purpose::STANDARD.decode(captcha_img.strip_prefix("data:image/gif;base64,").unwrap()).unwrap();
+ // println!("Captcha image source: {}", captcha_img);
+ // let img_decoded = general_purpose::STANDARD.decode(captcha_img.strip_prefix("data:image/gif;base64,").unwrap()).unwrap();
+ //
+ // Attempt to strip the appropriate prefix based on the MIME type
+ let base64_str =
+ if let Some(base64) = captcha_img.strip_prefix("data:image/png;base64,") {
+ base64
+ } else if let Some(base64) = captcha_img.strip_prefix("data:image/gif;base64,") {
+ base64
+ } else {
+ panic!("Unexpected captcha image format. Expected PNG or GIF.");
+ };
+
+ // Decode the base64 string into binary image data
+ let img_decoded = general_purpose::STANDARD.decode(base64_str).unwrap();
+
+ //
let img = image::load_from_memory(&img_decoded).unwrap();
let img_buf = image::imageops::resize(
&img,
@@ -98,15 +122,36 @@ pub fn login(
// Save captcha as file on disk
img_buf.save("captcha.gif").unwrap();
- termage::display_image("captcha.gif", img.width(), img.height());
+ if sxiv {
+ let mut sxiv_process = Command::new("sxiv")
+ .arg("captcha.gif")
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .spawn()
+ .expect("Failed to open image with sxiv");
+
+ // Prompt the user to enter the CAPTCHA
+ print!("Please enter the CAPTCHA: ");
+ io::stdout().flush().unwrap();
+ io::stdin().read_line(&mut captcha_input).unwrap();
+ trim_newline(&mut captcha_input);
+
+ // Close the sxiv window
+ sxiv_process.kill().expect("Failed to close sxiv");
- // Enter captcha
- print!("captcha: ");
- io::stdout().flush().unwrap();
- io::stdin().read_line(&mut captcha_input).unwrap();
- trim_newline(&mut captcha_input);
+ println!("Captcha input: {}", captcha_input);
+ } else {
+ termage::display_image("captcha.gif", img.width(), img.height());
+
+ // Enter captcha
+ print!("captcha: ");
+ io::stdout().flush().unwrap();
+ io::stdin().read_line(&mut captcha_input).unwrap();
+ trim_newline(&mut captcha_input);
+ }
} else {
- captcha_input = captcha::solve_b64(captcha_img).ok_or(LoginErr::CaptchaFailedSolveErr)?;
+ captcha_input =
+ captcha::solve_b64(captcha_img).ok_or(LoginErr::CaptchaFailedSolveErr)?;
}
params.extend(vec![
@@ -122,14 +167,30 @@ pub fn login(
_ => {}
}
- let mut refresh_header = resp.headers().get("refresh").map(|v| v.to_str().unwrap()).unwrap_or("");
+ let mut refresh_header = resp
+ .headers()
+ .get("refresh")
+ .map(|v| v.to_str().unwrap())
+ .unwrap_or("");
while refresh_header != "" {
let rgx = Regex::new(r#"URL=(.+)"#).unwrap();
- let refresh_url = format!("{}{}", base_url, rgx.captures(&refresh_header).unwrap().get(1).unwrap().as_str());
+ let refresh_url = format!(
+ "{}{}",
+ base_url,
+ rgx.captures(&refresh_header)
+ .unwrap()
+ .get(1)
+ .unwrap()
+ .as_str()
+ );
println!("waitroom enabled, wait 10sec");
thread::sleep(Duration::from_secs(10));
resp = client.get(refresh_url.clone()).send()?;
- refresh_header = resp.headers().get("refresh").map(|v| v.to_str().unwrap()).unwrap_or("");
+ refresh_header = resp
+ .headers()
+ .get("refresh")
+ .map(|v| v.to_str().unwrap())
+ .unwrap_or("");
}
let mut resp = resp.text()?;
@@ -186,14 +247,10 @@ pub fn logout(
client: &Client,
base_url: &str,
page_php: &str,
- session: &str) -> anyhow::Result<()>
-{
+ session: &str,
+) -> anyhow::Result<()> {
let full_url = format!("{}/{}", &base_url, &page_php);
- let params = [
- ("action", "logout"),
- ("session", &session),
- ("lang", LANG),
- ];
+ let params = [("action", "logout"), ("session", &session), ("lang", LANG)];
client.post(&full_url).form(¶ms).send()?;
Ok(())
-}
-\ No newline at end of file
+}
diff --git a/src/main.rs b/src/main.rs
@@ -167,6 +167,9 @@ struct Opts {
#[arg(long)]
session: Option<String>,
+
+ #[arg(long)]
+ sxiv: bool,
}
struct LeChatPHPConfig {
@@ -176,7 +179,6 @@ struct LeChatPHPConfig {
keepalive_send_to: String,
members_tag: String,
staffs_tag: String,
- // session: String
}
impl LeChatPHPConfig {
@@ -205,6 +207,7 @@ struct LeChatPHPClient {
config: LeChatPHPConfig,
last_key_event: Option<KeyCode>,
manual_captcha: bool,
+ sxiv: bool,
refresh_rate: u64,
max_login_retry: isize,
@@ -496,6 +499,7 @@ impl LeChatPHPClient {
return Ok(());
}
// println!("self.session is not Some");
+ // println!("self.sxiv = {:?}", self.sxiv);
self.session = Some(lechatphp::login(
&self.client,
&self.config.url,
@@ -504,6 +508,7 @@ impl LeChatPHPClient {
&self.base_client.password,
&self.guest_color,
self.manual_captcha,
+ self.sxiv,
)?);
Ok(())
}
@@ -2061,6 +2066,7 @@ fn new_default_le_chat_php_client(params: Params) -> LeChatPHPClient {
last_key_event: None,
client: params.client,
manual_captcha: params.manual_captcha,
+ sxiv: params.sxiv,
refresh_rate: params.refresh_rate,
config: LeChatPHPConfig::new_black_hat_chat_config(),
is_muted: Arc::new(Mutex::new(false)),
@@ -2090,6 +2096,7 @@ struct Params {
guest_color: String,
client: Client,
manual_captcha: bool,
+ sxiv: bool,
refresh_rate: u64,
max_login_retry: isize,
keepalive_send_to: Option<String>,
@@ -2372,6 +2379,7 @@ fn main() -> anyhow::Result<()> {
guest_color,
client: client.clone(),
manual_captcha: opts.manual_captcha,
+ sxiv: opts.sxiv,
refresh_rate: opts.refresh_rate,
max_login_retry: opts.max_login_retry,
keepalive_send_to: opts.keepalive_send_to,