easy_rsa_registry/
update.rs1use 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 ®istry_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}