fix: ECC cert support, ACME deploy hook path, NAT detection, and account config fallback
- Add find_cert_dir() to resolve both RSA and ECC (domain_ecc/) cert dirs - Copy acme deploy hook to /deploy/ where acme.sh resolves it - _parse_account_conf checks both legacy .account.conf and declarative config - Skip public DNS check when all local IPs are private (NAT) - Improve check message strings for validity and expiry status - Support timezone-aware date formats in _days_until parsing - Filter out "no" SAN domains in cert listing - Bump frontend asset version cache keys - Fix DOMContentLoaded race condition in app.js boot - Fix spread operator in certs.js modal template
This commit is contained in:
@@ -157,6 +157,39 @@ class TestGetEmail:
|
||||
assert result == "test@example.com"
|
||||
|
||||
|
||||
class TestFindCertDir:
|
||||
def test_rsa_dir(self, tmp_path):
|
||||
rsa_dir = tmp_path / "example.com"
|
||||
rsa_dir.mkdir()
|
||||
result = acme.find_cert_dir("example.com", tmp_path)
|
||||
assert result == rsa_dir
|
||||
|
||||
def test_ecc_dir(self, tmp_path):
|
||||
ecc_dir = tmp_path / "example.com_ecc"
|
||||
ecc_dir.mkdir()
|
||||
result = acme.find_cert_dir("example.com", tmp_path)
|
||||
assert result == ecc_dir
|
||||
|
||||
def test_eccPreferred(self, tmp_path):
|
||||
rsa_dir = tmp_path / "example.com"
|
||||
rsa_dir.mkdir()
|
||||
ecc_dir = tmp_path / "example.com_ecc"
|
||||
ecc_dir.mkdir()
|
||||
result = acme.find_cert_dir("example.com", tmp_path)
|
||||
assert result == ecc_dir
|
||||
|
||||
def test_fallback_when_neither(self, tmp_path):
|
||||
result = acme.find_cert_dir("example.com", tmp_path)
|
||||
assert result == tmp_path / "example.com"
|
||||
|
||||
def test_resolves_ecc_only(self, tmp_path):
|
||||
"""Only _ecc dir exists, no RSA dir — should resolve to _ecc."""
|
||||
ecc_dir = tmp_path / "example.com_ecc"
|
||||
ecc_dir.mkdir()
|
||||
result = acme.find_cert_dir("example.com", tmp_path)
|
||||
assert result == ecc_dir
|
||||
|
||||
|
||||
class TestGetCertPaths:
|
||||
def test_returns_paths(self, tmp_path):
|
||||
with patch.object(acme, "_ACME_HOME", tmp_path / "data" / "acme"):
|
||||
@@ -166,6 +199,18 @@ class TestGetCertPaths:
|
||||
assert paths["ca"].endswith("example.com/ca.cer")
|
||||
assert paths["fullchain"].endswith("example.com/fullchain.cer")
|
||||
|
||||
def test_resolves_ecc_dir(self, tmp_path):
|
||||
acme_dir = tmp_path / "data" / "acme"
|
||||
ecc_dir = acme_dir / "example.com_ecc"
|
||||
ecc_dir.mkdir(parents=True)
|
||||
|
||||
with patch.object(acme, "_ACME_HOME", acme_dir):
|
||||
paths = acme.get_cert_paths("example.com")
|
||||
assert paths["cert"].endswith("example.com_ecc/example.com.cert")
|
||||
assert paths["key"].endswith("example.com_ecc/example.com.key")
|
||||
assert paths["ca"].endswith("example.com_ecc/ca.cer")
|
||||
assert paths["fullchain"].endswith("example.com_ecc/fullchain.cer")
|
||||
|
||||
|
||||
class TestDeployHook:
|
||||
@patch("lib.acme._run_acme")
|
||||
|
||||
@@ -348,10 +348,10 @@ class TestCheckDnsPublic:
|
||||
from unittest.mock import patch
|
||||
|
||||
mock_result = MagicMock(
|
||||
returncode=0, stdout="example.com has address 192.168.1.1"
|
||||
returncode=0, stdout="example.com has address 52.14.150.110"
|
||||
)
|
||||
with (
|
||||
patch("socket.gethostbyname", return_value="192.168.1.1"),
|
||||
patch("daemon.handlers.acme._get_local_ips", return_value={"52.14.150.110"}),
|
||||
patch("subprocess.run", return_value=mock_result),
|
||||
):
|
||||
passed, _ = _check_dns_public("example.com")
|
||||
@@ -362,12 +362,23 @@ class TestCheckDnsPublic:
|
||||
|
||||
mock_result = MagicMock(returncode=1, stdout="NXDOMAIN")
|
||||
with (
|
||||
patch("socket.gethostbyname", return_value="192.168.1.1"),
|
||||
patch("daemon.handlers.acme._get_local_ips", return_value={"8.8.8.8"}),
|
||||
patch("subprocess.run", return_value=mock_result),
|
||||
):
|
||||
passed, _ = _check_dns_public("example.com")
|
||||
assert passed is False
|
||||
|
||||
def test_nat_detected_skips_check(self):
|
||||
from unittest.mock import patch
|
||||
|
||||
with patch(
|
||||
"daemon.handlers.acme._get_local_ips",
|
||||
return_value={"192.168.1.1"},
|
||||
):
|
||||
passed, msg = _check_dns_public("example.com")
|
||||
assert passed is True
|
||||
assert "NAT" in msg
|
||||
|
||||
|
||||
class TestCheckDomainFormat:
|
||||
def test_valid(self):
|
||||
|
||||
Reference in New Issue
Block a user