aap_protocol/
authorization.rs1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7use crate::crypto::{KeyPair, signable, verify_signature};
8use crate::errors::{AAPError, Result};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
12#[serde(rename_all = "lowercase")]
13pub enum Level {
14 Observe = 0,
15 Suggest = 1,
16 Assisted = 2,
17 Supervised = 3,
18 Autonomous = 4,
19}
20
21impl Level {
22 pub fn name(&self) -> &'static str {
23 match self {
24 Level::Observe => "observe",
25 Level::Suggest => "suggest",
26 Level::Assisted => "assisted",
27 Level::Supervised => "supervised",
28 Level::Autonomous => "autonomous",
29 }
30 }
31
32 pub fn as_u8(&self) -> u8 { *self as u8 }
33}
34
35const PHYSICAL_MAX_LEVEL: Level = Level::Supervised;
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct Authorization {
42 pub aap_version: String,
43 pub agent_id: String,
44 pub level: u8,
45 pub level_name: String,
46 pub scope: Vec<String>,
47 pub physical: bool,
48 pub granted_by: String,
49 pub granted_at: DateTime<Utc>,
50 #[serde(skip_serializing_if = "Option::is_none")]
51 pub expires_at: Option<DateTime<Utc>>,
52 pub session_id: String,
53 pub signature: String,
54 #[serde(skip)]
55 revoked: bool,
56}
57
58impl Authorization {
59 pub fn new(
62 agent_id: &str,
63 level: Level,
64 scope: Vec<String>,
65 physical: bool,
66 supervisor_kp: &KeyPair,
67 supervisor_did: &str,
68 ) -> Result<Self> {
69 if physical && level > PHYSICAL_MAX_LEVEL {
71 return Err(AAPError::PhysicalWorldViolation { agent_id: agent_id.into() });
72 }
73
74 let mut auth = Self {
75 aap_version: "0.1".into(),
76 agent_id: agent_id.into(),
77 level: level.as_u8(),
78 level_name: level.name().into(),
79 scope,
80 physical,
81 granted_by: supervisor_did.into(),
82 granted_at: Utc::now(),
83 expires_at: None,
84 session_id: Uuid::new_v4().to_string(),
85 signature: String::new(),
86 revoked: false,
87 };
88
89 let v = serde_json::to_value(&auth)?;
90 let data = signable(&v)?;
91 auth.signature = supervisor_kp.sign(&data);
92 Ok(auth)
93 }
94
95 pub fn revoke(&mut self) { self.revoked = true; }
96 pub fn is_revoked(&self) -> bool { self.revoked }
97 pub fn is_expired(&self) -> bool {
98 self.expires_at.map(|e| Utc::now() > e).unwrap_or(false)
99 }
100 pub fn is_valid(&self) -> bool { !self.is_revoked() && !self.is_expired() }
101
102 pub fn check(&self) -> Result<()> {
103 if self.is_revoked() {
104 return Err(AAPError::Revocation { id: self.session_id.clone() });
105 }
106 if self.is_expired() {
107 return Err(AAPError::Revocation {
108 id: format!("{} (expired)", self.session_id),
109 });
110 }
111 Ok(())
112 }
113
114 pub fn verify(&self, supervisor_public_key_b64: &str) -> Result<()> {
115 let v = serde_json::to_value(self)?;
116 let data = signable(&v)?;
117 verify_signature(supervisor_public_key_b64, &data, &self.signature)
118 }
119}