Skip to main content

junobuild_auth/state/
heap.rs

1use crate::openid::types::provider::{OpenIdCertificate, OpenIdProvider};
2use crate::state::types::automation::AutomationConfig;
3use crate::state::types::config::AuthenticationConfig;
4use crate::state::types::state::Salt;
5use crate::state::types::state::{AuthenticationHeapState, OpenIdCachedCertificate, OpenIdState};
6use crate::strategies::AuthHeapStrategy;
7use std::collections::hash_map::Entry;
8
9// ---------------------------------------------------------
10// Config
11// ---------------------------------------------------------
12
13pub fn get_config(auth_heap: &impl AuthHeapStrategy) -> Option<AuthenticationConfig> {
14    auth_heap
15        .with_auth_state(|authentication| authentication.as_ref().map(|auth| auth.config.clone()))
16}
17
18pub fn insert_config(auth_heap: &impl AuthHeapStrategy, config: &AuthenticationConfig) {
19    auth_heap.with_auth_state_mut(|authentication| insert_config_impl(config, authentication))
20}
21
22fn insert_config_impl(config: &AuthenticationConfig, state: &mut Option<AuthenticationHeapState>) {
23    match state {
24        None => {
25            *state = Some(AuthenticationHeapState {
26                config: config.clone(),
27                automation: None,
28                salt: None,
29                openid: None,
30            })
31        }
32        Some(state) => state.config = config.clone(),
33    }
34}
35
36// ---------------------------------------------------------
37// Automation
38// ---------------------------------------------------------
39
40pub fn get_automation(auth_heap: &impl AuthHeapStrategy) -> Option<AutomationConfig> {
41    auth_heap.with_auth_state(|authentication| {
42        authentication
43            .as_ref()
44            .and_then(|auth| auth.automation.clone())
45    })
46}
47
48pub fn insert_automation(auth_heap: &impl AuthHeapStrategy, automation: &AutomationConfig) {
49    auth_heap
50        .with_auth_state_mut(|authentication| insert_automation_impl(automation, authentication))
51}
52
53fn insert_automation_impl(
54    automation: &AutomationConfig,
55    state: &mut Option<AuthenticationHeapState>,
56) {
57    match state {
58        None => {
59            *state = Some(AuthenticationHeapState {
60                config: AuthenticationConfig::default(),
61                automation: Some(automation.clone()),
62                salt: None,
63                openid: None,
64            })
65        }
66        Some(state) => state.automation = Some(automation.clone()),
67    }
68}
69
70// ---------------------------------------------------------
71// Salt
72// ---------------------------------------------------------
73
74pub fn get_salt(auth_heap: &impl AuthHeapStrategy) -> Option<Salt> {
75    auth_heap.with_auth_state(|authentication| authentication.as_ref().and_then(|auth| auth.salt))
76}
77
78pub fn insert_salt(auth_heap: &impl AuthHeapStrategy, salt: &Salt) {
79    auth_heap.with_auth_state_mut(|authentication| insert_salt_impl(salt, authentication))
80}
81
82fn insert_salt_impl(salt: &Salt, state: &mut Option<AuthenticationHeapState>) {
83    match state {
84        None => {
85            *state = Some(AuthenticationHeapState {
86                config: AuthenticationConfig::default(),
87                automation: None,
88                salt: Some(*salt),
89                openid: None,
90            })
91        }
92        Some(state) => state.salt = Some(*salt),
93    }
94}
95
96// ---------------------------------------------------------
97// Openid
98// ---------------------------------------------------------
99
100pub fn get_openid_state(auth_heap: &impl AuthHeapStrategy) -> Option<OpenIdState> {
101    auth_heap.with_auth_state(|authentication| {
102        authentication.as_ref().and_then(|auth| auth.openid.clone())
103    })
104}
105
106pub fn get_cached_certificate(
107    provider: &OpenIdProvider,
108    auth_heap: &impl AuthHeapStrategy,
109) -> Option<OpenIdCachedCertificate> {
110    auth_heap
111        .with_auth_state(|authentication| get_cached_certificate_impl(provider, authentication))
112}
113
114pub fn cache_certificate(
115    provider: &OpenIdProvider,
116    certificate: &OpenIdCertificate,
117    auth_heap: &impl AuthHeapStrategy,
118) -> Result<(), String> {
119    auth_heap.with_auth_state_mut(|authentication| {
120        cache_certificate_impl(provider, certificate, authentication)
121    })
122}
123
124pub fn record_fetch_attempt(
125    provider: &OpenIdProvider,
126    reset_streak: bool,
127    auth_heap: &impl AuthHeapStrategy,
128) {
129    auth_heap.with_auth_state_mut(|authentication| {
130        record_fetch_attempt_impl(provider, reset_streak, authentication)
131    })
132}
133
134fn get_cached_certificate_impl(
135    provider: &OpenIdProvider,
136    state: &Option<AuthenticationHeapState>,
137) -> Option<OpenIdCachedCertificate> {
138    state
139        .as_ref()
140        .and_then(|auth| auth.openid.as_ref())
141        .and_then(|openid| openid.certificates.get(provider))
142        .cloned()
143}
144
145fn record_fetch_attempt_impl(
146    provider: &OpenIdProvider,
147    reset_streak: bool,
148    state: &mut Option<AuthenticationHeapState>,
149) {
150    let authentication = state.get_or_insert_with(AuthenticationHeapState::default);
151    let openid_state = authentication
152        .openid
153        .get_or_insert_with(OpenIdState::default);
154
155    openid_state
156        .certificates
157        .entry(provider.clone())
158        .and_modify(|cached_certificate| cached_certificate.record_attempt(reset_streak))
159        .or_insert_with(OpenIdCachedCertificate::init);
160}
161
162fn cache_certificate_impl(
163    provider: &OpenIdProvider,
164    certificate: &OpenIdCertificate,
165    state: &mut Option<AuthenticationHeapState>,
166) -> Result<(), String> {
167    let authentication = state.get_or_insert_with(AuthenticationHeapState::default);
168    let openid_state = authentication
169        .openid
170        .get_or_insert_with(OpenIdState::default);
171
172    match openid_state.certificates.entry(provider.clone()) {
173        Entry::Occupied(mut occ) => {
174            occ.get_mut().update_certificate(certificate);
175            Ok(())
176        }
177        Entry::Vacant(_) => Err("Cannot cache certificate: fetch attempt was not recorded".into()),
178    }
179}