mirror of
https://github.com/certbot/certbot.git
synced 2026-08-04 12:21:51 +02:00
fixes to address comments
This commit is contained in:
@@ -55,7 +55,7 @@ class Account(object):
|
|||||||
"""URI link for new registrations."""
|
"""URI link for new registrations."""
|
||||||
if self.regr is not None:
|
if self.regr is not None:
|
||||||
return self.regr.uri
|
return self.regr.uri
|
||||||
else:
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -198,7 +198,7 @@ class Account(object):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_email(cls, config, email):
|
def from_email(cls, config, email):
|
||||||
"""Generate an account from an email address.
|
"""Generate a new account from an email address.
|
||||||
|
|
||||||
:param config: Configuration
|
:param config: Configuration
|
||||||
:type config: :class:`letsencrypt.client.interfaces.IConfig`
|
:type config: :class:`letsencrypt.client.interfaces.IConfig`
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class NamespaceConfig(object):
|
|||||||
def accounts_dir(self): #pylint: disable=missing-docstring
|
def accounts_dir(self): #pylint: disable=missing-docstring
|
||||||
return os.path.join(
|
return os.path.join(
|
||||||
self.namespace.config_dir, constants.ACCOUNTS_DIR,
|
self.namespace.config_dir, constants.ACCOUNTS_DIR,
|
||||||
self.namespace.server.partition(":")[0])
|
self.namespace.server.replace(':', '-').replace('/', '-'))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def account_keys_dir(self): #pylint: disable=missing-docstring
|
def account_keys_dir(self): #pylint: disable=missing-docstring
|
||||||
|
|||||||
@@ -95,6 +95,8 @@ class IConfig(zope.interface.Interface):
|
|||||||
"be trusted in order to avoid further modifications to the client.")
|
"be trusted in order to avoid further modifications to the client.")
|
||||||
authenticator = zope.interface.Attribute(
|
authenticator = zope.interface.Attribute(
|
||||||
"Authenticator to use for responding to challenges.")
|
"Authenticator to use for responding to challenges.")
|
||||||
|
email = zope.interface.Attribute(
|
||||||
|
"Email used for registration and recovery contact.")
|
||||||
rsa_key_size = zope.interface.Attribute("Size of the RSA key.")
|
rsa_key_size = zope.interface.Attribute("Size of the RSA key.")
|
||||||
|
|
||||||
config_dir = zope.interface.Attribute("Configuration directory.")
|
config_dir = zope.interface.Attribute("Configuration directory.")
|
||||||
@@ -110,7 +112,7 @@ class IConfig(zope.interface.Interface):
|
|||||||
accounts_dir = zope.interface.Attribute(
|
accounts_dir = zope.interface.Attribute(
|
||||||
"Directory where all account information is stored.")
|
"Directory where all account information is stored.")
|
||||||
account_keys_dir = zope.interface.Attribute(
|
account_keys_dir = zope.interface.Attribute(
|
||||||
"Directory where all account keys are stored".)
|
"Directory where all account keys are stored.")
|
||||||
rec_token_dir = zope.interface.Attribute(
|
rec_token_dir = zope.interface.Attribute(
|
||||||
"Directory where all recovery tokens are saved.")
|
"Directory where all recovery tokens are saved.")
|
||||||
key_dir = zope.interface.Attribute("Keys storage.")
|
key_dir = zope.interface.Attribute("Keys storage.")
|
||||||
|
|||||||
@@ -86,9 +86,7 @@ class Network(object):
|
|||||||
logging.debug(
|
logging.debug(
|
||||||
'Ignoring wrong Content-Type (%r) for JSON Error',
|
'Ignoring wrong Content-Type (%r) for JSON Error',
|
||||||
response_ct)
|
response_ct)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# TODO: This is insufficient or doesn't work as intended.
|
|
||||||
logging.error("Error: %s", jobj)
|
logging.error("Error: %s", jobj)
|
||||||
logging.error("Response from server: %s", response.content)
|
logging.error("Response from server: %s", response.content)
|
||||||
raise messages2.Error.from_json(jobj)
|
raise messages2.Error.from_json(jobj)
|
||||||
@@ -328,7 +326,7 @@ class Network(object):
|
|||||||
body=messages2.ChallengeBody.from_json(response.json()))
|
body=messages2.ChallengeBody.from_json(response.json()))
|
||||||
# TODO: check that challr.uri == response.headers['Location']?
|
# TODO: check that challr.uri == response.headers['Location']?
|
||||||
if challr.uri != challb.uri:
|
if challr.uri != challb.uri:
|
||||||
raise errors.UnexpectedUpdate(challb.uri)
|
raise errors.UnexpectedUpdate(challr.uri)
|
||||||
return challr
|
return challr
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class AccountTest(unittest.TestCase):
|
|||||||
"""Tests letsencrypt.client.account.Account."""
|
"""Tests letsencrypt.client.account.Account."""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
from letsencrypt.client import account
|
from letsencrypt.client.account import Account
|
||||||
|
|
||||||
logging.disable(logging.CRITICAL)
|
logging.disable(logging.CRITICAL)
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ class AccountTest(unittest.TestCase):
|
|||||||
recovery_token="recovery_token", agreement="agreement")
|
recovery_token="recovery_token", agreement="agreement")
|
||||||
)
|
)
|
||||||
|
|
||||||
self.test_account = account.Account(
|
self.test_account = Account(
|
||||||
self.config, self.key, self.email, None, self.regr)
|
self.config, self.key, self.email, None, self.regr)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
@@ -61,27 +61,34 @@ class AccountTest(unittest.TestCase):
|
|||||||
@mock.patch("letsencrypt.client.account.zope.component.getUtility")
|
@mock.patch("letsencrypt.client.account.zope.component.getUtility")
|
||||||
@mock.patch("letsencrypt.client.account.crypto_util.init_save_key")
|
@mock.patch("letsencrypt.client.account.crypto_util.init_save_key")
|
||||||
def test_prompts(self, mock_key, mock_util):
|
def test_prompts(self, mock_key, mock_util):
|
||||||
from letsencrypt.client import account
|
from letsencrypt.client.account import Account
|
||||||
|
|
||||||
displayer = display_util.FileDisplay(sys.stdout)
|
|
||||||
zope.component.provideUtility(displayer)
|
|
||||||
|
|
||||||
mock_util().input.return_value = (display_util.OK, self.email)
|
mock_util().input.return_value = (display_util.OK, self.email)
|
||||||
mock_key.return_value = self.key
|
mock_key.return_value = self.key
|
||||||
|
|
||||||
acc = account.Account.from_prompts(self.config)
|
acc = Account.from_prompts(self.config)
|
||||||
self.assertEqual(acc.email, self.email)
|
self.assertEqual(acc.email, self.email)
|
||||||
self.assertEqual(acc.key, self.key)
|
self.assertEqual(acc.key, self.key)
|
||||||
self.assertEqual(acc.config, self.config)
|
self.assertEqual(acc.config, self.config)
|
||||||
|
|
||||||
|
@mock.patch("letsencrypt.client.account.zope.component.getUtility")
|
||||||
|
@mock.patch("letsencrypt.client.account.Account.from_email")
|
||||||
|
def test_prompts_bad_email(self, mock_from_email, mock_util):
|
||||||
|
from letsencrypt.client.account import Account
|
||||||
|
|
||||||
|
mock_from_email.side_effect = (errors.LetsEncryptClientError, "acc")
|
||||||
|
mock_util().input.return_value = (display_util.OK, self.email)
|
||||||
|
|
||||||
|
self.assertEqual(Account.from_prompts(self.config), "acc")
|
||||||
|
|
||||||
|
|
||||||
@mock.patch("letsencrypt.client.account.zope.component.getUtility")
|
@mock.patch("letsencrypt.client.account.zope.component.getUtility")
|
||||||
@mock.patch("letsencrypt.client.account.crypto_util.init_save_key")
|
@mock.patch("letsencrypt.client.account.crypto_util.init_save_key")
|
||||||
def test_prompts_empty_email(self, mock_key, mock_util):
|
def test_prompts_empty_email(self, mock_key, mock_util):
|
||||||
displayer = display_util.FileDisplay(sys.stdout)
|
from letsencrypt.client.account import Account
|
||||||
zope.component.provideUtility(displayer)
|
|
||||||
|
|
||||||
mock_util().input.return_value = (display_util.OK, "")
|
mock_util().input.return_value = (display_util.OK, "")
|
||||||
acc = account.Account.from_prompts(self.config)
|
acc = Account.from_prompts(self.config)
|
||||||
self.assertTrue(acc.email is None)
|
self.assertTrue(acc.email is None)
|
||||||
# _get_config_filename | pylint: disable=protected-access
|
# _get_config_filename | pylint: disable=protected-access
|
||||||
mock_key.assert_called_once_with(
|
mock_key.assert_called_once_with(
|
||||||
@@ -89,17 +96,23 @@ class AccountTest(unittest.TestCase):
|
|||||||
|
|
||||||
@mock.patch("letsencrypt.client.account.zope.component.getUtility")
|
@mock.patch("letsencrypt.client.account.zope.component.getUtility")
|
||||||
def test_prompts_cancel(self, mock_util):
|
def test_prompts_cancel(self, mock_util):
|
||||||
from letsencrypt.client import account
|
from letsencrypt.client.account import Account
|
||||||
|
|
||||||
mock_util().input.return_value = (display_util.CANCEL, "")
|
mock_util().input.return_value = (display_util.CANCEL, "")
|
||||||
|
|
||||||
self.assertTrue(account.Account.from_prompts(self.config) is None)
|
self.assertTrue(Account.from_prompts(self.config) is None)
|
||||||
|
|
||||||
|
def test_from_email(self):
|
||||||
|
from letsencrypt.client.account import Account
|
||||||
|
|
||||||
|
self.assertRaises(errors.LetsEncryptClientError,
|
||||||
|
Account.from_email, self.config, "not_valid...email")
|
||||||
|
|
||||||
def test_save_from_existing_account(self):
|
def test_save_from_existing_account(self):
|
||||||
from letsencrypt.client import account
|
from letsencrypt.client.account import Account
|
||||||
|
|
||||||
self.test_account.save()
|
self.test_account.save()
|
||||||
acc = account.Account.from_existing_account(self.config, self.email)
|
acc = Account.from_existing_account(self.config, self.email)
|
||||||
|
|
||||||
self.assertEqual(acc.key, self.test_account.key)
|
self.assertEqual(acc.key, self.test_account.key)
|
||||||
self.assertEqual(acc.email, self.test_account.email)
|
self.assertEqual(acc.email, self.test_account.email)
|
||||||
@@ -113,35 +126,22 @@ class AccountTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.test_account.recovery_token, "recovery_token")
|
self.assertEqual(self.test_account.recovery_token, "recovery_token")
|
||||||
|
|
||||||
def test_partial_properties(self):
|
def test_partial_properties(self):
|
||||||
from letsencrypt.client import account
|
from letsencrypt.client.account import Account
|
||||||
|
|
||||||
partial = account.Account(self.config, self.key)
|
partial = Account(self.config, self.key)
|
||||||
regr_no_authzr_uri = messages2.RegistrationResource(
|
|
||||||
uri="uri",
|
|
||||||
new_authzr_uri=None,
|
|
||||||
terms_of_service="terms_of_service",
|
|
||||||
body=messages2.Registration(
|
|
||||||
recovery_token="recovery_token", agreement="agreement")
|
|
||||||
)
|
|
||||||
partial2 = account.Account(
|
|
||||||
self.config, self.key, regr=regr_no_authzr_uri)
|
|
||||||
|
|
||||||
self.assertTrue(partial.uri is None)
|
self.assertTrue(partial.uri is None)
|
||||||
self.assertTrue(partial.new_authzr_uri is None)
|
self.assertTrue(partial.new_authzr_uri is None)
|
||||||
self.assertTrue(partial.terms_of_service is None)
|
self.assertTrue(partial.terms_of_service is None)
|
||||||
self.assertTrue(partial.recovery_token is None)
|
self.assertTrue(partial.recovery_token is None)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
partial2.new_authzr_uri,
|
|
||||||
"https://letsencrypt-demo.org/acme/new-authz")
|
|
||||||
|
|
||||||
def test_partial_account_default(self):
|
def test_partial_account_default(self):
|
||||||
from letsencrypt.client import account
|
from letsencrypt.client.account import Account
|
||||||
|
|
||||||
partial = account.Account(self.config, self.key)
|
partial = Account(self.config, self.key)
|
||||||
partial.save()
|
partial.save()
|
||||||
|
|
||||||
acc = account.Account.from_existing_account(self.config)
|
acc = Account.from_existing_account(self.config)
|
||||||
|
|
||||||
self.assertEqual(partial.key, acc.key)
|
self.assertEqual(partial.key, acc.key)
|
||||||
self.assertEqual(partial.email, acc.email)
|
self.assertEqual(partial.email, acc.email)
|
||||||
@@ -149,33 +149,33 @@ class AccountTest(unittest.TestCase):
|
|||||||
self.assertEqual(partial.regr, acc.regr)
|
self.assertEqual(partial.regr, acc.regr)
|
||||||
|
|
||||||
def test_get_accounts(self):
|
def test_get_accounts(self):
|
||||||
from letsencrypt.client import account
|
from letsencrypt.client.account import Account
|
||||||
|
|
||||||
accs = account.Account.get_accounts(self.config)
|
accs = Account.get_accounts(self.config)
|
||||||
self.assertFalse(accs)
|
self.assertFalse(accs)
|
||||||
|
|
||||||
self.test_account.save()
|
self.test_account.save()
|
||||||
accs = account.Account.get_accounts(self.config)
|
accs = Account.get_accounts(self.config)
|
||||||
self.assertEqual(len(accs), 1)
|
self.assertEqual(len(accs), 1)
|
||||||
self.assertEqual(accs[0].email, self.test_account.email)
|
self.assertEqual(accs[0].email, self.test_account.email)
|
||||||
|
|
||||||
acc2 = account.Account(self.config, self.key, "testing_email@gmail.com")
|
acc2 = Account(self.config, self.key, "testing_email@gmail.com")
|
||||||
acc2.save()
|
acc2.save()
|
||||||
accs = account.Account.get_accounts(self.config)
|
accs = Account.get_accounts(self.config)
|
||||||
self.assertEqual(len(accs), 2)
|
self.assertEqual(len(accs), 2)
|
||||||
|
|
||||||
def test_get_accounts_no_accounts(self):
|
def test_get_accounts_no_accounts(self):
|
||||||
from letsencrypt.client import account
|
from letsencrypt.client.account import Account
|
||||||
|
|
||||||
self.assertEqual(account.Account.get_accounts(
|
self.assertEqual(Account.get_accounts(
|
||||||
mock.Mock(accounts_dir="non-existant")), [])
|
mock.Mock(accounts_dir="non-existant")), [])
|
||||||
|
|
||||||
def test_failed_existing_account(self):
|
def test_failed_existing_account(self):
|
||||||
from letsencrypt.client import account
|
from letsencrypt.client.account import Account
|
||||||
|
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
errors.LetsEncryptClientError,
|
errors.LetsEncryptClientError,
|
||||||
account.Account.from_existing_account,
|
Account.from_existing_account,
|
||||||
self.config, "non-existant@email.org")
|
self.config, "non-existant@email.org")
|
||||||
|
|
||||||
class SafeEmailTest(unittest.TestCase):
|
class SafeEmailTest(unittest.TestCase):
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class NamespaceConfigTest(unittest.TestCase):
|
|||||||
from letsencrypt.client.configuration import NamespaceConfig
|
from letsencrypt.client.configuration import NamespaceConfig
|
||||||
namespace = mock.MagicMock(
|
namespace = mock.MagicMock(
|
||||||
config_dir='/tmp/config', work_dir='/tmp/foo', foo='bar',
|
config_dir='/tmp/config', work_dir='/tmp/foo', foo='bar',
|
||||||
server='acme-server.org:443')
|
server='acme-server.org:443/new')
|
||||||
self.config = NamespaceConfig(namespace)
|
self.config = NamespaceConfig(namespace)
|
||||||
|
|
||||||
def test_proxy_getattr(self):
|
def test_proxy_getattr(self):
|
||||||
@@ -33,10 +33,10 @@ class NamespaceConfigTest(unittest.TestCase):
|
|||||||
self.config.cert_key_backup, '/tmp/foo/c/acme-server.org')
|
self.config.cert_key_backup, '/tmp/foo/c/acme-server.org')
|
||||||
self.assertEqual(self.config.rec_token_dir, '/r')
|
self.assertEqual(self.config.rec_token_dir, '/r')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.config.accounts_dir, '/tmp/config/acc/acme-server.org')
|
self.config.accounts_dir, '/tmp/config/acc/acme-server.org-443-new')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.config.account_keys_dir,
|
self.config.account_keys_dir,
|
||||||
'/tmp/config/acc/acme-server.org/keys')
|
'/tmp/config/acc/acme-server.org-443-new/keys')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
+21
-19
@@ -70,7 +70,7 @@ def create_parser():
|
|||||||
|
|
||||||
add("-k", "--authkey", type=read_file,
|
add("-k", "--authkey", type=read_file,
|
||||||
help="Path to the authorized key file")
|
help="Path to the authorized key file")
|
||||||
add("m", "--email", type=str,
|
add("-m", "--email", type=str,
|
||||||
help="Email address used for account registration.")
|
help="Email address used for account registration.")
|
||||||
add("-B", "--rsa-key-size", type=int, default=2048, metavar="N",
|
add("-B", "--rsa-key-size", type=int, default=2048, metavar="N",
|
||||||
help=config_help("rsa_key_size"))
|
help=config_help("rsa_key_size"))
|
||||||
@@ -176,6 +176,24 @@ def main(): # pylint: disable=too-many-branches, too-many-statements
|
|||||||
client.rollback(args.rollback, config)
|
client.rollback(args.rollback, config)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
# Prepare for init of Client
|
||||||
|
if args.email is None:
|
||||||
|
acc = client.determine_account(config)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
# The way to get the default would be args.email = ""
|
||||||
|
# First try existing account
|
||||||
|
acc = account.Account.from_existing_account(config, args.email)
|
||||||
|
except errors.LetsEncryptClientError:
|
||||||
|
try:
|
||||||
|
# Try to make an account based on the email address
|
||||||
|
acc = account.Account.from_email(config, args.email)
|
||||||
|
except errors.LetsEncryptClientError:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if acc is None:
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
if not args.tos:
|
if not args.tos:
|
||||||
display_eula()
|
display_eula()
|
||||||
|
|
||||||
@@ -206,26 +224,10 @@ def main(): # pylint: disable=too-many-branches, too-many-statements
|
|||||||
if not doms:
|
if not doms:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
# Prepare for init of Client
|
|
||||||
if args.email is None:
|
|
||||||
acc = client.determine_account(config)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
# The way to get the default would be args.email = ""
|
|
||||||
acc = account.from_existing_account(config, args.email)
|
|
||||||
except errors.LetsEncryptClientError:
|
|
||||||
try:
|
|
||||||
acc = account.from_email(config, args.email)
|
|
||||||
except errors.LetsEncryptClientError:
|
|
||||||
logging.error("Invalid email address given")
|
|
||||||
|
|
||||||
if acc is None:
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
acme = client.Client(config, acc, auth, installer)
|
acme = client.Client(config, acc, auth, installer)
|
||||||
|
|
||||||
# Validate the key and csr
|
# Validate the key and csr
|
||||||
client.validate_key_csr(account.key)
|
client.validate_key_csr(acc.key)
|
||||||
|
|
||||||
# This more closely mimics the capabilities of the CLI
|
# This more closely mimics the capabilities of the CLI
|
||||||
# It should be possible for reconfig only, install-only, no-install
|
# It should be possible for reconfig only, install-only, no-install
|
||||||
@@ -236,7 +238,7 @@ def main(): # pylint: disable=too-many-branches, too-many-statements
|
|||||||
acme.register()
|
acme.register()
|
||||||
cert_file, chain_file = acme.obtain_certificate(doms)
|
cert_file, chain_file = acme.obtain_certificate(doms)
|
||||||
if installer is not None and cert_file is not None:
|
if installer is not None and cert_file is not None:
|
||||||
acme.deploy_certificate(doms, account.key, cert_file, chain_file)
|
acme.deploy_certificate(doms, acc.key, cert_file, chain_file)
|
||||||
if installer is not None:
|
if installer is not None:
|
||||||
acme.enhance_config(doms, args.redirect)
|
acme.enhance_config(doms, args.redirect)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user