firebase_user/
account.rs

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}