1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! # Firebase Auth API - User information
//!
//! Retrieve firebase user information

use super::errors::{extract_google_api_error, Result};

use super::sessions::user;
use serde::{Deserialize, Serialize};

use crate::FirebaseAuthBearer;
use reqwest::Client;

pub trait DocumentPath<'a> {
    fn path(&self) -> &'a str;
}

/// A federated services like Facebook, Github etc that the user has used to
/// authenticated himself and that he associated with this firebase auth account.
#[allow(non_snake_case)]
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct ProviderUserInfo {
    pub providerId: String,
    pub federatedId: String,
    pub displayName: Option<String>,
    pub photoUrl: Option<String>,
}

/// Users id, email, display name and a few more information
#[allow(non_snake_case)]
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct FirebaseAuthUser {
    pub localId: Option<String>,
    pub email: Option<String>,
    /// True if the user has verified his email address
    pub emailVerified: Option<bool>,
    pub displayName: Option<String>,
    /// Find all federated services like Facebook, Github etc that the user has used to
    /// authenticated himself and that he associated with this firebase auth account.
    pub providerUserInfo: Option<Vec<ProviderUserInfo>>,
    pub photoUrl: Option<String>,
    /// True if the account is disabled. A disabled account cannot login anymore.
    pub disabled: Option<bool>,
    /// Last login datetime in UTC
    pub lastLoginAt: Option<String>,
    /// Created datetime in UTC
    pub createdAt: Option<String>,
    /// True if email/password login have been used
    pub customAuth: Option<bool>,
}

/// Your user information query might return zero, one or more [`FirebaseAuthUser`] structures.
#[allow(non_snake_case)]
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct FirebaseAuthUserResponse {
    pub kind: String,
    pub users: Vec<FirebaseAuthUser>,
}

#[allow(non_snake_case)]
#[derive(Debug, Default, Deserialize, Serialize)]
struct UserRequest {
    pub idToken: String,
}

impl UserRequest {
    fn new(id_token: String) -> UserRequest {
        UserRequest { idToken: id_token }
    }
}

#[inline]
fn firebase_auth_url(v: &str, v2: &str) -> String {
    format!(
        "https://www.googleapis.com/identitytoolkit/v3/relyingparty/{}?key={}",
        v, v2
    )
}

#[inline]
fn user_info_internal(
    auth: String,
    api_key: &str,
    firebase_user_id: &str,
) -> Result<FirebaseAuthUserResponse> {
    let url = firebase_auth_url("getAccountInfo", api_key);

    let mut resp = Client::new()
        .post(&url)
        .json(&UserRequest::new(auth))
        .send()?;

    extract_google_api_error(&mut resp, || firebase_user_id.to_owned())?;

    Ok(resp.json()?)
}

/// Retrieve information about the firebase auth user associated with the given user session
///
/// Error codes:
/// - INVALID_ID_TOKEN
/// - USER_NOT_FOUND
pub fn user_info(session: &user::Session) -> Result<FirebaseAuthUserResponse> {
    user_info_internal(session.bearer(), &session.api_key, &session.userid)
}

#[inline]
fn user_remove_internal(auth: String, api_key: &str, firebase_user_id: &str) -> Result<()> {
    let url = firebase_auth_url("deleteAccount", api_key);
    let mut resp = Client::new()
        .post(&url)
        .json(&UserRequest::new(auth))
        .send()?;

    extract_google_api_error(&mut resp, || firebase_user_id.to_owned())?;
    Ok({})
}

/// Removes the firebase auth user associated with the given user session
///
/// Error codes:
/// - INVALID_ID_TOKEN
/// - USER_NOT_FOUND
pub fn user_remove(session: &user::Session) -> Result<()> {
    user_remove_internal(session.bearer(), &session.api_key, &session.userid)
}