futu_backend/auth/device/
websig_store.rs1use super::CredentialsStoreError;
2use super::credentials_load::load_credentials_from_path_unlocked;
3use super::credentials_lock::with_credentials_exclusive_path;
4use super::credentials_store::save_credentials_to_path_unlocked;
5use super::storage::try_credentials_path;
6
7#[derive(Debug)]
9pub enum WebSigPersistenceError {
10 MissingCredentials,
11 UserIdMismatch,
12 EmptyTicket,
13 StoreLockPoisoned,
14 Store(String),
15}
16
17impl std::fmt::Display for WebSigPersistenceError {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 match self {
20 Self::MissingCredentials => write!(f, "complete credentials are not available"),
21 Self::UserIdMismatch => write!(f, "credential user identity changed"),
22 Self::EmptyTicket => write!(f, "refreshed WebSig ticket is empty"),
23 Self::StoreLockPoisoned => write!(f, "credential WebSig store lock is poisoned"),
24 Self::Store(message) => write!(f, "credential WebSig persistence failed: {message}"),
25 }
26 }
27}
28
29impl std::error::Error for WebSigPersistenceError {}
30
31impl From<CredentialsStoreError> for WebSigPersistenceError {
32 fn from(value: CredentialsStoreError) -> Self {
33 Self::Store(value.to_string())
34 }
35}
36
37fn with_current_credentials(
38 account: &str,
39 user_id: u64,
40 update: impl FnOnce(&mut super::SavedCredentials),
41) -> Result<(), WebSigPersistenceError> {
42 let path =
43 try_credentials_path(account).map_err(|_| WebSigPersistenceError::MissingCredentials)?;
44 with_credentials_exclusive_path(&path, || {
45 let mut credentials = load_credentials_from_path_unlocked(account, &path)
46 .ok_or(WebSigPersistenceError::MissingCredentials)?;
47 if credentials.uid != user_id {
48 return Err(WebSigPersistenceError::UserIdMismatch);
49 }
50 update(&mut credentials);
51 save_credentials_to_path_unlocked(&path, &credentials)?;
52 Ok(())
53 })
54 .map_err(|error| WebSigPersistenceError::Store(error.to_string()))?
55}
56
57pub fn persist_platform_websigs(
60 account: &str,
61 user_id: u64,
62 web_sig: &str,
63 moomoo_web_sig: &str,
64) -> Result<(), WebSigPersistenceError> {
65 if web_sig.is_empty() || moomoo_web_sig.is_empty() {
66 return Err(WebSigPersistenceError::EmptyTicket);
67 }
68 with_current_credentials(account, user_id, |credentials| {
69 credentials.web_sig = web_sig.to_string();
70 credentials.moomoo_web_sig = moomoo_web_sig.to_string();
71 })
72}
73
74pub fn persist_broker_websig(
77 account: &str,
78 user_id: u64,
79 broker_id: u32,
80 broker_web_sig: &str,
81) -> Result<(), WebSigPersistenceError> {
82 if broker_web_sig.is_empty() {
83 return Err(WebSigPersistenceError::EmptyTicket);
84 }
85 with_current_credentials(account, user_id, |credentials| {
86 credentials
87 .broker_web_sigs
88 .insert(broker_id, broker_web_sig.to_string());
89 })
90}