Skip to main content

futu_backend/auth/commconfig/
mod.rs

1//! CommConfig transaction actor and atomically published last-good snapshot.
2//!
3//! C++ `PullCommonConfigV2()` 对齐:动态拉取后台 IP 池 + 配置, 比 DNS / 硬编码
4//! 更权威 (`guaranteed_ip_for_conn` 按 ConnIdentity 分组).
5//!
6//! Network IO, page action policy, raw transaction accumulation, typed
7//! projection, persistence, and publication stay in separate modules so a
8//! partial transaction can never escape as a runtime snapshot.
9//!
10//! Parent auth/mod.rs `pub mod commconfig;` 路径不变 (mod.rs re-export 全 pub 项).
11
12mod accessors;
13mod clock;
14mod fetch_page;
15mod parsers;
16mod projection;
17mod runner;
18mod snapshot;
19mod store;
20mod totp;
21mod transaction;
22mod types;
23mod wire;
24
25#[cfg(test)]
26mod tests;
27
28// hoist for tests.rs (super::* 接 trade_query 类似套路)
29#[cfg(test)]
30pub(super) use super::*;
31
32// ===== 外部 callers 直接用的 (auth/webtcp.rs, auth/broker.rs, auth/mod.rs) =====
33pub use accessors::{
34    broker_auth_webtcp_identity, default_webtcp_identity_for_client_type,
35    forced_ip_for_attribution, ips_for_attribution, ips_for_broker, ips_for_web_identity,
36    webtcp_addrs_for_identity, webtcp_hardcoded_addrs,
37};
38pub use clock::server_now_ts;
39pub use fetch_page::{api_root_for_client, client_version_dotted};
40pub use parsers::{
41    is_web_identity, project_order_ability_config, resolve_order_ability_capability,
42};
43pub use runner::{
44    COMMCONFIG_PRE_LOGIN_TIMEOUT, CommConfigBootstrapOutcome, CommConfigPersistence,
45    bootstrap_before_login, spawn_actor,
46};
47pub use snapshot::{SharedCommConfig, empty_snapshot, new_shared_snapshot};
48pub use store::{CommConfigStoreError, load_last_good_snapshot};
49pub use totp::gen_totp_sha1;
50pub use types::{
51    AuthGuaranteedDomainMap, CONN_WEB_AU, CONN_WEB_CA, CONN_WEB_CN, CONN_WEB_HK, CONN_WEB_JP,
52    CONN_WEB_MY, CONN_WEB_SG, CONN_WEB_US, CommConfigSource, CommonConfigSnapshot, ForcedIpEntry,
53    ForcedIpMap, GuaranteedBrokerIpMap, GuaranteedIpMap, GuaranteedWebIpMap,
54    OrderAbilityCapability, OrderAbilityConfig, OrderAbilityConfigError, OrderAbilityTradeType,
55};
56
57/// Build the shared Futu common HTTP `auth_token`.
58///
59/// Ref: C++ `NNProtoCenter/NNProtoCenter_Inner_Inline.h`
60/// `NNProto_BuildCommonHttpClientToken()` uses key `PEHMABDNLXIOG65U`,
61/// server time, 30s period, and `GenGoogleOTPCode_SHA1`.
62pub fn common_http_auth_token(unix_ts: i64) -> Option<String> {
63    gen_totp_sha1(types::AUTH_TOKEN_KEY_B32, unix_ts, 30)
64}
65
66/// Build the C++ common HTTP `client_token`.
67///
68/// Ref: `FutuOpenD/Src/NNProtoCenter/Login/NNDataUrl.cpp:222-235`
69/// `NNDataUrl::GetTimeEncryptKey()` writes server time into a 16-byte block,
70/// encrypts it with AES-128 using ASCII key `PEHMABDNLXIOG65U`, then hex encodes
71/// the encrypted block.
72pub fn common_http_client_token(unix_ts: i64) -> Option<String> {
73    if unix_ts <= 0 {
74        return None;
75    }
76
77    let unix_ts = unix_ts.to_string();
78    let mut block = [0u8; 16];
79    let bytes = unix_ts.as_bytes();
80    let len = bytes.len().min(block.len());
81    block[..len].copy_from_slice(&bytes[..len]);
82
83    use aes::cipher::{BlockCipherEncrypt, KeyInit};
84    let cipher = aes::Aes128::new_from_slice(types::AUTH_TOKEN_KEY_B32.as_bytes()).ok()?;
85    let mut cipher_block = aes::cipher::Block::<aes::Aes128>::from(block);
86    cipher.encrypt_block(&mut cipher_block);
87    Some(hex::encode(cipher_block))
88}
89
90// ===== 内部 re-export 给 sibling tests.rs (super::* 接) =====
91#[cfg(test)]
92pub(super) use accessors::delay_until_next_refresh;
93#[cfg(test)]
94pub(super) use clock::server_now_ts_at;
95#[cfg(test)]
96pub(super) use parsers::{
97    is_broker_identity, parse_auth_guaranteed_domain_list, parse_forced_ip, parse_guaranteed_ip,
98    parse_web_tcp_config_identity, value_kind,
99};
100#[cfg(test)]
101pub(super) use std::collections::HashMap;
102#[cfg(test)]
103pub(super) use totp::base32_decode;