use anyhow::{anyhow, Result};
use serde_json::json;
use ucan::capability::{
Ability, CapabilitySemantics, CapabilityView, Resource, ResourceUri, Scope,
};
use url::Url;
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
pub enum SphereAbility {
Fetch,
Push,
Publish,
Authorize,
}
impl Ability for SphereAbility {}
impl ToString for SphereAbility {
fn to_string(&self) -> String {
match self {
SphereAbility::Authorize => "sphere/authorize",
SphereAbility::Publish => "sphere/publish",
SphereAbility::Push => "sphere/push",
SphereAbility::Fetch => "sphere/fetch",
}
.into()
}
}
impl TryFrom<String> for SphereAbility {
type Error = anyhow::Error;
fn try_from(value: String) -> Result<Self> {
Ok(match value.as_str() {
"sphere/authorize" => SphereAbility::Authorize,
"sphere/publish" => SphereAbility::Publish,
"sphere/push" => SphereAbility::Push,
"sphere/fetch" => SphereAbility::Fetch,
_ => return Err(anyhow!("Unrecognized action: {:?}", value)),
})
}
}
#[cfg(doc)]
use crate::data::Did;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SphereReference {
pub did: String,
}
impl Scope for SphereReference {
fn contains(&self, other: &Self) -> bool {
other.did == self.did
}
}
impl ToString for SphereReference {
fn to_string(&self) -> String {
format!("sphere:{}", self.did)
}
}
impl TryFrom<Url> for SphereReference {
type Error = anyhow::Error;
fn try_from(value: Url) -> Result<Self> {
match value.scheme() {
"sphere" => Ok(SphereReference {
did: String::from(value.path()),
}),
_ => Err(anyhow!(
"Could not interpret URI as a sphere reference: {:?}",
value
)),
}
}
}
pub struct SphereSemantics {}
impl CapabilitySemantics<SphereReference, SphereAbility> for SphereSemantics {}
pub const SPHERE_SEMANTICS: SphereSemantics = SphereSemantics {};
pub fn generate_capability(
identity: &str,
ability: SphereAbility,
) -> CapabilityView<SphereReference, SphereAbility> {
CapabilityView {
resource: Resource::Resource {
kind: ResourceUri::Scoped(SphereReference {
did: identity.to_owned(),
}),
},
ability,
caveat: json!({}),
}
}