use candid::{CandidType, Principal};
use core::fmt::Display;
use ic_auth_types::ByteBufB64;
use serde::{Deserialize, Serialize};
pub use ic_auth_verifier::envelope::SignedEnvelope;
#[derive(Clone, Debug, CandidType, Deserialize, Serialize)]
pub struct TEEInfo {
pub id: Principal,
pub kind: TEEKind,
pub url: String,
pub attestation: Option<ByteBufB64>,
}
#[derive(
Clone, Debug, CandidType, Deserialize, Serialize, Eq, PartialEq, Hash, Ord, PartialOrd,
)]
pub enum TEEKind {
NITRO,
}
impl Display for TEEKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TEEKind::NITRO => write!(f, "NITRO"),
}
}
}
impl TryFrom<&str> for TEEKind {
type Error = String;
fn try_from(s: &str) -> Result<Self, Self::Error> {
match s.to_uppercase().as_str() {
"NITRO" => Ok(TEEKind::NITRO),
_ => Err(format!("Unknown TEE kind: {}", s)),
}
}
}
impl TEEInfo {
pub fn validate(&self) -> Result<(), String> {
if !self.url.starts_with("https://") {
return Err("url should start with https://".to_string());
}
if url::Url::parse(&self.url).is_err() {
return Err(format!("{:?} is not a valid URL", self.url));
}
if self.attestation.is_none() {
return Err("attestation is required".to_string());
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use cbor2::Value;
#[test]
fn test_tee_protocol() {
let val = TEEKind::try_from("NITRO").unwrap();
assert_eq!(val, TEEKind::NITRO);
let val = TEEKind::try_from("nitro").unwrap();
assert_eq!(val, TEEKind::NITRO);
assert_eq!(val.to_string(), "NITRO");
let got = serde_json::to_string(&val).unwrap();
assert_eq!(got, "\"NITRO\"");
let got: TEEKind = serde_json::from_str(&got).unwrap();
assert_eq!(got, val);
let got = Value::serialized(&val).unwrap();
let expected = Value::Text("NITRO".to_string());
assert_eq!(got, expected);
let got: TEEKind = Value::deserialized(&expected).unwrap();
assert_eq!(got, val);
}
}