futu_backend/auth/
credentials_refresh.rs1use crate::conn::BackendProtocolIdentity;
2use futu_core::error::FutuError;
3
4mod remember_session;
5
6use remember_session::{CachedRememberLoginSessionPurpose, load_cached_remember_login_session};
7
8use super::device::save_credentials;
9use super::redact::{account_log_fingerprint, uid_log_fingerprint};
10use super::remember::{RememberLoginInput, remember_login};
11use super::{AuthResult, UserAttribution};
12
13pub const REFRESH_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
19
20#[derive(Debug, Clone)]
26pub struct RefreshCredentialsReport {
27 pub credentials_refreshed: bool,
29 pub uid: u64,
31 pub auth_result: AuthResult,
33}
34
35pub async fn refresh_credentials_on_disk(
46 http: &reqwest::Client,
47 account: &str,
48 device_id: &str,
49 protocol_identity: BackendProtocolIdentity,
50 region_code: Option<&str>,
51 attribution: UserAttribution,
52) -> std::result::Result<RefreshCredentialsReport, FutuError> {
53 let session = load_cached_remember_login_session(
54 account,
55 device_id,
56 protocol_identity,
57 CachedRememberLoginSessionPurpose::AdminReload { region_code },
58 )?;
59
60 let (auth_result, new_cred_opt) = remember_login(
61 http,
62 RememberLoginInput {
63 config: &session.config,
64 region_code: session.region_code.as_deref(),
65 attribution,
66 uid: session.credentials.uid,
67 device_id,
68 device_sig: &session.credentials.device_sig,
69 tgtgt: &session.credentials.tgtgt,
70 rand_key: &session.rand_key,
71 web_sig: &session.credentials.web_sig,
72 moomoo_web_sig: &session.credentials.moomoo_web_sig,
73 verify_cb: None,
74 primary_webtcp: None,
75 },
76 )
77 .await?;
78 let credentials_refreshed = if let Some(new_cred) = new_cred_opt {
79 let uid = new_cred.uid;
80 save_credentials(account, &new_cred).map_err(|e| {
82 FutuError::Codec(format!(
83 "admin reload: save_credentials failed — {e} (cred not on disk; \
84 next startup will re-auth via password)"
85 ))
86 })?;
87 tracing::info!(
89 account_fp = %account_log_fingerprint(account),
90 uid_fp = %uid_log_fingerprint(uid),
91 "admin reload: credentials refreshed on disk"
92 );
93 true
94 } else {
95 tracing::debug!(
97 account_fp = %account_log_fingerprint(account),
98 "admin reload: remember_login ok but no fresh credentials (still valid)"
99 );
100 false
101 };
102 Ok(RefreshCredentialsReport {
103 credentials_refreshed,
104 uid: auth_result.user_id,
105 auth_result,
106 })
107}