hdm_am/operations/
session.rs1use crate::wire::OperationCode;
2use serde::{Deserialize, Serialize};
3
4use super::{EmptyResponse, Operation};
5
6#[derive(Clone, Serialize)]
11#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
12pub struct OperatorLoginRequest {
13 pub password: String,
15 pub cashier: u32,
17 pub pin: String,
19}
20
21impl std::fmt::Debug for OperatorLoginRequest {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 f.debug_struct("OperatorLoginRequest")
24 .field("password", &"[redacted]")
25 .field("cashier", &self.cashier)
26 .field("pin", &"[redacted]")
27 .finish()
28 }
29}
30
31impl Operation for OperatorLoginRequest {
32 const CODE: OperationCode = OperationCode::OperatorLogin;
33 const USES_PASSWORD_KEY: bool = true;
34 const RESPONSE_IS_SECRET: bool = true;
35 type Response = OperatorLoginResponse;
36}
37
38#[derive(Clone, Deserialize)]
44#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
45#[non_exhaustive]
46pub struct OperatorLoginResponse {
47 pub key: String,
49}
50
51impl std::fmt::Debug for OperatorLoginResponse {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 f.debug_struct("OperatorLoginResponse")
54 .field("key", &"[redacted]")
55 .finish()
56 }
57}
58
59#[derive(Debug, Clone, Serialize)]
61#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
62pub struct OperatorLogoutRequest {}
63
64impl Operation for OperatorLogoutRequest {
65 const CODE: OperationCode = OperationCode::OperatorLogout;
66 type Response = EmptyResponse;
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
75 fn debug_redacts_secrets() {
76 let request = OperatorLoginRequest {
77 password: "super-secret-pw".to_owned(),
78 cashier: 3,
79 pin: "9999".to_owned(),
80 };
81 let rendered = format!("{request:?}");
82 assert!(rendered.contains("[redacted]"), "{rendered}");
83 assert!(
84 !rendered.contains("super-secret-pw"),
85 "password leaked: {rendered}"
86 );
87 assert!(!rendered.contains("9999"), "pin leaked: {rendered}");
88 assert!(
89 rendered.contains("cashier: 3"),
90 "non-secret field should show: {rendered}"
91 );
92
93 let response = OperatorLoginResponse {
94 key: "SECRET-SESSION-KEY".to_owned(),
95 };
96 let rendered = format!("{response:?}");
97 assert!(rendered.contains("[redacted]"), "{rendered}");
98 assert!(
99 !rendered.contains("SECRET-SESSION-KEY"),
100 "session key leaked: {rendered}"
101 );
102 }
103}