1
0
mirror of https://github.com/certbot/certbot.git synced 2026-01-26 07:41:33 +03:00

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
docs/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
_build/

183
docs/Makefile Normal file
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."

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.CONFIG`
--------------------------------
.. automodule:: letsencrypt.client.CONFIG
:members:

5
docs/api/client/acme.rst Normal file
View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.acme`
------------------------------
.. automodule:: letsencrypt.client.acme
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.apache_configurator`
---------------------------------------------
.. automodule:: letsencrypt.client.apache_configurator
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.augeas_configurator`
---------------------------------------------
.. automodule:: letsencrypt.client.augeas_configurator
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.challenge`
-----------------------------------
.. automodule:: letsencrypt.client.challenge
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.client`
--------------------------------
.. automodule:: letsencrypt.client.client
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.configurator`
--------------------------------------
.. automodule:: letsencrypt.client.configurator
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.crypto_util`
-------------------------------------
.. automodule:: letsencrypt.client.crypto_util
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.display`
---------------------------------
.. automodule:: letsencrypt.client.display
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.errors`
--------------------------------
.. automodule:: letsencrypt.client.errors
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client`
-------------------------
.. automodule:: letsencrypt.client
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.interactive_challenge`
-----------------------------------------------
.. automodule:: letsencrypt.client.interactive_challenge
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.le_util`
---------------------------------
.. automodule:: letsencrypt.client.le_util
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.logger`
--------------------------------
.. automodule:: letsencrypt.client.logger
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.nginx_configurator`
--------------------------------------------
.. automodule:: letsencrypt.client.nginx_configurator
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.recovery_contact_challenge`
----------------------------------------------------
.. automodule:: letsencrypt.client.recovery_contact_challenge
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.recovery_token_challenge`
--------------------------------------------------
.. automodule:: letsencrypt.client.recovery_token_challenge
:members:

View File

@@ -0,0 +1,5 @@
:mod:`letsencrypt.client.validator`
-----------------------------------
.. automodule:: letsencrypt.client.validator
:members:

289
docs/conf.py Normal file
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
docs/index.rst Normal file
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
docs/make.bat Normal file
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

View File

@@ -1,62 +1,83 @@
"""Config for Let's Encrypt."""
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"
# 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/"
# Configuration file directory for letsencrypt
"""Apache server root directory"""
CONFIG_DIR = "/etc/letsencrypt/"
# Working directory for letsencrypt
"""Configuration file directory for letsencrypt"""
WORK_DIR = "/var/lib/letsencrypt/"
# Directory where configuration backups are stored
"""Working directory for letsencrypt"""
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/")
# 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/")
# 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/")
# 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/")
# Certificate storage
"""Where all keys should be stored"""
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")
# Let's Encrypt SSL vhost configuration extension
"""Contains standard Apache SSL directives"""
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")
"""Temporary file for challenge virtual hosts"""
# Byte size of S and Nonce
S_SIZE = 32
"""Byte size of S"""
NONCE_SIZE = 16
"""byte size of Nonce"""
# Key Sizes
RSA_KEY_SIZE = 2048
"""Key size"""
# bits of hashcash to generate
DIFFICULTY = 23
"""bits of hashcash to generate"""
# Let's Encrypt cert and chain files
CERT_PATH = CERT_DIR + "cert-letsencrypt.pem"
"""Let's Encrypt cert file."""
CHAIN_PATH = CERT_DIR + "chain-letsencrypt.pem"
"""Let's Encrypt chain file."""
# Invalid Extension
INVALID_EXT = ".acme.invalid"
"""Invalid Extension"""
# Challenge Preferences Dict for currently supported challenges
CHALLENGE_PREFERENCES = ["dvsni", "recoveryToken"]
"""Challenge Preferences Dict for currently supported challenges"""
# Mutually Exclusive Challenges - only solve 1
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"])
"""These are challenges that must be solved by a Configurator object"""
# Rewrite rule arguments used for redirections to https vhost
REWRITE_HTTPS_ARGS = [
"^.*$", "https://%{SERVER_NAME}%{REQUEST_URI}", "[L,R=permanent]"]
"""Rewrite rule arguments used for redirections to https vhost"""

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[domain] = vhost
@@ -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:
@@ -1567,11 +1529,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
@@ -1592,8 +1551,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()+"]"
@@ -1603,10 +1561,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

@@ -36,20 +36,11 @@ class Client(object):
private_key=None, private_key_file=None, use_curses=True):
"""
:param ca_server: Certificate authority server
:type ca_server: str
:param cert_signing_request: Contents of the CSR
:type cert_signing_request: str
: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
:param str ca_server: Certificate authority server
:param str cert_signing_request: Contents of the CSR
:param str private_key: Contents of the private key
:param str private_key_file: absolute path to private_key
:param bool use_curses: Use curses UI
"""
self.curses = use_curses
@@ -80,14 +71,12 @@ class Client(object):
def authenticate(self, domains=None, redirect=None, eula=False):
"""
:param domains: List of domains
:type domains: list
:param list domains: List of domains
:param redirect:
:type redirect: bool|None
:type redirect: bool or None
:param eula: EULA accepted
:type eula: bool
:param bool eula: EULA accepted
:raises errors.LetsEncryptClientError: CSR does not contain one of the
specified names.
@@ -157,9 +146,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 +159,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 +184,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 +197,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 +221,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 +259,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 +278,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 +365,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 +455,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 +495,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 +558,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 +719,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")
@@ -776,8 +746,7 @@ def remove_cert_key(cert):
def sanity_check_names(names):
"""Make sure host names are valid.
:param names: List of host names
:type names: list
:param list names: List of host names
"""
for name in names:
@@ -792,8 +761,7 @@ def is_hostname_sane(hostname):
Do enough to avoid shellcode from the environment. There's
no need to do more.
:param hostname: Host name to validate
:type hostname: str
:param str hostname: Host name to validate
:returns: True if hostname is valid, otherwise false.
:rtype: bool

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,21 @@ 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`.
:type key_str: str
:param str key_str: Key in string form. Accepted formats
are the same as for `Crypto.PublicKey.RSA.importKey`.
: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 +174,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 +210,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 +229,9 @@ 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
:type csr: str
:param str csr: CSR file contents
: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 +247,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 +262,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)
@@ -57,11 +48,8 @@ def check_permissions(filepath, mode, uid=0):
def unique_file(default_name, mode=0o777):
"""Safely finds a unique file for writing only (by default).
:param default_name: Default file name
:type default_name: str
:param mode: File mode
:type mode: int
:param str default_name: Default file name
:param int mode: File mode
:return: tuple of file object and file name
@@ -94,11 +82,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 +100,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

View File

@@ -100,8 +100,7 @@ def main():
def read_file(filename):
"""Returns the given file's contents with universal new line support.
:param filename: Filename
:type filename: str
:param str filename: Filename
:returns: File contents
:rtype: str
@@ -119,10 +118,9 @@ def rollback(config, checkpoints):
"""Revert configuration the specified number of checkpoints.
:param config: Configurator object
:type config: ApacheConfigurator
:type config: :class:`ApacheConfigurator`
:param checkpoints: Number of checkpoints to revert.
:type checkpoints: int
:param int checkpoints: Number of checkpoints to revert.
"""
config.rollback_checkpoints(checkpoints)
@@ -133,7 +131,7 @@ def view_checkpoints(config):
"""View checkpoints and associated configuration changes.
:param config: Configurator object
:type config: ApacheConfigurator
:type config: :class:`ApacheConfigurator`
"""
config.display_checkpoints()

View File

@@ -3,6 +3,7 @@ zip_ok = false
[aliases]
dev = develop easy_install letsencrypt[testing]
docs = develop easy_install letsencrypt[docs]
[nosetests]
nocapture=1

View File

@@ -12,6 +12,10 @@ install_requires = [
'requests',
]
docs_extras = [
'Sphinx',
]
testing_extras = [
'coverage',
'nose',
@@ -36,6 +40,7 @@ setup(
tests_require=install_requires,
test_suite='letsencrypt',
extras_require={
'docs': docs_extras,
'testing': testing_extras,
},
entry_points={