Skip to main content

rsfn_file/header/fields/
cert_serial.rs

1use std::fmt;
2
3/// Série do certificado digital.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct CertSerial([u8; 32]);
6
7impl From<[u8; 32]> for CertSerial {
8    fn from(value: [u8; 32]) -> Self {
9        Self(value)
10    }
11}
12
13impl CertSerial {
14    pub fn value(&self) -> [u8; 32] {
15        self.0
16    }
17
18    fn ascii_value(&self) -> Result<String, ()> {
19        let value: String = self
20            .value()
21            .into_iter()
22            .skip_while(|&byte| byte == 0 || byte == b'0')
23            .map(|byte| byte as char)
24            .collect();
25        if !value.is_empty() && value.chars().all(|c| c.is_ascii_hexdigit()) {
26            Ok(value)
27        } else {
28            Err(())
29        }
30    }
31
32    pub fn describe_value(&self) -> String {
33        match self.ascii_value() {
34            Ok(value) => format!("0x{}", value.to_lowercase()),
35            Err(_) => "INVÁLIDO".to_string(),
36        }
37    }
38
39    pub fn is_valid(&self) -> bool {
40        self.ascii_value().is_ok()
41    }
42
43    pub fn to_bytes(&self) -> [u8; 32] {
44        self.value()
45    }
46}
47
48impl fmt::Display for CertSerial {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        let value: String = self
51            .value()
52            .iter()
53            .map(|byte| format!("{byte:02x}"))
54            .collect();
55        let desc = self.describe_value();
56        write!(f, "0x{value} [{desc}]")
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn value_binary_zero() {
66        let value = [0; 32];
67
68        let sut: CertSerial = value.into();
69
70        assert_eq!(sut, CertSerial(value));
71        assert_eq!(sut, value.into());
72        assert_eq!(sut.value(), value);
73        assert_eq!(sut.describe_value(), "INVÁLIDO");
74        assert!(!sut.is_valid());
75        assert_eq!(sut.to_bytes(), value);
76        assert_eq!(
77            sut.to_string(),
78            "0x0000000000000000000000000000000000000000000000000000000000000000 [INVÁLIDO]"
79        );
80    }
81
82    #[test]
83    fn value_ascii_zero() {
84        let value = [b'0'; 32];
85
86        let sut: CertSerial = value.into();
87
88        assert_eq!(sut, CertSerial(value));
89        assert_eq!(sut, value.into());
90        assert_eq!(sut.value(), value);
91        assert_eq!(sut.describe_value(), "INVÁLIDO");
92        assert!(!sut.is_valid());
93        assert_eq!(sut.to_bytes(), value);
94        assert_eq!(
95            sut.to_string(),
96            "0x3030303030303030303030303030303030303030303030303030303030303030 [INVÁLIDO]"
97        );
98    }
99
100    #[test]
101    fn value_some_bytes() {
102        let mut value = [0; 32];
103        for i in 26..32 {
104            value[i as usize] = b'1' + i - 26;
105        }
106        let value = value;
107
108        let sut: CertSerial = value.into();
109
110        assert_eq!(sut, CertSerial(value));
111        assert_eq!(sut, value.into());
112        assert_eq!(sut.value(), value);
113        assert_eq!(sut.describe_value(), "0x123456");
114        assert!(sut.is_valid());
115        assert_eq!(sut.to_bytes(), value);
116        assert_eq!(
117            sut.to_string(),
118            "0x0000000000000000000000000000000000000000000000000000313233343536 [0x123456]"
119        );
120    }
121
122    #[test]
123    fn value_invalid_bytes() {
124        let value = [0xff; 32];
125
126        let sut: CertSerial = value.into();
127
128        assert_eq!(sut, CertSerial(value));
129        assert_eq!(sut, value.into());
130        assert_eq!(sut.value(), value);
131        assert_eq!(sut.describe_value(), "INVÁLIDO");
132        assert!(!sut.is_valid());
133        assert_eq!(sut.to_bytes(), value);
134        assert_eq!(
135            sut.to_string(),
136            "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff [INVÁLIDO]"
137        );
138    }
139
140    #[test]
141    fn value_full() {
142        let value: [u8; 32] = (0..16)
143            .flat_map(|byte| {
144                format!("{byte:02X}")
145                    .chars()
146                    .map(|c| c as u8)
147                    .collect::<Vec<_>>()
148            })
149            .collect::<Vec<_>>()
150            .try_into()
151            .unwrap();
152
153        let sut: CertSerial = value.into();
154
155        assert_eq!(sut, CertSerial(value));
156        assert_eq!(sut, value.into());
157        assert_eq!(sut.value(), value);
158        assert_eq!(sut.describe_value(), "0x102030405060708090a0b0c0d0e0f");
159        assert!(sut.is_valid());
160        assert_eq!(sut.to_bytes(), value);
161        assert_eq!(
162            sut.to_string(),
163            "0x3030303130323033303430353036303730383039304130423043304430453046 [0x102030405060708090a0b0c0d0e0f]"
164        );
165    }
166}