Seperated Code into different Files and functions Part 2

Dieser Commit ist enthalten in:
Sebastian Tobie 2025-05-15 08:35:09 +02:00
Ursprung dd026c901f
Commit bd3f0ad2ac
6 geänderte Dateien mit 225 neuen und 220 gelöschten Zeilen

Datei anzeigen

@ -5,17 +5,22 @@
pub(crate) mod consts;
pub(crate) mod macros;
pub(crate) mod prelude;
pub(crate) mod process;
pub(crate) mod types;
pub(crate) mod utils;
use crate::{
consts::*,
macros::match_error,
prelude::*,
process::{
process_accounts,
process_site,
services,
},
types::{
config,
config::{
CA,
GeneralConfig,
SiteConfig,
},
structs::{
@ -23,14 +28,8 @@ use crate::{
ProcessorArgs,
},
},
utils::prefix_emails,
};
use acme2_eab::{
Account,
AccountBuilder,
Directory,
DirectoryBuilder,
};
use acme2_eab::Directory;
use async_scoped::TokioScope;
use clap::Parser;
use env_logger::init as log_init;
@ -43,14 +42,7 @@ use openssl::{
Private,
},
};
use process::{
process_site,
services,
};
use reqwest::{
Client,
tls::Version,
};
use reqwest::tls::Version;
use std::{
collections::{
HashMap,
@ -69,20 +61,13 @@ use tokio::{
create_dir_all,
read_dir,
},
io::{
AsyncReadExt,
AsyncWriteExt,
},
io::AsyncReadExt,
sync::Mutex,
};
use tokio_stream::{
StreamExt,
wrappers::ReadDirStream,
};
use types::{
config::GeneralConfig,
traits::FromFile as _,
};
fn default_client() -> reqwest::Client {
@ -105,107 +90,6 @@ async fn load_privkey(path: PathBuf) -> Result<PKey<Private>, ()> {
}
}
async fn process_accounts(
name: &String,
ca: &CA,
directories: &mut HashMap<String, Arc<Directory>>,
accounts: &mut HashMap<String, Arc<Account>>,
client: &Client,
accountpath: PathBuf,
) {
let directory = match directories.get(&ca.directory) {
Some(directory) => directory.to_owned(),
None => {
match DirectoryBuilder::new(ca.directory.clone()).http_client(client.clone()).build().await {
Ok(dir) => {
directories.insert(ca.directory.clone(), Arc::clone(&dir));
dir
},
Err(error) => {
error!("Failed to initialize directory for ca {name}: {error}");
return;
},
}
},
};
let mut ac = AccountBuilder::new(Arc::clone(&directory));
match ca.email_addresses.clone() {
Some(addr) => {
ac.contact(prefix_emails(addr));
},
None => {
ac.contact(Vec::new());
debug!("No Email address given")
},
}
let accountkey = accountpath.join("file.pem").with_file_name(name.clone());
let mut accountkeyfile = None;
if accountkey.exists() {
if let Ok(key) = load_privkey(accountkey).await {
ac.private_key(key);
}
} else {
info!("Registering for the CA {}", name.clone());
accountkeyfile = match FILE_MODE_WRITE.open(accountkey).await {
Ok(file) => Some(file),
Err(error) => {
error!("Failed to open the file for the accountkey: {error}");
return;
},
}
}
if let Some(meta) = &directory.meta {
// Collecting the errors about the metadata before annoying the admin about errors at different stages
let mut errors = false;
if let Some(tos) = &meta.terms_of_service {
if !ca.tos_accepted {
error!("Terms of Services were not agreed into: {tos}");
errors = true;
} else {
ac.terms_of_service_agreed(true);
}
}
if meta.external_account_required.unwrap_or(false) {
if let Some(eab) = &ca.eab {
match eab.key() {
Ok(private) => {
trace!("EAB Key info: Type={:?} Bits={}, Security-Bits={}", private.id(), private.bits(), private.security_bits());
ac.external_account_binding(eab.token.clone(), private);
},
Err(error) => {
error!("{error}");
errors = true;
},
}
} else {
error!("eab_token and/or eab_key are unset, but the CA requires those.");
errors = true;
}
} else if ca.eab.is_some() {
warn!("The CA doesn't need EAB Tokens but they were configured")
}
if errors {
return;
}
}
let account = match ac.build().await {
Ok(account) => {
accounts.insert(name.clone(), Arc::clone(&account));
account
},
Err(error) => {
error!("Failed to get/create account: {error}");
return;
},
};
if let Some(mut keyfile) = accountkeyfile {
let keydata = match_error!(account.private_key().private_key_to_pem_pkcs8()=>Err(error)-> "Failed to convert the private key to an pem: {error}");
if let Err(error) = keyfile.write(keydata.as_slice()).await {
error!("Failed to write the accountkey: {error}");
}
}
}
async fn racme(flags: Arguments) {
let client = default_client();
let systemd_access = daemon::booted();

8
src/prelude.rs Normale Datei
Datei anzeigen

@ -0,0 +1,8 @@
pub(crate) use crate::{
macros::*,
types::traits::{
FromFile as _,
MatchAlgorithm as _,
MatchX509 as _,
},
};

Datei anzeigen

@ -1,8 +1,12 @@
use std::{
collections::HashSet,
collections::{
HashMap,
HashSet,
},
fs::Permissions,
os::unix::fs::PermissionsExt,
path::PathBuf,
sync::Arc,
};
use crate::{
@ -13,25 +17,31 @@ use crate::{
WAIT_TIME,
},
load_privkey,
macros::match_error,
prelude::*,
types::{
config::Dns,
config::{
CA,
Dns,
},
cryptography::Algorithm,
structs::{
ProcessorArgs,
San,
},
traits::{
MatchAlgorithm as _,
MatchX509,
},
utils::{
gen_key,
prefix_emails,
},
utils::gen_key,
};
use acme2_eab::{
Account,
AccountBuilder,
Authorization,
ChallengeStatus,
Csr,
Directory,
DirectoryBuilder,
Identifier,
OrderBuilder,
OrderStatus,
@ -54,6 +64,7 @@ use openssl::{
},
},
};
use reqwest::Client;
use tokio::{
fs::{
create_dir_all,
@ -86,6 +97,107 @@ fn gen_stack(args: &ProcessorArgs, context: X509v3Context) -> Stack<X509Extensio
stack
}
pub async fn process_accounts(
name: &String,
ca: &CA,
directories: &mut HashMap<String, Arc<Directory>>,
accounts: &mut HashMap<String, Arc<Account>>,
client: &Client,
accountpath: PathBuf,
) {
let directory = match directories.get(&ca.directory) {
Some(directory) => directory.to_owned(),
None => {
match DirectoryBuilder::new(ca.directory.clone()).http_client(client.clone()).build().await {
Ok(dir) => {
directories.insert(ca.directory.clone(), Arc::clone(&dir));
dir
},
Err(error) => {
error!("Failed to initialize directory for ca {name}: {error}");
return;
},
}
},
};
let mut ac = AccountBuilder::new(Arc::clone(&directory));
match ca.email_addresses.clone() {
Some(addr) => {
ac.contact(prefix_emails(addr));
},
None => {
ac.contact(Vec::new());
debug!("No Email address given")
},
}
let accountkey = accountpath.join("file.pem").with_file_name(name.clone());
let mut accountkeyfile = None;
if accountkey.exists() {
if let Ok(key) = load_privkey(accountkey).await {
ac.private_key(key);
}
} else {
info!("Registering for the CA {}", name.clone());
accountkeyfile = match FILE_MODE_WRITE.open(accountkey).await {
Ok(file) => Some(file),
Err(error) => {
error!("Failed to open the file for the accountkey: {error}");
return;
},
}
}
if let Some(meta) = &directory.meta {
// Collecting the errors about the metadata before annoying the admin about errors at different stages
let mut errors = false;
if let Some(tos) = &meta.terms_of_service {
if !ca.tos_accepted {
error!("Terms of Services were not agreed into: {tos}");
errors = true;
} else {
ac.terms_of_service_agreed(true);
}
}
if meta.external_account_required.unwrap_or(false) {
if let Some(eab) = &ca.eab {
match eab.key() {
Ok(private) => {
trace!("EAB Key info: Type={:?} Bits={}, Security-Bits={}", private.id(), private.bits(), private.security_bits());
ac.external_account_binding(eab.token.clone(), private);
},
Err(error) => {
error!("{error}");
errors = true;
},
}
} else {
error!("eab_token and/or eab_key are unset, but the CA requires those.");
errors = true;
}
} else if ca.eab.is_some() {
warn!("The CA doesn't need EAB Tokens but they were configured")
}
if errors {
return;
}
}
let account = match ac.build().await {
Ok(account) => {
accounts.insert(name.clone(), Arc::clone(&account));
account
},
Err(error) => {
error!("Failed to get/create account: {error}");
return;
},
};
if let Some(mut keyfile) = accountkeyfile {
let keydata = match_error!(account.private_key().private_key_to_pem_pkcs8()=>Err(error)-> "Failed to convert the private key to an pem: {error}");
if let Err(error) = keyfile.write(keydata.as_slice()).await {
error!("Failed to write the accountkey: {error}");
}
}
}
pub async fn process_site(args: ProcessorArgs<'_>) {
let mut cert_renew = false;
@ -98,8 +210,10 @@ pub async fn process_site(args: ProcessorArgs<'_>) {
};
cert_renew = true;
}
let private_key_file = directory.join("privkey.pem");
let mut private_key;
// Private key block
{
let private_key_file = directory.join("privkey.pem");
let mut write_pkey = false;
if !private_key_file.exists() {
cert_renew = true;
@ -124,6 +238,7 @@ pub async fn process_site(args: ProcessorArgs<'_>) {
let mut file = match_error!(FILE_MODE_WRITE.open(private_key_file.clone()).await=>Err(error)-> "Failed to write new private key: {error}");
match_error!(file.write_all(&pkey).await=>Err(error)->"Failed to write new private key: {error}");
}
}
let pubkey_filename = directory.join("pubkey.pem");
if pubkey_filename.exists() {
let mut file = match_error!(FILE_MODE.open(pubkey_filename.clone()).await=>Err(error)-> "Failed to open publickey. Aborting processing: {error}");
@ -151,10 +266,13 @@ pub async fn process_site(args: ProcessorArgs<'_>) {
info!("Site {} doesn't need an update for the certificate.", args.name());
return;
}
// Requesting a new cert
let mut order;
{
info!("Renewing Certificate for site {}", args.name());
let mut builder = OrderBuilder::new(args.account());
builder.set_identifiers(args.san().iter().map(|s| s.to_owned().into()).collect::<Vec<Identifier>>());
let mut order = match_error!(builder.build().await=>Err(error)-> "Failed order the certificate: {error}");
order = match_error!(builder.build().await=>Err(error)-> "Failed order the certificate: {error}");
let authorizations = match_error!(order.authorizations().await=>Err(error)-> "Failed to get the authorizations: {error}");
let (_, result) = tokio::join! {
unsafe {
@ -197,7 +315,8 @@ pub async fn process_site(args: ProcessorArgs<'_>) {
debug!("Received {} certificates.", certs.len());
let mut pubkey_file = match_error!(FILE_MODE_WRITE.open(pubkey_filename).await=>Err(error)-> "Failed to open the file for the publickey: {error}");
match_error!(pubkey_file.write_all(&certs[0].to_pem().unwrap()).await=>Err(error)-> "Failed to write the publickey: {error}");
let mut fullchain = match_error!(FILE_MODE_WRITE.open(directory.join("fullchain.pem")).await=>Err(error)-> "failed to open the fullchain.pem: {error}");
let mut fullchain =
match_error!(FILE_MODE_WRITE.open(directory.join("fullchain.pem")).await=>Err(error)-> "failed to open the fullchain.pem: {error}");
for cert in certs.clone() {
let _ = fullchain.write_all(&cert.to_pem().unwrap()).await;
}
@ -205,6 +324,7 @@ pub async fn process_site(args: ProcessorArgs<'_>) {
let _ = bundle.write_all(&private_key.private_key_to_pem_pkcs8().unwrap()).await;
let _ = bundle.write_all(&certs[0].to_pem().unwrap()).await;
info!("Processing of {} successful", args.name());
}
let mut services = args.reload_list().await;
for service in &args.reload_services() {
services.insert(service.to_owned());

Datei anzeigen

@ -1,8 +1,5 @@
use crate::{
macros::{
DefDer,
match_error,
},
prelude::*,
types::{
VString,
cryptography::{

Datei anzeigen

@ -1,7 +1,7 @@
use macro_rules_attribute::macro_rules_derive;
use serde::Deserialize;
use crate::macros::DefDer;
use crate::prelude::*;
#[macro_rules_derive(DefDer)]

Datei anzeigen

@ -11,14 +11,10 @@ use macro_rules_attribute::macro_rules_derive;
use tokio::sync::MutexGuard;
use crate::{
config::SiteConfig,
macros::{
DefDer,
Hashable,
attr_function,
},
prelude::*,
types::{
SafeSet,
config::SiteConfig,
cryptography::{
Algorithm,
Strength,
@ -26,7 +22,7 @@ use crate::{
},
};
use super::config::Dns;
use crate::types::config::Dns;
#[macro_rules_derive(DefDer)]