firebase_rs_sdk/app_check/
api.rs1use std::sync::Arc;
2use std::time::Duration;
3
4use crate::app::{get_app, AppError, FirebaseApp};
5
6use super::errors::{AppCheckError, AppCheckResult};
7use super::logger::LOGGER;
8use super::providers::{CustomProvider, ReCaptchaEnterpriseProvider, ReCaptchaV3Provider};
9use super::state;
10use super::types::{
11 AppCheck, AppCheckOptions, AppCheckProvider, AppCheckToken, AppCheckTokenListener,
12 AppCheckTokenResult, ListenerHandle, ListenerType,
13};
14
15pub fn initialize_app_check(
16 app: Option<FirebaseApp>,
17 options: AppCheckOptions,
18) -> AppCheckResult<AppCheck> {
19 let app = if let Some(app) = app {
20 app
21 } else {
22 match get_app(None) {
23 Ok(app) => app,
24 Err(AppError::NoApp { app_name }) => {
25 return Err(AppCheckError::InvalidConfiguration {
26 message: format!("Firebase app '{app_name}' is not initialized"),
27 });
28 }
29 Err(err) => {
30 return Err(AppCheckError::Internal(err.to_string()));
31 }
32 }
33 };
34
35 let app_check = AppCheck::new(app.clone());
36
37 let provider = options.provider.clone();
38 let auto_refresh = options
39 .is_token_auto_refresh_enabled
40 .unwrap_or_else(|| app.automatic_data_collection_enabled());
41
42 state::ensure_activation(&app_check, provider.clone(), auto_refresh)?;
43
44 provider.initialize(&app);
45
46 if auto_refresh {
47 LOGGER.debug("App Check auto-refresh enabled");
48 }
49
50 Ok(app_check)
51}
52
53pub fn set_token_auto_refresh_enabled(app_check: &AppCheck, enabled: bool) {
54 state::set_auto_refresh(app_check, enabled);
55 if enabled {
56 LOGGER.debug("App Check auto-refresh toggled on");
57 }
58}
59
60pub fn get_token(app_check: &AppCheck, force_refresh: bool) -> AppCheckResult<AppCheckTokenResult> {
61 if !state::is_activated(app_check) {
62 return Err(AppCheckError::UseBeforeActivation {
63 app_name: app_check.app().name().to_owned(),
64 });
65 }
66
67 if !force_refresh {
68 if let Some(token) = state::current_token(app_check) {
69 if !token.is_expired() {
70 return Ok(AppCheckTokenResult::from_token(token));
71 }
72 }
73 }
74
75 let provider =
76 state::provider(app_check).ok_or_else(|| AppCheckError::UseBeforeActivation {
77 app_name: app_check.app().name().to_owned(),
78 })?;
79
80 let token = provider.get_token()?;
81 state::store_token(app_check, token.clone());
82 Ok(AppCheckTokenResult::from_token(token))
83}
84
85pub fn get_limited_use_token(app_check: &AppCheck) -> AppCheckResult<AppCheckTokenResult> {
86 if !state::is_activated(app_check) {
87 return Err(AppCheckError::UseBeforeActivation {
88 app_name: app_check.app().name().to_owned(),
89 });
90 }
91
92 let provider =
93 state::provider(app_check).ok_or_else(|| AppCheckError::UseBeforeActivation {
94 app_name: app_check.app().name().to_owned(),
95 })?;
96
97 let token = provider.get_limited_use_token()?;
98 Ok(AppCheckTokenResult::from_token(token))
99}
100
101pub fn add_token_listener(
102 app_check: &AppCheck,
103 listener: AppCheckTokenListener,
104 listener_type: ListenerType,
105) -> AppCheckResult<ListenerHandle> {
106 if !state::is_activated(app_check) {
107 return Err(AppCheckError::UseBeforeActivation {
108 app_name: app_check.app().name().to_owned(),
109 });
110 }
111
112 let handle = state::add_listener(app_check, listener.clone(), listener_type);
113
114 if let Some(token) = state::current_token(app_check) {
115 listener(&AppCheckTokenResult::from_token(token));
116 }
117
118 Ok(handle)
119}
120
121pub fn remove_token_listener(handle: ListenerHandle) {
122 handle.unsubscribe();
123}
124
125pub fn custom_provider<F>(callback: F) -> Arc<dyn AppCheckProvider>
127where
128 F: Fn() -> AppCheckResult<AppCheckToken> + Send + Sync + 'static,
129{
130 Arc::new(CustomProvider::new(callback))
131}
132
133pub fn recaptcha_v3_provider(site_key: impl Into<String>) -> Arc<dyn AppCheckProvider> {
134 Arc::new(ReCaptchaV3Provider::new(site_key.into()))
135}
136
137pub fn recaptcha_enterprise_provider(site_key: impl Into<String>) -> Arc<dyn AppCheckProvider> {
138 Arc::new(ReCaptchaEnterpriseProvider::new(site_key.into()))
139}
140
141pub fn token_with_ttl(token: impl Into<String>, ttl: Duration) -> AppCheckResult<AppCheckToken> {
143 AppCheckToken::with_ttl(token, ttl)
144}