use minicbor::{CborLen, Decode, Encode};
use ockam::Message;
use ockam_abac::{
Action, Expr, PolicyExpression, ResourceName, ResourcePolicy, ResourceType, ResourceTypePolicy,
};
use ockam_core::errcode::{Kind, Origin};
use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded, Error};
use serde::Serialize;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
#[derive(Clone, Debug, Encode, Decode, CborLen, Message)]
#[rustfmt::skip]
#[cbor(map)]
pub struct SetPolicyRequest {
#[n(1)] pub resource: ResourceTypeOrName,
#[n(2)] pub expression: PolicyExpression,
}
impl Encodable for SetPolicyRequest {
fn encode(self) -> ockam_core::Result<Encoded> {
cbor_encode_preallocate(self)
}
}
impl Decodable for SetPolicyRequest {
fn decode(e: &[u8]) -> ockam_core::Result<Self> {
Ok(minicbor::decode(e)?)
}
}
impl SetPolicyRequest {
pub fn new(resource: ResourceTypeOrName, expression: PolicyExpression) -> Self {
Self {
resource,
expression,
}
}
}
#[derive(Debug, Encode, Decode, CborLen, PartialEq, Eq, Message)]
#[rustfmt::skip]
#[cbor(map)]
pub struct PoliciesList {
#[n(1)] resource_policies: Vec<ResourcePolicy>,
#[n(2)] resource_type_policies: Vec<ResourceTypePolicy>,
}
impl Encodable for PoliciesList {
fn encode(self) -> ockam_core::Result<Encoded> {
cbor_encode_preallocate(self)
}
}
impl Decodable for PoliciesList {
fn decode(e: &[u8]) -> ockam_core::Result<Self> {
Ok(minicbor::decode(e)?)
}
}
impl PoliciesList {
pub fn new(
resource_policies: Vec<ResourcePolicy>,
resource_type_policies: Vec<ResourceTypePolicy>,
) -> Self {
Self {
resource_policies,
resource_type_policies,
}
}
pub fn resource_policies(&self) -> &[ResourcePolicy] {
&self.resource_policies
}
pub fn resource_type_policies(&self) -> &[ResourceTypePolicy] {
&self.resource_type_policies
}
pub fn all(&self) -> Vec<Policy> {
self.resource_policies
.iter()
.map(|p| p.clone().into())
.chain(self.resource_type_policies.iter().map(|p| p.clone().into()))
.collect()
}
}
#[derive(Debug, Encode, Decode, CborLen, Serialize, PartialEq, Eq, Message)]
#[rustfmt::skip]
#[cbor(map)]
pub struct Policy {
#[n(1)] resource: ResourceTypeOrName,
#[n(2)] action: Action,
#[n(3)] expression: Expr,
}
impl Encodable for Policy {
fn encode(self) -> ockam_core::Result<Encoded> {
cbor_encode_preallocate(self)
}
}
impl Decodable for Policy {
fn decode(e: &[u8]) -> ockam_core::Result<Self> {
Ok(minicbor::decode(e)?)
}
}
impl Policy {
pub fn resource(&self) -> &ResourceTypeOrName {
&self.resource
}
pub fn action(&self) -> &Action {
&self.action
}
pub fn expression(&self) -> &Expr {
&self.expression
}
}
impl From<ResourceTypePolicy> for Policy {
fn from(policy: ResourceTypePolicy) -> Self {
Policy {
resource: ResourceTypeOrName::Type(policy.resource_type),
action: policy.action,
expression: policy.expression,
}
}
}
impl From<ResourcePolicy> for Policy {
fn from(policy: ResourcePolicy) -> Self {
Policy {
resource: ResourceTypeOrName::Name(policy.resource_name),
action: policy.action,
expression: policy.expression,
}
}
}
#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize, PartialEq, Eq, Message)]
#[serde(untagged)]
#[rustfmt::skip]
pub enum ResourceTypeOrName {
#[n(1)] Type(#[n(1)] ResourceType),
#[n(2)] Name(#[n(1)] ResourceName),
}
impl Encodable for ResourceTypeOrName {
fn encode(self) -> ockam_core::Result<Encoded> {
cbor_encode_preallocate(self)
}
}
impl Decodable for ResourceTypeOrName {
fn decode(e: &[u8]) -> ockam_core::Result<Self> {
Ok(minicbor::decode(e)?)
}
}
#[derive(Clone, Debug, Encode, Decode, CborLen, PartialEq, Eq, Message)]
#[cbor(transparent)]
pub struct ResourceTypeOrNameOption(#[n(0)] pub Option<ResourceTypeOrName>);
impl Encodable for ResourceTypeOrNameOption {
fn encode(self) -> ockam_core::Result<Encoded> {
cbor_encode_preallocate(self)
}
}
impl Decodable for ResourceTypeOrNameOption {
fn decode(e: &[u8]) -> ockam_core::Result<Self> {
Ok(minicbor::decode(e)?)
}
}
impl ResourceTypeOrName {
pub fn new(
resource_type: Option<&ResourceType>,
resource_name: Option<&ResourceName>,
) -> ockam_core::Result<Self> {
Ok(match (resource_type, resource_name) {
(Some(resource_type), _) => Self::Type(resource_type.clone()),
(_, Some(resource_name)) => Self::Name(resource_name.clone()),
_ => {
return Err(Error::new(
Origin::Application,
Kind::Misuse,
"Resource or resource type must be provided",
))
}
})
}
}
impl Display for ResourceTypeOrName {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let as_str = match self {
Self::Type(g) => g.to_string(),
Self::Name(s) => s.to_string(),
};
write!(f, "{}", as_str)
}
}
impl FromStr for ResourceTypeOrName {
type Err = Error;
fn from_str(s: &str) -> ockam_core::Result<Self> {
if let Ok(resource_type) = ResourceType::from_str(s) {
Ok(Self::Type(resource_type))
} else {
Ok(Self::Name(s.into()))
}
}
}