Merge pull request #105 from kuba/docs

Sphinx docs, various doc fixes
This commit is contained in:
James Kasten
2014-11-29 21:32:17 -08:00
36 changed files with 1123 additions and 372 deletions
+1
View File
@@ -0,0 +1 @@
_build/
+183
View File
@@ -0,0 +1,183 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/LetsEncrypt.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/LetsEncrypt.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/LetsEncrypt"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/LetsEncrypt"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.CONFIG`
--------------------------------
.. automodule:: letsencrypt.client.CONFIG
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.acme`
------------------------------
.. automodule:: letsencrypt.client.acme
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.apache_configurator`
---------------------------------------------
.. automodule:: letsencrypt.client.apache_configurator
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.augeas_configurator`
---------------------------------------------
.. automodule:: letsencrypt.client.augeas_configurator
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.challenge`
-----------------------------------
.. automodule:: letsencrypt.client.challenge
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.client`
--------------------------------
.. automodule:: letsencrypt.client.client
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.configurator`
--------------------------------------
.. automodule:: letsencrypt.client.configurator
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.crypto_util`
-------------------------------------
.. automodule:: letsencrypt.client.crypto_util
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.display`
---------------------------------
.. automodule:: letsencrypt.client.display
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.errors`
--------------------------------
.. automodule:: letsencrypt.client.errors
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client`
-------------------------
.. automodule:: letsencrypt.client
:members:
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.interactive_challenge`
-----------------------------------------------
.. automodule:: letsencrypt.client.interactive_challenge
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.le_util`
---------------------------------
.. automodule:: letsencrypt.client.le_util
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.logger`
--------------------------------
.. automodule:: letsencrypt.client.logger
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.nginx_configurator`
--------------------------------------------
.. automodule:: letsencrypt.client.nginx_configurator
:members:
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.recovery_contact_challenge`
----------------------------------------------------
.. automodule:: letsencrypt.client.recovery_contact_challenge
:members:
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.recovery_token_challenge`
--------------------------------------------------
.. automodule:: letsencrypt.client.recovery_token_challenge
:members:
+5
View File
@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.validator`
-----------------------------------
.. automodule:: letsencrypt.client.validator
:members:
+289
View File
@@ -0,0 +1,289 @@
# -*- coding: utf-8 -*-
#
# Let's Encrypt documentation build configuration file, created by
# sphinx-quickstart on Sun Nov 23 20:35:21 2014.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'sphinx.ext.coverage',
'sphinx.ext.viewcode',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Let\'s Encrypt'
copyright = u'2014, Let\'s Encrypt Project'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'LetsEncryptdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'LetsEncrypt.tex', u'Let\'s Encrypt Documentation',
u'Let\'s Encrypt Project', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'letsencrypt', u'Let\'s Encrypt Documentation',
[u'Let\'s Encrypt Project'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'LetsEncrypt', u'Let\'s Encrypt Documentation',
u'Let\'s Encrypt Project', 'LetsEncrypt', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'http://docs.python.org/': None}
todo_include_todos = True
+24
View File
@@ -0,0 +1,24 @@
.. Let's Encrypt documentation master file, created by
sphinx-quickstart on Sun Nov 23 20:35:21 2014.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Let's Encrypt's documentation!
=========================================
API documentation
-----------------
.. toctree::
:glob:
api/**
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
+263
View File
@@ -0,0 +1,263 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
echo. coverage to run coverage check of the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
REM Check if sphinx-build is available and fallback to Python version if any
%SPHINXBUILD% 2> nul
if errorlevel 9009 goto sphinx_python
goto sphinx_ok
:sphinx_python
set SPHINXBUILD=python -m sphinx.__init__
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
:sphinx_ok
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\LetsEncrypt.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\LetsEncrypt.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "coverage" (
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
if errorlevel 1 exit /b 1
echo.
echo.Testing of coverage in the sources finished, look at the ^
results in %BUILDDIR%/coverage/python.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end
+46 -25
View File
@@ -1,62 +1,83 @@
"""Config for Let's Encrypt."""
import os.path import os.path
# CA hostname
# If you create your own server... change this line
# Note: the server certificate must be trusted in order to avoid
# further modifications to the client
ACME_SERVER = "letsencrypt-demo.org" ACME_SERVER = "letsencrypt-demo.org"
# Apache server root directory """CA hostname.
If you create your own server... change this line
Note: the server certificate must be trusted in order to avoid
further modifications to the client."""
SERVER_ROOT = "/etc/apache2/" SERVER_ROOT = "/etc/apache2/"
# Configuration file directory for letsencrypt """Apache server root directory"""
CONFIG_DIR = "/etc/letsencrypt/" CONFIG_DIR = "/etc/letsencrypt/"
# Working directory for letsencrypt """Configuration file directory for letsencrypt"""
WORK_DIR = "/var/lib/letsencrypt/" WORK_DIR = "/var/lib/letsencrypt/"
# Directory where configuration backups are stored """Working directory for letsencrypt"""
BACKUP_DIR = os.path.join(WORK_DIR, "backups/") BACKUP_DIR = os.path.join(WORK_DIR, "backups/")
# Replaces MODIFIED_FILES, directory where temp checkpoint is created """Directory where configuration backups are stored"""
TEMP_CHECKPOINT_DIR = os.path.join(WORK_DIR, "temp_checkpoint/") TEMP_CHECKPOINT_DIR = os.path.join(WORK_DIR, "temp_checkpoint/")
# Directory used before a permanent checkpoint is finalized """Replaces MODIFIED_FILES, directory where temp checkpoint is created"""
IN_PROGRESS_DIR = os.path.join(BACKUP_DIR, "IN_PROGRESS/") IN_PROGRESS_DIR = os.path.join(BACKUP_DIR, "IN_PROGRESS/")
# Directory where all certificates/keys are stored - used for easy revocation """Directory used before a permanent checkpoint is finalized"""
CERT_KEY_BACKUP = os.path.join(WORK_DIR, "keys-certs/") CERT_KEY_BACKUP = os.path.join(WORK_DIR, "keys-certs/")
# Where all keys should be stored """Directory where all certificates/keys are stored.
Used for easy revocation"""
KEY_DIR = os.path.join(SERVER_ROOT, "ssl/") KEY_DIR = os.path.join(SERVER_ROOT, "ssl/")
# Certificate storage """Where all keys should be stored"""
CERT_DIR = os.path.join(SERVER_ROOT, "certs/") CERT_DIR = os.path.join(SERVER_ROOT, "certs/")
"""Certificate storage"""
# Contains standard Apache SSL directives
OPTIONS_SSL_CONF = os.path.join(CONFIG_DIR, "options-ssl.conf") OPTIONS_SSL_CONF = os.path.join(CONFIG_DIR, "options-ssl.conf")
# Let's Encrypt SSL vhost configuration extension """Contains standard Apache SSL directives"""
LE_VHOST_EXT = "-le-ssl.conf" LE_VHOST_EXT = "-le-ssl.conf"
# Temporary file for challenge virtual hosts """Let's Encrypt SSL vhost configuration extension"""
APACHE_CHALLENGE_CONF = os.path.join(CONFIG_DIR, "le_dvsni_cert_challenge.conf") APACHE_CHALLENGE_CONF = os.path.join(CONFIG_DIR, "le_dvsni_cert_challenge.conf")
"""Temporary file for challenge virtual hosts"""
# Byte size of S and Nonce
S_SIZE = 32 S_SIZE = 32
"""Byte size of S"""
NONCE_SIZE = 16 NONCE_SIZE = 16
"""byte size of Nonce"""
# Key Sizes
RSA_KEY_SIZE = 2048 RSA_KEY_SIZE = 2048
"""Key size"""
# bits of hashcash to generate
DIFFICULTY = 23 DIFFICULTY = 23
"""bits of hashcash to generate"""
# Let's Encrypt cert and chain files
CERT_PATH = CERT_DIR + "cert-letsencrypt.pem" CERT_PATH = CERT_DIR + "cert-letsencrypt.pem"
"""Let's Encrypt cert file."""
CHAIN_PATH = CERT_DIR + "chain-letsencrypt.pem" CHAIN_PATH = CERT_DIR + "chain-letsencrypt.pem"
"""Let's Encrypt chain file."""
# Invalid Extension
INVALID_EXT = ".acme.invalid" INVALID_EXT = ".acme.invalid"
"""Invalid Extension"""
# Challenge Preferences Dict for currently supported challenges
CHALLENGE_PREFERENCES = ["dvsni", "recoveryToken"] CHALLENGE_PREFERENCES = ["dvsni", "recoveryToken"]
"""Challenge Preferences Dict for currently supported challenges"""
# Mutually Exclusive Challenges - only solve 1
EXCLUSIVE_CHALLENGES = [frozenset(["dvsni", "simpleHttps"])] EXCLUSIVE_CHALLENGES = [frozenset(["dvsni", "simpleHttps"])]
"""Mutually Exclusive Challenges - only solve 1"""
# These are challenges that must be solved by a Configurator object
CONFIG_CHALLENGES = frozenset(["dvsni", "simpleHttps"]) CONFIG_CHALLENGES = frozenset(["dvsni", "simpleHttps"])
"""These are challenges that must be solved by a Configurator object"""
# Rewrite rule arguments used for redirections to https vhost
REWRITE_HTTPS_ARGS = [ REWRITE_HTTPS_ARGS = [
"^.*$", "https://%{SERVER_NAME}%{REQUEST_URI}", "[L,R=permanent]"] "^.*$", "https://%{SERVER_NAME}%{REQUEST_URI}", "[L,R=permanent]"]
"""Rewrite rule arguments used for redirections to https vhost"""
+9 -28
View File
@@ -29,12 +29,10 @@ SCHEMATA = dict([
def acme_object_validate(json_string, schemata=None): def acme_object_validate(json_string, schemata=None):
"""Validate a JSON string against the ACME protocol using JSON Schema. """Validate a JSON string against the ACME protocol using JSON Schema.
:param json_string: Well-formed input JSON string. :param str json_string: Well-formed input JSON string.
:type json_string: str
:param schemata: Mapping from type name to JSON Schema definition. :param dict schemata: Mapping from type name to JSON Schema
Useful for testing. definition. Useful for testing.
:type schemata: dict
:returns: None if validation was successful. :returns: None if validation was successful.
@@ -66,14 +64,12 @@ def pretty(json_string):
def challenge_request(name): def challenge_request(name):
"""Create ACME "challengeRequest message. """Create ACME "challengeRequest message.
:param name: Domain name :param unicode name: Domain name
:type name: unicode
:returns: ACME "challengeRequest" message. :returns: ACME "challengeRequest" message.
:rtype: dict :rtype: dict
""" """
return { return {
"type": "challengeRequest", "type": "challengeRequest",
"identifier": name, "identifier": name,
@@ -84,19 +80,10 @@ def authorization_request(req_id, name, server_nonce, responses, key_file):
"""Create ACME "authorizationRequest" message. """Create ACME "authorizationRequest" message.
:param req_id: TODO :param req_id: TODO
:type req_id: TODO
:param name: TODO :param name: TODO
:type name: TODO
:param server_nonce: TODO :param server_nonce: TODO
:type server_nonce: TODO
:param responses: TODO :param responses: TODO
:type response: TODO
:param key_file: TODO :param key_file: TODO
:type key_file: TODO
:returns: ACME "authorizationRequest" message. :returns: ACME "authorizationRequest" message.
:rtype: dict :rtype: dict
@@ -115,11 +102,8 @@ def authorization_request(req_id, name, server_nonce, responses, key_file):
def certificate_request(csr_der, key): def certificate_request(csr_der, key):
"""Create ACME "certificateRequest" message. """Create ACME "certificateRequest" message.
:param csr_der: DER encoded CSR. :param str csr_der: DER encoded CSR.
:type csr_der: str
:param key: TODO :param key: TODO
:type key: TODO
:returns: ACME "certificateRequest" message. :returns: ACME "certificateRequest" message.
:rtype: dict :rtype: dict
@@ -135,12 +119,10 @@ def certificate_request(csr_der, key):
def revocation_request(key_file, cert_der): def revocation_request(key_file, cert_der):
"""Create ACME "revocationRequest" message. """Create ACME "revocationRequest" message.
:param key_file: Path to a file containing RSA key. Accepted formats :param str key_file: Path to a file containing RSA key. Accepted
are the same as for `Crypto.PublicKey.RSA.importKey`. formats are the same as for `Crypto.PublicKey.RSA.importKey`.
:type key_file: str
:param cert_der: DER encoded certificate. :param str cert_der: DER encoded certificate.
:type cert_der: str
:returns: ACME "revocationRequest" message. :returns: ACME "revocationRequest" message.
:rtype: dict :rtype: dict
@@ -156,8 +138,7 @@ def revocation_request(key_file, cert_der):
def status_request(token): def status_request(token):
"""Create ACME "statusRequest" message. """Create ACME "statusRequest" message.
:param token: Token provided in ACME "defer" message. :param str token: Token provided in ACME "defer" message.
:type token: str
:returns: ACME "statusRequest" message. :returns: ACME "statusRequest" message.
:rtype: dict :rtype: dict
+93 -135
View File
@@ -44,6 +44,8 @@ from letsencrypt.client import logger
# transactional due to the use of register_file_creation() # transactional due to the use of register_file_creation()
class VH(object): class VH(object):
"""Virtual host."""
def __init__(self, filename_path, vh_path, vh_addrs, is_ssl, is_enabled): def __init__(self, filename_path, vh_path, vh_addrs, is_ssl, is_enabled):
self.file = filename_path self.file = filename_path
self.path = vh_path self.path = vh_path
@@ -133,21 +135,18 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
the "included" confs. The function verifies that it has located the "included" confs. The function verifies that it has located
the three directives and finally modifies them to point to the correct the three directives and finally modifies them to point to the correct
destination destination
TODO: Make sure last directive is changed
TODO: Might be nice to remove chain directive if none exists .. todo:: Make sure last directive is changed
* This shouldn't happen within letsencrypt though
.. 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 :param vhost: ssl vhost to deploy certificate
:type vhost: VH :type vhost: :class:`VH`
:param cert: certificate filename :param strcert: certificate filename
:type cert: str :param str key: private key filename
:param str cert_chain: certificate chain filename
:param key: private key filename
:type key: str
:param cert_chain: certificate chain filename
:type cert_chain: str
:returns: Success :returns: Success
:rtype: bool :rtype: bool
@@ -196,13 +195,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def choose_virtual_host(self, name, ssl=True): def choose_virtual_host(self, name, ssl=True):
""" Chooses a virtual host based on the given domain name. """ 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 :param str name: domain name
:type name: str
:returns: ssl vhost associated with name :returns: ssl vhost associated with name
:rtype: VH :rtype: :class:`VH`
""" """
# Allows for domain names to be associated with a virtual host # 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 Helps to choose an appropriate vhost
:param domain: domain name to associate :param str domain: domain name to associate
:type domain: str
:param vhost: virtual host to associate with domain :param vhost: virtual host to associate with domain
:type vhost: VH :type vhost: :class:`VH`
""" """
self.assoc[domain] = vhost self.assoc[domain] = vhost
@@ -286,10 +283,9 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def _set_user_config_file(self, filename=''): def _set_user_config_file(self, filename=''):
"""Set the appropriate user configuration file """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 :param str filename: optional filename that will be used as the user config
:type filename: str
""" """
if filename: if filename:
@@ -309,7 +305,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Helper function for get_virtual_hosts(). """Helper function for get_virtual_hosts().
:param host: In progress vhost whose names will be added :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')] | " nameMatch = self.aug.match(("%s//*[self::directive=~regexp('%s')] | "
@@ -326,11 +322,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def _create_vhost(self, path): def _create_vhost(self, path):
"""Used by get_virtual_hosts to create vhost objects """Used by get_virtual_hosts to create vhost objects
:param path: Augeas path to virtual host :param str path: Augeas path to virtual host
:type path: str
:returns: newly created vhost :returns: newly created vhost
:rtype: VH :rtype: :class:`VH`
""" """
addrs = [] addrs = []
@@ -353,7 +348,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def get_virtual_hosts(self): def get_virtual_hosts(self):
"""Returns list of virtual hosts found in the Apache configuration. """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 :rtype: list
""" """
@@ -372,8 +367,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Checks if addr has a NameVirtualHost directive in the Apache config Checks if addr has a NameVirtualHost directive in the Apache config
:param addr: vhost address ie. *:443 :param str addr: vhost address ie. \*:443
:type addr: str
:returns: Success :returns: Success
:rtype: bool :rtype: bool
@@ -403,8 +397,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Directive is added to ports.conf unless the file doesn't exist Directive is added to ports.conf unless the file doesn't exist
It is added to httpd.conf as a backup It is added to httpd.conf as a backup
:param addr: Address that will be added as NameVirtualHost directive :param str addr: Address that will be added as NameVirtualHost directive
:type addr: str
""" """
aug_file_path = "/files%sports.conf" % self.server_root 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 an IfMod mod_ssl.c block. If the IfMod block does not exist in
the file, it is created. the file, it is created.
:param aug_conf_path: Desired Augeas config path to add directive :param str aug_conf_path: Desired Augeas config path to add directive
:type aug_conf_path: str :param str directive: Directive you would like to add
:param str val: Value of directive ie. Listen 443, 443 is the value
: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
""" """
# TODO: Add error checking code... does the path given even exist? # 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"): def make_server_sni_ready(self, vhost, default_addr="*:443"):
"""Checks to see if the server is ready for SNI challenges. """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 :param vhost: VHost to check SNI compatibility
:type vhost: VH :type vhost: :class:`VH`
:param default_addr: TODO - investigate function further :param str default_addr: TODO - investigate function further
:type default_addr: str
""" """
# Check if mod_ssl is loaded # Check if mod_ssl is loaded
@@ -498,11 +485,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def get_ifmod(self, aug_conf_path, mod): def get_ifmod(self, aug_conf_path, mod):
"""Returns the path to <IfMod mod> and creates one if it doesn't exist. """Returns the path to <IfMod mod> and creates one if it doesn't exist.
:param aug_conf_path: Augeas configuration path :param str aug_conf_path: Augeas configuration path
:type aug_conf_path: str :param str mod: module ie. mod_ssl.c
:param mod: module ie. mod_ssl.c
:type mod: str
""" """
ifMods = self.aug.match(("%s/IfModule/*[self::arg='%s']" % 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 Note: Not added to AugeasConfigurator because it may depend on the lens
:param aug_conf_path: Augeas configuration path to add directive :param str aug_conf_path: Augeas configuration path to add directive
:type aug_conf_path: str :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) 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 Recursively searches through config files to find directives
Directives should be in the form of a case insensitive regex currently 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 Note: Augeas is inherently case sensitive while Apache is case
insensitive. Augeas 1.0 allows case insensitive regexes like 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 transformation by calling case_i() on everything to maintain
compatibility. compatibility.
:param directive: Directive to look for :param str directive: Directive to look for
:type directive: str
:param arg: Specific value direcitve must have, None if all should :param arg: Specific value direcitve must have, None if all should
be considered be considered
:type arg: str or None :type arg: str or None
:param start: Beginning Augeas path to begin looking :param str start: Beginning Augeas path to begin looking
:type start: str
""" """
# Cannot place member variable in the definition of the function so... # 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 Converts an Apache Include directive argument into an Augeas
searchable path searchable path
TODO: convert to use os.path.join()
:param cur_dir: current working directory .. todo:: convert to use os.path.join()
:type cur_dir: str
:param arg: Argument of Include directive :param str cur_dir: current working directory
:type arg: str
:param str arg: Argument of Include directive
:returns: Augeas path string :returns: Augeas path string
:rtype: str :rtype: str
@@ -676,7 +654,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Checks to see if mod_ssl is loaded """Checks to see if mod_ssl is loaded
Currently uses apache2ctl to get loaded module list 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 :returns: If ssl_module is included and active in Apache
:rtype: bool :rtype: bool
@@ -704,10 +683,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
New vhost will reside as (nonssl_vhost.path) + CONFIG.LE_VHOST_EXT New vhost will reside as (nonssl_vhost.path) + CONFIG.LE_VHOST_EXT
:param nonssl_vhost: Valid VH that doesn't have SSLEngine on :param nonssl_vhost: Valid VH that doesn't have SSLEngine on
:type nonssl_vhost: VH :type nonssl_vhost: :class:`VH`
:returns: SSL vhost :returns: SSL vhost
:rtype: VH :rtype: :class:`VH`
""" """
avail_fp = nonssl_vhost.file avail_fp = nonssl_vhost.file
@@ -809,10 +788,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
The function then adds the directive The function then adds the directive
:param ssl_vhost: Destination of traffic, an ssl enabled vhost :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) :returns: Success, general_vhost (HTTP vhost)
:rtype: bool, VH :rtype: (bool, :class:`VH`)
""" """
# TODO: Enable check to see if it is already there # 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 -1 is also returned in case of no redirection/rewrite directives
:param vhost: vhost to check :param vhost: vhost to check
:type vhost: VH :type vhost: :class:`VH`
:returns: Success, code value... see documentation :returns: Success, code value... see documentation
:rtype: bool, int :rtype: bool, int
@@ -889,10 +868,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Creates an http_vhost specifically to redirect for the ssl_vhost. """Creates an http_vhost specifically to redirect for the ssl_vhost.
:param ssl_vhost: ssl vhost :param ssl_vhost: ssl vhost
:type ssl_vhost: VH :type ssl_vhost: :class:`VH`
:returns: Success, vhost :returns: Success, vhost
:rtype: bool, VH :rtype: (bool, :class:`VH`)
""" """
# Consider changing this to a dictionary check # 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 if not conflict: returns space separated list of new host addrs
:param ssl_vhost: SSL Vhost to check for possible port 80 redirection :param ssl_vhost: SSL Vhost to check for possible port 80 redirection
:type ssl_vhost: VH :type ssl_vhost: :class:`VH`
:returns: TODO :returns: TODO
:rtype: TODO :rtype: TODO
@@ -1012,10 +991,10 @@ LogLevel warn \n\
Consider changing this into a dict check Consider changing this into a dict check
:param ssl_vhost: ssl vhost to check :param ssl_vhost: ssl vhost to check
:type ssl_vhost: VH :type ssl_vhost: :class:`VH`
:returns: HTTP vhost or None if unsuccessful :returns: HTTP vhost or None if unsuccessful
:rtype: VH or None :rtype: :class:`VH` or None
""" """
# _default_:443 check # _default_:443 check
@@ -1090,8 +1069,7 @@ LogLevel warn \n\
Takes in Augeas path and returns the file name Takes in Augeas path and returns the file name
:param vhost_path: Augeas virtual host path :param str vhost_path: Augeas virtual host path
:type vhost_path: str
:returns: filename of vhost :returns: filename of vhost
:rtype: str :rtype: str
@@ -1116,10 +1094,9 @@ LogLevel warn \n\
def is_site_enabled(self, avail_fp): def is_site_enabled(self, avail_fp):
"""Checks to see if the given site is enabled. """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 :param str avail_fp: Complete file path of available site
:type avail_fp: str
:returns: Success :returns: Success
:rtype: bool :rtype: bool
@@ -1135,11 +1112,12 @@ LogLevel warn \n\
def enable_site(self, vhost): def enable_site(self, vhost):
"""Enables an available site, Apache restart required. """Enables an available site, Apache restart required.
TODO: This function should number subdomains before the domain vhost .. todo:: This function should number subdomains before the domain vhost
TODO: Make sure link is not broken...
.. todo:: Make sure link is not broken...
:param vhost: vhost to enable :param vhost: vhost to enable
:type vhost: VH :type vhost: :class:`VH`
:returns: Success :returns: Success
:rtype: bool :rtype: bool
@@ -1164,8 +1142,7 @@ LogLevel warn \n\
Both enables and restarts Apache so module is active. Both enables and restarts Apache so module is active.
:param mod_name: Name of the module to enable :param str mod_name: Name of the module to enable
:type mod_name: str
""" """
try: try:
@@ -1185,8 +1162,7 @@ LogLevel warn \n\
def fnmatch_to_re(self, clean_fn_match): def fnmatch_to_re(self, clean_fn_match):
"""Method converts Apache's basic fnmatch to regular expression. """Method converts Apache's basic fnmatch to regular expression.
:param clean_fn_match: Apache style filename match, similar to globs :param str clean_fn_match: Apache style filename match, similar to globs
:type clean_fn_match: str
:returns: regex suitable for augeas :returns: regex suitable for augeas
:rtype: str :rtype: str
@@ -1212,8 +1188,7 @@ LogLevel warn \n\
Checks to see if file_path is parsed by Augeas Checks to see if file_path is parsed by Augeas
If file_path isn't parsed, the file is added and Augeas is reloaded If file_path isn't parsed, the file is added and Augeas is reloaded
:param file_path: Apache config file path :param str file_path: Apache config file path
:type file_path: str
""" """
# Test if augeas included file for Httpd.lens # Test if augeas included file for Httpd.lens
@@ -1313,8 +1288,7 @@ LogLevel warn \n\
This function will correctly add a transform to augeas This function will correctly add a transform to augeas
The existing augeas.add_transform in python is broken. The existing augeas.add_transform in python is broken.
:param incl: TODO :param str incl: TODO
:type incl: str
""" """
lastInclude = self.aug.match("/augeas/load/Httpd/incl [last()]") lastInclude = self.aug.match("/augeas/load/Httpd/incl [last()]")
@@ -1354,8 +1328,7 @@ LogLevel warn \n\
def perform(self, chall_dict): def perform(self, chall_dict):
"""Perform the configuration related challenge. """Perform the configuration related challenge.
:param chall_dict: Dictionary representing a challenge. :param dict chall_dict: Dictionary representing a challenge.
:type chall_dict: dict
""" """
@@ -1366,13 +1339,16 @@ LogLevel warn \n\
def dvsni_perform(self, chall_dict): def dvsni_perform(self, chall_dict):
"""Peform a DVSNI challenge. """Peform a DVSNI challenge.
Composed of 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
:param chall_dict: dvsni challenge - see documentation listSNITuple
:type chall_dict: dict 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 # Save any changes to the configuration as a precaution
@@ -1437,8 +1413,7 @@ LogLevel warn \n\
def dvsni_get_cert_file(self, nonce): def dvsni_get_cert_file(self, nonce):
"""Returns standardized name for challenge certificate. """Returns standardized name for challenge certificate.
:param nonce: hex form of nonce :param str nonce: hex form of nonce
:type nonce: str
:returns: certificate file name :returns: certificate file name
:rtype: str :rtype: str
@@ -1449,14 +1424,9 @@ LogLevel warn \n\
def _get_config_text(self, nonce, ip_addrs, key): def _get_config_text(self, nonce, ip_addrs, key):
"""Chocolate virtual server configuration text """Chocolate virtual server configuration text
:param nonce: hex form of nonce :param str nonce: hex form of nonce
:type nonce: str :param str ip_addrs: addresses of challenged domain
:param str key: file path to key
:param ip_addrs: addresses of challenged domain
:type ip_addrs: str
:param key: file path to key
:type key: str
:returns: virtual host configuration text :returns: virtual host configuration text
:rtype: str :rtype: str
@@ -1483,18 +1453,14 @@ LogLevel warn \n\
Result: Apache config includes virtual servers for issued challs Result: Apache config includes virtual servers for issued challs
:param mainConfig: file path to Apache user config file :param str mainConfig: file path to Apache user config file
:type mainConfig: str
:param listSNITuple: list of tuples with the form (addr, y, nonce) :param list listSNITuple: list of tuples with the form (addr, y, nonce)
addr (string), y (byte array), nonce (hex string) addr (string), y (byte array), nonce (hex string)
:type listSNITuple: lsit
:param dvsni_key: file path to key :param str dvsni_key: file path to key
:type dvsni_key: str
:param listlistAddrs: list of list of addresses to apply :param list listlistAddrs: list of list of addresses to apply
:type listlistAddrs: list
""" """
# WARNING: THIS IS A POTENTIAL SECURITY VULNERABILITY # 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 Adds DVSNI challenge include file if it does not already exist
within mainConfig within mainConfig
:param mainConfig: file path to main user apache config file :param str mainConfig: file path to main user apache config file
:type mainConfig: str
""" """
if len(self.find_directive( if len(self.find_directive(
@@ -1542,11 +1507,8 @@ LogLevel warn \n\
Certificate created at dvsni_get_cert_file(nonce) Certificate created at dvsni_get_cert_file(nonce)
:param nonce: hex form of nonce :param str nonce: hex form of nonce
:type nonce: str :param str key_file: absolute path to key file
:param key_file: absolute path to key file
:type key: str
""" """
try: try:
@@ -1567,11 +1529,8 @@ LogLevel warn \n\
def dvsni_gen_ext(self, r, s): def dvsni_gen_ext(self, r, s):
"""Generates z extension to be placed in certificate extension. """Generates z extension to be placed in certificate extension.
:param r: DVSNI r value :param bytearray r: DVSNI r value
:type r: byte array :param bytearray s: DVSNI s value
:param s: DVSNI s value
:type s: byte array
result: returns z + CONFIG.INVALID_EXT result: returns z + CONFIG.INVALID_EXT
@@ -1592,8 +1551,7 @@ def case_i(string):
May be replaced by a more proper /i once augeas 1.0 is widely May be replaced by a more proper /i once augeas 1.0 is widely
supported. supported.
:param string: string to make case i regex :param str string: string to make case i regex
:type string: str
""" """
return "".join(["["+c.upper()+c.lower()+"]" return "".join(["["+c.upper()+c.lower()+"]"
@@ -1603,10 +1561,10 @@ def case_i(string):
def strip_dir(path): def strip_dir(path):
"""Returns directory of file 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 :param str path: path is a file path. not an augeas section or
:type path: str directive path
:returns: directory :returns: directory
:rtype: str :rtype: str
+17 -29
View File
@@ -12,6 +12,7 @@ from letsencrypt.client import logger
class AugeasConfigurator(configurator.Configurator): class AugeasConfigurator(configurator.Configurator):
"""Augeas configurator."""
def __init__(self): def __init__(self):
super(AugeasConfigurator, self).__init__() super(AugeasConfigurator, self).__init__()
@@ -24,8 +25,7 @@ class AugeasConfigurator(configurator.Configurator):
def check_parsing_errors(self, lens): def check_parsing_errors(self, lens):
"""Verify Augeas can parse all of the lens files. """Verify Augeas can parse all of the lens files.
:param lens: lens to check for errors :param str lens: lens to check for errors
:type lens: str
""" """
error_files = self.aug.match("/augeas//error") 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 all configuration changes made will be saved. According to the
function parameters. function parameters.
:param title: The title of the save. If a title is given, the :param str title: The title of the save. If a title is given, the
configuration will be saved as a new checkpoint configuration will be saved as a new checkpoint and put in a
and put in a timestamped directory. timestamped directory.
:type title: str
:param temporary: Indicates whether the changes made will be quickly :param bool temporary: Indicates whether the changes made will
reversed in the future (ie. challenges) be quickly reversed in the future (ie. challenges)
:type temporary: bool
""" """
save_state = self.aug.get("/augeas/save") save_state = self.aug.get("/augeas/save")
@@ -141,8 +139,7 @@ class AugeasConfigurator(configurator.Configurator):
def rollback_checkpoints(self, rollback=1): def rollback_checkpoints(self, rollback=1):
"""Revert 'rollback' number of configuration checkpoints. """Revert 'rollback' number of configuration checkpoints.
:param rollback: Number of checkpoints to reverse :param int rollback: Number of checkpoints to reverse
:type rollback: int
""" """
try: try:
@@ -222,8 +219,7 @@ class AugeasConfigurator(configurator.Configurator):
Adds title to cp_dir CHANGES_SINCE Adds title to cp_dir CHANGES_SINCE
Move cp_dir to Backups directory and rename with timestamp Move cp_dir to Backups directory and rename with timestamp
:param cp_dir: "IN PROGRESS" directory :param str cp_dir: "IN PROGRESS" directory
:type cp_dir: str
:returns: Success :returns: Success
:rtype: bool :rtype: bool
@@ -250,11 +246,8 @@ class AugeasConfigurator(configurator.Configurator):
def add_to_checkpoint(self, cp_dir, save_files): def add_to_checkpoint(self, cp_dir, save_files):
"""Add save files to checkpoint directory. """Add save files to checkpoint directory.
:param cp_dir: Checkpoint directory filepath :param str cp_dir: Checkpoint directory filepath
:type cp_dir: str :param set save_files: set of files to save
:param save_files: set of files to save
:type save_files: set
""" """
le_util.make_or_verify_dir(cp_dir, 0o755) 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 Recover a specific checkpoint provided by cp_dir
Note: this function does not reload augeas. Note: this function does not reload augeas.
:param cp_dir: checkpoint directory file path :param str cp_dir: checkpoint directory file path
:type cp_dir: str
:returns: 0 success, 1 Unable to revert, -1 Unable to delete :returns: 0 success, 1 Unable to revert, -1 Unable to delete
:rtype: int :rtype: int
@@ -322,8 +314,7 @@ class AugeasConfigurator(configurator.Configurator):
def check_tempfile_saves(self, save_files): def check_tempfile_saves(self, save_files):
"""Verify save isn't overwriting any temporary files. """Verify save isn't overwriting any temporary files.
:param save_files: Set of files about to be saved. :param set save_files: Set of files about to be saved.
:type save_files: set
:returns: Success, error message :returns: Success, error message
:rtype: bool, str :rtype: bool, str
@@ -347,12 +338,10 @@ class AugeasConfigurator(configurator.Configurator):
file will be cleaned up if the program exits unexpectedly. file will be cleaned up if the program exits unexpectedly.
(Before a save occurs) (Before a save occurs)
:param temporary: If the file creation registry is for a temp or :param bool temporary: If the file creation registry is for
permanent save. a temp or permanent save.
:type temporary: bool
:param *files: file paths to be registered :param \*files: file paths (str) to be registered
:type *files: str
""" """
if temporary: if temporary:
@@ -395,8 +384,7 @@ class AugeasConfigurator(configurator.Configurator):
def _remove_contained_files(self, file_list): def _remove_contained_files(self, file_list):
"""Erase all files contained within file_list. """Erase all files contained within file_list.
:param file_list: file containing list of file paths to be deleted :param str file_list: file containing list of file paths to be deleted
:type file_list: str
:returns: Success :returns: Success
:rtype: bool :rtype: bool
+14 -19
View File
@@ -23,18 +23,16 @@ class Challenge(object):
def gen_challenge_path(challenges, combos=None): def gen_challenge_path(challenges, combos=None):
"""Generate a plan to get authority over the identity. """Generate a plan to get authority over the identity.
TODO: Make sure that the challenges are feasible... .. todo:: Make sure that the challenges are feasible...
Example: Do you have the recovery key? Example: Do you have the recovery key?
:param challenges: 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 server message to be fulfilled by the client in order to prove
in order to prove possession of the identifier. possession of the identifier.
:type challenges: list
:param combos: A collection of sets of challenges from ACME :param combos: A collection of sets of challenges from ACME
"challenge" server message ("combinations"), "challenge" server message ("combinations"), each of which would
each of which would be sufficient to prove be sufficient to prove possession of the identifier.
possession of the identifier.
:type combos: list or None :type combos: list or None
:returns: List of indices from `challenges`. :returns: List of indices from `challenges`.
@@ -53,15 +51,13 @@ def _find_smart_path(challenges, combos):
Function uses a simple ranking system to choose the combo with the Function uses a simple ranking system to choose the combo with the
lowest cost lowest cost
:param challenges: 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 server message to be fulfilled by the client in order to prove
in order to prove possession of the identifier. possession of the identifier.
:type challenges: list
:param combos: A collection of sets of challenges from ACME :param combos: A collection of sets of challenges from ACME
"challenge" server message ("combinations"), "challenge" server message ("combinations"), each of which would
each of which would be sufficient to prove be sufficient to prove possession of the identifier.
possession of the identifier.
:type combos: list or None :type combos: list or None
:returns: List of indices from `challenges`. :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 This function returns the best path that does not contain multiple
mutually exclusive challenges mutually exclusive challenges
:param challanges: A list of challenges from ACME "challenge" :param list challanges: A list of challenges from ACME "challenge"
server message to be fulfilled by the client server message to be fulfilled by the client in order to prove
in order to prove possession of the identifier. possession of the identifier.
:type challenges: list
:returns: List of indices from `challenges`. :returns: List of indices from `challenges`.
:rtype: list :rtype: list
+34 -66
View File
@@ -36,20 +36,11 @@ class Client(object):
private_key=None, private_key_file=None, use_curses=True): private_key=None, private_key_file=None, use_curses=True):
""" """
:param ca_server: Certificate authority server :param str ca_server: Certificate authority server
:type ca_server: str :param str cert_signing_request: Contents of the CSR
:param str private_key: Contents of the private key
:param cert_signing_request: Contents of the CSR :param str private_key_file: absolute path to private_key
:type cert_signing_request: str :param bool use_curses: Use curses UI
:param private_key: Contents of the private key
:type private_key: str
:param private_key_file: absolute path to private_key
:type private_key_file: str
:param use_curses: Use curses UI
:type use_curses: bool
""" """
self.curses = use_curses self.curses = use_curses
@@ -80,14 +71,12 @@ class Client(object):
def authenticate(self, domains=None, redirect=None, eula=False): def authenticate(self, domains=None, redirect=None, eula=False):
""" """
:param domains: List of domains :param list domains: List of domains
:type domains: list
:param redirect: :param redirect:
:type redirect: bool|None :type redirect: bool or None
:param eula: EULA accepted :param bool eula: EULA accepted
:type eula: bool
:raises errors.LetsEncryptClientError: CSR does not contain one of the :raises errors.LetsEncryptClientError: CSR does not contain one of the
specified names. specified names.
@@ -157,9 +146,12 @@ class Client(object):
def acme_challenge(self): def acme_challenge(self):
"""Handle ACME "challenge" phase. """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. :returns: ACME "challenge" message.
:rtype: dict :rtype: dict
""" """
return self.send_and_receive_expected( return self.send_and_receive_expected(
acme.challenge_request(self.names[0]), "challenge") acme.challenge_request(self.names[0]), "challenge")
@@ -167,14 +159,10 @@ class Client(object):
def acme_authorization(self, challenge_msg, chal_objs, responses): def acme_authorization(self, challenge_msg, chal_objs, responses):
"""Handle ACME "authorization" phase. """Handle ACME "authorization" phase.
:param challenge_msg: ACME "challenge" message. :param dict challenge_msg: ACME "challenge" message.
:type challenge_msg: dict
:param chal_objs: TODO :param chal_objs: TODO
:type chal_objs: TODO
:param responses: TODO :param responses: TODO
:type responses: TODO
:returns: ACME "authorization" message. :returns: ACME "authorization" message.
:rtype: dict :rtype: dict
@@ -196,8 +184,7 @@ class Client(object):
def acme_certificate(self, csr_der): def acme_certificate(self, csr_der):
"""Handle ACME "certificate" phase. """Handle ACME "certificate" phase.
:param csr_der: CSR in DER format. :param str csr_der: CSR in DER format.
:type csr_der: str
:returns: ACME "certificate" message. :returns: ACME "certificate" message.
:rtype: dict :rtype: dict
@@ -210,8 +197,7 @@ class Client(object):
def acme_revocation(self, cert): def acme_revocation(self, cert):
"""Handle ACME "revocation" phase. """Handle ACME "revocation" phase.
:param cert: TODO :param dict cert: TODO
:type cert: dict
:returns: ACME "revocation" message. :returns: ACME "revocation" message.
:rtype: dict :rtype: dict
@@ -235,8 +221,7 @@ class Client(object):
def send(self, msg): def send(self, msg):
"""Send ACME message to server. """Send ACME message to server.
:param msg: ACME message (JSON serializable). :param dict msg: ACME message (JSON serializable).
:type msg: dict
:returns: Server response message. :returns: Server response message.
:rtype: dict :rtype: dict
@@ -274,11 +259,8 @@ class Client(object):
def send_and_receive_expected(self, msg, expected): def send_and_receive_expected(self, msg, expected):
"""Send ACME message to server and return expected message. """Send ACME message to server and return expected message.
:param msg: ACME message (JSON serializable). :param dict msg: ACME message (JSON serializable).
:type msg: dict :param str expected: Name of the expected response ACME message type.
:param expected: Name of the expected response ACME message type.
:type expected: str
:returns: ACME response message of expected type. :returns: ACME response message of expected type.
:rtype: dict :rtype: dict
@@ -296,19 +278,15 @@ class Client(object):
def is_expected_msg(self, response, expected, delay=3, rounds=20): def is_expected_msg(self, response, expected, delay=3, rounds=20):
"""Is reponse expected ACME message? """Is reponse expected ACME message?
:param response: ACME response message from server. :param dict response: ACME response message from server.
:type response: dict
:param expected: Name of the expected response ACME message type. :param str expected: Name of the expected response ACME message type.
:type expected: str
:param delay: Number of seconds to delay before next round in case :param int delay: Number of seconds to delay before next round
of ACME "defer" response message. in case of ACME "defer" response message.
:type delay: int
:param rounds: Number of resend attempts in case of ACME "defer" :param int rounds: Number of resend attempts in case of ACME "defer"
reponse message. reponse message.
:type rounds: int
:returns: ACME response message from server. :returns: ACME response message from server.
:rtype: dict :rtype: dict
@@ -387,8 +365,7 @@ class Client(object):
def choose_certs(self, certs): def choose_certs(self, certs):
"""Display choose certificates menu. """Display choose certificates menu.
:param certs: List of cert dicts. :param list certs: List of cert dicts.
:type certs: list
""" """
code, tag = display.display_certs(certs) code, tag = display.display_certs(certs)
@@ -478,8 +455,7 @@ class Client(object):
def verify_identity(self, challenge_msg): def verify_identity(self, challenge_msg):
"""Verify identity. """Verify identity.
:param challenge_msg: ACME "challenge" message. :param dict challenge_msg: ACME "challenge" message.
:type challenge_msg: dict
:returns: TODO :returns: TODO
:rtype: dict :rtype: dict
@@ -519,11 +495,9 @@ class Client(object):
def store_cert_key(self, cert_file, encrypt=False): def store_cert_key(self, cert_file, encrypt=False):
"""Store certificate key. """Store certificate key.
:param cert_file: Path to a certificate file. :param str cert_file: Path to a certificate file.
:type cert_file: str
:param encrypt: Should the certificate key be encrypted? :param bool encrypt: Should the certificate key be encrypted?
:type encrypt: bool
:returns: True if key file was stored successfully, False otherwise. :returns: True if key file was stored successfully, False otherwise.
:rtype: bool :rtype: bool
@@ -584,15 +558,12 @@ class Client(object):
""" """
:param name: TODO :param name: TODO
:type name: TODO
:param challenges: 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 server message to be fulfilled by the client in order to prove
in order to prove possession of the identifier. possession of the identifier.
:type challenges: list
:param path: List of indices from `challenges`. :param list path: List of indices from `challenges`.
:type path: list
:returns: A pair of TODO :returns: A pair of TODO
:rtype: tuple :rtype: tuple
@@ -748,8 +719,7 @@ class Client(object):
def remove_cert_key(cert): def remove_cert_key(cert):
"""Remove certificate key. """Remove certificate key.
:param cert: :param dict cert:
:type cert: dict
""" """
list_file = os.path.join(CONFIG.CERT_KEY_BACKUP, "LIST") list_file = os.path.join(CONFIG.CERT_KEY_BACKUP, "LIST")
@@ -776,8 +746,7 @@ def remove_cert_key(cert):
def sanity_check_names(names): def sanity_check_names(names):
"""Make sure host names are valid. """Make sure host names are valid.
:param names: List of host names :param list names: List of host names
:type names: list
""" """
for name in names: for name in names:
@@ -792,8 +761,7 @@ def is_hostname_sane(hostname):
Do enough to avoid shellcode from the environment. There's Do enough to avoid shellcode from the environment. There's
no need to do more. no need to do more.
:param hostname: Host name to validate :param str hostname: Host name to validate
:type hostname: str
:returns: True if hostname is valid, otherwise false. :returns: True if hostname is valid, otherwise false.
:rtype: bool :rtype: bool
+13 -6
View File
@@ -11,6 +11,13 @@ class Configurator(object):
""" """
def deploy_cert(self, vhost, cert, key, cert_chain=None): 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() raise NotImplementedError()
def choose_virtual_host(self, name): 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 intended to be permanent, but the save is not ready to be a full
checkpoint checkpoint
title: string - The title of the save. If a title is given, the :param str title: The title of the save. If a title is given, the
configuration will be saved as a new checkpoint configuration will be saved as a new checkpoint and put in a
and put in a timestamped directory. timestamped directory. `title` has no effect if temporary is true.
`title` has no effect if temporary is true.
temporary: boolean - Indicates whether the changes made will be :param bool temporary: Indicates whether the changes made will
quickly reversed in the future (challenges) be quickly reversed in the future (challenges)
""" """
raise NotImplementedError() raise NotImplementedError()
+14 -24
View File
@@ -25,23 +25,21 @@ def b64_cert_to_pem(b64_der_cert):
def create_sig(msg, key_str, nonce=None, nonce_len=CONFIG.NONCE_SIZE): def create_sig(msg, key_str, nonce=None, nonce_len=CONFIG.NONCE_SIZE):
"""Create signature with nonce prepended to the message. """Create signature with nonce prepended to the message.
TODO: Change this over to M2Crypto... PKey .. todo:: Change this over to M2Crypto... PKey
Protect against crypto unicode errors... is this sufficient?
.. todo::Protect against crypto unicode errors... is this sufficient?
Do I need to escape? Do I need to escape?
:param msg: Message to be signed :param str key_str: Key in string form. Accepted formats
:type msg: Anything with __str__ method
:param key_str: Key in string form. Accepted formats
are the same as for `Crypto.PublicKey.RSA.importKey`. 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 :param nonce: Nonce to be used. If None, nonce of `nonce_len` size
will be randomly genereted. will be randomly genereted.
:type nonce: str or None :type nonce: str or None
:param nonce_len: Size of the automaticaly generated nonce. :param int nonce_len: Size of the automaticaly generated nonce.
:type nonce_len: int
:returns: Signature. :returns: Signature.
:rtype: dict :rtype: dict
@@ -176,8 +174,7 @@ def make_ss_cert(key_str, domains):
def get_cert_info(filename): def get_cert_info(filename):
"""Get certificate info. """Get certificate info.
:param filename: Name of file containing certificate in PEM format. :param str filename: Name of file containing certificate in PEM format.
:type filename: str
:rtype: dict :rtype: dict
@@ -213,8 +210,7 @@ def valid_csr(csr):
Check if `csr` is a valid CSR for the given domains. Check if `csr` is a valid CSR for the given domains.
:param csr: CSR file contents :param str csr: CSR file contents
:type csr: str
:returns: Validity of CSR. :returns: Validity of CSR.
:rtype: bool :rtype: bool
@@ -233,11 +229,9 @@ def csr_matches_names(csr, domains):
M2Crypto currently does not expose the OpenSSL interface to M2Crypto currently does not expose the OpenSSL interface to
also check the SAN extension. This is insufficient for full testing 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. :param list domains: Domains the CSR should contain.
:type domains: list
:returns: If the CSR subject contains one of the domains :returns: If the CSR subject contains one of the domains
:rtype: bool :rtype: bool
@@ -253,8 +247,7 @@ def csr_matches_names(csr, domains):
def valid_privkey(privkey): def valid_privkey(privkey):
"""Is valid RSA private key? """Is valid RSA private key?
:param privkey: Private key file contents :param str privkey: Private key file contents
:type privkey: str
:returns: Validity of private key. :returns: Validity of private key.
:rtype: bool :rtype: bool
@@ -269,11 +262,8 @@ def valid_privkey(privkey):
def csr_matches_pubkey(csr, privkey): def csr_matches_pubkey(csr, privkey):
"""Does private key correspond to the subject public key in the CSR? """Does private key correspond to the subject public key in the CSR?
:param csr: CSR file contents :param str csr: CSR file contents
:type csr: str :param str privkey: Private key file contents
:param privkey: Private key file contents
:type privkey: str
:returns: Correspondence of private key to CSR subject public key. :returns: Correspondence of private key to CSR subject public key.
:rtype: bool :rtype: bool
+14 -26
View File
@@ -10,14 +10,9 @@ from letsencrypt.client import errors
def make_or_verify_dir(directory, mode=0o755, uid=0): def make_or_verify_dir(directory, mode=0o755, uid=0):
"""Make sure directory exists with proper permissions. """Make sure directory exists with proper permissions.
:param directory: Path to a directry. :param str directory: Path to a directry.
:type directory: str :param int mode: Diretory mode.
:param int uid: Directory owner.
:param mode: Diretory mode.
:type mode: int
:param uid: Directory owner.
:type uid: int
:raises LetsEncryptClientError: if a directory already exists, :raises LetsEncryptClientError: if a directory already exists,
but has wrong permissions or owner 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): def check_permissions(filepath, mode, uid=0):
"""Check file or directory permissions. """Check file or directory permissions.
:param filepath: Path to the tested file (or directory). :param str filepath: Path to the tested file (or directory).
:type filepath: str :param int mode: Expected file mode.
:param int uid: Expected file owner.
:param mode: Expected file mode. :returns: True if `mode` and `uid` match, False otherwise.
:type mode: int :rtype: bool
:param uid: Expected file owner.
:type uid: int
:returns: bool -- True if `mode` and `uid` match, False otherwise.
""" """
file_stat = os.stat(filepath) file_stat = os.stat(filepath)
@@ -57,11 +48,8 @@ def check_permissions(filepath, mode, uid=0):
def unique_file(default_name, mode=0o777): def unique_file(default_name, mode=0o777):
"""Safely finds a unique file for writing only (by default). """Safely finds a unique file for writing only (by default).
:param default_name: Default file name :param str default_name: Default file name
:type default_name: str :param int mode: File mode
:param mode: File mode
:type mode: int
:return: tuple of file object and file name :return: tuple of file object and file name
@@ -94,11 +82,11 @@ def jose_b64encode(data):
:param data: Data to be encoded. :param data: Data to be encoded.
:type data: str or bytearray :type data: str or bytearray
:raises TypeError: if input is of incorrect type
:returns: JOSE Base64 string. :returns: JOSE Base64 string.
:rtype: str :rtype: str
:raises TypeError: if `data` is of incorrect type
""" """
if not isinstance(data, str): if not isinstance(data, str):
raise TypeError('argument should be str or bytearray') raise TypeError('argument should be str or bytearray')
@@ -112,11 +100,11 @@ def jose_b64decode(data):
only ASCII characters are allowed. only ASCII characters are allowed.
:type data: str or unicode :type data: str or unicode
:returns: Decoded data.
:raises TypeError: if input is of incorrect type :raises TypeError: if input is of incorrect type
:raises ValueError: if unput is unicode with non-ASCII characters :raises ValueError: if unput is unicode with non-ASCII characters
:returns: Decoded data.
""" """
if isinstance(data, unicode): if isinstance(data, unicode):
try: try:
+1
View File
@@ -1,3 +1,4 @@
"""Logger."""
import logger import logger
import textwrap import textwrap
import time import time
+4 -6
View File
@@ -100,8 +100,7 @@ def main():
def read_file(filename): def read_file(filename):
"""Returns the given file's contents with universal new line support. """Returns the given file's contents with universal new line support.
:param filename: Filename :param str filename: Filename
:type filename: str
:returns: File contents :returns: File contents
:rtype: str :rtype: str
@@ -119,10 +118,9 @@ def rollback(config, checkpoints):
"""Revert configuration the specified number of checkpoints. """Revert configuration the specified number of checkpoints.
:param config: Configurator object :param config: Configurator object
:type config: ApacheConfigurator :type config: :class:`ApacheConfigurator`
:param checkpoints: Number of checkpoints to revert. :param int checkpoints: Number of checkpoints to revert.
:type checkpoints: int
""" """
config.rollback_checkpoints(checkpoints) config.rollback_checkpoints(checkpoints)
@@ -133,7 +131,7 @@ def view_checkpoints(config):
"""View checkpoints and associated configuration changes. """View checkpoints and associated configuration changes.
:param config: Configurator object :param config: Configurator object
:type config: ApacheConfigurator :type config: :class:`ApacheConfigurator`
""" """
config.display_checkpoints() config.display_checkpoints()
+1
View File
@@ -3,6 +3,7 @@ zip_ok = false
[aliases] [aliases]
dev = develop easy_install letsencrypt[testing] dev = develop easy_install letsencrypt[testing]
docs = develop easy_install letsencrypt[docs]
[nosetests] [nosetests]
nocapture=1 nocapture=1
+5
View File
@@ -12,6 +12,10 @@ install_requires = [
'requests', 'requests',
] ]
docs_extras = [
'Sphinx',
]
testing_extras = [ testing_extras = [
'coverage', 'coverage',
'nose', 'nose',
@@ -36,6 +40,7 @@ setup(
tests_require=install_requires, tests_require=install_requires,
test_suite='letsencrypt', test_suite='letsencrypt',
extras_require={ extras_require={
'docs': docs_extras,
'testing': testing_extras, 'testing': testing_extras,
}, },
entry_points={ entry_points={