Skip to content

Commit

Permalink
Merge remote-tracking branch 'github/letsencrypt/master' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
kuba committed Oct 4, 2015
2 parents 3c08b51 + 74b2e3b commit 4ef7a6e
Show file tree
Hide file tree
Showing 39 changed files with 411 additions and 178 deletions.
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ load-plugins=linter_plugin
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=fixme,locally-disabled,abstract-class-not-used,bad-continuation,too-few-public-methods,no-self-use
disable=fixme,locally-disabled,abstract-class-not-used,bad-continuation,too-few-public-methods,no-self-use,invalid-name
# abstract-class-not-used cannot be disabled locally (at least in pylint 1.4.1)


Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,5 @@ RUN virtualenv --no-site-packages -p python2 /opt/letsencrypt/venv && \
# bash" and investigate, apply patches, etc.

ENV PATH /opt/letsencrypt/venv/bin:$PATH
# TODO: is --text really necessary?
ENTRYPOINT [ "letsencrypt", "--text" ]

ENTRYPOINT [ "letsencrypt" ]
4 changes: 2 additions & 2 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Let's Encrypt:
Copyright (c) Internet Security Research Group
Let's Encrypt Python Client
Copyright (c) Electronic Frontier Foundation and others
Licensed Apache Version 2.0

Incorporating code from nginxparser
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Current Features
* web servers supported:

- apache/2.x (tested and working on Ubuntu Linux)
- nginx/0.8.48+ (tested and mostly working on Ubuntu Linux)
- nginx/0.8.48+ (under development)
- standalone (runs its own webserver to prove you control the domain)

* the private key is generated locally on your system
Expand Down
36 changes: 35 additions & 1 deletion acme/acme/challenges.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ class Challenge(jose.TypedJSONObjectWithFields):
"""ACME challenge."""
TYPES = {}

@classmethod
def from_json(cls, jobj):
try:
return super(Challenge, cls).from_json(jobj)
except jose.UnrecognizedTypeError as error:
logger.debug(error)
return UnrecognizedChallenge.from_json(jobj)


class ContinuityChallenge(Challenge): # pylint: disable=abstract-method
"""Client validation challenges."""
Expand All @@ -42,6 +50,32 @@ class ChallengeResponse(jose.TypedJSONObjectWithFields):
resource = fields.Resource(resource_type)


class UnrecognizedChallenge(Challenge):
"""Unrecognized challenge.
ACME specification defines a generic framework for challenges and
defines some standard challenges that are implemented in this
module. However, other implementations (including peers) might
define additional challenge types, which should be ignored if
unrecognized.
:ivar jobj: Original JSON decoded object.
"""

def __init__(self, jobj):
super(UnrecognizedChallenge, self).__init__()
object.__setattr__(self, "jobj", jobj)

def to_partial_json(self):
# pylint: disable=no-member
return self.jobj

@classmethod
def from_json(cls, jobj):
return cls(jobj)


@Challenge.register
class SimpleHTTP(DVChallenge):
"""ACME "simpleHttp" challenge.
Expand Down Expand Up @@ -542,7 +576,7 @@ def gen_validation(self, account_key, alg=jose.RS256, **kwargs):
def check_validation(self, validation, account_public_key):
"""Check validation.
:param validation
:param JWS validation:
:type account_public_key:
`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`
or
Expand Down
26 changes: 26 additions & 0 deletions acme/acme/challenges_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,32 @@
KEY = test_util.load_rsa_private_key('rsa512_key.pem')


class ChallengeTest(unittest.TestCase):

def test_from_json_unrecognized(self):
from acme.challenges import Challenge
from acme.challenges import UnrecognizedChallenge
chall = UnrecognizedChallenge({"type": "foo"})
# pylint: disable=no-member
self.assertEqual(chall, Challenge.from_json(chall.jobj))


class UnrecognizedChallengeTest(unittest.TestCase):

def setUp(self):
from acme.challenges import UnrecognizedChallenge
self.jobj = {"type": "foo"}
self.chall = UnrecognizedChallenge(self.jobj)

def test_to_partial_json(self):
self.assertEqual(self.jobj, self.chall.to_partial_json())

def test_from_json(self):
from acme.challenges import UnrecognizedChallenge
self.assertEqual(
self.chall, UnrecognizedChallenge.from_json(self.jobj))


class SimpleHTTPTest(unittest.TestCase):

def setUp(self):
Expand Down
1 change: 1 addition & 0 deletions acme/acme/messages_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ class AuthorizationTest(unittest.TestCase):
def setUp(self):
from acme.messages import ChallengeBody
from acme.messages import STATUS_VALID

