Revert to ChallengeResource/ChallengeBody/Challenge triplet

This commit is contained in:
Jakub Warmuz
2015-04-14 13:06:08 +00:00
parent 8857cb738b
commit 458a61a177
2 changed files with 34 additions and 39 deletions
+14 -28
View File
@@ -5,20 +5,24 @@ import hashlib
import Crypto.Random import Crypto.Random
from letsencrypt.acme import fields
from letsencrypt.acme import jose from letsencrypt.acme import jose
from letsencrypt.acme import messages2
from letsencrypt.acme import other from letsencrypt.acme import other
# pylint: disable=too-few-public-methods # pylint: disable=too-few-public-methods
class ContinuityChallenge(messages2.Challenge): # pylint: disable=abstract-method class Challenge(jose.TypedJSONObjectWithFields):
# _fields_to_json | pylint: disable=abstract-method
"""ACME challenge."""
TYPES = {}
class ContinuityChallenge(Challenge): # pylint: disable=abstract-method
"""Client validation challenges.""" """Client validation challenges."""
class DVChallenge(messages2.Challenge): # pylint: disable=abstract-method class DVChallenge(Challenge): # pylint: disable=abstract-method
"""Domain validation challenges.""" """Domain validation challenges."""
@@ -37,7 +41,7 @@ class ChallengeResponse(jose.TypedJSONObjectWithFields):
return super(ChallengeResponse, cls).from_json(jobj) return super(ChallengeResponse, cls).from_json(jobj)
@messages2.Challenge.register @Challenge.register
class SimpleHTTPS(DVChallenge): class SimpleHTTPS(DVChallenge):
"""ACME "simpleHttps" challenge.""" """ACME "simpleHttps" challenge."""
typ = "simpleHttps" typ = "simpleHttps"
@@ -65,7 +69,7 @@ class SimpleHTTPSResponse(ChallengeResponse):
return self.URI_TEMPLATE.format(domain=domain, path=self.path) return self.URI_TEMPLATE.format(domain=domain, path=self.path)
@messages2.Challenge.register @Challenge.register
class DVSNI(DVChallenge): class DVSNI(DVChallenge):
"""ACME "dvsni" challenge. """ACME "dvsni" challenge.
@@ -89,9 +93,6 @@ class DVSNI(DVChallenge):
nonce = jose.Field("nonce", encoder=binascii.hexlify, nonce = jose.Field("nonce", encoder=binascii.hexlify,
decoder=functools.partial(functools.partial( decoder=functools.partial(functools.partial(
jose.decode_hex16, size=NONCE_SIZE))) jose.decode_hex16, size=NONCE_SIZE)))
uri = jose.Field('uri')
status = jose.Field('status', decoder=messages2.Status.from_json)
validated = fields.RFC3339Field('validated', omitempty=True)
@property @property
def nonce_domain(self): def nonce_domain(self):
@@ -137,7 +138,7 @@ class DVSNIResponse(ChallengeResponse):
"""Domain name for certificate subjectAltName.""" """Domain name for certificate subjectAltName."""
return self.z(chall) + self.DOMAIN_SUFFIX return self.z(chall) + self.DOMAIN_SUFFIX
@messages2.Challenge.register @Challenge.register
class RecoveryContact(ContinuityChallenge): class RecoveryContact(ContinuityChallenge):
"""ACME "recoveryContact" challenge.""" """ACME "recoveryContact" challenge."""
typ = "recoveryContact" typ = "recoveryContact"
@@ -146,10 +147,6 @@ class RecoveryContact(ContinuityChallenge):
success_url = jose.Field("successURL", omitempty=True) success_url = jose.Field("successURL", omitempty=True)
contact = jose.Field("contact", omitempty=True) contact = jose.Field("contact", omitempty=True)
uri = jose.Field('uri')
status = jose.Field('status', decoder=messages2.Status.from_json)
validated = fields.RFC3339Field('validated', omitempty=True)
@ChallengeResponse.register @ChallengeResponse.register
class RecoveryContactResponse(ChallengeResponse): class RecoveryContactResponse(ChallengeResponse):
@@ -158,15 +155,11 @@ class RecoveryContactResponse(ChallengeResponse):
token = jose.Field("token", omitempty=True) token = jose.Field("token", omitempty=True)
@messages2.Challenge.register @Challenge.register
class RecoveryToken(ContinuityChallenge): class RecoveryToken(ContinuityChallenge):
"""ACME "recoveryToken" challenge.""" """ACME "recoveryToken" challenge."""
typ = "recoveryToken" typ = "recoveryToken"
uri = jose.Field('uri')
status = jose.Field('status', decoder=messages2.Status.from_json)
validated = fields.RFC3339Field('validated', omitempty=True)
@ChallengeResponse.register @ChallengeResponse.register
class RecoveryTokenResponse(ChallengeResponse): class RecoveryTokenResponse(ChallengeResponse):
@@ -175,7 +168,7 @@ class RecoveryTokenResponse(ChallengeResponse):
token = jose.Field("token", omitempty=True) token = jose.Field("token", omitempty=True)
@messages2.Challenge.register @Challenge.register
class ProofOfPossession(ContinuityChallenge): class ProofOfPossession(ContinuityChallenge):
"""ACME "proofOfPossession" challenge. """ACME "proofOfPossession" challenge.
@@ -187,10 +180,6 @@ class ProofOfPossession(ContinuityChallenge):
NONCE_SIZE = 16 NONCE_SIZE = 16
uri = jose.Field('uri')
status = jose.Field('status', decoder=messages2.Status.from_json)
validated = fields.RFC3339Field('validated', omitempty=True)
class Hints(jose.JSONObjectWithFields): class Hints(jose.JSONObjectWithFields):
"""Hints for "proofOfPossession" challenge. """Hints for "proofOfPossession" challenge.
@@ -247,15 +236,12 @@ class ProofOfPossessionResponse(ChallengeResponse):
return self.signature.verify(self.nonce) return self.signature.verify(self.nonce)
@messages2.Challenge.register @Challenge.register
class DNS(DVChallenge): class DNS(DVChallenge):
"""ACME "dns" challenge.""" """ACME "dns" challenge."""
typ = "dns" typ = "dns"
token = jose.Field("token") token = jose.Field("token")
uri = jose.Field('uri')
status = jose.Field('status', decoder=messages2.Status.from_json)
validated = fields.RFC3339Field('validated', omitempty=True)
@ChallengeResponse.register @ChallengeResponse.register
class DNSResponse(ChallengeResponse): class DNSResponse(ChallengeResponse):
+20 -11
View File
@@ -1,4 +1,5 @@
"""ACME protocol v02 messages.""" """ACME protocol v02 messages."""
from letsencrypt.acme import challenges
from letsencrypt.acme import fields from letsencrypt.acme import fields
from letsencrypt.acme import jose from letsencrypt.acme import jose
@@ -110,12 +111,8 @@ class Resource(jose.ImmutableMap):
__slots__ = ('body', 'uri') __slots__ = ('body', 'uri')
class TypedResourceBody(jose.TypedJSONObjectWithFields):
"""ACME Resource Body with type."""
class ResourceBody(jose.JSONObjectWithFields): class ResourceBody(jose.JSONObjectWithFields):
"""ACME Resource Body""" """ACME Resource Body."""
class RegistrationResource(Resource): class RegistrationResource(Resource):
@@ -148,7 +145,7 @@ class Registration(ResourceBody):
class ChallengeResource(Resource, jose.JSONObjectWithFields): class ChallengeResource(Resource, jose.JSONObjectWithFields):
"""Challenge Resource. """Challenge Resource.
:ivar letsencrypt.acme.messages2.Challenge body: :ivar letsencrypt.acme.messages2.ChallengeBody body:
:ivar str authzr_uri: URI found in the 'up' ``Link`` header. :ivar str authzr_uri: URI found in the 'up' ``Link`` header.
""" """
@@ -161,22 +158,34 @@ class ChallengeResource(Resource, jose.JSONObjectWithFields):
return self.body.uri return self.body.uri
class Challenge(TypedResourceBody): class ChallengeBody(ResourceBody):
"""Challenge Resource Body. """Challenge Resource Body.
.. todo::
Confusingly, this has a similar name to `.challenges.Challenge`,
as well as `.achallenges.AnnotateChallenge`. Please use names
such as ``challb`` to distinguish instanced of this class from
``achall``.
:ivar letsencrypt.acme.messages2.Status status: :ivar letsencrypt.acme.messages2.Status status:
:ivar datetime.datetime validated: :ivar datetime.datetime validated:
""" """
TYPES = {} __slots__ = ('chall',)
uri = jose.Field('uri') uri = jose.Field('uri')
status = jose.Field('status', decoder=Status.from_json) status = jose.Field('status', decoder=Status.from_json)
validated = fields.RFC3339Field('validated', omitempty=True) validated = fields.RFC3339Field('validated', omitempty=True)
def to_json(self): def to_json(self):
jobj = super(Challenge, self).to_json() jobj = super(ChallengeBody, self).to_json()
jobj.update(self.chall.to_json())
return jobj return jobj
@classmethod
def fields_from_json(cls, jobj):
jobj_fields = super(ChallengeBody, cls).fields_from_json(jobj)
jobj_fields['chall'] = challenges.Challenge.from_json(jobj)
return jobj_fields
class AuthorizationResource(Resource): class AuthorizationResource(Resource):
@@ -193,7 +202,7 @@ class Authorization(ResourceBody):
"""Authorization Resource Body. """Authorization Resource Body.
:ivar letsencrypt.acme.messages2.Identifier identifier: :ivar letsencrypt.acme.messages2.Identifier identifier:
:ivar list challenges: `list` of `.Challenge` :ivar list challenges: `list` of `.ChallengeBody`
:ivar tuple combinations: Challenge combinations (`tuple` of `tuple` :ivar tuple combinations: Challenge combinations (`tuple` of `tuple`
of `int`, as opposed to `list` of `list` from the spec). of `int`, as opposed to `list` of `list` from the spec).
:ivar letsencrypt.acme.jose.jwk.JWK key: Public key. :ivar letsencrypt.acme.jose.jwk.JWK key: Public key.
@@ -220,7 +229,7 @@ class Authorization(ResourceBody):
@challenges.decoder @challenges.decoder
def challenges(value): # pylint: disable=missing-docstring,no-self-argument def challenges(value): # pylint: disable=missing-docstring,no-self-argument
return tuple(Challenge.from_json(chall) for chall in value) return tuple(ChallengeBody.from_json(chall) for chall in value)
@property @property
def resolved_combinations(self): def resolved_combinations(self):