certapi 0.2.7__tar.gz → 0.2.9__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-0.2.7 → certapi-0.2.9}/PKG-INFO +1 -1
- {certapi-0.2.7 → certapi-0.2.9}/setup.py +1 -1
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/Acme.py +2 -2
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/certauthority.py +8 -7
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/crypto.py +5 -0
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/db.py +14 -8
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/digitalocean_challenge_store.py +1 -1
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/digitalocean_client.py +5 -6
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi.egg-info/PKG-INFO +1 -1
- {certapi-0.2.7 → certapi-0.2.9}/MANIFEST.in +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/README.md +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/pyproject.toml +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/setup.cfg +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/__init__.py +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/challenge.py +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/cloudflare_challenge_store.py +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/cloudflare_client.py +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/crypto_classes.py +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/custom_certauthority.py +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi/util.py +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi.egg-info/SOURCES.txt +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi.egg-info/dependency_links.txt +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi.egg-info/requires.txt +0 -0
- {certapi-0.2.7 → certapi-0.2.9}/src/certapi.egg-info/top_level.txt +0 -0
|
@@ -127,7 +127,7 @@ class AcmeHttpError(AcmeError, requests.HTTPError):
|
|
|
127
127
|
else:
|
|
128
128
|
message = err_detail
|
|
129
129
|
else:
|
|
130
|
-
message=error
|
|
130
|
+
message = error
|
|
131
131
|
|
|
132
132
|
if message is None:
|
|
133
133
|
if res_json.get("detail"):
|
|
@@ -345,7 +345,7 @@ class Order:
|
|
|
345
345
|
self._data["certificate"], step="Get Certificate from Successful Order"
|
|
346
346
|
)
|
|
347
347
|
certificate = crypto.x509.load_pem_x509_certificates(certificate_res.content)
|
|
348
|
-
return (
|
|
348
|
+
return (certificate_res.content, certificate)
|
|
349
349
|
|
|
350
350
|
def finalize(self, csr: CertificateSigningRequest):
|
|
351
351
|
"""
|
|
@@ -17,7 +17,7 @@ from requests import Response
|
|
|
17
17
|
from . import Acme, Challenge, Order
|
|
18
18
|
from . import crypto
|
|
19
19
|
from . import challenge
|
|
20
|
-
from .crypto import cert_to_pem, key_to_pem, digest_sha256
|
|
20
|
+
from .crypto import cert_to_pem, certs_to_pem, key_to_pem, digest_sha256
|
|
21
21
|
from .crypto_classes import Key
|
|
22
22
|
from .db import KeyStore
|
|
23
23
|
from .util import b64_string
|
|
@@ -121,9 +121,9 @@ class CertAuthority:
|
|
|
121
121
|
order.refresh() # is this refresh necessary?
|
|
122
122
|
|
|
123
123
|
if order.status == "valid":
|
|
124
|
-
fullchain_cert,certificate =
|
|
124
|
+
fullchain_cert, certificate = order.get_certificate()
|
|
125
125
|
key_id = self.key_store.save_key(private_key, missing[0])
|
|
126
|
-
cert_id = self.key_store.save_cert(key_id,
|
|
126
|
+
cert_id = self.key_store.save_cert(key_id, fullchain_cert, missing)
|
|
127
127
|
issued_cert = IssuedCert(key_to_pem(private_key), fullchain_cert, missing)
|
|
128
128
|
# Clean up challenges after successful certificate issuance
|
|
129
129
|
for c in challenges:
|
|
@@ -145,7 +145,9 @@ class CertAuthority:
|
|
|
145
145
|
return createExistingResponse(existing, [])
|
|
146
146
|
|
|
147
147
|
|
|
148
|
-
def createExistingResponse(
|
|
148
|
+
def createExistingResponse(
|
|
149
|
+
existing: Dict[str, Tuple[int | str, Key, List[Certificate] | str]], issued_certs: List["IssuedCert"]
|
|
150
|
+
):
|
|
149
151
|
certs = []
|
|
150
152
|
certMap = {}
|
|
151
153
|
|
|
@@ -159,7 +161,7 @@ def createExistingResponse(existing: Dict[str, Tuple[int | str, Key, List[Certif
|
|
|
159
161
|
cert_pem = certs_to_pem(cert).decode("utf-8")
|
|
160
162
|
else:
|
|
161
163
|
cert_pem = cert_to_pem(cert).decode("utf-8")
|
|
162
|
-
|
|
164
|
+
|
|
163
165
|
certMap[id] = (
|
|
164
166
|
[h],
|
|
165
167
|
key.to_pem().decode("utf-8"),
|
|
@@ -172,7 +174,6 @@ def createExistingResponse(existing: Dict[str, Tuple[int | str, Key, List[Certif
|
|
|
172
174
|
return CertificateResponse(certs, issued_certs)
|
|
173
175
|
|
|
174
176
|
|
|
175
|
-
|
|
176
177
|
class CertificateResponse:
|
|
177
178
|
def __init__(self, existing, issued):
|
|
178
179
|
self.existing: List[IssuedCert] = existing
|
|
@@ -200,7 +201,7 @@ class IssuedCert:
|
|
|
200
201
|
key = key.to_pem().decode("utf-8")
|
|
201
202
|
elif isinstance(key, bytes):
|
|
202
203
|
key = key.decode("utf-8")
|
|
203
|
-
|
|
204
|
+
|
|
204
205
|
if isinstance(cert, list):
|
|
205
206
|
cert = certs_to_pem(cert).decode("utf-8")
|
|
206
207
|
elif isinstance(cert, Certificate):
|
|
@@ -106,18 +106,23 @@ def key_from_pem(data: bytes):
|
|
|
106
106
|
def cert_from_pem(data: bytes) -> Certificate:
|
|
107
107
|
return x509.load_pem_x509_certificate(data)
|
|
108
108
|
|
|
109
|
+
|
|
109
110
|
def certs_from_pem(data: bytes) -> List[Certificate]:
|
|
110
111
|
return x509.load_pem_x509_certificates(data)
|
|
111
112
|
|
|
113
|
+
|
|
112
114
|
def cert_to_der(cert):
|
|
113
115
|
return cert.public_bytes(serialization.Encoding.DER)
|
|
114
116
|
|
|
117
|
+
|
|
115
118
|
def cert_to_pem(cert):
|
|
116
119
|
return cert.public_bytes(serialization.Encoding.PEM)
|
|
117
120
|
|
|
121
|
+
|
|
118
122
|
def certs_to_pem(certs: List[Certificate]) -> bytes:
|
|
119
123
|
return b"".join([cert_to_pem(cert) for cert in certs])
|
|
120
124
|
|
|
125
|
+
|
|
121
126
|
def cert_from_der(data: bytes) -> Certificate:
|
|
122
127
|
return x509.load_der_x509_certificate(data)
|
|
123
128
|
|
|
@@ -21,7 +21,9 @@ class KeyStore(ABC):
|
|
|
21
21
|
pass
|
|
22
22
|
|
|
23
23
|
@abstractmethod
|
|
24
|
-
def save_cert(
|
|
24
|
+
def save_cert(
|
|
25
|
+
self, private_key_id: int, cert: Certificate | str | List[Certificate], domains: List[str], name: str = None
|
|
26
|
+
) -> int:
|
|
25
27
|
pass
|
|
26
28
|
|
|
27
29
|
@abstractmethod
|
|
@@ -91,10 +93,12 @@ class SqliteKeyStore(KeyStore):
|
|
|
91
93
|
self.save_key(key, name)
|
|
92
94
|
return key
|
|
93
95
|
|
|
94
|
-
def save_cert(
|
|
96
|
+
def save_cert(
|
|
97
|
+
self, private_key_id: int, cert: Certificate | str | List[Certificate], domains: List[str], name: str = None
|
|
98
|
+
) -> int:
|
|
95
99
|
conn = self._get_db_connection()
|
|
96
100
|
cur = conn.cursor()
|
|
97
|
-
|
|
101
|
+
|
|
98
102
|
if isinstance(cert, list):
|
|
99
103
|
cert_data = certs_to_pem(cert)
|
|
100
104
|
elif isinstance(cert, str):
|
|
@@ -133,7 +137,7 @@ class SqliteKeyStore(KeyStore):
|
|
|
133
137
|
|
|
134
138
|
if res is None:
|
|
135
139
|
return None
|
|
136
|
-
|
|
140
|
+
|
|
137
141
|
certs = certs_from_pem(res[2])
|
|
138
142
|
return (res[0], Key.from_der(res[1]), certs)
|
|
139
143
|
|
|
@@ -194,8 +198,9 @@ class FilesystemKeyStore(KeyStore):
|
|
|
194
198
|
return certs_from_pem(cert_data)
|
|
195
199
|
return None
|
|
196
200
|
|
|
197
|
-
|
|
198
|
-
|
|
201
|
+
def save_cert(
|
|
202
|
+
self, private_key_id: str, cert: Certificate | str | List[Certificate], domains: list, name: str = None
|
|
203
|
+
) -> int:
|
|
199
204
|
if isinstance(cert, list):
|
|
200
205
|
cert_pem = certs_to_pem(cert)
|
|
201
206
|
elif isinstance(cert, str):
|
|
@@ -226,7 +231,6 @@ class FilesystemKeyStore(KeyStore):
|
|
|
226
231
|
with open(domain_cert_path, "wb") as f:
|
|
227
232
|
f.write(cert_pem)
|
|
228
233
|
|
|
229
|
-
|
|
230
234
|
return name if name else domains[0] # Dummy ID since filesystem does not use numeric IDs
|
|
231
235
|
|
|
232
236
|
def get_cert(self, name: str) -> None | Tuple[str, Key, List[Certificate]]:
|
|
@@ -343,7 +347,9 @@ class PostgresKeyStore(KeyStore):
|
|
|
343
347
|
self.save_key(key, name)
|
|
344
348
|
return key
|
|
345
349
|
|
|
346
|
-
def save_cert(
|
|
350
|
+
def save_cert(
|
|
351
|
+
self, private_key_id: int, cert: Certificate | str | List[Certificate], domains: List[str], name: str = None
|
|
352
|
+
) -> int:
|
|
347
353
|
"""Saves a certificate along with associated domains."""
|
|
348
354
|
with self.get_connection() as conn:
|
|
349
355
|
if isinstance(cert, list):
|
|
@@ -34,7 +34,7 @@ class DigitalOceanChallengeStore(ChallengeStore):
|
|
|
34
34
|
records = self.digitalocean.list_records(base_domain, name_filter=key)
|
|
35
35
|
for record in records:
|
|
36
36
|
if record["name"] == key:
|
|
37
|
-
return record["data"]
|
|
37
|
+
return record["data"] # DigitalOcean API returns 'data' for TXT record content
|
|
38
38
|
return None # Return None if not found, as per ChallengeStore's __getitem__ behavior
|
|
39
39
|
|
|
40
40
|
def delete_challenge(self, key: str, domain: str):
|
|
@@ -4,10 +4,9 @@ from os import getenv
|
|
|
4
4
|
from urllib.request import urlopen, Request # Python 3
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
|
|
8
7
|
class DigitalOcean(object):
|
|
9
|
-
def __init__(self,api_key=None):
|
|
10
|
-
self.token=api_key
|
|
8
|
+
def __init__(self, api_key=None):
|
|
9
|
+
self.token = api_key
|
|
11
10
|
self.api = "https://api.digitalocean.com/v2/domains"
|
|
12
11
|
if not self.token:
|
|
13
12
|
self.token = getenv("DIGITALOCEAN_API_TOKEN")
|
|
@@ -75,12 +74,12 @@ class DigitalOcean(object):
|
|
|
75
74
|
response = urlopen(Request(api, headers=request_headers))
|
|
76
75
|
if response.getcode() != 200:
|
|
77
76
|
raise Exception(json.loads(response.read().decode("utf8")))
|
|
78
|
-
|
|
77
|
+
|
|
79
78
|
all_records = json.loads(response.read().decode("utf8"))["domain_records"]
|
|
80
|
-
|
|
79
|
+
|
|
81
80
|
if name_filter:
|
|
82
81
|
filtered_records = [r for r in all_records if r["name"] == name_filter and r["type"] == "TXT"]
|
|
83
82
|
else:
|
|
84
83
|
filtered_records = [r for r in all_records if r["type"] == "TXT"]
|
|
85
|
-
|
|
84
|
+
|
|
86
85
|
return filtered_records
|
|
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
|