1use serde_json::Value;
2
3use crate::canonical::canonical_json_bytes;
4use crate::crypto::verify_ed25519_signature;
5use crate::error::{Error, Result};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct WarrantMeta {
9 pub version: u64,
10 pub tool: String,
11 pub created: String,
12 pub issuer: String,
13}
14
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct SignatureBlock {
17 pub algorithm: String,
18 pub public_key_b64: String,
19 pub value_b64: String,
20}
21
22#[derive(Debug, Clone, PartialEq)]
23pub struct ParsedWarrant {
24 pub meta: WarrantMeta,
25 pub capabilities: Value,
26 pub unsigned_payload: Value,
28 pub signature: SignatureBlock,
29}
30
31impl ParsedWarrant {
32 pub fn canonical_payload_bytes(&self) -> Result<Vec<u8>> {
33 canonical_json_bytes(&self.unsigned_payload)
34 }
35
36 pub fn verify_signature(&self) -> Result<()> {
37 if !self.signature.algorithm.eq_ignore_ascii_case("ed25519") {
38 return Err(Error::UnsupportedAlgorithm(
39 self.signature.algorithm.clone(),
40 ));
41 }
42 let payload = self.canonical_payload_bytes()?;
43 verify_ed25519_signature(
44 &self.signature.public_key_b64,
45 &payload,
46 &self.signature.value_b64,
47 )
48 }
49
50 pub(crate) fn new(
51 meta: WarrantMeta,
52 capabilities: Value,
53 signature: SignatureBlock,
54 unsigned_payload: Value,
55 ) -> Result<Self> {
56 if !unsigned_payload.is_object() {
57 return Err(Error::InvalidRoot);
58 }
59 Ok(Self {
60 meta,
61 capabilities,
62 unsigned_payload,
63 signature,
64 })
65 }
66}