use serde::{Deserialize, Serialize};
use crate::{Oso, Value};
type Result<T> = core::result::Result<T, crate::Error>;
#[derive(Clone, Debug)]
pub struct LocalFilteringHandle<S> {
oso: Oso,
data_bindings: S,
}
impl Oso {
pub fn into_local_filtering_handle<S>(self, data_bindings: S) -> LocalFilteringHandle<S> {
LocalFilteringHandle {
oso: self,
data_bindings,
}
}
}
impl<S> LocalFilteringHandle<S> {
pub fn oso(&self) -> &Oso {
&self.oso
}
}
#[derive(Deserialize)]
struct LocalQueryResult {
sql: String,
}
impl<S: AsRef<str>> LocalFilteringHandle<S> {
pub async fn authorize_local(
&self,
actor: impl Into<Value<'_>>,
action: &str,
resource: impl Into<Value<'_>>,
) -> Result<String> {
#[derive(Debug, Serialize)]
struct AuthorizeRequest<'a> {
actor_type: &'a str,
actor_id: &'a str,
action: &'a str,
resource_type: &'a str,
resource_id: &'a str,
}
#[derive(Debug, Serialize)]
struct LocalAuthQuery<'a> {
query: AuthorizeRequest<'a>,
data_bindings: &'a str,
}
let actor = actor.into();
let resource = resource.into();
let (Some(actor_type), Some(actor_id)) = (actor.type_.as_ref(), actor.id.as_ref()) else {
return Err(crate::Error::Input(
"Actor must be a concrete value. Try `oso.query` if you want to get all permitted actors".to_owned(),
));
};
let (Some(resource_type), Some(resource_id)) = (resource.type_.as_ref(), resource.id.as_ref()) else {
return Err(crate::Error::Input(
"Resource must be a concrete value. Try `oso.list` if you want to get all allowed resources".to_owned(),
));
};
let query = AuthorizeRequest {
actor_type,
actor_id,
action,
resource_type,
resource_id,
};
let body = LocalAuthQuery {
query,
data_bindings: self.data_bindings.as_ref(),
};
let resp: LocalQueryResult = self.oso.client.post("authorize_query", &body, false).await?;
Ok(resp.sql)
}
pub async fn list_local(
&self,
actor: impl Into<Value<'_>>,
action: &str,
resource_type: &str,
column: &str,
) -> Result<String> {
#[derive(Debug, Serialize)]
struct ListRequest<'a> {
actor_type: &'a str,
actor_id: &'a str,
action: &'a str,
resource_type: &'a str,
}
#[derive(Debug, Serialize)]
struct LocalListQuery<'a> {
query: ListRequest<'a>,
column: &'a str,
data_bindings: &'a str,
}
let actor = actor.into();
let (Some(actor_type), Some(actor_id)) = (actor.type_.as_ref(), actor.id.as_ref()) else {
return Err(crate::Error::Input(
"Actor must be a concrete value. Try `oso.query` if you want to get all permitted actors".to_owned(),
));
};
let query = ListRequest {
actor_type,
actor_id,
action,
resource_type,
};
let body = LocalListQuery {
query,
column,
data_bindings: self.data_bindings.as_ref(),
};
let resp: LocalQueryResult = self.oso.client.post("list_query", &body, false).await?;
Ok(resp.sql)
}
}