diff options
author | Vika <vika@fireburn.ru> | 2023-07-29 21:59:56 +0300 |
---|---|---|
committer | Vika <vika@fireburn.ru> | 2023-07-29 21:59:56 +0300 |
commit | 0617663b249f9ca488e5de652108b17d67fbaf45 (patch) | |
tree | 11564b6c8fa37bf9203a0a4cc1c4e9cc088cb1a5 /kittybox-rs/indieauth/src/scopes.rs | |
parent | 26c2b79f6a6380ae3224e9309b9f3352f5717bd7 (diff) | |
download | kittybox-0617663b249f9ca488e5de652108b17d67fbaf45.tar.zst |
Moved the entire Kittybox tree into the root
Diffstat (limited to 'kittybox-rs/indieauth/src/scopes.rs')
-rw-r--r-- | kittybox-rs/indieauth/src/scopes.rs | 208 |
1 files changed, 0 insertions, 208 deletions
diff --git a/kittybox-rs/indieauth/src/scopes.rs b/kittybox-rs/indieauth/src/scopes.rs deleted file mode 100644 index d74878e..0000000 --- a/kittybox-rs/indieauth/src/scopes.rs +++ /dev/null @@ -1,208 +0,0 @@ -use std::str::FromStr; - -use serde::{ - Serialize, Serializer, - Deserialize, - de::{ - Deserializer, Visitor, - Error as DeserializeError - } -}; - -/// Various scopes that can be requested through IndieAuth. -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum Scope { - /// Allows to create posts using Micropub. - Create, - /// Allows to edit posts using Micropub. - Update, - /// Allows to delete posts using Micropub. - Delete, - /// Allows to upload blobs to the media endpoint. - Media, - /// Allows to read feeds via Microsub. - Read, - /// Allows to manage follows via Microsub. - Follow, - /// Allows to mute and unmute users in feeds via Microsub. - Mute, - /// Allows to block and unblock users. - Block, - /// Allows to create and manage feeds via Microsub. - Channels, - /// Allows to request profile information (except email, see Email) - Profile, - /// Allows to receive email in the profile information. - Email, - /// Custom scope not included above. - Custom(String) -} -impl Scope { - /// Create a custom scope from a string slice. - pub fn custom(scope: &str) -> Scope { - Scope::Custom(scope.to_string()) - } -} - -// TODO consider relying on serde_variant for these conversions -impl AsRef<str> for Scope { - fn as_ref(&self) -> &str { - use Scope::*; - match self { - Create => "create", - Update => "update", - Delete => "delete", - Media => "media", - Read => "read", - Follow => "follow", - Mute => "mute", - Block => "block", - Channels => "channels", - Profile => "profile", - Email => "email", - Custom(s) => s.as_ref() - } - } -} -impl From<&str> for Scope { - fn from(scope: &str) -> Self { - match scope { - "create" => Scope::Create, - "update" => Scope::Update, - "delete" => Scope::Delete, - "media" => Scope::Media, - "read" => Scope::Read, - "follow" => Scope::Follow, - "mute" => Scope::Mute, - "block" => Scope::Block, - "channels" => Scope::Channels, - "profile" => Scope::Profile, - "email" => Scope::Email, - other => Scope::custom(other) - } - } -} -impl FromStr for Scope { - type Err = std::convert::Infallible; - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(s.into()) - } -} - -/// A list of scopes that serializes to a space-separated string instead of a list. -/// -/// OAuth2 is weird, don't ask me why it's a thing. -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct Scopes(Vec<Scope>); -impl Scopes { - /// Create a list of scopes from a vector of scopes. - pub fn new(scopes: Vec<Scope>) -> Self { - Self(scopes) - } - /// Ensure a certain scope is listed in the scope list. - pub fn has(&self, scope: &Scope) -> bool { - self.0.iter().any(|s| s == scope) - } - /// Ensure all of the requested scopes are in the list. - pub fn has_all(&self, scopes: &[Scope]) -> bool { - scopes.iter() - .map(|s1| self.iter().any(|s2| s1 == s2)) - .all(|s| s) - } - /// Transform this into an iterator over individual scopes. - pub fn iter(&self) -> std::slice::Iter<'_, Scope> { - self.0.iter() - } -} -impl AsRef<[Scope]> for Scopes { - fn as_ref(&self) -> &[Scope] { - self.0.as_ref() - } -} -impl ToString for Scopes { - fn to_string(&self) -> String { - self.0.iter() - .map(|s| s.as_ref()) - .fold(String::new(), |a, s| if a.is_empty() { - s.to_string() - } else { - a + " " + s - }) - } -} -impl FromStr for Scopes { - type Err = std::convert::Infallible; - - fn from_str(value: &str) -> Result<Self, Self::Err> { - Ok(Self(value.split_ascii_whitespace() - .map(Scope::from) - .collect::<Vec<Scope>>())) - } -} -impl Serialize for Scopes { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer - { - serializer.serialize_str(&self.to_string()) - } -} -struct ScopeVisitor; -impl<'de> Visitor<'de> for ScopeVisitor { - type Value = Scopes; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a string of space-separated OAuth2 scopes") - } - - fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> - where - E: DeserializeError - { - Ok(Scopes::from_str(value).unwrap()) - } -} -impl<'de> Deserialize<'de> for Scopes { - - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de> - { - deserializer.deserialize_str(ScopeVisitor) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_serde_vec_scope() { - let scopes = vec![ - Scope::Create, Scope::Update, Scope::Delete, - Scope::Media, - Scope::custom("kittybox_internal_access") - ]; - - let scope_serialized = serde_json::to_value( - Scopes::new(scopes.clone()) - ).unwrap(); - let scope_str = scope_serialized.as_str().unwrap(); - assert_eq!(scope_str, "create update delete media kittybox_internal_access"); - - assert!(serde_json::from_value::<Scopes>(scope_serialized).unwrap().has_all(&scopes)) - } - - #[test] - fn test_scope_has_all() { - let scopes = Scopes(vec![ - Scope::Create, Scope::Update, Scope::custom("draft") - ]); - - assert!(scopes.has_all(&[Scope::Create, Scope::custom("draft")])); - - assert!(!scopes.has_all(&[Scope::Read, Scope::custom("kittybox_internal_access")])); - } - -} |