1pub 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 EnvironmentMetricsPrivileges;
17impl redfish_core::privilege::OperationPrivilegeMapping for EnvironmentMetricsPrivileges {
18 type Get = redfish_core::privilege::Login;
19 type Head = redfish_core::privilege::Login;
20 type Post = redfish_core::privilege::ConfigureComponents;
21 type Put = redfish_core::privilege::ConfigureComponents;
22 type Patch = redfish_core::privilege::ConfigureComponents;
23 type Delete = redfish_core::privilege::ConfigureComponents;
24}
25
26pub struct Memory<S, P>
32where
33 S: Clone,
34{
35 router: axum::routing::MethodRouter<S>,
36 privilege_marker: std::marker::PhantomData<fn() -> P>,
37 allowed_methods: Vec<axum::http::method::Method>,
38 device_log: Option<axum::Router<S>>,
39 certificates: Option<axum::Router<S>>,
40 environment_metrics: Option<axum::Router<S>>,
41 memory_metrics: Option<axum::Router<S>>,
42 assembly: Option<axum::Router<S>>,
43 disable_master_passphrase: Option<axum::routing::MethodRouter<S>>,
44 disable_passphrase: Option<axum::routing::MethodRouter<S>>,
45 freeze_security_state: Option<axum::routing::MethodRouter<S>>,
46 inject_persistent_poison: Option<axum::routing::MethodRouter<S>>,
47 overwrite_unit: Option<axum::routing::MethodRouter<S>>,
48 reset: Option<axum::routing::MethodRouter<S>>,
49 reset_to_defaults: Option<axum::routing::MethodRouter<S>>,
50 scan_media: Option<axum::routing::MethodRouter<S>>,
51 secure_erase_unit: Option<axum::routing::MethodRouter<S>>,
52 set_master_passphrase: Option<axum::routing::MethodRouter<S>>,
53 set_passphrase: Option<axum::routing::MethodRouter<S>>,
54 unlock_unit: Option<axum::routing::MethodRouter<S>>,
55}
56
57impl<S> Default for Memory<S, DefaultPrivileges>
58where
59 S: Clone,
60{
61 fn default() -> Self {
62 Self {
63 router: Default::default(),
64 privilege_marker: Default::default(),
65 allowed_methods: Vec::new(),
66 device_log: Default::default(),
67 certificates: Default::default(),
68 environment_metrics: Default::default(),
69 memory_metrics: Default::default(),
70 assembly: Default::default(),
71 disable_master_passphrase: Default::default(),
72 disable_passphrase: Default::default(),
73 freeze_security_state: Default::default(),
74 inject_persistent_poison: Default::default(),
75 overwrite_unit: Default::default(),
76 reset: Default::default(),
77 reset_to_defaults: Default::default(),
78 scan_media: Default::default(),
79 secure_erase_unit: Default::default(),
80 set_master_passphrase: Default::default(),
81 set_passphrase: Default::default(),
82 unlock_unit: Default::default(),
83 }
84 }
85}
86
87impl<S, P> Memory<S, P>
88where
89 S: AsRef<dyn redfish_core::auth::AuthenticateRequest> + Clone + Send + Sync + 'static,
90 P: redfish_core::privilege::OperationPrivilegeMapping + 'static,
91 <P as redfish_core::privilege::OperationPrivilegeMapping>::Get: Send,
92 <P as redfish_core::privilege::OperationPrivilegeMapping>::Put: Send,
93 <P as redfish_core::privilege::OperationPrivilegeMapping>::Patch: Send,
94 <P as redfish_core::privilege::OperationPrivilegeMapping>::Post: Send,
95{
96 pub fn get<H, T>(mut self, handler: H) -> Self
97 where
98 H: axum::handler::Handler<T, S, axum::body::Body>,
99 T: 'static,
100 {
101 let operation = axum::routing::get(
102 |auth: redfish_core::extract::RedfishAuth<P::Get>,
103 axum::extract::State(state): axum::extract::State<S>,
104 mut request: axum::http::Request<axum::body::Body>| async {
105 request.extensions_mut().insert(auth.user);
106 handler.call(request, state).await
107 },
108 );
109 self.router = self.router.get(operation);
110 self.allowed_methods.push(axum::http::method::Method::GET);
111 self
112 }
113
114 pub fn put<H, T>(mut self, handler: H) -> Self
115 where
116 H: axum::handler::Handler<T, S, axum::body::Body>,
117 T: 'static,
118 {
119 let operation = axum::routing::put(
120 |auth: redfish_core::extract::RedfishAuth<P::Put>,
121 axum::extract::State(state): axum::extract::State<S>,
122 mut request: axum::http::Request<axum::body::Body>| async {
123 request.extensions_mut().insert(auth.user);
124 handler.call(request, state).await
125 },
126 );
127 self.router = self.router.put(operation);
128 self.allowed_methods.push(axum::http::method::Method::PUT);
129 self
130 }
131
132 pub fn patch<H, T>(mut self, handler: H) -> Self
133 where
134 H: axum::handler::Handler<T, S, axum::body::Body>,
135 T: 'static,
136 {
137 let operation = axum::routing::patch(
138 |auth: redfish_core::extract::RedfishAuth<P::Patch>,
139 axum::extract::State(state): axum::extract::State<S>,
140 mut request: axum::http::Request<axum::body::Body>| async {
141 request.extensions_mut().insert(auth.user);
142 handler.call(request, state).await
143 },
144 );
145 self.router = self.router.patch(operation);
146 self.allowed_methods.push(axum::http::method::Method::PATCH);
147 self
148 }
149
150 pub fn device_log(mut self, device_log: axum::Router<S>) -> Self {
152 self.device_log = Some(device_log);
153 self
154 }
155
156 pub fn certificates(mut self, certificates: axum::Router<S>) -> Self {
158 self.certificates = Some(certificates);
159 self
160 }
161
162 pub fn environment_metrics(mut self, environment_metrics: axum::Router<S>) -> Self {
164 self.environment_metrics = Some(environment_metrics);
165 self
166 }
167
168 pub fn memory_metrics(mut self, memory_metrics: axum::Router<S>) -> Self {
170 self.memory_metrics = Some(memory_metrics);
171 self
172 }
173
174 pub fn assembly(mut self, assembly: axum::Router<S>) -> Self {
176 self.assembly = Some(assembly);
177 self
178 }
179
180 pub fn disable_master_passphrase<H, T>(mut self, handler: H) -> Self
182 where
183 H: axum::handler::Handler<T, S, axum::body::Body>,
184 T: 'static,
185 {
186 self.disable_master_passphrase = Some(axum::routing::post(
187 |auth: redfish_core::extract::RedfishAuth<P::Post>,
188 axum::extract::State(state): axum::extract::State<S>,
189 mut request: axum::http::Request<axum::body::Body>| async {
190 request.extensions_mut().insert(auth.user);
191 handler.call(request, state).await
192 },
193 ));
194 self
195 }
196
197 pub fn disable_passphrase<H, T>(mut self, handler: H) -> Self
199 where
200 H: axum::handler::Handler<T, S, axum::body::Body>,
201 T: 'static,
202 {
203 self.disable_passphrase = Some(axum::routing::post(
204 |auth: redfish_core::extract::RedfishAuth<P::Post>,
205 axum::extract::State(state): axum::extract::State<S>,
206 mut request: axum::http::Request<axum::body::Body>| async {
207 request.extensions_mut().insert(auth.user);
208 handler.call(request, state).await
209 },
210 ));
211 self
212 }
213
214 pub fn freeze_security_state<H, T>(mut self, handler: H) -> Self
216 where
217 H: axum::handler::Handler<T, S, axum::body::Body>,
218 T: 'static,
219 {
220 self.freeze_security_state = Some(axum::routing::post(
221 |auth: redfish_core::extract::RedfishAuth<P::Post>,
222 axum::extract::State(state): axum::extract::State<S>,
223 mut request: axum::http::Request<axum::body::Body>| async {
224 request.extensions_mut().insert(auth.user);
225 handler.call(request, state).await
226 },
227 ));
228 self
229 }
230
231 pub fn inject_persistent_poison<H, T>(mut self, handler: H) -> Self
233 where
234 H: axum::handler::Handler<T, S, axum::body::Body>,
235 T: 'static,
236 {
237 self.inject_persistent_poison = Some(axum::routing::post(
238 |auth: redfish_core::extract::RedfishAuth<P::Post>,
239 axum::extract::State(state): axum::extract::State<S>,
240 mut request: axum::http::Request<axum::body::Body>| async {
241 request.extensions_mut().insert(auth.user);
242 handler.call(request, state).await
243 },
244 ));
245 self
246 }
247
248 pub fn overwrite_unit<H, T>(mut self, handler: H) -> Self
250 where
251 H: axum::handler::Handler<T, S, axum::body::Body>,
252 T: 'static,
253 {
254 self.overwrite_unit = Some(axum::routing::post(
255 |auth: redfish_core::extract::RedfishAuth<P::Post>,
256 axum::extract::State(state): axum::extract::State<S>,
257 mut request: axum::http::Request<axum::body::Body>| async {
258 request.extensions_mut().insert(auth.user);
259 handler.call(request, state).await
260 },
261 ));
262 self
263 }
264
265 pub fn reset<H, T>(mut self, handler: H) -> Self
267 where
268 H: axum::handler::Handler<T, S, axum::body::Body>,
269 T: 'static,
270 {
271 self.reset = Some(axum::routing::post(
272 |auth: redfish_core::extract::RedfishAuth<P::Post>,
273 axum::extract::State(state): axum::extract::State<S>,
274 mut request: axum::http::Request<axum::body::Body>| async {
275 request.extensions_mut().insert(auth.user);
276 handler.call(request, state).await
277 },
278 ));
279 self
280 }
281
282 pub fn reset_to_defaults<H, T>(mut self, handler: H) -> Self
284 where
285 H: axum::handler::Handler<T, S, axum::body::Body>,
286 T: 'static,
287 {
288 self.reset_to_defaults = Some(axum::routing::post(
289 |auth: redfish_core::extract::RedfishAuth<P::Post>,
290 axum::extract::State(state): axum::extract::State<S>,
291 mut request: axum::http::Request<axum::body::Body>| async {
292 request.extensions_mut().insert(auth.user);
293 handler.call(request, state).await
294 },
295 ));
296 self
297 }
298
299 pub fn scan_media<H, T>(mut self, handler: H) -> Self
301 where
302 H: axum::handler::Handler<T, S, axum::body::Body>,
303 T: 'static,
304 {
305 self.scan_media = Some(axum::routing::post(
306 |auth: redfish_core::extract::RedfishAuth<P::Post>,
307 axum::extract::State(state): axum::extract::State<S>,
308 mut request: axum::http::Request<axum::body::Body>| async {
309 request.extensions_mut().insert(auth.user);
310 handler.call(request, state).await
311 },
312 ));
313 self
314 }
315
316 pub fn secure_erase_unit<H, T>(mut self, handler: H) -> Self
318 where
319 H: axum::handler::Handler<T, S, axum::body::Body>,
320 T: 'static,
321 {
322 self.secure_erase_unit = Some(axum::routing::post(
323 |auth: redfish_core::extract::RedfishAuth<P::Post>,
324 axum::extract::State(state): axum::extract::State<S>,
325 mut request: axum::http::Request<axum::body::Body>| async {
326 request.extensions_mut().insert(auth.user);
327 handler.call(request, state).await
328 },
329 ));
330 self
331 }
332
333 pub fn set_master_passphrase<H, T>(mut self, handler: H) -> Self
335 where
336 H: axum::handler::Handler<T, S, axum::body::Body>,
337 T: 'static,
338 {
339 self.set_master_passphrase = Some(axum::routing::post(
340 |auth: redfish_core::extract::RedfishAuth<P::Post>,
341 axum::extract::State(state): axum::extract::State<S>,
342 mut request: axum::http::Request<axum::body::Body>| async {
343 request.extensions_mut().insert(auth.user);
344 handler.call(request, state).await
345 },
346 ));
347 self
348 }
349
350 pub fn set_passphrase<H, T>(mut self, handler: H) -> Self
352 where
353 H: axum::handler::Handler<T, S, axum::body::Body>,
354 T: 'static,
355 {
356 self.set_passphrase = Some(axum::routing::post(
357 |auth: redfish_core::extract::RedfishAuth<P::Post>,
358 axum::extract::State(state): axum::extract::State<S>,
359 mut request: axum::http::Request<axum::body::Body>| async {
360 request.extensions_mut().insert(auth.user);
361 handler.call(request, state).await
362 },
363 ));
364 self
365 }
366
367 pub fn unlock_unit<H, T>(mut self, handler: H) -> Self
369 where
370 H: axum::handler::Handler<T, S, axum::body::Body>,
371 T: 'static,
372 {
373 self.unlock_unit = Some(axum::routing::post(
374 |auth: redfish_core::extract::RedfishAuth<P::Post>,
375 axum::extract::State(state): axum::extract::State<S>,
376 mut request: axum::http::Request<axum::body::Body>| async {
377 request.extensions_mut().insert(auth.user);
378 handler.call(request, state).await
379 },
380 ));
381 self
382 }
383
384 pub fn into_router(self) -> axum::Router<S> {
385 let Self {
386 router,
387 mut allowed_methods,
388 device_log,
389 certificates,
390 environment_metrics,
391 memory_metrics,
392 assembly,
393 disable_master_passphrase,
394 disable_passphrase,
395 freeze_security_state,
396 inject_persistent_poison,
397 overwrite_unit,
398 reset,
399 reset_to_defaults,
400 scan_media,
401 secure_erase_unit,
402 set_master_passphrase,
403 set_passphrase,
404 unlock_unit,
405 ..
406 } = self;
407 let result = axum::Router::default();
408 let result = match device_log {
409 Some(router) => result.nest("/DeviceLog", router),
410 None => result,
411 };
412 let result = match certificates {
413 Some(router) => result.nest("/Certificates", router),
414 None => result,
415 };
416 let result = match environment_metrics {
417 Some(router) => result.nest("/EnvironmentMetrics", router),
418 None => result,
419 };
420 let result = match memory_metrics {
421 Some(router) => result.nest("/MemoryMetrics", router),
422 None => result,
423 };
424 let result = match assembly {
425 Some(router) => result.nest("/Assembly", router),
426 None => result,
427 };
428 let result = match disable_master_passphrase {
429 Some(router) => result.route("/Actions/Memory.DisableMasterPassphrase", router),
430 None => result,
431 };
432 let result = match disable_passphrase {
433 Some(router) => result.route("/Actions/Memory.DisablePassphrase", router),
434 None => result,
435 };
436 let result = match freeze_security_state {
437 Some(router) => result.route("/Actions/Memory.FreezeSecurityState", router),
438 None => result,
439 };
440 let result = match inject_persistent_poison {
441 Some(router) => result.route("/Actions/Memory.InjectPersistentPoison", router),
442 None => result,
443 };
444 let result = match overwrite_unit {
445 Some(router) => result.route("/Actions/Memory.OverwriteUnit", router),
446 None => result,
447 };
448 let result = match reset {
449 Some(router) => result.route("/Actions/Memory.Reset", router),
450 None => result,
451 };
452 let result = match reset_to_defaults {
453 Some(router) => result.route("/Actions/Memory.ResetToDefaults", router),
454 None => result,
455 };
456 let result = match scan_media {
457 Some(router) => result.route("/Actions/Memory.ScanMedia", router),
458 None => result,
459 };
460 let result = match secure_erase_unit {
461 Some(router) => result.route("/Actions/Memory.SecureEraseUnit", router),
462 None => result,
463 };
464 let result = match set_master_passphrase {
465 Some(router) => result.route("/Actions/Memory.SetMasterPassphrase", router),
466 None => result,
467 };
468 let result = match set_passphrase {
469 Some(router) => result.route("/Actions/Memory.SetPassphrase", router),
470 None => result,
471 };
472 let result = match unlock_unit {
473 Some(router) => result.route("/Actions/Memory.UnlockUnit", router),
474 None => result,
475 };
476 allowed_methods.dedup();
477 let allow_header = allowed_methods
478 .into_iter()
479 .map(|method| method.to_string())
480 .reduce(|one, two| one + "," + &two)
481 .unwrap();
482 result.route(
483 "/",
484 router.fallback(|| async {
485 (
486 axum::http::StatusCode::METHOD_NOT_ALLOWED,
487 axum::Json(redfish_core::error::one_message(redfish_codegen::registries::base::v1_16_0::Base::OperationNotAllowed.into())),
488 )
489 })
490 .route_layer(axum::middleware::from_fn_with_state(
491 allow_header,
492 |axum::extract::State(allow_header): axum::extract::State<String>,
493 request: axum::http::Request<axum::body::Body>,
494 next: axum::middleware::Next<axum::body::Body>| async move {
495 let apply_allow = matches!(*request.method(), axum::http::Method::GET | axum::http::Method::HEAD);
496 let mut response = next.run(request).await;
497 if apply_allow && !response.headers().contains_key(axum::http::header::ALLOW) {
498 response.headers_mut().insert(
499 axum::http::header::ALLOW,
500 axum::http::HeaderValue::from_str(&allow_header).unwrap(),
501 );
502 }
503 response
504 },
505 )),
506 )
507 }
508}