mirror of
https://github.com/certbot/certbot.git
synced 2026-08-01 18:56:55 +02:00
Merge remote-tracking branch 'upstream/master' into plugin_tests
This commit is contained in:
@@ -5,6 +5,7 @@ build/
|
|||||||
dist/
|
dist/
|
||||||
/venv/
|
/venv/
|
||||||
/venv3/
|
/venv3/
|
||||||
|
/.tox/
|
||||||
letsencrypt.log
|
letsencrypt.log
|
||||||
|
|
||||||
# coverage
|
# coverage
|
||||||
|
|||||||
+3
-12
@@ -7,7 +7,7 @@ import os
|
|||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from acme import interfaces
|
from acme import fields
|
||||||
from acme import jose
|
from acme import jose
|
||||||
from acme import other
|
from acme import other
|
||||||
|
|
||||||
@@ -32,21 +32,12 @@ class DVChallenge(Challenge): # pylint: disable=abstract-method
|
|||||||
"""Domain validation challenges."""
|
"""Domain validation challenges."""
|
||||||
|
|
||||||
|
|
||||||
class ChallengeResponse(interfaces.ClientRequestableResource,
|
class ChallengeResponse(jose.TypedJSONObjectWithFields):
|
||||||
jose.TypedJSONObjectWithFields):
|
|
||||||
# _fields_to_partial_json | pylint: disable=abstract-method
|
# _fields_to_partial_json | pylint: disable=abstract-method
|
||||||
"""ACME challenge response."""
|
"""ACME challenge response."""
|
||||||
TYPES = {}
|
TYPES = {}
|
||||||
resource_type = 'challenge'
|
resource_type = 'challenge'
|
||||||
|
resource = fields.Resource(resource_type)
|
||||||
@classmethod
|
|
||||||
def from_json(cls, jobj):
|
|
||||||
if jobj is None:
|
|
||||||
# if the client chooses not to respond to a given
|
|
||||||
# challenge, then the corresponding entry in the response
|
|
||||||
# array is set to None (null)
|
|
||||||
return None
|
|
||||||
return super(ChallengeResponse, cls).from_json(jobj)
|
|
||||||
|
|
||||||
|
|
||||||
@Challenge.register
|
@Challenge.register
|
||||||
|
|||||||
@@ -16,13 +16,6 @@ CERT = test_util.load_cert('cert.pem')
|
|||||||
KEY = test_util.load_rsa_private_key('rsa512_key.pem')
|
KEY = test_util.load_rsa_private_key('rsa512_key.pem')
|
||||||
|
|
||||||
|
|
||||||
class ChallengeResponseTest(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_from_json_none(self):
|
|
||||||
from acme.challenges import ChallengeResponse
|
|
||||||
self.assertTrue(ChallengeResponse.from_json(None) is None)
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleHTTPTest(unittest.TestCase):
|
class SimpleHTTPTest(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -55,11 +48,13 @@ class SimpleHTTPResponseTest(unittest.TestCase):
|
|||||||
path='6tbIMBC5Anhl5bOlWT5ZFA', tls=False)
|
path='6tbIMBC5Anhl5bOlWT5ZFA', tls=False)
|
||||||
self.msg_https = SimpleHTTPResponse(path='6tbIMBC5Anhl5bOlWT5ZFA')
|
self.msg_https = SimpleHTTPResponse(path='6tbIMBC5Anhl5bOlWT5ZFA')
|
||||||
self.jmsg_http = {
|
self.jmsg_http = {
|
||||||
|
'resource': 'challenge',
|
||||||
'type': 'simpleHttp',
|
'type': 'simpleHttp',
|
||||||
'path': '6tbIMBC5Anhl5bOlWT5ZFA',
|
'path': '6tbIMBC5Anhl5bOlWT5ZFA',
|
||||||
'tls': False,
|
'tls': False,
|
||||||
}
|
}
|
||||||
self.jmsg_https = {
|
self.jmsg_https = {
|
||||||
|
'resource': 'challenge',
|
||||||
'type': 'simpleHttp',
|
'type': 'simpleHttp',
|
||||||
'path': '6tbIMBC5Anhl5bOlWT5ZFA',
|
'path': '6tbIMBC5Anhl5bOlWT5ZFA',
|
||||||
'tls': True,
|
'tls': True,
|
||||||
@@ -191,6 +186,7 @@ class DVSNIResponseTest(unittest.TestCase):
|
|||||||
s=b'\xf5\xd6\xe3\xb2]\xe0L\x0bN\x9cKJ\x14I\xa1K\xa3#\xf9\xa8'
|
s=b'\xf5\xd6\xe3\xb2]\xe0L\x0bN\x9cKJ\x14I\xa1K\xa3#\xf9\xa8'
|
||||||
b'\xcd\x8c7\x0e\x99\x19)\xdc\xb7\xf3\x9bw')
|
b'\xcd\x8c7\x0e\x99\x19)\xdc\xb7\xf3\x9bw')
|
||||||
self.jmsg = {
|
self.jmsg = {
|
||||||
|
'resource': 'challenge',
|
||||||
'type': 'dvsni',
|
'type': 'dvsni',
|
||||||
's': '9dbjsl3gTAtOnEtKFEmhS6Mj-ajNjDcOmRkp3Lfzm3c',
|
's': '9dbjsl3gTAtOnEtKFEmhS6Mj-ajNjDcOmRkp3Lfzm3c',
|
||||||
}
|
}
|
||||||
@@ -264,7 +260,11 @@ class RecoveryContactResponseTest(unittest.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
from acme.challenges import RecoveryContactResponse
|
from acme.challenges import RecoveryContactResponse
|
||||||
self.msg = RecoveryContactResponse(token='23029d88d9e123e')
|
self.msg = RecoveryContactResponse(token='23029d88d9e123e')
|
||||||
self.jmsg = {'type': 'recoveryContact', 'token': '23029d88d9e123e'}
|
self.jmsg = {
|
||||||
|
'resource': 'challenge',
|
||||||
|
'type': 'recoveryContact',
|
||||||
|
'token': '23029d88d9e123e',
|
||||||
|
}
|
||||||
|
|
||||||
def test_to_partial_json(self):
|
def test_to_partial_json(self):
|
||||||
self.assertEqual(self.jmsg, self.msg.to_partial_json())
|
self.assertEqual(self.jmsg, self.msg.to_partial_json())
|
||||||
@@ -312,7 +312,11 @@ class RecoveryTokenResponseTest(unittest.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
from acme.challenges import RecoveryTokenResponse
|
from acme.challenges import RecoveryTokenResponse
|
||||||
self.msg = RecoveryTokenResponse(token='23029d88d9e123e')
|
self.msg = RecoveryTokenResponse(token='23029d88d9e123e')
|
||||||
self.jmsg = {'type': 'recoveryToken', 'token': '23029d88d9e123e'}
|
self.jmsg = {
|
||||||
|
'resource': 'challenge',
|
||||||
|
'type': 'recoveryToken',
|
||||||
|
'token': '23029d88d9e123e'
|
||||||
|
}
|
||||||
|
|
||||||
def test_to_partial_json(self):
|
def test_to_partial_json(self):
|
||||||
self.assertEqual(self.jmsg, self.msg.to_partial_json())
|
self.assertEqual(self.jmsg, self.msg.to_partial_json())
|
||||||
@@ -462,11 +466,13 @@ class ProofOfPossessionResponseTest(unittest.TestCase):
|
|||||||
signature=signature)
|
signature=signature)
|
||||||
|
|
||||||
self.jmsg_to = {
|
self.jmsg_to = {
|
||||||
|
'resource': 'challenge',
|
||||||
'type': 'proofOfPossession',
|
'type': 'proofOfPossession',
|
||||||
'nonce': 'eET5udtV7aoX8Xl8gYiZIA',
|
'nonce': 'eET5udtV7aoX8Xl8gYiZIA',
|
||||||
'signature': signature,
|
'signature': signature,
|
||||||
}
|
}
|
||||||
self.jmsg_from = {
|
self.jmsg_from = {
|
||||||
|
'resource': 'challenge',
|
||||||
'type': 'proofOfPossession',
|
'type': 'proofOfPossession',
|
||||||
'nonce': 'eET5udtV7aoX8Xl8gYiZIA',
|
'nonce': 'eET5udtV7aoX8Xl8gYiZIA',
|
||||||
'signature': signature.to_json(),
|
'signature': signature.to_json(),
|
||||||
@@ -512,7 +518,10 @@ class DNSResponseTest(unittest.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
from acme.challenges import DNSResponse
|
from acme.challenges import DNSResponse
|
||||||
self.msg = DNSResponse()
|
self.msg = DNSResponse()
|
||||||
self.jmsg = {'type': 'dns'}
|
self.jmsg = {
|
||||||
|
'resource': 'challenge',
|
||||||
|
'type': 'dns',
|
||||||
|
}
|
||||||
|
|
||||||
def test_to_partial_json(self):
|
def test_to_partial_json(self):
|
||||||
self.assertEqual(self.jmsg, self.msg.to_partial_json())
|
self.assertEqual(self.jmsg, self.msg.to_partial_json())
|
||||||
|
|||||||
+10
-12
@@ -1,7 +1,6 @@
|
|||||||
"""ACME client API."""
|
"""ACME client API."""
|
||||||
import datetime
|
import datetime
|
||||||
import heapq
|
import heapq
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -71,8 +70,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
|||||||
def register(self, new_reg=None):
|
def register(self, new_reg=None):
|
||||||
"""Register.
|
"""Register.
|
||||||
|
|
||||||
:param contact: Contact list, as accepted by `.Registration`
|
:param .NewRegistration new_reg:
|
||||||
:type contact: `tuple`
|
|
||||||
|
|
||||||
:returns: Registration Resource.
|
:returns: Registration Resource.
|
||||||
:rtype: `.RegistrationResource`
|
:rtype: `.RegistrationResource`
|
||||||
@@ -80,7 +78,8 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
|||||||
:raises .UnexpectedUpdate:
|
:raises .UnexpectedUpdate:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
new_reg = messages.Registration() if new_reg is None else new_reg
|
new_reg = messages.NewRegistration() if new_reg is None else new_reg
|
||||||
|
assert isinstance(new_reg, messages.NewRegistration)
|
||||||
|
|
||||||
response = self.net.post(self.new_reg_uri, new_reg)
|
response = self.net.post(self.new_reg_uri, new_reg)
|
||||||
# TODO: handle errors
|
# TODO: handle errors
|
||||||
@@ -105,7 +104,8 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
|||||||
:rtype: `.RegistrationResource`
|
:rtype: `.RegistrationResource`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
response = self.net.post(regr.uri, regr.body)
|
response = self.net.post(
|
||||||
|
regr.uri, messages.UpdateRegistration(**dict(regr.body)))
|
||||||
|
|
||||||
# TODO: Boulder returns httplib.ACCEPTED
|
# TODO: Boulder returns httplib.ACCEPTED
|
||||||
#assert response.status_code == httplib.OK
|
#assert response.status_code == httplib.OK
|
||||||
@@ -164,7 +164,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
|||||||
:rtype: `.AuthorizationResource`
|
:rtype: `.AuthorizationResource`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
new_authz = messages.Authorization(identifier=identifier)
|
new_authz = messages.NewAuthorization(identifier=identifier)
|
||||||
response = self.net.post(new_authzr_uri, new_authz)
|
response = self.net.post(new_authzr_uri, new_authz)
|
||||||
# TODO: handle errors
|
# TODO: handle errors
|
||||||
assert response.status_code == http_client.CREATED
|
assert response.status_code == http_client.CREATED
|
||||||
@@ -451,17 +451,15 @@ class ClientNetwork(object):
|
|||||||
|
|
||||||
.. todo:: Implement ``acmePath``.
|
.. todo:: Implement ``acmePath``.
|
||||||
|
|
||||||
:param .ClientRequestableResource obj:
|
:param .JSONDeSerializable obj:
|
||||||
:param bytes nonce:
|
:param bytes nonce:
|
||||||
:rtype: `.JWS`
|
:rtype: `.JWS`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
jobj = obj.to_json()
|
jobj = obj.json_dumps().encode()
|
||||||
jobj['resource'] = obj.resource_type
|
logger.debug('Serialized JSON: %s', jobj)
|
||||||
dumps = json.dumps(jobj).encode()
|
|
||||||
logger.debug('Serialized JSON: %s', dumps)
|
|
||||||
return jws.JWS.sign(
|
return jws.JWS.sign(
|
||||||
payload=dumps, key=self.key, alg=self.alg, nonce=nonce).json_dumps()
|
payload=jobj, key=self.key, alg=self.alg, nonce=nonce).json_dumps()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _check_response(cls, response, content_type=None):
|
def _check_response(cls, response, content_type=None):
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class ClientTest(unittest.TestCase):
|
|||||||
self.contact = ('mailto:cert-admin@example.com', 'tel:+12025551212')
|
self.contact = ('mailto:cert-admin@example.com', 'tel:+12025551212')
|
||||||
reg = messages.Registration(
|
reg = messages.Registration(
|
||||||
contact=self.contact, key=KEY.public_key(), recovery_token='t')
|
contact=self.contact, key=KEY.public_key(), recovery_token='t')
|
||||||
|
self.new_reg = messages.NewRegistration(**dict(reg))
|
||||||
self.regr = messages.RegistrationResource(
|
self.regr = messages.RegistrationResource(
|
||||||
body=reg, uri='https://www.letsencrypt-demo.org/acme/reg/1',
|
body=reg, uri='https://www.letsencrypt-demo.org/acme/reg/1',
|
||||||
new_authzr_uri='https://www.letsencrypt-demo.org/acme/new-reg',
|
new_authzr_uri='https://www.letsencrypt-demo.org/acme/new-reg',
|
||||||
@@ -82,19 +83,19 @@ class ClientTest(unittest.TestCase):
|
|||||||
'terms-of-service': {'url': self.regr.terms_of_service},
|
'terms-of-service': {'url': self.regr.terms_of_service},
|
||||||
})
|
})
|
||||||
|
|
||||||
self.assertEqual(self.regr, self.client.register(self.regr.body))
|
self.assertEqual(self.regr, self.client.register(self.new_reg))
|
||||||
# TODO: test POST call arguments
|
# TODO: test POST call arguments
|
||||||
|
|
||||||
# TODO: split here and separate test
|
# TODO: split here and separate test
|
||||||
reg_wrong_key = self.regr.body.update(key=KEY2.public_key())
|
reg_wrong_key = self.regr.body.update(key=KEY2.public_key())
|
||||||
self.response.json.return_value = reg_wrong_key.to_json()
|
self.response.json.return_value = reg_wrong_key.to_json()
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
errors.UnexpectedUpdate, self.client.register, self.regr.body)
|
errors.UnexpectedUpdate, self.client.register, self.new_reg)
|
||||||
|
|
||||||
def test_register_missing_next(self):
|
def test_register_missing_next(self):
|
||||||
self.response.status_code = http_client.CREATED
|
self.response.status_code = http_client.CREATED
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
errors.ClientError, self.client.register, self.regr.body)
|
errors.ClientError, self.client.register, self.new_reg)
|
||||||
|
|
||||||
def test_update_registration(self):
|
def test_update_registration(self):
|
||||||
# "Instance of 'Field' has no to_json/update member" bug:
|
# "Instance of 'Field' has no to_json/update member" bug:
|
||||||
@@ -102,6 +103,7 @@ class ClientTest(unittest.TestCase):
|
|||||||
self.response.headers['Location'] = self.regr.uri
|
self.response.headers['Location'] = self.regr.uri
|
||||||
self.response.json.return_value = self.regr.body.to_json()
|
self.response.json.return_value = self.regr.body.to_json()
|
||||||
self.assertEqual(self.regr, self.client.update_registration(self.regr))
|
self.assertEqual(self.regr, self.client.update_registration(self.regr))
|
||||||
|
# TODO: test POST call arguments
|
||||||
|
|
||||||
# TODO: split here and separate test
|
# TODO: split here and separate test
|
||||||
self.response.json.return_value = self.regr.body.update(
|
self.response.json.return_value = self.regr.body.update(
|
||||||
@@ -369,9 +371,8 @@ class ClientNetworkTest(unittest.TestCase):
|
|||||||
self.assertTrue(self.net.verify_ssl is self.verify_ssl)
|
self.assertTrue(self.net.verify_ssl is self.verify_ssl)
|
||||||
|
|
||||||
def test_wrap_in_jws(self):
|
def test_wrap_in_jws(self):
|
||||||
class MockClientRequestableResource(jose.JSONDeSerializable):
|
class MockJSONDeSerializable(jose.JSONDeSerializable):
|
||||||
# pylint: disable=missing-docstring
|
# pylint: disable=missing-docstring
|
||||||
resource_type = 'mock'
|
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = value
|
self.value = value
|
||||||
def to_partial_json(self):
|
def to_partial_json(self):
|
||||||
@@ -381,10 +382,9 @@ class ClientNetworkTest(unittest.TestCase):
|
|||||||
pass # pragma: no cover
|
pass # pragma: no cover
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
jws_dump = self.net._wrap_in_jws(
|
jws_dump = self.net._wrap_in_jws(
|
||||||
MockClientRequestableResource('foo'), nonce=b'Tg')
|
MockJSONDeSerializable('foo'), nonce=b'Tg')
|
||||||
jws = acme_jws.JWS.json_loads(jws_dump)
|
jws = acme_jws.JWS.json_loads(jws_dump)
|
||||||
self.assertEqual(json.loads(jws.payload.decode()),
|
self.assertEqual(json.loads(jws.payload.decode()), {'foo': 'foo'})
|
||||||
{'foo': 'foo', 'resource': 'mock'})
|
|
||||||
self.assertEqual(jws.signature.combined.nonce, b'Tg')
|
self.assertEqual(jws.signature.combined.nonce, b'Tg')
|
||||||
|
|
||||||
def test_check_response_not_ok_jobj_no_error(self):
|
def test_check_response_not_ok_jobj_no_error(self):
|
||||||
|
|||||||
@@ -23,3 +23,21 @@ class RFC3339Field(jose.Field):
|
|||||||
return pyrfc3339.parse(value)
|
return pyrfc3339.parse(value)
|
||||||
except ValueError as error:
|
except ValueError as error:
|
||||||
raise jose.DeserializationError(error)
|
raise jose.DeserializationError(error)
|
||||||
|
|
||||||
|
|
||||||
|
class Resource(jose.Field):
|
||||||
|
"""Resource MITM field."""
|
||||||
|
|
||||||
|
def __init__(self, resource_type, *args, **kwargs):
|
||||||
|
self.resource_type = resource_type
|
||||||
|
super(Resource, self).__init__(
|
||||||
|
# TODO: omitempty used only to trick
|
||||||
|
# JSONObjectWithFieldsMeta._defaults..., server implementation
|
||||||
|
'resource', default=resource_type, *args, **kwargs)
|
||||||
|
|
||||||
|
def decode(self, value):
|
||||||
|
if value != self.resource_type:
|
||||||
|
raise jose.DeserializationError(
|
||||||
|
'Wrong resource type: {0} instead of {1}'.format(
|
||||||
|
value, self.resource_type))
|
||||||
|
return value
|
||||||
|
|||||||
@@ -35,5 +35,19 @@ class RFC3339FieldTest(unittest.TestCase):
|
|||||||
jose.DeserializationError, RFC3339Field.default_decoder, '')
|
jose.DeserializationError, RFC3339Field.default_decoder, '')
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceTest(unittest.TestCase):
|
||||||
|
"""Tests for acme.fields.Resource."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
from acme.fields import Resource
|
||||||
|
self.field = Resource('x')
|
||||||
|
|
||||||
|
def test_decode_good(self):
|
||||||
|
self.assertEqual('x', self.field.decode('x'))
|
||||||
|
|
||||||
|
def test_decode_wrong(self):
|
||||||
|
self.assertRaises(jose.DeserializationError, self.field.decode, 'y')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main() # pragma: no cover
|
unittest.main() # pragma: no cover
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
"""ACME interfaces."""
|
|
||||||
from acme import jose
|
|
||||||
|
|
||||||
|
|
||||||
class ClientRequestableResource(jose.JSONDeSerializable):
|
|
||||||
"""Resource that can be requested by client.
|
|
||||||
|
|
||||||
:ivar unicode resource_type: ACME resource identifier used in client
|
|
||||||
HTTPS requests in order to protect against MITM.
|
|
||||||
|
|
||||||
"""
|
|
||||||
# pylint: disable=abstract-method
|
|
||||||
resource_type = NotImplemented
|
|
||||||
@@ -214,7 +214,7 @@ class JSONObjectWithFields(util.ImmutableMap, interfaces.JSONDeSerializable):
|
|||||||
def _defaults(cls):
|
def _defaults(cls):
|
||||||
"""Get default fields values."""
|
"""Get default fields values."""
|
||||||
return dict([(slot, field.default) for slot, field
|
return dict([(slot, field.default) for slot, field
|
||||||
in six.iteritems(cls._fields) if field.omitempty])
|
in six.iteritems(cls._fields)])
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
# pylint: disable=star-args
|
# pylint: disable=star-args
|
||||||
|
|||||||
+21
-16
@@ -5,7 +5,6 @@ from six.moves.urllib import parse as urllib_parse # pylint: disable=import-err
|
|||||||
|
|
||||||
from acme import challenges
|
from acme import challenges
|
||||||
from acme import fields
|
from acme import fields
|
||||||
from acme import interfaces
|
|
||||||
from acme import jose
|
from acme import jose
|
||||||
|
|
||||||
|
|
||||||
@@ -151,7 +150,7 @@ class ResourceBody(jose.JSONObjectWithFields):
|
|||||||
"""ACME Resource Body."""
|
"""ACME Resource Body."""
|
||||||
|
|
||||||
|
|
||||||
class Registration(interfaces.ClientRequestableResource, ResourceBody):
|
class Registration(ResourceBody):
|
||||||
"""Registration Resource Body.
|
"""Registration Resource Body.
|
||||||
|
|
||||||
:ivar acme.jose.jwk.JWK key: Public key.
|
:ivar acme.jose.jwk.JWK key: Public key.
|
||||||
@@ -161,8 +160,6 @@ class Registration(interfaces.ClientRequestableResource, ResourceBody):
|
|||||||
:ivar unicode agreement:
|
:ivar unicode agreement:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
resource_type = 'new-reg'
|
|
||||||
|
|
||||||
# on new-reg key server ignores 'key' and populates it based on
|
# on new-reg key server ignores 'key' and populates it based on
|
||||||
# JWS.signature.combined.jwk
|
# JWS.signature.combined.jwk
|
||||||
key = jose.Field('key', omitempty=True, decoder=jose.JWK.from_json)
|
key = jose.Field('key', omitempty=True, decoder=jose.JWK.from_json)
|
||||||
@@ -199,9 +196,17 @@ class Registration(interfaces.ClientRequestableResource, ResourceBody):
|
|||||||
"""All emails found in the ``contact`` field."""
|
"""All emails found in the ``contact`` field."""
|
||||||
return self._filter_contact(self.email_prefix)
|
return self._filter_contact(self.email_prefix)
|
||||||
|
|
||||||
|
class NewRegistration(Registration):
|
||||||
|
"""New registration."""
|
||||||
|
resource_type = 'new-reg'
|
||||||
|
resource = fields.Resource(resource_type)
|
||||||
|
|
||||||
class RegistrationResource(interfaces.ClientRequestableResource,
|
class UpdateRegistration(Registration):
|
||||||
ResourceWithURI):
|
"""Update registration."""
|
||||||
|
resource_type = 'reg'
|
||||||
|
resource = fields.Resource(resource_type)
|
||||||
|
|
||||||
|
class RegistrationResource(ResourceWithURI):
|
||||||
"""Registration Resource.
|
"""Registration Resource.
|
||||||
|
|
||||||
:ivar acme.messages.Registration body:
|
:ivar acme.messages.Registration body:
|
||||||
@@ -209,7 +214,6 @@ class RegistrationResource(interfaces.ClientRequestableResource,
|
|||||||
:ivar unicode terms_of_service: URL for the CA TOS.
|
:ivar unicode terms_of_service: URL for the CA TOS.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
resource_type = 'reg'
|
|
||||||
body = jose.Field('body', decoder=Registration.from_json)
|
body = jose.Field('body', decoder=Registration.from_json)
|
||||||
new_authzr_uri = jose.Field('new_authzr_uri')
|
new_authzr_uri = jose.Field('new_authzr_uri')
|
||||||
terms_of_service = jose.Field('terms_of_service', omitempty=True)
|
terms_of_service = jose.Field('terms_of_service', omitempty=True)
|
||||||
@@ -272,7 +276,7 @@ class ChallengeResource(Resource):
|
|||||||
return self.body.uri # pylint: disable=no-member
|
return self.body.uri # pylint: disable=no-member
|
||||||
|
|
||||||
|
|
||||||
class Authorization(interfaces.ClientRequestableResource, ResourceBody):
|
class Authorization(ResourceBody):
|
||||||
"""Authorization Resource Body.
|
"""Authorization Resource Body.
|
||||||
|
|
||||||
:ivar acme.messages.Identifier identifier:
|
:ivar acme.messages.Identifier identifier:
|
||||||
@@ -283,7 +287,6 @@ class Authorization(interfaces.ClientRequestableResource, ResourceBody):
|
|||||||
:ivar datetime.datetime expires:
|
:ivar datetime.datetime expires:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
resource_type = 'new-authz'
|
|
||||||
identifier = jose.Field('identifier', decoder=Identifier.from_json)
|
identifier = jose.Field('identifier', decoder=Identifier.from_json)
|
||||||
challenges = jose.Field('challenges', omitempty=True)
|
challenges = jose.Field('challenges', omitempty=True)
|
||||||
combinations = jose.Field('combinations', omitempty=True)
|
combinations = jose.Field('combinations', omitempty=True)
|
||||||
@@ -305,6 +308,10 @@ class Authorization(interfaces.ClientRequestableResource, ResourceBody):
|
|||||||
return tuple(tuple(self.challenges[idx] for idx in combo)
|
return tuple(tuple(self.challenges[idx] for idx in combo)
|
||||||
for combo in self.combinations)
|
for combo in self.combinations)
|
||||||
|
|
||||||
|
class NewAuthorization(Authorization):
|
||||||
|
"""New authorization."""
|
||||||
|
resource_type = 'new-authz'
|
||||||
|
resource = fields.Resource(resource_type)
|
||||||
|
|
||||||
class AuthorizationResource(ResourceWithURI):
|
class AuthorizationResource(ResourceWithURI):
|
||||||
"""Authorization Resource.
|
"""Authorization Resource.
|
||||||
@@ -317,8 +324,7 @@ class AuthorizationResource(ResourceWithURI):
|
|||||||
new_cert_uri = jose.Field('new_cert_uri')
|
new_cert_uri = jose.Field('new_cert_uri')
|
||||||
|
|
||||||
|
|
||||||
class CertificateRequest(interfaces.ClientRequestableResource,
|
class CertificateRequest(jose.JSONObjectWithFields):
|
||||||
jose.JSONObjectWithFields):
|
|
||||||
"""ACME new-cert request.
|
"""ACME new-cert request.
|
||||||
|
|
||||||
:ivar acme.jose.util.ComparableX509 csr:
|
:ivar acme.jose.util.ComparableX509 csr:
|
||||||
@@ -327,12 +333,12 @@ class CertificateRequest(interfaces.ClientRequestableResource,
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
resource_type = 'new-cert'
|
resource_type = 'new-cert'
|
||||||
|
resource = fields.Resource(resource_type)
|
||||||
csr = jose.Field('csr', decoder=jose.decode_csr, encoder=jose.encode_csr)
|
csr = jose.Field('csr', decoder=jose.decode_csr, encoder=jose.encode_csr)
|
||||||
authorizations = jose.Field('authorizations', decoder=tuple)
|
authorizations = jose.Field('authorizations', decoder=tuple)
|
||||||
|
|
||||||
|
|
||||||
class CertificateResource(interfaces.ClientRequestableResource,
|
class CertificateResource(ResourceWithURI):
|
||||||
ResourceWithURI):
|
|
||||||
"""Certificate Resource.
|
"""Certificate Resource.
|
||||||
|
|
||||||
:ivar acme.jose.util.ComparableX509 body:
|
:ivar acme.jose.util.ComparableX509 body:
|
||||||
@@ -341,13 +347,11 @@ class CertificateResource(interfaces.ClientRequestableResource,
|
|||||||
:ivar tuple authzrs: `tuple` of `AuthorizationResource`.
|
:ivar tuple authzrs: `tuple` of `AuthorizationResource`.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
resource_type = 'cert'
|
|
||||||
cert_chain_uri = jose.Field('cert_chain_uri')
|
cert_chain_uri = jose.Field('cert_chain_uri')
|
||||||
authzrs = jose.Field('authzrs')
|
authzrs = jose.Field('authzrs')
|
||||||
|
|
||||||
|
|
||||||
class Revocation(interfaces.ClientRequestableResource,
|
class Revocation(jose.JSONObjectWithFields):
|
||||||
jose.JSONObjectWithFields):
|
|
||||||
"""Revocation message.
|
"""Revocation message.
|
||||||
|
|
||||||
:ivar .ComparableX509 certificate: `OpenSSL.crypto.X509` wrapped in
|
:ivar .ComparableX509 certificate: `OpenSSL.crypto.X509` wrapped in
|
||||||
@@ -355,6 +359,7 @@ class Revocation(interfaces.ClientRequestableResource,
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
resource_type = 'revoke-cert'
|
resource_type = 'revoke-cert'
|
||||||
|
resource = fields.Resource(resource_type)
|
||||||
certificate = jose.Field(
|
certificate = jose.Field(
|
||||||
'certificate', decoder=jose.decode_cert, encoder=jose.encode_cert)
|
'certificate', decoder=jose.decode_cert, encoder=jose.encode_cert)
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -48,9 +48,9 @@ http {
|
|||||||
|
|
||||||
server {
|
server {
|
||||||
# IPv4.
|
# IPv4.
|
||||||
listen 8080;
|
listen 8081;
|
||||||
# IPv6.
|
# IPv6.
|
||||||
listen [::]:8080 default ipv6only=on;
|
listen [::]:8081 default ipv6only=on;
|
||||||
|
|
||||||
root $root/webroot;
|
root $root/webroot;
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
export PATH="/usr/sbin:$PATH" # /usr/sbin/nginx
|
export PATH="/usr/sbin:$PATH" # /usr/sbin/nginx
|
||||||
nginx_root="$root/nginx"
|
nginx_root="$root/nginx"
|
||||||
mkdir $nginx_root
|
mkdir $nginx_root
|
||||||
root="$nginx_root" ./tests/integration/nginx.conf.sh > $nginx_root/nginx.conf
|
root="$nginx_root" ./letsencrypt-nginx/tests/boulder-integration.conf.sh > $nginx_root/nginx.conf
|
||||||
|
|
||||||
killall nginx || true
|
killall nginx || true
|
||||||
nginx -c $nginx_root/nginx.conf
|
nginx -c $nginx_root/nginx.conf
|
||||||
@@ -88,7 +88,7 @@ def register(config, account_storage, tos_cb=None):
|
|||||||
backend=default_backend())))
|
backend=default_backend())))
|
||||||
acme = _acme_from_config_key(config, key)
|
acme = _acme_from_config_key(config, key)
|
||||||
# TODO: add phone?
|
# TODO: add phone?
|
||||||
regr = acme.register(messages.Registration.from_data(email=config.email))
|
regr = acme.register(messages.NewRegistration.from_data(email=config.email))
|
||||||
|
|
||||||
if regr.terms_of_service is not None:
|
if regr.terms_of_service is not None:
|
||||||
if tos_cb is not None and not tos_cb(regr):
|
if tos_cb is not None and not tos_cb(regr):
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
letsencrypt-apache
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
letsencrypt-nginx/
|
|
||||||
@@ -55,5 +55,5 @@ done
|
|||||||
|
|
||||||
if type nginx;
|
if type nginx;
|
||||||
then
|
then
|
||||||
. ./tests/integration/nginx.sh
|
. ./letsencrypt-nginx/tests/boulder-integration.sh
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user