pub struct AuthResult {
pub user_id: u64,
pub client_sig: Vec<u8>,
pub client_key: Vec<u8>,
pub user_attribution: UserAttribution,
pub auth_code_list: Vec<BrokerAuthCode>,
pub rand_key: Vec<u8>,
pub svr_time_offset: i64,
pub web_sig: String,
pub client_sig_invalid_local_time_s: u64,
pub moomoo_client_sig: Vec<u8>,
pub moomoo_client_key: Vec<u8>,
pub moomoo_web_sig: String,
}Fields§
§user_id: u64§client_sig: Vec<u8>§client_key: Vec<u8>§user_attribution: UserAttribution从 salt 响应拿到的归属地,TCP 登录时会用来派生 conn_identity
auth_code_list: Vec<BrokerAuthCode>HTTP auth 响应的 auth_code_list——每个已授权 broker 的票据,
用来后续向 /broker_auth/client_auth 换取 broker_client_sig / broker_client_key
rand_key: Vec<u8>原始 rand_key(解密用)——broker_auth 响应里的 broker_client_key 也是
用这个 rand_key 加密过的,需要它做 aes_cbc_md5_decrypt_var 解开
svr_time_offset: i64v1.4.22:服务端时间 - 本机时间(秒)—— salt 响应时捕获。
用于让后续 TOTP / time-based token 用“服务端时间“而不是本机时间。
机器时钟飘了 > 30s 的场景下 TOTP 会被服务端拒,offset 校正后可免。
对齐 C++ INNBiz_SvrTime::GetSvrTimeStamp() 机制。
使用方式:let server_now = local_now + svr_time_offset;
首次 salt 时 offset < 0 说明本机时钟比服务端快,反之则慢。0 = 没取到。
web_sig: Stringv1.4.93 G3 (CLAUDE.md C4 audit): web_sig from /authority/ 响应里的
web_sig_new 字段(对齐 C++ auth_impl.cpp:3193,3260
account.web_sig_)。
用途:G2 crate::auth::repull::repull_auth_code 把它作 POST
/authority/repull_auth_code body 字段(C++ auth_impl.cpp:738-748),
broker auth_code 过期时拉新 auth_code,让 broker channel self-heal
不必重启 daemon。
缺失 → 空字符串(旧 v1.4.92 及之前的凭据 / device-verify shell 路径 没此字段)。空时调用方应跳过 repull, fallback 走 platform refresh。
client_sig_invalid_local_time_s: u64v1.4.93 G1 (CLAUDE.md C4 audit P1): client_sig 失效的本地时戳 (秒, UTC epoch).
对齐 C++ auth_impl.cpp:3245-3247 解 cltsig_invalidtime
(服务端绝对过期 epoch),再按
(cltsig_invalidtime - svr_time) + local_now 得本地时间, 写到
account.client_sig_invalid_local_time_s_.
用途: 记录服务端下发的 client_sig 失效时间。当前 auth 模块只负责 解析/持久化该字段,不启动 proactive timer;长跑 daemon 的 client_sig 更新走 reconnect 失败后的 reactive remember-login refresh 路径。
缺失 (老 backend / 旧 credentials shell): 0 (不触发 proactive refresh).
moomoo_client_sig: Vec<u8>v1.4.94 G6 (P2 protocol gap): moomoo_client_sig from /authority/
响应里的 moomoo_client_sig 字段, base64 已解码.
对齐 C++ auth_impl.cpp:3195 ParseJsonString(jval_result, "moomoo_client_sig", mm_sig);
映射到 account.us_client_sig_. 用于 moomoo / US 路径独立于
client_sig 的 broker channel 鉴权 — 当账号 attribution = US/SG/AU/JP/CA
时, broker_auth_code 换 client_sig 走的是 moomoo_client_sig 而不是
主 client_sig.
缺失 (futunn HK 账号 / 老 backend) → 空 Vec (handler 检查 is_empty()
决定 fallback 主 client_sig).
§⚠️ v1.4.96 BUG #010 doctrine fix (external reviewer double-tester 2026-04-26):
真机 verify 发现 backend 对 futunn 账号也下发 moomoo_client_sig
(mm_sig_len=128). 字段名 moomoo_* 不意味着账号是 moomoo 系.
不要基于 moomoo_client_sig.is_empty() 判账号 broker path. 真正
的 broker path 判断用 broker_id (1001/1007=Futu HK/US, 6xxx=moomoo).
moomoo_client_key: Vec<u8>v1.4.94 G6 (P2 protocol gap): moomoo_client_key 解密后的 client key
(对应 moomoo path), 与 client_key 平级. 缺失 → 空 Vec.
对齐 C++ auth_impl.cpp:3196,3260 account.us_client_key_ (经
UpdateRandKey 解密).
moomoo_web_sig: Stringv1.4.94 G6 (P2 protocol gap): moomoo_web_sig_new from /authority/
响应. 对齐 C++ auth_impl.cpp:3197,3260 account.us_web_sig_. 用于
moomoo path repull_auth_code (类似 web_sig 之于主 path). 缺失 →
空字符串.
Trait Implementations§
Source§impl Clone for AuthResult
impl Clone for AuthResult
Source§fn clone(&self) -> AuthResult
fn clone(&self) -> AuthResult
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for AuthResult
impl RefUnwindSafe for AuthResult
impl Send for AuthResult
impl Sync for AuthResult
impl Unpin for AuthResult
impl UnsafeUnpin for AuthResult
impl UnwindSafe for AuthResult
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more