Skip to main content

futu_backend/auth/
mod.rs

1// HTTP 认证模块 — 移植自成功项目 futuopend-rs
2//
3// 流程: salt → tgtgt → POST auth → (可能设备验证) → client_sig + client_key
4
5use base64::Engine;
6use futu_core::error::{FutuError, Result};
7
8mod auth_ip_list;
9mod broker;
10pub mod redact;
11/// v1.4.93 G2 (CLAUDE.md C4 audit): RepullAuthCode broker auth_code self-heal.
12/// Triggered when broker auth_code expires (typical 30-day window) or
13/// `kAuthNoValidCid` (20029); avoids requiring a daemon restart.
14pub mod repull;
15#[doc(hidden)]
16pub mod site_config;
17mod webtcp;
18pub use broker::{
19    BrokerAuth, BrokerAuthRequest, BrokerAuthRouteCache, BrokerConfig, broker_auth, broker_config,
20    is_cpp_known_broker_id,
21};
22pub use futu_domain_auth::AuthRefreshReason;
23pub use repull::{ERROR_CODE_NO_VALID_CID, repull_auth_code, repull_auth_code_with_client_type};
24pub use webtcp::install_default_rustls_crypto_provider;
25pub mod commconfig;
26mod parse;
27mod util;
28pub(crate) use util::device_type;
29
30/// Platform 通道后端连接点,按 `UserAttribution` 分池。
31///
32/// 完整对齐 C++ `FTLogin/Src/ftlogin/channel/impl/address.cpp:495-557`
33/// `LoadHardcodeAddress()` 里 `CONN_PLATFORM_*` 的条目。每个 IP 后面是 C++
34/// 源里的 `Region::kRegion*` 字段(gz/sh/hk/us/sg/au/jp),仅作注释。
35///
36/// v1.4.11 前只有 CN 12 个 IP,海外账号(HK/US/SG/AU/JP)首选 IP 命中 CN 池
37/// → 非大陆网络连不通 → 进 offline mode。v1.4.10 的 fallback 逻辑即使有也只
38/// 会 fallback 到其他 CN IP,依然死路。修复方式是按 `user_attribution` 选池。
39///
40/// 端口 9595 是 C++ 硬编码的标准端口。
41pub mod conn_points;
42// v1.4.110+ Tier 1 split: 顶层类型 + 2 const 抽到 types.rs (无业务逻辑).
43mod types;
44pub use types::{
45    AUTH_SERVER_PROD, AuthChallengePort, AuthChallengeWork, AuthConfig, AuthResult, AuthSession,
46    BrokerAuthCode, CredentialTicketStatus, TGTGT_VALIDITY_SECS, UserAttribution,
47};
48mod credentials_refresh;
49pub use credentials_refresh::{
50    REFRESH_TIMEOUT, RefreshCredentialsReport, refresh_credentials_on_disk,
51};
52mod login;
53pub use login::{
54    VerifyCodeCallback, authenticate, authenticate_with_callback, authenticate_with_challenge_port,
55    with_auth_challenge_port,
56};
57// v1.4.110+ Tier 1 split: reqwest HTTP client builder 抽到 http_client.rs.
58mod http_client;
59pub use http_client::build_http_client;
60pub(crate) use http_client::build_http_client_with_resolve;
61
62mod phone;
63use phone::normalize_phone_account;
64
65mod device;
66pub use device::{
67    DeviceStoreError, WebSigPersistenceError, forget_cached_credentials, persist_broker_websig,
68    persist_platform_websigs, read_or_generate_device_id, reset_device_state,
69    tighten_secret_files_at_startup,
70};
71pub(crate) use device::{try_futu_opend_dir, write_secret_file};
72
73/// Return non-sensitive metadata about the cached auth ticket for diagnostics.
74pub fn credential_ticket_status(account: &str) -> Option<CredentialTicketStatus> {
75    device::credential_ticket_status(account)
76}
77
78fn decode_saved_rand_key_b64(rand_key_b64: &str) -> Result<Vec<u8>> {
79    let rand_key = base64::engine::general_purpose::STANDARD
80        .decode(rand_key_b64)
81        .map_err(|e| FutuError::Codec(format!("rand_key base64 decode: {e}")))?;
82    parse::validate_account_rand_key_len("cached credentials rand_key_b64", &rand_key)?;
83    Ok(rand_key)
84}
85
86// v1.4.110+ Tier 2/3 split: 登录主流程、磁盘凭据刷新、remember-login、
87// password-auth、device-verify 分别由 sibling modules 收口;root 只保留 facade。
88mod device_verify;
89mod endpoints;
90mod password_auth;
91mod remember;
92
93#[cfg(test)]
94mod tests;