From d70c7eec05a9db178c6e110584543fe7e3a15db3 Mon Sep 17 00:00:00 2001 From: Roman Kivalin Date: Tue, 14 Apr 2026 17:29:27 +0200 Subject: [PATCH] Implement account deactivate command Deactivates the ACME account on the server and removes local credential files so subsequent commands don't use the stale account. Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 1 + src/acme.rs | 5 +++++ src/main.rs | 20 +++++++++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc251d7..d9926f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Multiple listen addresses for HTTP-01 and TLS-ALPN-01 solvers (`listen = ["[::]:80", "[::]:8080"]`). Certforge tries all addresses and succeeds if at least one binds. Useful for initial provisioning when a proxy isn't running yet. - `dane-check` now queries published TLSA records from DNS and verifies them against expected values. Exits with code 1 if any records are missing or mismatched. - Configurable DNS propagation delay per solver (`propagation_delay`, default 5s). +- Implement `account deactivate` command. ### Fixes diff --git a/src/acme.rs b/src/acme.rs index 3ff4328..e173e56 100644 --- a/src/acme.rs +++ b/src/acme.rs @@ -254,4 +254,9 @@ impl AcmeClient { pub fn account(&self) -> &Account { &self.account } + + pub async fn deactivate(self) -> Result<()> { + self.account.deactivate().await?; + Ok(()) + } } diff --git a/src/main.rs b/src/main.rs index 303c3bb..6b5e147 100644 --- a/src/main.rs +++ b/src/main.rs @@ -90,7 +90,25 @@ async fn main() -> anyhow::Result<()> { println!("Account ID: {}", client.account().id()); } AccountAction::Deactivate => { - tracing::warn!("account deactivation not yet implemented"); + let client = acme::AcmeClient::load(&config.acme).await?; + let id = client.account().id().to_string(); + client.deactivate().await?; + + // Remove local credentials so show/renew don't use the stale account + if let Some(path) = &config.acme.account_key_credential + && path.exists() + { + std::fs::remove_file(path)?; + tracing::info!(path = %path.display(), "removed account credential"); + } + if let Some(path) = &config.acme.account_key_path + && path.exists() + { + std::fs::remove_file(path)?; + tracing::info!(path = %path.display(), "removed account key file"); + } + + println!("Account {id} deactivated"); } } }