#![allow(dead_code)] // TODO: Remove when implemented #![allow(unused_variables)] mod graph; use crate::{Authorization, Secd, SecdError}; use async_trait::async_trait; use uuid::Uuid; pub type Namespace = String; pub type Object = (Namespace, Uuid); pub type Relation = String; pub struct Relationship { pub subject: Subject, pub object: Object, pub relation: Relation, } #[derive(Clone)] pub enum Subject { User(Object), UserSet { user: Object, relation: Relation }, } #[async_trait] impl Authorization for Secd { async fn check(&self, r: &Relationship) -> Result { let spice = self .spice .clone() .expect("TODO: only supports postgres right now"); Ok(spice.check_permission(r).await?) } async fn check_list_namespaces( &self, ns: &Namespace, subj: &Subject, relation: &Relation, ) -> Result, SecdError> { let spice = self .spice .clone() .expect("TODO: only supports postgres right now"); Ok(spice .lookup_resources(ns, relation, subj) .await? .iter() .map(|e| Uuid::parse_str(e).unwrap()) .collect()) } async fn write(&self, ts: &[Relationship]) -> Result<(), SecdError> { let spice = self .spice .clone() .expect("TODO: only supports postgres right now"); // Since spice doesn't really have a great schema pattern, we // prefix all incoming write relationships with an r_ to indicate // they are "relationships" rather than what spice calls permissions spice .write_relationship( &ts.iter() .map(|r| Relationship { subject: r.subject.clone(), object: r.object.clone(), relation: format!("r_{}", r.relation), }) .collect::>(), ) .await?; Ok(()) } } enum RelationToken { Start, Or, And, Exclude, } struct RelationContainer { name: Relation, bins: Vec<(RelationToken, Relation)>, } struct NamespaceContainer { relations: Vec, } impl Secd { async fn write_namespace(&self, ns: &NamespaceContainer) -> Result<(), SecdError> { todo!() } async fn read_namespace(&self) -> Result { todo!() } }