use hessra_token_core::{KeyPair, PublicKey, TokenTimeConfig};
use crate::error::EngineError;
use crate::types::{ExposureLabel, ObjectId, SessionConfig};
#[derive(Debug, Clone)]
pub struct ContextToken {
token: String,
exposure_labels: Vec<ExposureLabel>,
}
impl ContextToken {
pub(crate) fn new(token: String, exposure_labels: Vec<ExposureLabel>) -> Self {
Self {
token,
exposure_labels,
}
}
pub fn token(&self) -> &str {
&self.token
}
pub fn exposure_labels(&self) -> &[ExposureLabel] {
&self.exposure_labels
}
pub fn has_exposure(&self, label: &ExposureLabel) -> bool {
self.exposure_labels.contains(label)
}
pub fn is_exposed(&self) -> bool {
!self.exposure_labels.is_empty()
}
}
pub struct HessraContext {
subject: ObjectId,
session_config: SessionConfig,
}
impl HessraContext {
pub fn new(subject: ObjectId, session_config: SessionConfig) -> Self {
Self {
subject,
session_config,
}
}
pub fn issue(self, keypair: &KeyPair) -> Result<ContextToken, EngineError> {
let time_config = TokenTimeConfig {
start_time: None,
duration: self.session_config.ttl,
};
let token = hessra_context_token::HessraContext::new(
self.subject.as_str().to_string(),
time_config,
)
.issue(keypair)
.map_err(|e| EngineError::Context(format!("failed to mint context token: {e}")))?;
Ok(ContextToken::new(token, vec![]))
}
}
pub fn add_exposure_block(
context: &ContextToken,
labels: &[ExposureLabel],
source: &ObjectId,
keypair: &KeyPair,
) -> Result<ContextToken, EngineError> {
if labels.is_empty() {
return Ok(context.clone());
}
let label_strings: Vec<String> = labels.iter().map(|l| l.as_str().to_string()).collect();
let new_token = hessra_context_token::add_exposure(
context.token(),
keypair,
&label_strings,
source.as_str().to_string(),
)
.map_err(|e| EngineError::Context(format!("failed to add exposure: {e}")))?;
let mut all_labels = context.exposure_labels().to_vec();
for label in labels {
if !all_labels.contains(label) {
all_labels.push(label.clone());
}
}
Ok(ContextToken::new(new_token, all_labels))
}
pub fn extract_exposure_labels(
token: &str,
public_key: PublicKey,
) -> Result<Vec<ExposureLabel>, EngineError> {
let labels = hessra_context_token::extract_exposure_labels(token, public_key)
.map_err(|e| EngineError::Context(format!("failed to extract exposure labels: {e}")))?;
Ok(labels.into_iter().map(ExposureLabel::new).collect())
}
pub fn fork_context(
parent: &ContextToken,
child_subject: &ObjectId,
session_config: SessionConfig,
keypair: &KeyPair,
) -> Result<ContextToken, EngineError> {
let time_config = TokenTimeConfig {
start_time: None,
duration: session_config.ttl,
};
let child_token = hessra_context_token::fork_context(
parent.token(),
keypair.public(),
child_subject.as_str().to_string(),
time_config,
keypair,
)
.map_err(|e| EngineError::Context(format!("failed to fork context: {e}")))?;
let exposure_labels =
hessra_context_token::extract_exposure_labels(&child_token, keypair.public())
.map_err(|e| EngineError::Context(format!("failed to extract child exposure: {e}")))?
.into_iter()
.map(ExposureLabel::new)
.collect();
Ok(ContextToken::new(child_token, exposure_labels))
}