1use serde::{Deserialize, Serialize};
2
3use crate::{
4 error::{ApiError, check_response},
5 url::FirebaseUrl,
6};
7
8pub async fn get(
9 firebase_url: &FirebaseUrl,
10 id_token: &str,
11) -> Result<Option<GetAccountResponse>, ApiError> {
12 let client = reqwest::Client::new();
13
14 let response = client
15 .post(&firebase_url.account_lookup_url)
16 .header("Content-Type", "application/json")
17 .json(&GetAccountPayload { id_token })
18 .send()
19 .await?;
20
21 let mut body: GetAccountResponseOuter = check_response(response).await?;
22
23 Ok(body.users.pop())
24}
25
26#[derive(Debug, Serialize)]
27#[serde(rename_all = "camelCase")]
28struct GetAccountPayload<'a> {
29 id_token: &'a str,
30}
31
32#[derive(Debug, Deserialize)]
33struct GetAccountResponseOuter {
34 users: Vec<GetAccountResponse>,
35}
36
37#[derive(Debug, Serialize, Deserialize)]
38#[serde(rename_all = "camelCase")]
39pub struct GetAccountResponse {
40 pub local_id: String,
41 pub email: String,
42 pub password_hash: String,
43 pub email_verified: bool,
44 pub password_updated_at: u64,
45 pub provider_user_info: Vec<ProviderUserInfo>,
46 pub valid_since: String,
47 pub last_login_at: String,
48 pub created_at: String,
49 pub last_refresh_at: String,
50}
51
52#[derive(Clone, Debug, Serialize, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub struct ProviderUserInfo {
55 pub provider_id: String,
56 pub federated_id: String,
57 pub email: String,
58 pub raw_id: String,
59}
60
61pub async fn update(
62 firebase_url: &FirebaseUrl,
63 id_token: &str,
64 email: Option<&str>,
65 password: Option<&str>,
66 return_secure_token: bool,
67) -> Result<UpdateAccountResponse, ApiError> {
68 let client = reqwest::Client::new();
69
70 let response = client
71 .post(&firebase_url.account_update_url)
72 .header("Content-Type", "application/json")
73 .json(&UpdateAccountPayload {
74 id_token,
75 email,
76 password,
77 return_secure_token,
78 })
79 .send()
80 .await?;
81
82 check_response(response).await
83}
84
85pub async fn change_email(
86 firebase_url: &FirebaseUrl,
87 id_token: &str,
88 email: &str,
89 return_secure_token: bool,
90) -> Result<UpdateAccountResponse, ApiError> {
91 update(
92 firebase_url,
93 id_token,
94 Some(email),
95 None,
96 return_secure_token,
97 )
98 .await
99}
100
101pub async fn change_password(
102 firebase_url: &FirebaseUrl,
103 id_token: &str,
104 password: &str,
105 return_secure_token: bool,
106) -> Result<UpdateAccountResponse, ApiError> {
107 update(
108 firebase_url,
109 id_token,
110 None,
111 Some(password),
112 return_secure_token,
113 )
114 .await
115}
116
117#[derive(Debug, Serialize)]
118#[serde(rename_all = "camelCase")]
119struct UpdateAccountPayload<'a> {
120 id_token: &'a str,
121 #[serde(skip_serializing_if = "Option::is_none")]
122 email: Option<&'a str>,
123 #[serde(skip_serializing_if = "Option::is_none")]
124 password: Option<&'a str>,
125 return_secure_token: bool,
126}
127
128#[derive(Debug, Serialize, Deserialize)]
129#[serde(rename_all = "camelCase")]
130pub struct UpdateAccountResponse {
131 pub kind: String,
132 pub local_id: String,
133 pub email: String,
134 pub provider_user_info: Vec<ProviderUserInfo>,
135 pub password_hash: String,
136 pub email_verified: bool,
137 pub id_token: Option<String>,
138 pub refresh_token: Option<String>,
139 pub expires_in: Option<String>,
140}
141
142pub async fn send_oob_code(
143 firebase_url: &FirebaseUrl,
144 request_type: &str,
145 id_token: Option<&str>,
146 email: Option<&str>,
147) -> Result<SendOobCodeResponse, ApiError> {
148 let client = reqwest::Client::new();
149
150 let response = client
151 .post(&firebase_url.account_send_oob_code_url)
152 .header("Content-Type", "application/json")
153 .json(&SendOobCodePayload {
154 request_type,
155 id_token,
156 email,
157 })
158 .send()
159 .await?;
160
161 check_response(response).await
162}
163
164pub async fn reset_password(
165 firebase_url: &FirebaseUrl,
166 email: &str,
167) -> Result<SendOobCodeResponse, ApiError> {
168 send_oob_code(firebase_url, "PASSWORD_RESET", None, Some(email)).await
169}
170
171pub async fn verify_email(
172 firebase_url: &FirebaseUrl,
173 id_token: &str,
174) -> Result<SendOobCodeResponse, ApiError> {
175 send_oob_code(firebase_url, "VERIFY_EMAIL", Some(id_token), None).await
176}
177
178#[derive(Debug, Serialize)]
179#[serde(rename_all = "camelCase")]
180struct SendOobCodePayload<'a> {
181 request_type: &'a str,
182 id_token: Option<&'a str>,
183 email: Option<&'a str>,
184}
185
186#[derive(Debug, Serialize, Deserialize)]
187pub struct SendOobCodeResponse {
188 pub kind: String,
189 pub email: String,
190}