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 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 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 pub fn confirm(&self, verification_code: &str) -> AuthResult<UserCredential> {
132 (self.confirm_handler)(verification_code)
133 }
134
135 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 pub fn enrolled_factors(&self) -> Vec<MultiFactorInfo> {
174 Vec::new()
175 }
176
177 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 pub fn get_session(&self) -> AuthResult<MultiFactorSession> {
188 Err(AuthError::NotImplemented("multi-factor session"))
189 }
190
191 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 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 pub fn new(inner: Arc<Auth>) -> Self {
219 Self { inner }
220 }
221
222 pub fn app(&self) -> &FirebaseApp {
224 self.inner.app()
225 }
226
227 pub fn current_user(&self) -> Option<Arc<User>> {
229 self.inner.current_user()
230 }
231
232 pub fn sign_out(&self) {
234 self.inner.sign_out();
235 }
236
237 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 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 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}