self.challbs = (
ChallengeBody(
uri='http://challb1', status=STATUS_VALID,
Expand Down
6 changes: 0 additions & 6 deletions docs/api/display.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,3 @@

.. automodule:: letsencrypt.display.enhancements
:members:

:mod:`letsencrypt.display.revocation`
=====================================

.. automodule:: letsencrypt.display.revocation
:members:
5 changes: 0 additions & 5 deletions docs/api/recovery_token.rst

This file was deleted.

5 changes: 0 additions & 5 deletions docs/api/revoker.rst

This file was deleted.

8 changes: 7 additions & 1 deletion letsencrypt-apache/letsencrypt_apache/configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ def prepare(self):
:raises .errors.PluginError: If there is any other error
"""
# Verify Apache is installed
for exe in (self.conf("ctl"), self.conf("enmod"),
self.conf("dismod"), self.conf("init-script")):
if not le_util.exe_exists(exe):
raise errors.NoInstallationError

# Make sure configuration is valid
self.config_test()

Expand Down Expand Up @@ -1162,7 +1168,7 @@ def _get_mod_deps(mod_name):
changes.
.. warning:: If all deps are not included, it may cause incorrect parsing
behavior, due to enable_mod's shortcut for updating the parser's
currently defined modules (:method:`.ApacheConfigurator._add_parser_mod`)
currently defined modules (`.ApacheConfigurator._add_parser_mod`)
This would only present a major problem in extremely atypical
configs that use ifmod for the missing deps.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,16 @@ def tearDown(self):
shutil.rmtree(self.config_dir)
shutil.rmtree(self.work_dir)

@mock.patch("letsencrypt_apache.configurator.le_util.exe_exists")
def test_prepare_no_install(self, mock_exe_exists):
mock_exe_exists.return_value = False
self.assertRaises(
errors.NoInstallationError, self.config.prepare)

@mock.patch("letsencrypt_apache.parser.ApacheParser")
def test_prepare_version(self, _):
@mock.patch("letsencrypt_apache.configurator.le_util.exe_exists")
def test_prepare_version(self, mock_exe_exists, _):
mock_exe_exists.return_value = True
self.config.version = None
self.config.config_test = mock.Mock()
self.config.get_version = mock.Mock(return_value=(1, 1))
Expand Down
47 changes: 25 additions & 22 deletions letsencrypt-apache/letsencrypt_apache/tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,31 +66,34 @@ def get_apache_configurator(
"""
backups = os.path.join(work_dir, "backups")
mock_le_config = mock.MagicMock(
apache_server_root=config_path,
apache_le_vhost_ext=constants.CLI_DEFAULTS["le_vhost_ext"],
backup_dir=backups,
config_dir=config_dir,
temp_checkpoint_dir=os.path.join(work_dir, "temp_checkpoints"),
in_progress_dir=os.path.join(backups, "IN_PROGRESS"),
work_dir=work_dir)

with mock.patch("letsencrypt_apache.configurator."
"subprocess.Popen") as mock_popen:
with mock.patch("letsencrypt_apache.parser.ApacheParser."
"update_runtime_variables"):
# This indicates config_test passes
mock_popen().communicate.return_value = ("Fine output", "No problems")
mock_popen().returncode = 0

config = configurator.ApacheConfigurator(
config=mock.MagicMock(
apache_server_root=config_path,
apache_le_vhost_ext=constants.CLI_DEFAULTS["le_vhost_ext"],
backup_dir=backups,
config_dir=config_dir,
temp_checkpoint_dir=os.path.join(work_dir, "temp_checkpoints"),
in_progress_dir=os.path.join(backups, "IN_PROGRESS"),
work_dir=work_dir),
name="apache",
version=version)
# This allows testing scripts to set it a bit more quickly
if conf is not None:
config.conf = conf # pragma: no cover

config.prepare()
# This indicates config_test passes
mock_popen().communicate.return_value = ("Fine output", "No problems")
mock_popen().returncode = 0
with mock.patch("letsencrypt_apache.configurator.le_util."
"exe_exists") as mock_exe_exists:
mock_exe_exists.return_value = True
with mock.patch("letsencrypt_apache.parser.ApacheParser."
"update_runtime_variables"):
config = configurator.ApacheConfigurator(
config=mock_le_config,
name="apache",
version=version)
# This allows testing scripts to set it a bit more quickly
if conf is not None:
config.conf = conf # pragma: no cover

config.prepare()

return config

Expand Down
2 changes: 1 addition & 1 deletion letsencrypt-nginx/letsencrypt_nginx/configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class NginxConfigurator(common.Plugin):
zope.interface.implements(interfaces.IAuthenticator, interfaces.IInstaller)
zope.interface.classProvides(interfaces.IPluginFactory)

description = "Nginx Web Server"
description = "Nginx Web Server - currently doesn't work"

@classmethod
def add_parser_arguments(cls, add):
Expand Down
6 changes: 3 additions & 3 deletions letsencrypt/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def __init__(self, regr, key, meta=None):
tz=pytz.UTC).replace(microsecond=0),
creation_host=socket.getfqdn()) if meta is None else meta

self.id = hashlib.md5( # pylint: disable=invalid-name
self.id = hashlib.md5(
self.key.key.public_key().public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
Expand Down Expand Up @@ -92,13 +92,13 @@ def report_new_account(acc, config):
"contain certificates and private keys obtained by Let's Encrypt "
"so making regular backups of this folder is ideal.".format(
config.config_dir),
reporter.MEDIUM_PRIORITY, True)
reporter.MEDIUM_PRIORITY)

if acc.regr.body.emails:
recovery_msg = ("If you lose your account credentials, you can "
"recover through e-mails sent to {0}.".format(
", ".join(acc.regr.body.emails)))
reporter.add_message(recovery_msg, reporter.HIGH_PRIORITY, True)
reporter.add_message(recovery_msg, reporter.HIGH_PRIORITY)


class AccountMemoryStorage(interfaces.AccountStorage):
Expand Down
2 changes: 1 addition & 1 deletion letsencrypt/auth_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ def _report_failed_challs(failed_achalls):
reporter = zope.component.getUtility(interfaces.IReporter)
for achalls in problems.itervalues():
reporter.add_message(
_generate_failed_chall_msg(achalls), reporter.MEDIUM_PRIORITY, True)
_generate_failed_chall_msg(achalls), reporter.MEDIUM_PRIORITY)


def _generate_failed_chall_msg(failed_achalls):
Expand Down
Loading

0 comments on commit 4ef7a6e

Please sign in to comment.