easy_rsa_registry/
update.rs

1use std::fs;
2
3use chrono::Local;
4use log::info;
5
6use crate::EasyRsaCertificateStatus;
7use crate::error::EasyRsaRegistryError;
8use crate::read::read_certs_from_file;
9
10pub fn update_cert_status(index_file_path: &str,
11          cert_serial: &str, status: EasyRsaCertificateStatus) -> Result<(), EasyRsaRegistryError> {
12    info!("update certificate status for '{cert_serial}' to {:?}", status);
13    info!("index file path '{index_file_path}'");
14
15    let certs = read_certs_from_file(&index_file_path)?;
16
17    let mut rows: Vec<String> = vec![];
18
19    for cert in certs {
20        if cert.serial_number == cert_serial {
21            let mut updated_cert = cert.clone();
22
23            if status == EasyRsaCertificateStatus::Valid {
24                updated_cert.revocation_date = None;
25            }
26
27            if status == EasyRsaCertificateStatus::Revoked {
28                let now = Local::now();
29                let now = now.format("%y%m%d%H%M%SZ");
30                updated_cert.revocation_date = Some(format!("{now}"));
31            }
32
33            updated_cert.status = status.clone();
34            rows.push(updated_cert.to_registry_row())
35
36        } else {
37            rows.push(cert.to_registry_row())
38        }
39    }
40
41    let content = rows.join("\n");
42
43    fs::write(index_file_path, content)?;
44
45    info!("status has been updated for '{cert_serial}' to '{}'", status.to_string());
46
47    Ok(())
48}
49
50#[cfg(test)]
51mod tests {
52    use std::fs;
53    use std::path::Path;
54
55    use crate::{EasyRsaCertificateStatus, EasyRsaCertificateStatusCode};
56    use crate::error::EasyRsaRegistryError;
57    use crate::read::read_certs_from_file;
58    use crate::update::update_cert_status;
59
60    #[test]
61    fn return_parse_error_for_corrupted_file() {
62        let registry_file = Path::new("test-data").join("invalid.txt");
63        let registry_file = format!("{}", registry_file.display());
64
65        match update_cert_status(
66            &registry_file, "F15621FE882946FC63FA657837888821",
67            EasyRsaCertificateStatus::Revoked) {
68            Ok(_) => panic!("parse error expected"),
69            Err(e) => {
70                match e {
71                    EasyRsaRegistryError::ParseError => assert!(true),
72                    _ => panic!("parse error expected")
73                }
74            }
75        }
76    }
77
78    #[test]
79    fn status_should_be_updated_from_revoked_to_valid() {
80        assert_status_changed("36593F7437AEB5007D2953E7A98B7601", EasyRsaCertificateStatus::Valid);
81        assert_status_changed("F15621FE882946FC63FA657837888821", EasyRsaCertificateStatus::Expired);
82        assert_status_changed("91453D05307390677E4848FDD0D812D4", EasyRsaCertificateStatus::Revoked);
83    }
84
85    fn assert_status_changed(cert_serial: &str, target_status: EasyRsaCertificateStatus) {
86        let nominal_registry_file = Path::new("test-data").join("index.txt");
87        let dest_registry_file = Path::new("test-data").join("index.txt_");
88
89        if dest_registry_file.exists() {
90            fs::remove_file(&dest_registry_file).unwrap();
91        }
92
93        fs::copy(nominal_registry_file, &dest_registry_file).unwrap();
94
95        let dest_registry_file = format!("{}", dest_registry_file.display());
96
97        update_cert_status(&dest_registry_file, cert_serial, target_status.clone()).unwrap();
98
99        let certs = read_certs_from_file(&dest_registry_file).unwrap();
100
101        let result = certs.iter().find(|c|
102            c.serial_number == cert_serial).unwrap();
103
104        assert_eq!(result.status, target_status.clone());
105        assert_eq!(result.status_code, EasyRsaCertificateStatusCode::Unknown);
106        assert_eq!(result.serial_number, cert_serial);
107
108        if target_status == EasyRsaCertificateStatus::Revoked {
109            assert!(result.revocation_date.is_some());
110
111        } else {
112            assert!(result.revocation_date.is_none());
113        }
114    }
115}