use hessra_token_core::TokenTimeConfig;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ObjectId(pub String);
impl ObjectId {
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for ObjectId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<&str> for ObjectId {
fn from(s: &str) -> Self {
Self(s.to_string())
}
}
impl From<String> for ObjectId {
fn from(s: String) -> Self {
Self(s)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Operation(pub String);
impl Operation {
pub fn new(op: impl Into<String>) -> Self {
Self(op.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for Operation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<&str> for Operation {
fn from(s: &str) -> Self {
Self(s.to_string())
}
}
impl From<String> for Operation {
fn from(s: String) -> Self {
Self(s)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ExposureLabel(pub String);
impl ExposureLabel {
pub fn new(label: impl Into<String>) -> Self {
Self(label.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for ExposureLabel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<&str> for ExposureLabel {
fn from(s: &str) -> Self {
Self(s.to_string())
}
}
impl From<String> for ExposureLabel {
fn from(s: String) -> Self {
Self(s)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum AnchorBinding {
Subject,
Principal(ObjectId),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CapabilityGrant {
pub target: ObjectId,
pub operations: Vec<Operation>,
pub anchor: Option<AnchorBinding>,
#[serde(default)]
pub designations: Vec<Designation>,
}
pub struct MintResult {
pub token: String,
pub context: Option<crate::ContextToken>,
}
#[derive(Debug, Clone, Default)]
pub struct MintOptions {
pub anchor: Option<ObjectId>,
pub time_config: Option<TokenTimeConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Designation {
pub label: String,
pub value: String,
}
#[derive(Debug, Clone)]
pub struct IdentityConfig {
pub ttl: i64,
pub delegatable: bool,
}
impl Default for IdentityConfig {
fn default() -> Self {
Self {
ttl: 3600,
delegatable: false,
}
}
}
#[derive(Debug, Clone)]
pub struct SessionConfig {
pub ttl: i64,
}
impl Default for SessionConfig {
fn default() -> Self {
Self { ttl: 3600 }
}
}
#[derive(Debug, Clone)]
pub enum PolicyDecision {
Granted {
anchor: Option<ObjectId>,
designations: Vec<Designation>,
},
Denied { reason: String },
DeniedByExposure {
label: ExposureLabel,
blocked_target: ObjectId,
},
}
impl PolicyDecision {
pub fn is_granted(&self) -> bool {
matches!(self, PolicyDecision::Granted { .. })
}
}
pub trait PolicyBackend: Send + Sync {
fn evaluate(
&self,
subject: &ObjectId,
target: &ObjectId,
operation: &Operation,
exposure_labels: &[ExposureLabel],
) -> PolicyDecision;
fn classification(&self, target: &ObjectId) -> Vec<ExposureLabel>;
fn list_grants(&self, subject: &ObjectId) -> Vec<CapabilityGrant>;
fn can_delegate(&self, subject: &ObjectId) -> bool;
fn all_grants(&self) -> Vec<(ObjectId, CapabilityGrant)> {
Vec::new()
}
fn parent(&self, _subject: &ObjectId) -> Option<ObjectId> {
None
}
fn has_grant(&self, subject: &ObjectId, target: &ObjectId, operation: &Operation) -> bool {
self.lookup_grant(subject, target, operation).is_some()
}
fn lookup_grant(
&self,
subject: &ObjectId,
target: &ObjectId,
operation: &Operation,
) -> Option<CapabilityGrant> {
self.list_grants(subject)
.into_iter()
.find(|g| g.target == *target && g.operations.iter().any(|o| o == operation))
}
}