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

feat(qsign): add qsign client support #45

Merged
merged 3 commits into from
Sep 18, 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
100 changes: 58 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ QQ机器人框架 | [Telegram(电报)机器人框架](https://github.com/niuhuan
## 框架目的

- 简单化 : 让程序员写更少的代码
- 自动管理客户端生命周期以及TCP重连
- 封装登录流程, 自动获取ticket, 验证滑动条
- 自动管理客户端生命周期以及TCP重连
- 封装登录流程, 自动获取ticket, 验证滑动条
- 模块化 : 让调理更清晰
- 模块化, 实现插件之间的分离, 更好的启用禁用
- 模块化, 实现插件之间的分离, 更好的启用禁用

# 设计思路

Expand Down Expand Up @@ -112,56 +112,65 @@ pub(crate) fn module() -> Module {
main.rs

```rust
use tracing::Level;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

use std::sync::Arc;
use proc_qq::re_exports::ricq;
use proc_qq::Authentication::{QRCode, UinPassword};
use proc_qq::ClientBuilder;
use tracing::Level;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

mod hello_module;

/// 启动并使用为二维码登录
#[tokio::test]
async fn test_qr_login() {
// 初始化日志打印
init_tracing_subscriber();
// 使用builder创建
let client = ClientBuilder::new()
// 使用session.token登录
// .session_store(Box::new(FileSessionStore {
// path: "session.token".to_string(),
// }))
.authentication(QRCode) // 若不成功则使用二维码登录
// 注意,这里使用的设备必须支持二维码登录,例如安卓手表
// 如果您使用为不支持的协议协议,则会登录失败,例如安卓QQ
// .authentication(UinPasswordMd5(config.account.uin, password)) // 账号密码登录
.device(JsonFile("device.json")) // 设备默认值
.version(&ANDROID_WATCH) // 安卓手表支持扫码登录
// .show_slider_pop_menu_if_possible() // 密码登录时, 如果是windows, 弹出一个窗口代替手机滑块 (需要启用feature=pop_window_slider)
.modules(vec![hello_module::module()]) // 您可以注册多个模块
.schedulers(vec![scheduler_handlers::scheduler()]) // 设置定时任务
.show_rq(Some(ShowQR::OpenBySystem)) // 自动打开二维码 在macos/linux/windows中, 不支持安卓
.build()
.await
.unwrap();
run_client(Arc::new(client)).await?;
// 初始化日志打印
init_tracing_subscriber();
// 设置签名服务器
let qsign =
ricq::qsign::QSignClient::new(
"url".to_owned(),
"key ".to_owned(),
Duration::from_secs(60),
).expect("qsign client build err");
// 使用builder创建
let client = ClientBuilder::new()
// 使用session.token登录
// .session_store(Box::new(FileSessionStore {
// path: "session.token".to_string(),
// }))
.authentication(QRCode) // 若不成功则使用二维码登录
// 注意,这里使用的设备必须支持二维码登录,例如安卓手表
// 如果您使用为不支持的协议协议,则会登录失败,例如安卓QQ
// .authentication(UinPasswordMd5(config.account.uin, password)) // 账号密码登录
.device(JsonFile("device.json".to_owned())) // 设备默认值
.version(&ANDROID_WATCH) // 安卓手表支持扫码登录
.qsign(Some(Arc::new(qsign))) // 签名服务器,目前的版本必须使用
// .show_slider_pop_menu_if_possible() // 密码登录时, 如果是windows, 弹出一个窗口代替手机滑块 (需要启用feature=pop_window_slider)
.modules(vec![hello_module::module()]) // 您可以注册多个模块
.schedulers(vec![scheduler_handlers::scheduler()]) // 设置定时任务
.show_rq(Some(ShowQR::OpenBySystem)) // 自动打开二维码 在macos/linux/windows中, 不支持安卓
.build()
.await
.unwrap();
run_client(Arc::new(client)).await?;
}

fn init_tracing_subscriber() {
tracing_subscriber::registry()
.with(
tracing_subscriber::registry()
.with(
tracing_subscriber::fmt::layer()
.with_target(true)
.without_time(),
)
.with(
.with_target(true)
.without_time(),
)
.with(
tracing_subscriber::filter::Targets::new()
.with_target("ricq", Level::DEBUG)
.with_target("proc_qq", Level::DEBUG)
// 这里改成自己的crate名称
.with_target("proc_qq_examples", Level::DEBUG),
)
.init();
.with_target("ricq", Level::DEBUG)
.with_target("proc_qq", Level::DEBUG)
// 这里改成自己的crate名称
.with_target("proc_qq_examples", Level::DEBUG),
)
.init();
}

```
Expand Down Expand Up @@ -202,6 +211,13 @@ use proc_qq::{

支持更多种事件封装中...

### 签名服务器
> 从`8.9.63`开始,QQ使用了签名服务器,在不使用签名服务器的情况下将无法登录

搭建方法可到 https://github.com/fuqiuluo/unidbg-fetch-qsign 查看
或者使用 `docker` 直接运行 `docker run -d --restart=always --name qsign -p 8080:8080 xzhouqd/qsign:8.9.63`
**请注意 sso 版本必须和协议版本一致**

## 字段匹配

对消息进行匹配(`空白字符`或`RQElem界限`作为分隔符)
Expand Down Expand Up @@ -484,8 +500,8 @@ event.reply_text("你好").await?;
##### 额外协议的说明

- 暂定本仓库开源协议与RICQ保持一致.
- MPL 2.0
- 如RICQ更换协议, 请以最新协议为准, 您可以提出ISSUE提醒我进行更新
- MPL 2.0
- 如RICQ更换协议, 请以最新协议为准, 您可以提出ISSUE提醒我进行更新
- 仓库持有人在变更仓库协议时无需经过其他代码贡献者的同意, 您在PR时就代表您同意此观点

## 贡献代码
Expand Down
4 changes: 2 additions & 2 deletions proc_qq/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ proc_qq_codegen = { path = "../proc_qq_codegen" }
bytes = "1"
tokio = { version = "1", features = ["full"] }
tracing = "0.1"
ricq = { git = "https://github.com/lz1998/ricq.git", rev = "5182cb7" }
ricq-core = { git = "https://github.com/lz1998/ricq.git", rev = "5182cb7" }
ricq = { git = "https://github.com/lz1998/ricq.git", branch = "master" }
ricq-core = { git = "https://github.com/lz1998/ricq.git", branch = "master" }
anyhow = "1.0"
serde = "1.0"
serde_json = "1.0"
Expand Down
12 changes: 12 additions & 0 deletions proc_qq/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use futures::future::BoxFuture;
use futures::FutureExt;
use rand::prelude::IteratorRandom;
use ricq::ext::common::after_login;
use ricq::qsign::QSignClient;
use ricq_core::binary::{BinaryReader, BinaryWriter};
use ricq_core::command::wtlogin::{
LoginDeviceLocked, LoginNeedCaptcha, LoginResponse, LoginSuccess, LoginUnknownStatus,
Expand Down Expand Up @@ -544,6 +545,7 @@ pub fn bytes_to_token(token: Vec<u8>) -> Token {

/// 用于构建客户端
pub struct ClientBuilder {
qsign_client: Option<Arc<QSignClient>>,
device_source: DeviceSource,
version: &'static Version,
authentication: Option<Authentication>,
Expand All @@ -564,6 +566,7 @@ impl ClientBuilder {
// 构造
pub fn new() -> Self {
Self {
qsign_client: None,
device_source: DeviceSource::default(),
version: &ANDROID_PHONE,
authentication: None,
Expand All @@ -581,6 +584,12 @@ impl ClientBuilder {
}
}

/// 设置签名服务器
pub fn qsign<S: Into<Option<Arc<QSignClient>>>>(mut self, h: S) -> Self {
self.qsign_client = h.into();
self
}

/// 设置模块
pub fn modules<S: Into<Arc<Vec<Module>>>>(mut self, h: S) -> Self {
self.modules_vec = h.into();
Expand Down Expand Up @@ -657,6 +666,9 @@ impl ClientBuilder {
JsonString(json_string) => parse_device_json(json_string)?,
},
self.version.clone(),
self.qsign_client
.clone()
.with_context(|| "您必须设置签名服务器")?,
ClientHandler {
modules: self.modules_vec.clone(),
result_handlers: self.result_handlers_vec.clone(),
Expand Down
6 changes: 6 additions & 0 deletions proc_qq_examples/src/input_uin_password/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::io::{stdin, stdout, Write};
use std::sync::Arc;
use std::time::Duration;

use proc_qq::re_exports::async_trait::async_trait;
use proc_qq::re_exports::ricq;
use proc_qq::re_exports::ricq::version::ANDROID_PHONE;
use proc_qq::*;
use proc_qq_examples::init_tracing_subscriber;
Expand All @@ -11,13 +13,17 @@ use proc_qq_examples::{hello_module, scheduler_handlers};
#[tokio::main]
async fn main() {
init_tracing_subscriber();
let qsign =
ricq::qsign::QSignClient::new("url".to_owned(), "key ".to_owned(), Duration::from_secs(60))
.expect("qsign client build err");
let client = ClientBuilder::new()
.authentication(Authentication::CustomUinPassword(Arc::new(Box::new(
InputUinPassword {},
))))
.show_slider_pop_menu_if_possible()
.device(DeviceSource::JsonFile("device.json".to_owned()))
.version(&ANDROID_PHONE)
.qsign(Some(Arc::new(qsign)))
.session_store(Box::new(FileSessionStore {
path: "session.token".to_string(),
}))
Expand Down
10 changes: 8 additions & 2 deletions proc_qq_examples/src/password_login/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use proc_qq::re_exports::ricq::version::ANDROID_PHONE;
use proc_qq::*;
use std::sync::Arc;
use std::time::Duration;

use proc_qq::re_exports::ricq;
use proc_qq::re_exports::ricq::version::ANDROID_PHONE;
use proc_qq::*;
use proc_qq_examples::hello_module;
use proc_qq_examples::init_tracing_subscriber;
use proc_qq_examples::result_handlers;
Expand All @@ -10,11 +12,15 @@ use proc_qq_examples::scheduler_handlers;
#[tokio::main]
async fn main() {
init_tracing_subscriber();
let qsign =
ricq::qsign::QSignClient::new("url".to_owned(), "key ".to_owned(), Duration::from_secs(60))
.expect("qsign client build err");
let client = ClientBuilder::new()
.authentication(Authentication::UinPasswordMd5(123456, [0; 16]))
.show_slider_pop_menu_if_possible()
.device(DeviceSource::JsonFile("device.json".to_owned()))
.version(&ANDROID_PHONE)
.qsign(Some(Arc::new(qsign)))
.session_store(Box::new(FileSessionStore {
path: "session.token".to_string(),
}))
Expand Down
6 changes: 6 additions & 0 deletions proc_qq_template/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ extern crate core;
use crate::config::load_config;
use crate::database::mongo::init_mongo;
use crate::database::redis::init_redis;
use proc_qq::re_exports::ricq;
use proc_qq::re_exports::ricq::version::ANDROID_WATCH;
use proc_qq::Authentication::UinPasswordMd5;
use proc_qq::{run_client, ClientBuilder, DeviceSource, FileSessionStore};
use std::sync::Arc;
use std::time::Duration;
use tracing::Level;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
Expand All @@ -26,11 +28,15 @@ async fn main() -> anyhow::Result<()> {
let password_vec = hex::decode(config.account.password_md5)?;
let mut password = [0 as u8; 16];
password[..16].clone_from_slice(password_vec.as_slice());
let qsign =
ricq::qsign::QSignClient::new("url".to_owned(), "key ".to_owned(), Duration::from_secs(60))
.expect("qsign client build err");
let client = ClientBuilder::new()
.device(DeviceSource::JsonFile("device.json".to_owned()))
.version(&ANDROID_WATCH)
.session_store(FileSessionStore::boxed("session.token"))
.authentication(UinPasswordMd5(config.account.uin, password))
.qsign(Some(Arc::new(qsign)))
.show_slider_pop_menu_if_possible()
.modules(modules::all_modules())
.build()
Expand Down
Loading