redfish_axum/
secure_boot_database.rs1pub struct DefaultPrivileges;
5impl redfish_core::privilege::OperationPrivilegeMapping for DefaultPrivileges {
6 type Get = redfish_core::privilege::Login;
7 type Head = redfish_core::privilege::Login;
8 type Post = redfish_core::privilege::ConfigureComponents;
9 type Put = redfish_core::privilege::ConfigureComponents;
10 type Patch = redfish_core::privilege::ConfigureComponents;
11 type Delete = redfish_core::privilege::ConfigureComponents;
12}
13
14pub struct SecureBootDatabase<S, P>
19where
20 S: Clone,
21{
22 router: axum::routing::MethodRouter<S>,
23 privilege_marker: std::marker::PhantomData<fn() -> P>,
24 allowed_methods: Vec<axum::http::method::Method>,
25 certificates: Option<axum::Router<S>>,
26 signatures: Option<axum::Router<S>>,
27 reset_keys: Option<axum::routing::MethodRouter<S>>,
28}
29
30impl<S> Default for SecureBootDatabase<S, DefaultPrivileges>
31where
32 S: Clone,
33{
34 fn default() -> Self {
35 Self {
36 router: Default::default(),
37 privilege_marker: Default::default(),
38 allowed_methods: Vec::new(),
39 certificates: Default::default(),
40 signatures: Default::default(),
41 reset_keys: Default::default(),
42 }
43 }
44}
45
46impl<S, P> SecureBootDatabase<S, P>
47where
48 S: AsRef<dyn redfish_core::auth::AuthenticateRequest> + Clone + Send + Sync + 'static,
49 P: redfish_core::privilege::OperationPrivilegeMapping + 'static,
50 <P as redfish_core::privilege::OperationPrivilegeMapping>::Get: Send,
51 <P as redfish_core::privilege::OperationPrivilegeMapping>::Post: Send,
52{
53 pub fn get<H, T>(mut self, handler: H) -> Self
54 where
55 H: axum::handler::Handler<T, S, axum::body::Body>,
56 T: 'static,
57 {
58 let operation = axum::routing::get(
59 |auth: redfish_core::extract::RedfishAuth<P::Get>,
60 axum::extract::State(state): axum::extract::State<S>,
61 mut request: axum::http::Request<axum::body::Body>| async {
62 request.extensions_mut().insert(auth.user);
63 handler.call(request, state).await
64 },
65 );
66 self.router = self.router.get(operation);
67 self.allowed_methods.push(axum::http::method::Method::GET);
68 self
69 }
70
71 pub fn certificates(mut self, certificates: axum::Router<S>) -> Self {
73 self.certificates = Some(certificates);
74 self
75 }
76
77 pub fn signatures(mut self, signatures: axum::Router<S>) -> Self {
79 self.signatures = Some(signatures);
80 self
81 }
82
83 pub fn reset_keys<H, T>(mut self, handler: H) -> Self
85 where
86 H: axum::handler::Handler<T, S, axum::body::Body>,
87 T: 'static,
88 {
89 self.reset_keys = Some(axum::routing::post(
90 |auth: redfish_core::extract::RedfishAuth<P::Post>,
91 axum::extract::State(state): axum::extract::State<S>,
92 mut request: axum::http::Request<axum::body::Body>| async {
93 request.extensions_mut().insert(auth.user);
94 handler.call(request, state).await
95 },
96 ));
97 self
98 }
99
100 pub fn into_router(self) -> axum::Router<S> {
101 let Self {
102 router,
103 mut allowed_methods,
104 certificates,
105 signatures,
106 reset_keys,
107 ..
108 } = self;
109 let result = axum::Router::default();
110 let result = match certificates {
111 Some(router) => result.nest("/Certificates", router),
112 None => result,
113 };
114 let result = match signatures {
115 Some(router) => result.nest("/Signatures", router),
116 None => result,
117 };
118 let result = match reset_keys {
119 Some(router) => result.route("/Actions/SecureBootDatabase.ResetKeys", router),
120 None => result,
121 };
122 allowed_methods.dedup();
123 let allow_header = allowed_methods
124 .into_iter()
125 .map(|method| method.to_string())
126 .reduce(|one, two| one + "," + &two)
127 .unwrap();
128 result.route(
129 "/",
130 router.fallback(|| async {
131 (
132 axum::http::StatusCode::METHOD_NOT_ALLOWED,
133 axum::Json(redfish_core::error::one_message(redfish_codegen::registries::base::v1_16_0::Base::OperationNotAllowed.into())),
134 )
135 })
136 .route_layer(axum::middleware::from_fn_with_state(
137 allow_header,
138 |axum::extract::State(allow_header): axum::extract::State<String>,
139 request: axum::http::Request<axum::body::Body>,
140 next: axum::middleware::Next<axum::body::Body>| async move {
141 let apply_allow = matches!(*request.method(), axum::http::Method::GET | axum::http::Method::HEAD);
142 let mut response = next.run(request).await;
143 if apply_allow && !response.headers().contains_key(axum::http::header::ALLOW) {
144 response.headers_mut().insert(
145 axum::http::header::ALLOW,
146 axum::http::HeaderValue::from_str(&allow_header).unwrap(),
147 );
148 }
149 response
150 },
151 )),
152 )
153 }
154}