Merge branch 'boulder' of https://github.com/kuba/lets-encrypt-preview into kuba-boulder

This commit is contained in:
James Kasten 2015-04-30 17:57:19 -07:00
commit 84fd90841c
8 changed files with 49 additions and 30 deletions

View file

@ -18,7 +18,7 @@ class Error(jose.JSONObjectWithFields, Exception):
'badCSR': 'The CSR is unacceptable (e.g., due to a short key)',
}
# TODO: Boulder omits 'type' and 'instance', spec requires
# TODO: Boulder omits 'type' and 'instance', spec requires, boulder#128
typ = jose.Field('type', omitempty=True)
title = jose.Field('title', omitempty=True)
detail = jose.Field('detail')
@ -164,8 +164,8 @@ class ChallengeBody(ResourceBody):
.. 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
as well as `.achallenges.AnnotatedChallenge`. Please use names
such as ``challb`` to distinguish instances of this class from
``achall``.
:ivar letsencrypt.acme.challenges.Challenge: Wrapped challenge.

View file

@ -35,7 +35,7 @@ class Account(object):
# Just make sure we don't get pwned
# Make sure that it also doesn't start with a period or have two consecutive
# periods <- this needs to be done in addition to the regex
EMAIL_REGEX = "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+$"
EMAIL_REGEX = re.compile("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+$")
def __init__(self, config, key, email=None, phone=None, regr=None):
le_util.make_or_verify_dir(
@ -55,6 +55,8 @@ class Account(object):
"""URI link for new registrations."""
if self.regr is not None:
return self.regr.uri
else:
return None
@property
def new_authzr_uri(self): # pylint: disable=missing-docstring
@ -65,16 +67,22 @@ class Account(object):
# Default: spec says they "may" provide the header
# ugh.. acme-spec #93
return "https://%s/acme/new-authz" % self.config.server
else:
return None
@property
def terms_of_service(self): # pylint: disable=missing-docstring
if self.regr is not None:
return self.regr.terms_of_service
else:
return None
@property
def recovery_token(self): # pylint: disable=missing-docstring
if self.regr is not None and self.regr.body is not None:
return self.regr.body.recovery_token
else:
return None
def save(self):
"""Save account to disk."""
@ -112,7 +120,6 @@ class Account(object):
@classmethod
def from_existing_account(cls, config, email=None):
"""Populate an account from an existing email."""
config_fp = os.path.join(
config.accounts_dir, cls._get_config_filename(email))
return cls._from_config_fp(config, config_fp)
@ -185,13 +192,14 @@ class Account(object):
"Enter email address (optional, press Enter to skip)")
if code == display_util.OK:
if email == "" or cls.safe_email(email):
email = email if email != "" else None
if not email or cls.safe_email(email):
email = email if email else None
le_util.make_or_verify_dir(
config.account_keys_dir, 0o700, os.geteuid())
key = crypto_util.init_save_key(
config.rsa_key_size, config.account_keys_dir, email)
config.rsa_key_size, config.account_keys_dir,
cls._get_config_filename(email))
return cls(config, key, email)
else:
return None
@ -199,7 +207,8 @@ class Account(object):
@classmethod
def safe_email(cls, email):
"""Scrub email address before using it."""
if re.match(cls.EMAIL_REGEX, email):
return bool(not email.startswith(".") and ".." not in email)
logging.warn("Invalid email address.")
return False
if cls.EMAIL_REGEX.match(email):
return not email.startswith(".") and ".." not in email
else:
logging.warn("Invalid email address.")
return False

View file

@ -165,8 +165,8 @@ class Client(object):
cert_file.write(certr.body.as_pem())
finally:
cert_file.close()
logging.info(
"Server issued certificate; certificate written to %s", cert_path)
logging.info("Server issued certificate; certificate written to %s",
act_cert_path)
if certr.cert_chain_uri:
# TODO: Except

View file

