firebase_rs_sdk/installations/rest/
mod.rs1use std::time::{Duration, SystemTime};
2
3use serde::{Deserialize, Serialize};
4
5use crate::installations::error::{invalid_argument, InstallationsResult};
6use crate::installations::types::InstallationToken;
7
8pub const INSTALLATIONS_API_URL: &str = "https://firebaseinstallations.googleapis.com/v1";
9const INTERNAL_AUTH_VERSION: &str = "FIS_v2";
10const SDK_VERSION: &str = concat!("w:", env!("CARGO_PKG_VERSION"));
11
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct RegisteredInstallation {
14 pub fid: String,
15 pub refresh_token: String,
16 pub auth_token: InstallationToken,
17}
18
19#[derive(Serialize)]
20#[serde(rename_all = "camelCase")]
21struct CreateInstallationRequest<'a> {
22 fid: &'a str,
23 auth_version: &'static str,
24 app_id: &'a str,
25 sdk_version: &'static str,
26}
27
28#[derive(Deserialize)]
29#[serde(rename_all = "camelCase")]
30struct CreateInstallationResponse {
31 refresh_token: String,
32 auth_token: GenerateAuthTokenResponse,
33 fid: Option<String>,
34}
35
36#[derive(Serialize)]
37struct GenerateAuthTokenRequest<'a> {
38 installation: GenerateAuthTokenInstallation<'a>,
39}
40
41#[derive(Serialize)]
42#[serde(rename_all = "camelCase")]
43struct GenerateAuthTokenInstallation<'a> {
44 app_id: &'a str,
45 sdk_version: &'static str,
46}
47
48#[derive(Deserialize)]
49#[serde(rename_all = "camelCase")]
50struct GenerateAuthTokenResponse {
51 token: String,
52 expires_in: String,
53}
54
55#[derive(Deserialize)]
56struct ErrorResponse {
57 error: ErrorBody,
58}
59
60#[derive(Deserialize)]
61struct ErrorBody {
62 code: i64,
63 message: String,
64 status: String,
65}
66
67fn convert_auth_token(
68 response: GenerateAuthTokenResponse,
69) -> InstallationsResult<InstallationToken> {
70 let expires_at = SystemTime::now() + parse_expires_in(&response.expires_in)?;
71 Ok(InstallationToken {
72 token: response.token,
73 expires_at,
74 })
75}
76
77fn parse_expires_in(raw: &str) -> InstallationsResult<Duration> {
78 let stripped = raw
79 .strip_suffix('s')
80 .ok_or_else(|| invalid_argument(format!("Invalid expiresIn format: {}", raw)))?;
81 let seconds: u64 = stripped
82 .parse()
83 .map_err(|err| invalid_argument(format!("Invalid expiresIn value '{}': {}", raw, err)))?;
84 Ok(Duration::from_secs(seconds))
85}
86
87#[cfg(not(target_arch = "wasm32"))]
88pub mod native;
89#[cfg(not(target_arch = "wasm32"))]
90pub use native::RestClient;
91
92#[cfg(all(target_arch = "wasm32", feature = "wasm-web"))]
93pub mod wasm;
94#[cfg(all(target_arch = "wasm32", feature = "wasm-web"))]
95pub use wasm::RestClient;
96
97#[cfg(all(target_arch = "wasm32", not(feature = "wasm-web")))]
98compile_error!(
99 "Building firebase-rs-sdk for wasm32 requires enabling the `wasm-web` feature to include the installations REST client."
100);
101
102#[cfg(test)]
103mod tests;