firebase_rs_sdk/auth/
types.rs

1use reqwest::Url;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use std::sync::Arc;
5
6use crate::app::FirebaseApp;
7use crate::auth::api::Auth;
8use crate::auth::error::{AuthError, AuthResult};
9use crate::auth::model::{User, UserCredential};
10use crate::util::PartialObserver;
11
12#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
13pub struct IdTokenResult {
14    pub token: String,
15    pub auth_time: Option<String>,
16    pub issued_at_time: Option<String>,
17    pub expiration_time: Option<String>,
18    pub sign_in_provider: Option<String>,
19    pub sign_in_second_factor: Option<String>,
20    pub claims: Value,
21}
22
23#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
24pub struct UserMetadata {
25    pub creation_time: Option<String>,
26    pub last_sign_in_time: Option<String>,
27}
28
29#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
30pub struct ActionCodeSettings {
31    pub url: String,
32    pub handle_code_in_app: bool,
33    pub i_os: Option<IosSettings>,
34    pub android: Option<AndroidSettings>,
35    pub dynamic_link_domain: Option<String>,
36    pub link_domain: Option<String>,
37}
38
39#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
40pub struct IosSettings {
41    pub bundle_id: String,
42}
43
44#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
45pub struct AndroidSettings {
46    pub package_name: String,
47    pub install_app: Option<bool>,
48    pub minimum_version: Option<String>,
49}
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
52pub enum ActionCodeOperation {
53    PasswordReset,
54    RecoverEmail,
55    EmailSignIn,
56    RevertSecondFactorAddition,
57    VerifyAndChangeEmail,
58    #[default]
59    VerifyEmail,
60}
61
62#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
63pub struct ActionCodeInfoData {
64    pub email: Option<String>,
65    pub previous_email: Option<String>,
66    pub multi_factor_info: Option<MultiFactorInfo>,
67    pub from_email: Option<String>,
68}
69
70#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
71pub struct ActionCodeInfo {
72    pub data: ActionCodeInfoData,
73    pub operation: ActionCodeOperation,
74}
75
76#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
77pub struct ActionCodeUrl {
78    pub api_key: String,
79    pub code: String,
80    pub continue_url: Option<String>,
81    pub language_code: Option<String>,
82    pub tenant_id: Option<String>,
83    pub operation: ActionCodeOperation,
84}
85
86impl ActionCodeUrl {
87    /// Parses an out-of-band action link into its structured representation.
88    pub fn parse(link: &str) -> Option<Self> {
89        let parsed = Url::parse(link).ok()?;
90        let query: std::collections::HashMap<_, _> = parsed.query_pairs().into_owned().collect();
91        let api_key = query.get("apiKey")?.clone();
92        let code = query.get("oobCode")?.clone();
93        Some(Self {
94            api_key,
95            code,
96            continue_url: query.get("continueUrl").cloned(),
97            language_code: query.get("languageCode").cloned(),
98            tenant_id: query.get("tenantId").cloned(),
99            operation: ActionCodeOperation::EmailSignIn,
100        })
101    }
102}
103
104#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
105pub struct AdditionalUserInfo {
106    pub is_new_user: bool,
107    pub provider_id: Option<String>,
108    pub profile: Option<Value>,
109    pub username: Option<String>,
110}
111
112#[derive(Clone)]
113pub struct ConfirmationResult {
114    verification_id: String,
115    confirm_handler: Arc<dyn Fn(&str) -> AuthResult<UserCredential> + Send + Sync + 'static>,
116}
117
118impl ConfirmationResult {
119    /// Creates a confirmation result that can complete sign-in with the provided handler.
120    pub fn new<F>(verification_id: String, confirm_handler: F) -> Self
121    where
122        F: Fn(&str) -> AuthResult<UserCredential> + Send + Sync + 'static,
123    {
124        Self {
125            verification_id,
126            confirm_handler: Arc::new(confirm_handler),
127        }
128    }
129
130    /// Finalizes authentication by providing the SMS verification code.
131    pub fn confirm(&self, verification_code: &str) -> AuthResult<UserCredential> {
132        (self.confirm_handler)(verification_code)
133    }
134
135    /// Returns the verification ID that should be paired with the SMS code.
136    pub fn verification_id(&self) -> &str {
137        &self.verification_id
138    }
139}
140
141#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
142pub struct AuthSettings {
143    pub app_verification_disabled_for_testing: bool,
144}
145
146pub trait ApplicationVerifier: Send + Sync {
147    fn verify(&self) -> AuthResult<String>;
148    fn verifier_type(&self) -> &str;
149}
150
151#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
152pub struct MultiFactorInfo {
153    pub uid: String,
154    pub display_name: Option<String>,
155    pub enrollment_time: Option<String>,
156    pub factor_id: String,
157}
158
159#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
160pub struct MultiFactorSession;
161
162#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
163pub struct MultiFactorAssertion;
164
165#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
166pub struct MultiFactorResolver;
167
168#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
169pub struct MultiFactorUser;
170
171impl MultiFactorUser {
172    /// Returns the list of enrolled multi-factor authenticators.
173    pub fn enrolled_factors(&self) -> Vec<MultiFactorInfo> {
174        Vec::new()
175    }
176
177    /// Attempts to enroll a new multi-factor assertion (not yet implemented).
178    pub fn enroll(
179        &self,
180        _assertion: MultiFactorAssertion,
181        _display_name: Option<&str>,
182    ) -> AuthResult<()> {
183        Err(AuthError::NotImplemented("multi-factor enrollment"))
184    }
185
186    /// Requests a multi-factor session for subsequent operations.
187    pub fn get_session(&self) -> AuthResult<MultiFactorSession> {
188        Err(AuthError::NotImplemented("multi-factor session"))
189    }
190
191    /// Removes an enrolled multi-factor authenticator.
192    pub fn unenroll(&self, _factor: &MultiFactorInfo) -> AuthResult<()> {
193        Err(AuthError::NotImplemented("multi-factor unenroll"))
194    }
195}
196
197#[derive(Clone)]
198pub struct AuthStateListener {
199    pub observer: PartialObserver<Arc<User>>,
200}
201
202impl AuthStateListener {
203    /// Wraps an observer so it can be registered with the Auth state machine.
204    pub fn new(observer: PartialObserver<Arc<User>>) -> Self {
205        Self { observer }
206    }
207}
208
209pub type Observer<T> = PartialObserver<T>;
210
211#[derive(Clone)]
212pub struct FirebaseAuth {
213    inner: Arc<Auth>,
214}
215
216impl FirebaseAuth {
217    /// Creates a high-level Auth façade around the shared `Auth` core.
218    pub fn new(inner: Arc<Auth>) -> Self {
219        Self { inner }
220    }
221
222    /// Returns the `FirebaseApp` associated with this Auth instance.
223    pub fn app(&self) -> &FirebaseApp {
224        self.inner.app()
225    }
226
227    /// Returns the currently signed-in user, if any.
228    pub fn current_user(&self) -> Option<Arc<User>> {
229        self.inner.current_user()
230    }
231
232    /// Signs the current user out of Firebase Auth.
233    pub fn sign_out(&self) {
234        self.inner.sign_out();
235    }
236
237    /// Signs a user in with an email and password.
238    pub fn sign_in_with_email_and_password(
239        &self,
240        email: &str,
241        password: &str,
242    ) -> AuthResult<UserCredential> {
243        self.inner.sign_in_with_email_and_password(email, password)
244    }
245
246    /// Creates a new user with the provided email and password.
247    pub fn create_user_with_email_and_password(
248        &self,
249        email: &str,
250        password: &str,
251    ) -> AuthResult<UserCredential> {
252        self.inner
253            .create_user_with_email_and_password(email, password)
254    }
255
256    /// Registers an observer that is notified whenever the auth state changes.
257    pub fn on_auth_state_changed(
258        &self,
259        observer: PartialObserver<Arc<User>>,
260    ) -> impl FnOnce() + Send + 'static {
261        self.inner.on_auth_state_changed(observer)
262    }
263}
264#[cfg(test)]
265mod tests {
266    use super::*;
267    use crate::auth::error::AuthError;
268
269    #[test]
270    fn confirmation_result_invokes_handler() {
271        let result = ConfirmationResult::new("verification_id".into(), |code| {
272            assert_eq!(code, "123456");
273            Err(AuthError::NotImplemented("test"))
274        });
275        assert!(result.confirm("123456").is_err());
276    }
277}