diff --git a/examples/custom_storage.rs b/examples/custom_storage.rs index f1db2cf..e78ad3c 100644 --- a/examples/custom_storage.rs +++ b/examples/custom_storage.rs @@ -2,7 +2,7 @@ use anyhow::anyhow; use async_trait::async_trait; use std::sync::RwLock; -use yup_oauth2::storage::{ScopeSet, TokenInfo, TokenStorage}; +use yup_oauth2::storage::{TokenInfo, TokenStorage}; struct ExampleTokenStore { store: RwLock>, @@ -13,11 +13,19 @@ struct StoredToken { serialized_token: String, } +/// Is this set of scopes covered by the other? Returns true if the other +/// set is a superset of this one. Use this when implementing TokenStorage.get() +fn scopes_covered_by(scopes: &[&str], possible_match_or_superset: &[&str]) -> bool { + scopes + .iter() + .all(|s| possible_match_or_superset.iter().any(|t| t == s)) +} + /// Here we implement our own token storage. You could write the serialized token and scope data /// to disk, an OS keychain, a database or whatever suits your use-case #[async_trait] impl TokenStorage for ExampleTokenStore { - async fn set(&self, scopes: ScopeSet<'_, &str>, token: TokenInfo) -> anyhow::Result<()> { + async fn set(&self, scopes: &[&str], token: TokenInfo) -> anyhow::Result<()> { let data = serde_json::to_string(&token).unwrap(); println!("Storing token for scopes {:?}", scopes); @@ -28,18 +36,25 @@ impl TokenStorage for ExampleTokenStore { .map_err(|_| anyhow!("Unable to lock store for writing"))?; store.push(StoredToken { - scopes: scopes.scopes(), + scopes: scopes.iter().map(|str| str.to_string()).collect(), serialized_token: data, }); Ok(()) } - async fn get(&self, target_scopes: ScopeSet<'_, &str>) -> Option { + async fn get(&self, target_scopes: &[&str]) -> Option { // Retrieve the token data self.store.read().ok().and_then(|store| { for stored_token in store.iter() { - if target_scopes.is_covered_by(&stored_token.scopes) { + if scopes_covered_by( + target_scopes, + &stored_token + .scopes + .iter() + .map(|s| &s[..]) + .collect::>()[..], + ) { return serde_json::from_str(&stored_token.serialized_token).ok(); } } diff --git a/src/storage.rs b/src/storage.rs index d26c90e..303730e 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -54,7 +54,7 @@ impl ScopeFilter { /// A set of scopes #[derive(Debug)] -pub struct ScopeSet<'a, T> { +pub(crate) struct ScopeSet<'a, T> { hash: ScopeHash, filter: ScopeFilter, scopes: &'a [T], @@ -109,25 +109,6 @@ where scopes, } } - - /// Get the scopes for storage when implementing TokenStorage.set(). - /// Returned scope strings are unique and sorted. - pub fn scopes(&self) -> Vec { - self.scopes - .iter() - .map(|scope| scope.as_ref().to_string()) - .sorted() - .unique() - .collect() - } - - /// Is this set of scopes covered by the other? Returns true if the other - /// set is a superset of this one. Use this when implementing TokenStorage.get() - pub fn is_covered_by(&self, other_scopes: &[String]) -> bool { - self.scopes - .iter() - .all(|s| other_scopes.iter().any(|t| t.as_str() == s.as_ref())) - } } /// Implement your own token storage solution by implementing this trait. You need a way to @@ -137,10 +118,10 @@ pub trait TokenStorage: Send + Sync { /// Store a token for the given set of scopes so that it can be retrieved later by get() /// ScopeSet implements Hash so that you can easily serialize and store it. /// TokenInfo can be serialized with serde. - async fn set(&self, scopes: ScopeSet<'_, &str>, token: TokenInfo) -> anyhow::Result<()>; + async fn set(&self, scopes: &[&str], token: TokenInfo) -> anyhow::Result<()>; /// Retrieve a token stored by set for the given set of scopes - async fn get(&self, scopes: ScopeSet<'_, &str>) -> Option; + async fn get(&self, scopes: &[&str]) -> Option; } pub(crate) enum Storage { @@ -162,15 +143,17 @@ impl Storage { Storage::Memory { tokens } => Ok(tokens.lock().await.set(scopes, token)?), Storage::Disk(disk_storage) => Ok(disk_storage.set(scopes, token).await?), Storage::Custom(custom_storage) => { - let str_scopes: Vec<_> = scopes.scopes.iter().map(|scope| scope.as_ref()).collect(); + let str_scopes: Vec<_> = scopes + .scopes + .iter() + .map(|scope| scope.as_ref()) + .sorted() + .unique() + .collect(); (*custom_storage) .set( - ScopeSet { - hash: scopes.hash, - filter: scopes.filter, - scopes: &str_scopes[..], - }, + &str_scopes[..], // TODO: sorted, unique token, ) .await @@ -186,15 +169,15 @@ impl Storage { Storage::Memory { tokens } => tokens.lock().await.get(scopes), Storage::Disk(disk_storage) => disk_storage.get(scopes).await, Storage::Custom(custom_storage) => { - let str_scopes: Vec<_> = scopes.scopes.iter().map(|scope| scope.as_ref()).collect(); + let str_scopes: Vec<_> = scopes + .scopes + .iter() + .map(|scope| scope.as_ref()) + .sorted() + .unique() + .collect(); - (*custom_storage) - .get(ScopeSet { - hash: scopes.hash, - filter: scopes.filter, - scopes: &str_scopes[..], - }) - .await + (*custom_storage).get(&str_scopes[..]).await } } }