1 use std::fmt;
2 use std::str::FromStr;
3 
4 use serde::Serialize;
5 
6 use crate::{
7     commons::{
8         api::{
9             AllCertAuthIssues, AspaDefinitionList, CaCommandDetails, CaRepoDetails, CertAuthInfo, CertAuthIssues,
10             CertAuthList, ChildCaInfo, ChildrenConnectionStats, CommandHistory, ParentCaContact, ParentStatuses,
11             PublisherDetails, PublisherList, RepoStatus, RoaDefinitions, RtaList, RtaPrepResponse, ServerInfo,
12         },
13         bgp::{BgpAnalysisAdvice, BgpAnalysisReport, BgpAnalysisSuggestion},
14         remote::{api::ClientInfos, rfc8183},
15     },
16     daemon::ca::ResourceTaggedAttestation,
17     pubd::RepoStats,
18 };
19 
20 //------------ ApiResponse ---------------------------------------------------
21 
22 /// This type defines all supported responses for the api
23 #[derive(Clone, Debug, Eq, PartialEq)]
24 #[allow(clippy::large_enum_variant)]
25 pub enum ApiResponse {
26     Health,
27     Info(ServerInfo),
28 
29     CertAuthInfo(CertAuthInfo),
30     CertAuthHistory(CommandHistory),
31     CertAuthAction(CaCommandDetails),
32     CertAuths(CertAuthList),
33 
34     // ROA related
35     RouteAuthorizations(RoaDefinitions),
36     BgpAnalysisAdvice(BgpAnalysisAdvice),
37     BgpAnalysisFull(BgpAnalysisReport),
38     BgpAnalysisSuggestions(BgpAnalysisSuggestion),
39 
40     // ASPA related
41     AspaDefinitions(AspaDefinitionList),
42 
43     ParentCaContact(ParentCaContact),
44     ParentStatuses(ParentStatuses),
45 
46     ChildInfo(ChildCaInfo),
47     ChildrenStats(ChildrenConnectionStats),
48 
49     PublisherDetails(PublisherDetails),
50     PublisherList(PublisherList),
51     RepoStats(RepoStats),
52 
53     Rfc8181ClientList(ClientInfos),
54     Rfc8183RepositoryResponse(rfc8183::RepositoryResponse),
55     Rfc8183ChildRequest(rfc8183::ChildRequest),
56     Rfc8183PublisherRequest(rfc8183::PublisherRequest),
57 
58     RepoDetails(CaRepoDetails),
59     RepoStatus(RepoStatus),
60 
61     CertAuthIssues(CertAuthIssues),
62     AllCertAuthIssues(AllCertAuthIssues),
63 
64     RtaList(RtaList),
65     RtaMultiPrep(RtaPrepResponse),
66     Rta(ResourceTaggedAttestation),
67 
68     Empty,               // Typically a successful post just gets an empty 200 response
69     GenericBody(String), // For when the server echos Json to a successful post
70 }
71 
72 impl ApiResponse {
report(&self, fmt: ReportFormat) -> Result<Option<String>, ReportError>73     pub fn report(&self, fmt: ReportFormat) -> Result<Option<String>, ReportError> {
74         if fmt == ReportFormat::None {
75             Ok(None)
76         } else {
77             match self {
78                 ApiResponse::Health => Ok(None),
79                 ApiResponse::Info(info) => Ok(Some(info.report(fmt)?)),
80                 ApiResponse::CertAuths(list) => Ok(Some(list.report(fmt)?)),
81                 ApiResponse::CertAuthInfo(info) => Ok(Some(info.report(fmt)?)),
82                 ApiResponse::CertAuthHistory(history) => Ok(Some(history.report(fmt)?)),
83                 ApiResponse::CertAuthAction(details) => Ok(Some(details.report(fmt)?)),
84                 ApiResponse::CertAuthIssues(issues) => Ok(Some(issues.report(fmt)?)),
85                 ApiResponse::AllCertAuthIssues(issues) => Ok(Some(issues.report(fmt)?)),
86                 ApiResponse::RouteAuthorizations(definitions) => Ok(Some(definitions.report(fmt)?)),
87                 ApiResponse::BgpAnalysisAdvice(analysis) => Ok(Some(analysis.report(fmt)?)),
88                 ApiResponse::BgpAnalysisFull(table) => Ok(Some(table.report(fmt)?)),
89                 ApiResponse::BgpAnalysisSuggestions(suggestions) => Ok(Some(suggestions.report(fmt)?)),
90                 ApiResponse::AspaDefinitions(definitions) => Ok(Some(definitions.report(fmt)?)),
91                 ApiResponse::ParentCaContact(contact) => Ok(Some(contact.report(fmt)?)),
92                 ApiResponse::ParentStatuses(statuses) => Ok(Some(statuses.report(fmt)?)),
93                 ApiResponse::ChildInfo(info) => Ok(Some(info.report(fmt)?)),
94                 ApiResponse::ChildrenStats(stats) => Ok(Some(stats.report(fmt)?)),
95                 ApiResponse::PublisherList(list) => Ok(Some(list.report(fmt)?)),
96                 ApiResponse::PublisherDetails(details) => Ok(Some(details.report(fmt)?)),
97                 ApiResponse::RepoStats(stats) => Ok(Some(stats.report(fmt)?)),
98                 ApiResponse::Rfc8181ClientList(list) => Ok(Some(list.report(fmt)?)),
99                 ApiResponse::Rfc8183ChildRequest(req) => Ok(Some(req.report(fmt)?)),
100                 ApiResponse::Rfc8183PublisherRequest(req) => Ok(Some(req.report(fmt)?)),
101                 ApiResponse::Rfc8183RepositoryResponse(res) => Ok(Some(res.report(fmt)?)),
102                 ApiResponse::RepoDetails(details) => Ok(Some(details.report(fmt)?)),
103                 ApiResponse::RepoStatus(status) => Ok(Some(status.report(fmt)?)),
104                 ApiResponse::Rta(rta) => Ok(Some(rta.report(fmt)?)),
105                 ApiResponse::RtaList(list) => Ok(Some(list.report(fmt)?)),
106                 ApiResponse::RtaMultiPrep(res) => Ok(Some(res.report(fmt)?)),
107                 ApiResponse::GenericBody(body) => Ok(Some(body.clone())),
108                 ApiResponse::Empty => Ok(None),
109             }
110         }
111     }
112 }
113 
114 //------------ ReportFormat --------------------------------------------------
115 
116 /// This type defines the format to use when representing the api response
117 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
118 pub enum ReportFormat {
119     None,
120     Json,
121     Text,
122 }
123 
124 impl FromStr for ReportFormat {
125     type Err = ReportError;
126 
from_str(s: &str) -> Result<Self, ReportError>127     fn from_str(s: &str) -> Result<Self, ReportError> {
128         match s {
129             "none" => Ok(ReportFormat::None),
130             "json" => Ok(ReportFormat::Json),
131             "text" => Ok(ReportFormat::Text),
132             _ => Err(ReportError::UnrecognizedFormat(s.to_string())),
133         }
134     }
135 }
136 
137 //------------ ReportError ---------------------------------------------------
138 
139 /// This type defines possible Errors for KeyStore
140 #[derive(Debug)]
141 pub enum ReportError {
142     UnsupportedFormat,
143     UnrecognizedFormat(String),
144 }
145 
146 impl fmt::Display for ReportError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result147     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148         match self {
149             ReportError::UnsupportedFormat => write!(f, "This report format is not supported for this data"),
150             ReportError::UnrecognizedFormat(s) => write!(f, "This report format is not recognized: {}", s),
151         }
152     }
153 }
154 
155 //------------ Report --------------------------------------------------------
156 
157 /// This trait should be implemented by all api responses, so that the
158 /// response can be formatted for users.
159 trait Report: Serialize + ToString {
text(&self) -> Result<String, ReportError>160     fn text(&self) -> Result<String, ReportError> {
161         Ok(self.to_string())
162     }
163 
json(&self) -> String164     fn json(&self) -> String {
165         serde_json::to_string_pretty(self).unwrap()
166     }
167 
report(&self, format: ReportFormat) -> Result<String, ReportError>168     fn report(&self, format: ReportFormat) -> Result<String, ReportError> {
169         match format {
170             ReportFormat::None => Ok("".to_string()),
171             ReportFormat::Json => Ok(self.json()),
172             ReportFormat::Text => self.text(),
173         }
174     }
175 }
176 
177 impl Report for CertAuthList {}
178 impl Report for CertAuthInfo {}
179 
180 impl Report for ChildCaInfo {}
181 
182 impl Report for ParentCaContact {}
183 impl Report for ParentStatuses {}
184 
185 impl Report for CommandHistory {}
186 impl Report for CaCommandDetails {}
187 
188 impl Report for PublisherList {}
189 
190 impl Report for RepoStats {}
191 impl Report for ChildrenConnectionStats {}
192 
193 impl Report for PublisherDetails {}
194 
195 impl Report for ClientInfos {}
196 
197 impl Report for rfc8183::RepositoryResponse {}
198 impl Report for rfc8183::ChildRequest {}
199 impl Report for rfc8183::PublisherRequest {}
200 
201 impl Report for RoaDefinitions {}
202 
203 impl Report for BgpAnalysisAdvice {}
204 impl Report for BgpAnalysisReport {}
205 impl Report for BgpAnalysisSuggestion {}
206 
207 impl Report for AspaDefinitionList {}
208 
209 impl Report for CaRepoDetails {}
210 impl Report for RepoStatus {}
211 
212 impl Report for CertAuthIssues {}
213 
214 impl Report for AllCertAuthIssues {}
215 
216 impl Report for ServerInfo {}
217 
218 impl Report for ResourceTaggedAttestation {}
219 impl Report for RtaList {}
220 impl Report for RtaPrepResponse {}
221