hessra_context_token/
mint.rs1extern crate biscuit_auth as biscuit;
2
3use biscuit::macros::biscuit;
4use chrono::Utc;
5use hessra_token_core::{KeyPair, TokenTimeConfig};
6use std::error::Error;
7
8pub struct HessraContext {
27 subject: String,
28 time_config: TokenTimeConfig,
29}
30
31impl HessraContext {
32 pub fn new(subject: String, time_config: TokenTimeConfig) -> Self {
38 Self {
39 subject,
40 time_config,
41 }
42 }
43
44 pub fn issue(self, keypair: &KeyPair) -> Result<String, Box<dyn Error>> {
56 let start_time = self
57 .time_config
58 .start_time
59 .unwrap_or_else(|| Utc::now().timestamp());
60 let expiration = start_time + self.time_config.duration;
61 let subject = self.subject;
62
63 let builder = biscuit!(
64 r#"
65 context({subject});
66 check if time($time), $time < {expiration};
67 "#
68 );
69
70 let biscuit = builder.build(keypair)?;
71 let token = biscuit.to_base64()?;
72
73 Ok(token)
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use crate::verify::ContextVerifier;
81
82 #[test]
83 fn test_create_context_token() {
84 let keypair = KeyPair::new();
85 let public_key = keypair.public();
86
87 let token = HessraContext::new("agent:openclaw".to_string(), TokenTimeConfig::default())
88 .issue(&keypair)
89 .expect("Failed to create context token");
90
91 assert!(!token.is_empty());
92
93 ContextVerifier::new(token, public_key)
95 .verify()
96 .expect("Should verify fresh context token");
97 }
98
99 #[test]
100 fn test_expired_context_token() {
101 let keypair = KeyPair::new();
102 let public_key = keypair.public();
103
104 let expired_config = TokenTimeConfig {
105 start_time: Some(0),
106 duration: 1,
107 };
108
109 let token = HessraContext::new("agent:test".to_string(), expired_config)
110 .issue(&keypair)
111 .expect("Failed to create expired context token");
112
113 let result = ContextVerifier::new(token, public_key).verify();
114 assert!(
115 result.is_err(),
116 "Expired context token should fail verification"
117 );
118 }
119
120 #[test]
121 fn test_custom_time_config() {
122 let keypair = KeyPair::new();
123 let public_key = keypair.public();
124
125 let config = TokenTimeConfig {
126 start_time: None,
127 duration: 7200, };
129
130 let token = HessraContext::new("agent:test".to_string(), config)
131 .issue(&keypair)
132 .expect("Failed to create context token with custom config");
133
134 ContextVerifier::new(token, public_key)
135 .verify()
136 .expect("Should verify context token with custom duration");
137 }
138}