@ -201,13 +201,10 @@ class Network(object):
"""
details = (
"mailto:" + account.email if account.email is not None else None,
"tel:" + account.phone if account.phone is not None else None
"tel:" + account.phone if account.phone is not None else None,
)
contact_tuple = tuple(det for det in details if det is not None)
account.regr = self.register(contact=contact_tuple)
account.regr = self.register(contact=tuple(
det for det in details if det is not None))
return account
def update_registration(self, regr):
@ -323,7 +320,7 @@ class Network(object):
except KeyError:
# TODO: Right now Boulder responds with the authorization resource
# instead of a challenge resource... this can be uncommented
# once the error is fixed.
# once the error is fixed (boulder#130).
return None
# raise errors.NetworkError('"up" Link header missing')
challr = messages2.ChallengeResource(
@ -376,7 +373,6 @@ class Network(object):
updated_authzr = self._authzr_from_response(
response, authzr.body.identifier, authzr.uri, authzr.new_cert_uri)
# TODO: check and raise UnexpectedUpdate
return updated_authzr, response
def request_issuance(self, csr, authzrs):
@ -534,6 +530,8 @@ class Network(object):
"""
if certr.cert_chain_uri is not None:
return self._get_cert(certr.cert_chain_uri)[1]
else:
return None
def revoke(self, certr, when=messages2.Revocation.NOW):
"""Revoke certificate.

View file

@ -64,14 +64,26 @@ class AccountTest(unittest.TestCase):
zope.component.provideUtility(displayer)
mock_util().input.return_value = (display_util.OK, self.email)
mock_key.return_value = self.key
acc = account.Account.from_prompts(self.config)
acc = account.Account.from_prompts(self.config)
self.assertEqual(acc.email, self.email)
self.assertEqual(acc.key, self.key)
self.assertEqual(acc.config, self.config)
@mock.patch("letsencrypt.client.account.zope.component.getUtility")
@mock.patch("letsencrypt.client.account.crypto_util.init_save_key")
def test_prompts_empty_email(self, mock_key, mock_util):
displayer = display_util.FileDisplay(sys.stdout)
zope.component.provideUtility(displayer)
mock_util().input.return_value = (display_util.OK, "")
acc = account.Account.from_prompts(self.config)
self.assertTrue(acc.email is None)
# _get_config_filename | pylint: disable=protected-access
mock_key.assert_called_once_with(
mock.ANY, mock.ANY, acc._get_config_filename(None))
@mock.patch("letsencrypt.client.account.zope.component.getUtility")
def test_prompts_cancel(self, mock_util):
# displayer = display_util.FileDisplay(sys.stdout)
@ -169,7 +181,7 @@ class SafeEmailTest(unittest.TestCase):
addrs = [
"letsencrypt@letsencrypt.org",
"tbd.ade@gmail.com",
"abc_def.jdk@hotmail.museum"
"abc_def.jdk@hotmail.museum",
]
for addr in addrs:
self.assertTrue(self._call(addr), "%s failed." % addr)

View file

@ -75,7 +75,7 @@ def chall_to_challb(chall, status): # pylint: disable=redefined-outer-name
"""Return ChallengeBody from Challenge."""
kwargs = {
"chall": chall,
"uri": chall.typ+"_uri",
"uri": chall.typ + "_uri",
"status": status,
}
@ -129,7 +129,7 @@ def gen_authzr(authz_status, domain, challs, statuses, combos=True):
now = datetime.datetime.now()
authz_kwargs.update({
"status": authz_status,
"expires": datetime.datetime(now.year, now.month+1, now.day),
"expires": datetime.datetime(now.year, now.month + 1, now.day),
})
else:
authz_kwargs.update({

View file

@ -7,10 +7,10 @@ import unittest
import mock
import zope.component
from letsencrypt.client import account
from letsencrypt.client import le_util
from letsencrypt.client.display import util as display_util
class ChooseAuthenticatorTest(unittest.TestCase):
"""Test choose_authenticator function."""
def setUp(self):
@ -59,7 +59,6 @@ class ChooseAuthenticatorTest(unittest.TestCase):
class ChooseAccountTest(unittest.TestCase):
"""Test choose_account."""
def setUp(self):
from letsencrypt.client import account
zope.component.provideUtility(display_util.FileDisplay(sys.stdout))
self.accounts_dir = tempfile.mkdtemp("accounts")

View file

@ -49,7 +49,8 @@ class RecoveryTokenTest(unittest.TestCase):
# SHOULD throw an error (OSError other than nonexistent file)
self.assertRaises(
OSError, self.rec_token.cleanup,
achallenges.RecoveryToken(challb=None, domain="a"+"r"*10000+".com"))
achallenges.RecoveryToken(
challb=None, domain=("a" + "r" * 10000 + ".com")))
def test_perform_stored(self):
self.rec_token.store_token("example4.com", 444)