mirror of
https://github.com/rkivalin/certforge.git
synced 2026-10-13 00:00:42 +00:00
Fix account show creating account when credentials are missing
Split AcmeClient::new into load (existing only) and create (register new). account show now uses load and errors if no credentials exist, account create always registers a new account. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
4a41e60790
commit
d6e95bade5
@@ -10,6 +10,7 @@
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix `account show` creating a new account instead of erroring when no credentials exist
|
||||
- Fix inline hooks ignoring `--dry-run` flag
|
||||
- Validate certificate name and hook name uniqueness
|
||||
- Validate that every domain has a solver configured (via `solver`, `solvers`, or `default_solver`)
|
||||
|
||||
+65
-58
@@ -30,72 +30,79 @@ pub struct ChallengeInfo {
|
||||
}
|
||||
|
||||
impl AcmeClient {
|
||||
/// Load existing account or create a new one if credentials don't exist.
|
||||
pub async fn new(config: &AcmeConfig) -> Result<Self> {
|
||||
let cred_data = credentials::load_secret(
|
||||
match Self::load(config).await {
|
||||
Ok(client) => Ok(client),
|
||||
Err(_) => Self::create(config).await,
|
||||
}
|
||||
}
|
||||
|
||||
/// Load an existing account from credentials. Errors if no credentials exist.
|
||||
pub async fn load(config: &AcmeConfig) -> Result<Self> {
|
||||
let data = credentials::load_secret(
|
||||
config.account_key_credential.as_deref(),
|
||||
config.account_key_path.as_deref(),
|
||||
)
|
||||
.await;
|
||||
.await?;
|
||||
|
||||
match cred_data {
|
||||
Ok(data) => {
|
||||
let creds: AccountCredentials = serde_json::from_slice(&data).map_err(|e| {
|
||||
Error::Config(format!("invalid account credentials: {e}"))
|
||||
})?;
|
||||
let account = Account::builder()
|
||||
.map_err(Error::Acme)?
|
||||
.from_credentials(creds)
|
||||
.await?;
|
||||
tracing::info!(id = %account.id(), "loaded existing ACME account");
|
||||
Ok(Self { account })
|
||||
let creds: AccountCredentials = serde_json::from_slice(&data).map_err(|e| {
|
||||
Error::Config(format!("invalid account credentials: {e}"))
|
||||
})?;
|
||||
let account = Account::builder()
|
||||
.map_err(Error::Acme)?
|
||||
.from_credentials(creds)
|
||||
.await?;
|
||||
tracing::info!(id = %account.id(), "loaded existing ACME account");
|
||||
Ok(Self { account })
|
||||
}
|
||||
|
||||
/// Create a new ACME account and save credentials.
|
||||
pub async fn create(config: &AcmeConfig) -> Result<Self> {
|
||||
tracing::info!(directory = %config.directory_url, "creating new ACME account");
|
||||
let (account, creds) = Account::builder()
|
||||
.map_err(Error::Acme)?
|
||||
.create(
|
||||
&NewAccount {
|
||||
contact: &config
|
||||
.contact
|
||||
.iter()
|
||||
.map(|s| s.as_str())
|
||||
.collect::<Vec<_>>(),
|
||||
terms_of_service_agreed: true,
|
||||
only_return_existing: false,
|
||||
},
|
||||
config.directory_url.clone(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
tracing::info!(id = %account.id(), "created new ACME account");
|
||||
|
||||
let creds_json = serde_json::to_vec(&creds)
|
||||
.map_err(|e| Error::Config(format!("failed to serialize credentials: {e}")))?;
|
||||
|
||||
if let Some(cred_path) = &config.account_key_credential {
|
||||
credentials::encrypt_credential(&creds_json, cred_path)
|
||||
.await?;
|
||||
tracing::info!(path = %cred_path.display(), "saved account credentials (encrypted)");
|
||||
} else if let Some(file_path) = &config.account_key_path {
|
||||
if let Some(parent) = file_path.parent() {
|
||||
std::fs::create_dir_all(parent)?;
|
||||
}
|
||||
Err(_) => {
|
||||
tracing::info!(directory = %config.directory_url, "creating new ACME account");
|
||||
let (account, creds) = Account::builder()
|
||||
.map_err(Error::Acme)?
|
||||
.create(
|
||||
&NewAccount {
|
||||
contact: &config
|
||||
.contact
|
||||
.iter()
|
||||
.map(|s| s.as_str())
|
||||
.collect::<Vec<_>>(),
|
||||
terms_of_service_agreed: true,
|
||||
only_return_existing: false,
|
||||
},
|
||||
config.directory_url.clone(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
tracing::info!(id = %account.id(), "created new ACME account");
|
||||
|
||||
let creds_json = serde_json::to_vec(&creds)
|
||||
.map_err(|e| Error::Config(format!("failed to serialize credentials: {e}")))?;
|
||||
|
||||
if let Some(cred_path) = &config.account_key_credential {
|
||||
credentials::encrypt_credential(&creds_json, cred_path)
|
||||
.await?;
|
||||
tracing::info!(path = %cred_path.display(), "saved account credentials (encrypted)");
|
||||
} else if let Some(file_path) = &config.account_key_path {
|
||||
if let Some(parent) = file_path.parent() {
|
||||
std::fs::create_dir_all(parent)?;
|
||||
}
|
||||
std::fs::write(file_path, &creds_json)?;
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
std::fs::set_permissions(
|
||||
file_path,
|
||||
std::fs::Permissions::from_mode(0o600),
|
||||
)?;
|
||||
}
|
||||
tracing::info!(path = %file_path.display(), "saved account credentials");
|
||||
}
|
||||
|
||||
Ok(Self { account })
|
||||
std::fs::write(file_path, &creds_json)?;
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
std::fs::set_permissions(
|
||||
file_path,
|
||||
std::fs::Permissions::from_mode(0o600),
|
||||
)?;
|
||||
}
|
||||
tracing::info!(path = %file_path.display(), "saved account credentials");
|
||||
}
|
||||
|
||||
Ok(Self { account })
|
||||
}
|
||||
|
||||
/// Create a new ACME order for the given domains/IPs.
|
||||
|
||||
+2
-2
@@ -82,11 +82,11 @@ async fn main() -> anyhow::Result<()> {
|
||||
let config = config::Config::load(&cli.config)?;
|
||||
match action {
|
||||
AccountAction::Create => {
|
||||
let client = acme::AcmeClient::new(&config.acme).await?;
|
||||
let client = acme::AcmeClient::create(&config.acme).await?;
|
||||
println!("Account ID: {}", client.account().id());
|
||||
}
|
||||
AccountAction::Show => {
|
||||
let client = acme::AcmeClient::new(&config.acme).await?;
|
||||
let client = acme::AcmeClient::load(&config.acme).await?;
|
||||
println!("Account ID: {}", client.account().id());
|
||||
}
|
||||
AccountAction::Deactivate => {
|
||||
|
||||
Reference in New Issue
Block a user