certapi 1.1.2__tar.gz → 1.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {certapi-1.1.2/src/certapi.egg-info → certapi-1.1.3}/PKG-INFO +1 -1
- {certapi-1.1.2 → certapi-1.1.3}/setup.py +1 -1
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/client/cert_manager_client.py +4 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/manager/acme_cert_manager.py +13 -1
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/server/api.py +16 -7
- {certapi-1.1.2 → certapi-1.1.3/src/certapi.egg-info}/PKG-INFO +1 -1
- {certapi-1.1.2 → certapi-1.1.3}/tests/test_acme_cert_manager_batching.py +34 -0
- {certapi-1.1.2 → certapi-1.1.3}/tests/test_obtain_interface.py +65 -0
- {certapi-1.1.2 → certapi-1.1.3}/MANIFEST.in +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/README.md +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/pyproject.toml +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/setup.cfg +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/acme/Acme.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/acme/AcmeError.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/acme/Challenge.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/acme/Order.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/acme/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/acme/http.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/ChallengeSolver.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/FileSystemChallengeSolver.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/InmemoryChallengeSolver.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/dns/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/dns/cloudflare/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/dns/cloudflare/cloudflare_challenge_solver.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/dns/cloudflare/cloudflare_client.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/dns/digitalocean/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/dns/digitalocean/digitalocean_challenge_solver.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/dns/digitalocean/digitalocean_client.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/cli.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/client/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/client/renewal_manager.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/crypto/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/crypto/crypto.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/crypto/crypto_classes.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/domain_batching.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/errors.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/http/HttpClientBase.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/http/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/http/types.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/issuers/AcmeCertIssuer.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/issuers/SelfCertIssuer.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/issuers/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/issuers/abstract_certissuer.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/keystore/FileSystemKeyStore.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/keystore/KeyStore.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/keystore/PostgresqlKeyStore.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/keystore/RemoteKeyStore.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/keystore/SqliteKeyStore.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/keystore/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/manager/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/server/__init__.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/server/cert_api.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/server/key_api.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/util.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi/utils.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi.egg-info/SOURCES.txt +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi.egg-info/dependency_links.txt +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi.egg-info/entry_points.txt +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi.egg-info/requires.txt +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/src/certapi.egg-info/top_level.txt +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/tests/test_acme_error_handling.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/tests/test_cert_issuer_generic.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/tests/test_certs_with_key_types.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/tests/test_cli.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/tests/test_domain_batching_boulder_cases.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/tests/test_http_error_handling.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/tests/test_keystores.py +0 -0
- {certapi-1.1.2 → certapi-1.1.3}/tests/test_renewal_manager.py +0 -0
|
@@ -50,6 +50,7 @@ class CertManagerClient:
|
|
|
50
50
|
renew_threshold_days: Optional[int] = None,
|
|
51
51
|
skip_failing: bool = True,
|
|
52
52
|
batch_domains: bool = False,
|
|
53
|
+
self_verify: bool = True,
|
|
53
54
|
) -> CertificateResponse:
|
|
54
55
|
return self.obtain(
|
|
55
56
|
hosts=hosts,
|
|
@@ -63,6 +64,7 @@ class CertManagerClient:
|
|
|
63
64
|
renew_threshold_days=renew_threshold_days,
|
|
64
65
|
skip_failing=skip_failing,
|
|
65
66
|
batch_domains=batch_domains,
|
|
67
|
+
self_verify=self_verify,
|
|
66
68
|
)
|
|
67
69
|
|
|
68
70
|
def obtain(
|
|
@@ -78,6 +80,7 @@ class CertManagerClient:
|
|
|
78
80
|
renew_threshold_days: Optional[int] = None,
|
|
79
81
|
skip_failing: bool = True,
|
|
80
82
|
batch_domains: bool = False,
|
|
83
|
+
self_verify: bool = True,
|
|
81
84
|
) -> CertificateResponse:
|
|
82
85
|
params = {
|
|
83
86
|
"hostname": hosts if isinstance(hosts, str) else hosts,
|
|
@@ -98,6 +101,7 @@ class CertManagerClient:
|
|
|
98
101
|
params["renew_threshold_days"] = renew_threshold_days
|
|
99
102
|
params["skip_failing"] = skip_failing
|
|
100
103
|
params["batch_domains"] = batch_domains
|
|
104
|
+
params["self_verify"] = self_verify
|
|
101
105
|
|
|
102
106
|
data = self._get("/api/obtain", params=params)
|
|
103
107
|
res = CertificateResponse.from_json(data)
|
|
@@ -75,6 +75,7 @@ class AcmeCertManager:
|
|
|
75
75
|
organization: Optional[str] = None,
|
|
76
76
|
user_id: Optional[str] = None,
|
|
77
77
|
renew_threshold_days: Optional[int] = None,
|
|
78
|
+
self_verify: bool = True,
|
|
78
79
|
) -> CertificateResponse:
|
|
79
80
|
return self.obtain(
|
|
80
81
|
hosts=hosts,
|
|
@@ -86,6 +87,7 @@ class AcmeCertManager:
|
|
|
86
87
|
organization=organization,
|
|
87
88
|
user_id=user_id,
|
|
88
89
|
renew_threshold_days=renew_threshold_days,
|
|
90
|
+
self_verify=self_verify,
|
|
89
91
|
)
|
|
90
92
|
|
|
91
93
|
def obtain(
|
|
@@ -99,6 +101,7 @@ class AcmeCertManager:
|
|
|
99
101
|
organization: Optional[str] = None,
|
|
100
102
|
user_id: Optional[str] = None,
|
|
101
103
|
renew_threshold_days: Optional[int] = None,
|
|
104
|
+
self_verify: bool = True,
|
|
102
105
|
) -> CertificateResponse:
|
|
103
106
|
return self._issue_certificate_internal(
|
|
104
107
|
hosts=hosts,
|
|
@@ -111,6 +114,7 @@ class AcmeCertManager:
|
|
|
111
114
|
user_id=user_id,
|
|
112
115
|
renew_threshold_days=renew_threshold_days,
|
|
113
116
|
batch_generator=None,
|
|
117
|
+
self_verify=self_verify,
|
|
114
118
|
)
|
|
115
119
|
|
|
116
120
|
def issue_certificate_in_batches(
|
|
@@ -125,6 +129,7 @@ class AcmeCertManager:
|
|
|
125
129
|
user_id: Optional[str] = None,
|
|
126
130
|
renew_threshold_days: Optional[int] = None,
|
|
127
131
|
batch_generator: Callable[[List[str]], List[List[str]]] = create_safe_domain_batches,
|
|
132
|
+
self_verify: bool = True,
|
|
128
133
|
) -> CertificateResponse:
|
|
129
134
|
return self._issue_certificate_internal(
|
|
130
135
|
hosts=hosts,
|
|
@@ -137,6 +142,7 @@ class AcmeCertManager:
|
|
|
137
142
|
user_id=user_id,
|
|
138
143
|
renew_threshold_days=renew_threshold_days,
|
|
139
144
|
batch_generator=batch_generator,
|
|
145
|
+
self_verify=self_verify,
|
|
140
146
|
)
|
|
141
147
|
|
|
142
148
|
def _issue_certificate_internal(
|
|
@@ -151,6 +157,7 @@ class AcmeCertManager:
|
|
|
151
157
|
user_id: Optional[str] = None,
|
|
152
158
|
renew_threshold_days: Optional[int] = None,
|
|
153
159
|
batch_generator: Optional[Callable[[List[str]], List[List[str]]]] = None,
|
|
160
|
+
self_verify: bool = True,
|
|
154
161
|
) -> CertificateResponse:
|
|
155
162
|
if isinstance(hosts, str):
|
|
156
163
|
hosts = [hosts]
|
|
@@ -174,7 +181,12 @@ class AcmeCertManager:
|
|
|
174
181
|
for host in missing:
|
|
175
182
|
found_store = None
|
|
176
183
|
for store in self.challenge_solvers:
|
|
177
|
-
|
|
184
|
+
supports_domain = (
|
|
185
|
+
store.supports_domain_strict(host)
|
|
186
|
+
if self_verify and hasattr(store, "supports_domain_strict")
|
|
187
|
+
else store.supports_domain(host)
|
|
188
|
+
)
|
|
189
|
+
if supports_domain:
|
|
178
190
|
found_store = store
|
|
179
191
|
break
|
|
180
192
|
if found_store is not None:
|
|
@@ -103,6 +103,12 @@ def create_api_resources(api_ns, cert_manager: AcmeCertManager, renew_queue_size
|
|
|
103
103
|
default=False,
|
|
104
104
|
help="Issue certificates in separate safe batches instead of one combined order",
|
|
105
105
|
)
|
|
106
|
+
obtain_parser.add_argument(
|
|
107
|
+
"self_verify",
|
|
108
|
+
type=inputs.boolean,
|
|
109
|
+
default=True,
|
|
110
|
+
help="Verify local challenge reachability/ownership before attempting issuance",
|
|
111
|
+
)
|
|
106
112
|
|
|
107
113
|
@api_ns.route("/obtain")
|
|
108
114
|
class ObtainCert(Resource):
|
|
@@ -117,16 +123,18 @@ def create_api_resources(api_ns, cert_manager: AcmeCertManager, renew_queue_size
|
|
|
117
123
|
args = obtain_parser.parse_args()
|
|
118
124
|
hostnames = args["hostname"]
|
|
119
125
|
skip_failing = args.get("skip_failing", False)
|
|
126
|
+
self_verify = args.get("self_verify", True)
|
|
120
127
|
|
|
121
128
|
with lock_manager:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
129
|
+
if self_verify:
|
|
130
|
+
verified_hostnames = []
|
|
131
|
+
for h in hostnames:
|
|
132
|
+
# Find the first solver that supports and can verify this domain.
|
|
133
|
+
for solver in reversed(cert_manager.challenge_solvers):
|
|
134
|
+
if solver.supports_domain_strict(h):
|
|
135
|
+
verified_hostnames.append(h)
|
|
128
136
|
|
|
129
|
-
|
|
137
|
+
hostnames = verified_hostnames
|
|
130
138
|
|
|
131
139
|
if not hostnames and not skip_failing:
|
|
132
140
|
api_ns.abort(400, message="None of the domains are owned by this machine or could be verified")
|
|
@@ -149,6 +157,7 @@ def create_api_resources(api_ns, cert_manager: AcmeCertManager, renew_queue_size
|
|
|
149
157
|
organization=args["organization"],
|
|
150
158
|
user_id=args["user_id"],
|
|
151
159
|
renew_threshold_days=args.get("renew_threshold_days"),
|
|
160
|
+
self_verify=False,
|
|
152
161
|
)
|
|
153
162
|
|
|
154
163
|
print(data)
|
|
@@ -22,6 +22,9 @@ class DummySolver:
|
|
|
22
22
|
def supports_domain(self, _domain):
|
|
23
23
|
return True
|
|
24
24
|
|
|
25
|
+
def supports_domain_strict(self, _domain):
|
|
26
|
+
return True
|
|
27
|
+
|
|
25
28
|
|
|
26
29
|
class DummyIssuer:
|
|
27
30
|
def __init__(self):
|
|
@@ -93,3 +96,34 @@ def test_issue_certificate_in_batches_uses_custom_batch_generator():
|
|
|
93
96
|
]
|
|
94
97
|
assert len(response.issued) == 3
|
|
95
98
|
assert [issued.domains for issued in response.issued] == issuer.calls
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_issue_certificate_self_verify_false_skips_strict_solver_check():
|
|
102
|
+
class StrictFailingSolver(DummySolver):
|
|
103
|
+
def supports_domain_strict(self, _domain):
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
key_store = DummyKeyStore()
|
|
107
|
+
issuer = DummyIssuer()
|
|
108
|
+
solver = StrictFailingSolver()
|
|
109
|
+
manager = AcmeCertManager(key_store=key_store, cert_issuer=issuer, challenge_solvers=[solver])
|
|
110
|
+
|
|
111
|
+
manager.issue_certificate(hosts=["force.example.com"], self_verify=False)
|
|
112
|
+
|
|
113
|
+
assert issuer.calls == [["force.example.com"]]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def test_issue_certificate_self_verify_true_uses_strict_solver_check():
|
|
117
|
+
class StrictFailingSolver(DummySolver):
|
|
118
|
+
def supports_domain_strict(self, _domain):
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
key_store = DummyKeyStore()
|
|
122
|
+
issuer = DummyIssuer()
|
|
123
|
+
solver = StrictFailingSolver()
|
|
124
|
+
manager = AcmeCertManager(key_store=key_store, cert_issuer=issuer, challenge_solvers=[solver])
|
|
125
|
+
|
|
126
|
+
response = manager.issue_certificate(hosts=["force.example.com"])
|
|
127
|
+
|
|
128
|
+
assert issuer.calls == []
|
|
129
|
+
assert response.issued == []
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
from unittest.mock import Mock
|
|
2
2
|
|
|
3
|
+
from flask import Flask
|
|
4
|
+
from flask_restx import Api, Namespace
|
|
5
|
+
|
|
3
6
|
from certapi.client.cert_manager_client import CertManagerClient
|
|
4
7
|
from certapi.http.types import CertificateResponse
|
|
5
8
|
from certapi.manager.acme_cert_manager import AcmeCertManager
|
|
9
|
+
from certapi.server.api import create_api_resources
|
|
6
10
|
|
|
7
11
|
|
|
8
12
|
def test_acme_cert_manager_issue_certificate_delegates_to_obtain(monkeypatch):
|
|
@@ -25,6 +29,7 @@ def test_acme_cert_manager_issue_certificate_delegates_to_obtain(monkeypatch):
|
|
|
25
29
|
organization="Org",
|
|
26
30
|
user_id="u1",
|
|
27
31
|
renew_threshold_days=25,
|
|
32
|
+
self_verify=False,
|
|
28
33
|
)
|
|
29
34
|
|
|
30
35
|
assert res is expected
|
|
@@ -37,6 +42,7 @@ def test_acme_cert_manager_issue_certificate_delegates_to_obtain(monkeypatch):
|
|
|
37
42
|
assert captured["organization"] == "Org"
|
|
38
43
|
assert captured["user_id"] == "u1"
|
|
39
44
|
assert captured["renew_threshold_days"] == 25
|
|
45
|
+
assert captured["self_verify"] is False
|
|
40
46
|
|
|
41
47
|
|
|
42
48
|
def test_acme_cert_manager_obtain_uses_internal_issue_path(monkeypatch):
|
|
@@ -54,6 +60,7 @@ def test_acme_cert_manager_obtain_uses_internal_issue_path(monkeypatch):
|
|
|
54
60
|
key_type="ecdsa",
|
|
55
61
|
expiry_days=90,
|
|
56
62
|
renew_threshold_days=30,
|
|
63
|
+
self_verify=False,
|
|
57
64
|
)
|
|
58
65
|
|
|
59
66
|
assert res is expected
|
|
@@ -62,6 +69,7 @@ def test_acme_cert_manager_obtain_uses_internal_issue_path(monkeypatch):
|
|
|
62
69
|
assert captured["expiry_days"] == 90
|
|
63
70
|
assert captured["renew_threshold_days"] == 30
|
|
64
71
|
assert captured["batch_generator"] is None
|
|
72
|
+
assert captured["self_verify"] is False
|
|
65
73
|
|
|
66
74
|
|
|
67
75
|
def test_cert_manager_client_issue_certificate_delegates_to_obtain(monkeypatch):
|
|
@@ -86,6 +94,7 @@ def test_cert_manager_client_issue_certificate_delegates_to_obtain(monkeypatch):
|
|
|
86
94
|
renew_threshold_days=15,
|
|
87
95
|
skip_failing=False,
|
|
88
96
|
batch_domains=True,
|
|
97
|
+
self_verify=False,
|
|
89
98
|
)
|
|
90
99
|
|
|
91
100
|
assert res is expected
|
|
@@ -100,6 +109,7 @@ def test_cert_manager_client_issue_certificate_delegates_to_obtain(monkeypatch):
|
|
|
100
109
|
assert captured["renew_threshold_days"] == 15
|
|
101
110
|
assert captured["skip_failing"] is False
|
|
102
111
|
assert captured["batch_domains"] is True
|
|
112
|
+
assert captured["self_verify"] is False
|
|
103
113
|
|
|
104
114
|
|
|
105
115
|
def test_cert_manager_client_obtain_calls_api_obtain(monkeypatch):
|
|
@@ -118,6 +128,7 @@ def test_cert_manager_client_obtain_calls_api_obtain(monkeypatch):
|
|
|
118
128
|
renew_threshold_days=12,
|
|
119
129
|
skip_failing=False,
|
|
120
130
|
batch_domains=True,
|
|
131
|
+
self_verify=False,
|
|
121
132
|
)
|
|
122
133
|
|
|
123
134
|
assert isinstance(res, CertificateResponse)
|
|
@@ -127,3 +138,57 @@ def test_cert_manager_client_obtain_calls_api_obtain(monkeypatch):
|
|
|
127
138
|
assert captured["params"]["renew_threshold_days"] == 12
|
|
128
139
|
assert captured["params"]["skip_failing"] is False
|
|
129
140
|
assert captured["params"]["batch_domains"] is True
|
|
141
|
+
assert captured["params"]["self_verify"] is False
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def test_remote_obtain_self_verify_false_skips_server_prefilter():
|
|
145
|
+
app = Flask(__name__)
|
|
146
|
+
api = Api(app)
|
|
147
|
+
api_ns = Namespace("api")
|
|
148
|
+
api.add_namespace(api_ns)
|
|
149
|
+
|
|
150
|
+
class Solver:
|
|
151
|
+
def supports_domain_strict(self, _domain):
|
|
152
|
+
return False
|
|
153
|
+
|
|
154
|
+
class Manager:
|
|
155
|
+
challenge_solvers = [Solver()]
|
|
156
|
+
|
|
157
|
+
def __init__(self):
|
|
158
|
+
self.calls = []
|
|
159
|
+
|
|
160
|
+
def issue_certificate(self, hosts, **kwargs):
|
|
161
|
+
self.calls.append({"hosts": hosts, "kwargs": kwargs})
|
|
162
|
+
return CertificateResponse()
|
|
163
|
+
|
|
164
|
+
manager = Manager()
|
|
165
|
+
create_api_resources(api_ns, manager)
|
|
166
|
+
|
|
167
|
+
response = app.test_client().get("/api/obtain?hostname=force.example.com&self_verify=false")
|
|
168
|
+
|
|
169
|
+
assert response.status_code == 200
|
|
170
|
+
assert manager.calls[0]["hosts"] == ["force.example.com"]
|
|
171
|
+
assert manager.calls[0]["kwargs"]["self_verify"] is False
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def test_remote_obtain_self_verify_true_keeps_server_prefilter():
|
|
175
|
+
app = Flask(__name__)
|
|
176
|
+
api = Api(app)
|
|
177
|
+
api_ns = Namespace("api")
|
|
178
|
+
api.add_namespace(api_ns)
|
|
179
|
+
|
|
180
|
+
class Solver:
|
|
181
|
+
def supports_domain_strict(self, _domain):
|
|
182
|
+
return False
|
|
183
|
+
|
|
184
|
+
class Manager:
|
|
185
|
+
challenge_solvers = [Solver()]
|
|
186
|
+
|
|
187
|
+
def issue_certificate(self, hosts, **kwargs):
|
|
188
|
+
raise AssertionError("unverified host should not reach manager")
|
|
189
|
+
|
|
190
|
+
create_api_resources(api_ns, Manager())
|
|
191
|
+
|
|
192
|
+
response = app.test_client().get("/api/obtain?hostname=force.example.com")
|
|
193
|
+
|
|
194
|
+
assert response.status_code == 400
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/dns/cloudflare/cloudflare_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{certapi-1.1.2 → certapi-1.1.3}/src/certapi/challenge_solver/dns/digitalocean/digitalocean_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|