ACME freshness check improvements
This commit is contained in:
13
.github/workflows/ci.yml
vendored
13
.github/workflows/ci.yml
vendored
@@ -150,9 +150,22 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Free disk space (heavy ARM targets)
|
||||
if: contains(matrix.target, 'arm')
|
||||
run: |
|
||||
df -h /mnt /
|
||||
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android /usr/local/.ghcup /usr/local/share/powershell /usr/share/swift /opt/hostedtoolcache/CodeQL
|
||||
sudo docker image prune --all --force || true
|
||||
df -h /mnt /
|
||||
|
||||
- name: Add swap (heavy ARM targets)
|
||||
if: contains(matrix.target, 'arm')
|
||||
run: |
|
||||
mnt_avail=$(df --output=avail -k /mnt | tail -1)
|
||||
if [ "$mnt_avail" -lt 18874368 ]; then
|
||||
echo "Insufficient space on /mnt (${mnt_avail}K available), aborting swap setup"
|
||||
exit 1
|
||||
fi
|
||||
sudo fallocate -l 16G /mnt/swapfile
|
||||
sudo chmod 600 /mnt/swapfile
|
||||
sudo mkswap /mnt/swapfile
|
||||
|
||||
8
crates/common/src/cache/principals.rs
vendored
8
crates/common/src/cache/principals.rs
vendored
@@ -238,8 +238,8 @@ impl Server {
|
||||
.addresses
|
||||
.iter()
|
||||
.any(|address| {
|
||||
address.local_part.as_ref() == local_part
|
||||
&& address.domain_id == domain_id
|
||||
address.domain_id == domain_id
|
||||
&& address.local_part.as_ref() == local_part
|
||||
})
|
||||
{
|
||||
EmailCache::Account(item_id)
|
||||
@@ -250,8 +250,8 @@ impl Server {
|
||||
ObjectType::MailingList => {
|
||||
if let Some(list) = self.try_list(item_id).await?
|
||||
&& !list.addresses.iter().any(|address| {
|
||||
address.local_part.as_ref() == local_part
|
||||
&& address.domain_id == domain_id
|
||||
address.domain_id == domain_id
|
||||
&& address.local_part.as_ref() == local_part
|
||||
})
|
||||
{
|
||||
EmailCache::DisabledListAddress(item_id)
|
||||
|
||||
@@ -32,6 +32,7 @@ pub enum AcmeError {
|
||||
Json(serde_json::Error),
|
||||
Crypto(String),
|
||||
Invalid(String),
|
||||
NotDue(String),
|
||||
Dns(String),
|
||||
AuthInvalid(String),
|
||||
OrderInvalid(String),
|
||||
@@ -257,6 +258,7 @@ impl Display for AcmeError {
|
||||
AcmeError::Dns(err) => write!(f, "DNS error: {}", err),
|
||||
AcmeError::Crypto(err) => write!(f, "Cryptographic error: {}", err),
|
||||
AcmeError::Invalid(err) => write!(f, "Invalid request: {}", err),
|
||||
AcmeError::NotDue(err) => write!(f, "{}", err),
|
||||
AcmeError::AuthInvalid(status) => write!(f, "Authentication failed: {:?}", status),
|
||||
AcmeError::OrderTimeout { .. } => write!(f, "Order processing timed out"),
|
||||
AcmeError::OrderInvalid(reason) => write!(f, "Order is invalid: {}", reason),
|
||||
|
||||
@@ -65,10 +65,11 @@ impl Server {
|
||||
);
|
||||
|
||||
if let Some(renew_at) = self.acme_certificate_renewal_due(&domains, renew_before, now()) {
|
||||
return Ok(vec![Task::AcmeRenewal(TaskDomainManagement {
|
||||
domain_id,
|
||||
status: TaskStatus::at(renew_at as i64),
|
||||
})]);
|
||||
return Err(AcmeError::NotDue(format!(
|
||||
"Certificate for domain {} is still valid; renewal is not due until {}",
|
||||
domain.name,
|
||||
UTCDateTime::from_timestamp(renew_at as i64)
|
||||
)));
|
||||
}
|
||||
|
||||
let dns_parameters = match &domain.dns_management {
|
||||
@@ -168,29 +169,15 @@ impl Server {
|
||||
self.cluster_broadcast(BroadcastEvent::RegistryChange(change))
|
||||
.await;
|
||||
|
||||
// Schedule next renewal
|
||||
let mut tasks = Vec::new();
|
||||
let renew_in = match renew_before {
|
||||
AcmeRenewBefore::R12 => {
|
||||
// 1/2 of the remaining time until expiration
|
||||
expires_in / 2
|
||||
}
|
||||
AcmeRenewBefore::R23 => {
|
||||
// 2/3 of the remaining time until expiration
|
||||
expires_in * 2 / 3
|
||||
}
|
||||
AcmeRenewBefore::R34 => {
|
||||
// 3/4 of the remaining time until expiration
|
||||
expires_in * 3 / 4
|
||||
}
|
||||
AcmeRenewBefore::R45 => {
|
||||
// 4/5 of the remaining time until expiration
|
||||
expires_in * 4 / 5
|
||||
}
|
||||
};
|
||||
let renew_at = Self::acme_renewal_due_at(
|
||||
parsed_cert.valid_not_before.timestamp(),
|
||||
parsed_cert.valid_not_after.timestamp(),
|
||||
renew_before,
|
||||
);
|
||||
tasks.push(Task::AcmeRenewal(TaskDomainManagement {
|
||||
domain_id,
|
||||
status: TaskStatus::at((now + renew_in) as i64),
|
||||
status: TaskStatus::at(renew_at),
|
||||
}));
|
||||
|
||||
// Update TLSA records
|
||||
@@ -245,14 +232,8 @@ impl Server {
|
||||
return None;
|
||||
}
|
||||
let not_valid_before = parsed.valid_not_before.timestamp();
|
||||
let total = not_valid_after.saturating_sub(not_valid_before);
|
||||
let (numerator, denominator) = match renew_before {
|
||||
AcmeRenewBefore::R12 => (1, 2),
|
||||
AcmeRenewBefore::R23 => (2, 3),
|
||||
AcmeRenewBefore::R34 => (3, 4),
|
||||
AcmeRenewBefore::R45 => (4, 5),
|
||||
};
|
||||
let renew_at = not_valid_before + total * numerator / denominator;
|
||||
let renew_at =
|
||||
Self::acme_renewal_due_at(not_valid_before, not_valid_after, renew_before);
|
||||
return if now < renew_at {
|
||||
Some(renew_at as u64)
|
||||
} else {
|
||||
@@ -262,4 +243,19 @@ impl Server {
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn acme_renewal_due_at(
|
||||
not_valid_before: i64,
|
||||
not_valid_after: i64,
|
||||
renew_before: AcmeRenewBefore,
|
||||
) -> i64 {
|
||||
let total = not_valid_after.saturating_sub(not_valid_before);
|
||||
let (numerator, denominator) = match renew_before {
|
||||
AcmeRenewBefore::R12 => (1, 2),
|
||||
AcmeRenewBefore::R23 => (2, 3),
|
||||
AcmeRenewBefore::R34 => (3, 4),
|
||||
AcmeRenewBefore::R45 => (4, 5),
|
||||
};
|
||||
not_valid_before + total * numerator / denominator
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ async fn acme_management(server: &Server, task: &TaskDomainManagement) -> trc::R
|
||||
Err(err) => match err {
|
||||
AcmeError::Crypto(_)
|
||||
| AcmeError::Invalid(_)
|
||||
| AcmeError::NotDue(_)
|
||||
| AcmeError::ChallengeNotSupported { .. }
|
||||
| AcmeError::OrderInvalid(_)
|
||||
| AcmeError::Json(_)
|
||||
|
||||
Reference in New Issue
Block a user