Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Ticket trait #43

Merged
merged 7 commits into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 21 additions & 54 deletions proc_qq/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use crate::features::scheduler;
use crate::handler::EventSender;
use crate::DeviceSource::{JsonFile, JsonString};
use crate::{
Authentication, ClientHandler, DeviceLockVerification, DeviceSource, EventResultHandler,
Module, SessionStore, ShowQR, ShowSlider,
show_slider, Authentication, ClientHandler, DeviceLockVerification, DeviceSource,
EventResultHandler, Module, SessionStore, ShowQR, ShowSliderTrait,
};

/// 客户端
Expand All @@ -44,7 +44,7 @@ pub struct Client {
pub(crate) modules: Arc<Vec<Module>>,
pub(crate) result_handlers: Arc<Vec<EventResultHandler>>,
pub show_qr: ShowQR,
pub show_slider: ShowSlider,
pub show_slider: Arc<Box<dyn ShowSliderTrait + Sync + Send>>,
pub shutting: bool,
pub device_lock_verification: DeviceLockVerification,
#[cfg(feature = "connect_handler")]
Expand Down Expand Up @@ -473,45 +473,17 @@ async fn loop_login(client: &Client, first: RQResult<LoginResponse>) -> Result<(
// 图片应该没了
image_captcha: ref _image_captcha,
..
}) => match client.show_slider {
ShowSlider::AndroidHelper => {
tracing::info!("滑动条 (原URL) : {:?}", verify_url);
let helper_url = verify_url
.clone()
.unwrap()
.replace("ssl.captcha.qq.com", "txhelper.glitch.me");
tracing::info!("滑动条 (改URL) : {:?}", helper_url);
let mut txt = http_get(&helper_url)
.await
.with_context(|| "http请求失败")?;
tracing::info!("您需要使用该仓库 提供的APP进行滑动 , 滑动后请等待, https://github.com/mzdluo123/TxCaptchaHelper : {}", txt);
loop {
sleep(Duration::from_secs(5)).await;
let rsp = http_get(&helper_url)
.await
.with_context(|| "http请求失败")?;
if !rsp.eq(&txt) {
txt = rsp;
break;
}
}
tracing::info!("获取到ticket : {}", txt);
resp = rq_client.submit_ticket(&txt).await.expect("发送ticket失败");
}
#[cfg(all(any(target_os = "windows"), feature = "pop_window_slider"))]
ShowSlider::PopWindow => {
if let Some(ticket) =
crate::captcha_window::ticket(verify_url.as_ref().unwrap())
{
resp = rq_client
.submit_ticket(&ticket)
.await
.expect("failed to submit ticket");
} else {
panic!("not slide");
}
}
},
}) => {
let ticket = client
.show_slider
.show_slider(verify_url.clone())
.await
.expect("未能获取ticket");
resp = rq_client
.submit_ticket(&ticket)
.await
.expect("failed to submit ticket");
}
LoginResponse::DeviceLockLogin { .. } => {
resp = rq_client
.device_lock_login()
Expand Down Expand Up @@ -539,14 +511,6 @@ async fn loop_login(client: &Client, first: RQResult<LoginResponse>) -> Result<(
}
}

async fn http_get(url: &str) -> Result<String> {
Ok(reqwest::ClientBuilder::new().build().unwrap().get(url).header(
"user-agent", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Mobile Safari/537.36",
).send().await?
.text()
.await?)
}

