Skip to content

Commit 227d6a9

Browse files
wouter-bonclaude
andcommitted
fix: resolve ACME library compatibility issues
- Fix account registration for existing accounts (ConflictError handling) - Fix poll() return type handling (tuple vs single value) - Remove unused crypto_util.load_pem_private_key call - Fix datetime timezone handling in certificate info 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 0476785 commit 227d6a9

2 files changed

Lines changed: 23 additions & 7 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,4 @@ fortigate_mcp.log
197197
config/config.yaml
198198
config/local_config.yaml
199199
config/config.json
200+
secret.txt

src/fortigate_mcp/core/acme_client.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import os
33
import time
44
from typing import Optional, Tuple, Callable
5-
from datetime import datetime, timedelta
5+
from datetime import datetime, timedelta, timezone
66
from cryptography import x509
77
from cryptography.x509.oid import NameOID
88
from cryptography.hazmat.primitives import hashes, serialization
@@ -103,6 +103,8 @@ def register_account(self) -> messages.RegistrationResource:
103103

104104
self.logger.info(f"Registering ACME account for {self.email}")
105105

106+
from acme import errors as acme_errors
107+
106108
try:
107109
# Try to create new registration
108110
registration = acme_client.new_account(
@@ -112,9 +114,15 @@ def register_account(self) -> messages.RegistrationResource:
112114
)
113115
)
114116
self.logger.info("Created new ACME account")
115-
except Exception as e:
116-
# Account might already exist
117-
self.logger.info(f"Account may already exist: {e}")
117+
except acme_errors.ConflictError as e:
118+
# Account already exists - use only_return_existing
119+
self.logger.info(f"Account already exists at {e}, retrieving...")
120+
# Set the account URI on the network client
121+
acme_client.net.account = messages.RegistrationResource(
122+
uri=str(e),
123+
body=messages.Registration()
124+
)
125+
# Query with only_return_existing
118126
registration = acme_client.new_account(
119127
messages.NewRegistration.from_data(
120128
email=self.email,
@@ -123,6 +131,9 @@ def register_account(self) -> messages.RegistrationResource:
123131
)
124132
)
125133
self.logger.info("Retrieved existing ACME account")
134+
except Exception as e:
135+
self.logger.error(f"Account registration failed: {e}")
136+
raise
126137

127138
self._registration = registration
128139
return registration
@@ -222,7 +233,6 @@ def request_certificate(
222233
private_key_pem, csr_pem = self.generate_csr(domains, key_type, key_size)
223234

224235
# Request new order
225-
csr = crypto_util.load_pem_private_key(private_key_pem)
226236
order = acme_client.new_order(csr_pem)
227237

228238
self.logger.info(f"Created order with {len(order.authorizations)} authorizations")
@@ -265,7 +275,12 @@ def request_certificate(
265275
# Wait for validation
266276
start_time = time.time()
267277
while time.time() - start_time < timeout:
268-
authz_resource = acme_client.poll(authz)
278+
poll_result = acme_client.poll(authz)
279+
# Handle both old (single) and new (tuple) return formats
280+
if isinstance(poll_result, tuple):
281+
authz_resource = poll_result[0]
282+
else:
283+
authz_resource = poll_result
269284
if authz_resource.body.status == messages.STATUS_VALID:
270285
self.logger.info(f"Authorization valid for {domain}")
271286
break
@@ -318,5 +333,5 @@ def get_certificate_info(self, cert_pem: bytes) -> dict:
318333
"not_valid_before": cert.not_valid_before_utc.isoformat(),
319334
"not_valid_after": cert.not_valid_after_utc.isoformat(),
320335
"domains": sans,
321-
"days_remaining": (cert.not_valid_after_utc - datetime.utcnow()).days
336+
"days_remaining": (cert.not_valid_after_utc - datetime.now(timezone.utc)).days
322337
}

0 commit comments

Comments
 (0)