#[cfg(feature = "diesel")]
pub(in crate::biome) mod diesel;
mod error;
pub(in crate::biome) mod memory;
use std::time::SystemTime;
use uuid::Uuid;
use crate::error::InvalidStateError;
pub use error::OAuthUserSessionStoreError;
const UUID_NAMESPACE: Uuid = Uuid::from_u128(187643141867173602676740887132833008173);
#[derive(Clone)]
pub struct OAuthUser {
subject: String,
user_id: String,
}
impl OAuthUser {
pub fn new(subject: String) -> Self {
Self {
subject,
user_id: Uuid::new_v5(&UUID_NAMESPACE, Uuid::new_v4().as_bytes()).to_string(),
}
}
pub fn new_with_id(subject: String, user_id: String) -> Self {
Self { subject, user_id }
}
pub fn subject(&self) -> &str {
&self.subject
}
pub fn user_id(&self) -> &str {
&self.user_id
}
}
#[derive(Clone)]
pub struct OAuthUserSession {
splinter_access_token: String,
user: OAuthUser,
oauth_access_token: String,
oauth_refresh_token: Option<String>,
last_authenticated: SystemTime,
}
impl OAuthUserSession {
pub fn splinter_access_token(&self) -> &str {
&self.splinter_access_token
}
pub fn user(&self) -> &OAuthUser {
&self.user
}
pub fn oauth_access_token(&self) -> &str {
&self.oauth_access_token
}
pub fn oauth_refresh_token(&self) -> Option<&str> {
self.oauth_refresh_token.as_deref()
}
pub fn last_authenticated(&self) -> SystemTime {
self.last_authenticated
}
pub fn into_update_builder(self) -> InsertableOAuthUserSessionUpdateBuilder {
InsertableOAuthUserSessionUpdateBuilder {
splinter_access_token: self.splinter_access_token,
subject: self.user.subject,
oauth_access_token: self.oauth_access_token,
oauth_refresh_token: self.oauth_refresh_token,
}
}
}
#[derive(Default)]
pub struct OAuthUserSessionBuilder {
splinter_access_token: Option<String>,
user: Option<OAuthUser>,
oauth_access_token: Option<String>,
oauth_refresh_token: Option<String>,
last_authenticated: Option<SystemTime>,
}
impl OAuthUserSessionBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_splinter_access_token(mut self, splinter_access_token: String) -> Self {
self.splinter_access_token = Some(splinter_access_token);
self
}
pub fn with_user(mut self, user: OAuthUser) -> Self {
self.user = Some(user);
self
}
pub fn with_oauth_access_token(mut self, oauth_access_token: String) -> Self {
self.oauth_access_token = Some(oauth_access_token);
self
}
pub fn with_oauth_refresh_token(mut self, oauth_refresh_token: Option<String>) -> Self {
self.oauth_refresh_token = oauth_refresh_token;
self
}
pub fn with_last_authenticated(mut self, last_authenticated: SystemTime) -> Self {
self.last_authenticated = Some(last_authenticated);
self
}
pub fn build(self) -> Result<OAuthUserSession, InvalidStateError> {
Ok(OAuthUserSession {
splinter_access_token: self.splinter_access_token.ok_or_else(|| {
InvalidStateError::with_message(
"A Splinter access token is required to build an OAuthUserSession".into(),
)
})?,
user: self.user.ok_or_else(|| {
InvalidStateError::with_message(
"A user is required to build an OAuthUserSession".into(),
)
})?,
oauth_access_token: self.oauth_access_token.ok_or_else(|| {
InvalidStateError::with_message(
"An OAuth access token is required to build an OAuthUserSession".into(),
)
})?,
oauth_refresh_token: self.oauth_refresh_token,
last_authenticated: self.last_authenticated.ok_or_else(|| {
InvalidStateError::with_message(
"A 'last authenticated' time is required to build an OAuthUserSession".into(),
)
})?,
})
}
}
pub struct InsertableOAuthUserSession {
splinter_access_token: String,
subject: String,
oauth_access_token: String,
oauth_refresh_token: Option<String>,
}
impl InsertableOAuthUserSession {
pub fn splinter_access_token(&self) -> &str {
&self.splinter_access_token
}
pub fn subject(&self) -> &str {
&self.subject
}
pub fn oauth_access_token(&self) -> &str {
&self.oauth_access_token
}
pub fn oauth_refresh_token(&self) -> Option<&str> {
self.oauth_refresh_token.as_deref()
}
}
#[derive(Default)]
pub struct InsertableOAuthUserSessionBuilder {
splinter_access_token: Option<String>,
subject: Option<String>,
oauth_access_token: Option<String>,
oauth_refresh_token: Option<String>,
}
impl InsertableOAuthUserSessionBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_splinter_access_token(mut self, splinter_access_token: String) -> Self {
self.splinter_access_token = Some(splinter_access_token);
self
}
pub fn with_subject(mut self, subject: String) -> Self {
self.subject = Some(subject);
self
}
pub fn with_oauth_access_token(mut self, oauth_access_token: String) -> Self {
self.oauth_access_token = Some(oauth_access_token);
self
}
pub fn with_oauth_refresh_token(mut self, oauth_refresh_token: Option<String>) -> Self {
self.oauth_refresh_token = oauth_refresh_token;
self
}
pub fn build(self) -> Result<InsertableOAuthUserSession, InvalidStateError> {
Ok(InsertableOAuthUserSession {
splinter_access_token: self.splinter_access_token.ok_or_else(|| {
InvalidStateError::with_message(
"A Splinter access token is required to build an InsertableOAuthUserSession"
.into(),
)
})?,
subject: self.subject.ok_or_else(|| {
InvalidStateError::with_message(
"A subject identifier is required to build an InsertableOAuthUserSession"
.into(),
)
})?,
oauth_access_token: self.oauth_access_token.ok_or_else(|| {
InvalidStateError::with_message(
"An OAuth access token is required to build an InsertableOAuthUserSession"
.into(),
)
})?,
oauth_refresh_token: self.oauth_refresh_token,
})
}
}
pub struct InsertableOAuthUserSessionUpdateBuilder {
splinter_access_token: String,
subject: String,
oauth_access_token: String,
oauth_refresh_token: Option<String>,
}
impl InsertableOAuthUserSessionUpdateBuilder {
pub fn with_oauth_access_token(mut self, oauth_access_token: String) -> Self {
self.oauth_access_token = oauth_access_token;
self
}
pub fn with_oauth_refresh_token(mut self, oauth_refresh_token: Option<String>) -> Self {
self.oauth_refresh_token = oauth_refresh_token;
self
}
pub fn build(self) -> InsertableOAuthUserSession {
InsertableOAuthUserSession {
splinter_access_token: self.splinter_access_token,
subject: self.subject,
oauth_access_token: self.oauth_access_token,
oauth_refresh_token: self.oauth_refresh_token,
}
}
}
pub trait OAuthUserSessionStore: Send + Sync {
fn add_session(
&self,
session: InsertableOAuthUserSession,
) -> Result<(), OAuthUserSessionStoreError>;
fn update_session(
&self,
session: InsertableOAuthUserSession,
) -> Result<(), OAuthUserSessionStoreError>;
fn remove_session(&self, splinter_access_token: &str)
-> Result<(), OAuthUserSessionStoreError>;
fn get_session(
&self,
splinter_access_token: &str,
) -> Result<Option<OAuthUserSession>, OAuthUserSessionStoreError>;
fn get_user(&self, subject: &str) -> Result<Option<OAuthUser>, OAuthUserSessionStoreError>;
fn list_users(&self) -> Result<OAuthUserIter, OAuthUserSessionStoreError>;
fn clone_box(&self) -> Box<dyn OAuthUserSessionStore>;
}
impl Clone for Box<dyn OAuthUserSessionStore> {
fn clone(&self) -> Self {
self.clone_box()
}
}
pub struct OAuthUserIter {
inner: Box<dyn ExactSizeIterator<Item = OAuthUser>>,
}
impl OAuthUserIter {
pub fn new(users: Vec<OAuthUser>) -> Self {
Self {
inner: Box::new(users.into_iter()),
}
}
}
impl Iterator for OAuthUserIter {
type Item = OAuthUser;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.inner.len(), Some(self.inner.len()))
}
}
impl ExactSizeIterator for OAuthUserIter {
fn len(&self) -> usize {
self.inner.len()
}
}