Skip to content

Commit 342c846

Browse files
committed
Implemented trans_emp 0x31
1 parent 04de7b3 commit 342c846

File tree

27 files changed

+2414
-502
lines changed

27 files changed

+2414
-502
lines changed

Cargo.lock

Lines changed: 1141 additions & 33 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/lagrange-core-runner/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ path = "src/main.rs"
1313

1414
[dependencies]
1515
# Core library
16-
lagrange-core = { path = "../lagrange-core" }
16+
lagrange-core = { path = "../lagrange-core", features = ["sign-provider"] }
1717

1818
# Async runtime
1919
tokio.workspace = true

crates/lagrange-core-runner/src/main.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
use anyhow::Result;
2-
use lagrange_core::{config::BotConfig, keystore::BotKeystore, protocol::Protocols, BotContext};
2+
use lagrange_core::{
3+
common::sign::{DefaultSignProvider, SignProvider},
4+
config::BotConfig,
5+
protocol::Protocols,
6+
BotContext,
7+
};
38
use std::sync::Arc;
4-
use tracing::{error, info, warn, Level};
9+
use tracing::{error, info, Level};
510
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
611

712
const BOT_UIN: Option<u64> = None;
@@ -20,28 +25,21 @@ async fn main() -> Result<()> {
2025
info!("Protocol: {:?}", BOT_PROTOCOL);
2126
info!("Log Level: {:?}", LOG_LEVEL);
2227

28+
// Initialize sign provider
29+
let sign_provider = Arc::new(DefaultSignProvider::new());
30+
info!("Using sign provider: {}", sign_provider.platform());
31+
2332
let config = BotConfig::builder()
2433
.protocol(BOT_PROTOCOL)
2534
.verbose(BOT_VERBOSE)
2635
.auto_reconnect(AUTO_RECONNECT)
2736
.auto_re_login(AUTO_RELOGIN)
37+
.sign_provider(sign_provider)
2838
.build();
2939

30-
let keystore = match BOT_UIN {
31-
Some(uin) => {
32-
info!("Bot UIN configured: {}", uin);
33-
BotKeystore::default().with_uin(uin)
34-
}
35-
None => {
36-
warn!("No BOT_UIN configured - set it in main.rs");
37-
BotKeystore::default()
38-
}
39-
};
40-
4140
info!("Building bot context...");
4241
let context = BotContext::builder()
4342
.config(config)
44-
.keystore(keystore)
4543
.build();
4644

4745
setup_event_handlers(context.clone());
@@ -50,10 +48,11 @@ async fn main() -> Result<()> {
5048
info!("Press Ctrl+C to shutdown gracefully");
5149

5250
context.connect().await.expect("Failed to establish initial connection");
53-
54-
// Start connection monitor for auto-reconnect
5551
context.clone().start_connection_monitor();
5652

53+
let qrcode = context.fetch_qrcode().await?;
54+
info!("QR Code URL: {}", qrcode.len());
55+
5756
match tokio::signal::ctrl_c().await {
5857
Ok(()) => {
5958
info!("Received shutdown signal, cleaning up...");

crates/lagrange-core/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,11 @@ sha1 = "0.10"
2828
sha2 = "0.10"
2929
md5 = "0.7"
3030
num-bigint = "0.4"
31+
32+
# Optional: Sign provider
33+
reqwest = { version = "0.12", features = ["json"], optional = true }
34+
serde_json = { version = "1.0", optional = true }
35+
hex = { version = "0.4", optional = true }
36+
37+
[features]
38+
sign-provider = ["reqwest", "serde_json", "hex", "base64"]
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
pub mod network;
1+
pub mod network;
2+
mod account;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use std::sync::Arc;
2+
use crate::{BotContext, Error};
3+
use crate::internal::services::{TransEmp31EventReq};
4+
5+
impl BotContext {
6+
pub async fn fetch_qrcode(self: &Arc<Self>) -> Result<Vec<u8>, Error> {
7+
let event = TransEmp31EventReq {
8+
unusual_sig: None
9+
};
10+
if let Err(e) = self.event.send_event(self.clone(), event).await {
11+
tracing::warn!(error = %e, "Failed to send fetch_qrcode");
12+
}
13+
14+
Ok(vec![])
15+
}
16+
}

crates/lagrange-core/src/common/sign.rs

Lines changed: 194 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ use async_trait::async_trait;
22
use bytes::Bytes;
33
use std::sync::Arc;
44

5+
#[cfg(feature = "sign-provider")]
6+
use std::collections::HashSet;
7+
58
#[async_trait]
69
pub trait SignProvider: Send + Sync + std::fmt::Debug {
710
async fn sign(&self, cmd: &str, seq: u32, data: &[u8]) -> Option<SignResult>;
@@ -19,20 +22,20 @@ pub struct SignResult {
1922
}
2023

2124
#[derive(Debug)]
22-
pub struct DefaultSignProvider;
25+
pub struct NoOpSignProvider;
2326

2427
#[async_trait]
25-
impl SignProvider for DefaultSignProvider {
28+
impl SignProvider for NoOpSignProvider {
2629
async fn sign(&self, _cmd: &str, _seq: u32, _data: &[u8]) -> Option<SignResult> {
2730
None
2831
}
2932

3033
fn platform(&self) -> &str {
31-
"default"
34+
"noop"
3235
}
3336
}
3437

35-
impl Default for DefaultSignProvider {
38+
impl Default for NoOpSignProvider {
3639
fn default() -> Self {
3740
Self
3841
}
@@ -75,3 +78,190 @@ impl Default for AndroidSignProvider {
7578
}
7679

7780
pub type BoxedSignProvider = Arc<dyn SignProvider>;
81+
82+
#[cfg(feature = "sign-provider")]
83+
mod default {
84+
use super::*;
85+
use serde::{Deserialize, Serialize};
86+
87+
const SIGN_API_URL: &str = "";
88+
89+
#[derive(Debug, Serialize)]
90+
struct SignRequest {
91+
cmd: String,
92+
seq: u32,
93+
src: String,
94+
}
95+
96+
#[derive(Debug, Deserialize)]
97+
struct SignResponse {
98+
value: SignResponseValue,
99+
}
100+
101+
#[derive(Debug, Deserialize)]
102+
struct SignResponseValue {
103+
sign: String,
104+
token: String,
105+
extra: String,
106+
}
107+
108+
#[derive(Debug)]
109+
pub struct DefaultSignProvider {
110+
client: reqwest::Client,
111+
whitelist: HashSet<String>,
112+
}
113+
114+
impl DefaultSignProvider {
115+
pub fn new() -> Self {
116+
let whitelist = Self::build_whitelist();
117+
Self {
118+
client: reqwest::Client::new(),
119+
whitelist,
120+
}
121+
}
122+
123+
fn build_whitelist() -> HashSet<String> {
124+
let mut set = HashSet::new();
125+
126+
set.insert("trpc.o3.ecdh_access.EcdhAccess.SsoEstablishShareKey".to_string());
127+
set.insert("trpc.o3.ecdh_access.EcdhAccess.SsoSecureAccess".to_string());
128+
set.insert("trpc.o3.report.Report.SsoReport".to_string());
129+
set.insert("MessageSvc.PbSendMsg".to_string());
130+
set.insert("wtlogin.trans_emp".to_string());
131+
set.insert("wtlogin.login".to_string());
132+
set.insert("wtlogin.exchange_emp".to_string());
133+
set.insert("trpc.login.ecdh.EcdhService.SsoKeyExchange".to_string());
134+
135+
set.insert("trpc.login.ecdh.EcdhService.SsoNTLoginPasswordLogin".to_string());
136+
set.insert("trpc.login.ecdh.EcdhService.SsoNTLoginEasyLogin".to_string());
137+
set.insert("trpc.login.ecdh.EcdhService.SsoNTLoginPasswordLoginNewDevice".to_string());
138+
set.insert("trpc.login.ecdh.EcdhService.SsoNTLoginEasyLoginUnusualDevice".to_string());
139+
set.insert("trpc.login.ecdh.EcdhService.SsoNTLoginPasswordLoginUnusualDevice".to_string());
140+
set.insert("trpc.login.ecdh.EcdhService.SsoNTLoginRefreshTicket".to_string());
141+
set.insert("trpc.login.ecdh.EcdhService.SsoNTLoginRefreshA2".to_string());
142+
143+
set.insert("OidbSvcTrpcTcp.0x11ec_1".to_string());
144+
set.insert("OidbSvcTrpcTcp.0x758_1".to_string());
145+
set.insert("OidbSvcTrpcTcp.0x7c1_1".to_string());
146+
set.insert("OidbSvcTrpcTcp.0x7c2_5".to_string());
147+
set.insert("OidbSvcTrpcTcp.0x10db_1".to_string());
148+
set.insert("OidbSvcTrpcTcp.0x8a1_7".to_string());
149+
set.insert("OidbSvcTrpcTcp.0x89a_0".to_string());
150+
set.insert("OidbSvcTrpcTcp.0x89a_15".to_string());
151+
set.insert("OidbSvcTrpcTcp.0x88d_0".to_string());
152+
set.insert("OidbSvcTrpcTcp.0x88d_14".to_string());
153+
set.insert("OidbSvcTrpcTcp.0x112a_1".to_string());
154+
set.insert("OidbSvcTrpcTcp.0x587_74".to_string());
155+
set.insert("OidbSvcTrpcTcp.0x587_103".to_string());
156+
set.insert("OidbSvcTrpcTcp.0x1100_1".to_string());
157+
set.insert("OidbSvcTrpcTcp.0x1102_1".to_string());
158+
set.insert("OidbSvcTrpcTcp.0x1103_1".to_string());
159+
set.insert("OidbSvcTrpcTcp.0x1107_1".to_string());
160+
set.insert("OidbSvcTrpcTcp.0x1105_1".to_string());
161+
set.insert("OidbSvcTrpcTcp.0xf88_1".to_string());
162+
set.insert("OidbSvcTrpcTcp.0xf89_1".to_string());
163+
set.insert("OidbSvcTrpcTcp.0xf57_1".to_string());
164+
set.insert("OidbSvcTrpcTcp.0xf57_106".to_string());
165+
set.insert("OidbSvcTrpcTcp.0xf57_9".to_string());
166+
set.insert("OidbSvcTrpcTcp.0xf55_1".to_string());
167+
set.insert("OidbSvcTrpcTcp.0xf67_1".to_string());
168+
set.insert("OidbSvcTrpcTcp.0xf67_5".to_string());
169+
set.insert("OidbSvcTrpcTcp.0x10c0_1".to_string());
170+
set.insert("OidbSvcTrpcTcp.0x10c3_1".to_string());
171+
set.insert("OidbSvcTrpcTcp.0x1ba9".to_string());
172+
set.insert("OidbSvcTrpcTcp.0x6d9_4".to_string());
173+
174+
set
175+
}
176+
177+
pub fn is_whitelisted(&self, cmd: &str) -> bool {
178+
self.whitelist.contains(cmd)
179+
}
180+
181+
async fn decode_hex_field(hex_str: &str) -> Result<Bytes, String> {
182+
hex::decode(hex_str)
183+
.map(Bytes::from)
184+
.map_err(|e| format!("Failed to decode hex string: {}", e))
185+
}
186+
}
187+
188+
impl Default for DefaultSignProvider {
189+
fn default() -> Self {
190+
Self::new()
191+
}
192+
}
193+
194+
#[async_trait]
195+
impl SignProvider for DefaultSignProvider {
196+
async fn sign(&self, cmd: &str, seq: u32, data: &[u8]) -> Option<SignResult> {
197+
if !self.is_whitelisted(cmd) {
198+
tracing::debug!(cmd = cmd,"Command not in whitelist, skipping sign");
199+
return None;
200+
}
201+
202+
let request = SignRequest {
203+
cmd: cmd.to_string(),
204+
seq,
205+
src: hex::encode(data),
206+
};
207+
208+
let response = match self.client
209+
.post(SIGN_API_URL)
210+
.json(&request)
211+
.send()
212+
.await
213+
{
214+
Ok(resp) => resp,
215+
Err(e) => {
216+
tracing::error!(error = %e, cmd = cmd, seq = seq, "Failed to send sign request");
217+
return None;
218+
}
219+
};
220+
221+
let sign_response: SignResponse = match response.json().await {
222+
Ok(data) => data,
223+
Err(e) => {
224+
tracing::error!(error = %e, cmd = cmd, seq = seq, "Failed to parse sign response");
225+
return None;
226+
}
227+
};
228+
229+
let sign = match Self::decode_hex_field(&sign_response.value.sign).await {
230+
Ok(bytes) => bytes,
231+
Err(e) => {
232+
tracing::error!(error = e, field = "sign", "Failed to decode hex");
233+
return None;
234+
}
235+
};
236+
237+
let token = match Self::decode_hex_field(&sign_response.value.token).await {
238+
Ok(bytes) => bytes,
239+
Err(e) => {
240+
tracing::error!(error = e, field = "token", "Failed to decode hex");
241+
return None;
242+
}
243+
};
244+
245+
let extra = match Self::decode_hex_field(&sign_response.value.extra).await {
246+
Ok(bytes) => bytes,
247+
Err(e) => {
248+
tracing::error!(error = e, field = "extra", "Failed to decode hex");
249+
return None;
250+
}
251+
};
252+
253+
Some(SignResult {
254+
sign,
255+
token,
256+
extra,
257+
})
258+
}
259+
260+
fn platform(&self) -> &str {
261+
"default"
262+
}
263+
}
264+
}
265+
266+
#[cfg(feature = "sign-provider")]
267+
pub use default::DefaultSignProvider;

crates/lagrange-core/src/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
common::{sign::BoxedSignProvider, sign::DefaultSignProvider},
2+
common::{sign::BoxedSignProvider, sign::NoOpSignProvider},
33
protocol::Protocols,
44
};
55
use serde::{Deserialize, Serialize};
@@ -94,7 +94,7 @@ impl BotConfig {
9494
pub fn get_sign_provider(&self) -> BoxedSignProvider {
9595
self.sign_provider
9696
.clone()
97-
.unwrap_or_else(|| Arc::new(DefaultSignProvider))
97+
.unwrap_or_else(|| Arc::new(NoOpSignProvider))
9898
}
9999
}
100100

crates/lagrange-core/src/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl Default for BotContextBuilder {
8787
Self {
8888
config: Some(BotConfig::default()),
8989
app_info: Some(BotAppInfo::default()),
90-
keystore: Some(BotKeystore::default()),
90+
keystore: Some(BotKeystore::new()),
9191
}
9292
}
9393
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
pub mod qr_login_ext_info;
12
pub mod tlv;
23
pub mod tlv_qrcode;
34
pub mod tlv_writer;
45
pub mod wtlogin;
56

7+
pub use qr_login_ext_info::{DevInfo, GenInfo, QrExtInfo, ScanExtInfo};
68
pub use wtlogin::WtLogin;

0 commit comments

Comments
 (0)