pub fn token_to_bytes(t: &Token) -> Bytes {
let mut token = BytesMut::with_capacity(1024);
token.put_i64(t.uin);
Expand Down Expand Up @@ -589,7 +553,7 @@ pub struct ClientBuilder {
#[cfg(feature = "scheduler")]
schedulers: Arc<Vec<scheduler::Scheduler>>,
show_qr: Option<ShowQR>,
show_slider: Option<ShowSlider>,
show_slider: Option<Arc<Box<dyn ShowSliderTrait + Sync + Send>>>,
device_lock_verification: Option<DeviceLockVerification>,
#[cfg(feature = "connect_handler")]
connect_handler_arc: Arc<Option<Box<dyn ConnectionHandler + Sync + Send>>>,
Expand Down Expand Up @@ -641,15 +605,18 @@ impl ClientBuilder {
}

/// 设置显示滑动条的方式
pub fn show_slider<E: Into<Option<ShowSlider>>>(mut self, show_slider: E) -> Self {
pub fn show_slider<S: Into<Option<Arc<Box<dyn ShowSliderTrait + Sync + Send>>>>>(
mut self,
show_slider: S,
) -> Self {
self.show_slider = show_slider.into();
self
}

/// 设置显示滑动条的方式(如果是windows可以直接在桌面滑动)
#[cfg(all(any(target_os = "windows"), feature = "pop_window_slider"))]
pub fn show_slider_pop_menu_if_possible(self) -> Self {
self.show_slider(ShowSlider::PopWindow)
self.show_slider(show_slider::PopWindow::arc_boxed())
}

/// 设置显示滑动条的方式(如果是windows可以直接在桌面滑动)
Expand Down Expand Up @@ -714,7 +681,7 @@ impl ClientBuilder {
show_slider: if self.show_slider.is_some() {
self.show_slider.clone().unwrap()
} else {
ShowSlider::AndroidHelper
Arc::new(show_slider::AndroidHelper::boxed())
},
device_lock_verification: if self.device_lock_verification.is_some() {
self.device_lock_verification.clone().unwrap()
Expand Down
101 changes: 92 additions & 9 deletions proc_qq/src/entities.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use anyhow::Result;
use async_trait::async_trait;
use bytes::Bytes;
use core::future::Future;
use ricq_core::msg::elem::{FlashImage, FriendImage, GroupImage};
use std::fmt::{Debug, Formatter};
use std::path::Path;
use std::pin::Pin;
use std::sync::Arc;

use anyhow::Result;
use async_trait::async_trait;
use bytes::Bytes;
use ricq_core::msg::elem::{FlashImage, FriendImage, GroupImage};

use crate::DeviceSource::JsonFile;

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -77,12 +76,96 @@ pub enum ShowQR {
SaveToFile,
}

#[derive(Clone, Debug)]
pub enum ShowSlider {
AndroidHelper,
#[async_trait]
pub trait ShowSliderTrait {
async fn show_slider(&self, verify_url: Option<String>) -> Result<String>;
}

#[deprecated(since = "0.1.36", note = "please use `show_slider` instead")]
#[allow(non_snake_case)]
pub mod ShowSlider {
pub use super::show_slider::*;
}

pub mod show_slider {
use super::ShowSliderTrait;
use anyhow::{Context, Result};
use async_trait::async_trait;
use std::sync::Arc;
use std::time::Duration;
use tokio::time::sleep;

pub struct AndroidHelper;

impl AndroidHelper {
async fn http_get(&self, url: &str) -> Result<String> {
Ok(reqwest::ClientBuilder::new().build().unwrap().get(url).header(
"user-agent", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Mobile Safari/537.36",
).send().await?
.text()
.await?)
}

pub fn boxed() -> Box<dyn ShowSliderTrait + Sync + Send> {
Box::new(Self)
}

pub fn arc_boxed() -> Arc<Box<dyn ShowSliderTrait + Sync + Send>> {
Arc::new(Box::new(Self))
}
}

#[async_trait]
impl ShowSliderTrait for AndroidHelper {
async fn show_slider(&self, verify_url: Option<String>) -> Result<String> {
tracing::info!("滑动条 (原URL) : {:?}", verify_url);
let helper_url = verify_url
.clone()
.with_context(|| "滑动条URL不存在")?
.replace("ssl.captcha.qq.com", "txhelper.glitch.me");
tracing::info!("滑动条 (改URL) : {:?}", helper_url);
let mut txt = self
.http_get(&helper_url)
.await
.with_context(|| "http请求失败")?;
tracing::info!("您需要使用该仓库 提供的APP进行滑动 , 滑动后请等待, https://github.com/mzdluo123/TxCaptchaHelper : {}", txt);
loop {
sleep(Duration::from_secs(5)).await;
let rsp = self
.http_get(&helper_url)
.await
.with_context(|| "http请求失败")?;
if !rsp.eq(&txt) {
txt = rsp;
break;
}
}
Ok(txt)
}
}

#[cfg(all(any(target_os = "windows"), feature = "pop_window_slider"))]
pub struct PopWindow;

#[cfg(all(any(target_os = "windows"), feature = "pop_window_slider"))]
PopWindow,
impl PopWindow {
pub fn boxed() -> Box<dyn ShowSliderTrait + Sync + Send> {
Box::new(Self)
}

pub fn arc_boxed() -> Arc<Box<dyn ShowSliderTrait + Sync + Send>> {
Arc::new(Box::new(Self))
}
}

#[cfg(all(any(target_os = "windows"), feature = "pop_window_slider"))]
#[async_trait]
impl ShowSliderTrait for PopWindow {
async fn show_slider(&self, verify_url: Option<String>) -> Result<String> {
crate::captcha_window::ticket(verify_url.as_ref().with_context(|| "滑动条URL不存在")?)
.with_context(|| "ticket未获取到")
}
}
}

#[derive(Clone)]
Expand Down
Loading