1use crate::Validated;
2use chrono::{DateTime, Local, Utc};
3use luct_core::{CertificateChain, LogId, v1::SignedTreeHead};
4use luct_store::StringStoreValue;
5use serde::{Deserialize, Serialize};
6use web_time::UNIX_EPOCH;
7
8mod evaluate;
9mod generate;
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct Report {
13 pub(crate) ca_issuer: String,
14 pub(crate) ca_subject: String,
15 pub(crate) cert_issuer: String,
16 pub(crate) cert_subject: String,
17 pub(crate) fingerprint: String,
18 pub(crate) ca_fingerprint: String,
19 pub(crate) not_before: DateTime<Utc>,
20 pub(crate) not_after: DateTime<Utc>,
21 #[serde(skip_serializing_if = "Vec::is_empty", default)]
23 pub(crate) scts: Vec<SctReport>,
24 #[serde(skip_serializing_if = "Option::is_none", default)]
25 pub(crate) error_description: Option<String>,
26}
27
28impl Report {
29 pub fn get_error(&self) -> Option<String> {
30 self.error_description.clone()
31 }
32
33 pub(crate) fn error_description(mut self, err: String) -> Self {
34 self.error_description = Some(err);
35 self
36 }
37}
38
39impl From<&CertificateChain> for Report {
40 fn from(chain: &CertificateChain) -> Self {
41 let (not_before, not_after) = chain.cert().get_validity();
42
43 Self {
44 ca_issuer: chain.root().get_issuer_name(),
45 ca_subject: chain.root().get_subject_name(),
46 cert_issuer: chain.cert().get_issuer_name(),
47 cert_subject: chain.cert().get_subject_name(),
48 fingerprint: chain.cert().fingerprint_sha256().to_string(),
49 ca_fingerprint: chain.root().fingerprint_sha256().to_string(),
50 not_before,
51 not_after,
52 scts: vec![],
53 error_description: None,
54 }
55 }
56}
57
58impl StringStoreValue for Report {
59 fn serialize_value(&self) -> String {
60 serde_json::to_string(self).unwrap()
61 }
62
63 fn deserialize_value(value: &str) -> Option<Self> {
64 serde_json::from_str(value).ok()
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
69pub struct SctReport {
70 pub(crate) log_id: String,
71 #[serde(skip_serializing_if = "Option::is_none", default)]
72 pub(crate) signature_validation_time: Option<DateTime<Local>>,
73 #[serde(skip_serializing_if = "Option::is_none", default)]
74 pub(crate) log_name: Option<String>,
75 #[serde(skip_serializing_if = "Option::is_none", default)]
76 pub(crate) latest_sth: Option<SthReport>,
77 #[serde(skip_serializing_if = "Option::is_none", default)]
78 pub(crate) index: Option<u64>,
79 #[serde(skip_serializing_if = "Option::is_none", default)]
80 pub(crate) inclusion_proof: Option<SthReport>,
81 #[serde(skip_serializing_if = "Option::is_none", default)]
82 pub(crate) error_description: Option<String>,
83}
84
85impl SctReport {
86 pub(crate) fn new(log_id: LogId) -> Self {
87 Self {
88 log_id: log_id.to_string(),
89 signature_validation_time: None,
90 log_name: None,
91 latest_sth: None,
92 index: None,
93 inclusion_proof: None,
94 error_description: None,
95 }
96 }
97
98 pub(crate) fn signature_validation_time(mut self, time: DateTime<Local>) -> Self {
99 self.signature_validation_time = Some(time);
100 self
101 }
102
103 pub(crate) fn log_name(mut self, name: String) -> Self {
104 self.log_name = Some(name);
105 self
106 }
107
108 pub(crate) fn latest_sth(mut self, sth: SthReport) -> Self {
109 self.latest_sth = Some(sth);
110 self
111 }
112
113 pub(crate) fn index(mut self, index: u64) -> Self {
114 self.index = Some(index);
115 self
116 }
117
118 pub(crate) fn inclusion_proof(mut self, sth: SthReport) -> Self {
119 self.inclusion_proof = Some(sth);
120 self
121 }
122
123 pub(crate) fn error_description(mut self, err: String) -> Self {
124 self.error_description = Some(err);
125 self
126 }
127
128 pub(crate) fn set_error_description(&mut self, err: String) {
129 self.error_description = Some(err);
130 }
131}
132
133#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
134pub struct SthReport {
135 height: u64,
136 timestamp: DateTime<Utc>,
137 verification_time: DateTime<Utc>,
138}
139
140impl From<&Validated<SignedTreeHead>> for SthReport {
141 fn from(value: &Validated<SignedTreeHead>) -> Self {
142 Self {
143 height: value.tree_size(),
144 timestamp: DateTime::from_timestamp_millis(value.timestamp() as i64).unwrap(),
145 verification_time: DateTime::from_timestamp_millis(
146 value
147 .validated_at()
148 .duration_since(UNIX_EPOCH)
149 .unwrap()
150 .as_millis() as i64,
151 )
152 .unwrap(),
153 }
154 }
155}
156
157