use alloc::{string::String, vec::Vec};
use borsh::{BorshDeserialize, BorshSerialize};
use core::str::FromStr;
use derive_more::{Deref, From, Into};
use hex::FromHexError;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use thiserror::Error;
pub use dcap_qvl::QuoteCollateralV3;
#[derive(
Clone, From, Deref, Into, Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
)]
#[serde(try_from = "Value")]
pub struct Collateral(QuoteCollateralV3);
impl Collateral {
pub fn try_from_json(v: Value) -> Result<Self, CollateralError> {
fn get_str(v: &Value, key: &str) -> Result<String, CollateralError> {
v.get(key)
.and_then(Value::as_str)
.map(String::from)
.ok_or_else(|| CollateralError::MissingField(String::from(key)))
}
fn get_hex(v: &Value, key: &str) -> Result<Vec<u8>, CollateralError> {
let hex_str = get_str(v, key)?;
hex::decode(hex_str).map_err(|source| CollateralError::HexDecode {
field: String::from(key),
source,
})
}
let quote_collateral = QuoteCollateralV3 {
tcb_info_issuer_chain: get_str(&v, "tcb_info_issuer_chain")?,
tcb_info: get_str(&v, "tcb_info")?,
tcb_info_signature: get_hex(&v, "tcb_info_signature")?,
qe_identity_issuer_chain: get_str(&v, "qe_identity_issuer_chain")?,
qe_identity: get_str(&v, "qe_identity")?,
qe_identity_signature: get_hex(&v, "qe_identity_signature")?,
pck_certificate_chain: get_str(&v, "pck_certificate_chain").ok(),
pck_crl_issuer_chain: get_str(&v, "pck_crl_issuer_chain")?,
root_ca_crl: get_hex(&v, "root_ca_crl")?,
pck_crl: get_hex(&v, "pck_crl")?,
};
Ok(Self(quote_collateral))
}
}
impl FromStr for Collateral {
type Err = CollateralError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let json_value: Value =
serde_json::from_str(s).map_err(|_| CollateralError::InvalidJson)?;
Self::try_from_json(json_value)
}
}
impl TryFrom<Value> for Collateral {
type Error = CollateralError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
Self::try_from_json(value)
}
}
#[derive(Debug, Error)]
pub enum CollateralError {
#[error("Missing or invalid field: {0}")]
MissingField(String),
#[error("Failed to decode hex field '{field}': {source}")]
HexDecode {
field: String,
#[source]
source: FromHexError,
},
#[error("Invalid JSON format")]
InvalidJson,
}