Unify docs

This commit is contained in:
Jakub Warmuz 2014-11-30 01:20:36 +01:00
parent 56b75e93ce
commit 59a7559c05
10 changed files with 207 additions and 311 deletions

View file

@ -285,3 +285,5 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'http://docs.python.org/': None}
todo_include_todos = True

View file

@ -29,12 +29,10 @@ SCHEMATA = dict([
def acme_object_validate(json_string, schemata=None):
"""Validate a JSON string against the ACME protocol using JSON Schema.
:param json_string: Well-formed input JSON string.
:type json_string: str
:param str json_string: Well-formed input JSON string.
:param schemata: Mapping from type name to JSON Schema definition.
Useful for testing.
:type schemata: dict
:param dict schemata: Mapping from type name to JSON Schema
definition. Useful for testing.
:returns: None if validation was successful.
@ -66,14 +64,12 @@ def pretty(json_string):
def challenge_request(name):
"""Create ACME "challengeRequest message.
:param name: Domain name
:type name: unicode
:param unicode name: Domain name
:returns: ACME "challengeRequest" message.
:rtype: dict
"""
return {
"type": "challengeRequest",
"identifier": name,
@ -84,19 +80,10 @@ def authorization_request(req_id, name, server_nonce, responses, key_file):
"""Create ACME "authorizationRequest" message.
:param req_id: TODO
:type req_id: TODO
:param name: TODO
:type name: TODO
:param server_nonce: TODO
:type server_nonce: TODO
:param responses: TODO
:type response: TODO
:param key_file: TODO
:type key_file: TODO
:returns: ACME "authorizationRequest" message.
:rtype: dict
@ -115,11 +102,8 @@ def authorization_request(req_id, name, server_nonce, responses, key_file):
def certificate_request(csr_der, key):
"""Create ACME "certificateRequest" message.
:param csr_der: DER encoded CSR.
:type csr_der: str
:param str csr_der: DER encoded CSR.
:param key: TODO
:type key: TODO
:returns: ACME "certificateRequest" message.
:rtype: dict
@ -135,12 +119,10 @@ def certificate_request(csr_der, key):
def revocation_request(key_file, cert_der):
"""Create ACME "revocationRequest" message.
:param key_file: Path to a file containing RSA key. Accepted formats
are the same as for `Crypto.PublicKey.RSA.importKey`.
:type key_file: str
:param str key_file: Path to a file containing RSA key. Accepted
formats are the same as for `Crypto.PublicKey.RSA.importKey`.
:param cert_der: DER encoded certificate.
:type cert_der: str
:param str cert_der: DER encoded certificate.
:returns: ACME "revocationRequest" message.
:rtype: dict
@ -156,8 +138,7 @@ def revocation_request(key_file, cert_der):
def status_request(token):
"""Create ACME "statusRequest" message.
:param token: Token provided in ACME "defer" message.
:type token: str
:param str token: Token provided in ACME "defer" message.
:returns: ACME "statusRequest" message.
:rtype: dict

View file

@ -44,6 +44,8 @@ from letsencrypt.client import logger
# transactional due to the use of register_file_creation()
class VH(object):
"""Virtual host."""
def __init__(self, filename_path, vh_path, vh_addrs, is_ssl, is_enabled):
self.file = filename_path
self.path = vh_path
@ -129,25 +131,22 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Deploys certificate to specified virtual host.
Currently tries to find the last directives to deploy the cert in
the given virtualhost. If it can't find the directives, it searches
the "included" confs. The function verifies that it has located
the given virtualhost. If it can't find the directives, it searches
the "included" confs. The function verifies that it has located
the three directives and finally modifies them to point to the correct
destination
TODO: Make sure last directive is changed
TODO: Might be nice to remove chain directive if none exists
* This shouldn't happen within letsencrypt though
.. todo:: Make sure last directive is changed
.. todo:: Might be nice to remove chain directive if none exists
This shouldn't happen within letsencrypt though
:param vhost: ssl vhost to deploy certificate
:type vhost: VH
:type vhost: :class:`VH`
:param cert: certificate filename
:type cert: str
:param key: private key filename
:type key: str
:param cert_chain: certificate chain filename
:type cert_chain: str
:param strcert: certificate filename
:param str key: private key filename
:param str cert_chain: certificate chain filename
:returns: Success
:rtype: bool
@ -196,13 +195,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def choose_virtual_host(self, name, ssl=True):
""" Chooses a virtual host based on the given domain name.
TODO: This should maybe return list if no obvious answer is presented
.. todo:: This should maybe return list if no obvious answer is presented
:param name: domain name
:type name: str
:param str name: domain name
:returns: ssl vhost associated with name
:rtype: VH
:rtype: :class:`VH`
"""
# Allows for domain names to be associated with a virtual host
@ -244,11 +242,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Helps to choose an appropriate vhost
:param domain: domain name to associate
:type domain: str
:param str domain: domain name to associate
:param vhost: virtual host to associate with domain
:type vhost: VH
:type vhost: :class:`VH`
"""
self.assoc[dn] = vh
@ -257,7 +254,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Returns all names found in the Apache Configuration.
:returns: All ServerNames, ServerAliases, and reverse DNS entries for
virtual host addresses
virtual host addresses
:rtype: set
"""
@ -286,10 +283,9 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def _set_user_config_file(self, filename=''):
"""Set the appropriate user configuration file
TODO: This will have to be updated for other distros versions
.. todo:: This will have to be updated for other distros versions
:param filename: optional filename that will be used as the user config
:type filename: str
:param str filename: optional filename that will be used as the user config
"""
if filename:
@ -309,7 +305,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Helper function for get_virtual_hosts().
:param host: In progress vhost whose names will be added
:type host: VH
:type host: :class:`VH`
"""
nameMatch = self.aug.match(("%s//*[self::directive=~regexp('%s')] | "
@ -326,11 +322,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def _create_vhost(self, path):
"""Used by get_virtual_hosts to create vhost objects
:param path: Augeas path to virtual host
:type path: str
:param str path: Augeas path to virtual host
:returns: newly created vhost
:rtype: VH
:rtype: :class:`VH`
"""
addrs = []
@ -353,7 +348,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def get_virtual_hosts(self):
"""Returns list of virtual hosts found in the Apache configuration.
:returns: List of VH objects found in configuration
:returns: List of :class:`VH` objects found in configuration
:rtype: list
"""
@ -372,8 +367,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Checks if addr has a NameVirtualHost directive in the Apache config
:param addr: vhost address ie. *:443
:type addr: str
:param str addr: vhost address ie. \*:443
:returns: Success
:rtype: bool
@ -403,8 +397,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Directive is added to ports.conf unless the file doesn't exist
It is added to httpd.conf as a backup
:param addr: Address that will be added as NameVirtualHost directive
:type addr: str
:param str addr: Address that will be added as NameVirtualHost directive
"""
aug_file_path = "/files%sports.conf" % self.server_root
@ -429,14 +422,9 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
an IfMod mod_ssl.c block. If the IfMod block does not exist in
the file, it is created.
:param aug_conf_path: Desired Augeas config path to add directive
:type aug_conf_path: str
:param directive: Directive you would like to add
:type directive: str
:param val: Value of directive ie. Listen 443, 443 is the value
:type val: str
:param str aug_conf_path: Desired Augeas config path to add directive
:param str directive: Directive you would like to add
:param str val: Value of directive ie. Listen 443, 443 is the value
"""
# TODO: Add error checking code... does the path given even exist?
@ -451,13 +439,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def make_server_sni_ready(self, vhost, default_addr="*:443"):
"""Checks to see if the server is ready for SNI challenges.
TODO: This should largely depend on the version of Apache
.. todo:: This should largely depend on the version of Apache
:param vhost: VHost to check SNI compatibility
:type vhost: VH
:type vhost: :class:`VH`
:param default_addr: TODO - investigate function further
:type default_addr: str
:param str default_addr: TODO - investigate function further
"""
# Check if mod_ssl is loaded
@ -498,11 +485,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def get_ifmod(self, aug_conf_path, mod):
"""Returns the path to <IfMod mod> and creates one if it doesn't exist.
:param aug_conf_path: Augeas configuration path
:type aug_conf_path: str
:param mod: module ie. mod_ssl.c
:type mod: str
:param str aug_conf_path: Augeas configuration path
:param str mod: module ie. mod_ssl.c
"""
ifMods = self.aug.match(("%s/IfModule/*[self::arg='%s']" %
@ -520,14 +504,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Note: Not added to AugeasConfigurator because it may depend on the lens
:param aug_conf_path: Augeas configuration path to add directive
:type aug_conf_path: str
:param str aug_conf_path: Augeas configuration path to add directive
:param str directive: Directive to add
:param str arg: Value of the directive. ie. Listen 443, 443 is arg
:param directive: Directive to add
:type directive: str
:param arg: Value of the directive. ie. Listen 443, 443 is arg
:type arg: str
"""
self.aug.set(aug_conf_path + "/directive[last() + 1]", directive)
@ -544,7 +524,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Recursively searches through config files to find directives
Directives should be in the form of a case insensitive regex currently
TODO: arg should probably be a list
.. todo:: arg should probably be a list
Note: Augeas is inherently case sensitive while Apache is case
insensitive. Augeas 1.0 allows case insensitive regexes like
@ -553,15 +534,13 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
transformation by calling case_i() on everything to maintain
compatibility.
:param directive: Directive to look for
:type directive: str
:param str directive: Directive to look for
:param arg: Specific value direcitve must have, None if all should
be considered
:type arg: str or None
:param start: Beginning Augeas path to begin looking
:type start: str
:param str start: Beginning Augeas path to begin looking
"""
# Cannot place member variable in the definition of the function so...
@ -606,13 +585,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Converts an Apache Include directive argument into an Augeas
searchable path
TODO: convert to use os.path.join()
:param cur_dir: current working directory
:type cur_dir: str
.. todo:: convert to use os.path.join()
:param arg: Argument of Include directive
:type arg: str
:param str cur_dir: current working directory
:param str arg: Argument of Include directive
:returns: Augeas path string
:rtype: str
@ -676,7 +654,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Checks to see if mod_ssl is loaded
Currently uses apache2ctl to get loaded module list
TODO: This function is likely fragile to versions/distros
.. todo:: This function is likely fragile to versions/distros
:returns: If ssl_module is included and active in Apache
:rtype: bool
@ -704,10 +683,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
New vhost will reside as (nonssl_vhost.path) + CONFIG.LE_VHOST_EXT
:param nonssl_vhost: Valid VH that doesn't have SSLEngine on
:type nonssl_vhost: VH
:type nonssl_vhost: :class:`VH`
:returns: SSL vhost
:rtype: VH
:rtype: :class:`VH`
"""
avail_fp = nonssl_vhost.file
@ -809,10 +788,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
The function then adds the directive
:param ssl_vhost: Destination of traffic, an ssl enabled vhost
:type ssl_vhost: VH
:type ssl_vhost: :class:`VH`
:returns: Success, general_vhost (HTTP vhost)
:rtype: bool, VH
:rtype: (bool, :class:`VH`)
"""
# TODO: Enable check to see if it is already there
@ -858,7 +837,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
-1 is also returned in case of no redirection/rewrite directives
:param vhost: vhost to check
:type vhost: VH
:type vhost: :class:`VH`
:returns: Success, code value... see documentation
:rtype: bool, int
@ -889,10 +868,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Creates an http_vhost specifically to redirect for the ssl_vhost.
:param ssl_vhost: ssl vhost
:type ssl_vhost: VH
:type ssl_vhost: :class:`VH`
:returns: Success, vhost
:rtype: bool, VH
:rtype: (bool, :class:`VH`)
"""
# Consider changing this to a dictionary check
@ -973,7 +952,7 @@ LogLevel warn \n\
if not conflict: returns space separated list of new host addrs
:param ssl_vhost: SSL Vhost to check for possible port 80 redirection
:type ssl_vhost: VH
:type ssl_vhost: :class:`VH`
:returns: TODO
:rtype: TODO
@ -1012,10 +991,10 @@ LogLevel warn \n\
Consider changing this into a dict check
:param ssl_vhost: ssl vhost to check
:type ssl_vhost: VH
:type ssl_vhost: :class:`VH`
:returns: HTTP vhost or None if unsuccessful
:rtype: VH or None
:rtype: :class:`VH` or None
"""
# _default_:443 check
@ -1090,8 +1069,7 @@ LogLevel warn \n\
Takes in Augeas path and returns the file name
:param vhost_path: Augeas virtual host path
:type vhost_path: str
:param str vhost_path: Augeas virtual host path
:returns: filename of vhost
:rtype: str
@ -1116,10 +1094,9 @@ LogLevel warn \n\
def is_site_enabled(self, avail_fp):
"""Checks to see if the given site is enabled.
TODO: fix hardcoded sites-enabled
.. todo:: fix hardcoded sites-enabled
:param avail_fp: Complete file path of available site
:type avail_fp: str
:param str avail_fp: Complete file path of available site
:returns: Success
:rtype: bool
@ -1135,11 +1112,12 @@ LogLevel warn \n\
def enable_site(self, vhost):
"""Enables an available site, Apache restart required.
TODO: This function should number subdomains before the domain vhost
TODO: Make sure link is not broken...
.. todo:: This function should number subdomains before the domain vhost
.. todo:: Make sure link is not broken...
:param vhost: vhost to enable
:type vhost: VH
:type vhost: :class:`VH`
:returns: Success
:rtype: bool
@ -1164,8 +1142,7 @@ LogLevel warn \n\
Both enables and restarts Apache so module is active.
:param mod_name: Name of the module to enable
:type mod_name: str
:param str mod_name: Name of the module to enable
"""
try:
@ -1185,8 +1162,7 @@ LogLevel warn \n\
def fnmatch_to_re(self, clean_fn_match):
"""Method converts Apache's basic fnmatch to regular expression.
:param clean_fn_match: Apache style filename match, similar to globs
:type clean_fn_match: str
:param str clean_fn_match: Apache style filename match, similar to globs
:returns: regex suitable for augeas
:rtype: str
@ -1212,8 +1188,7 @@ LogLevel warn \n\
Checks to see if file_path is parsed by Augeas
If file_path isn't parsed, the file is added and Augeas is reloaded
:param file_path: Apache config file path
:type file_path: str
:param str file_path: Apache config file path
"""
# Test if augeas included file for Httpd.lens
@ -1313,8 +1288,7 @@ LogLevel warn \n\
This function will correctly add a transform to augeas
The existing augeas.add_transform in python is broken.
:param incl: TODO
:type incl: str
:param str incl: TODO
"""
lastInclude = self.aug.match("/augeas/load/Httpd/incl [last()]")
@ -1354,8 +1328,7 @@ LogLevel warn \n\
def perform(self, chall_dict):
"""Perform the configuration related challenge.
:param chall_dict: Dictionary representing a challenge.
:type chall_dict: dict
:param dict chall_dict: Dictionary representing a challenge.
"""
@ -1366,13 +1339,16 @@ LogLevel warn \n\
def dvsni_perform(self, chall_dict):
"""Peform a DVSNI challenge.
Composed of
listSNITuple: List of tuples with form (addr, r, nonce)
addr (string), r (base64 string), nonce (hex string)
dvsni_key: string - File path to key
Composed of:
:param chall_dict: dvsni challenge - see documentation
:type chall_dict: dict
listSNITuple
List of tuples with form (addr, r, nonce)
addr (string), r (base64 string), nonce (hex string)
dvsni_key
string - File path to key
:param dict chall_dict: dvsni challenge - see documentation
"""
# Save any changes to the configuration as a precaution
@ -1437,8 +1413,7 @@ LogLevel warn \n\
def dvsni_get_cert_file(self, nonce):
"""Returns standardized name for challenge certificate.
:param nonce: hex form of nonce
:type nonce: str
:param str nonce: hex form of nonce
:returns: certificate file name
:rtype: str
@ -1449,14 +1424,9 @@ LogLevel warn \n\
def _get_config_text(self, nonce, ip_addrs, key):
"""Chocolate virtual server configuration text
:param nonce: hex form of nonce
:type nonce: str
:param ip_addrs: addresses of challenged domain
:type ip_addrs: str
:param key: file path to key
:type key: str
:param str nonce: hex form of nonce
:param str ip_addrs: addresses of challenged domain
:param str key: file path to key
:returns: virtual host configuration text
:rtype: str
@ -1483,18 +1453,14 @@ LogLevel warn \n\
Result: Apache config includes virtual servers for issued challs
:param mainConfig: file path to Apache user config file
:type mainConfig: str
:param str mainConfig: file path to Apache user config file
:param listSNITuple: list of tuples with the form (addr, y, nonce)
addr (string), y (byte array), nonce (hex string)
:type listSNITuple: lsit
:param list listSNITuple: list of tuples with the form (addr, y, nonce)
addr (string), y (byte array), nonce (hex string)
:param dvsni_key: file path to key
:type dvsni_key: str
:param str dvsni_key: file path to key
:param listlistAddrs: list of list of addresses to apply
:type listlistAddrs: list
:param list listlistAddrs: list of list of addresses to apply
"""
# WARNING: THIS IS A POTENTIAL SECURITY VULNERABILITY
@ -1527,8 +1493,7 @@ LogLevel warn \n\
Adds DVSNI challenge include file if it does not already exist
within mainConfig
:param mainConfig: file path to main user apache config file
:type mainConfig: str
:param str mainConfig: file path to main user apache config file
"""
if len(self.find_directive(
@ -1542,11 +1507,8 @@ LogLevel warn \n\
Certificate created at dvsni_get_cert_file(nonce)
:param nonce: hex form of nonce
:type nonce: str
:param key_file: absolute path to key file
:type key: str
:param str nonce: hex form of nonce
:param str key_file: absolute path to key file
"""
try:
@ -1566,11 +1528,8 @@ LogLevel warn \n\
def dvsni_gen_ext(self, r, s):
"""Generates z extension to be placed in certificate extension.
:param r: DVSNI r value
:type r: byte array
:param s: DVSNI s value
:type s: byte array
:param bytearray r: DVSNI r value
:param bytearray s: DVSNI s value
result: returns z + CONFIG.INVALID_EXT
@ -1591,8 +1550,7 @@ def case_i(string):
May be replaced by a more proper /i once augeas 1.0 is widely
supported.
:param string: string to make case i regex
:type string: str
:param str string: string to make case i regex
"""
return "".join(["["+c.upper()+c.lower()+"]"
@ -1602,10 +1560,10 @@ def case_i(string):
def strip_dir(path):
"""Returns directory of file path.
TODO: Replace this with Python standard function
.. todo:: Replace this with Python standard function
:param path: path is a file path. not an augeas section or directive path
:type path: str
:param str path: path is a file path. not an augeas section or
directive path
:returns: directory
:rtype: str

View file

@ -12,6 +12,7 @@ from letsencrypt.client import logger
class AugeasConfigurator(configurator.Configurator):
"""Augeas configurator."""
def __init__(self):
super(AugeasConfigurator, self).__init__()
@ -24,8 +25,7 @@ class AugeasConfigurator(configurator.Configurator):
def check_parsing_errors(self, lens):
"""Verify Augeas can parse all of the lens files.
:param lens: lens to check for errors
:type lens: str
:param str lens: lens to check for errors
"""
error_files = self.aug.match("/augeas//error")
@ -48,14 +48,12 @@ class AugeasConfigurator(configurator.Configurator):
all configuration changes made will be saved. According to the
function parameters.
:param title: The title of the save. If a title is given, the
configuration will be saved as a new checkpoint
and put in a timestamped directory.
:type title: str
:param str title: The title of the save. If a title is given, the
configuration will be saved as a new checkpoint and put in a
timestamped directory.
:param temporary: Indicates whether the changes made will be quickly
reversed in the future (ie. challenges)
:type temporary: bool
:param bool temporary: Indicates whether the changes made will
be quickly reversed in the future (ie. challenges)
"""
save_state = self.aug.get("/augeas/save")
@ -141,8 +139,7 @@ class AugeasConfigurator(configurator.Configurator):
def rollback_checkpoints(self, rollback=1):
"""Revert 'rollback' number of configuration checkpoints.
:param rollback: Number of checkpoints to reverse
:type rollback: int
:param int rollback: Number of checkpoints to reverse
"""
try:
@ -222,8 +219,7 @@ class AugeasConfigurator(configurator.Configurator):
Adds title to cp_dir CHANGES_SINCE
Move cp_dir to Backups directory and rename with timestamp
:param cp_dir: "IN PROGRESS" directory
:type cp_dir: str
:param str cp_dir: "IN PROGRESS" directory
:returns: Success
:rtype: bool
@ -250,11 +246,8 @@ class AugeasConfigurator(configurator.Configurator):
def add_to_checkpoint(self, cp_dir, save_files):
"""Add save files to checkpoint directory.
:param cp_dir: Checkpoint directory filepath
:type cp_dir: str
:param save_files: set of files to save
:type save_files: set
:param str cp_dir: Checkpoint directory filepath
:param set save_files: set of files to save
"""
le_util.make_or_verify_dir(cp_dir, 0o755)
@ -289,8 +282,7 @@ class AugeasConfigurator(configurator.Configurator):
Recover a specific checkpoint provided by cp_dir
Note: this function does not reload augeas.
:param cp_dir: checkpoint directory file path
:type cp_dir: str
:param str cp_dir: checkpoint directory file path
:returns: 0 success, 1 Unable to revert, -1 Unable to delete
:rtype: int
@ -322,8 +314,7 @@ class AugeasConfigurator(configurator.Configurator):
def check_tempfile_saves(self, save_files):
"""Verify save isn't overwriting any temporary files.
:param save_files: Set of files about to be saved.
:type save_files: set
:param set save_files: Set of files about to be saved.
:returns: Success, error message
:rtype: bool, str
@ -347,12 +338,10 @@ class AugeasConfigurator(configurator.Configurator):
file will be cleaned up if the program exits unexpectedly.
(Before a save occurs)
:param temporary: If the file creation registry is for a temp or
permanent save.
:type temporary: bool
:param bool temporary: If the file creation registry is for
a temp or permanent save.
:param *files: file paths to be registered
:type *files: str
:param \*files: file paths (str) to be registered
"""
if temporary:
@ -395,8 +384,7 @@ class AugeasConfigurator(configurator.Configurator):
def _remove_contained_files(self, file_list):
"""Erase all files contained within file_list.
:param file_list: file containing list of file paths to be deleted
:type file_list: str
:param str file_list: file containing list of file paths to be deleted
:returns: Success
:rtype: bool

View file

@ -23,18 +23,16 @@ class Challenge(object):
def gen_challenge_path(challenges, combos=None):
"""Generate a plan to get authority over the identity.
TODO: Make sure that the challenges are feasible...
Example: Do you have the recovery key?
.. todo:: Make sure that the challenges are feasible...
Example: Do you have the recovery key?
:param challenges: A list of challenges from ACME "challenge"
server message to be fulfilled by the client
in order to prove possession of the identifier.
:type challenges: list
: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.
:param combos: A collection of sets of challenges from ACME
"challenge" server message ("combinations"),
each of which would be sufficient to prove
possession of the identifier.
"challenge" server message ("combinations"), each of which would
be sufficient to prove possession of the identifier.
:type combos: list or None
:returns: List of indices from `challenges`.
@ -49,19 +47,17 @@ def gen_challenge_path(challenges, combos=None):
def _find_smart_path(challenges, combos):
"""
Can be called if combinations is included
Can be called if combinations is included
Function uses a simple ranking system to choose the combo with the
lowest cost
:param challenges: A list of challenges from ACME "challenge"
server message to be fulfilled by the client
in order to prove possession of the identifier.
:type challenges: list
: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.
:param combos: A collection of sets of challenges from ACME
"challenge" server message ("combinations"),
each of which would be sufficient to prove
possession of the identifier.
"challenge" server message ("combinations"), each of which would
be sufficient to prove possession of the identifier.
:type combos: list or None
:returns: List of indices from `challenges`.
@ -102,10 +98,9 @@ def _find_dumb_path(challenges):
This function returns the best path that does not contain multiple
mutually exclusive challenges
:param challanges: A list of challenges from ACME "challenge"
server message to be fulfilled by the client
in order to prove possession of the identifier.
:type challenges: list
:param list challanges: A list of challenges from ACME "challenge"
server message to be fulfilled by the client in order to prove
possession of the identifier.
:returns: List of indices from `challenges`.
:rtype: list

View file

@ -157,9 +157,12 @@ class Client(object):
def acme_challenge(self):
"""Handle ACME "challenge" phase.
TODO: Handle more than one domain name in self.names
.. todo:: Handle more than one domain name in self.names
:returns: ACME "challenge" message.
:rtype: dict
"""
return self.send_and_receive_expected(
acme.challenge_request(self.names[0]), "challenge")
@ -167,14 +170,10 @@ class Client(object):
def acme_authorization(self, challenge_msg, chal_objs, responses):
"""Handle ACME "authorization" phase.
:param challenge_msg: ACME "challenge" message.
:type challenge_msg: dict
:param dict challenge_msg: ACME "challenge" message.
:param chal_objs: TODO
:type chal_objs: TODO
:param responses: TODO
:type responses: TODO
:returns: ACME "authorization" message.
:rtype: dict
@ -196,8 +195,7 @@ class Client(object):
def acme_certificate(self, csr_der):
"""Handle ACME "certificate" phase.
:param csr_der: CSR in DER format.
:type csr_der: str
:param str csr_der: CSR in DER format.
:returns: ACME "certificate" message.
:rtype: dict
@ -210,8 +208,7 @@ class Client(object):
def acme_revocation(self, cert):
"""Handle ACME "revocation" phase.
:param cert: TODO
:type cert: dict
:param dict cert: TODO
:returns: ACME "revocation" message.
:rtype: dict
@ -235,8 +232,7 @@ class Client(object):
def send(self, msg):
"""Send ACME message to server.
:param msg: ACME message (JSON serializable).
:type msg: dict
:param dict msg: ACME message (JSON serializable).
:returns: Server response message.
:rtype: dict
@ -274,11 +270,8 @@ class Client(object):
def send_and_receive_expected(self, msg, expected):
"""Send ACME message to server and return expected message.
:param msg: ACME message (JSON serializable).
:type msg: dict
:param expected: Name of the expected response ACME message type.
:type expected: str
:param dict msg: ACME message (JSON serializable).
:param str expected: Name of the expected response ACME message type.
:returns: ACME response message of expected type.
:rtype: dict
@ -296,19 +289,15 @@ class Client(object):
def is_expected_msg(self, response, expected, delay=3, rounds=20):
"""Is reponse expected ACME message?
:param response: ACME response message from server.
:type response: dict
:param dict response: ACME response message from server.
:param expected: Name of the expected response ACME message type.
:type expected: str
:param str expected: Name of the expected response ACME message type.
:param delay: Number of seconds to delay before next round in case
of ACME "defer" response message.
:type delay: int
:param int delay: Number of seconds to delay before next round
in case of ACME "defer" response message.
:param rounds: Number of resend attempts in case of ACME "defer"
reponse message.
:type rounds: int
:param int rounds: Number of resend attempts in case of ACME "defer"
reponse message.
:returns: ACME response message from server.
:rtype: dict
@ -387,8 +376,7 @@ class Client(object):
def choose_certs(self, certs):
"""Display choose certificates menu.
:param certs: List of cert dicts.
:type certs: list
:param list certs: List of cert dicts.
"""
code, tag = display.display_certs(certs)
@ -478,8 +466,7 @@ class Client(object):
def verify_identity(self, challenge_msg):
"""Verify identity.
:param challenge_msg: ACME "challenge" message.
:type challenge_msg: dict
:param dict challenge_msg: ACME "challenge" message.
:returns: TODO
:rtype: dict
@ -519,11 +506,9 @@ class Client(object):
def store_cert_key(self, cert_file, encrypt=False):
"""Store certificate key.
:param cert_file: Path to a certificate file.
:type cert_file: str
:param str cert_file: Path to a certificate file.
:param encrypt: Should the certificate key be encrypted?
:type encrypt: bool
:param bool encrypt: Should the certificate key be encrypted?
:returns: True if key file was stored successfully, False otherwise.
:rtype: bool
@ -584,15 +569,12 @@ class Client(object):
"""
:param name: TODO
:type name: TODO
:param challenges: A list of challenges from ACME "challenge"
server message to be fulfilled by the client
in order to prove possession of the identifier.
:type challenges: list
: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.
:param path: List of indices from `challenges`.
:type path: list
:param list path: List of indices from `challenges`.
:returns: A pair of TODO
:rtype: tuple
@ -748,8 +730,7 @@ class Client(object):
def remove_cert_key(cert):
"""Remove certificate key.
:param cert:
:type cert: dict
:param dict cert:
"""
list_file = os.path.join(CONFIG.CERT_KEY_BACKUP, "LIST")

View file

@ -11,6 +11,13 @@ class Configurator(object):
"""
def deploy_cert(self, vhost, cert, key, cert_chain=None):
"""Deploy certificate.
:param vhost
:param str cert: CSR
:param str key: Private key
"""
raise NotImplementedError()
def choose_virtual_host(self, name):
@ -53,12 +60,12 @@ class Configurator(object):
intended to be permanent, but the save is not ready to be a full
checkpoint
title: string - The title of the save. If a title is given, the
configuration will be saved as a new checkpoint
and put in a timestamped directory.
`title` has no effect if temporary is true.
temporary: boolean - Indicates whether the changes made will be
quickly reversed in the future (challenges)
:param str title: The title of the save. If a title is given, the
configuration will be saved as a new checkpoint and put in a
timestamped directory. `title` has no effect if temporary is true.
:param bool temporary: Indicates whether the changes made will
be quickly reversed in the future (challenges)
"""
raise NotImplementedError()

View file

@ -25,23 +25,22 @@ def b64_cert_to_pem(b64_der_cert):
def create_sig(msg, key_str, nonce=None, nonce_len=CONFIG.NONCE_SIZE):
"""Create signature with nonce prepended to the message.
TODO: Change this over to M2Crypto... PKey
Protect against crypto unicode errors... is this sufficient?
Do I need to escape?
.. todo:: Change this over to M2Crypto... PKey
:param msg: Message to be signed
:type msg: Anything with __str__ method
.. todo::Protect against crypto unicode errors... is this sufficient?
Do I need to escape?
:param key_str: Key in string form. Accepted formats
are the same as for `Crypto.PublicKey.RSA.importKey`.
:param str key_str: Key in string form. Accepted formats
are the same as for `Crypto.PublicKey.RSA.importKey`.
:type key_str: str
:param str msg: Message to be signed
:param nonce: Nonce to be used. If None, nonce of `nonce_len` size
will be randomly genereted.
:type nonce: str or None
:param nonce_len: Size of the automaticaly generated nonce.
:type nonce_len: int
:param int nonce_len: Size of the automaticaly generated nonce.
:returns: Signature.
:rtype: dict
@ -176,8 +175,7 @@ def make_ss_cert(key_str, domains):
def get_cert_info(filename):
"""Get certificate info.
:param filename: Name of file containing certificate in PEM format.
:type filename: str
:param str filename: Name of file containing certificate in PEM format.
:rtype: dict
@ -213,8 +211,7 @@ def valid_csr(csr):
Check if `csr` is a valid CSR for the given domains.
:param csr: CSR file contents
:type csr: str
:param str csr: CSR file contents
:returns: Validity of CSR.
:rtype: bool
@ -233,11 +230,10 @@ def csr_matches_names(csr, domains):
M2Crypto currently does not expose the OpenSSL interface to
also check the SAN extension. This is insufficient for full testing
:param csr: CSR file contents
:param str csr: CSR file contents
:type csr: str
:param domains: Domains the CSR should contain.
:type domains: list
:param list domains: Domains the CSR should contain.
:returns: If the CSR subject contains one of the domains
:rtype: bool
@ -253,8 +249,7 @@ def csr_matches_names(csr, domains):
def valid_privkey(privkey):
"""Is valid RSA private key?
:param privkey: Private key file contents
:type privkey: str
:param str privkey: Private key file contents
:returns: Validity of private key.
:rtype: bool
@ -269,11 +264,8 @@ def valid_privkey(privkey):
def csr_matches_pubkey(csr, privkey):
"""Does private key correspond to the subject public key in the CSR?
:param csr: CSR file contents
:type csr: str
:param privkey: Private key file contents
:type privkey: str
:param str csr: CSR file contents
:param str privkey: Private key file contents
:returns: Correspondence of private key to CSR subject public key.
:rtype: bool

View file

@ -10,14 +10,9 @@ from letsencrypt.client import errors
def make_or_verify_dir(directory, mode=0o755, uid=0):
"""Make sure directory exists with proper permissions.
:param directory: Path to a directry.
:type directory: str
:param mode: Diretory mode.
:type mode: int
:param uid: Directory owner.
:type uid: int
:param str directory: Path to a directry.
:param int mode: Diretory mode.
:param int uid: Directory owner.
:raises LetsEncryptClientError: if a directory already exists,
but has wrong permissions or owner
@ -38,16 +33,12 @@ def make_or_verify_dir(directory, mode=0o755, uid=0):
def check_permissions(filepath, mode, uid=0):
"""Check file or directory permissions.
:param filepath: Path to the tested file (or directory).
:type filepath: str
:param str filepath: Path to the tested file (or directory).
:param int mode: Expected file mode.
:param int uid: Expected file owner.
:param mode: Expected file mode.
:type mode: int
:param uid: Expected file owner.
:type uid: int
:returns: bool -- True if `mode` and `uid` match, False otherwise.
:returns: True if `mode` and `uid` match, False otherwise.
:rtype: bool
"""
file_stat = os.stat(filepath)
@ -94,11 +85,11 @@ def jose_b64encode(data):
:param data: Data to be encoded.
:type data: str or bytearray
:raises TypeError: if input is of incorrect type
:returns: JOSE Base64 string.
:rtype: str
:raises TypeError: if `data` is of incorrect type
"""
if not isinstance(data, str):
raise TypeError('argument should be str or bytearray')
@ -112,11 +103,11 @@ def jose_b64decode(data):
only ASCII characters are allowed.
:type data: str or unicode
:returns: Decoded data.
:raises TypeError: if input is of incorrect type
:raises ValueError: if unput is unicode with non-ASCII characters
:returns: Decoded data.
"""
if isinstance(data, unicode):
try:

View file

@ -1,3 +1,4 @@
"""Logger."""
import logger
import textwrap
import time