firebase_verifyid/
settings.rs

1use crate::{Error, GOOGLE_PUBKEY_URI};
2use jwt_simple::{
3    common::VerificationOptions,
4    prelude::{Duration, Ed25519PublicKey},
5};
6use serde::Deserialize;
7use std::{collections::HashSet, fs};
8
9#[derive(Clone, Debug, Deserialize)]
10pub struct Settings {
11    /// The URL to retrieve rotating jwks from Firebase
12    #[serde(default = "default_jwk_url")]
13    pub url: String,
14    /// Firebase project number
15    pub project_id: String,
16    /// The maximum amount of time in seconds after a token has expired to allow a token to verify
17    pub max_validity_secs: Option<u64>,
18    /// How much clock in seconds to tolerate when verifying token timestamps; default 15 min
19    pub time_tolerance_secs: Option<u64>,
20    /// Accepts tokens in the future
21    pub accept_future: Option<bool>,
22    /// Bypass Firebase Token with self-issued JWT bearer tokens
23    /// The base58-encoded address of, or the path to, the PEM-encoded Ed2559 public signing key
24    pub bearer_pubkey: Option<String>,
25}
26
27fn default_jwk_url() -> String {
28    GOOGLE_PUBKEY_URI.to_string()
29}
30
31impl Settings {
32    pub fn max_validity(&self) -> Option<Duration> {
33        self.max_validity_secs.map(Duration::from_secs)
34    }
35
36    pub fn time_tolerance(&self) -> Option<Duration> {
37        self.time_tolerance_secs.map(Duration::from_secs)
38    }
39
40    pub fn bearer_pubkey(&self) -> Option<Result<Ed25519PublicKey, Error>> {
41        self.bearer_pubkey.as_ref().map(|addr_or_path| {
42            bs58::decode(&addr_or_path)
43                .into_vec()
44                .map_err(|err| err.into())
45                .and_then(|bytes| Ed25519PublicKey::from_bytes(&bytes))
46                .or_else(|_| {
47                    fs::read_to_string(addr_or_path)
48                        .map_err(|err| err.into())
49                        .and_then(|pem| Ed25519PublicKey::from_pem(&pem).map_err(|err| err.into()))
50                })
51        })
52    }
53}
54
55impl From<Settings> for VerificationOptions {
56    fn from(settings: Settings) -> Self {
57        let default = VerificationOptions::default();
58        VerificationOptions {
59            accept_future: settings.accept_future.unwrap_or(default.accept_future),
60            allowed_issuers: Some(HashSet::from([format!(
61                "https://securetoken.google.com/{}",
62                settings.project_id
63            )])),
64            allowed_audiences: Some(HashSet::from([settings.project_id.clone()])),
65            time_tolerance: settings.time_tolerance().or(default.time_tolerance),
66            max_validity: settings.max_validity().or(default.max_validity),
67            ..default
68        }
69    }
70}