s/letsencrypt/certbot

This commit is contained in:
Brad Warren
2016-04-13 16:03:59 -07:00
parent 4af2b3e9e8
commit 3961b70deb
102 changed files with 734 additions and 736 deletions
-1
View File
@@ -1 +0,0 @@
"""Let's Encrypt Tests"""
-185
View File
@@ -1,185 +0,0 @@
"""Tests for letsencrypt.account."""
import datetime
import os
import shutil
import stat
import tempfile
import unittest
import mock
import pytz
from acme import jose
from acme import messages
from letsencrypt import errors
from letsencrypt.tests import test_util
KEY = jose.JWKRSA.load(test_util.load_vector("rsa512_key_2.pem"))
class AccountTest(unittest.TestCase):
"""Tests for letsencrypt.account.Account."""
def setUp(self):
from letsencrypt.account import Account
self.regr = mock.MagicMock()
self.meta = Account.Meta(
creation_host="test.letsencrypt.org",
creation_dt=datetime.datetime(
2015, 7, 4, 14, 4, 10, tzinfo=pytz.UTC))
self.acc = Account(self.regr, KEY, self.meta)
with mock.patch("letsencrypt.account.socket") as mock_socket:
mock_socket.getfqdn.return_value = "test.letsencrypt.org"
with mock.patch("letsencrypt.account.datetime") as mock_dt:
mock_dt.datetime.now.return_value = self.meta.creation_dt
self.acc_no_meta = Account(self.regr, KEY)
def test_init(self):
self.assertEqual(self.regr, self.acc.regr)
self.assertEqual(KEY, self.acc.key)
self.assertEqual(self.meta, self.acc_no_meta.meta)
def test_id(self):
self.assertEqual(
self.acc.id, "bca5889f66457d5b62fbba7b25f9ab6f")
def test_slug(self):
self.assertEqual(
self.acc.slug, "test.letsencrypt.org@2015-07-04T14:04:10Z (bca5)")
def test_repr(self):
self.assertEqual(
repr(self.acc),
"<Account(bca5889f66457d5b62fbba7b25f9ab6f)>")
class ReportNewAccountTest(unittest.TestCase):
"""Tests for letsencrypt.account.report_new_account."""
def setUp(self):
self.config = mock.MagicMock(config_dir="/etc/letsencrypt")
reg = messages.Registration.from_data(email="rhino@jungle.io")
self.acc = mock.MagicMock(regr=messages.RegistrationResource(
uri=None, new_authzr_uri=None, body=reg))
def _call(self):
from letsencrypt.account import report_new_account
report_new_account(self.acc, self.config)
@mock.patch("letsencrypt.account.zope.component.queryUtility")
def test_no_reporter(self, mock_zope):
mock_zope.return_value = None
self._call()
@mock.patch("letsencrypt.account.zope.component.queryUtility")
def test_it(self, mock_zope):
self._call()
call_list = mock_zope().add_message.call_args_list
self.assertTrue(self.config.config_dir in call_list[0][0][0])
self.assertTrue(
", ".join(self.acc.regr.body.emails) in call_list[1][0][0])
class AccountMemoryStorageTest(unittest.TestCase):
"""Tests for letsencrypt.account.AccountMemoryStorage."""
def setUp(self):
from letsencrypt.account import AccountMemoryStorage
self.storage = AccountMemoryStorage()
def test_it(self):
account = mock.Mock(id="x")
self.assertEqual([], self.storage.find_all())
self.assertRaises(errors.AccountNotFound, self.storage.load, "x")
self.storage.save(account)
self.assertEqual([account], self.storage.find_all())
self.assertEqual(account, self.storage.load("x"))
self.storage.save(account)
self.assertEqual([account], self.storage.find_all())
class AccountFileStorageTest(unittest.TestCase):
"""Tests for letsencrypt.account.AccountFileStorage."""
def setUp(self):
self.tmp = tempfile.mkdtemp()
self.config = mock.MagicMock(
accounts_dir=os.path.join(self.tmp, "accounts"))
from letsencrypt.account import AccountFileStorage
self.storage = AccountFileStorage(self.config)
from letsencrypt.account import Account
self.acc = Account(
regr=messages.RegistrationResource(
uri=None, new_authzr_uri=None, body=messages.Registration()),
key=KEY)
def tearDown(self):
shutil.rmtree(self.tmp)
def test_init_creates_dir(self):
self.assertTrue(os.path.isdir(self.config.accounts_dir))
def test_save_and_restore(self):
self.storage.save(self.acc)
account_path = os.path.join(self.config.accounts_dir, self.acc.id)
self.assertTrue(os.path.exists(account_path))
for file_name in "regr.json", "meta.json", "private_key.json":
self.assertTrue(os.path.exists(
os.path.join(account_path, file_name)))
self.assertEqual("0400", oct(os.stat(os.path.join(
account_path, "private_key.json"))[stat.ST_MODE] & 0o777))
# restore
self.assertEqual(self.acc, self.storage.load(self.acc.id))
def test_find_all(self):
self.storage.save(self.acc)
self.assertEqual([self.acc], self.storage.find_all())
def test_find_all_none_empty_list(self):
self.assertEqual([], self.storage.find_all())
def test_find_all_accounts_dir_absent(self):
os.rmdir(self.config.accounts_dir)
self.assertEqual([], self.storage.find_all())
def test_find_all_load_skips(self):
self.storage.load = mock.MagicMock(
side_effect=["x", errors.AccountStorageError, "z"])
with mock.patch("letsencrypt.account.os.listdir") as mock_listdir:
mock_listdir.return_value = ["x", "y", "z"]
self.assertEqual(["x", "z"], self.storage.find_all())
def test_load_non_existent_raises_error(self):
self.assertRaises(errors.AccountNotFound, self.storage.load, "missing")
def test_load_id_mismatch_raises_error(self):
self.storage.save(self.acc)
shutil.move(os.path.join(self.config.accounts_dir, self.acc.id),
os.path.join(self.config.accounts_dir, "x" + self.acc.id))
self.assertRaises(errors.AccountStorageError, self.storage.load,
"x" + self.acc.id)
def test_load_ioerror(self):
self.storage.save(self.acc)
mock_open = mock.mock_open()
mock_open.side_effect = IOError
with mock.patch("__builtin__.open", mock_open):
self.assertRaises(
errors.AccountStorageError, self.storage.load, self.acc.id)
def test_save_ioerrors(self):
mock_open = mock.mock_open()
mock_open.side_effect = IOError # TODO: [None, None, IOError]
with mock.patch("__builtin__.open", mock_open):
self.assertRaises(
errors.AccountStorageError, self.storage.save, self.acc)
if __name__ == "__main__":
unittest.main() # pragma: no cover
-89
View File
@@ -1,89 +0,0 @@
"""ACME utilities for testing."""
import datetime
import itertools
from acme import challenges
from acme import jose
from acme import messages
from letsencrypt.tests import test_util
KEY = test_util.load_rsa_private_key('rsa512_key.pem')
# Challenges
HTTP01 = challenges.HTTP01(
token="evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ+PCt92wr+oA")
TLSSNI01 = challenges.TLSSNI01(
token=jose.b64decode(b"evaGxfADs6pSRb2LAv9IZf17Dt3juxGJyPCt92wrDoA"))
DNS = challenges.DNS(token="17817c66b60ce2e4012dfad92657527a")
CHALLENGES = [HTTP01, TLSSNI01, DNS]
def gen_combos(challbs):
"""Generate natural combinations for challbs."""
# completing a single DV challenge satisfies the CA
return tuple((i,) for i, _ in enumerate(challbs))
def chall_to_challb(chall, status): # pylint: disable=redefined-outer-name
"""Return ChallengeBody from Challenge."""
kwargs = {
"chall": chall,
"uri": chall.typ + "_uri",
"status": status,
}
if status == messages.STATUS_VALID:
kwargs.update({"validated": datetime.datetime.now()})
return messages.ChallengeBody(**kwargs) # pylint: disable=star-args
# Pending ChallengeBody objects
TLSSNI01_P = chall_to_challb(TLSSNI01, messages.STATUS_PENDING)
HTTP01_P = chall_to_challb(HTTP01, messages.STATUS_PENDING)
DNS_P = chall_to_challb(DNS, messages.STATUS_PENDING)
CHALLENGES_P = [HTTP01_P, TLSSNI01_P, DNS_P]
def gen_authzr(authz_status, domain, challs, statuses, combos=True):
"""Generate an authorization resource.
:param authz_status: Status object
:type authz_status: :class:`acme.messages.Status`
:param list challs: Challenge objects
:param list statuses: status of each challenge object
:param bool combos: Whether or not to add combinations
"""
# pylint: disable=redefined-outer-name
challbs = tuple(
chall_to_challb(chall, status)
for chall, status in itertools.izip(challs, statuses)
)
authz_kwargs = {
"identifier": messages.Identifier(
typ=messages.IDENTIFIER_FQDN, value=domain),
"challenges": challbs,
}
if combos:
authz_kwargs.update({"combinations": gen_combos(challbs)})
if authz_status == messages.STATUS_VALID:
authz_kwargs.update({
"status": authz_status,
"expires": datetime.datetime.now() + datetime.timedelta(days=31),
})
else:
authz_kwargs.update({
"status": authz_status,
})
# pylint: disable=star-args
return messages.AuthorizationResource(
uri="https://trusted.ca/new-authz-resource",
new_cert_uri="https://trusted.ca/new-cert",
body=messages.Authorization(**authz_kwargs)
)
-422
View File
@@ -1,422 +0,0 @@
"""Tests for letsencrypt.auth_handler."""
import functools
import logging
import unittest
import mock
from acme import challenges
from acme import client as acme_client
from acme import messages
from letsencrypt import achallenges
from letsencrypt import errors
from letsencrypt import le_util
from letsencrypt.tests import acme_util
class ChallengeFactoryTest(unittest.TestCase):
# pylint: disable=protected-access
def setUp(self):
from letsencrypt.auth_handler import AuthHandler
# Account is mocked...
self.handler = AuthHandler(None, None, mock.Mock(key="mock_key"))
self.dom = "test"
self.handler.authzr[self.dom] = acme_util.gen_authzr(
messages.STATUS_PENDING, self.dom, acme_util.CHALLENGES,
[messages.STATUS_PENDING] * 6, False)
def test_all(self):
achalls = self.handler._challenge_factory(
self.dom, range(0, len(acme_util.CHALLENGES)))
self.assertEqual(
[achall.chall for achall in achalls], acme_util.CHALLENGES)
def test_one_tls_sni(self):
achalls = self.handler._challenge_factory(self.dom, [1])
self.assertEqual(
[achall.chall for achall in achalls], [acme_util.TLSSNI01])
def test_unrecognized(self):
self.handler.authzr["failure.com"] = acme_util.gen_authzr(
messages.STATUS_PENDING, "failure.com",
[mock.Mock(chall="chall", typ="unrecognized")],
[messages.STATUS_PENDING])
self.assertRaises(
errors.Error, self.handler._challenge_factory, "failure.com", [0])
class GetAuthorizationsTest(unittest.TestCase):
"""get_authorizations test.
This tests everything except for all functions under _poll_challenges.
"""
def setUp(self):
from letsencrypt.auth_handler import AuthHandler
self.mock_auth = mock.MagicMock(name="ApacheConfigurator")
self.mock_auth.get_chall_pref.return_value = [challenges.TLSSNI01]
self.mock_auth.perform.side_effect = gen_auth_resp
self.mock_account = mock.Mock(key=le_util.Key("file_path", "PEM"))
self.mock_net = mock.MagicMock(spec=acme_client.Client)
self.handler = AuthHandler(
self.mock_auth, self.mock_net, self.mock_account)
logging.disable(logging.CRITICAL)
def tearDown(self):
logging.disable(logging.NOTSET)
@mock.patch("letsencrypt.auth_handler.AuthHandler._poll_challenges")
def test_name1_tls_sni_01_1(self, mock_poll):
self.mock_net.request_domain_challenges.side_effect = functools.partial(
gen_dom_authzr, challs=acme_util.CHALLENGES)
mock_poll.side_effect = self._validate_all
authzr = self.handler.get_authorizations(["0"])
self.assertEqual(self.mock_net.answer_challenge.call_count, 1)
self.assertEqual(mock_poll.call_count, 1)
chall_update = mock_poll.call_args[0][0]
self.assertEqual(chall_update.keys(), ["0"])
self.assertEqual(len(chall_update.values()), 1)
self.assertEqual(self.mock_auth.cleanup.call_count, 1)
# Test if list first element is TLSSNI01, use typ because it is an achall
self.assertEqual(
self.mock_auth.cleanup.call_args[0][0][0].typ, "tls-sni-01")
self.assertEqual(len(authzr), 1)
@mock.patch("letsencrypt.auth_handler.AuthHandler._poll_challenges")
def test_name1_tls_sni_01_1_http_01_1_dns_1(self, mock_poll):
self.mock_net.request_domain_challenges.side_effect = functools.partial(
gen_dom_authzr, challs=acme_util.CHALLENGES, combos=False)
mock_poll.side_effect = self._validate_all
self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01)
self.mock_auth.get_chall_pref.return_value.append(challenges.DNS)
authzr = self.handler.get_authorizations(["0"])
self.assertEqual(self.mock_net.answer_challenge.call_count, 3)
self.assertEqual(mock_poll.call_count, 1)
chall_update = mock_poll.call_args[0][0]
self.assertEqual(chall_update.keys(), ["0"])
self.assertEqual(len(chall_update.values()), 1)
self.assertEqual(self.mock_auth.cleanup.call_count, 1)
# Test if list first element is TLSSNI01, use typ because it is an achall
for achall in self.mock_auth.cleanup.call_args[0][0]:
self.assertTrue(achall.typ in ["tls-sni-01", "http-01", "dns"])
# Length of authorizations list
self.assertEqual(len(authzr), 1)
@mock.patch("letsencrypt.auth_handler.AuthHandler._poll_challenges")
def test_name3_tls_sni_01_3(self, mock_poll):
self.mock_net.request_domain_challenges.side_effect = functools.partial(
gen_dom_authzr, challs=acme_util.CHALLENGES)
mock_poll.side_effect = self._validate_all
authzr = self.handler.get_authorizations(["0", "1", "2"])
self.assertEqual(self.mock_net.answer_challenge.call_count, 3)
# Check poll call
self.assertEqual(mock_poll.call_count, 1)
chall_update = mock_poll.call_args[0][0]
self.assertEqual(len(chall_update.keys()), 3)
self.assertTrue("0" in chall_update.keys())
self.assertEqual(len(chall_update["0"]), 1)
self.assertTrue("1" in chall_update.keys())
self.assertEqual(len(chall_update["1"]), 1)
self.assertTrue("2" in chall_update.keys())
self.assertEqual(len(chall_update["2"]), 1)
self.assertEqual(self.mock_auth.cleanup.call_count, 1)
self.assertEqual(len(authzr), 3)
def test_perform_failure(self):
self.mock_net.request_domain_challenges.side_effect = functools.partial(
gen_dom_authzr, challs=acme_util.CHALLENGES)
self.mock_auth.perform.side_effect = errors.AuthorizationError
self.assertRaises(
errors.AuthorizationError, self.handler.get_authorizations, ["0"])
def test_no_domains(self):
self.assertRaises(errors.AuthorizationError, self.handler.get_authorizations, [])
def _validate_all(self, unused_1, unused_2):
for dom in self.handler.authzr.keys():
azr = self.handler.authzr[dom]
self.handler.authzr[dom] = acme_util.gen_authzr(
messages.STATUS_VALID,
dom,
[challb.chall for challb in azr.body.challenges],
[messages.STATUS_VALID] * len(azr.body.challenges),
azr.body.combinations)
class PollChallengesTest(unittest.TestCase):
# pylint: disable=protected-access
"""Test poll challenges."""
def setUp(self):
from letsencrypt.auth_handler import challb_to_achall
from letsencrypt.auth_handler import AuthHandler
# Account and network are mocked...
self.mock_net = mock.MagicMock()
self.handler = AuthHandler(
None, self.mock_net, mock.Mock(key="mock_key"))
self.doms = ["0", "1", "2"]
self.handler.authzr[self.doms[0]] = acme_util.gen_authzr(
messages.STATUS_PENDING, self.doms[0],
[acme_util.HTTP01, acme_util.TLSSNI01],
[messages.STATUS_PENDING] * 2, False)
self.handler.authzr[self.doms[1]] = acme_util.gen_authzr(
messages.STATUS_PENDING, self.doms[1],
acme_util.CHALLENGES, [messages.STATUS_PENDING] * 3, False)
self.handler.authzr[self.doms[2]] = acme_util.gen_authzr(
messages.STATUS_PENDING, self.doms[2],
acme_util.CHALLENGES, [messages.STATUS_PENDING] * 3, False)
self.chall_update = {}
for dom in self.doms:
self.chall_update[dom] = [
challb_to_achall(challb, mock.Mock(key="dummy_key"), dom)
for challb in self.handler.authzr[dom].body.challenges]
@mock.patch("letsencrypt.auth_handler.time")
def test_poll_challenges(self, unused_mock_time):
self.mock_net.poll.side_effect = self._mock_poll_solve_one_valid
self.handler._poll_challenges(self.chall_update, False)
for authzr in self.handler.authzr.values():
self.assertEqual(authzr.body.status, messages.STATUS_VALID)
@mock.patch("letsencrypt.auth_handler.time")
def test_poll_challenges_failure_best_effort(self, unused_mock_time):
self.mock_net.poll.side_effect = self._mock_poll_solve_one_invalid
self.handler._poll_challenges(self.chall_update, True)
for authzr in self.handler.authzr.values():
self.assertEqual(authzr.body.status, messages.STATUS_PENDING)
@mock.patch("letsencrypt.auth_handler.time")
@mock.patch("letsencrypt.auth_handler.zope.component.getUtility")
def test_poll_challenges_failure(self, unused_mock_time, unused_mock_zope):
self.mock_net.poll.side_effect = self._mock_poll_solve_one_invalid
self.assertRaises(
errors.AuthorizationError, self.handler._poll_challenges,
self.chall_update, False)
@mock.patch("letsencrypt.auth_handler.time")
def test_unable_to_find_challenge_status(self, unused_mock_time):
from letsencrypt.auth_handler import challb_to_achall
self.mock_net.poll.side_effect = self._mock_poll_solve_one_valid
self.chall_update[self.doms[0]].append(
challb_to_achall(acme_util.DNS_P, "key", self.doms[0]))
self.assertRaises(
errors.AuthorizationError, self.handler._poll_challenges,
self.chall_update, False)
def test_verify_authzr_failure(self):
self.assertRaises(
errors.AuthorizationError, self.handler.verify_authzr_complete)
def _mock_poll_solve_one_valid(self, authzr):
# Pending here because my dummy script won't change the full status.
# Basically it didn't raise an error and it stopped earlier than
# Making all challenges invalid which would make mock_poll_solve_one
# change authzr to invalid
return self._mock_poll_solve_one_chall(authzr, messages.STATUS_VALID)
def _mock_poll_solve_one_invalid(self, authzr):
return self._mock_poll_solve_one_chall(authzr, messages.STATUS_INVALID)
def _mock_poll_solve_one_chall(self, authzr, desired_status):
# pylint: disable=no-self-use
"""Dummy method that solves one chall at a time to desired_status.
When all are solved.. it changes authzr.status to desired_status
"""
new_challbs = authzr.body.challenges
for challb in authzr.body.challenges:
if challb.status != desired_status:
new_challbs = tuple(
challb_temp if challb_temp != challb
else acme_util.chall_to_challb(challb.chall, desired_status)
for challb_temp in authzr.body.challenges
)
break
if all(test_challb.status == desired_status
for test_challb in new_challbs):
status_ = desired_status
else:
status_ = authzr.body.status
new_authzr = messages.AuthorizationResource(
uri=authzr.uri,
new_cert_uri=authzr.new_cert_uri,
body=messages.Authorization(
identifier=authzr.body.identifier,
challenges=new_challbs,
combinations=authzr.body.combinations,
status=status_,
),
)
return (new_authzr, "response")
class ChallbToAchallTest(unittest.TestCase):
"""Tests for letsencrypt.auth_handler.challb_to_achall."""
def _call(self, challb):
from letsencrypt.auth_handler import challb_to_achall
return challb_to_achall(challb, "account_key", "domain")
def test_it(self):
self.assertEqual(
self._call(acme_util.HTTP01_P),
achallenges.KeyAuthorizationAnnotatedChallenge(
challb=acme_util.HTTP01_P, account_key="account_key",
domain="domain"),
)
class GenChallengePathTest(unittest.TestCase):
"""Tests for letsencrypt.auth_handler.gen_challenge_path.
.. todo:: Add more tests for dumb_path... depending on what we want to do.
"""
def setUp(self):
logging.disable(logging.fatal)
def tearDown(self):
logging.disable(logging.NOTSET)
@classmethod
def _call(cls, challbs, preferences, combinations):
from letsencrypt.auth_handler import gen_challenge_path
return gen_challenge_path(challbs, preferences, combinations)
def test_common_case(self):
"""Given TLSSNI01 and HTTP01 with appropriate combos."""
challbs = (acme_util.TLSSNI01_P, acme_util.HTTP01_P)
prefs = [challenges.TLSSNI01, challenges.HTTP01]
combos = ((0,), (1,))
# Smart then trivial dumb path test
self.assertEqual(self._call(challbs, prefs, combos), (0,))
self.assertTrue(self._call(challbs, prefs, None))
# Rearrange order...
self.assertEqual(self._call(challbs[::-1], prefs, combos), (1,))
self.assertTrue(self._call(challbs[::-1], prefs, None))
def test_not_supported(self):
challbs = (acme_util.DNS_P, acme_util.TLSSNI01_P)
prefs = [challenges.TLSSNI01]
combos = ((0, 1),)
# smart path fails because no challs in perfs satisfies combos
self.assertRaises(
errors.AuthorizationError, self._call, challbs, prefs, combos)
# dumb path fails because all challbs are not supported
self.assertRaises(
errors.AuthorizationError, self._call, challbs, prefs, None)
class ReportFailedChallsTest(unittest.TestCase):
"""Tests for letsencrypt.auth_handler._report_failed_challs."""
# pylint: disable=protected-access
def setUp(self):
kwargs = {
"chall": acme_util.HTTP01,
"uri": "uri",
"status": messages.STATUS_INVALID,
"error": messages.Error(typ="urn:acme:error:tls", detail="detail"),
}
# Prevent future regressions if the error type changes
self.assertTrue(kwargs["error"].description is not None)
self.http01 = achallenges.KeyAuthorizationAnnotatedChallenge(
# pylint: disable=star-args
challb=messages.ChallengeBody(**kwargs),
domain="example.com",
account_key="key")
kwargs["chall"] = acme_util.TLSSNI01
self.tls_sni_same = achallenges.KeyAuthorizationAnnotatedChallenge(
# pylint: disable=star-args
challb=messages.ChallengeBody(**kwargs),
domain="example.com",
account_key="key")
kwargs["error"] = messages.Error(typ="dnssec", detail="detail")
self.tls_sni_diff = achallenges.KeyAuthorizationAnnotatedChallenge(
# pylint: disable=star-args
challb=messages.ChallengeBody(**kwargs),
domain="foo.bar",
account_key="key")
@mock.patch("letsencrypt.auth_handler.zope.component.getUtility")
def test_same_error_and_domain(self, mock_zope):
from letsencrypt import auth_handler
auth_handler._report_failed_challs([self.http01, self.tls_sni_same])
call_list = mock_zope().add_message.call_args_list
self.assertTrue(len(call_list) == 1)
self.assertTrue("Domain: example.com\nType: tls\nDetail: detail" in call_list[0][0][0])
@mock.patch("letsencrypt.auth_handler.zope.component.getUtility")
def test_different_errors_and_domains(self, mock_zope):
from letsencrypt import auth_handler
auth_handler._report_failed_challs([self.http01, self.tls_sni_diff])
self.assertTrue(mock_zope().add_message.call_count == 2)
def gen_auth_resp(chall_list):
"""Generate a dummy authorization response."""
return ["%s%s" % (chall.__class__.__name__, chall.domain)
for chall in chall_list]
def gen_dom_authzr(domain, unused_new_authzr_uri, challs, combos=True):
"""Generates new authzr for domains."""
return acme_util.gen_authzr(
messages.STATUS_PENDING, domain, challs,
[messages.STATUS_PENDING] * len(challs), combos)
if __name__ == "__main__":
unittest.main() # pragma: no cover
File diff suppressed because it is too large Load Diff
-474
View File
@@ -1,474 +0,0 @@
"""Tests for letsencrypt.client."""
import os
import shutil
import tempfile
import unittest
import OpenSSL
import mock
from acme import jose
from letsencrypt import account
from letsencrypt import errors
from letsencrypt import le_util
from letsencrypt.tests import test_util
KEY = test_util.load_vector("rsa512_key.pem")
CSR_SAN = test_util.load_vector("csr-san.der")
class ConfigHelper(object):
"""Creates a dummy object to imitate a namespace object
Example: cfg = ConfigHelper(redirect=True, hsts=False, uir=False)
will result in: cfg.redirect=True, cfg.hsts=False, etc.
"""
def __init__(self, **kwds):
self.__dict__.update(kwds)
class RegisterTest(unittest.TestCase):
"""Tests for letsencrypt.client.register."""
def setUp(self):
self.config = mock.MagicMock(rsa_key_size=1024, register_unsafely_without_email=False)
self.account_storage = account.AccountMemoryStorage()
self.tos_cb = mock.MagicMock()
def _call(self):
from letsencrypt.client import register
return register(self.config, self.account_storage, self.tos_cb)
def test_no_tos(self):
with mock.patch("letsencrypt.client.acme_client.Client") as mock_client:
mock_client.register().terms_of_service = "http://tos"
with mock.patch("letsencrypt.account.report_new_account"):
self.tos_cb.return_value = False
self.assertRaises(errors.Error, self._call)
self.tos_cb.return_value = True
self._call()
self.tos_cb = None
self._call()
def test_it(self):
with mock.patch("letsencrypt.client.acme_client.Client"):
with mock.patch("letsencrypt.account.report_new_account"):
self._call()
@mock.patch("letsencrypt.account.report_new_account")
@mock.patch("letsencrypt.client.display_ops.get_email")
def test_email_retry(self, _rep, mock_get_email):
from acme import messages
msg = "DNS problem: NXDOMAIN looking up MX for example.com"
mx_err = messages.Error(detail=msg, typ="urn:acme:error:invalidEmail")
with mock.patch("letsencrypt.client.acme_client.Client") as mock_client:
mock_client().register.side_effect = [mx_err, mock.MagicMock()]
self._call()
self.assertEqual(mock_get_email.call_count, 1)
def test_needs_email(self):
self.config.email = None
self.assertRaises(errors.Error, self._call)
@mock.patch("letsencrypt.client.logger")
def test_without_email(self, mock_logger):
with mock.patch("letsencrypt.client.acme_client.Client"):
with mock.patch("letsencrypt.account.report_new_account"):
self.config.email = None
self.config.register_unsafely_without_email = True
self.config.dry_run = False
self._call()
mock_logger.warn.assert_called_once_with(mock.ANY)
def test_unsupported_error(self):
from acme import messages
msg = "Test"
mx_err = messages.Error(detail=msg, typ="malformed", title="title")
with mock.patch("letsencrypt.client.acme_client.Client") as mock_client:
mock_client().register.side_effect = [mx_err, mock.MagicMock()]
self.assertRaises(messages.Error, self._call)
class ClientTest(unittest.TestCase):
"""Tests for letsencrypt.client.Client."""
def setUp(self):
self.config = mock.MagicMock(
no_verify_ssl=False, config_dir="/etc/letsencrypt", allow_subset_of_names=False)
# pylint: disable=star-args
self.account = mock.MagicMock(**{"key.pem": KEY})
self.eg_domains = ["example.com", "www.example.com"]
from letsencrypt.client import Client
with mock.patch("letsencrypt.client.acme_client.Client") as acme:
self.acme_client = acme
self.acme = acme.return_value = mock.MagicMock()
self.client = Client(
config=self.config, account_=self.account,
auth=None, installer=None)
def test_init_acme_verify_ssl(self):
net = self.acme_client.call_args[1]["net"]
self.assertTrue(net.verify_ssl)
def _mock_obtain_certificate(self):
self.client.auth_handler = mock.MagicMock()
self.client.auth_handler.get_authorizations.return_value = [None]
self.acme.request_issuance.return_value = mock.sentinel.certr
self.acme.fetch_chain.return_value = mock.sentinel.chain
def _check_obtain_certificate(self):
self.client.auth_handler.get_authorizations.assert_called_once_with(
self.eg_domains,
self.config.allow_subset_of_names)
authzr = self.client.auth_handler.get_authorizations()
self.acme.request_issuance.assert_called_once_with(
jose.ComparableX509(OpenSSL.crypto.load_certificate_request(
OpenSSL.crypto.FILETYPE_ASN1, CSR_SAN)),
authzr)
self.acme.fetch_chain.assert_called_once_with(mock.sentinel.certr)
# FIXME move parts of this to test_cli.py...
@mock.patch("letsencrypt.client.logger")
def test_obtain_certificate_from_csr(self, mock_logger):
self._mock_obtain_certificate()
from letsencrypt import cli
test_csr = le_util.CSR(form="der", file=None, data=CSR_SAN)
mock_parsed_args = mock.MagicMock()
# The CLI should believe that this is a certonly request, because
# a CSR would not be allowed with other kinds of requests!
mock_parsed_args.verb = "certonly"
with mock.patch("letsencrypt.client.le_util.CSR") as mock_CSR:
mock_CSR.return_value = test_csr
mock_parsed_args.domains = self.eg_domains[:]
mock_parser = mock.MagicMock(cli.HelpfulArgumentParser)
cli.HelpfulArgumentParser.handle_csr(mock_parser, mock_parsed_args)
# Now provoke an inconsistent domains error...
mock_parsed_args.domains.append("hippopotamus.io")
self.assertRaises(errors.ConfigurationError,
cli.HelpfulArgumentParser.handle_csr, mock_parser, mock_parsed_args)
authzr = self.client.auth_handler.get_authorizations(self.eg_domains, False)
self.assertEqual(
(mock.sentinel.certr, mock.sentinel.chain),
self.client.obtain_certificate_from_csr(
self.eg_domains,
test_csr,
authzr=authzr))
# and that the cert was obtained correctly
self._check_obtain_certificate()
# Test for authzr=None
self.assertEqual(
(mock.sentinel.certr, mock.sentinel.chain),
self.client.obtain_certificate_from_csr(
self.eg_domains,
test_csr,
authzr=None))
self.client.auth_handler.get_authorizations.assert_called_with(
self.eg_domains)
# Test for no auth_handler
self.client.auth_handler = None
self.assertRaises(
errors.Error,
self.client.obtain_certificate_from_csr,
self.eg_domains,
test_csr)
mock_logger.warning.assert_called_once_with(mock.ANY)
@mock.patch("letsencrypt.client.crypto_util")
def test_obtain_certificate(self, mock_crypto_util):
self._mock_obtain_certificate()
csr = le_util.CSR(form="der", file=None, data=CSR_SAN)
mock_crypto_util.init_save_csr.return_value = csr
mock_crypto_util.init_save_key.return_value = mock.sentinel.key
domains = ["example.com", "www.example.com"]
# return_value is essentially set to (None, None) in
# _mock_obtain_certificate(), which breaks this test.
# Thus fixed by the next line.
authzr = []
for domain in domains:
authzr.append(
mock.MagicMock(
body=mock.MagicMock(
identifier=mock.MagicMock(
value=domain))))
self.client.auth_handler.get_authorizations.return_value = authzr
self.assertEqual(
self.client.obtain_certificate(domains),
(mock.sentinel.certr, mock.sentinel.chain, mock.sentinel.key, csr))
mock_crypto_util.init_save_key.assert_called_once_with(
self.config.rsa_key_size, self.config.key_dir)
mock_crypto_util.init_save_csr.assert_called_once_with(
mock.sentinel.key, domains, self.config.csr_dir)
self._check_obtain_certificate()
def test_save_certificate(self):
certs = ["matching_cert.pem", "cert.pem", "cert-san.pem"]
tmp_path = tempfile.mkdtemp()
os.chmod(tmp_path, 0o755) # TODO: really??
certr = mock.MagicMock(body=test_util.load_comparable_cert(certs[0]))
chain_cert = [test_util.load_comparable_cert(certs[1]),
test_util.load_comparable_cert(certs[2])]
candidate_cert_path = os.path.join(tmp_path, "certs", "cert.pem")
candidate_chain_path = os.path.join(tmp_path, "chains", "chain.pem")
candidate_fullchain_path = os.path.join(tmp_path, "chains", "fullchain.pem")
cert_path, chain_path, fullchain_path = self.client.save_certificate(
certr, chain_cert, candidate_cert_path, candidate_chain_path,
candidate_fullchain_path)
self.assertEqual(os.path.dirname(cert_path),
os.path.dirname(candidate_cert_path))
self.assertEqual(os.path.dirname(chain_path),
os.path.dirname(candidate_chain_path))
self.assertEqual(os.path.dirname(fullchain_path),
os.path.dirname(candidate_fullchain_path))
with open(cert_path, "r") as cert_file:
cert_contents = cert_file.read()
self.assertEqual(cert_contents, test_util.load_vector(certs[0]))
with open(chain_path, "r") as chain_file:
chain_contents = chain_file.read()
self.assertEqual(chain_contents, test_util.load_vector(certs[1]) +
test_util.load_vector(certs[2]))
shutil.rmtree(tmp_path)
def test_deploy_certificate_success(self):
self.assertRaises(errors.Error, self.client.deploy_certificate,
["foo.bar"], "key", "cert", "chain", "fullchain")
installer = mock.MagicMock()
self.client.installer = installer
self.client.deploy_certificate(
["foo.bar"], "key", "cert", "chain", "fullchain")
installer.deploy_cert.assert_called_once_with(
cert_path=os.path.abspath("cert"),
chain_path=os.path.abspath("chain"),
domain='foo.bar',
fullchain_path='fullchain',
key_path=os.path.abspath("key"))
self.assertEqual(installer.save.call_count, 2)
installer.restart.assert_called_once_with()
def test_deploy_certificate_failure(self):
installer = mock.MagicMock()
self.client.installer = installer
installer.deploy_cert.side_effect = errors.PluginError
self.assertRaises(errors.PluginError, self.client.deploy_certificate,
["foo.bar"], "key", "cert", "chain", "fullchain")
installer.recovery_routine.assert_called_once_with()
def test_deploy_certificate_save_failure(self):
installer = mock.MagicMock()
self.client.installer = installer
installer.save.side_effect = errors.PluginError
self.assertRaises(errors.PluginError, self.client.deploy_certificate,
["foo.bar"], "key", "cert", "chain", "fullchain")
installer.recovery_routine.assert_called_once_with()
@mock.patch("letsencrypt.client.zope.component.getUtility")
def test_deploy_certificate_restart_failure(self, mock_get_utility):
installer = mock.MagicMock()
installer.restart.side_effect = [errors.PluginError, None]
self.client.installer = installer
self.assertRaises(errors.PluginError, self.client.deploy_certificate,
["foo.bar"], "key", "cert", "chain", "fullchain")
self.assertEqual(mock_get_utility().add_message.call_count, 1)
installer.rollback_checkpoints.assert_called_once_with()
self.assertEqual(installer.restart.call_count, 2)
@mock.patch("letsencrypt.client.zope.component.getUtility")
def test_deploy_certificate_restart_failure2(self, mock_get_utility):
installer = mock.MagicMock()
installer.restart.side_effect = errors.PluginError
installer.rollback_checkpoints.side_effect = errors.ReverterError
self.client.installer = installer
self.assertRaises(errors.PluginError, self.client.deploy_certificate,
["foo.bar"], "key", "cert", "chain", "fullchain")
self.assertEqual(mock_get_utility().add_message.call_count, 1)
installer.rollback_checkpoints.assert_called_once_with()
self.assertEqual(installer.restart.call_count, 1)
@mock.patch("letsencrypt.client.enhancements")
def test_enhance_config(self, mock_enhancements):
config = ConfigHelper(redirect=True, hsts=False, uir=False)
self.assertRaises(errors.Error,
self.client.enhance_config, ["foo.bar"], config)
mock_enhancements.ask.return_value = True
installer = mock.MagicMock()
self.client.installer = installer
installer.supported_enhancements.return_value = ["redirect"]
self.client.enhance_config(["foo.bar"], config)
installer.enhance.assert_called_once_with("foo.bar", "redirect", None)
self.assertEqual(installer.save.call_count, 1)
installer.restart.assert_called_once_with()
@mock.patch("letsencrypt.client.enhancements")
def test_enhance_config_no_ask(self, mock_enhancements):
config = ConfigHelper(redirect=True, hsts=False, uir=False)
self.assertRaises(errors.Error,
self.client.enhance_config, ["foo.bar"], config)
mock_enhancements.ask.return_value = True
installer = mock.MagicMock()
self.client.installer = installer
installer.supported_enhancements.return_value = ["redirect", "ensure-http-header"]
config = ConfigHelper(redirect=True, hsts=False, uir=False)
self.client.enhance_config(["foo.bar"], config)
installer.enhance.assert_called_with("foo.bar", "redirect", None)
config = ConfigHelper(redirect=False, hsts=True, uir=False)
self.client.enhance_config(["foo.bar"], config)
installer.enhance.assert_called_with("foo.bar", "ensure-http-header",
"Strict-Transport-Security")
config = ConfigHelper(redirect=False, hsts=False, uir=True)
self.client.enhance_config(["foo.bar"], config)
installer.enhance.assert_called_with("foo.bar", "ensure-http-header",
"Upgrade-Insecure-Requests")
self.assertEqual(installer.save.call_count, 3)
self.assertEqual(installer.restart.call_count, 3)
@mock.patch("letsencrypt.client.enhancements")
def test_enhance_config_unsupported(self, mock_enhancements):
installer = mock.MagicMock()
self.client.installer = installer
installer.supported_enhancements.return_value = []
config = ConfigHelper(redirect=None, hsts=True, uir=True)
self.client.enhance_config(["foo.bar"], config)
installer.enhance.assert_not_called()
mock_enhancements.ask.assert_not_called()
def test_enhance_config_no_installer(self):
config = ConfigHelper(redirect=True, hsts=False, uir=False)
self.assertRaises(errors.Error,
self.client.enhance_config, ["foo.bar"], config)
@mock.patch("letsencrypt.client.zope.component.getUtility")
@mock.patch("letsencrypt.client.enhancements")
def test_enhance_config_enhance_failure(self, mock_enhancements,
mock_get_utility):
mock_enhancements.ask.return_value = True
installer = mock.MagicMock()
self.client.installer = installer
installer.supported_enhancements.return_value = ["redirect"]
installer.enhance.side_effect = errors.PluginError
config = ConfigHelper(redirect=True, hsts=False, uir=False)
self.assertRaises(errors.PluginError,
self.client.enhance_config, ["foo.bar"], config)
installer.recovery_routine.assert_called_once_with()
self.assertEqual(mock_get_utility().add_message.call_count, 1)
@mock.patch("letsencrypt.client.zope.component.getUtility")
@mock.patch("letsencrypt.client.enhancements")
def test_enhance_config_save_failure(self, mock_enhancements,
mock_get_utility):
mock_enhancements.ask.return_value = True
installer = mock.MagicMock()
self.client.installer = installer
installer.supported_enhancements.return_value = ["redirect"]
installer.save.side_effect = errors.PluginError
config = ConfigHelper(redirect=True, hsts=False, uir=False)
self.assertRaises(errors.PluginError,
self.client.enhance_config, ["foo.bar"], config)
installer.recovery_routine.assert_called_once_with()
self.assertEqual(mock_get_utility().add_message.call_count, 1)
@mock.patch("letsencrypt.client.zope.component.getUtility")
@mock.patch("letsencrypt.client.enhancements")
def test_enhance_config_restart_failure(self, mock_enhancements,
mock_get_utility):
mock_enhancements.ask.return_value = True
installer = mock.MagicMock()
self.client.installer = installer
installer.supported_enhancements.return_value = ["redirect"]
installer.restart.side_effect = [errors.PluginError, None]
config = ConfigHelper(redirect=True, hsts=False, uir=False)
self.assertRaises(errors.PluginError,
self.client.enhance_config, ["foo.bar"], config)
self.assertEqual(mock_get_utility().add_message.call_count, 1)
installer.rollback_checkpoints.assert_called_once_with()
self.assertEqual(installer.restart.call_count, 2)
@mock.patch("letsencrypt.client.zope.component.getUtility")
@mock.patch("letsencrypt.client.enhancements")
def test_enhance_config_restart_failure2(self, mock_enhancements,
mock_get_utility):
mock_enhancements.ask.return_value = True
installer = mock.MagicMock()
self.client.installer = installer
installer.supported_enhancements.return_value = ["redirect"]
installer.restart.side_effect = errors.PluginError
installer.rollback_checkpoints.side_effect = errors.ReverterError
config = ConfigHelper(redirect=True, hsts=False, uir=False)
self.assertRaises(errors.PluginError,
self.client.enhance_config, ["foo.bar"], config)
self.assertEqual(mock_get_utility().add_message.call_count, 1)
installer.rollback_checkpoints.assert_called_once_with()
self.assertEqual(installer.restart.call_count, 1)
class RollbackTest(unittest.TestCase):
"""Tests for letsencrypt.client.rollback."""
def setUp(self):
self.m_install = mock.MagicMock()
@classmethod
def _call(cls, checkpoints, side_effect):
from letsencrypt.client import rollback
with mock.patch("letsencrypt.client.plugin_selection.pick_installer") as mpi:
mpi.side_effect = side_effect
rollback(None, checkpoints, {}, mock.MagicMock())
def test_no_problems(self):
self._call(1, self.m_install)
self.assertEqual(self.m_install().rollback_checkpoints.call_count, 1)
self.assertEqual(self.m_install().restart.call_count, 1)
def test_no_installer(self):
self._call(1, None) # Just make sure no exceptions are raised
if __name__ == "__main__":
unittest.main() # pragma: no cover
-41
View File
@@ -1,41 +0,0 @@
"""Tests for letsencrypt.colored_logging."""
import logging
import unittest
import six
from letsencrypt import le_util
class StreamHandlerTest(unittest.TestCase):
"""Tests for letsencrypt.colored_logging."""
def setUp(self):
from letsencrypt import colored_logging
self.stream = six.StringIO()
self.stream.isatty = lambda: True
self.handler = colored_logging.StreamHandler(self.stream)
self.logger = logging.getLogger()
self.logger.setLevel(logging.DEBUG)
self.logger.addHandler(self.handler)
def test_format(self):
msg = 'I did a thing'
self.logger.debug(msg)
self.assertEqual(self.stream.getvalue(), '{0}\n'.format(msg))
def test_format_and_red_level(self):
msg = 'I did another thing'
self.handler.red_level = logging.DEBUG
self.logger.debug(msg)
self.assertEqual(self.stream.getvalue(),
'{0}{1}{2}\n'.format(le_util.ANSI_SGR_RED,
msg,
le_util.ANSI_SGR_RESET))
if __name__ == "__main__":
unittest.main() # pragma: no cover
-135
View File
@@ -1,135 +0,0 @@
"""Tests for letsencrypt.configuration."""
import os
import unittest
import mock
from letsencrypt import errors
class NamespaceConfigTest(unittest.TestCase):
"""Tests for letsencrypt.configuration.NamespaceConfig."""
def setUp(self):
self.namespace = mock.MagicMock(
config_dir='/tmp/config', work_dir='/tmp/foo', foo='bar',
server='https://acme-server.org:443/new',
tls_sni_01_port=1234, http01_port=4321)
from letsencrypt.configuration import NamespaceConfig
self.config = NamespaceConfig(self.namespace)
def test_init_same_ports(self):
self.namespace.tls_sni_01_port = 4321
from letsencrypt.configuration import NamespaceConfig
self.assertRaises(errors.Error, NamespaceConfig, self.namespace)
def test_proxy_getattr(self):
self.assertEqual(self.config.foo, 'bar')
self.assertEqual(self.config.work_dir, '/tmp/foo')
def test_server_path(self):
self.assertEqual(['acme-server.org:443', 'new'],
self.config.server_path.split(os.path.sep))
self.namespace.server = ('http://user:pass@acme.server:443'
'/p/a/t/h;parameters?query#fragment')
self.assertEqual(['user:pass@acme.server:443', 'p', 'a', 't', 'h'],
self.config.server_path.split(os.path.sep))
@mock.patch('letsencrypt.configuration.constants')
def test_dynamic_dirs(self, constants):
constants.ACCOUNTS_DIR = 'acc'
constants.BACKUP_DIR = 'backups'
constants.CSR_DIR = 'csr'
constants.IN_PROGRESS_DIR = '../p'
constants.KEY_DIR = 'keys'
constants.TEMP_CHECKPOINT_DIR = 't'
self.assertEqual(
self.config.accounts_dir, '/tmp/config/acc/acme-server.org:443/new')
self.assertEqual(self.config.backup_dir, '/tmp/foo/backups')
self.assertEqual(self.config.csr_dir, '/tmp/config/csr')
self.assertEqual(self.config.in_progress_dir, '/tmp/foo/../p')
self.assertEqual(self.config.key_dir, '/tmp/config/keys')
self.assertEqual(self.config.temp_checkpoint_dir, '/tmp/foo/t')
def test_absolute_paths(self):
from letsencrypt.configuration import NamespaceConfig
config_base = "foo"
work_base = "bar"
logs_base = "baz"
mock_namespace = mock.MagicMock(spec=['config_dir', 'work_dir',
'logs_dir', 'http01_port',
'tls_sni_01_port',
'domains', 'server'])
mock_namespace.config_dir = config_base
mock_namespace.work_dir = work_base
mock_namespace.logs_dir = logs_base
config = NamespaceConfig(mock_namespace)
self.assertTrue(os.path.isabs(config.config_dir))
self.assertEqual(config.config_dir,
os.path.join(os.getcwd(), config_base))
self.assertTrue(os.path.isabs(config.work_dir))
self.assertEqual(config.work_dir,
os.path.join(os.getcwd(), work_base))
self.assertTrue(os.path.isabs(config.logs_dir))
self.assertEqual(config.logs_dir,
os.path.join(os.getcwd(), logs_base))
self.assertTrue(os.path.isabs(config.accounts_dir))
self.assertTrue(os.path.isabs(config.backup_dir))
self.assertTrue(os.path.isabs(config.csr_dir))
self.assertTrue(os.path.isabs(config.in_progress_dir))
self.assertTrue(os.path.isabs(config.key_dir))
self.assertTrue(os.path.isabs(config.temp_checkpoint_dir))
class RenewerConfigurationTest(unittest.TestCase):
"""Test for letsencrypt.configuration.RenewerConfiguration."""
def setUp(self):
self.namespace = mock.MagicMock(config_dir='/tmp/config')
from letsencrypt.configuration import RenewerConfiguration
self.config = RenewerConfiguration(self.namespace)
@mock.patch('letsencrypt.configuration.constants')
def test_dynamic_dirs(self, constants):
constants.ARCHIVE_DIR = 'a'
constants.LIVE_DIR = 'l'
constants.RENEWAL_CONFIGS_DIR = 'renewal_configs'
constants.RENEWER_CONFIG_FILENAME = 'r.conf'
self.assertEqual(self.config.archive_dir, '/tmp/config/a')
self.assertEqual(self.config.live_dir, '/tmp/config/l')
self.assertEqual(
self.config.renewal_configs_dir, '/tmp/config/renewal_configs')
self.assertEqual(self.config.renewer_config_file, '/tmp/config/r.conf')
def test_absolute_paths(self):
from letsencrypt.configuration import NamespaceConfig
from letsencrypt.configuration import RenewerConfiguration
config_base = "foo"
work_base = "bar"
logs_base = "baz"
mock_namespace = mock.MagicMock(spec=['config_dir', 'work_dir',
'logs_dir', 'http01_port',
'tls_sni_01_port',
'domains', 'server'])
mock_namespace.config_dir = config_base
mock_namespace.work_dir = work_base
mock_namespace.logs_dir = logs_base
config = RenewerConfiguration(NamespaceConfig(mock_namespace))
self.assertTrue(os.path.isabs(config.archive_dir))
self.assertTrue(os.path.isabs(config.live_dir))
self.assertTrue(os.path.isabs(config.renewal_configs_dir))
self.assertTrue(os.path.isabs(config.renewer_config_file))
if __name__ == '__main__':
unittest.main() # pragma: no cover
-254
View File
@@ -1,254 +0,0 @@
"""Tests for letsencrypt.crypto_util."""
import logging
import shutil
import tempfile
import unittest
import OpenSSL
import mock
import zope.component
from letsencrypt import errors
from letsencrypt import interfaces
from letsencrypt.tests import test_util
RSA256_KEY = test_util.load_vector('rsa256_key.pem')
RSA512_KEY = test_util.load_vector('rsa512_key.pem')
CERT_PATH = test_util.vector_path('cert.pem')
CERT = test_util.load_vector('cert.pem')
SAN_CERT = test_util.load_vector('cert-san.pem')
class InitSaveKeyTest(unittest.TestCase):
"""Tests for letsencrypt.crypto_util.init_save_key."""
def setUp(self):
logging.disable(logging.CRITICAL)
zope.component.provideUtility(
mock.Mock(strict_permissions=True), interfaces.IConfig)
self.key_dir = tempfile.mkdtemp('key_dir')
def tearDown(self):
logging.disable(logging.NOTSET)
shutil.rmtree(self.key_dir)
@classmethod
def _call(cls, key_size, key_dir):
from letsencrypt.crypto_util import init_save_key
return init_save_key(key_size, key_dir, 'key-letsencrypt.pem')
@mock.patch('letsencrypt.crypto_util.make_key')
def test_success(self, mock_make):
mock_make.return_value = 'key_pem'
key = self._call(1024, self.key_dir)
self.assertEqual(key.pem, 'key_pem')
self.assertTrue('key-letsencrypt.pem' in key.file)
@mock.patch('letsencrypt.crypto_util.make_key')
def test_key_failure(self, mock_make):
mock_make.side_effect = ValueError
self.assertRaises(ValueError, self._call, 431, self.key_dir)
class InitSaveCSRTest(unittest.TestCase):
"""Tests for letsencrypt.crypto_util.init_save_csr."""
def setUp(self):
zope.component.provideUtility(
mock.Mock(strict_permissions=True), interfaces.IConfig)
self.csr_dir = tempfile.mkdtemp('csr_dir')
def tearDown(self):
shutil.rmtree(self.csr_dir)
@mock.patch('letsencrypt.crypto_util.make_csr')
@mock.patch('letsencrypt.crypto_util.le_util.make_or_verify_dir')
def test_it(self, unused_mock_verify, mock_csr):
from letsencrypt.crypto_util import init_save_csr
mock_csr.return_value = ('csr_pem', 'csr_der')
csr = init_save_csr(
mock.Mock(pem='dummy_key'), 'example.com', self.csr_dir,
'csr-letsencrypt.pem')
self.assertEqual(csr.data, 'csr_der')
self.assertTrue('csr-letsencrypt.pem' in csr.file)
class MakeCSRTest(unittest.TestCase):
"""Tests for letsencrypt.crypto_util.make_csr."""
@classmethod
def _call(cls, *args, **kwargs):
from letsencrypt.crypto_util import make_csr
return make_csr(*args, **kwargs)
def test_san(self):
from letsencrypt.crypto_util import get_sans_from_csr
# TODO: Fails for RSA256_KEY
csr_pem, csr_der = self._call(
RSA512_KEY, ['example.com', 'www.example.com'])
self.assertEqual(
['example.com', 'www.example.com'], get_sans_from_csr(csr_pem))
self.assertEqual(
['example.com', 'www.example.com'], get_sans_from_csr(
csr_der, OpenSSL.crypto.FILETYPE_ASN1))
class ValidCSRTest(unittest.TestCase):
"""Tests for letsencrypt.crypto_util.valid_csr."""
@classmethod
def _call(cls, csr):
from letsencrypt.crypto_util import valid_csr
return valid_csr(csr)
def test_valid_pem_true(self):
self.assertTrue(self._call(test_util.load_vector('csr.pem')))
def test_valid_pem_san_true(self):
self.assertTrue(self._call(test_util.load_vector('csr-san.pem')))
def test_valid_der_false(self):
self.assertFalse(self._call(test_util.load_vector('csr.der')))
def test_valid_der_san_false(self):
self.assertFalse(self._call(test_util.load_vector('csr-san.der')))
def test_empty_false(self):
self.assertFalse(self._call(''))
def test_random_false(self):
self.assertFalse(self._call('foo bar'))
class CSRMatchesPubkeyTest(unittest.TestCase):
"""Tests for letsencrypt.crypto_util.csr_matches_pubkey."""
@classmethod
def _call(cls, *args, **kwargs):
from letsencrypt.crypto_util import csr_matches_pubkey
return csr_matches_pubkey(*args, **kwargs)
def test_valid_true(self):
self.assertTrue(self._call(
test_util.load_vector('csr.pem'), RSA512_KEY))
def test_invalid_false(self):
self.assertFalse(self._call(
test_util.load_vector('csr.pem'), RSA256_KEY))
class MakeKeyTest(unittest.TestCase): # pylint: disable=too-few-public-methods
"""Tests for letsencrypt.crypto_util.make_key."""
def test_it(self): # pylint: disable=no-self-use
from letsencrypt.crypto_util import make_key
# Do not test larger keys as it takes too long.
OpenSSL.crypto.load_privatekey(
OpenSSL.crypto.FILETYPE_PEM, make_key(1024))
class ValidPrivkeyTest(unittest.TestCase):
"""Tests for letsencrypt.crypto_util.valid_privkey."""
@classmethod
def _call(cls, privkey):
from letsencrypt.crypto_util import valid_privkey
return valid_privkey(privkey)
def test_valid_true(self):
self.assertTrue(self._call(RSA256_KEY))
def test_empty_false(self):
self.assertFalse(self._call(''))
def test_random_false(self):
self.assertFalse(self._call('foo bar'))
class GetSANsFromCertTest(unittest.TestCase):
"""Tests for letsencrypt.crypto_util.get_sans_from_cert."""
@classmethod
def _call(cls, *args, **kwargs):
from letsencrypt.crypto_util import get_sans_from_cert
return get_sans_from_cert(*args, **kwargs)
def test_single(self):
self.assertEqual([], self._call(test_util.load_vector('cert.pem')))
def test_san(self):
self.assertEqual(
['example.com', 'www.example.com'],
self._call(test_util.load_vector('cert-san.pem')))
class GetSANsFromCSRTest(unittest.TestCase):
"""Tests for letsencrypt.crypto_util.get_sans_from_csr."""
@classmethod
def _call(cls, *args, **kwargs):
from letsencrypt.crypto_util import get_sans_from_csr
return get_sans_from_csr(*args, **kwargs)
def test_extract_one_san(self):
self.assertEqual(['example.com'], self._call(
test_util.load_vector('csr.pem')))
def test_extract_two_sans(self):
self.assertEqual(['example.com', 'www.example.com'], self._call(
test_util.load_vector('csr-san.pem')))
def test_extract_six_sans(self):
self.assertEqual(self._call(test_util.load_vector('csr-6sans.pem')),
["example.com", "example.org", "example.net",
"example.info", "subdomain.example.com",
"other.subdomain.example.com"])
def test_parse_non_csr(self):
self.assertRaises(OpenSSL.crypto.Error, self._call, "hello there")
def test_parse_no_sans(self):
self.assertEqual(
[], self._call(test_util.load_vector('csr-nosans.pem')))
class CertLoaderTest(unittest.TestCase):
"""Tests for letsencrypt.crypto_util.pyopenssl_load_certificate"""
def test_load_valid_cert(self):
from letsencrypt.crypto_util import pyopenssl_load_certificate
cert, file_type = pyopenssl_load_certificate(CERT)
self.assertEqual(cert.digest('sha1'),
OpenSSL.crypto.load_certificate(file_type, CERT).digest('sha1'))
def test_load_invalid_cert(self):
from letsencrypt.crypto_util import pyopenssl_load_certificate
bad_cert_data = CERT.replace("BEGIN CERTIFICATE", "ASDFASDFASDF!!!")
self.assertRaises(
errors.Error, pyopenssl_load_certificate, bad_cert_data)
class NotBeforeTest(unittest.TestCase):
"""Tests for letsencrypt.crypto_util.notBefore"""
def test_notBefore(self):
from letsencrypt.crypto_util import notBefore
self.assertEqual(notBefore(CERT_PATH).isoformat(),
'2014-12-11T22:34:45+00:00')
class NotAfterTest(unittest.TestCase):
"""Tests for letsencrypt.crypto_util.notAfter"""
def test_notAfter(self):
from letsencrypt.crypto_util import notAfter
self.assertEqual(notAfter(CERT_PATH).isoformat(),
'2014-12-18T22:34:45+00:00')
if __name__ == '__main__':
unittest.main() # pragma: no cover
-1
View File
@@ -1 +0,0 @@
"""Let's Encrypt Display Tests"""
-102
View File
@@ -1,102 +0,0 @@
"""Test letsencrypt.display.completer."""
import os
import readline
import shutil
import string
import sys
import tempfile
import unittest
import mock
from six.moves import reload_module # pylint: disable=import-error
class CompleterTest(unittest.TestCase):
"""Test letsencrypt.display.completer.Completer."""
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
# directories must end with os.sep for completer to
# search inside the directory for possible completions
if self.temp_dir[-1] != os.sep:
self.temp_dir += os.sep
self.paths = []
# create some files and directories in temp_dir
for c in string.ascii_lowercase:
path = os.path.join(self.temp_dir, c)
self.paths.append(path)
if ord(c) % 2:
os.mkdir(path)
else:
with open(path, 'w'):
pass
def tearDown(self):
shutil.rmtree(self.temp_dir)
def test_complete(self):
from letsencrypt.display import completer
my_completer = completer.Completer()
num_paths = len(self.paths)
for i in range(num_paths):
completion = my_completer.complete(self.temp_dir, i)
self.assertTrue(completion in self.paths)
self.paths.remove(completion)
self.assertFalse(self.paths)
completion = my_completer.complete(self.temp_dir, num_paths)
self.assertEqual(completion, None)
def test_import_error(self):
original_readline = sys.modules['readline']
sys.modules['readline'] = None
self.test_context_manager_with_unmocked_readline()
sys.modules['readline'] = original_readline
def test_context_manager_with_unmocked_readline(self):
from letsencrypt.display import completer
reload_module(completer)
original_completer = readline.get_completer()
original_delims = readline.get_completer_delims()
with completer.Completer():
pass
self.assertEqual(readline.get_completer(), original_completer)
self.assertEqual(readline.get_completer_delims(), original_delims)
@mock.patch('letsencrypt.display.completer.readline', autospec=True)
def test_context_manager_libedit(self, mock_readline):
mock_readline.__doc__ = 'libedit'
self._test_context_manager_with_mock_readline(mock_readline)
@mock.patch('letsencrypt.display.completer.readline', autospec=True)
def test_context_manager_readline(self, mock_readline):
mock_readline.__doc__ = 'GNU readline'
self._test_context_manager_with_mock_readline(mock_readline)
def _test_context_manager_with_mock_readline(self, mock_readline):
from letsencrypt.display import completer
mock_readline.parse_and_bind.side_effect = enable_tab_completion
with completer.Completer():
pass
self.assertTrue(mock_readline.parse_and_bind.called)
def enable_tab_completion(unused_command):
"""Enables readline tab completion using the system specific syntax."""
libedit = 'libedit' in readline.__doc__
command = 'bind ^I rl_complete' if libedit else 'tab: complete'
readline.parse_and_bind(command)
if __name__ == "__main__":
unittest.main() # pragma: no cover
@@ -1,57 +0,0 @@
"""Module for enhancement UI."""
import logging
import unittest
import mock
from letsencrypt import errors
from letsencrypt.display import util as display_util
class AskTest(unittest.TestCase):
"""Test the ask method."""
def setUp(self):
logging.disable(logging.CRITICAL)
def tearDown(self):
logging.disable(logging.NOTSET)
@classmethod
def _call(cls, enhancement):
from letsencrypt.display.enhancements import ask
return ask(enhancement)
@mock.patch("letsencrypt.display.enhancements.util")
def test_redirect(self, mock_util):
mock_util().menu.return_value = (display_util.OK, 1)
self.assertTrue(self._call("redirect"))
def test_key_error(self):
self.assertRaises(errors.Error, self._call, "unknown_enhancement")
class RedirectTest(unittest.TestCase):
"""Test the redirect_by_default method."""
@classmethod
def _call(cls):
from letsencrypt.display.enhancements import redirect_by_default
return redirect_by_default()
@mock.patch("letsencrypt.display.enhancements.util")
def test_secure(self, mock_util):
mock_util().menu.return_value = (display_util.OK, 1)
self.assertTrue(self._call())
@mock.patch("letsencrypt.display.enhancements.util")
def test_cancel(self, mock_util):
mock_util().menu.return_value = (display_util.CANCEL, 1)
self.assertFalse(self._call())
@mock.patch("letsencrypt.display.enhancements.util")
def test_easy(self, mock_util):
mock_util().menu.return_value = (display_util.OK, 0)
self.assertFalse(self._call())
if __name__ == "__main__":
unittest.main() # pragma: no cover
-345
View File
@@ -1,345 +0,0 @@
# coding=utf-8
"""Test letsencrypt.display.ops."""
import os
import sys
import tempfile
import unittest
import mock
import zope.component
from acme import jose
from acme import messages
from letsencrypt import account
from letsencrypt import interfaces
from letsencrypt.display import util as display_util
from letsencrypt.tests import test_util
KEY = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem"))
class GetEmailTest(unittest.TestCase):
"""Tests for letsencrypt.display.ops.get_email."""
def setUp(self):
mock_display = mock.MagicMock()
self.input = mock_display.input
zope.component.provideUtility(mock_display, interfaces.IDisplay)
@classmethod
def _call(cls, **kwargs):
from letsencrypt.display.ops import get_email
return get_email(**kwargs)
def test_cancel_none(self):
self.input.return_value = (display_util.CANCEL, "foo@bar.baz")
self.assertTrue(self._call() is None)
def test_ok_safe(self):
self.input.return_value = (display_util.OK, "foo@bar.baz")
with mock.patch("letsencrypt.display.ops.le_util.safe_email") as mock_safe_email:
mock_safe_email.return_value = True
self.assertTrue(self._call() is "foo@bar.baz")
def test_ok_not_safe(self):
self.input.return_value = (display_util.OK, "foo@bar.baz")
with mock.patch("letsencrypt.display.ops.le_util.safe_email") as mock_safe_email:
mock_safe_email.side_effect = [False, True]
self.assertTrue(self._call() is "foo@bar.baz")
def test_more_and_invalid_flags(self):
more_txt = "--register-unsafely-without-email"
invalid_txt = "There seem to be problems"
base_txt = "Enter email"
self.input.return_value = (display_util.OK, "foo@bar.baz")
with mock.patch("letsencrypt.display.ops.le_util.safe_email") as mock_safe_email:
mock_safe_email.return_value = True
self._call()
msg = self.input.call_args[0][0]
self.assertTrue(more_txt not in msg)
self.assertTrue(invalid_txt not in msg)
self.assertTrue(base_txt in msg)
self._call(more=True)
msg = self.input.call_args[0][0]
self.assertTrue(more_txt in msg)
self.assertTrue(invalid_txt not in msg)
self._call(more=True, invalid=True)
msg = self.input.call_args[0][0]
self.assertTrue(more_txt in msg)
self.assertTrue(invalid_txt in msg)
self.assertTrue(base_txt in msg)
class ChooseAccountTest(unittest.TestCase):
"""Tests for letsencrypt.display.ops.choose_account."""
def setUp(self):
zope.component.provideUtility(display_util.FileDisplay(sys.stdout))
self.accounts_dir = tempfile.mkdtemp("accounts")
self.account_keys_dir = os.path.join(self.accounts_dir, "keys")
os.makedirs(self.account_keys_dir, 0o700)
self.config = mock.MagicMock(
accounts_dir=self.accounts_dir,
account_keys_dir=self.account_keys_dir,
server="letsencrypt-demo.org")
self.key = KEY
self.acc1 = account.Account(messages.RegistrationResource(
uri=None, new_authzr_uri=None, body=messages.Registration.from_data(
email="email1@g.com")), self.key)
self.acc2 = account.Account(messages.RegistrationResource(
uri=None, new_authzr_uri=None, body=messages.Registration.from_data(
email="email2@g.com", phone="phone")), self.key)
@classmethod
def _call(cls, accounts):
from letsencrypt.display import ops
return ops.choose_account(accounts)
@mock.patch("letsencrypt.display.ops.z_util")
def test_one(self, mock_util):
mock_util().menu.return_value = (display_util.OK, 0)
self.assertEqual(self._call([self.acc1]), self.acc1)
@mock.patch("letsencrypt.display.ops.z_util")
def test_two(self, mock_util):
mock_util().menu.return_value = (display_util.OK, 1)
self.assertEqual(self._call([self.acc1, self.acc2]), self.acc2)
@mock.patch("letsencrypt.display.ops.z_util")
def test_cancel(self, mock_util):
mock_util().menu.return_value = (display_util.CANCEL, 1)
self.assertTrue(self._call([self.acc1, self.acc2]) is None)
class GenSSLLabURLs(unittest.TestCase):
"""Loose test of _gen_ssl_lab_urls. URL can change easily in the future."""
def setUp(self):
zope.component.provideUtility(display_util.FileDisplay(sys.stdout))
@classmethod
def _call(cls, domains):
from letsencrypt.display.ops import _gen_ssl_lab_urls
return _gen_ssl_lab_urls(domains)
def test_zero(self):
self.assertEqual(self._call([]), [])
def test_two(self):
urls = self._call(["eff.org", "umich.edu"])
self.assertTrue("eff.org" in urls[0])
self.assertTrue("umich.edu" in urls[1])
class GenHttpsNamesTest(unittest.TestCase):
"""Test _gen_https_names."""
def setUp(self):
zope.component.provideUtility(display_util.FileDisplay(sys.stdout))
@classmethod
def _call(cls, domains):
from letsencrypt.display.ops import _gen_https_names
return _gen_https_names(domains)
def test_zero(self):
self.assertEqual(self._call([]), "")
def test_one(self):
doms = [
"example.com",
"asllkjsadfljasdf.c",
]
for dom in doms:
self.assertEqual(self._call([dom]), "https://%s" % dom)
def test_two(self):
domains_list = [
["foo.bar.org", "bar.org"],
["paypal.google.facebook.live.com", "*.zombo.example.com"],
]
for doms in domains_list:
self.assertEqual(
self._call(doms),
"https://{dom[0]} and https://{dom[1]}".format(dom=doms))
def test_three(self):
doms = ["a.org", "b.org", "c.org"]
# We use an oxford comma
self.assertEqual(
self._call(doms),
"https://{dom[0]}, https://{dom[1]}, and https://{dom[2]}".format(
dom=doms))
def test_four(self):
doms = ["a.org", "b.org", "c.org", "d.org"]
exp = ("https://{dom[0]}, https://{dom[1]}, https://{dom[2]}, "
"and https://{dom[3]}".format(dom=doms))
self.assertEqual(self._call(doms), exp)
class ChooseNamesTest(unittest.TestCase):
"""Test choose names."""
def setUp(self):
zope.component.provideUtility(display_util.FileDisplay(sys.stdout))
self.mock_install = mock.MagicMock()
@classmethod
def _call(cls, installer):
from letsencrypt.display.ops import choose_names
return choose_names(installer)
@mock.patch("letsencrypt.display.ops._choose_names_manually")
def test_no_installer(self, mock_manual):
self._call(None)
self.assertEqual(mock_manual.call_count, 1)
@mock.patch("letsencrypt.display.ops.z_util")
def test_no_installer_cancel(self, mock_util):
mock_util().input.return_value = (display_util.CANCEL, [])
self.assertEqual(self._call(None), [])
@mock.patch("letsencrypt.display.ops.z_util")
def test_no_names_choose(self, mock_util):
self.mock_install().get_all_names.return_value = set()
mock_util().yesno.return_value = True
domain = "example.com"
mock_util().input.return_value = (display_util.OK, domain)
actual_doms = self._call(self.mock_install)
self.assertEqual(mock_util().input.call_count, 1)
self.assertEqual(actual_doms, [domain])
@mock.patch("letsencrypt.display.ops.z_util")
def test_no_names_quit(self, mock_util):
self.mock_install().get_all_names.return_value = set()
mock_util().yesno.return_value = False
self.assertEqual(self._call(self.mock_install), [])
@mock.patch("letsencrypt.display.ops.z_util")
def test_filter_names_valid_return(self, mock_util):
self.mock_install.get_all_names.return_value = set(["example.com"])
mock_util().checklist.return_value = (display_util.OK, ["example.com"])
names = self._call(self.mock_install)
self.assertEqual(names, ["example.com"])
self.assertEqual(mock_util().checklist.call_count, 1)
@mock.patch("letsencrypt.display.ops.z_util")
def test_filter_names_nothing_selected(self, mock_util):
self.mock_install.get_all_names.return_value = set(["example.com"])
mock_util().checklist.return_value = (display_util.OK, [])
self.assertEqual(self._call(self.mock_install), [])
@mock.patch("letsencrypt.display.ops.z_util")
def test_filter_names_cancel(self, mock_util):
self.mock_install.get_all_names.return_value = set(["example.com"])
mock_util().checklist.return_value = (
display_util.CANCEL, ["example.com"])
self.assertEqual(self._call(self.mock_install), [])
def test_get_valid_domains(self):
from letsencrypt.display.ops import get_valid_domains
all_valid = ["example.com", "second.example.com",
"also.example.com"]
all_invalid = ["xn--ls8h.tld", "*.wildcard.com", "notFQDN",
"uniçodé.com"]
two_valid = ["example.com", "xn--ls8h.tld", "also.example.com"]
self.assertEqual(get_valid_domains(all_valid), all_valid)
self.assertEqual(get_valid_domains(all_invalid), [])
self.assertEqual(len(get_valid_domains(two_valid)), 2)
@mock.patch("letsencrypt.display.ops.z_util")
def test_choose_manually(self, mock_util):
from letsencrypt.display.ops import _choose_names_manually
# No retry
mock_util().yesno.return_value = False
# IDN and no retry
mock_util().input.return_value = (display_util.OK,
"uniçodé.com")
self.assertEqual(_choose_names_manually(), [])
# IDN exception with previous mocks
with mock.patch(
"letsencrypt.display.ops.display_util.separate_list_input"
) as mock_sli:
unicode_error = UnicodeEncodeError('mock', u'', 0, 1, 'mock')
mock_sli.side_effect = unicode_error
self.assertEqual(_choose_names_manually(), [])
# Punycode and no retry
mock_util().input.return_value = (display_util.OK,
"xn--ls8h.tld")
self.assertEqual(_choose_names_manually(), [])
# non-FQDN and no retry
mock_util().input.return_value = (display_util.OK,
"notFQDN")
self.assertEqual(_choose_names_manually(), [])
# Two valid domains
mock_util().input.return_value = (display_util.OK,
("example.com,"
"valid.example.com"))
self.assertEqual(_choose_names_manually(),
["example.com", "valid.example.com"])
# Three iterations
mock_util().input.return_value = (display_util.OK,
"notFQDN")
yn = mock.MagicMock()
yn.side_effect = [True, True, False]
mock_util().yesno = yn
_choose_names_manually()
self.assertEqual(mock_util().yesno.call_count, 3)
class SuccessInstallationTest(unittest.TestCase):
# pylint: disable=too-few-public-methods
"""Test the success installation message."""
@classmethod
def _call(cls, names):
from letsencrypt.display.ops import success_installation
success_installation(names)
@mock.patch("letsencrypt.display.ops.z_util")
def test_success_installation(self, mock_util):
mock_util().notification.return_value = None
names = ["example.com", "abc.com"]
self._call(names)
self.assertEqual(mock_util().notification.call_count, 1)
arg = mock_util().notification.call_args_list[0][0][0]
for name in names:
self.assertTrue(name in arg)
class SuccessRenewalTest(unittest.TestCase):
# pylint: disable=too-few-public-methods
"""Test the success renewal message."""
@classmethod
def _call(cls, names):
from letsencrypt.display.ops import success_renewal
success_renewal(names, "renew")
@mock.patch("letsencrypt.display.ops.z_util")
def test_success_renewal(self, mock_util):
mock_util().notification.return_value = None
names = ["example.com", "abc.com"]
self._call(names)
self.assertEqual(mock_util().notification.call_count, 1)
arg = mock_util().notification.call_args_list[0][0][0]
for name in names:
self.assertTrue(name in arg)
if __name__ == "__main__":
unittest.main() # pragma: no cover
-393
View File
@@ -1,393 +0,0 @@
"""Test :mod:`letsencrypt.display.util`."""
import os
import unittest
import mock
import letsencrypt.errors as errors
from letsencrypt.display import util as display_util
CHOICES = [("First", "Description1"), ("Second", "Description2")]
TAGS = ["tag1", "tag2", "tag3"]
TAGS_CHOICES = [("1", "tag1"), ("2", "tag2"), ("3", "tag3")]
class NcursesDisplayTest(unittest.TestCase):
"""Test ncurses display.
Since this is mostly a wrapper, it might be more helpful to test the
actual dialog boxes. The test file located in ./tests/display.py
(relative to the root of the repository) will actually display the
various boxes but requires the user to do the verification. If
something seems amiss please use that test script to debug it, the
automatic tests rely on too much mocking.
"""
def setUp(self):
super(NcursesDisplayTest, self).setUp()
self.displayer = display_util.NcursesDisplay()
self.default_menu_options = {
"choices": CHOICES,
"ok_label": "OK",
"cancel_label": "Cancel",
"help_button": False,
"help_label": "",
"width": display_util.WIDTH,
"height": display_util.HEIGHT,
"menu_height": display_util.HEIGHT - 6,
}
@mock.patch("letsencrypt.display.util.dialog.Dialog.msgbox")
def test_notification(self, mock_msgbox):
"""Kind of worthless... one liner."""
self.displayer.notification("message")
self.assertEqual(mock_msgbox.call_count, 1)
@mock.patch("letsencrypt.display.util.dialog.Dialog.menu")
def test_menu_tag_and_desc(self, mock_menu):
mock_menu.return_value = (display_util.OK, "First")
ret = self.displayer.menu("Message", CHOICES)
mock_menu.assert_called_with("Message", **self.default_menu_options)
self.assertEqual(ret, (display_util.OK, 0))
@mock.patch("letsencrypt.display.util.dialog.Dialog.menu")
def test_menu_tag_and_desc_cancel(self, mock_menu):
mock_menu.return_value = (display_util.CANCEL, "")
ret = self.displayer.menu("Message", CHOICES)
mock_menu.assert_called_with("Message", **self.default_menu_options)
self.assertEqual(ret, (display_util.CANCEL, -1))
@mock.patch("letsencrypt.display.util.dialog.Dialog.menu")
def test_menu_desc_only(self, mock_menu):
mock_menu.return_value = (display_util.OK, "1")
ret = self.displayer.menu("Message", TAGS, help_label="More Info")
self.default_menu_options.update(
choices=TAGS_CHOICES, help_button=True, help_label="More Info")
mock_menu.assert_called_with("Message", **self.default_menu_options)
self.assertEqual(ret, (display_util.OK, 0))
@mock.patch("letsencrypt.display.util.dialog.Dialog.menu")
def test_menu_desc_only_help(self, mock_menu):
mock_menu.return_value = (display_util.HELP, "2")
ret = self.displayer.menu("Message", TAGS, help_label="More Info")
self.assertEqual(ret, (display_util.HELP, 1))
@mock.patch("letsencrypt.display.util.dialog.Dialog.menu")
def test_menu_desc_only_cancel(self, mock_menu):
mock_menu.return_value = (display_util.CANCEL, "")
ret = self.displayer.menu("Message", TAGS, help_label="More Info")
self.assertEqual(ret, (display_util.CANCEL, -1))
@mock.patch("letsencrypt.display.util."
"dialog.Dialog.inputbox")
def test_input(self, mock_input):
self.displayer.input("message")
self.assertEqual(mock_input.call_count, 1)
@mock.patch("letsencrypt.display.util.dialog.Dialog.yesno")
def test_yesno(self, mock_yesno):
mock_yesno.return_value = display_util.OK
self.assertTrue(self.displayer.yesno("message"))
mock_yesno.assert_called_with(
"message", display_util.HEIGHT, display_util.WIDTH,
yes_label="Yes", no_label="No")
@mock.patch("letsencrypt.display.util."
"dialog.Dialog.checklist")
def test_checklist(self, mock_checklist):
self.displayer.checklist("message", TAGS)
choices = [
(TAGS[0], "", True),
(TAGS[1], "", True),
(TAGS[2], "", True),
]
mock_checklist.assert_called_with(
"message", width=display_util.WIDTH, height=display_util.HEIGHT,
choices=choices)
@mock.patch("letsencrypt.display.util.dialog.Dialog.dselect")
def test_directory_select(self, mock_dselect):
self.displayer.directory_select("message")
self.assertEqual(mock_dselect.call_count, 1)
class FileOutputDisplayTest(unittest.TestCase):
"""Test stdout display.
Most of this class has to deal with visual output. In order to test how the
functions look to a user, uncomment the test_visual function.
"""
def setUp(self):
super(FileOutputDisplayTest, self).setUp()
self.mock_stdout = mock.MagicMock()
self.displayer = display_util.FileDisplay(self.mock_stdout)
def test_notification_no_pause(self):
self.displayer.notification("message", 10, False)
string = self.mock_stdout.write.call_args[0][0]
self.assertTrue("message" in string)
def test_notification_pause(self):
with mock.patch("__builtin__.raw_input", return_value="enter"):
self.displayer.notification("message")
self.assertTrue("message" in self.mock_stdout.write.call_args[0][0])
@mock.patch("letsencrypt.display.util."
"FileDisplay._get_valid_int_ans")
def test_menu(self, mock_ans):
mock_ans.return_value = (display_util.OK, 1)
ret = self.displayer.menu("message", CHOICES)
self.assertEqual(ret, (display_util.OK, 0))
def test_input_cancel(self):
with mock.patch("__builtin__.raw_input", return_value="c"):
code, _ = self.displayer.input("message")
self.assertTrue(code, display_util.CANCEL)
def test_input_normal(self):
with mock.patch("__builtin__.raw_input", return_value="domain.com"):
code, input_ = self.displayer.input("message")
self.assertEqual(code, display_util.OK)
self.assertEqual(input_, "domain.com")
def test_yesno(self):
with mock.patch("__builtin__.raw_input", return_value="Yes"):
self.assertTrue(self.displayer.yesno("message"))
with mock.patch("__builtin__.raw_input", return_value="y"):
self.assertTrue(self.displayer.yesno("message"))
with mock.patch("__builtin__.raw_input", side_effect=["maybe", "y"]):
self.assertTrue(self.displayer.yesno("message"))
with mock.patch("__builtin__.raw_input", return_value="No"):
self.assertFalse(self.displayer.yesno("message"))
with mock.patch("__builtin__.raw_input", side_effect=["cancel", "n"]):
self.assertFalse(self.displayer.yesno("message"))
with mock.patch("__builtin__.raw_input", return_value="a"):
self.assertTrue(self.displayer.yesno("msg", yes_label="Agree"))
@mock.patch("letsencrypt.display.util.FileDisplay.input")
def test_checklist_valid(self, mock_input):
mock_input.return_value = (display_util.OK, "2 1")
code, tag_list = self.displayer.checklist("msg", TAGS)
self.assertEqual(
(code, set(tag_list)), (display_util.OK, set(["tag1", "tag2"])))
@mock.patch("letsencrypt.display.util.FileDisplay.input")
def test_checklist_miss_valid(self, mock_input):
mock_input.side_effect = [
(display_util.OK, "10"),
(display_util.OK, "tag1 please"),
(display_util.OK, "1")
]
ret = self.displayer.checklist("msg", TAGS)
self.assertEqual(ret, (display_util.OK, ["tag1"]))
@mock.patch("letsencrypt.display.util.FileDisplay.input")
def test_checklist_miss_quit(self, mock_input):
mock_input.side_effect = [
(display_util.OK, "10"),
(display_util.CANCEL, "1")
]
ret = self.displayer.checklist("msg", TAGS)
self.assertEqual(ret, (display_util.CANCEL, []))
def test_scrub_checklist_input_valid(self):
# pylint: disable=protected-access
indices = [
["1"],
["1", "2", "1"],
["2", "3"],
]
exp = [
set(["tag1"]),
set(["tag1", "tag2"]),
set(["tag2", "tag3"]),
]
for i, list_ in enumerate(indices):
set_tags = set(
self.displayer._scrub_checklist_input(list_, TAGS))
self.assertEqual(set_tags, exp[i])
@mock.patch("letsencrypt.display.util.FileDisplay.input")
def test_directory_select(self, mock_input):
message = "msg"
result = (display_util.OK, "/var/www/html",)
mock_input.return_value = result
self.assertEqual(self.displayer.directory_select(message), result)
mock_input.assert_called_once_with(message)
def test_scrub_checklist_input_invalid(self):
# pylint: disable=protected-access
indices = [
["0"],
["4"],
["tag1"],
["1", "tag1"],
["2", "o"]
]
for list_ in indices:
self.assertEqual(
self.displayer._scrub_checklist_input(list_, TAGS), [])
def test_print_menu(self):
# pylint: disable=protected-access
# This is purely cosmetic... just make sure there aren't any exceptions
self.displayer._print_menu("msg", CHOICES)
self.displayer._print_menu("msg", TAGS)
def test_wrap_lines(self):
# pylint: disable=protected-access
msg = ("This is just a weak test{0}"
"This function is only meant to be for easy viewing{0}"
"Test a really really really really really really really really "
"really really really really long line...".format(os.linesep))
text = display_util._wrap_lines(msg)
self.assertEqual(text.count(os.linesep), 3)
def test_get_valid_int_ans_valid(self):
# pylint: disable=protected-access
with mock.patch("__builtin__.raw_input", return_value="1"):
self.assertEqual(
self.displayer._get_valid_int_ans(1), (display_util.OK, 1))
ans = "2"
with mock.patch("__builtin__.raw_input", return_value=ans):
self.assertEqual(
self.displayer._get_valid_int_ans(3),
(display_util.OK, int(ans)))
def test_get_valid_int_ans_invalid(self):
# pylint: disable=protected-access
answers = [
["0", "c"],
["4", "one", "C"],
["c"],
]
for ans in answers:
with mock.patch("__builtin__.raw_input", side_effect=ans):
self.assertEqual(
self.displayer._get_valid_int_ans(3),
(display_util.CANCEL, -1))
class NoninteractiveDisplayTest(unittest.TestCase):
"""Test non-interactive display.
These tests are pretty easy!
"""
def setUp(self):
super(NoninteractiveDisplayTest, self).setUp()
self.mock_stdout = mock.MagicMock()
self.displayer = display_util.NoninteractiveDisplay(self.mock_stdout)
def test_notification_no_pause(self):
self.displayer.notification("message", 10)
string = self.mock_stdout.write.call_args[0][0]
self.assertTrue("message" in string)
def test_input(self):
d = "an incomputable value"
ret = self.displayer.input("message", default=d)
self.assertEqual(ret, (display_util.OK, d))
self.assertRaises(errors.MissingCommandlineFlag, self.displayer.input, "message")
def test_menu(self):
ret = self.displayer.menu("message", CHOICES, default=1)
self.assertEqual(ret, (display_util.OK, 1))
self.assertRaises(errors.MissingCommandlineFlag, self.displayer.menu, "message", CHOICES)
def test_yesno(self):
d = False
ret = self.displayer.yesno("message", default=d)
self.assertEqual(ret, d)
self.assertRaises(errors.MissingCommandlineFlag, self.displayer.yesno, "message")
def test_checklist(self):
d = [1, 3]
ret = self.displayer.checklist("message", TAGS, default=d)
self.assertEqual(ret, (display_util.OK, d))
self.assertRaises(errors.MissingCommandlineFlag, self.displayer.checklist, "message", TAGS)
def test_directory_select(self):
default = "/var/www/html"
expected = (display_util.OK, default)
actual = self.displayer.directory_select("msg", default)
self.assertEqual(expected, actual)
self.assertRaises(
errors.MissingCommandlineFlag, self.displayer.directory_select, "msg")
class SeparateListInputTest(unittest.TestCase):
"""Test Module functions."""
def setUp(self):
self.exp = ["a", "b", "c", "test"]
@classmethod
def _call(cls, input_):
from letsencrypt.display.util import separate_list_input
return separate_list_input(input_)
def test_commas(self):
self.assertEqual(self._call("a,b,c,test"), self.exp)
def test_spaces(self):
self.assertEqual(self._call("a b c test"), self.exp)
def test_both(self):
self.assertEqual(self._call("a, b, c, test"), self.exp)
def test_mess(self):
actual = [
self._call(" a , b c \t test"),
self._call(",a, ,, , b c test "),
self._call(",,,,, , a b,,, , c,test"),
]
for act in actual:
self.assertEqual(act, self.exp)
class PlaceParensTest(unittest.TestCase):
@classmethod
def _call(cls, label): # pylint: disable=protected-access
from letsencrypt.display.util import _parens_around_char
return _parens_around_char(label)
def test_single_letter(self):
self.assertEqual("(a)", self._call("a"))
def test_multiple(self):
self.assertEqual("(L)abel", self._call("Label"))
self.assertEqual("(y)es please", self._call("yes please"))
if __name__ == "__main__":
unittest.main() # pragma: no cover
-71
View File
@@ -1,71 +0,0 @@
"""Tests for letsencrypt.error_handler."""
import signal
import sys
import unittest
import mock
class ErrorHandlerTest(unittest.TestCase):
"""Tests for letsencrypt.error_handler."""
def setUp(self):
from letsencrypt import error_handler
self.init_func = mock.MagicMock()
self.init_args = set((42,))
self.init_kwargs = {'foo': 'bar'}
self.handler = error_handler.ErrorHandler(self.init_func,
*self.init_args,
**self.init_kwargs)
# pylint: disable=protected-access
self.signals = error_handler._SIGNALS
def test_context_manager(self):
try:
with self.handler:
raise ValueError
except ValueError:
pass
self.init_func.assert_called_once_with(*self.init_args,
**self.init_kwargs)
@mock.patch('letsencrypt.error_handler.os')
@mock.patch('letsencrypt.error_handler.signal')
def test_signal_handler(self, mock_signal, mock_os):
# pylint: disable=protected-access
mock_signal.getsignal.return_value = signal.SIG_DFL
self.handler.set_signal_handlers()
signal_handler = self.handler._signal_handler
for signum in self.signals:
mock_signal.signal.assert_any_call(signum, signal_handler)
signum = self.signals[0]
signal_handler(signum, None)
self.init_func.assert_called_once_with(*self.init_args,
**self.init_kwargs)
mock_os.kill.assert_called_once_with(mock_os.getpid(), signum)
self.handler.reset_signal_handlers()
for signum in self.signals:
mock_signal.signal.assert_any_call(signum, signal.SIG_DFL)
def test_bad_recovery(self):
bad_func = mock.MagicMock(side_effect=[ValueError])
self.handler.register(bad_func)
self.handler.call_registered()
self.init_func.assert_called_once_with(*self.init_args,
**self.init_kwargs)
bad_func.assert_called_once_with()
def test_sysexit_ignored(self):
try:
with self.handler:
sys.exit(0)
except SystemExit:
pass
self.assertFalse(self.init_func.called)
if __name__ == "__main__":
unittest.main() # pragma: no cover
-44
View File
@@ -1,44 +0,0 @@
"""Tests for letsencrypt.errors."""
import unittest
import mock
from acme import messages
from letsencrypt import achallenges
from letsencrypt.tests import acme_util
class FaiiledChallengesTest(unittest.TestCase):
"""Tests for letsencrypt.errors.FailedChallenges."""
def setUp(self):
from letsencrypt.errors import FailedChallenges
self.error = FailedChallenges(set([achallenges.DNS(
domain="example.com", challb=messages.ChallengeBody(
chall=acme_util.DNS, uri=None,
error=messages.Error(typ="tls", detail="detail")))]))
def test_str(self):
self.assertTrue(str(self.error).startswith(
"Failed authorization procedure. example.com (dns): tls"))
class StandaloneBindErrorTest(unittest.TestCase):
"""Tests for letsencrypt.errors.StandaloneBindError."""
def setUp(self):
from letsencrypt.errors import StandaloneBindError
self.error = StandaloneBindError(mock.sentinel.error, 1234)
def test_instance_args(self):
self.assertEqual(mock.sentinel.error, self.error.socket_error)
self.assertEqual(1234, self.error.port)
def test_str(self):
self.assertTrue(str(self.error).startswith(
"Problem binding to port 1234: "))
if __name__ == "__main__":
unittest.main() # pragma: no cover
-101
View File
@@ -1,101 +0,0 @@
"""Tests for hooks.py"""
# pylint: disable=protected-access
import os
import unittest
import mock
from letsencrypt import errors
from letsencrypt import hooks
class HookTest(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
@mock.patch('letsencrypt.hooks._prog')
def test_validate_hooks(self, mock_prog):
config = mock.MagicMock(pre_hook="", post_hook="ls -lR", renew_hook="uptime")
hooks.validate_hooks(config)
self.assertEqual(mock_prog.call_count, 2)
self.assertEqual(mock_prog.call_args_list[1][0][0], 'uptime')
self.assertEqual(mock_prog.call_args_list[0][0][0], 'ls')
mock_prog.return_value = None
config = mock.MagicMock(pre_hook="explodinator", post_hook="", renew_hook="")
self.assertRaises(errors.HookCommandNotFound, hooks.validate_hooks, config)
@mock.patch('letsencrypt.hooks._is_exe')
def test_which(self, mock_is_exe):
mock_is_exe.return_value = True
self.assertEqual(hooks._which("/path/to/something"), "/path/to/something")
with mock.patch.dict('os.environ', {"PATH": "/floop:/fleep"}):
mock_is_exe.return_value = True
self.assertEqual(hooks._which("pingify"), "/floop/pingify")
mock_is_exe.return_value = False
self.assertEqual(hooks._which("pingify"), None)
self.assertEqual(hooks._which("/path/to/something"), None)
@mock.patch('letsencrypt.hooks._which')
def test_prog(self, mockwhich):
mockwhich.return_value = "/very/very/funky"
self.assertEqual(hooks._prog("funky"), "funky")
mockwhich.return_value = None
self.assertEqual(hooks._prog("funky"), None)
def _test_a_hook(self, config, hook_function, calls_expected):
with mock.patch('letsencrypt.hooks.logger') as mock_logger:
mock_logger.warning = mock.MagicMock()
with mock.patch('letsencrypt.hooks._run_hook') as mock_run_hook:
hook_function(config)
hook_function(config)
self.assertEqual(mock_run_hook.call_count, calls_expected)
return mock_logger.warning
def test_pre_hook(self):
config = mock.MagicMock(pre_hook="true")
self._test_a_hook(config, hooks.pre_hook, 1)
config = mock.MagicMock(pre_hook="")
self._test_a_hook(config, hooks.pre_hook, 0)
def test_post_hook(self):
config = mock.MagicMock(post_hook="true", verb="splonk")
self._test_a_hook(config, hooks.post_hook, 2)
config = mock.MagicMock(post_hook="true", verb="renew")
self._test_a_hook(config, hooks.post_hook, 0)
def test_renew_hook(self):
with mock.patch.dict('os.environ', {}):
domains = ["a", "b"]
lineage = "thing"
rhook = lambda x: hooks.renew_hook(x, domains, lineage)
config = mock.MagicMock(renew_hook="true", dry_run=False)
self._test_a_hook(config, rhook, 2)
self.assertEqual(os.environ["RENEWED_DOMAINS"], "a b")
self.assertEqual(os.environ["RENEWED_LINEAGE"], "thing")
config = mock.MagicMock(renew_hook="true", dry_run=True)
mock_warn = self._test_a_hook(config, rhook, 0)
self.assertEqual(mock_warn.call_count, 2)
@mock.patch('letsencrypt.hooks.Popen')
def test_run_hook(self, mock_popen):
with mock.patch('letsencrypt.hooks.logger.error') as mock_error:
mock_cmd = mock.MagicMock()
mock_cmd.returncode = 1
mock_cmd.communicate.return_value = ("", "")
mock_popen.return_value = mock_cmd
hooks._run_hook("ls")
self.assertEqual(mock_error.call_count, 1)
with mock.patch('letsencrypt.hooks.logger.error') as mock_error:
mock_cmd.communicate.return_value = ("", "thing")
hooks._run_hook("ls")
self.assertEqual(mock_error.call_count, 2)
if __name__ == '__main__':
unittest.main() # pragma: no cover
-343
View File
@@ -1,343 +0,0 @@
"""Tests for letsencrypt.le_util."""
import argparse
import errno
import os
import shutil
import stat
import tempfile
import unittest
import mock
import six
from letsencrypt import errors
class RunScriptTest(unittest.TestCase):
"""Tests for letsencrypt.le_util.run_script."""
@classmethod
def _call(cls, params):
from letsencrypt.le_util import run_script
return run_script(params)
@mock.patch("letsencrypt.le_util.subprocess.Popen")
def test_default(self, mock_popen):
"""These will be changed soon enough with reload."""
mock_popen().returncode = 0
mock_popen().communicate.return_value = ("stdout", "stderr")
out, err = self._call(["test"])
self.assertEqual(out, "stdout")
self.assertEqual(err, "stderr")
@mock.patch("letsencrypt.le_util.subprocess.Popen")
def test_bad_process(self, mock_popen):
mock_popen.side_effect = OSError
self.assertRaises(errors.SubprocessError, self._call, ["test"])
@mock.patch("letsencrypt.le_util.subprocess.Popen")
def test_failure(self, mock_popen):
mock_popen().communicate.return_value = ("", "")
mock_popen().returncode = 1
self.assertRaises(errors.SubprocessError, self._call, ["test"])
class ExeExistsTest(unittest.TestCase):
"""Tests for letsencrypt.le_util.exe_exists."""
@classmethod
def _call(cls, exe):
from letsencrypt.le_util import exe_exists
return exe_exists(exe)
@mock.patch("letsencrypt.le_util.os.path.isfile")
@mock.patch("letsencrypt.le_util.os.access")
def test_full_path(self, mock_access, mock_isfile):
mock_access.return_value = True
mock_isfile.return_value = True
self.assertTrue(self._call("/path/to/exe"))
@mock.patch("letsencrypt.le_util.os.path.isfile")
@mock.patch("letsencrypt.le_util.os.access")
def test_on_path(self, mock_access, mock_isfile):
mock_access.return_value = True
mock_isfile.return_value = True
self.assertTrue(self._call("exe"))
@mock.patch("letsencrypt.le_util.os.path.isfile")
@mock.patch("letsencrypt.le_util.os.access")
def test_not_found(self, mock_access, mock_isfile):
mock_access.return_value = False
mock_isfile.return_value = True
self.assertFalse(self._call("exe"))
class MakeOrVerifyDirTest(unittest.TestCase):
"""Tests for letsencrypt.le_util.make_or_verify_dir.
Note that it is not possible to test for a wrong directory owner,
as this testing script would have to be run as root.
"""
def setUp(self):
self.root_path = tempfile.mkdtemp()
self.path = os.path.join(self.root_path, "foo")
os.mkdir(self.path, 0o400)
self.uid = os.getuid()
def tearDown(self):
shutil.rmtree(self.root_path, ignore_errors=True)
def _call(self, directory, mode):
from letsencrypt.le_util import make_or_verify_dir
return make_or_verify_dir(directory, mode, self.uid, strict=True)
def test_creates_dir_when_missing(self):
path = os.path.join(self.root_path, "bar")
self._call(path, 0o650)
self.assertTrue(os.path.isdir(path))
self.assertEqual(stat.S_IMODE(os.stat(path).st_mode), 0o650)
def test_existing_correct_mode_does_not_fail(self):
self._call(self.path, 0o400)
self.assertEqual(stat.S_IMODE(os.stat(self.path).st_mode), 0o400)
def test_existing_wrong_mode_fails(self):
self.assertRaises(errors.Error, self._call, self.path, 0o600)
def test_reraises_os_error(self):
with mock.patch.object(os, "makedirs") as makedirs:
makedirs.side_effect = OSError()
self.assertRaises(OSError, self._call, "bar", 12312312)
class CheckPermissionsTest(unittest.TestCase):
"""Tests for letsencrypt.le_util.check_permissions.
Note that it is not possible to test for a wrong file owner,
as this testing script would have to be run as root.
"""
def setUp(self):
_, self.path = tempfile.mkstemp()
self.uid = os.getuid()
def tearDown(self):
os.remove(self.path)
def _call(self, mode):
from letsencrypt.le_util import check_permissions
return check_permissions(self.path, mode, self.uid)
def test_ok_mode(self):
os.chmod(self.path, 0o600)
self.assertTrue(self._call(0o600))
def test_wrong_mode(self):
os.chmod(self.path, 0o400)
self.assertFalse(self._call(0o600))
class UniqueFileTest(unittest.TestCase):
"""Tests for letsencrypt.le_util.unique_file."""
def setUp(self):
self.root_path = tempfile.mkdtemp()
self.default_name = os.path.join(self.root_path, "foo.txt")
def tearDown(self):
shutil.rmtree(self.root_path, ignore_errors=True)
def _call(self, mode=0o600):
from letsencrypt.le_util import unique_file
return unique_file(self.default_name, mode)
def test_returns_fd_for_writing(self):
fd, name = self._call()
fd.write("bar")
fd.close()
self.assertEqual(open(name).read(), "bar")
def test_right_mode(self):
self.assertEqual(0o700, os.stat(self._call(0o700)[1]).st_mode & 0o777)
self.assertEqual(0o100, os.stat(self._call(0o100)[1]).st_mode & 0o777)
def test_default_exists(self):
name1 = self._call()[1] # create 0000_foo.txt
name2 = self._call()[1]
name3 = self._call()[1]
self.assertNotEqual(name1, name2)
self.assertNotEqual(name1, name3)
self.assertNotEqual(name2, name3)
self.assertEqual(os.path.dirname(name1), self.root_path)
self.assertEqual(os.path.dirname(name2), self.root_path)
self.assertEqual(os.path.dirname(name3), self.root_path)
basename1 = os.path.basename(name2)
self.assertTrue(basename1.endswith("foo.txt"))
basename2 = os.path.basename(name2)
self.assertTrue(basename2.endswith("foo.txt"))
basename3 = os.path.basename(name3)
self.assertTrue(basename3.endswith("foo.txt"))
class UniqueLineageNameTest(unittest.TestCase):
"""Tests for letsencrypt.le_util.unique_lineage_name."""
def setUp(self):
self.root_path = tempfile.mkdtemp()
def tearDown(self):
shutil.rmtree(self.root_path, ignore_errors=True)
def _call(self, filename, mode=0o777):
from letsencrypt.le_util import unique_lineage_name
return unique_lineage_name(self.root_path, filename, mode)
def test_basic(self):
f, path = self._call("wow")
self.assertTrue(isinstance(f, file))
self.assertEqual(os.path.join(self.root_path, "wow.conf"), path)
def test_multiple(self):
for _ in xrange(10):
f, name = self._call("wow")
self.assertTrue(isinstance(f, file))
self.assertTrue(isinstance(name, str))
self.assertTrue("wow-0009.conf" in name)
@mock.patch("letsencrypt.le_util.os.fdopen")
def test_failure(self, mock_fdopen):
err = OSError("whoops")
err.errno = errno.EIO
mock_fdopen.side_effect = err
self.assertRaises(OSError, self._call, "wow")
@mock.patch("letsencrypt.le_util.os.fdopen")
def test_subsequent_failure(self, mock_fdopen):
self._call("wow")
err = OSError("whoops")
err.errno = errno.EIO
mock_fdopen.side_effect = err
self.assertRaises(OSError, self._call, "wow")
class SafelyRemoveTest(unittest.TestCase):
"""Tests for letsencrypt.le_util.safely_remove."""
def setUp(self):
self.tmp = tempfile.mkdtemp()
self.path = os.path.join(self.tmp, "foo")
def tearDown(self):
shutil.rmtree(self.tmp)
def _call(self):
from letsencrypt.le_util import safely_remove
return safely_remove(self.path)
def test_exists(self):
with open(self.path, "w"):
pass # just create the file
self._call()
self.assertFalse(os.path.exists(self.path))
def test_missing(self):
self._call()
# no error, yay!
self.assertFalse(os.path.exists(self.path))
@mock.patch("letsencrypt.le_util.os.remove")
def test_other_error_passthrough(self, mock_remove):
mock_remove.side_effect = OSError
self.assertRaises(OSError, self._call)
class SafeEmailTest(unittest.TestCase):
"""Test safe_email."""
@classmethod
def _call(cls, addr):
from letsencrypt.le_util import safe_email
return safe_email(addr)
def test_valid_emails(self):
addrs = [
"letsencrypt@letsencrypt.org",
"tbd.ade@gmail.com",
"abc_def.jdk@hotmail.museum",
]
for addr in addrs:
self.assertTrue(self._call(addr), "%s failed." % addr)
def test_invalid_emails(self):
addrs = [
"letsencrypt@letsencrypt..org",
".tbd.ade@gmail.com",
"~/abc_def.jdk@hotmail.museum",
]
for addr in addrs:
self.assertFalse(self._call(addr), "%s failed." % addr)
class AddDeprecatedArgumentTest(unittest.TestCase):
"""Test add_deprecated_argument."""
def setUp(self):
self.parser = argparse.ArgumentParser()
def _call(self, argument_name, nargs):
from letsencrypt.le_util import add_deprecated_argument
add_deprecated_argument(self.parser.add_argument, argument_name, nargs)
def test_warning_no_arg(self):
self._call("--old-option", 0)
stderr = self._get_argparse_warnings(["--old-option"])
self.assertTrue("--old-option is deprecated" in stderr)
def test_warning_with_arg(self):
self._call("--old-option", 1)
stderr = self._get_argparse_warnings(["--old-option", "42"])
self.assertTrue("--old-option is deprecated" in stderr)
def _get_argparse_warnings(self, args):
stderr = six.StringIO()
with mock.patch("letsencrypt.le_util.sys.stderr", new=stderr):
self.parser.parse_args(args)
return stderr.getvalue()
def test_help(self):
self._call("--old-option", 2)
stdout = six.StringIO()
with mock.patch("letsencrypt.le_util.sys.stdout", new=stdout):
try:
self.parser.parse_args(["-h"])
except SystemExit:
pass
self.assertTrue("--old-option" not in stdout.getvalue())
class EnforceDomainSanityTest(unittest.TestCase):
"""Test enforce_domain_sanity."""
def _call(self, domain):
from letsencrypt.le_util import enforce_domain_sanity
return enforce_domain_sanity(domain)
def test_nonascii_str(self):
self.assertRaises(errors.ConfigurationError, self._call,
u"eichh\u00f6rnchen.example.com".encode("utf-8"))
def test_nonascii_unicode(self):
self.assertRaises(errors.ConfigurationError, self._call,
u"eichh\u00f6rnchen.example.com")
if __name__ == "__main__":
unittest.main() # pragma: no cover
-48
View File
@@ -1,48 +0,0 @@
"""Tests for letsencrypt.log."""
import logging
import unittest
import mock
class DialogHandlerTest(unittest.TestCase):
def setUp(self):
self.d = mock.MagicMock()
from letsencrypt.log import DialogHandler
self.handler = DialogHandler(height=2, width=6, d=self.d)
self.handler.PADDING_HEIGHT = 2
self.handler.PADDING_WIDTH = 4
def test_adds_padding(self):
self.handler.emit(logging.makeLogRecord({}))
self.d.infobox.assert_called_once_with(mock.ANY, 4, 10)
def test_args_in_msg_get_replaced(self):
assert len('123456') <= self.handler.width
self.handler.emit(logging.makeLogRecord(
{'msg': '123%s', 'args': (456,)}))
self.d.infobox.assert_called_once_with('123456', mock.ANY, mock.ANY)
def test_wraps_nospace_is_greedy(self):
assert len('1234567') > self.handler.width
self.handler.emit(logging.makeLogRecord({'msg': '1234567'}))
self.d.infobox.assert_called_once_with('123456\n7', mock.ANY, mock.ANY)
def test_wraps_at_whitespace(self):
assert len('123 567') > self.handler.width
self.handler.emit(logging.makeLogRecord({'msg': '123 567'}))
self.d.infobox.assert_called_once_with('123\n567', mock.ANY, mock.ANY)
def test_only_last_lines_are_printed(self):
assert len('a\nb\nc'.split()) > self.handler.height
self.handler.emit(logging.makeLogRecord({'msg': 'a\n\nb\nc'}))
self.d.infobox.assert_called_once_with('b\nc', mock.ANY, mock.ANY)
def test_non_str(self):
self.handler.emit(logging.makeLogRecord({'msg': {'foo': 'bar'}}))
if __name__ == '__main__':
unittest.main() # pragma: no cover
-52
View File
@@ -1,52 +0,0 @@
"""Tests for letsencrypt.notify."""
import socket
import unittest
import mock
class NotifyTests(unittest.TestCase):
"""Tests for the notifier."""
@mock.patch("letsencrypt.notify.smtplib.LMTP")
def test_smtp_success(self, mock_lmtp):
from letsencrypt.notify import notify
lmtp_obj = mock.MagicMock()
mock_lmtp.return_value = lmtp_obj
self.assertTrue(notify("Goose", "auntrhody@example.com",
"The old grey goose is dead."))
self.assertEqual(lmtp_obj.connect.call_count, 1)
self.assertEqual(lmtp_obj.sendmail.call_count, 1)
@mock.patch("letsencrypt.notify.smtplib.LMTP")
@mock.patch("letsencrypt.notify.subprocess.Popen")
def test_smtp_failure(self, mock_popen, mock_lmtp):
from letsencrypt.notify import notify
lmtp_obj = mock.MagicMock()
mock_lmtp.return_value = lmtp_obj
lmtp_obj.sendmail.side_effect = socket.error(17)
proc = mock.MagicMock()
mock_popen.return_value = proc
self.assertTrue(notify("Goose", "auntrhody@example.com",
"The old grey goose is dead."))
self.assertEqual(lmtp_obj.sendmail.call_count, 1)
self.assertEqual(proc.communicate.call_count, 1)
@mock.patch("letsencrypt.notify.smtplib.LMTP")
@mock.patch("letsencrypt.notify.subprocess.Popen")
def test_everything_fails(self, mock_popen, mock_lmtp):
from letsencrypt.notify import notify
lmtp_obj = mock.MagicMock()
mock_lmtp.return_value = lmtp_obj
lmtp_obj.sendmail.side_effect = socket.error(17)
proc = mock.MagicMock()
mock_popen.return_value = proc
proc.communicate.side_effect = OSError("What we have here is a "
"failure to communicate.")
self.assertFalse(notify("Goose", "auntrhody@example.com",
"The old grey goose is dead."))
self.assertEqual(lmtp_obj.sendmail.call_count, 1)
self.assertEqual(proc.communicate.call_count, 1)
if __name__ == "__main__":
unittest.main() # pragma: no cover
-95
View File
@@ -1,95 +0,0 @@
"""Tests for letsencrypt.reporter."""
import mock
import sys
import unittest
import six
class ReporterTest(unittest.TestCase):
"""Tests for letsencrypt.reporter.Reporter."""
def setUp(self):
from letsencrypt import reporter
self.reporter = reporter.Reporter(mock.MagicMock(quiet=False))
self.old_stdout = sys.stdout
sys.stdout = six.StringIO()
def tearDown(self):
sys.stdout = self.old_stdout
def test_multiline_message(self):
self.reporter.add_message("Line 1\nLine 2", self.reporter.LOW_PRIORITY)
self.reporter.atexit_print_messages()
output = sys.stdout.getvalue()
self.assertTrue("Line 1\n" in output)
self.assertTrue("Line 2" in output)
def test_tty_print_empty(self):
sys.stdout.isatty = lambda: True
self.test_no_tty_print_empty()
def test_no_tty_print_empty(self):
self.reporter.print_messages()
self.assertEqual(sys.stdout.getvalue(), "")
try:
raise ValueError
except ValueError:
self.reporter.print_messages()
self.assertEqual(sys.stdout.getvalue(), "")
def test_atexit_print_messages(self):
self._add_messages()
self.reporter.atexit_print_messages()
output = sys.stdout.getvalue()
self.assertTrue("IMPORTANT NOTES:" in output)
self.assertTrue("High" in output)
self.assertTrue("Med" in output)
self.assertTrue("Low" in output)
def test_tty_successful_exit(self):
sys.stdout.isatty = lambda: True
self._successful_exit_common()
def test_no_tty_successful_exit(self):
self._successful_exit_common()
def test_tty_unsuccessful_exit(self):
sys.stdout.isatty = lambda: True
self._unsuccessful_exit_common()
def test_no_tty_unsuccessful_exit(self):
self._unsuccessful_exit_common()
def _successful_exit_common(self):
self._add_messages()
self.reporter.print_messages()
output = sys.stdout.getvalue()
self.assertTrue("IMPORTANT NOTES:" in output)
self.assertTrue("High" in output)
self.assertTrue("Med" in output)
self.assertTrue("Low" in output)
def _unsuccessful_exit_common(self):
self._add_messages()
try:
raise ValueError
except ValueError:
self.reporter.print_messages()
output = sys.stdout.getvalue()
self.assertTrue("IMPORTANT NOTES:" in output)
self.assertTrue("High" in output)
self.assertTrue("Med" not in output)
self.assertTrue("Low" not in output)
def _add_messages(self):
self.reporter.add_message("High", self.reporter.HIGH_PRIORITY)
self.reporter.add_message(
"Med", self.reporter.MEDIUM_PRIORITY, on_crash=False)
self.reporter.add_message(
"Low", self.reporter.LOW_PRIORITY, on_crash=False)
if __name__ == "__main__":
unittest.main() # pragma: no cover
-493
View File
@@ -1,493 +0,0 @@
"""Test letsencrypt.reverter."""
import csv
import itertools
import logging
import os
import shutil
import tempfile
import unittest
import mock
from letsencrypt import errors
class ReverterCheckpointLocalTest(unittest.TestCase):
# pylint: disable=too-many-instance-attributes, too-many-public-methods
"""Test the Reverter Class."""
def setUp(self):
from letsencrypt.reverter import Reverter
# Disable spurious errors... we are trying to test for them
logging.disable(logging.CRITICAL)
self.config = setup_work_direc()
self.reverter = Reverter(self.config)
tup = setup_test_files()
self.config1, self.config2, self.dir1, self.dir2, self.sets = tup
def tearDown(self):
shutil.rmtree(self.config.work_dir)
shutil.rmtree(self.dir1)
shutil.rmtree(self.dir2)
logging.disable(logging.NOTSET)
def test_basic_add_to_temp_checkpoint(self):
# These shouldn't conflict even though they are both named config.txt
self.reverter.add_to_temp_checkpoint(self.sets[0], "save1")
self.reverter.add_to_temp_checkpoint(self.sets[1], "save2")
self.assertTrue(os.path.isdir(self.config.temp_checkpoint_dir))
self.assertEqual(get_save_notes(
self.config.temp_checkpoint_dir), "save1save2")
self.assertFalse(os.path.isfile(
os.path.join(self.config.temp_checkpoint_dir, "NEW_FILES")))
self.assertEqual(
get_filepaths(self.config.temp_checkpoint_dir),
"{0}\n{1}\n".format(self.config1, self.config2))
def test_add_to_checkpoint_copy_failure(self):
with mock.patch("letsencrypt.reverter.shutil.copy2") as mock_copy2:
mock_copy2.side_effect = IOError("bad copy")
self.assertRaises(
errors.ReverterError, self.reverter.add_to_checkpoint,
self.sets[0], "save1")
def test_checkpoint_conflict(self):
"""Make sure that checkpoint errors are thrown appropriately."""
config3 = os.path.join(self.dir1, "config3.txt")
self.reverter.register_file_creation(True, config3)
update_file(config3, "This is a new file!")
self.reverter.add_to_checkpoint(self.sets[2], "save1")
# This shouldn't throw an error
self.reverter.add_to_temp_checkpoint(self.sets[0], "save2")
# Raise error
self.assertRaises(errors.ReverterError, self.reverter.add_to_checkpoint,
self.sets[2], "save3")
# Should not cause an error
self.reverter.add_to_checkpoint(self.sets[1], "save4")
# Check to make sure new files are also checked...
self.assertRaises(errors.ReverterError, self.reverter.add_to_checkpoint,
set([config3]), "invalid save")
def test_multiple_saves_and_temp_revert(self):
self.reverter.add_to_temp_checkpoint(self.sets[0], "save1")
update_file(self.config1, "updated-directive")
self.reverter.add_to_temp_checkpoint(self.sets[0], "save2-updated dir")
update_file(self.config1, "new directive change that we won't keep")
self.reverter.revert_temporary_config()
self.assertEqual(read_in(self.config1), "directive-dir1")
def test_multiple_registration_fail_and_revert(self):
config3 = os.path.join(self.dir1, "config3.txt")
update_file(config3, "Config3")
config4 = os.path.join(self.dir2, "config4.txt")
update_file(config4, "Config4")
# Test multiple registrations and two registrations at once
self.reverter.register_file_creation(True, self.config1)
self.reverter.register_file_creation(True, self.config2)
self.reverter.register_file_creation(True, config3, config4)
# Simulate Let's Encrypt crash... recovery routine is run
self.reverter.recovery_routine()
self.assertFalse(os.path.isfile(self.config1))
self.assertFalse(os.path.isfile(self.config2))
self.assertFalse(os.path.isfile(config3))
self.assertFalse(os.path.isfile(config4))
def test_multiple_registration_same_file(self):
self.reverter.register_file_creation(True, self.config1)
self.reverter.register_file_creation(True, self.config1)
self.reverter.register_file_creation(True, self.config1)
self.reverter.register_file_creation(True, self.config1)
files = get_new_files(self.config.temp_checkpoint_dir)
self.assertEqual(len(files), 1)
def test_register_file_creation_write_error(self):
m_open = mock.mock_open()
with mock.patch("letsencrypt.reverter.open", m_open, create=True):
m_open.side_effect = OSError("bad open")
self.assertRaises(
errors.ReverterError, self.reverter.register_file_creation,
True, self.config1)
def test_bad_registration(self):
# Made this mistake and want to make sure it doesn't happen again...
self.assertRaises(
errors.ReverterError, self.reverter.register_file_creation,
"filepath")
def test_register_undo_command(self):
coms = [
["a2dismod", "ssl"],
["a2dismod", "rewrite"],
["cleanslate"]
]
for com in coms:
self.reverter.register_undo_command(True, com)
act_coms = get_undo_commands(self.config.temp_checkpoint_dir)
for a_com, com in itertools.izip(act_coms, coms):
self.assertEqual(a_com, com)
def test_bad_register_undo_command(self):
m_open = mock.mock_open()
with mock.patch("letsencrypt.reverter.open", m_open, create=True):
m_open.side_effect = OSError("bad open")
self.assertRaises(
errors.ReverterError, self.reverter.register_undo_command,
True, ["command"])
@mock.patch("letsencrypt.le_util.run_script")
def test_run_undo_commands(self, mock_run):
mock_run.side_effect = ["", errors.SubprocessError]
coms = [
["invalid_command"],
["a2dismod", "ssl"],
]
for com in coms:
self.reverter.register_undo_command(True, com)
self.reverter.revert_temporary_config()
self.assertEqual(mock_run.call_count, 2)
def test_recovery_routine_in_progress_failure(self):
self.reverter.add_to_checkpoint(self.sets[0], "perm save")
# pylint: disable=protected-access
self.reverter._recover_checkpoint = mock.MagicMock(
side_effect=errors.ReverterError)
self.assertRaises(errors.ReverterError, self.reverter.recovery_routine)
def test_recover_checkpoint_revert_temp_failures(self):
mock_recover = mock.MagicMock(
side_effect=errors.ReverterError("e"))
# pylint: disable=protected-access
self.reverter._recover_checkpoint = mock_recover
self.reverter.add_to_temp_checkpoint(self.sets[0], "config1 save")
self.assertRaises(
errors.ReverterError, self.reverter.revert_temporary_config)
def test_recover_checkpoint_rollback_failure(self):
mock_recover = mock.MagicMock(
side_effect=errors.ReverterError("e"))
# pylint: disable=protected-access
self.reverter._recover_checkpoint = mock_recover
self.reverter.add_to_checkpoint(self.sets[0], "config1 save")
self.reverter.finalize_checkpoint("Title")
self.assertRaises(
errors.ReverterError, self.reverter.rollback_checkpoints, 1)
def test_recover_checkpoint_copy_failure(self):
self.reverter.add_to_temp_checkpoint(self.sets[0], "save1")
with mock.patch("letsencrypt.reverter.shutil.copy2") as mock_copy2:
mock_copy2.side_effect = OSError("bad copy")
self.assertRaises(
errors.ReverterError, self.reverter.revert_temporary_config)
def test_recover_checkpoint_rm_failure(self):
self.reverter.add_to_temp_checkpoint(self.sets[0], "temp save")
with mock.patch("letsencrypt.reverter.shutil.rmtree") as mock_rmtree:
mock_rmtree.side_effect = OSError("Cannot remove tree")
self.assertRaises(
errors.ReverterError, self.reverter.revert_temporary_config)
@mock.patch("letsencrypt.reverter.logger.warning")
def test_recover_checkpoint_missing_new_files(self, mock_warn):
self.reverter.register_file_creation(
True, os.path.join(self.dir1, "missing_file.txt"))
self.reverter.revert_temporary_config()
self.assertEqual(mock_warn.call_count, 1)
@mock.patch("letsencrypt.reverter.os.remove")
def test_recover_checkpoint_remove_failure(self, mock_remove):
self.reverter.register_file_creation(True, self.config1)
mock_remove.side_effect = OSError("Can't remove")
self.assertRaises(
errors.ReverterError, self.reverter.revert_temporary_config)
def test_recovery_routine_temp_and_perm(self):
# Register a new perm checkpoint file
config3 = os.path.join(self.dir1, "config3.txt")
self.reverter.register_file_creation(False, config3)
update_file(config3, "This is a new perm file!")
# Add changes to perm checkpoint
self.reverter.add_to_checkpoint(self.sets[0], "perm save1")
update_file(self.config1, "updated perm config1")
self.reverter.add_to_checkpoint(self.sets[1], "perm save2")
update_file(self.config2, "updated perm config2")
# Add changes to a temporary checkpoint
self.reverter.add_to_temp_checkpoint(self.sets[0], "temp save1")
update_file(self.config1, "second update now temp config1")
# Register a new temp checkpoint file
config4 = os.path.join(self.dir2, "config4.txt")
self.reverter.register_file_creation(True, config4)
update_file(config4, "New temporary file!")
# Now erase everything
self.reverter.recovery_routine()
# Now Run tests
# These were new files.. they should be removed
self.assertFalse(os.path.isfile(config3))
self.assertFalse(os.path.isfile(config4))
# Check to make sure everything got rolled back appropriately
self.assertEqual(read_in(self.config1), "directive-dir1")
self.assertEqual(read_in(self.config2), "directive-dir2")
class TestFullCheckpointsReverter(unittest.TestCase):
# pylint: disable=too-many-instance-attributes
"""Tests functions having to deal with full checkpoints."""
def setUp(self):
from letsencrypt.reverter import Reverter
# Disable spurious errors...
logging.disable(logging.CRITICAL)
self.config = setup_work_direc()
self.reverter = Reverter(self.config)
tup = setup_test_files()
self.config1, self.config2, self.dir1, self.dir2, self.sets = tup
def tearDown(self):
shutil.rmtree(self.config.work_dir)
shutil.rmtree(self.dir1)
shutil.rmtree(self.dir2)
logging.disable(logging.NOTSET)
def test_rollback_improper_inputs(self):
self.assertRaises(
errors.ReverterError, self.reverter.rollback_checkpoints, "-1")
self.assertRaises(
errors.ReverterError, self.reverter.rollback_checkpoints, -1000)
self.assertRaises(
errors.ReverterError, self.reverter.rollback_checkpoints, "one")
def test_rollback_finalize_checkpoint_valid_inputs(self):
config3 = self._setup_three_checkpoints()
# Check resulting backup directory
self.assertEqual(len(os.listdir(self.config.backup_dir)), 3)
# Check rollbacks
# First rollback
self.reverter.rollback_checkpoints(1)
self.assertEqual(read_in(self.config1), "update config1")
self.assertEqual(read_in(self.config2), "update config2")
# config3 was not included in checkpoint
self.assertEqual(read_in(config3), "Final form config3")
# Second rollback
self.reverter.rollback_checkpoints(1)
self.assertEqual(read_in(self.config1), "update config1")
self.assertEqual(read_in(self.config2), "directive-dir2")
self.assertFalse(os.path.isfile(config3))
# One dir left... check title
all_dirs = os.listdir(self.config.backup_dir)
self.assertEqual(len(all_dirs), 1)
self.assertTrue(
"First Checkpoint" in get_save_notes(
os.path.join(self.config.backup_dir, all_dirs[0])))
# Final rollback
self.reverter.rollback_checkpoints(1)
self.assertEqual(read_in(self.config1), "directive-dir1")
def test_finalize_checkpoint_no_in_progress(self):
# No need to warn for this... just make sure there are no errors.
self.reverter.finalize_checkpoint("No checkpoint...")
@mock.patch("letsencrypt.reverter.shutil.move")
def test_finalize_checkpoint_cannot_title(self, mock_move):
self.reverter.add_to_checkpoint(self.sets[0], "perm save")
mock_move.side_effect = OSError("cannot move")
self.assertRaises(
errors.ReverterError, self.reverter.finalize_checkpoint, "Title")
@mock.patch("letsencrypt.reverter.os.rename")
def test_finalize_checkpoint_no_rename_directory(self, mock_rename):
self.reverter.add_to_checkpoint(self.sets[0], "perm save")
mock_rename.side_effect = OSError
self.assertRaises(
errors.ReverterError, self.reverter.finalize_checkpoint, "Title")
@mock.patch("letsencrypt.reverter.logger")
def test_rollback_too_many(self, mock_logger):
# Test no exist warning...
self.reverter.rollback_checkpoints(1)
self.assertEqual(mock_logger.warning.call_count, 1)
# Test Generic warning
mock_logger.warning.call_count = 0
self._setup_three_checkpoints()
self.reverter.rollback_checkpoints(4)
self.assertEqual(mock_logger.warning.call_count, 1)
def test_multi_rollback(self):
config3 = self._setup_three_checkpoints()
self.reverter.rollback_checkpoints(3)
self.assertEqual(read_in(self.config1), "directive-dir1")
self.assertEqual(read_in(self.config2), "directive-dir2")
self.assertFalse(os.path.isfile(config3))
@mock.patch("letsencrypt.reverter.zope.component.getUtility")
def test_view_config_changes(self, mock_output):
"""This is not strict as this is subject to change."""
self._setup_three_checkpoints()
# Make sure it doesn't throw any errors
self.reverter.view_config_changes()
# Make sure notification is output
self.assertEqual(mock_output().notification.call_count, 1)
@mock.patch("letsencrypt.reverter.logger")
def test_view_config_changes_no_backups(self, mock_logger):
self.reverter.view_config_changes()
self.assertTrue(mock_logger.info.call_count > 0)
def test_view_config_changes_bad_backups_dir(self):
# There shouldn't be any "in progess directories when this is called
# It must just be clean checkpoints
os.makedirs(os.path.join(self.config.backup_dir, "in_progress"))
self.assertRaises(
errors.ReverterError, self.reverter.view_config_changes)
def test_view_config_changes_for_logging(self):
self._setup_three_checkpoints()
config_changes = self.reverter.view_config_changes(for_logging=True)
self.assertTrue("First Checkpoint" in config_changes)
self.assertTrue("Second Checkpoint" in config_changes)
self.assertTrue("Third Checkpoint" in config_changes)
def _setup_three_checkpoints(self):
"""Generate some finalized checkpoints."""
# Checkpoint1 - config1
self.reverter.add_to_checkpoint(self.sets[0], "first save")
self.reverter.finalize_checkpoint("First Checkpoint")
update_file(self.config1, "update config1")
# Checkpoint2 - new file config3, update config2
config3 = os.path.join(self.dir1, "config3.txt")
self.reverter.register_file_creation(False, config3)
update_file(config3, "directive-config3")
self.reverter.add_to_checkpoint(self.sets[1], "second save")
self.reverter.finalize_checkpoint("Second Checkpoint")
update_file(self.config2, "update config2")
update_file(config3, "update config3")
# Checkpoint3 - update config1, config2
self.reverter.add_to_checkpoint(self.sets[2], "third save")
self.reverter.finalize_checkpoint("Third Checkpoint - Save both")
update_file(self.config1, "Final form config1")
update_file(self.config2, "Final form config2")
update_file(config3, "Final form config3")
return config3
def setup_work_direc():
"""Setup directories.
:returns: Mocked :class:`letsencrypt.interfaces.IConfig`
"""
work_dir = tempfile.mkdtemp("work")
backup_dir = os.path.join(work_dir, "backup")
return mock.MagicMock(
work_dir=work_dir, backup_dir=backup_dir,
temp_checkpoint_dir=os.path.join(work_dir, "temp"),
in_progress_dir=os.path.join(backup_dir, "in_progress_dir"))
def setup_test_files():
"""Setup sample configuration files."""
dir1 = tempfile.mkdtemp("dir1")
dir2 = tempfile.mkdtemp("dir2")
config1 = os.path.join(dir1, "config.txt")
config2 = os.path.join(dir2, "config.txt")
with open(config1, "w") as file_fd:
file_fd.write("directive-dir1")
with open(config2, "w") as file_fd:
file_fd.write("directive-dir2")
sets = [set([config1]),
set([config2]),
set([config1, config2])]
return config1, config2, dir1, dir2, sets
def get_save_notes(dire):
"""Read save notes"""
return read_in(os.path.join(dire, "CHANGES_SINCE"))
def get_filepaths(dire):
"""Get Filepaths"""
return read_in(os.path.join(dire, "FILEPATHS"))
def get_new_files(dire):
"""Get new files."""
return read_in(os.path.join(dire, "NEW_FILES")).splitlines()
def get_undo_commands(dire):
"""Get new files."""
with open(os.path.join(dire, "COMMANDS")) as csvfile:
return list(csv.reader(csvfile))
def read_in(path):
"""Read in a file, return the str"""
with open(path, "r") as file_fd:
return file_fd.read()
def update_file(filename, string):
"""Update a file with a new value."""
with open(filename, "w") as file_fd:
file_fd.write(string)
if __name__ == "__main__":
unittest.main() # pragma: no cover
-770
View File
@@ -1,770 +0,0 @@
"""Tests for letsencrypt.storage."""
# pylint disable=protected-access
import datetime
import os
import shutil
import tempfile
import unittest
import configobj
import mock
import pytz
from letsencrypt import configuration
from letsencrypt import errors
from letsencrypt.storage import ALL_FOUR
from letsencrypt.tests import test_util
CERT = test_util.load_cert('cert.pem')
def unlink_all(rc_object):
"""Unlink all four items associated with this RenewableCert."""
for kind in ALL_FOUR:
os.unlink(getattr(rc_object, kind))
def fill_with_sample_data(rc_object):
"""Put dummy data into all four files of this RenewableCert."""
for kind in ALL_FOUR:
with open(getattr(rc_object, kind), "w") as f:
f.write(kind)
class BaseRenewableCertTest(unittest.TestCase):
"""Base class for setting up Renewable Cert tests.
.. note:: It may be required to write out self.config for
your test. Check :class:`.cli_test.DuplicateCertTest` for an example.
"""
def setUp(self):
from letsencrypt import storage
self.tempdir = tempfile.mkdtemp()
self.cli_config = configuration.RenewerConfiguration(
namespace=mock.MagicMock(
config_dir=self.tempdir,
work_dir=self.tempdir,
logs_dir=self.tempdir,
)
)
# TODO: maybe provide RenewerConfiguration.make_dirs?
# TODO: main() should create those dirs, c.f. #902
os.makedirs(os.path.join(self.tempdir, "live", "example.org"))
os.makedirs(os.path.join(self.tempdir, "archive", "example.org"))
os.makedirs(os.path.join(self.tempdir, "renewal"))
config = configobj.ConfigObj()
for kind in ALL_FOUR:
config[kind] = os.path.join(self.tempdir, "live", "example.org",
kind + ".pem")
config.filename = os.path.join(self.tempdir, "renewal",
"example.org.conf")
config.write()
self.config = config
# We also create a file that isn't a renewal config in the same
# location to test that logic that reads in all-and-only renewal
# configs will ignore it and NOT attempt to parse it.
junk = open(os.path.join(self.tempdir, "renewal", "IGNORE.THIS"), "w")
junk.write("This file should be ignored!")
junk.close()
self.defaults = configobj.ConfigObj()
with mock.patch("letsencrypt.storage.RenewableCert._check_symlinks") as check:
check.return_value = True
self.test_rc = storage.RenewableCert(config.filename, self.cli_config)
def tearDown(self):
shutil.rmtree(self.tempdir)
def _write_out_ex_kinds(self):
for kind in ALL_FOUR:
where = getattr(self.test_rc, kind)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"{0}12.pem".format(kind)), where)
with open(where, "w") as f:
f.write(kind)
os.unlink(where)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"{0}11.pem".format(kind)), where)
with open(where, "w") as f:
f.write(kind)
class RenewableCertTests(BaseRenewableCertTest):
# pylint: disable=too-many-public-methods
"""Tests for letsencrypt.storage."""
def test_initialization(self):
self.assertEqual(self.test_rc.lineagename, "example.org")
for kind in ALL_FOUR:
self.assertEqual(
getattr(self.test_rc, kind), os.path.join(
self.tempdir, "live", "example.org", kind + ".pem"))
def test_renewal_bad_config(self):
"""Test that the RenewableCert constructor will complain if
the renewal configuration file doesn't end in ".conf"
"""
from letsencrypt import storage
broken = os.path.join(self.tempdir, "broken.conf")
with open(broken, "w") as f:
f.write("[No closing bracket for you!")
self.assertRaises(errors.CertStorageError, storage.RenewableCert,
broken, self.cli_config)
os.unlink(broken)
self.assertRaises(errors.CertStorageError, storage.RenewableCert,
"fun", self.cli_config)
def test_renewal_incomplete_config(self):
"""Test that the RenewableCert constructor will complain if
the renewal configuration file is missing a required file element."""
from letsencrypt import storage
config = configobj.ConfigObj()
config["cert"] = "imaginary_cert.pem"
# Here the required privkey is missing.
config["chain"] = "imaginary_chain.pem"
config["fullchain"] = "imaginary_fullchain.pem"
config.filename = os.path.join(self.tempdir, "imaginary_config.conf")
config.write()
self.assertRaises(errors.CertStorageError, storage.RenewableCert,
config.filename, self.cli_config)
def test_consistent(self):
# pylint: disable=too-many-statements,protected-access
oldcert = self.test_rc.cert
self.test_rc.cert = "relative/path"
# Absolute path for item requirement
self.assertFalse(self.test_rc._consistent())
self.test_rc.cert = oldcert
# Items must exist requirement
self.assertFalse(self.test_rc._consistent())
# Items must be symlinks requirements
fill_with_sample_data(self.test_rc)
self.assertFalse(self.test_rc._consistent())
unlink_all(self.test_rc)
# Items must point to desired place if they are relative
for kind in ALL_FOUR:
os.symlink(os.path.join("..", kind + "17.pem"),
getattr(self.test_rc, kind))
self.assertFalse(self.test_rc._consistent())
unlink_all(self.test_rc)
# Items must point to desired place if they are absolute
for kind in ALL_FOUR:
os.symlink(os.path.join(self.tempdir, kind + "17.pem"),
getattr(self.test_rc, kind))
self.assertFalse(self.test_rc._consistent())
unlink_all(self.test_rc)
# Items must point to things that exist
for kind in ALL_FOUR:
os.symlink(os.path.join("..", "..", "archive", "example.org",
kind + "17.pem"),
getattr(self.test_rc, kind))
self.assertFalse(self.test_rc._consistent())
# This version should work
fill_with_sample_data(self.test_rc)
self.assertTrue(self.test_rc._consistent())
# Items must point to things that follow the naming convention
os.unlink(self.test_rc.fullchain)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"fullchain_17.pem"), self.test_rc.fullchain)
with open(self.test_rc.fullchain, "w") as f:
f.write("wrongly-named fullchain")
self.assertFalse(self.test_rc._consistent())
def test_current_target(self):
# Relative path logic
os.symlink(os.path.join("..", "..", "archive", "example.org",
"cert17.pem"), self.test_rc.cert)
with open(self.test_rc.cert, "w") as f:
f.write("cert")
self.assertTrue(os.path.samefile(self.test_rc.current_target("cert"),
os.path.join(self.tempdir, "archive",
"example.org",
"cert17.pem")))
# Absolute path logic
os.unlink(self.test_rc.cert)
os.symlink(os.path.join(self.tempdir, "archive", "example.org",
"cert17.pem"), self.test_rc.cert)
with open(self.test_rc.cert, "w") as f:
f.write("cert")
self.assertTrue(os.path.samefile(self.test_rc.current_target("cert"),
os.path.join(self.tempdir, "archive",
"example.org",
"cert17.pem")))
def test_current_version(self):
for ver in (1, 5, 10, 20):
os.symlink(os.path.join("..", "..", "archive", "example.org",
"cert{0}.pem".format(ver)),
self.test_rc.cert)
with open(self.test_rc.cert, "w") as f:
f.write("cert")
os.unlink(self.test_rc.cert)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"cert10.pem"), self.test_rc.cert)
self.assertEqual(self.test_rc.current_version("cert"), 10)
def test_no_current_version(self):
self.assertEqual(self.test_rc.current_version("cert"), None)
def test_latest_and_next_versions(self):
for ver in xrange(1, 6):
for kind in ALL_FOUR:
where = getattr(self.test_rc, kind)
if os.path.islink(where):
os.unlink(where)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"{0}{1}.pem".format(kind, ver)), where)
with open(where, "w") as f:
f.write(kind)
self.assertEqual(self.test_rc.latest_common_version(), 5)
self.assertEqual(self.test_rc.next_free_version(), 6)
# Having one kind of file of a later version doesn't change the
# result
os.unlink(self.test_rc.privkey)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"privkey7.pem"), self.test_rc.privkey)
with open(self.test_rc.privkey, "w") as f:
f.write("privkey")
self.assertEqual(self.test_rc.latest_common_version(), 5)
# ... although it does change the next free version
self.assertEqual(self.test_rc.next_free_version(), 8)
# Nor does having three out of four change the result
os.unlink(self.test_rc.cert)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"cert7.pem"), self.test_rc.cert)
with open(self.test_rc.cert, "w") as f:
f.write("cert")
os.unlink(self.test_rc.fullchain)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"fullchain7.pem"), self.test_rc.fullchain)
with open(self.test_rc.fullchain, "w") as f:
f.write("fullchain")
self.assertEqual(self.test_rc.latest_common_version(), 5)
# If we have everything from a much later version, it does change
# the result
ver = 17
for kind in ALL_FOUR:
where = getattr(self.test_rc, kind)
if os.path.islink(where):
os.unlink(where)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"{0}{1}.pem".format(kind, ver)), where)
with open(where, "w") as f:
f.write(kind)
self.assertEqual(self.test_rc.latest_common_version(), 17)
self.assertEqual(self.test_rc.next_free_version(), 18)
def test_update_link_to(self):
for ver in xrange(1, 6):
for kind in ALL_FOUR:
where = getattr(self.test_rc, kind)
if os.path.islink(where):
os.unlink(where)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"{0}{1}.pem".format(kind, ver)), where)
with open(where, "w") as f:
f.write(kind)
self.assertEqual(ver, self.test_rc.current_version(kind))
# pylint: disable=protected-access
self.test_rc._update_link_to("cert", 3)
self.test_rc._update_link_to("privkey", 2)
self.assertEqual(3, self.test_rc.current_version("cert"))
self.assertEqual(2, self.test_rc.current_version("privkey"))
self.assertEqual(5, self.test_rc.current_version("chain"))
self.assertEqual(5, self.test_rc.current_version("fullchain"))
# Currently we are allowed to update to a version that doesn't exist
self.test_rc._update_link_to("chain", 3000)
# However, current_version doesn't allow querying the resulting
# version (because it's a broken link).
self.assertEqual(os.path.basename(os.readlink(self.test_rc.chain)),
"chain3000.pem")
def test_version(self):
os.symlink(os.path.join("..", "..", "archive", "example.org",
"cert12.pem"), self.test_rc.cert)
with open(self.test_rc.cert, "w") as f:
f.write("cert")
# TODO: We should probably test that the directory is still the
# same, but it's tricky because we can get an absolute
# path out when we put a relative path in.
self.assertEqual("cert8.pem",
os.path.basename(self.test_rc.version("cert", 8)))
def test_update_all_links_to_success(self):
for ver in xrange(1, 6):
for kind in ALL_FOUR:
where = getattr(self.test_rc, kind)
if os.path.islink(where):
os.unlink(where)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"{0}{1}.pem".format(kind, ver)), where)
with open(where, "w") as f:
f.write(kind)
self.assertEqual(ver, self.test_rc.current_version(kind))
self.assertEqual(self.test_rc.latest_common_version(), 5)
for ver in xrange(1, 6):
self.test_rc.update_all_links_to(ver)
for kind in ALL_FOUR:
self.assertEqual(ver, self.test_rc.current_version(kind))
self.assertEqual(self.test_rc.latest_common_version(), 5)
def test_update_all_links_to_partial_failure(self):
def unlink_or_raise(path, real_unlink=os.unlink):
# pylint: disable=missing-docstring
basename = os.path.basename(path)
if "fullchain" in basename and basename.startswith("prev"):
raise ValueError
else:
real_unlink(path)
self._write_out_ex_kinds()
with mock.patch("letsencrypt.storage.os.unlink") as mock_unlink:
mock_unlink.side_effect = unlink_or_raise
self.assertRaises(ValueError, self.test_rc.update_all_links_to, 12)
for kind in ALL_FOUR:
self.assertEqual(self.test_rc.current_version(kind), 12)
def test_update_all_links_to_full_failure(self):
def unlink_or_raise(path, real_unlink=os.unlink):
# pylint: disable=missing-docstring
if "fullchain" in os.path.basename(path):
raise ValueError
else:
real_unlink(path)
self._write_out_ex_kinds()
with mock.patch("letsencrypt.storage.os.unlink") as mock_unlink:
mock_unlink.side_effect = unlink_or_raise
self.assertRaises(ValueError, self.test_rc.update_all_links_to, 12)
for kind in ALL_FOUR:
self.assertEqual(self.test_rc.current_version(kind), 11)
def test_has_pending_deployment(self):
for ver in xrange(1, 6):
for kind in ALL_FOUR:
where = getattr(self.test_rc, kind)
if os.path.islink(where):
os.unlink(where)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"{0}{1}.pem".format(kind, ver)), where)
with open(where, "w") as f:
f.write(kind)
self.assertEqual(ver, self.test_rc.current_version(kind))
for ver in xrange(1, 6):
self.test_rc.update_all_links_to(ver)
for kind in ALL_FOUR:
self.assertEqual(ver, self.test_rc.current_version(kind))
if ver < 5:
self.assertTrue(self.test_rc.has_pending_deployment())
else:
self.assertFalse(self.test_rc.has_pending_deployment())
def test_names(self):
# Trying the current version
test_cert = test_util.load_vector("cert-san.pem")
os.symlink(os.path.join("..", "..", "archive", "example.org",
"cert12.pem"), self.test_rc.cert)
with open(self.test_rc.cert, "w") as f:
f.write(test_cert)
self.assertEqual(self.test_rc.names(),
["example.com", "www.example.com"])
# Trying a non-current version
test_cert = test_util.load_vector("cert.pem")
os.unlink(self.test_rc.cert)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"cert15.pem"), self.test_rc.cert)
with open(self.test_rc.cert, "w") as f:
f.write(test_cert)
self.assertEqual(self.test_rc.names(12),
["example.com", "www.example.com"])
# Trying missing cert
os.unlink(self.test_rc.cert)
self.assertRaises(errors.CertStorageError, self.test_rc.names)
@mock.patch("letsencrypt.storage.datetime")
def test_time_interval_judgments(self, mock_datetime):
"""Test should_autodeploy() and should_autorenew() on the basis
of expiry time windows."""
test_cert = test_util.load_vector("cert.pem")
self._write_out_ex_kinds()
self.test_rc.update_all_links_to(12)
with open(self.test_rc.cert, "w") as f:
f.write(test_cert)
self.test_rc.update_all_links_to(11)
with open(self.test_rc.cert, "w") as f:
f.write(test_cert)
mock_datetime.timedelta = datetime.timedelta
for (current_time, interval, result) in [
# 2014-12-13 12:00:00+00:00 (about 5 days prior to expiry)
# Times that should result in autorenewal/autodeployment
(1418472000, "2 months", True), (1418472000, "1 week", True),
# Times that should not
(1418472000, "4 days", False), (1418472000, "2 days", False),
# 2009-05-01 12:00:00+00:00 (about 5 years prior to expiry)
# Times that should result in autorenewal/autodeployment
(1241179200, "7 years", True),
(1241179200, "11 years 2 months", True),
# Times that should not
(1241179200, "8 hours", False), (1241179200, "2 days", False),
(1241179200, "40 days", False), (1241179200, "9 months", False),
# 2015-01-01 (after expiry has already happened, so all
# intervals should cause autorenewal/autodeployment)
(1420070400, "0 seconds", True),
(1420070400, "10 seconds", True),
(1420070400, "10 minutes", True),
(1420070400, "10 weeks", True), (1420070400, "10 months", True),
(1420070400, "10 years", True), (1420070400, "99 months", True),
]:
sometime = datetime.datetime.utcfromtimestamp(current_time)
mock_datetime.datetime.utcnow.return_value = sometime
self.test_rc.configuration["deploy_before_expiry"] = interval
self.test_rc.configuration["renew_before_expiry"] = interval
self.assertEqual(self.test_rc.should_autodeploy(), result)
self.assertEqual(self.test_rc.should_autorenew(), result)
def test_autodeployment_is_enabled(self):
self.assertTrue(self.test_rc.autodeployment_is_enabled())
self.test_rc.configuration["autodeploy"] = "1"
self.assertTrue(self.test_rc.autodeployment_is_enabled())
self.test_rc.configuration["autodeploy"] = "0"
self.assertFalse(self.test_rc.autodeployment_is_enabled())
def test_should_autodeploy(self):
"""Test should_autodeploy() on the basis of reasons other than
expiry time window."""
# pylint: disable=too-many-statements
# Autodeployment turned off
self.test_rc.configuration["autodeploy"] = "0"
self.assertFalse(self.test_rc.should_autodeploy())
self.test_rc.configuration["autodeploy"] = "1"
# No pending deployment
for ver in xrange(1, 6):
for kind in ALL_FOUR:
where = getattr(self.test_rc, kind)
if os.path.islink(where):
os.unlink(where)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"{0}{1}.pem".format(kind, ver)), where)
with open(where, "w") as f:
f.write(kind)
self.assertFalse(self.test_rc.should_autodeploy())
def test_autorenewal_is_enabled(self):
self.assertTrue(self.test_rc.autorenewal_is_enabled())
self.test_rc.configuration["autorenew"] = "1"
self.assertTrue(self.test_rc.autorenewal_is_enabled())
self.test_rc.configuration["autorenew"] = "0"
self.assertFalse(self.test_rc.autorenewal_is_enabled())
@mock.patch("letsencrypt.storage.RenewableCert.ocsp_revoked")
def test_should_autorenew(self, mock_ocsp):
"""Test should_autorenew on the basis of reasons other than
expiry time window."""
# pylint: disable=too-many-statements
# Autorenewal turned off
self.test_rc.configuration["autorenew"] = "0"
self.assertFalse(self.test_rc.should_autorenew())
self.test_rc.configuration["autorenew"] = "1"
for kind in ALL_FOUR:
where = getattr(self.test_rc, kind)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"{0}12.pem".format(kind)), where)
with open(where, "w") as f:
f.write(kind)
# Mandatory renewal on the basis of OCSP revocation
mock_ocsp.return_value = True
self.assertTrue(self.test_rc.should_autorenew())
mock_ocsp.return_value = False
@mock.patch("letsencrypt.storage.relevant_values")
def test_save_successor(self, mock_rv):
# Mock relevant_values() to claim that all values are relevant here
# (to avoid instantiating parser)
mock_rv.side_effect = lambda x: x
for ver in xrange(1, 6):
for kind in ALL_FOUR:
where = getattr(self.test_rc, kind)
if os.path.islink(where):
os.unlink(where)
os.symlink(os.path.join("..", "..", "archive", "example.org",
"{0}{1}.pem".format(kind, ver)), where)
with open(where, "w") as f:
f.write(kind)
self.test_rc.update_all_links_to(3)
self.assertEqual(
6, self.test_rc.save_successor(3, "new cert", None,
"new chain", self.cli_config))
with open(self.test_rc.version("cert", 6)) as f:
self.assertEqual(f.read(), "new cert")
with open(self.test_rc.version("chain", 6)) as f:
self.assertEqual(f.read(), "new chain")
with open(self.test_rc.version("fullchain", 6)) as f:
self.assertEqual(f.read(), "new cert" + "new chain")
# version 6 of the key should be a link back to version 3
self.assertFalse(os.path.islink(self.test_rc.version("privkey", 3)))
self.assertTrue(os.path.islink(self.test_rc.version("privkey", 6)))
# Let's try two more updates
self.assertEqual(
7, self.test_rc.save_successor(6, "again", None,
"newer chain", self.cli_config))
self.assertEqual(
8, self.test_rc.save_successor(7, "hello", None,
"other chain", self.cli_config))
# All of the subsequent versions should link directly to the original
# privkey.
for i in (6, 7, 8):
self.assertTrue(os.path.islink(self.test_rc.version("privkey", i)))
self.assertEqual("privkey3.pem", os.path.basename(os.readlink(
self.test_rc.version("privkey", i))))
for kind in ALL_FOUR:
self.assertEqual(self.test_rc.available_versions(kind), range(1, 9))
self.assertEqual(self.test_rc.current_version(kind), 3)
# Test updating from latest version rather than old version
self.test_rc.update_all_links_to(8)
self.assertEqual(
9, self.test_rc.save_successor(8, "last", None,
"attempt", self.cli_config))
for kind in ALL_FOUR:
self.assertEqual(self.test_rc.available_versions(kind),
range(1, 10))
self.assertEqual(self.test_rc.current_version(kind), 8)
with open(self.test_rc.version("fullchain", 9)) as f:
self.assertEqual(f.read(), "last" + "attempt")
temp_config_file = os.path.join(self.cli_config.renewal_configs_dir,
self.test_rc.lineagename) + ".conf.new"
with open(temp_config_file, "w") as f:
f.write("We previously crashed while writing me :(")
# Test updating when providing a new privkey. The key should
# be saved in a new file rather than creating a new symlink.
self.assertEqual(
10, self.test_rc.save_successor(9, "with", "a",
"key", self.cli_config))
self.assertTrue(os.path.exists(self.test_rc.version("privkey", 10)))
self.assertFalse(os.path.islink(self.test_rc.version("privkey", 10)))
self.assertFalse(os.path.exists(temp_config_file))
@mock.patch("letsencrypt.cli.helpful_parser")
def test_relevant_values(self, mock_parser):
"""Test that relevant_values() can reject an irrelevant value."""
# pylint: disable=protected-access
from letsencrypt import storage
mock_parser.verb = "certonly"
mock_parser.args = ["--standalone"]
mock_action = mock.Mock(dest="rsa_key_size", default=2048)
mock_parser.parser._actions = [mock_action]
self.assertEqual(storage.relevant_values({"hello": "there"}), {})
@mock.patch("letsencrypt.cli.helpful_parser")
def test_relevant_values_default(self, mock_parser):
"""Test that relevant_values() can reject a default value."""
# pylint: disable=protected-access
from letsencrypt import storage
mock_parser.verb = "certonly"
mock_parser.args = ["--standalone"]
mock_action = mock.Mock(dest="rsa_key_size", default=2048)
mock_parser.parser._actions = [mock_action]
self.assertEqual(storage.relevant_values({"rsa_key_size": 2048}), {})
@mock.patch("letsencrypt.cli.helpful_parser")
def test_relevant_values_nondefault(self, mock_parser):
"""Test that relevant_values() can retain a non-default value."""
# pylint: disable=protected-access
from letsencrypt import storage
mock_parser.verb = "certonly"
mock_parser.args = ["--standalone"]
mock_action = mock.Mock(dest="rsa_key_size", default=2048)
mock_parser.parser._actions = [mock_action]
self.assertEqual(storage.relevant_values({"rsa_key_size": 12}),
{"rsa_key_size": 12})
@mock.patch("letsencrypt.storage.relevant_values")
def test_new_lineage(self, mock_rv):
"""Test for new_lineage() class method."""
# Mock relevant_values to say everything is relevant here (so we
# don't have to mock the parser to help it decide!)
mock_rv.side_effect = lambda x: x
from letsencrypt import storage
result = storage.RenewableCert.new_lineage(
"the-lineage.com", "cert", "privkey", "chain", self.cli_config)
# This consistency check tests most relevant properties about the
# newly created cert lineage.
# pylint: disable=protected-access
self.assertTrue(result._consistent())
self.assertTrue(os.path.exists(os.path.join(
self.cli_config.renewal_configs_dir, "the-lineage.com.conf")))
with open(result.fullchain) as f:
self.assertEqual(f.read(), "cert" + "chain")
# Let's do it again and make sure it makes a different lineage
result = storage.RenewableCert.new_lineage(
"the-lineage.com", "cert2", "privkey2", "chain2", self.cli_config)
self.assertTrue(os.path.exists(os.path.join(
self.cli_config.renewal_configs_dir, "the-lineage.com-0001.conf")))
# Now trigger the detection of already existing files
os.mkdir(os.path.join(
self.cli_config.live_dir, "the-lineage.com-0002"))
self.assertRaises(errors.CertStorageError,
storage.RenewableCert.new_lineage, "the-lineage.com",
"cert3", "privkey3", "chain3", self.cli_config)
os.mkdir(os.path.join(self.cli_config.archive_dir, "other-example.com"))
self.assertRaises(errors.CertStorageError,
storage.RenewableCert.new_lineage,
"other-example.com", "cert4",
"privkey4", "chain4", self.cli_config)
# Make sure it can accept renewal parameters
result = storage.RenewableCert.new_lineage(
"the-lineage.com", "cert2", "privkey2", "chain2", self.cli_config)
# TODO: Conceivably we could test that the renewal parameters actually
# got saved
@mock.patch("letsencrypt.storage.relevant_values")
def test_new_lineage_nonexistent_dirs(self, mock_rv):
"""Test that directories can be created if they don't exist."""
# Mock relevant_values to say everything is relevant here (so we
# don't have to mock the parser to help it decide!)
mock_rv.side_effect = lambda x: x
from letsencrypt import storage
shutil.rmtree(self.cli_config.renewal_configs_dir)
shutil.rmtree(self.cli_config.archive_dir)
shutil.rmtree(self.cli_config.live_dir)
storage.RenewableCert.new_lineage(
"the-lineage.com", "cert2", "privkey2", "chain2", self.cli_config)
self.assertTrue(os.path.exists(
os.path.join(
self.cli_config.renewal_configs_dir, "the-lineage.com.conf")))
self.assertTrue(os.path.exists(os.path.join(
self.cli_config.live_dir, "the-lineage.com", "privkey.pem")))
self.assertTrue(os.path.exists(os.path.join(
self.cli_config.archive_dir, "the-lineage.com", "privkey1.pem")))
@mock.patch("letsencrypt.storage.le_util.unique_lineage_name")
def test_invalid_config_filename(self, mock_uln):
from letsencrypt import storage
mock_uln.return_value = "this_does_not_end_with_dot_conf", "yikes"
self.assertRaises(errors.CertStorageError,
storage.RenewableCert.new_lineage, "example.com",
"cert", "privkey", "chain", self.cli_config)
def test_bad_kind(self):
self.assertRaises(
errors.CertStorageError, self.test_rc.current_target, "elephant")
self.assertRaises(
errors.CertStorageError, self.test_rc.current_version, "elephant")
self.assertRaises(
errors.CertStorageError, self.test_rc.version, "elephant", 17)
self.assertRaises(
errors.CertStorageError,
self.test_rc.available_versions, "elephant")
self.assertRaises(
errors.CertStorageError,
self.test_rc.newest_available_version, "elephant")
# pylint: disable=protected-access
self.assertRaises(
errors.CertStorageError,
self.test_rc._update_link_to, "elephant", 17)
def test_ocsp_revoked(self):
# XXX: This is currently hardcoded to False due to a lack of an
# OCSP server to test against.
self.assertFalse(self.test_rc.ocsp_revoked())
def test_add_time_interval(self):
from letsencrypt import storage
# this month has 30 days, and the next year is a leap year
time_1 = pytz.UTC.fromutc(datetime.datetime(2003, 11, 20, 11, 59, 21))
# this month has 31 days, and the next year is not a leap year
time_2 = pytz.UTC.fromutc(datetime.datetime(2012, 10, 18, 21, 31, 16))
# in different time zone (GMT+8)
time_3 = pytz.timezone('Asia/Shanghai').fromutc(
datetime.datetime(2015, 10, 26, 22, 25, 41))
intended = {
(time_1, ""): time_1,
(time_2, ""): time_2,
(time_3, ""): time_3,
(time_1, "17 days"): time_1 + datetime.timedelta(17),
(time_2, "17 days"): time_2 + datetime.timedelta(17),
(time_1, "30"): time_1 + datetime.timedelta(30),
(time_2, "30"): time_2 + datetime.timedelta(30),
(time_1, "7 weeks"): time_1 + datetime.timedelta(49),
(time_2, "7 weeks"): time_2 + datetime.timedelta(49),
# 1 month is always 30 days, no matter which month it is
(time_1, "1 month"): time_1 + datetime.timedelta(30),
(time_2, "1 month"): time_2 + datetime.timedelta(31),
# 1 year could be 365 or 366 days, depends on the year
(time_1, "1 year"): time_1 + datetime.timedelta(366),
(time_2, "1 year"): time_2 + datetime.timedelta(365),
(time_1, "1 year 1 day"): time_1 + datetime.timedelta(367),
(time_2, "1 year 1 day"): time_2 + datetime.timedelta(366),
(time_1, "1 year-1 day"): time_1 + datetime.timedelta(365),
(time_2, "1 year-1 day"): time_2 + datetime.timedelta(364),
(time_1, "4 years"): time_1 + datetime.timedelta(1461),
(time_2, "4 years"): time_2 + datetime.timedelta(1461),
}
for parameters, excepted in intended.items():
base_time, interval = parameters
self.assertEqual(storage.add_time_interval(base_time, interval),
excepted)
def test_missing_cert(self):
from letsencrypt import storage
self.assertRaises(errors.CertStorageError,
storage.RenewableCert,
self.config.filename, self.cli_config)
os.symlink("missing", self.config[ALL_FOUR[0]])
self.assertRaises(errors.CertStorageError,
storage.RenewableCert,
self.config.filename, self.cli_config)
def test_write_renewal_config(self):
# Mostly tested by the process of creating and updating lineages,
# but we can test that this successfully creates files, removes
# unneeded items, and preserves comments.
temp = os.path.join(self.tempdir, "sample-file")
temp2 = os.path.join(self.tempdir, "sample-file.new")
with open(temp, "w") as f:
f.write("[renewalparams]\nuseful = value # A useful value\n"
"useless = value # Not needed\n")
target = {}
for x in ALL_FOUR:
target[x] = "somewhere"
relevant_data = {"useful": "new_value"}
from letsencrypt import storage
storage.write_renewal_config(temp, temp2, target, relevant_data)
with open(temp2, "r") as f:
content = f.read()
# useful value was updated
assert "useful = new_value" in content
# associated comment was preserved
assert "A useful value" in content
# useless value was deleted
assert "useless" not in content
if __name__ == "__main__":
unittest.main() # pragma: no cover
-75
View File
@@ -1,75 +0,0 @@
"""Test utilities.
.. warning:: This module is not part of the public API.
"""
import os
import pkg_resources
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
import OpenSSL
from acme import jose
def vector_path(*names):
"""Path to a test vector."""
return pkg_resources.resource_filename(
__name__, os.path.join('testdata', *names))
def load_vector(*names):
"""Load contents of a test vector."""
# luckily, resource_string opens file in binary mode
return pkg_resources.resource_string(
__name__, os.path.join('testdata', *names))
def _guess_loader(filename, loader_pem, loader_der):
_, ext = os.path.splitext(filename)
if ext.lower() == '.pem':
return loader_pem
elif ext.lower() == '.der':
return loader_der
else: # pragma: no cover
raise ValueError("Loader could not be recognized based on extension")
def load_cert(*names):
"""Load certificate."""
loader = _guess_loader(
names[-1], OpenSSL.crypto.FILETYPE_PEM, OpenSSL.crypto.FILETYPE_ASN1)
return OpenSSL.crypto.load_certificate(loader, load_vector(*names))
def load_comparable_cert(*names):
"""Load ComparableX509 cert."""
return jose.ComparableX509(load_cert(*names))
def load_csr(*names):
"""Load certificate request."""
loader = _guess_loader(
names[-1], OpenSSL.crypto.FILETYPE_PEM, OpenSSL.crypto.FILETYPE_ASN1)
return OpenSSL.crypto.load_certificate_request(loader, load_vector(*names))
def load_comparable_csr(*names):
"""Load ComparableX509 certificate request."""
return jose.ComparableX509(load_csr(*names))
def load_rsa_private_key(*names):
"""Load RSA private key."""
loader = _guess_loader(names[-1], serialization.load_pem_private_key,
serialization.load_der_private_key)
return jose.ComparableRSAKey(loader(
load_vector(*names), password=None, backend=default_backend()))
def load_pyopenssl_private_key(*names):
"""Load pyOpenSSL private key."""
loader = _guess_loader(
names[-1], OpenSSL.crypto.FILETYPE_PEM, OpenSSL.crypto.FILETYPE_ASN1)
return OpenSSL.crypto.load_privatekey(loader, load_vector(*names))
@@ -1,28 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIE1DCCA7ygAwIBAgITAPoz/CBluNQV/Eh9F+CS6dSxEDANBgkqhkiG9w0BAQsF
ADAfMR0wGwYDVQQDDBRoYXBweSBoYWNrZXIgZmFrZSBDQTAeFw0xNjAyMDIyMzQ5
MDBaFw0xNjA1MDIyMzQ5MDBaMBQxEjAQBgNVBAMTCWlzbm90Lm9yZzCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBALyudqLKcIdWZ5VaK1fuhlEDbZtvs2E+
slm4dmSS1nFve7MdlZ69K0gdtnhkiPQ0wGQTligeDZ8fY8iL87GZO0tp5f7S+QJN
NYCiYw6j4qp5JBy/zG22kJz1Quu7/vXMYLzLvK6x6YixiWAWyqqvlUVBLS1r4W3h
A5Z+F1EIsXeyz7TJe3lAzIWAAxpfH9OviIz2rEDotuCdU771USLLNSw4qJojNlTx
UpZG6lGFs8KGb8tqROXknaMKE4PvN3SITixSUTFbktt1Wz60moWbNdLMKvgkzuUP
r4viO2P4SO5slNAY0ZeEssPpVAelN3EvrAcEZtoKmG5fnQDVo8uVag0CAwEAAaOC
AhIwggIOMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
BQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUqhI4u6aaPrcYQnmypxV8Tap8
L54wHwYDVR0jBBgwFoAU+3hPEvlgFYMsnxd/NBmzLjbqQYkweAYIKwYBBQUHAQEE
bDBqMDMGCCsGAQUFBzABhidodHRwOi8vb2NzcC5zdGFnaW5nLXgxLmxldHNlbmNy
eXB0Lm9yZy8wMwYIKwYBBQUHMAKGJ2h0dHA6Ly9jZXJ0LnN0YWdpbmcteDEubGV0
c2VuY3J5cHQub3JnLzAUBgNVHREEDTALgglpc25vdC5vcmcwgf4GA1UdIASB9jCB
8zAIBgZngQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpodHRw
Oi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENl
cnRpZmljYXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFy
dGllcyBhbmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmljYXRl
IFBvbGljeSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0
b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAbAhX6FfQwELayneY4l5RvYSdw/Jj5CRy
KzrM7ISld7x9YPpxX6Pmht/YyMhLWrtxvFUR2+RNhSIYB8IjQEjmKjvR7UNeiUve
jzPEAuTg/9m3i0FJpPHc2aKGzlLFQCMm5/RrvnXI6ljIcyhocLvMiN46iexcExI2
Ese3w8GoH6wARYKxU/QBexfoXQLgtAbYzNRE6EgKWtB+txV+7+d2MgbhCEit5VwU
+ydT8inp9URsA7iKM03hDdGOBysddkrm1/yEhVy/Oo6bT9WMAUHVvz61hHekWcSf
rAQ6BayubvWOUx06eTowXr1gln/rl+WXOxcsJeag127NuhmHOCXZxQ==
-----END CERTIFICATE-----
@@ -1,19 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDETCCAfmgAwIBAgIJAJzxkS6o1QkIMA0GCSqGSIb3DQEBCwUAMB8xHTAbBgNV
BAMMFGhhcHB5IGhhY2tlciBmYWtlIENBMB4XDTE1MDQwNzIzNTAzOFoXDTI1MDQw
NDIzNTAzOFowHzEdMBsGA1UEAwwUaGFwcHkgaGFja2VyIGZha2UgQ0EwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCCkd5mgXFErJ3F2M0E9dw+Ta/md5i
8TDId01HberAApqmydG7UZYF3zLTSzNjlNSOmtybvrSGUnZ9r9tSQcL8VM6WUOM8
tnIpiIjEA2QkBycMwvRmZ/B2ltPdYs/R9BqNwO1g18GDZrHSzUYtNKNeFI6Glamj
7GK2Vr0SmiEamlNIR5ktAFsEErzf/d4jCF7sosMsJpMCm1p58QkP4LHLShVLXDa8
BMfVoI+ipYcA08iNUFkgW8VWDclIDxcysa0psDDtMjX3+4aPkE/cefmP+1xOfUuD
HOGV8XFynsP4EpTfVOZr0/g9gYQ7ZArqXX7GTQkFqduwPm/w5qxSPTarAgMBAAGj
UDBOMB0GA1UdDgQWBBT7eE8S+WAVgyyfF380GbMuNupBiTAfBgNVHSMEGDAWgBT7
eE8S+WAVgyyfF380GbMuNupBiTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
A4IBAQAd9Da+Zv+TjMv7NTAmliqnWHY6d3UxEZN3hFEJ58IQVHbBZVZdW7zhRktB
vR05Kweac0HJeK91TKmzvXl21IXLvh0gcNLU/uweD3no/snfdB4OoFompljThmgl
zBqiqWoKBJQrLCA8w5UB+ReomRYd/EYXF/6TAfzm6hr//Xt5mPiUHPdvYt75lMAo
vRxLSbF8TSQ6b7BYxISWjPgFASNNqJNHEItWsmQMtAjjwzb9cs01XH9pChVAWn9L
oeMKa+SlHSYrWG93+EcrIH/dGU76uNOiaDzBSKvaehG53h25MHuO1anNICJvZovW
rFo4Uv1EnkKJm3vJFe50eJGhEKlx
-----END CERTIFICATE-----
@@ -1,47 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIE1DCCA7ygAwIBAgITAPoz/CBluNQV/Eh9F+CS6dSxEDANBgkqhkiG9w0BAQsF
ADAfMR0wGwYDVQQDDBRoYXBweSBoYWNrZXIgZmFrZSBDQTAeFw0xNjAyMDIyMzQ5
MDBaFw0xNjA1MDIyMzQ5MDBaMBQxEjAQBgNVBAMTCWlzbm90Lm9yZzCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBALyudqLKcIdWZ5VaK1fuhlEDbZtvs2E+
slm4dmSS1nFve7MdlZ69K0gdtnhkiPQ0wGQTligeDZ8fY8iL87GZO0tp5f7S+QJN
NYCiYw6j4qp5JBy/zG22kJz1Quu7/vXMYLzLvK6x6YixiWAWyqqvlUVBLS1r4W3h
A5Z+F1EIsXeyz7TJe3lAzIWAAxpfH9OviIz2rEDotuCdU771USLLNSw4qJojNlTx
UpZG6lGFs8KGb8tqROXknaMKE4PvN3SITixSUTFbktt1Wz60moWbNdLMKvgkzuUP
r4viO2P4SO5slNAY0ZeEssPpVAelN3EvrAcEZtoKmG5fnQDVo8uVag0CAwEAAaOC
AhIwggIOMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
BQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUqhI4u6aaPrcYQnmypxV8Tap8
L54wHwYDVR0jBBgwFoAU+3hPEvlgFYMsnxd/NBmzLjbqQYkweAYIKwYBBQUHAQEE
bDBqMDMGCCsGAQUFBzABhidodHRwOi8vb2NzcC5zdGFnaW5nLXgxLmxldHNlbmNy
eXB0Lm9yZy8wMwYIKwYBBQUHMAKGJ2h0dHA6Ly9jZXJ0LnN0YWdpbmcteDEubGV0
c2VuY3J5cHQub3JnLzAUBgNVHREEDTALgglpc25vdC5vcmcwgf4GA1UdIASB9jCB
8zAIBgZngQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpodHRw
Oi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENl
cnRpZmljYXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFy
dGllcyBhbmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmljYXRl
IFBvbGljeSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0
b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAbAhX6FfQwELayneY4l5RvYSdw/Jj5CRy
KzrM7ISld7x9YPpxX6Pmht/YyMhLWrtxvFUR2+RNhSIYB8IjQEjmKjvR7UNeiUve
jzPEAuTg/9m3i0FJpPHc2aKGzlLFQCMm5/RrvnXI6ljIcyhocLvMiN46iexcExI2
Ese3w8GoH6wARYKxU/QBexfoXQLgtAbYzNRE6EgKWtB+txV+7+d2MgbhCEit5VwU
+ydT8inp9URsA7iKM03hDdGOBysddkrm1/yEhVy/Oo6bT9WMAUHVvz61hHekWcSf
rAQ6BayubvWOUx06eTowXr1gln/rl+WXOxcsJeag127NuhmHOCXZxQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDETCCAfmgAwIBAgIJAJzxkS6o1QkIMA0GCSqGSIb3DQEBCwUAMB8xHTAbBgNV
BAMMFGhhcHB5IGhhY2tlciBmYWtlIENBMB4XDTE1MDQwNzIzNTAzOFoXDTI1MDQw
NDIzNTAzOFowHzEdMBsGA1UEAwwUaGFwcHkgaGFja2VyIGZha2UgQ0EwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCCkd5mgXFErJ3F2M0E9dw+Ta/md5i
8TDId01HberAApqmydG7UZYF3zLTSzNjlNSOmtybvrSGUnZ9r9tSQcL8VM6WUOM8
tnIpiIjEA2QkBycMwvRmZ/B2ltPdYs/R9BqNwO1g18GDZrHSzUYtNKNeFI6Glamj
7GK2Vr0SmiEamlNIR5ktAFsEErzf/d4jCF7sosMsJpMCm1p58QkP4LHLShVLXDa8
BMfVoI+ipYcA08iNUFkgW8VWDclIDxcysa0psDDtMjX3+4aPkE/cefmP+1xOfUuD
HOGV8XFynsP4EpTfVOZr0/g9gYQ7ZArqXX7GTQkFqduwPm/w5qxSPTarAgMBAAGj
UDBOMB0GA1UdDgQWBBT7eE8S+WAVgyyfF380GbMuNupBiTAfBgNVHSMEGDAWgBT7
eE8S+WAVgyyfF380GbMuNupBiTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
A4IBAQAd9Da+Zv+TjMv7NTAmliqnWHY6d3UxEZN3hFEJ58IQVHbBZVZdW7zhRktB
vR05Kweac0HJeK91TKmzvXl21IXLvh0gcNLU/uweD3no/snfdB4OoFompljThmgl
zBqiqWoKBJQrLCA8w5UB+ReomRYd/EYXF/6TAfzm6hr//Xt5mPiUHPdvYt75lMAo
vRxLSbF8TSQ6b7BYxISWjPgFASNNqJNHEItWsmQMtAjjwzb9cs01XH9pChVAWn9L
oeMKa+SlHSYrWG93+EcrIH/dGU76uNOiaDzBSKvaehG53h25MHuO1anNICJvZovW
rFo4Uv1EnkKJm3vJFe50eJGhEKlx
-----END CERTIFICATE-----
@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8rnaiynCHVmeV
WitX7oZRA22bb7NhPrJZuHZkktZxb3uzHZWevStIHbZ4ZIj0NMBkE5YoHg2fH2PI
i/OxmTtLaeX+0vkCTTWAomMOo+KqeSQcv8xttpCc9ULru/71zGC8y7yusemIsYlg
Fsqqr5VFQS0ta+Ft4QOWfhdRCLF3ss+0yXt5QMyFgAMaXx/Tr4iM9qxA6LbgnVO+
9VEiyzUsOKiaIzZU8VKWRupRhbPChm/LakTl5J2jChOD7zd0iE4sUlExW5LbdVs+
tJqFmzXSzCr4JM7lD6+L4jtj+EjubJTQGNGXhLLD6VQHpTdxL6wHBGbaCphuX50A
1aPLlWoNAgMBAAECggEAfKKWFWS6PnwSAnNErFoQeZVVItb/XB5JO8EA2+CvLNFi
mefR/MCixYlzDkYCvaXW7ISPrMJlZxYaGNBx0oAQzfkPB2wfNqj/zY/29SXGxast
8puzk0mEb1oHsaZGfeFaiXvfkFpPlI8J2uJTT7qaVNv/1sArciSv9QonpsyiRhlB
yqT49juNVoR1tJHyXzkkRfHKTG8OlJd4kuFOl3fM9dTFPQ/ft0kTNAQ/B4SFvSwF
RJsbLbsbFGsUdV9ekE6UX6oWD/Ah707rvgtCyS0Bc+0O3t2EKwmm3RXPRUMHCVxE
bKdTxRB4etbjMVXMuVhB8Y4GbfrtMCy+qxZQ6znCAQKBgQDr7bcYAZVZp/nBMVB+
lBO9w73J6lnEWm6bZ9728KlGAKETaRhxZQSi6TN6MWwNwnk6rinyz4uVwVr9ZRCs
WkB1TbvW0JNcWdr3YClwsKXAt8X22bjGe0LagDJHG6r1TPS+MdovOS2M6IMaxlbT
rzFhSJ8ojLX3tqnOsmc7YAFLjQKBgQDMu8E9hoJt82lQzOGrjHmGzGEu2GLx9WKO
e4nkj335kX6fIhMMqSXBFbTJZwXoYvk5J8ZnaARbYG0m5nxDCwRjX5HWa8q0B2Po
ta53w01sKKznzlPjUhsdhEthun7MCFfLZpgvcZ9xVzOXo3/Zfn2+RrsPSjrVDqBy
hj+k5mW4gQKBgHFWKf3LTO7cBdvsD8ou4mjn7nVgMi1kb/wR4wdnxzmMtdR4STi4
GYkVVBhgQ5M8mDY7UoWFdH3FfCt8cI0Lcimn5ROl8RSNSeZKeL3c7lNtNRmHr/8R
WaVTrlOAlBjxFiWEF1dWNW6ah9jF7RIV+DfOxj6ZkhTk2CAmjfb1AMpFAoGABf96
KdNG/vGipDtcYSo8ZTaXoke0nmISARqdb5TEnAsnKoJVDInoEUARi9T411YO9x2z
MlRZzFOG3xzhhxVLi53BKAcAaUXOJ4MrGVcfbYvDhQcGbiJ5qOO3UaWlEVUtPUhE
LR+nDCsB1+9yT2zlQi3QTSJflt5W1QQZ2TrmwAECgYEAvQ7+sTcHs1K9yKj7koEu
A19FbMA0IwvrVRcV/VqmlsoW6e6wW2YND+GtaDbKdD0aBPivqLJwpNFrsRA+W0iB
vzmML6sKhhL+j7tjSgq+iQdBkKz0j9PyReuhe9CRnljMmyun+4qKEk0KUvxBrjPY
Skn+ML18qyUoEPnmbpfHxCs=
-----END PRIVATE KEY-----
-14
View File
@@ -1,14 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICFjCCAcCgAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhMCVVMx
ETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoM
IlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4
YW1wbGUuY29tMB4XDTE0MTIxMTIyMzQ0NVoXDTE0MTIxODIyMzQ0NVowdzELMAkG
A1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3Ix
KzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDAS
BgNVBAMMC2V4YW1wbGUuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKx1c7RR
7R/drnBSQ/zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79vukFhN9HFoHZiUvOjm0c
+pVE6K+EdE/twuUCAwEAAaM2MDQwCQYDVR0TBAIwADAnBgNVHREEIDAeggtleGFt
cGxlLmNvbYIPd3d3LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA0EASuvNKFTF
nTJsvnSXn52f4BMZJJ2id/kW7+r+FJRm+L20gKQ1aqq8d3e/lzRUrv5SMf1TAOe7
RDjyGMKy5ZgM2w==
-----END CERTIFICATE-----
-1
View File
@@ -1 +0,0 @@
MIIB3jCCAYigAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4YW1wbGUuY29tMB4XDTE0MTIxMTIyMzQ0NVoXDTE0MTIxODIyMzQ0NVowdzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4YW1wbGUuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKx1c7RR7R_drnBSQ_zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79vukFhN9HFoHZiUvOjm0c-pVE6K-EdE_twuUCAwEAATANBgkqhkiG9w0BAQsFAANBAC24z0IdwIVKSlntksllvr6zJepBH5fMndfk3XJp10jT6VE-14KNtjh02a56GoraAvJAT5_H67E8GvJ_ocNnB_o
Binary file not shown.
-13
View File
@@ -1,13 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIB3jCCAYigAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhMCVVMx
ETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoM
IlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4
YW1wbGUuY29tMB4XDTE0MTIxMTIyMzQ0NVoXDTE0MTIxODIyMzQ0NVowdzELMAkG
A1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3Ix
KzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDAS
BgNVBAMMC2V4YW1wbGUuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKx1c7RR
7R/drnBSQ/zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79vukFhN9HFoHZiUvOjm0c
+pVE6K+EdE/twuUCAwEAATANBgkqhkiG9w0BAQsFAANBAC24z0IdwIVKSlntksll
vr6zJepBH5fMndfk3XJp10jT6VE+14KNtjh02a56GoraAvJAT5/H67E8GvJ/ocNn
B/o=
-----END CERTIFICATE-----
-1
View File
@@ -1 +0,0 @@
agree-dev-preview = True
-12
View File
@@ -1,12 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBuzCCAWUCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE1pY2hpZ2FuMRIw
EAYDVQQHEwlBbm4gQXJib3IxDDAKBgNVBAoTA0VGRjEfMB0GA1UECxMWVW5pdmVy
c2l0eSBvZiBNaWNoaWdhbjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wXDANBgkqhkiG
9w0BAQEFAANLADBIAkEA9LYRcVE3Nr+qleecEcX8JwVDnjeG1X7ucsCasuuZM0e0
9cmYuUzxIkMjO/9x4AVcvXXRXPEV+LzWWkfkTlzRMwIDAQABoIGGMIGDBgkqhkiG
9w0BCQ4xdjB0MHIGA1UdEQRrMGmCC2V4YW1wbGUuY29tggtleGFtcGxlLm9yZ4IL
ZXhhbXBsZS5uZXSCDGV4YW1wbGUuaW5mb4IVc3ViZG9tYWluLmV4YW1wbGUuY29t
ghtvdGhlci5zdWJkb21haW4uZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADQQBd
k4BE5qvEvkYoZM/2++Xd9RrQ6wsdj0QiJQCozfsI4lQx6ZJnbtNc7HpDrX4W6XIv
IvzVBz/nD11drfz/RNuX
-----END CERTIFICATE REQUEST-----
-8
View File
@@ -1,8 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBFTCBwAIBADBbMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh
MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRQwEgYDVQQDDAtleGFt
cGxlLm9yZzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQD0thFxUTc2v6qV55wRxfwn
BUOeN4bVfu5ywJqy65kzR7T1yZi5TPEiQyM7/3HgBVy9ddFc8RX4vNZaR+ROXNEz
AgMBAAGgADANBgkqhkiG9w0BAQsFAANBAMikGL8Ch7hQCStXH7chhDp6+pt2+VSo
wgsrPQ2Bw4veDMlSemUrH+4e0TwbbntHfvXTDHWs9P3BiIDJLxFrjuA=
-----END CERTIFICATE REQUEST-----
Binary file not shown.
-10
View File
@@ -1,10 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBbjCCARgCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIw
EAYDVQQHDAlBbm4gQXJib3IxDDAKBgNVBAoMA0VGRjEfMB0GA1UECwwWVW5pdmVy
c2l0eSBvZiBNaWNoaWdhbjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wXDANBgkqhkiG
9w0BAQEFAANLADBIAkEArHVztFHtH92ucFJD/N/HW9AsdRsUuHUBBBDlHwNlRd3f
p580rv2+6QWE30cWgdmJS86ObRz6lUTor4R0T+3C5QIDAQABoDowOAYJKoZIhvcN
AQkOMSswKTAnBgNVHREEIDAeggtleGFtcGxlLmNvbYIPd3d3LmV4YW1wbGUuY29t
MA0GCSqGSIb3DQEBCwUAA0EAZGBM8J1rRs7onFgtc76mOeoT1c3v0ZsEmxQfb2Wy
tmReY6X1N4cs38D9VSow+VMRu2LWkKvzS7RUFSaTaeQz1A==
-----END CERTIFICATE REQUEST-----
Binary file not shown.
-10
View File
@@ -1,10 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBXTCCAQcCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIw
EAYDVQQHDAlBbm4gQXJib3IxDDAKBgNVBAoMA0VGRjEfMB0GA1UECwwWVW5pdmVy
c2l0eSBvZiBNaWNoaWdhbjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wXDANBgkqhkiG
9w0BAQEFAANLADBIAkEArHVztFHtH92ucFJD/N/HW9AsdRsUuHUBBBDlHwNlRd3f
p580rv2+6QWE30cWgdmJS86ObRz6lUTor4R0T+3C5QIDAQABoCkwJwYJKoZIhvcN
AQkOMRowGDAWBgNVHREEDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAANB
AHJH/O6BtC9aGzEVCMGOZ7z9iIRHWSzr9x/bOzn7hLwsbXPAgO1QxEwL+X+4g20G
n9XBE1N9W6HCIEut2d8wACg=
-----END CERTIFICATE REQUEST-----
-14
View File
@@ -1,14 +0,0 @@
-----BEGIN DSA PARAMETERS-----
MIGdAkEAwebEoGBfokKQeALHHnAZMQwYU35ILEBdV8oUmzv7qpSVUoHihyqfn6GC
OixAKSP8EJYcTilIqPbFbfFyOPlbLwIVANoFHEDiQgknAvKrG78pHzAJdQSPAkEA
qfka5Bnl+CeEMpzVZGrOVqZE/LFdZK9eT6YtWjzqtIkf3hwXUVxJsTnBG4xmrfvl
41pgNJpgu99YOYqPpS0g7A==
-----END DSA PARAMETERS-----
-----BEGIN DSA PRIVATE KEY-----
MIH5AgEAAkEAwebEoGBfokKQeALHHnAZMQwYU35ILEBdV8oUmzv7qpSVUoHihyqf
n6GCOixAKSP8EJYcTilIqPbFbfFyOPlbLwIVANoFHEDiQgknAvKrG78pHzAJdQSP
AkEAqfka5Bnl+CeEMpzVZGrOVqZE/LFdZK9eT6YtWjzqtIkf3hwXUVxJsTnBG4xm
rfvl41pgNJpgu99YOYqPpS0g7AJATQ2LUzjGQSM6UljcPY5I2OD9THkUR9kH2tth
zZd70UoI9btrVaTizgqYShuok94glSQNK0H92JgUk3scJPaAkAIVAMDn61h6vrCE
mNv063So6E+eYaIN
-----END DSA PRIVATE KEY-----
-17
View File
@@ -1,17 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICuDCCAnWgAwIBAgIJAPjmErVMzwVLMAsGCWCGSAFlAwQDAjB3MQswCQYDVQQG
EwJVUzERMA8GA1UECAwITWljaGlnYW4xEjAQBgNVBAcMCUFubiBBcmJvcjErMCkG
A1UECgwiVW5pdmVyc2l0eSBvZiBNaWNoaWdhbiBhbmQgdGhlIEVGRjEUMBIGA1UE
AwwLZXhhbXBsZS5jb20wHhcNMTUwNTEyMTUzOTQzWhcNMTUwNjExMTUzOTQzWjB3
MQswCQYDVQQGEwJVUzERMA8GA1UECAwITWljaGlnYW4xEjAQBgNVBAcMCUFubiBB
cmJvcjErMCkGA1UECgwiVW5pdmVyc2l0eSBvZiBNaWNoaWdhbiBhbmQgdGhlIEVG
RjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wgfEwgakGByqGSM44BAEwgZ0CQQDB5sSg
YF+iQpB4AscecBkxDBhTfkgsQF1XyhSbO/uqlJVSgeKHKp+foYI6LEApI/wQlhxO
KUio9sVt8XI4+VsvAhUA2gUcQOJCCScC8qsbvykfMAl1BI8CQQCp+RrkGeX4J4Qy
nNVkas5WpkT8sV1kr15Ppi1aPOq0iR/eHBdRXEmxOcEbjGat++XjWmA0mmC731g5
io+lLSDsA0MAAkBNDYtTOMZBIzpSWNw9jkjY4P1MeRRH2Qfa22HNl3vRSgj1u2tV
pOLOCphKG6iT3iCVJA0rQf3YmBSTexwk9oCQo1AwTjAdBgNVHQ4EFgQUZ2DlTDGU
PMwTUt0KztM6IyX61BcwHwYDVR0jBBgwFoAUZ2DlTDGUPMwTUt0KztM6IyX61Bcw
DAYDVR0TBAUwAwEB/zALBglghkgBZQMEAwIDMAAwLQIVAIbMgGx+KwBr4rgqZ2Lh
AAO8TegHAhQsuxpIIIphiReoWEtEJk4TqEIz/A==
-----END CERTIFICATE-----
@@ -1 +0,0 @@
../../archive/sample-renewal/cert1.pem
@@ -1 +0,0 @@
../../archive/sample-renewal/chain1.pem
@@ -1 +0,0 @@
../../archive/sample-renewal/fullchain1.pem
@@ -1 +0,0 @@
../../archive/sample-renewal/privkey1.pem
-14
View File
@@ -1,14 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICNzCCAeGgAwIBAgIJALizm9Y3q620MA0GCSqGSIb3DQEBCwUAMHcxCzAJBgNV
BAYTAlVTMREwDwYDVQQIDAhNaWNoaWdhbjESMBAGA1UEBwwJQW5uIEFyYm9yMSsw
KQYDVQQKDCJVbml2ZXJzaXR5IG9mIE1pY2hpZ2FuIGFuZCB0aGUgRUZGMRQwEgYD
VQQDDAtleGFtcGxlLmNvbTAeFw0xNTA1MDkwMDI0NTJaFw0xNjA1MDgwMDI0NTJa
MHcxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNaWNoaWdhbjESMBAGA1UEBwwJQW5u
IEFyYm9yMSswKQYDVQQKDCJVbml2ZXJzaXR5IG9mIE1pY2hpZ2FuIGFuZCB0aGUg
RUZGMRQwEgYDVQQDDAtleGFtcGxlLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgC
QQD0thFxUTc2v6qV55wRxfwnBUOeN4bVfu5ywJqy65kzR7T1yZi5TPEiQyM7/3Hg
BVy9ddFc8RX4vNZaR+ROXNEzAgMBAAGjUDBOMB0GA1UdDgQWBBRJieHEVSHKmBk0
mTExx1erzlylCjAfBgNVHSMEGDAWgBRJieHEVSHKmBk0mTExx1erzlylCjAMBgNV
HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA0EABT/nlpqOaanFSLZmWIrKv0zt63k4
bmWNMA8fYT45KYpLomsW8qXdpC82IlVKfNk7fW0UYT3HOeDSJRcycxNCTQ==
-----END CERTIFICATE-----
-6
View File
@@ -1,6 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIGrAgEAAiEAm2Fylv+Uz7trgTW8EBHP3FQSMeZs2GNQ6VRo1sIVJEkCAwEAAQIh
AJT0BA/xD01dFCAXzSNyj9nfSZa3NpqzJZZn/eOm7vghAhEAzUVNZn4lLLBD1R6N
E8TKNQIRAMHHyn3O5JeY36lwKwkUlEUCEAliRauN0L0+QZuYjfJ9aJECEGx4dru3
rTPCyighdqWNlHUCEQCiLjlwSRtWgmMBudCkVjzt
-----END RSA PRIVATE KEY-----
-9
View File
@@ -1,9 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAKx1c7RR7R/drnBSQ/zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79
vukFhN9HFoHZiUvOjm0c+pVE6K+EdE/twuUCAwEAAQJAMbrEnJCrQe8YqAbw1/Bn
elAzIamndfE3U8bTavf9sgFpS4HL83rhd6PDbvx81ucaJAT/5x048fM/nFl4fzAc
mQIhAOF/a9o3EIsDKEmUl+Z1OaOiUxDF3kqWSmALEsmvDhwXAiEAw8ljV5RO/rUp
Zu2YMDFq3MKpyyMgBIJ8CxmGRc6gCmMCIGRQzkcmhfqBrhOFwkmozrqIBRIKJIjj
8TRm2LXWZZ2DAiAqVO7PztdNpynugUy4jtbGKKjBrTSNBRGA7OHlUgm0dQIhALQq
6oGU29Vxlvt3k0vmiRKU4AVfLyNXIGtcWcNG46h/
-----END RSA PRIVATE KEY-----
-9
View File
@@ -1,9 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAPS2EXFRNza/qpXnnBHF/CcFQ543htV+7nLAmrLrmTNHtPXJmLlM
8SJDIzv/ceAFXL110VzxFfi81lpH5E5c0TMCAwEAAQJBALmppYQ/JVARjWBcsEm/
1/bXBJ127YLv4gQIY5baL4r6IdEE33OXMTTmD9wf+ajuq1eaH0htHkwhOvREu0sz
bskCIQD/Cg+xhEVLcwK3pFp3afPIhj1IPFiL3Uy/nqyMZ6O/RQIhAPWiDBofp7Cp
J4dGZs+hkRySq/IOeeRJlNK1Pq64nToXAiBZ7+te1100YSd5KT051SRB94zO13EG
SZESFduVW8rz3QIgK+tLiqg6TYYRQUi/PUTAM4GuKNuZw828RGiPyqHLywUCIQCd
pkZrNphL/y0D7HSbPIfZzD90M2V8tUjlK0BTqk1bHA==
-----END RSA PRIVATE KEY-----
-75
View File
@@ -1,75 +0,0 @@
cert = MAGICDIR/live/sample-renewal/cert.pem
privkey = MAGICDIR/live/sample-renewal/privkey.pem
chain = MAGICDIR/live/sample-renewal/chain.pem
fullchain = MAGICDIR/live/sample-renewal/fullchain.pem
renew_before_expiry = 1 year
# Options and defaults used in the renewal process
[renewalparams]
no_self_upgrade = False
apache_enmod = a2enmod
no_verify_ssl = False
ifaces = None
apache_dismod = a2dismod
register_unsafely_without_email = False
apache_handle_modules = True
uir = None
installer = None
nginx_ctl = nginx
config_dir = MAGICDIR
text_mode = False
func = <function obtain_cert at 0x7f093a163c08>
staging = True
prepare = False
work_dir = /var/lib/letsencrypt
tos = False
init = False
http01_port = 80
duplicate = False
noninteractive_mode = True
key_path = None
nginx = False
nginx_server_root = /etc/nginx
fullchain_path = /home/ubuntu/letsencrypt/chain.pem
email = None
csr = None
agree_dev_preview = None
redirect = None
verb = certonly
verbose_count = -3
config_file = None
renew_by_default = False
hsts = False
apache_handle_sites = True
authenticator = webroot
domains = isnot.org,
rsa_key_size = 2048
apache_challenge_location = /etc/apache2
checkpoints = 1
manual_test_mode = False
apache = False
cert_path = /home/ubuntu/letsencrypt/cert.pem
webroot_path = /var/www/
reinstall = False
expand = False
strict_permissions = False
apache_server_root = /etc/apache2
account = None
dry_run = False
manual_public_ip_logging_ok = False
chain_path = /home/ubuntu/letsencrypt/chain.pem
break_my_certs = False
standalone = True
manual = False
server = https://acme-staging.api.letsencrypt.org/directory
standalone_supported_challenges = "tls-sni-01,http-01"
webroot = True
os_packages_only = False
apache_init_script = None
user_agent = None
apache_le_vhost_ext = -le-ssl.conf
debug = False
tls_sni_01_port = 443
logs_dir = /var/log/letsencrypt
apache_vhost_root = /etc/apache2/sites-available
configurator = None
-76
View File
@@ -1,76 +0,0 @@
cert = MAGICDIR/live/sample-renewal/cert.pem
privkey = MAGICDIR/live/sample-renewal/privkey.pem
chain = MAGICDIR/live/sample-renewal/chain.pem
fullchain = MAGICDIR/live/sample-renewal/fullchain.pem
renew_before_expiry = 4 years
# Options and defaults used in the renewal process
[renewalparams]
no_self_upgrade = False
apache_enmod = a2enmod
no_verify_ssl = False
ifaces = None
apache_dismod = a2dismod
register_unsafely_without_email = False
apache_handle_modules = True
uir = None
installer = None
nginx_ctl = nginx
config_dir = MAGICDIR
text_mode = False
func = <function obtain_cert at 0x7f093a163c08>
staging = True
prepare = False
work_dir = /var/lib/letsencrypt
tos = False
init = False
http01_port = 80
duplicate = False
noninteractive_mode = True
key_path = None
nginx = False
nginx_server_root = /etc/nginx
fullchain_path = /home/ubuntu/letsencrypt/chain.pem
email = None
csr = None
agree_dev_preview = None
redirect = None
verb = certonly
verbose_count = -3
config_file = None
renew_by_default = False
hsts = False
apache_handle_sites = True
authenticator = standalone
domains = isnot.org,
rsa_key_size = 2048
apache_challenge_location = /etc/apache2
checkpoints = 1
manual_test_mode = False
apache = False
cert_path = /home/ubuntu/letsencrypt/cert.pem
webroot_path = None
reinstall = False
expand = False
strict_permissions = False
apache_server_root = /etc/apache2
account = None
dry_run = False
manual_public_ip_logging_ok = False
chain_path = /home/ubuntu/letsencrypt/chain.pem
break_my_certs = False
standalone = True
manual = False
server = https://acme-staging.api.letsencrypt.org/directory
standalone_supported_challenges = "tls-sni-01,http-01"
webroot = False
os_packages_only = False
apache_init_script = None
user_agent = None
apache_le_vhost_ext = -le-ssl.conf
debug = False
tls_sni_01_port = 443
logs_dir = /var/log/letsencrypt
apache_vhost_root = /etc/apache2/sites-available
configurator = None
[[webroot_map]]
-3
View File
@@ -1,3 +0,0 @@
webroot
webroot-path = /tmp
domains = eg.com, eg2.com