mas_data_model/upstream_oauth2/
session.rs1use chrono::{DateTime, Utc};
8use serde::Serialize;
9use ulid::Ulid;
10
11use super::UpstreamOAuthLink;
12use crate::InvalidTransitionError;
13
14#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
15pub enum UpstreamOAuthAuthorizationSessionState {
16 #[default]
17 Pending,
18 Completed {
19 completed_at: DateTime<Utc>,
20 link_id: Ulid,
21 id_token: Option<String>,
22 id_token_claims: Option<serde_json::Value>,
23 extra_callback_parameters: Option<serde_json::Value>,
24 userinfo: Option<serde_json::Value>,
25 },
26 Consumed {
27 completed_at: DateTime<Utc>,
28 consumed_at: DateTime<Utc>,
29 link_id: Ulid,
30 id_token: Option<String>,
31 id_token_claims: Option<serde_json::Value>,
32 extra_callback_parameters: Option<serde_json::Value>,
33 userinfo: Option<serde_json::Value>,
34 },
35 Unlinked {
36 completed_at: DateTime<Utc>,
37 consumed_at: Option<DateTime<Utc>>,
38 unlinked_at: DateTime<Utc>,
39 id_token: Option<String>,
40 id_token_claims: Option<serde_json::Value>,
41 },
42}
43
44impl UpstreamOAuthAuthorizationSessionState {
45 pub fn complete(
54 self,
55 completed_at: DateTime<Utc>,
56 link: &UpstreamOAuthLink,
57 id_token: Option<String>,
58 id_token_claims: Option<serde_json::Value>,
59 extra_callback_parameters: Option<serde_json::Value>,
60 userinfo: Option<serde_json::Value>,
61 ) -> Result<Self, InvalidTransitionError> {
62 match self {
63 Self::Pending => Ok(Self::Completed {
64 completed_at,
65 link_id: link.id,
66 id_token,
67 id_token_claims,
68 extra_callback_parameters,
69 userinfo,
70 }),
71 Self::Completed { .. } | Self::Consumed { .. } | Self::Unlinked { .. } => {
72 Err(InvalidTransitionError)
73 }
74 }
75 }
76
77 pub fn consume(self, consumed_at: DateTime<Utc>) -> Result<Self, InvalidTransitionError> {
86 match self {
87 Self::Completed {
88 completed_at,
89 link_id,
90 id_token,
91 id_token_claims,
92 extra_callback_parameters,
93 userinfo,
94 } => Ok(Self::Consumed {
95 completed_at,
96 link_id,
97 consumed_at,
98 id_token,
99 id_token_claims,
100 extra_callback_parameters,
101 userinfo,
102 }),
103 Self::Pending | Self::Consumed { .. } | Self::Unlinked { .. } => {
104 Err(InvalidTransitionError)
105 }
106 }
107 }
108
109 #[must_use]
116 pub fn link_id(&self) -> Option<Ulid> {
117 match self {
118 Self::Pending | Self::Unlinked { .. } => None,
119 Self::Completed { link_id, .. } | Self::Consumed { link_id, .. } => Some(*link_id),
120 }
121 }
122
123 #[must_use]
131 pub fn completed_at(&self) -> Option<DateTime<Utc>> {
132 match self {
133 Self::Pending => None,
134 Self::Completed { completed_at, .. }
135 | Self::Consumed { completed_at, .. }
136 | Self::Unlinked { completed_at, .. } => Some(*completed_at),
137 }
138 }
139
140 #[must_use]
147 pub fn id_token(&self) -> Option<&str> {
148 match self {
149 Self::Pending => None,
150 Self::Completed { id_token, .. }
151 | Self::Consumed { id_token, .. }
152 | Self::Unlinked { id_token, .. } => id_token.as_deref(),
153 }
154 }
155
156 #[must_use]
164 pub fn id_token_claims(&self) -> Option<&serde_json::Value> {
165 match self {
166 Self::Pending => None,
167 Self::Completed {
168 id_token_claims, ..
169 }
170 | Self::Consumed {
171 id_token_claims, ..
172 }
173 | Self::Unlinked {
174 id_token_claims, ..
175 } => id_token_claims.as_ref(),
176 }
177 }
178
179 #[must_use]
186 pub fn extra_callback_parameters(&self) -> Option<&serde_json::Value> {
187 match self {
188 Self::Pending | Self::Unlinked { .. } => None,
189 Self::Completed {
190 extra_callback_parameters,
191 ..
192 }
193 | Self::Consumed {
194 extra_callback_parameters,
195 ..
196 } => extra_callback_parameters.as_ref(),
197 }
198 }
199
200 #[must_use]
201 pub fn userinfo(&self) -> Option<&serde_json::Value> {
202 match self {
203 Self::Pending | Self::Unlinked { .. } => None,
204 Self::Completed { userinfo, .. } | Self::Consumed { userinfo, .. } => userinfo.as_ref(),
205 }
206 }
207
208 #[must_use]
216 pub fn consumed_at(&self) -> Option<DateTime<Utc>> {
217 match self {
218 Self::Pending | Self::Completed { .. } => None,
219 Self::Consumed { consumed_at, .. } => Some(*consumed_at),
220 Self::Unlinked { consumed_at, .. } => *consumed_at,
221 }
222 }
223
224 #[must_use]
232 pub fn unlinked_at(&self) -> Option<DateTime<Utc>> {
233 match self {
234 Self::Pending | Self::Completed { .. } | Self::Consumed { .. } => None,
235 Self::Unlinked { unlinked_at, .. } => Some(*unlinked_at),
236 }
237 }
238
239 #[must_use]
244 pub fn is_pending(&self) -> bool {
245 matches!(self, Self::Pending)
246 }
247
248 #[must_use]
253 pub fn is_completed(&self) -> bool {
254 matches!(self, Self::Completed { .. })
255 }
256
257 #[must_use]
262 pub fn is_consumed(&self) -> bool {
263 matches!(self, Self::Consumed { .. })
264 }
265
266 #[must_use]
271 pub fn is_unlinked(&self) -> bool {
272 matches!(self, Self::Unlinked { .. })
273 }
274}
275
276#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
277pub struct UpstreamOAuthAuthorizationSession {
278 pub id: Ulid,
279 pub state: UpstreamOAuthAuthorizationSessionState,
280 pub provider_id: Ulid,
281 pub state_str: String,
282 pub code_challenge_verifier: Option<String>,
283 pub nonce: Option<String>,
284 pub created_at: DateTime<Utc>,
285}
286
287impl std::ops::Deref for UpstreamOAuthAuthorizationSession {
288 type Target = UpstreamOAuthAuthorizationSessionState;
289
290 fn deref(&self) -> &Self::Target {
291 &self.state
292 }
293}
294
295impl UpstreamOAuthAuthorizationSession {
296 pub fn complete(
306 mut self,
307 completed_at: DateTime<Utc>,
308 link: &UpstreamOAuthLink,
309 id_token: Option<String>,
310 id_token_claims: Option<serde_json::Value>,
311 extra_callback_parameters: Option<serde_json::Value>,
312 userinfo: Option<serde_json::Value>,
313 ) -> Result<Self, InvalidTransitionError> {
314 self.state = self.state.complete(
315 completed_at,
316 link,
317 id_token,
318 id_token_claims,
319 extra_callback_parameters,
320 userinfo,
321 )?;
322 Ok(self)
323 }
324
325 pub fn consume(mut self, consumed_at: DateTime<Utc>) -> Result<Self, InvalidTransitionError> {
335 self.state = self.state.consume(consumed_at)?;
336 Ok(self)
337 }
338}