From 20efe7b5334dc4dbbcb67ccd563aeef65646b5d7 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Wed, 17 Dec 2014 10:12:59 +0100 Subject: [PATCH] zope.interface --- docs/api/client/configurator.rst | 5 -- docs/api/client/interfaces.rst | 5 ++ docs/api/client/validator.rst | 5 -- letsencrypt/client/augeas_configurator.py | 6 +- letsencrypt/client/challenge.py | 27 +----- letsencrypt/client/interactive_challenge.py | 10 ++- .../client/{configurator.py => interfaces.py} | 89 ++++++++++++------- .../client/recovery_contact_challenge.py | 9 +- .../client/recovery_token_challenge.py | 12 +-- letsencrypt/client/validator.py | 14 --- setup.py | 1 + 11 files changed, 87 insertions(+), 96 deletions(-) delete mode 100644 docs/api/client/configurator.rst create mode 100644 docs/api/client/interfaces.rst delete mode 100644 docs/api/client/validator.rst rename letsencrypt/client/{configurator.py => interfaces.py} (60%) delete mode 100644 letsencrypt/client/validator.py diff --git a/docs/api/client/configurator.rst b/docs/api/client/configurator.rst deleted file mode 100644 index 7331f35ec..000000000 --- a/docs/api/client/configurator.rst +++ /dev/null @@ -1,5 +0,0 @@ -:mod:`letsencrypt.client.configurator` --------------------------------------- - -.. automodule:: letsencrypt.client.configurator - :members: diff --git a/docs/api/client/interfaces.rst b/docs/api/client/interfaces.rst new file mode 100644 index 000000000..e14daed7f --- /dev/null +++ b/docs/api/client/interfaces.rst @@ -0,0 +1,5 @@ +:mod:`letsencrypt.client.interfaces` +------------------------------------ + +.. automodule:: letsencrypt.client.interfaces + :members: diff --git a/docs/api/client/validator.rst b/docs/api/client/validator.rst deleted file mode 100644 index 7f990e2a4..000000000 --- a/docs/api/client/validator.rst +++ /dev/null @@ -1,5 +0,0 @@ -:mod:`letsencrypt.client.validator` ------------------------------------ - -.. automodule:: letsencrypt.client.validator - :members: diff --git a/letsencrypt/client/augeas_configurator.py b/letsencrypt/client/augeas_configurator.py index 0ad813c8a..080376793 100644 --- a/letsencrypt/client/augeas_configurator.py +++ b/letsencrypt/client/augeas_configurator.py @@ -6,13 +6,14 @@ import shutil import time import augeas +import zope.interface from letsencrypt.client import CONFIG -from letsencrypt.client import configurator +from letsencrypt.client import interfaces from letsencrypt.client import le_util -class AugeasConfigurator(configurator.Configurator): +class AugeasConfigurator(object): """Base Augeas Configurator class. .. todo:: Fix generic exception handling. @@ -24,6 +25,7 @@ class AugeasConfigurator(configurator.Configurator): :ivar dict direc: dictionary containing save directory paths """ + zope.interface.implements(interfaces.IConfigurator) def __init__(self, direc=None): """Initialize Augeas Configurator. diff --git a/letsencrypt/client/challenge.py b/letsencrypt/client/challenge.py index 44aabcda4..b2eb33c53 100644 --- a/letsencrypt/client/challenge.py +++ b/letsencrypt/client/challenge.py @@ -5,29 +5,6 @@ import sys from letsencrypt.client import CONFIG -class Challenge(object): - """Let's Encrypt challenge.""" - - def __init__(self, configurator): - self.config = configurator - - def perform(self, quiet=True): - """Perform the challange. - - :param bool quiet: TODO - - """ - raise NotImplementedError() - - def generate_response(self): - """Generate response.""" - raise NotImplementedError() - - def cleanup(self): - """Cleanup.""" - raise NotImplementedError() - - def gen_challenge_path(challenges, combos=None): """Generate a plan to get authority over the identity. @@ -101,13 +78,13 @@ def _find_smart_path(challenges, combos): def _find_dumb_path(challenges): - """Find challange path without server hints. + """Find challenge path without server hints. Should be called if the combinations hint is not included by the server. This function returns the best path that does not contain multiple mutually exclusive challenges. - :param list challanges: A list of challenges from ACME "challenge" + :param list challenges: A list of challenges from ACME "challenge" server message to be fulfilled by the client in order to prove possession of the identifier. diff --git a/letsencrypt/client/interactive_challenge.py b/letsencrypt/client/interactive_challenge.py index 4f93f1e4f..c802ca191 100644 --- a/letsencrypt/client/interactive_challenge.py +++ b/letsencrypt/client/interactive_challenge.py @@ -1,12 +1,13 @@ import textwrap import dialog +import zope.interface -from letsencrypt.client import challenge +from letsencrypt.client import interfaces -class InteractiveChallenge(challenge.Challenge): - """Interactive challange. +class InteractiveChallenge(object): + """Interactive challenge. Interactive challenge displays the string sent by the CA formatted to fit on the screen of the client. The Challenge also adds proper @@ -14,9 +15,12 @@ class InteractiveChallenge(challenge.Challenge): process. """ + zope.interface.implements(interfaces.IChallenge) + BOX_SIZE = 70 def __init__(self, string): + super(InteractiveChallenge, self).__init__() self.string = string def perform(self, quiet=True): diff --git a/letsencrypt/client/configurator.py b/letsencrypt/client/interfaces.py similarity index 60% rename from letsencrypt/client/configurator.py rename to letsencrypt/client/interfaces.py index c47557289..cbe71cd4c 100644 --- a/letsencrypt/client/configurator.py +++ b/letsencrypt/client/interfaces.py @@ -1,16 +1,36 @@ -"""Configurator.""" +"""Let's Encrypt client interfaces.""" +import zope.interface + +# pylint: disable=no-self-argument,no-method-argument + +class IChallenge(zope.interface.Interface): + """Let's Encrypt challenge.""" + + def perform(quiet=True): + """Perform the challenge. + + :param bool quiet: TODO + + """ + + def generate_response(): + """Generate response.""" + + def cleanup(): + """Cleanup.""" -class Configurator(object): +class IConfigurator(zope.interface.Interface): """Generic Let's Encrypt configurator. Class represents all possible webservers and configuration editors This includes the generic webserver which wont have configuration files at all, but instead create a new process to handle the DVSNI and other challenges. + """ - def deploy_cert(self, vhost, cert, key, cert_chain=None): + def deploy_cert(vhost, cert, key, cert_chain=None): """Deploy certificate. :param vhost @@ -18,42 +38,34 @@ class Configurator(object): :param str key: Private key """ - raise NotImplementedError() - def choose_virtual_host(self, name): + def choose_virtual_host(name): """Chooses a virtual host based on a given domain name.""" - raise NotImplementedError() - def get_all_names(self): + def get_all_names(): """Returns all names found in the configuration.""" - raise NotImplementedError() - def enable_redirect(self, ssl_vhost): + def enable_redirect(ssl_vhost): """Redirect all traffic to the given ssl_vhost (port 80 => 443).""" - raise NotImplementedError() - def enable_hsts(self, ssl_vhost): + def enable_hsts(ssl_vhost): """Enable HSTS on the given ssl_vhost.""" - raise NotImplementedError() - def enable_ocsp_stapling(self, ssl_vhost): + def enable_ocsp_stapling(ssl_vhost): """Enable OCSP stapling on given ssl_vhost.""" - raise NotImplementedError() - def get_all_certs_keys(self): + def get_all_certs_keys(): """Retrieve all certs and keys set in configuration. :returns: List of tuples with form [(cert, key, path)]. :rtype: list """ - raise NotImplementedError() - def enable_site(self, vhost): + def enable_site(vhost): """Enable the site at the given vhost.""" - raise NotImplementedError() - def save(self, title=None, temporary=False): + def save(title=None, temporary=False): """Saves all changes to the configuration files. Both title and temporary are needed because a save may be @@ -66,33 +78,42 @@ class Configurator(object): :param bool temporary: Indicates whether the changes made will be quickly reversed in the future (challenges) + """ - raise NotImplementedError() - def revert_challenge_config(self): + def revert_challenge_config(): """Reload the users original configuration files.""" - raise NotImplementedError() - def rollback_checkpoints(self, rollback=1): + def rollback_checkpoints(rollback=1): """Revert `rollback` number of configuration checkpoints.""" - raise NotImplementedError() - def display_checkpoints(self): + def display_checkpoints(): """Display the saved configuration checkpoints.""" - raise NotImplementedError() - def config_test(self): + def config_test(): """Make sure the configuration is valid.""" - raise NotImplementedError() - def restart(self, quiet=False): + def restart(quiet=False): """Restart or refresh the server content.""" - raise NotImplementedError() - def perform(self, chall_dict): + def perform(chall_dict): """Perform the given challenge""" - raise NotImplementedError() - def cleanup(self): + def cleanup(): """Cleanup configuration changes from challenge.""" - raise NotImplementedError() + + +class IValidator(object): + """Configuration validator.""" + + def redirect(name): + pass + + def ocsp_stapling(name): + pass + + def https(names): + pass + + def hsts(name): + pass diff --git a/letsencrypt/client/recovery_contact_challenge.py b/letsencrypt/client/recovery_contact_challenge.py index 6b8f23e91..d5cd5f889 100644 --- a/letsencrypt/client/recovery_contact_challenge.py +++ b/letsencrypt/client/recovery_contact_challenge.py @@ -8,19 +8,22 @@ import time import dialog import requests +import zope.interface -from letsencrypt.client import challenge +from letsencrypt.client import interfaces -class RecoveryContact(challenge.Challenge): - """Recovery Contact Identitifier Validation Challange. +class RecoveryContact(object): + """Recovery Contact Identitifier Validation Challenge. Based on draft-barnes-acme, section 6.3. """ + zope.interface.implements(interfaces.IChallenge) def __init__(self, activation_url="", success_url="", contact="", poll_delay=3): + super(RecoveryContact, self).__init__() self.token = "" self.activation_url = activation_url self.success_url = success_url diff --git a/letsencrypt/client/recovery_token_challenge.py b/letsencrypt/client/recovery_token_challenge.py index 04a3d3ec9..abe8789b7 100644 --- a/letsencrypt/client/recovery_token_challenge.py +++ b/letsencrypt/client/recovery_token_challenge.py @@ -3,20 +3,22 @@ .. note:: This challenge has not been implemented into the project yet """ -import display +import zope.interface -from letsencrypt.client import challenge +from letsencrypt.client import display +from letsencrypt.client import interfaces -class RecoveryToken(challenge.Challenge): +class RecoveryToken(object): """Recovery Token Identifier Validation Challenge. Based on draft-barnes-acme, section 6.4. """ + zope.interface.implements(interfaces.IChallenge) - def __init__(self, configurator): - super(RecoveryToken, self).__init__(configurator) + def __init__(self): + super(RecoveryToken, self).__init__() self.token = "" def perform(self, quiet=True): diff --git a/letsencrypt/client/validator.py b/letsencrypt/client/validator.py deleted file mode 100644 index 716d1528f..000000000 --- a/letsencrypt/client/validator.py +++ /dev/null @@ -1,14 +0,0 @@ -class Validator(object): - """Configuration validator.""" - - def redirect(self, name): - raise NotImplementedError() - - def ocsp_stapling(self, name): - raise NotImplementedError() - - def https(self, names): - raise NotImplementedError() - - def hsts(self, name): - raise NotImplementedError() diff --git a/setup.py b/setup.py index 8a473ebb4..f5190807c 100755 --- a/setup.py +++ b/setup.py @@ -11,6 +11,7 @@ install_requires = [ 'python-augeas', 'python2-pythondialog', 'requests', + 'zope.interface', ] docs_extras = [