rust_tdlib/client/
auth_handler.rs

1use std::fmt::Debug;
2use std::sync::Arc;
3
4use async_trait::async_trait;
5use dyn_clone::DynClone;
6use tokio::sync::Mutex;
7
8use crate::types::{
9    AuthorizationStateWaitCode, AuthorizationStateWaitEncryptionKey,
10    AuthorizationStateWaitOtherDeviceConfirmation, AuthorizationStateWaitPassword,
11    AuthorizationStateWaitPhoneNumber, AuthorizationStateWaitRegistration,
12};
13
14use crate::utils;
15
16/// `ClientIdentifier` allows to determine if client is bot (with bot token as identifier) or client (with a phone number)
17#[derive(Debug, Clone)]
18pub enum ClientIdentifier {
19    PhoneNumber(String),
20    BotToken(String),
21}
22
23/// `ClientAuthStateHandler` trait provides methods that returns data, required for authentication.
24/// Mandatory to use [AuthStateHandlerProxy](crate::client::AuthStateHandlerProxy) if you want to handle authorization per-client, see See `examples/auth_bot.rs` for details.
25#[async_trait]
26pub trait ClientAuthStateHandler: DynClone + Send + Sync + Debug {
27    /// Interacts with provided link
28    async fn handle_other_device_confirmation(
29        &self,
30        wait_device_confirmation: &AuthorizationStateWaitOtherDeviceConfirmation,
31    ) {
32        println!(
33            "other device confirmation link: {}",
34            wait_device_confirmation.link()
35        );
36    }
37    /// Returns wait code
38    async fn handle_wait_code(&self, wait_code: &AuthorizationStateWaitCode) -> String;
39    /// Returns database encryption key
40    async fn handle_encryption_key(
41        &self,
42        wait_encryption_key: &AuthorizationStateWaitEncryptionKey,
43    ) -> String;
44    /// Returns password
45    async fn handle_wait_password(&self, wait_password: &AuthorizationStateWaitPassword) -> String;
46    /// Returns [ClientIdentifier](crate::client::auth_handler::ClientIdentifier)
47    async fn handle_wait_client_identifier(
48        &self,
49        wait_phone_number: &AuthorizationStateWaitPhoneNumber,
50    ) -> ClientIdentifier;
51    /// Returns first_name and second_name
52    async fn handle_wait_registration(
53        &self,
54        wait_registration: &AuthorizationStateWaitRegistration,
55    ) -> (String, String);
56}
57
58dyn_clone::clone_trait_object!(ClientAuthStateHandler);
59
60/// `AuthStateHandler` trait provides methods that returns data, required for authentication
61/// It allows you to handle particular "auth states", such as [WaitPassword](crate::types::AuthorizationStateWaitPassword), [WaitPhoneNumber](crate::types::AuthorizationStateWaitPhoneNumber) and so on.
62#[async_trait]
63pub trait AuthStateHandler {
64    /// Interacts with provided link
65    async fn handle_other_device_confirmation(
66        &self,
67        _client: Box<dyn ClientAuthStateHandler>,
68        wait_device_confirmation: &AuthorizationStateWaitOtherDeviceConfirmation,
69    ) {
70        println!(
71            "other device confirmation link: {}",
72            wait_device_confirmation.link()
73        );
74    }
75    /// Returns wait code
76    async fn handle_wait_code(
77        &self,
78        client: Box<dyn ClientAuthStateHandler>,
79        wait_code: &AuthorizationStateWaitCode,
80    ) -> String;
81    /// Returns database encryption key
82    async fn handle_encryption_key(
83        &self,
84        client: Box<dyn ClientAuthStateHandler>,
85        wait_encryption_key: &AuthorizationStateWaitEncryptionKey,
86    ) -> String;
87    /// Returns password
88    async fn handle_wait_password(
89        &self,
90        client: Box<dyn ClientAuthStateHandler>,
91        wait_password: &AuthorizationStateWaitPassword,
92    ) -> String;
93    /// Returns [ClientIdentifier](crate::client::auth_handler::ClientIdentifier)
94    async fn handle_wait_client_identifier(
95        &self,
96        client: Box<dyn ClientAuthStateHandler>,
97        wait_phone_number: &AuthorizationStateWaitPhoneNumber,
98    ) -> ClientIdentifier;
99    /// Returns first_name and second_name
100    async fn handle_wait_registration(
101        &self,
102        client: Box<dyn ClientAuthStateHandler>,
103        wait_registration: &AuthorizationStateWaitRegistration,
104    ) -> (String, String);
105}
106
107/// Provides minimal implementation of `AuthStateHandler`.
108/// All required methods wait (synchronously) for stdin input
109#[derive(Debug, Clone)]
110#[deprecated(
111    since = "0.4.3",
112    note = "use ClientAuthStateHandler trait implementations bound to particular client with AuthStateHandlerProxy bound to worker"
113)]
114pub struct ConsoleAuthStateHandler;
115
116impl Default for ConsoleAuthStateHandler {
117    fn default() -> Self {
118        Self::new()
119    }
120}
121
122impl ConsoleAuthStateHandler {
123    pub fn new() -> Self {
124        Self
125    }
126}
127
128#[async_trait]
129impl AuthStateHandler for ConsoleAuthStateHandler {
130    async fn handle_wait_code(
131        &self,
132        _client: Box<dyn ClientAuthStateHandler>,
133        _wait_code: &AuthorizationStateWaitCode,
134    ) -> String {
135        println!("waiting for auth code");
136        utils::wait_input_sync()
137    }
138
139    async fn handle_encryption_key(
140        &self,
141        _client: Box<dyn ClientAuthStateHandler>,
142        _wait_encryption_key: &AuthorizationStateWaitEncryptionKey,
143    ) -> String {
144        println!("waiting for encryption key");
145        utils::wait_input_sync()
146    }
147
148    async fn handle_wait_password(
149        &self,
150        _client: Box<dyn ClientAuthStateHandler>,
151        _wait_password: &AuthorizationStateWaitPassword,
152    ) -> String {
153        println!("waiting for password");
154        utils::wait_input_sync()
155    }
156
157    async fn handle_wait_client_identifier(
158        &self,
159        _client: Box<dyn ClientAuthStateHandler>,
160        _: &AuthorizationStateWaitPhoneNumber,
161    ) -> ClientIdentifier {
162        loop {
163            println!("choose one of phone number (p) or bot token (b)");
164            let inp = utils::wait_input_sync();
165            match inp.to_lowercase().trim() {
166                "b" => {
167                    println!("enter bot token");
168                    return ClientIdentifier::BotToken(utils::wait_input_sync());
169                }
170                "p" => {
171                    println!("enter phone number");
172                    return ClientIdentifier::PhoneNumber(utils::wait_input_sync());
173                }
174                _ => {
175                    // invalid input, next iteration}
176                    continue;
177                }
178            }
179        }
180    }
181    async fn handle_wait_registration(
182        &self,
183        _client: Box<dyn ClientAuthStateHandler>,
184        _wait_registration: &AuthorizationStateWaitRegistration,
185    ) -> (String, String) {
186        loop {
187            println!("waiting for first_name and second_name separated by comma");
188            let inp: String = utils::wait_input_sync();
189            if let Some((f, l)) = utils::split_string(inp, ',') {
190                return (f, l);
191            }
192        }
193    }
194}
195
196/// All required methods wait for data sent by [Sender](tokio::sync::mpsc::Sender).
197#[derive(Debug, Clone)]
198#[deprecated(
199    since = "0.4.3",
200    note = "use ClientAuthStateHandler trait implementations bound to particular client with AuthStateHandlerProxy bound to worker"
201)]
202pub struct SignalAuthStateHandler {
203    rec: Arc<Mutex<tokio::sync::mpsc::Receiver<String>>>,
204}
205
206impl SignalAuthStateHandler {
207    pub fn new(receiver: tokio::sync::mpsc::Receiver<String>) -> Self {
208        Self {
209            rec: Arc::new(Mutex::new(receiver)),
210        }
211    }
212
213    async fn wait_signal(&self) -> String {
214        let mut guard = self.rec.lock().await;
215        guard.recv().await.expect("no signals received")
216    }
217}
218
219#[async_trait]
220impl AuthStateHandler for SignalAuthStateHandler {
221    async fn handle_wait_code(
222        &self,
223        _client: Box<dyn ClientAuthStateHandler>,
224        _: &AuthorizationStateWaitCode,
225    ) -> String {
226        log::info!("waiting for auth code");
227        self.wait_signal().await
228    }
229
230    async fn handle_encryption_key(
231        &self,
232        _client: Box<dyn ClientAuthStateHandler>,
233        _: &AuthorizationStateWaitEncryptionKey,
234    ) -> String {
235        log::info!("waiting for encryption key");
236        let f = self.wait_signal().await;
237        log::info!("get encryption key");
238        f
239    }
240
241    async fn handle_wait_password(
242        &self,
243        _client: Box<dyn ClientAuthStateHandler>,
244        _: &AuthorizationStateWaitPassword,
245    ) -> String {
246        log::info!("waiting for password");
247        self.wait_signal().await
248    }
249
250    async fn handle_wait_client_identifier(
251        &self,
252        _client: Box<dyn ClientAuthStateHandler>,
253        _: &AuthorizationStateWaitPhoneNumber,
254    ) -> ClientIdentifier {
255        loop {
256            log::info!("choose one of phone number (p) or bot token (b)");
257            let inp = self.wait_signal().await;
258            match inp.to_lowercase().trim() {
259                "b" => {
260                    log::info!("enter bot token");
261                    return ClientIdentifier::BotToken(self.wait_signal().await);
262                }
263                "p" => {
264                    log::info!("enter phone number");
265                    return ClientIdentifier::PhoneNumber(self.wait_signal().await);
266                }
267                _ => {
268                    // invalid input, next iteration}
269                    continue;
270                }
271            }
272        }
273    }
274
275    async fn handle_wait_registration(
276        &self,
277        _client: Box<dyn ClientAuthStateHandler>,
278        _: &AuthorizationStateWaitRegistration,
279    ) -> (String, String) {
280        loop {
281            log::info!("waiting for first name and last name separated by comma");
282            let inp = self.wait_signal().await;
283            if let Some((f, l)) = utils::split_string(inp, ',') {
284                return (f, l);
285            }
286        }
287    }
288}
289
290/// `AuthStateHandlerProxy` implements [AuthStateHandlerProxy](crate::client::AuthStateHandlerProxy) in a way that allows to proxy all auth methods to particular clients.
291#[derive(Debug, Clone)]
292pub struct AuthStateHandlerProxy(Option<String>);
293
294impl AuthStateHandlerProxy {
295    pub fn new() -> Self {
296        Self(None)
297    }
298
299    pub fn new_with_encryption_key(key: String) -> Self {
300        Self(Some(key))
301    }
302}
303
304impl Default for AuthStateHandlerProxy {
305    fn default() -> Self {
306        Self::new()
307    }
308}
309
310#[async_trait]
311impl AuthStateHandler for AuthStateHandlerProxy {
312    async fn handle_other_device_confirmation(
313        &self,
314        client: Box<dyn ClientAuthStateHandler>,
315        wait_device_confirmation: &AuthorizationStateWaitOtherDeviceConfirmation,
316    ) {
317        client
318            .handle_other_device_confirmation(wait_device_confirmation)
319            .await
320    }
321
322    async fn handle_wait_code(
323        &self,
324        client: Box<dyn ClientAuthStateHandler>,
325        wait_code: &AuthorizationStateWaitCode,
326    ) -> String {
327        client.handle_wait_code(wait_code).await
328    }
329
330    async fn handle_encryption_key(
331        &self,
332        client: Box<dyn ClientAuthStateHandler>,
333        wait_encryption_key: &AuthorizationStateWaitEncryptionKey,
334    ) -> String {
335        match &self.0 {
336            None => {
337                log::info!("wait for client's encryption key");
338                client.handle_encryption_key(wait_encryption_key).await
339            }
340            Some(key) => key.clone(),
341        }
342    }
343
344    async fn handle_wait_password(
345        &self,
346        client: Box<dyn ClientAuthStateHandler>,
347        wait_password: &AuthorizationStateWaitPassword,
348    ) -> String {
349        client.handle_wait_password(wait_password).await
350    }
351
352    async fn handle_wait_client_identifier(
353        &self,
354        client: Box<dyn ClientAuthStateHandler>,
355        wait_phone_number: &AuthorizationStateWaitPhoneNumber,
356    ) -> ClientIdentifier {
357        client
358            .handle_wait_client_identifier(wait_phone_number)
359            .await
360    }
361
362    async fn handle_wait_registration(
363        &self,
364        client: Box<dyn ClientAuthStateHandler>,
365        wait_registration: &AuthorizationStateWaitRegistration,
366    ) -> (String, String) {
367        client.handle_wait_registration(wait_registration).await
368    }
369}