hessra_cap_engine/
context.rs1use hessra_token_core::{KeyPair, PublicKey, TokenTimeConfig};
7
8use crate::error::EngineError;
9use crate::types::{ExposureLabel, ObjectId, SessionConfig};
10
11#[derive(Debug, Clone)]
17pub struct ContextToken {
18 token: String,
20 exposure_labels: Vec<ExposureLabel>,
22}
23
24impl ContextToken {
25 pub(crate) fn new(token: String, exposure_labels: Vec<ExposureLabel>) -> Self {
27 Self {
28 token,
29 exposure_labels,
30 }
31 }
32
33 pub fn token(&self) -> &str {
35 &self.token
36 }
37
38 pub fn exposure_labels(&self) -> &[ExposureLabel] {
40 &self.exposure_labels
41 }
42
43 pub fn has_exposure(&self, label: &ExposureLabel) -> bool {
45 self.exposure_labels.contains(label)
46 }
47
48 pub fn is_exposed(&self) -> bool {
50 !self.exposure_labels.is_empty()
51 }
52}
53
54pub struct HessraContext {
58 subject: ObjectId,
59 session_config: SessionConfig,
60}
61
62impl HessraContext {
63 pub fn new(subject: ObjectId, session_config: SessionConfig) -> Self {
65 Self {
66 subject,
67 session_config,
68 }
69 }
70
71 pub fn issue(self, keypair: &KeyPair) -> Result<ContextToken, EngineError> {
73 let time_config = TokenTimeConfig {
74 start_time: None,
75 duration: self.session_config.ttl,
76 };
77
78 let token = hessra_context_token::HessraContext::new(
79 self.subject.as_str().to_string(),
80 time_config,
81 )
82 .issue(keypair)
83 .map_err(|e| EngineError::Context(format!("failed to mint context token: {e}")))?;
84
85 Ok(ContextToken::new(token, vec![]))
86 }
87}
88
89pub fn add_exposure_block(
91 context: &ContextToken,
92 labels: &[ExposureLabel],
93 source: &ObjectId,
94 keypair: &KeyPair,
95) -> Result<ContextToken, EngineError> {
96 if labels.is_empty() {
97 return Ok(context.clone());
98 }
99
100 let label_strings: Vec<String> = labels.iter().map(|l| l.as_str().to_string()).collect();
101
102 let new_token = hessra_context_token::add_exposure(
103 context.token(),
104 keypair.public(),
105 &label_strings,
106 source.as_str().to_string(),
107 )
108 .map_err(|e| EngineError::Context(format!("failed to add exposure: {e}")))?;
109
110 let mut all_labels = context.exposure_labels().to_vec();
112 for label in labels {
113 if !all_labels.contains(label) {
114 all_labels.push(label.clone());
115 }
116 }
117
118 Ok(ContextToken::new(new_token, all_labels))
119}
120
121pub fn extract_exposure_labels(
123 token: &str,
124 public_key: PublicKey,
125) -> Result<Vec<ExposureLabel>, EngineError> {
126 let labels = hessra_context_token::extract_exposure_labels(token, public_key)
127 .map_err(|e| EngineError::Context(format!("failed to extract exposure labels: {e}")))?;
128
129 Ok(labels.into_iter().map(ExposureLabel::new).collect())
130}
131
132pub fn fork_context(
134 parent: &ContextToken,
135 child_subject: &ObjectId,
136 session_config: SessionConfig,
137 keypair: &KeyPair,
138) -> Result<ContextToken, EngineError> {
139 let time_config = TokenTimeConfig {
140 start_time: None,
141 duration: session_config.ttl,
142 };
143
144 let child_token = hessra_context_token::fork_context(
145 parent.token(),
146 keypair.public(),
147 child_subject.as_str().to_string(),
148 time_config,
149 keypair,
150 )
151 .map_err(|e| EngineError::Context(format!("failed to fork context: {e}")))?;
152
153 let exposure_labels =
155 hessra_context_token::extract_exposure_labels(&child_token, keypair.public())
156 .map_err(|e| EngineError::Context(format!("failed to extract child exposure: {e}")))?
157 .into_iter()
158 .map(ExposureLabel::new)
159 .collect();
160
161 Ok(ContextToken::new(child_token, exposure_labels))
162}