twisted / txacme

@@ -2,7 +2,7 @@
Loading
2 2
3 3
4 4
LETSENCRYPT_DIRECTORY = URL.fromText(
5 -
    u'https://acme-v01.api.letsencrypt.org/directory')
5 +
    u'https://acme-v02.api.letsencrypt.org/directory')
6 6
7 7
8 8
LETSENCRYPT_STAGING_DIRECTORY = URL.fromText(

@@ -166,11 +166,12 @@
Loading
166 166
        agent = Agent(reactor, pool=pool)
167 167
        jws_d = JWSClient.from_directory(agent, key, alg, directory)
168 168
    else:
169 +
        assert 0, "Not supported right now, we need a directory object."
169 170
        jws_d = defer.succeed(jws_client)
170 171
171 -
    def set_timeout(jws_client):
172 -
        jws_client.timeout = timeout
173 -
        return jws_client
172 +
    def set_timeout(jws_client_and_dir):
173 +
        jws_client_and_dir[0].timeout = timeout
174 +
        return jws_client_and_dir
174 175
175 176
    return jws_d.addCallback(set_timeout)
176 177
@@ -220,6 +221,7 @@
Loading
220 221
        self.directory = directory
221 222
        self.key = key
222 223
        self._kid = None
224 +
        print("created client:", vars(self))
223 225
224 226
    @classmethod
225 227
    def from_url(
@@ -251,11 +253,12 @@
Loading
251 253
        with action.context():
252 254
            check_directory_url_type(url)
253 255
            directory = url.asText()
254 -
            jws_client = _default_client(
255 -
                jws_client, reactor, key, alg, directory, timeout
256 -
            )
257 256
            action.add_success_fields(directory=directory)
258 -
            return succeed(cls(reactor, key, jws_client))
257 +
            return DeferredContext(
258 +
                _default_client(jws_client, reactor, key, alg, directory, timeout)
259 +
            ).addCallback(
260 +
                lambda jws_client_and_dir: cls(directory=jws_client_and_dir[1], reactor=reactor, key=key, jws_client=jws_client_and_dir[0])
261 +
            ).addActionFinish()
259 262
260 263
    def start(self, email=None):
261 264
        """
@@ -828,20 +831,20 @@
Loading
828 831
        :param str directory: The URL to the ACME v2 directory.
829 832
830 833
        :return: When operation is done.
831 -
        :rtype: Deferred[None]
834 +
        :rtype: Deferred[Tuple[JWSClient, directory]]
832 835
        """
833 836
        # Provide invalid new_nonce_url & kid, but don't expose it to the
834 837
        # caller.
835 838
        self = cls(agent, key, alg, None, None)
836 839
837 -
        def cb_extract_new_nonce(directory):
840 +
        def cb_extract_new_nonce(messages_dir_object):
841 +
            print("MSGDIR", vars(messages_dir_object))
838 842
            try:
839 -
                self._new_nonce = directory.newNonce
843 +
                self._new_nonce = messages_dir_object.newNonce
840 844
            except AttributeError:
841 845
                raise errors.ClientError(
842 -
                    'Directory has no newNonce URL', directory)
843 -
844 -
            return directory
846 +
                    'Directory has no newNonce URL', messages_dir_object)
847 +
            return self, messages_dir_object
845 848
        return (
846 849
            self.get(directory)
847 850
            .addCallback(json_content)

@@ -34,11 +34,13 @@
Loading
34 34
        manage.
35 35
36 36
    :type client: `txacme.client.Client`
37 -
    :param client: A client which is already set to be used for an
38 -
        environment.  For example, ``Client.from_url(reactor=reactor,
39 -
        url=LETSENCRYPT_STAGING_DIRECTORY, key=acme_key, alg=RS256)``.
40 -
        When the service is stopped, it will automatically call the stop
41 -
        method on the client.
37 +
    :param client: A client, or Deferred of a client, which is already set to
38 +
        be used for an environment; for example,
39 +
        Client.from_url(reactor=reactor, url=LETSENCRYPT_STAGING_DIRECTORY,
40 +
        key=acme_key, alg=RS256).
41 +
42 +
        When the service is stopped, it will automatically call the stop method
43 +
        on the client.
42 44
43 45
    :param clock: ``IReactorTime`` provider; usually the reactor, when not
44 46
        testing.
@@ -82,6 +84,7 @@
Loading
82 84
83 85
    _waiting = attr.ib(default=attr.Factory(list), init=False)
84 86
    _issuing = attr.ib(default=attr.Factory(dict), init=False)
87 +
    _cached_client = attr.ib(default=None)
85 88
    ready = False
86 89
    # Service used to repeatedly call the certificate check and renewal.
87 90
    _timer_service = None
@@ -95,6 +98,29 @@
Loading
95 98
        """
96 99
        return clock_now(self._clock)
97 100
101 +
    def _get_client(self):
102 +
        """
103 +
        Get the client, cache it if it's ready.
104 +
        """
105 +
        if self._cached_client is not None:
106 +
            return defer.succeed(self._cached_client)
107 +
        client_or_d = self._client
108 +
        if isinstance(client_or_d, defer.Deferred):
109 +
            new_d = defer.Deferred()
110 +
            @client_or_d.addCallback
111 +
            def got_client(final_client):
112 +
                self._cached_client = final_client
113 +
                new_d.callback(final_client)
114 +
                return final_client
115 +
            @client_or_d.addErrback
116 +
            def got_client(error):
117 +
                new_d.errback(error)
118 +
                return error
119 +
            return got_client
120 +
        else:
121 +
            self._cached_client = client_or_d
122 +
            return defer.succeed(client_or_d)
123 +
98 124
    def _check_certs(self):
99 125
        """
100 126
        Check all of the certs in the store, and reissue any that are expired
@@ -199,6 +225,7 @@
Loading
199 225
        names = [n.strip() for n in server_names.split(',')]
200 226
        return ','.join(names)
201 227
228 +
    @defer.inlineCallbacks
202 229
    def _issue_cert(self, server_names):
203 230
        """
204 231
        Issue a new cert for the list of server_names.
@@ -212,40 +239,28 @@
Loading
212 239
            server_names=server_names)
213 240
        key = self._generate_key()
214 241
        objects = [
215 -
            pem.Key(key.private_bytes(
216 -
                encoding=serialization.Encoding.PEM,
217 -
                format=serialization.PrivateFormat.TraditionalOpenSSL,
218 -
                encryption_algorithm=serialization.NoEncryption()))]
219 -
220 -
        @defer.inlineCallbacks
221 -
        def answer_to_order(orderr):
222 -
            """
223 -
            Answer the challenges associated with the order.
224 -
            """
225 -
            for authorization in orderr.authorizations:
226 -
                yield answer_challenge(
227 -
                    authorization,
228 -
                    self._client,
229 -
                    self._responders,
230 -
                    clock=self._clock,
231 -
                )
232 -
            certificate = yield get_certificate(
233 -
                orderr, self._client, clock=self._clock)
234 -
            defer.returnValue(certificate)
235 -
236 -
        def got_cert(certr):
237 -
            """
238 -
            Called when we got a certificate.
239 -
            """
240 -
            # The certificate is returned as chain.
241 -
            objects.extend(pem.parse(certr.body))
242 -
            self.cert_store.store(','.join(names), objects)
243 -
244 -
        return (
245 -
            self._client.submit_order(key, names)
246 -
            .addCallback(answer_to_order)
247 -
            .addCallback(got_cert)
242 +
            pem.Key(
243 +
                key.private_bytes(
244 +
                    encoding=serialization.Encoding.PEM,
245 +
                    format=serialization.PrivateFormat.TraditionalOpenSSL,
246 +
                    encryption_algorithm=serialization.NoEncryption())
247 +
            )
248 +
        ]
249 +
        client = yield self._get_client()
250 +
        orderr = yield client.submit_order(key, names)
251 +
        for authorization in orderr.authorizations:
252 +
            yield answer_challenge(
253 +
                authorization,
254 +
                client,
255 +
                self._responders,
256 +
                clock=self._clock,
248 257
            )
258 +
        certificate = yield get_certificate(
259 +
            orderr, client, clock=self._clock)
260 +
        # The certificate is returned as chain.
261 +
        objects.extend(pem.parse(certr.body))
262 +
        self.cert_store.store(','.join(names), objects)
263 +
        return certificate
249 264
250 265
    def when_certs_valid(self):
251 266
        """
@@ -268,6 +283,7 @@
Loading
268 283
        self._waiting.append(d)
269 284
        return d
270 285
286 +
    @defer.inlineCallbacks
271 287
    def start(self):
272 288
        """
273 289
        Like startService, but will return a deferred once the service was
@@ -275,16 +291,13 @@
Loading
275 291
        """
276 292
        Service.startService(self)
277 293
278 -
        def cb_start(result):
279 -
            """
280 -
            Called when the client is ready for operation.
281 -
            """
282 -
            self._timer_service = TimerService(
283 -
                self.check_interval.total_seconds(), self._check_certs)
284 -
            self._timer_service.clock = self._clock
285 -
            self._timer_service.startService()
286 -
287 -
        return self._client.start(email=self._email).addCallback(cb_start)
294 +
        client = yield self._get_client()
295 +
        result = yield client.start(email=self._email)
296 +
        self._timer_service = TimerService(
297 +
            self.check_interval.total_seconds(), self._check_certs
298 +
        )
299 +
        self._timer_service.clock = self._clock
300 +
        self._timer_service.startService()
288 301
289 302
    def startService(self):
290 303
        """
@@ -295,26 +308,21 @@
Loading
295 308
        """
296 309
        self.start().addErrback(self._panic, 'FAIL-TO-START')
297 310
311 +
    @defer.inlineCallbacks
298 312
    def stopService(self):
299 313
        Service.stopService(self)
300 314
        self.ready = False
301 315
        for d in list(self._waiting):
302 316
            d.cancel()
303 317
        self._waiting = []
304 -
305 -
        def stop_timer(ignored):
306 -
            if not self._timer_service:
307 -
                return
308 -
            return self._timer_service.stopService()
309 -
310 -
        def cleanup(ignored):
311 -
            self._timer_service = None
312 -
313 -
        return (
314 -
            self._client.stop()
315 -
            .addBoth(tap(stop_timer))
316 -
            .addBoth(tap(cleanup))
317 -
            )
318 +
        client = yield self._get_client()
319 +
320 +
        result = yield self._client.stop()
321 +
        if not self._timer_service:
322 +
            return result
323 +
        yield self._timer_service.stopService()
324 +
        self._timer_service = None
325 +
        return result
318 326
319 327
320 328
__all__ = ['AcmeIssuingService']
Files Coverage
src/txacme 70.80%
Project Totals (27 files) 70.80%
lnx-3.7-py37
Build #1042283646 -
lnx-3.8-py38
Build #1042283646 -
lnx-3.9-py39
Build #1042283646 -
lnx-3.6-py36
Build #1042283646 -
lnx-pypy-3.7-pypy3
Build #1042283646 -
1
ignore:
2
  - src/txacme/_version.py
3
  - src/txacme/interfaces.py
4

5
status:
6
  project: off
7
  patch: off
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading