rust_serv/auto_tls/
mod.rs1mod account;
6mod challenge;
7mod client;
8mod store;
9
10pub use account::AcmeAccount;
11pub use challenge::ChallengeHandler;
12pub use client::AcmeClient;
13pub use store::{CertificateStore, StoredCertificate};
14
15use serde::{Deserialize, Serialize};
16
17#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
19pub struct AutoTlsConfig {
20 #[serde(default)]
22 pub enabled: bool,
23
24 #[serde(default)]
26 pub domains: Vec<String>,
27
28 #[serde(default)]
30 pub email: String,
31
32 #[serde(default = "default_challenge_type")]
34 pub challenge_type: String,
35
36 #[serde(default = "default_cache_dir")]
38 pub cache_dir: String,
39
40 #[serde(default = "default_renew_days")]
42 pub renew_before_days: u32,
43}
44
45fn default_challenge_type() -> String { "http-01".to_string() }
46fn default_cache_dir() -> String { "./certs".to_string() }
47fn default_renew_days() -> u32 { 30 }
48
49impl Default for AutoTlsConfig {
50 fn default() -> Self {
51 Self {
52 enabled: false,
53 domains: vec![],
54 email: String::new(),
55 challenge_type: default_challenge_type(),
56 cache_dir: default_cache_dir(),
57 renew_before_days: default_renew_days(),
58 }
59 }
60}
61
62pub const LETSENCRYPT_PRODUCTION_URL: &str = "https://acme-v02.api.letsencrypt.org/directory";
64
65pub const LETSENCRYPT_STAGING_URL: &str = "https://acme-staging-v02.api.letsencrypt.org/directory";
67
68#[derive(Debug, thiserror::Error)]
70pub enum AutoTlsError {
71 #[error("ACME error: {0}")]
73 AcmeError(String),
74
75 #[error("Challenge error: {0}")]
77 ChallengeError(String),
78
79 #[error("Certificate error: {0}")]
81 CertificateError(String),
82
83 #[error("IO error: {0}")]
85 IoError(#[from] std::io::Error),
86
87 #[error("Configuration error: {0}")]
89 ConfigError(String),
90
91 #[error("Store error: {0}")]
93 StoreError(String),
94
95 #[error("Serialization error: {0}")]
97 SerializationError(#[from] serde_json::Error),
98}
99
100pub type AutoTlsResult<T> = Result<T, AutoTlsError>;
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_auto_tls_config_default() {
109 let config = AutoTlsConfig::default();
110 assert!(!config.enabled);
111 assert!(config.domains.is_empty());
112 assert_eq!(config.challenge_type, "http-01");
113 assert_eq!(config.cache_dir, "./certs");
114 assert_eq!(config.renew_before_days, 30);
115 }
116
117 #[test]
118 fn test_auto_tls_config_custom() {
119 let config = AutoTlsConfig {
120 enabled: true,
121 domains: vec!["example.com".to_string()],
122 email: "admin@example.com".to_string(),
123 challenge_type: "dns-01".to_string(),
124 cache_dir: "/etc/certs".to_string(),
125 renew_before_days: 14,
126 };
127 assert!(config.enabled);
128 assert_eq!(config.domains.len(), 1);
129 assert_eq!(config.challenge_type, "dns-01");
130 assert_eq!(config.renew_before_days, 14);
131 }
132
133 #[test]
134 fn test_letsencrypt_urls() {
135 assert!(LETSENCRYPT_PRODUCTION_URL.contains("letsencrypt.org"));
136 assert!(LETSENCRYPT_STAGING_URL.contains("letsencrypt.org"));
137 assert!(LETSENCRYPT_STAGING_URL.contains("staging"));
138 }
139
140 #[test]
141 fn test_auto_tls_error_display() {
142 let error = AutoTlsError::AcmeError("test".to_string());
143 assert!(error.to_string().contains("ACME error"));
144
145 let error = AutoTlsError::ChallengeError("fail".to_string());
146 assert!(error.to_string().contains("Challenge error"));
147 }
148}