mirror of
https://github.com/certbot/certbot.git
synced 2026-06-06 15:22:38 -04:00
fix merge
This commit is contained in:
commit
c946589dab
51 changed files with 883 additions and 497 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -17,9 +17,11 @@ letsencrypt-auto-source/letsencrypt-auto.sig.lzma.base64
|
|||
|
||||
/.vagrant
|
||||
|
||||
tags
|
||||
|
||||
# editor temporary files
|
||||
*~
|
||||
*.swp
|
||||
*.sw?
|
||||
\#*#
|
||||
.idea
|
||||
|
||||
|
|
|
|||
12
.travis.yml
12
.travis.yml
|
|
@ -34,6 +34,8 @@ matrix:
|
|||
- python: "2.7"
|
||||
env: TOXENV=apacheconftest
|
||||
sudo: required
|
||||
- python: "2.7"
|
||||
env: TOXENV=nginxroundtrip
|
||||
- python: "2.7"
|
||||
env: TOXENV=py27 BOULDER_INTEGRATION=1
|
||||
sudo: true
|
||||
|
|
@ -53,6 +55,16 @@ matrix:
|
|||
services: docker
|
||||
before_install:
|
||||
addons:
|
||||
- sudo: required
|
||||
env: TOXENV=apache_compat
|
||||
services: docker
|
||||
before_install:
|
||||
addons:
|
||||
- sudo: required
|
||||
env: TOXENV=nginx_compat
|
||||
services: docker
|
||||
before_install:
|
||||
addons:
|
||||
- python: "2.7"
|
||||
env: TOXENV=cover
|
||||
- python: "3.3"
|
||||
|
|
|
|||
130
README.rst
130
README.rst
|
|
@ -1,4 +1,4 @@
|
|||
.. This file contains of a series of comments that are used to include sections of this README in other files. Do not modify these comments unless you know what you are doing. tag:intro-begin
|
||||
.. This file contains a series of comments that are used to include sections of this README in other files. Do not modify these comments unless you know what you are doing. tag:intro-begin
|
||||
|
||||
Certbot is part of EFF’s effort to encrypt the entire Internet. Secure communication over the Web relies on HTTPS, which requires the use of a digital certificate that lets browsers verify the identify of web servers (e.g., is that really google.com?). Web servers obtain their certificates from trusted third parties called certificate authorities (CAs). Certbot is an easy-to-use client that fetches a certificate from Let’s Encrypt—an open certificate authority launched by the EFF, Mozilla, and others—and deploys it to a web server.
|
||||
|
||||
|
|
@ -8,6 +8,134 @@ How you use Certbot depends on the configuration of your web server. The best wa
|
|||
|
||||
If you’re using a hosted service and don’t have direct access to your web server, you might not be able to use Certbot. Check with your hosting provider for documentation about uploading certificates or using certificates issues by Let’s Encrypt.
|
||||
|
||||
Certbot is a fully-featured, extensible client for the Let's
|
||||
Encrypt CA (or any other CA that speaks the `ACME
|
||||
<https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md>`_
|
||||
protocol) that can automate the tasks of obtaining certificates and
|
||||
configuring webservers to use them. This client runs on Unix-based operating
|
||||
systems.
|
||||
|
||||
Until May 2016, Certbot was named simply ``letsencrypt`` or ``letsencrypt-auto``,
|
||||
depending on install method. Instructions on the Internet, and some pieces of the
|
||||
software, may still refer to this older name.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
If you'd like to contribute to this project please read `Developer Guide
|
||||
<https://certbot.eff.org/docs/contributing.html>`_.
|
||||
|
||||
.. _installation:
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
The easiest way to install Certbot is by visiting https://certbot.eff.org, where you can
|
||||
find the correct installation instructions for many web server and OS combinations.
|
||||
For more information, see the `User Guide <https://certbot.eff.org/docs/using.html#getting-certbot>`_.
|
||||
|
||||
How to run the client
|
||||
---------------------
|
||||
|
||||
In many cases, you can just run ``certbot-auto`` or ``certbot``, and the
|
||||
client will guide you through the process of obtaining and installing certs
|
||||
interactively.
|
||||
|
||||
For full command line help, you can type::
|
||||
|
||||
./certbot-auto --help all
|
||||
|
||||
|
||||
You can also tell it exactly what you want it to do from the command line.
|
||||
For instance, if you want to obtain a cert for ``example.com``,
|
||||
``www.example.com``, and ``other.example.net``, using the Apache plugin to both
|
||||
obtain and install the certs, you could do this::
|
||||
|
||||
./certbot-auto --apache -d example.com -d www.example.com -d other.example.net
|
||||
|
||||
(The first time you run the command, it will make an account, and ask for an
|
||||
email and agreement to the Let's Encrypt Subscriber Agreement; you can
|
||||
automate those with ``--email`` and ``--agree-tos``)
|
||||
|
||||
If you want to use a webserver that doesn't have full plugin support yet, you
|
||||
can still use "standalone" or "webroot" plugins to obtain a certificate::
|
||||
|
||||
./certbot-auto certonly --standalone --email admin@example.com -d example.com -d www.example.com -d other.example.net
|
||||
|
||||
|
||||
Understanding the client in more depth
|
||||
--------------------------------------
|
||||
|
||||
To understand what the client is doing in detail, it's important to
|
||||
understand the way it uses plugins. Please see the `explanation of
|
||||
plugins <https://certbot.eff.org/docs/using.html#plugins>`_ in
|
||||
the User Guide.
|
||||
|
||||
Links
|
||||
=====
|
||||
|
||||
Documentation: https://certbot.eff.org/docs
|
||||
|
||||
Software project: https://github.com/certbot/certbot
|
||||
|
||||
Notes for developers: https://certbot.eff.org/docs/contributing.html
|
||||
|
||||
Main Website: https://letsencrypt.org/
|
||||
|
||||
IRC Channel: #letsencrypt on `Freenode`_ or #certbot on `OFTC`_
|
||||
|
||||
Community: https://community.letsencrypt.org
|
||||
|
||||
ACME spec: http://ietf-wg-acme.github.io/acme/
|
||||
|
||||
ACME working area in github: https://github.com/ietf-wg-acme/acme
|
||||
|
||||
|
||||
Mailing list: `client-dev`_ (to subscribe without a Google account, send an
|
||||
email to client-dev+subscribe@letsencrypt.org)
|
||||
|
||||
|build-status| |coverage| |docs| |container|
|
||||
|
||||
|
||||
|
||||
.. |build-status| image:: https://travis-ci.org/certbot/certbot.svg?branch=master
|
||||
:target: https://travis-ci.org/certbot/certbot
|
||||
:alt: Travis CI status
|
||||
|
||||
.. |coverage| image:: https://coveralls.io/repos/certbot/certbot/badge.svg?branch=master
|
||||
:target: https://coveralls.io/r/certbot/certbot
|
||||
:alt: Coverage status
|
||||
|
||||
.. |docs| image:: https://readthedocs.org/projects/letsencrypt/badge/
|
||||
:target: https://readthedocs.org/projects/letsencrypt/
|
||||
:alt: Documentation status
|
||||
|
||||
.. |container| image:: https://quay.io/repository/letsencrypt/letsencrypt/status
|
||||
:target: https://quay.io/repository/letsencrypt/letsencrypt
|
||||
:alt: Docker Repository on Quay.io
|
||||
|
||||
.. _`installation instructions`:
|
||||
https://letsencrypt.readthedocs.org/en/latest/using.html#getting-certbot
|
||||
|
||||
.. _watch demo video: https://www.youtube.com/watch?v=Gas_sSB-5SU
|
||||
|
||||
System Requirements
|
||||
===================
|
||||
|
||||
The Let's Encrypt Client presently only runs on Unix-ish OSes that include
|
||||
Python 2.6 or 2.7; Python 3.x support will hopefully be added in the future. The
|
||||
client requires root access in order to write to ``/etc/letsencrypt``,
|
||||
``/var/log/letsencrypt``, ``/var/lib/letsencrypt``; to bind to ports 80 and 443
|
||||
(if you use the ``standalone`` plugin) and to read and modify webserver
|
||||
configurations (if you use the ``apache`` or ``nginx`` plugins). If none of
|
||||
these apply to you, it is theoretically possible to run without root privileges,
|
||||
but for most users who want to avoid running an ACME client as root, either
|
||||
`letsencrypt-nosudo <https://github.com/diafygi/letsencrypt-nosudo>`_ or
|
||||
`simp_le <https://github.com/kuba/simp_le>`_ are more appropriate choices.
|
||||
|
||||
The Apache plugin currently requires a Debian-based OS with augeas version
|
||||
1.0; this includes Ubuntu 12.04+ and Debian 7+.
|
||||
|
||||
.. Do not modify this comment unless you know what you're doing. tag:intro-end
|
||||
|
||||
.. Do not modify this comment unless you know what you're doing. tag:features-begin
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
|
||||
"""
|
||||
|
||||
description = "Apache Web Server - Alpha"
|
||||
description = "Apache Web Server plugin - Beta"
|
||||
|
||||
@classmethod
|
||||
def add_parser_arguments(cls, add):
|
||||
|
|
@ -538,6 +538,9 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
is_ssl = True
|
||||
|
||||
filename = get_file_path(self.aug.get("/augeas/files%s/path" % get_file_path(path)))
|
||||
if filename is None:
|
||||
return None
|
||||
|
||||
if self.conf("handle-sites"):
|
||||
is_enabled = self.is_site_enabled(filename)
|
||||
else:
|
||||
|
|
@ -1801,25 +1804,25 @@ def get_file_path(vhost_path):
|
|||
:rtype: str
|
||||
|
||||
"""
|
||||
# Strip off /files
|
||||
avail_fp = vhost_path[6:]
|
||||
# This can be optimized...
|
||||
while True:
|
||||
# Cast all to lowercase to be case insensitive
|
||||
find_if = avail_fp.lower().find("/ifmodule")
|
||||
if find_if != -1:
|
||||
avail_fp = avail_fp[:find_if]
|
||||
continue
|
||||
find_vh = avail_fp.lower().find("/virtualhost")
|
||||
if find_vh != -1:
|
||||
avail_fp = avail_fp[:find_vh]
|
||||
continue
|
||||
find_macro = avail_fp.lower().find("/macro")
|
||||
if find_macro != -1:
|
||||
avail_fp = avail_fp[:find_macro]
|
||||
continue
|
||||
break
|
||||
return avail_fp
|
||||
# Strip off /files/
|
||||
try:
|
||||
if vhost_path.startswith("/files/"):
|
||||
avail_fp = vhost_path[7:].split("/")
|
||||
else:
|
||||
return None
|
||||
except AttributeError:
|
||||
# If we recieved a None path
|
||||
return None
|
||||
|
||||
last_good = ""
|
||||
# Loop through the path parts and validate after every addition
|
||||
for p in avail_fp:
|
||||
cur_path = last_good+"/"+p
|
||||
if os.path.exists(cur_path):
|
||||
last_good = cur_path
|
||||
else:
|
||||
break
|
||||
return last_good
|
||||
|
||||
|
||||
def install_ssl_options_conf(options_ssl):
|
||||
|
|
|
|||
|
|
@ -125,6 +125,12 @@ class MultipleVhostsTest(util.ApacheTest):
|
|||
self.assertTrue("google.com" in names)
|
||||
self.assertTrue("certbot.demo" in names)
|
||||
|
||||
def test_get_bad_path(self):
|
||||
from certbot_apache.configurator import get_file_path
|
||||
self.assertEqual(get_file_path(None), None)
|
||||
self.assertEqual(get_file_path("nonexistent"), None)
|
||||
self.assertEqual(self.config._create_vhost("nonexistent"), None) # pylint: disable=protected-access
|
||||
|
||||
def test_bad_servername_alias(self):
|
||||
ssl_vh1 = obj.VirtualHost(
|
||||
"fp1", "ap1", set([obj.Addr(("*", "443"))]),
|
||||
|
|
|
|||
51
certbot-compatibility-test/Dockerfile
Normal file
51
certbot-compatibility-test/Dockerfile
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
FROM debian:jessie
|
||||
MAINTAINER Brad Warren <bmw@eff.org>
|
||||
|
||||
# no need to mkdir anything:
|
||||
# https://docs.docker.com/reference/builder/#copy
|
||||
# If <dest> doesn't exist, it is created along with all missing
|
||||
# directories in its path.
|
||||
|
||||
# TODO: Install non-default Python versions for tox.
|
||||
# TODO: Install Apache/Nginx for plugin development.
|
||||
COPY certbot-auto /opt/certbot/src/certbot-auto
|
||||
RUN /opt/certbot/src/certbot-auto -n --os-packages-only
|
||||
|
||||
# the above is not likely to change, so by putting it further up the
|
||||
# Dockerfile we make sure we cache as much as possible
|
||||
|
||||
COPY setup.py README.rst CHANGES.rst MANIFEST.in linter_plugin.py tox.cover.sh tox.ini pep8.travis.sh .pep8 .pylintrc /opt/certbot/src/
|
||||
|
||||
# all above files are necessary for setup.py, however, package source
|
||||
# code directory has to be copied separately to a subdirectory...
|
||||
# https://docs.docker.com/reference/builder/#copy: "If <src> is a
|
||||
# directory, the entire contents of the directory are copied,
|
||||
# including filesystem metadata. Note: The directory itself is not
|
||||
# copied, just its contents." Order again matters, three files are far
|
||||
# more likely to be cached than the whole project directory
|
||||
|
||||
COPY certbot /opt/certbot/src/certbot/
|
||||
COPY acme /opt/certbot/src/acme/
|
||||
COPY certbot-apache /opt/certbot/src/certbot-apache/
|
||||
COPY certbot-nginx /opt/certbot/src/certbot-nginx/
|
||||
COPY certbot-compatibility-test /opt/certbot/src/certbot-compatibility-test/
|
||||
|
||||
RUN virtualenv --no-site-packages -p python2 /opt/certbot/venv && \
|
||||
/opt/certbot/venv/bin/pip install -U setuptools && \
|
||||
/opt/certbot/venv/bin/pip install -U pip && \
|
||||
/opt/certbot/venv/bin/pip install \
|
||||
-e /opt/certbot/src/acme \
|
||||
-e /opt/certbot/src \
|
||||
-e /opt/certbot/src/certbot-apache \
|
||||
-e /opt/certbot/src/certbot-nginx \
|
||||
-e /opt/certbot/src/certbot-compatibility-test \
|
||||
-e /opt/certbot/src[dev,docs]
|
||||
|
||||
# install in editable mode (-e) to save space: it's not possible to
|
||||
# "rm -rf /opt/certbot/src" (it's stays in the underlaying image);
|
||||
# this might also help in debugging: you can "docker run --entrypoint
|
||||
# bash" and investigate, apply patches, etc.
|
||||
|
||||
WORKDIR /opt/certbot/src/certbot-compatibility-test/certbot_compatibility_test/testdata
|
||||
|
||||
ENV PATH /opt/certbot/venv/bin:$PATH
|
||||
6
certbot-compatibility-test/Dockerfile-apache
Normal file
6
certbot-compatibility-test/Dockerfile-apache
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
FROM certbot-compatibility-test
|
||||
MAINTAINER Brad Warren <bmw@eff.org>
|
||||
|
||||
RUN apt-get install apache2 -y
|
||||
|
||||
ENTRYPOINT [ "certbot-compatibility-test", "-p", "apache" ]
|
||||
6
certbot-compatibility-test/Dockerfile-nginx
Normal file
6
certbot-compatibility-test/Dockerfile-nginx
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
FROM certbot-compatibility-test
|
||||
MAINTAINER Brad Warren <bmw@eff.org>
|
||||
|
||||
RUN apt-get install nginx -y
|
||||
|
||||
ENTRYPOINT [ "certbot-compatibility-test", "-p", "nginx" ]
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
FROM httpd
|
||||
MAINTAINER Brad Warren <bradmw@umich.edu>
|
||||
|
||||
RUN mkdir /var/run/apache2
|
||||
|
||||
ENV APACHE_RUN_USER=daemon \
|
||||
APACHE_RUN_GROUP=daemon \
|
||||
APACHE_PID_FILE=/usr/local/apache2/logs/httpd.pid \
|
||||
APACHE_RUN_DIR=/var/run/apache2 \
|
||||
APACHE_LOCK_DIR=/var/lock \
|
||||
APACHE_LOG_DIR=/usr/local/apache2/logs
|
||||
|
||||
COPY certbot-compatibility-test/certbot_compatibility_test/configurators/apache/a2enmod.sh /usr/local/bin/
|
||||
COPY certbot-compatibility-test/certbot_compatibility_test/configurators/apache/a2dismod.sh /usr/local/bin/
|
||||
COPY certbot-compatibility-test/certbot_compatibility_test/testdata/rsa1024_key2.pem /usr/local/apache2/conf/
|
||||
COPY certbot-compatibility-test/certbot_compatibility_test/testdata/empty_cert.pem /usr/local/apache2/conf/
|
||||
|
||||
# Note: this only exposes the port to other docker containers. You
|
||||
# still have to bind to 443@host at runtime.
|
||||
EXPOSE 443
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
"""Provides a common base for Apache proxies"""
|
||||
import re
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
|
|
@ -17,10 +16,6 @@ from certbot_compatibility_test import util
|
|||
from certbot_compatibility_test.configurators import common as configurators_common
|
||||
|
||||
|
||||
APACHE_VERSION_REGEX = re.compile(r"Apache/([0-9\.]*)", re.IGNORECASE)
|
||||
APACHE_COMMANDS = ["apachectl", "a2enmod", "a2dismod"]
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IConfiguratorProxy)
|
||||
class Proxy(configurators_common.Proxy):
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
|
|
@ -32,37 +27,25 @@ class Proxy(configurators_common.Proxy):
|
|||
self.le_config.apache_le_vhost_ext = "-le-ssl.conf"
|
||||
|
||||
self.modules = self.server_root = self.test_conf = self.version = None
|
||||
self._apache_configurator = self._all_names = self._test_names = None
|
||||
patch = mock.patch(
|
||||
"certbot_apache.configurator.display_ops.select_vhost")
|
||||
mock_display = patch.start()
|
||||
mock_display.side_effect = le_errors.PluginError(
|
||||
"Unable to determine vhost")
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Wraps the Apache Configurator methods"""
|
||||
method = getattr(self._apache_configurator, name, None)
|
||||
if callable(method):
|
||||
return method
|
||||
else:
|
||||
raise AttributeError()
|
||||
|
||||
def load_config(self):
|
||||
"""Loads the next configuration for the plugin to test"""
|
||||
|
||||
config = super(Proxy, self).load_config()
|
||||
self._all_names, self._test_names = _get_names(config)
|
||||
|
||||
server_root = _get_server_root(config)
|
||||
# with open(os.path.join(config, "config_file")) as f:
|
||||
# config_file = os.path.join(server_root, f.readline().rstrip())
|
||||
shutil.rmtree("/etc/apache2")
|
||||
shutil.copytree(server_root, "/etc/apache2", symlinks=True)
|
||||
|
||||
self._prepare_configurator()
|
||||
|
||||
try:
|
||||
subprocess.check_call("apachectl -k start".split())
|
||||
subprocess.check_call("apachectl -k restart".split())
|
||||
except errors.Error:
|
||||
raise errors.Error(
|
||||
"Apache failed to load {0} before tests started".format(
|
||||
|
|
@ -78,38 +61,16 @@ class Proxy(configurators_common.Proxy):
|
|||
# An alias
|
||||
self.le_config.apache_handle_modules = self.le_config.apache_handle_mods
|
||||
|
||||
self._apache_configurator = configurator.ApacheConfigurator(
|
||||
self._configurator = configurator.ApacheConfigurator(
|
||||
config=configuration.NamespaceConfig(self.le_config),
|
||||
name="apache")
|
||||
self._apache_configurator.prepare()
|
||||
self._configurator.prepare()
|
||||
|
||||
def cleanup_from_tests(self):
|
||||
"""Performs any necessary cleanup from running plugin tests"""
|
||||
super(Proxy, self).cleanup_from_tests()
|
||||
mock.patch.stopall()
|
||||
|
||||
def get_all_names_answer(self):
|
||||
"""Returns the set of domain names that the plugin should find"""
|
||||
if self._all_names:
|
||||
return self._all_names
|
||||
else:
|
||||
raise errors.Error("No configuration file loaded")
|
||||
|
||||
def get_testable_domain_names(self):
|
||||
"""Returns the set of domain names that can be tested against"""
|
||||
if self._test_names:
|
||||
return self._test_names
|
||||
else:
|
||||
return {"example.com"}
|
||||
|
||||
def deploy_cert(self, domain, cert_path, key_path, chain_path=None,
|
||||
fullchain_path=None):
|
||||
"""Installs cert"""
|
||||
cert_path, key_path, chain_path = self.copy_certs_and_keys(
|
||||
cert_path, key_path, chain_path)
|
||||
self._apache_configurator.deploy_cert(
|
||||
domain, cert_path, key_path, chain_path, fullchain_path)
|
||||
|
||||
|
||||
def _get_server_root(config):
|
||||
"""Returns the server root directory in config"""
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import shutil
|
|||
import tempfile
|
||||
|
||||
from certbot import constants
|
||||
from certbot_compatibility_test import errors
|
||||
from certbot_compatibility_test import util
|
||||
|
||||
|
||||
|
|
@ -31,6 +32,18 @@ class Proxy(object):
|
|||
self.args = args
|
||||
self.http_port = 80
|
||||
self.https_port = 443
|
||||
self._configurator = self._all_names = self._test_names = None
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Wraps the configurator methods"""
|
||||
if self._configurator is None:
|
||||
raise AttributeError()
|
||||
|
||||
method = getattr(self._configurator, name, None)
|
||||
if callable(method):
|
||||
return method
|
||||
else:
|
||||
raise AttributeError()
|
||||
|
||||
def has_more_configs(self):
|
||||
"""Returns true if there are more configs to test"""
|
||||
|
|
@ -63,3 +76,25 @@ class Proxy(object):
|
|||
chain = None
|
||||
|
||||
return cert, key, chain
|
||||
|
||||
def get_all_names_answer(self):
|
||||
"""Returns the set of domain names that the plugin should find"""
|
||||
if self._all_names:
|
||||
return self._all_names
|
||||
else:
|
||||
raise errors.Error("No configuration file loaded")
|
||||
|
||||
def get_testable_domain_names(self):
|
||||
"""Returns the set of domain names that can be tested against"""
|
||||
if self._test_names:
|
||||
return self._test_names
|
||||
else:
|
||||
return {"example.com"}
|
||||
|
||||
def deploy_cert(self, domain, cert_path, key_path, chain_path=None,
|
||||
fullchain_path=None):
|
||||
"""Installs cert"""
|
||||
cert_path, key_path, chain_path = self.copy_certs_and_keys(
|
||||
cert_path, key_path, chain_path)
|
||||
self._configurator.deploy_cert(
|
||||
domain, cert_path, key_path, chain_path, fullchain_path)
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
"""Certbot compatibility test Nginx configurators"""
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
"""Provides a common base for Nginx proxies"""
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
import zope.interface
|
||||
|
||||
from certbot import configuration
|
||||
from certbot_nginx import configurator
|
||||
from certbot_nginx import constants
|
||||
from certbot_compatibility_test import errors
|
||||
from certbot_compatibility_test import interfaces
|
||||
from certbot_compatibility_test import util
|
||||
from certbot_compatibility_test.configurators import common as configurators_common
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IConfiguratorProxy)
|
||||
class Proxy(configurators_common.Proxy):
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
"""A common base for Nginx test configurators"""
|
||||
|
||||
def __init__(self, args):
|
||||
"""Initializes the plugin with the given command line args"""
|
||||
super(Proxy, self).__init__(args)
|
||||
|
||||
def load_config(self):
|
||||
"""Loads the next configuration for the plugin to test"""
|
||||
config = super(Proxy, self).load_config()
|
||||
self._all_names, self._test_names = _get_names(config)
|
||||
|
||||
server_root = _get_server_root(config)
|
||||
|
||||
# XXX: Deleting all of this is kind of scary unless the test
|
||||
# instances really each have a complete configuration!
|
||||
shutil.rmtree("/etc/nginx")
|
||||
shutil.copytree(server_root, "/etc/nginx", symlinks=True)
|
||||
|
||||
self._prepare_configurator()
|
||||
|
||||
try:
|
||||
subprocess.check_call("service nginx reload".split())
|
||||
except errors.Error:
|
||||
raise errors.Error(
|
||||
"Nginx failed to load {0} before tests started".format(
|
||||
config))
|
||||
|
||||
return config
|
||||
|
||||
def _prepare_configurator(self):
|
||||
"""Prepares the Nginx plugin for testing"""
|
||||
for k in constants.CLI_DEFAULTS.keys():
|
||||
setattr(self.le_config, "nginx_" + k, constants.os_constant(k))
|
||||
|
||||
conf = configuration.NamespaceConfig(self.le_config)
|
||||
zope.component.provideUtility(conf)
|
||||
self._configurator = configurator.NginxConfigurator(
|
||||
config=conf, name="nginx")
|
||||
self._configurator.prepare()
|
||||
|
||||
|
||||
def _get_server_root(config):
|
||||
"""Returns the server root directory in config"""
|
||||
subdirs = [
|
||||
name for name in os.listdir(config)
|
||||
if os.path.isdir(os.path.join(config, name))]
|
||||
|
||||
if len(subdirs) != 1:
|
||||
raise errors.Error("Malformed configuration directory {0}".format(config))
|
||||
|
||||
return os.path.join(config, subdirs[0].rstrip())
|
||||
|
||||
|
||||
def _get_names(config):
|
||||
"""Returns all and testable domain names in config"""
|
||||
all_names = set()
|
||||
for root, _dirs, files in os.walk(config):
|
||||
for this_file in files:
|
||||
for line in open(os.path.join(root, this_file)):
|
||||
if line.strip().startswith("server_name"):
|
||||
names = line.partition("server_name")[2].rpartition(";")[0]
|
||||
for n in names.split():
|
||||
all_names.add(n)
|
||||
non_ip_names = set(n for n in all_names if not util.IP_REGEX.match(n))
|
||||
return all_names, non_ip_names
|
||||
|
|
@ -22,7 +22,8 @@ from certbot_compatibility_test import errors
|
|||
from certbot_compatibility_test import util
|
||||
from certbot_compatibility_test import validator
|
||||
|
||||
from certbot_compatibility_test.configurators.apache import common
|
||||
from certbot_compatibility_test.configurators.apache import common as a_common
|
||||
from certbot_compatibility_test.configurators.nginx import common as n_common
|
||||
|
||||
|
||||
DESCRIPTION = """
|
||||
|
|
@ -32,7 +33,7 @@ tests that the plugin supports are performed.
|
|||
|
||||
"""
|
||||
|
||||
PLUGINS = {"apache": common.Proxy}
|
||||
PLUGINS = {"apache": a_common.Proxy, "nginx": n_common.Proxy}
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -143,7 +144,7 @@ def test_deploy_cert(plugin, temp_dir, domains):
|
|||
|
||||
for domain in domains:
|
||||
try:
|
||||
plugin.deploy_cert(domain, cert_path, util.KEY_PATH, cert_path)
|
||||
plugin.deploy_cert(domain, cert_path, util.KEY_PATH, cert_path, cert_path)
|
||||
plugin.save() # Needed by the Apache plugin
|
||||
except le_errors.Error as error:
|
||||
logger.error("Plugin failed to deploy ceritificate for %s:", domain)
|
||||
|
|
|
|||
BIN
certbot-compatibility-test/certbot_compatibility_test/testdata/nginx.tar.gz
vendored
Normal file
BIN
certbot-compatibility-test/certbot_compatibility_test/testdata/nginx.tar.gz
vendored
Normal file
Binary file not shown.
|
|
@ -16,3 +16,17 @@ MOD_SSL_CONF_SRC = pkg_resources.resource_filename(
|
|||
"certbot_nginx", "options-ssl-nginx.conf")
|
||||
"""Path to the nginx mod_ssl config file found in the Certbot
|
||||
distribution."""
|
||||
|
||||
def os_constant(key):
|
||||
# XXX TODO: In the future, this could return different constants
|
||||
# based on what OS we are running under. To see an
|
||||
# approach to how to handle different OSes, see the
|
||||
# apache version of this file. Currently, we do not
|
||||
# actually have any OS-specific constants on Nginx.
|
||||
"""
|
||||
Get a constant value for operating system
|
||||
|
||||
:param key: name of cli constant
|
||||
:return: value of constant for active os
|
||||
"""
|
||||
return CLI_DEFAULTS[key]
|
||||
|
|
|
|||
|
|
@ -91,10 +91,10 @@ class NginxTlsSni01(common.TLSSNI01):
|
|||
# Add the 'include' statement for the challenges if it doesn't exist
|
||||
# already in the main config
|
||||
included = False
|
||||
include_directive = ['include', ' ', self.challenge_conf]
|
||||
include_directive = ['\n', 'include', ' ', self.challenge_conf]
|
||||
root = self.configurator.parser.loc["root"]
|
||||
|
||||
bucket_directive = ['server_names_hash_bucket_size', ' ', '128']
|
||||
bucket_directive = ['\n', 'server_names_hash_bucket_size', ' ', '128']
|
||||
|
||||
main = self.configurator.parser.parsed[root]
|
||||
for key, body in main:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import socket
|
|||
from cryptography.hazmat.primitives import serialization
|
||||
import pyrfc3339
|
||||
import pytz
|
||||
import six
|
||||
import zope.component
|
||||
|
||||
from acme import fields as acme_fields
|
||||
|
|
@ -108,7 +109,7 @@ class AccountMemoryStorage(interfaces.AccountStorage):
|
|||
self.accounts = initial_accounts if initial_accounts is not None else {}
|
||||
|
||||
def find_all(self):
|
||||
return self.accounts.values()
|
||||
return list(six.itervalues(self.accounts))
|
||||
|
||||
def save(self, account):
|
||||
if account.id in self.accounts:
|
||||
|
|
|
|||
184
certbot/cli.py
184
certbot/cli.py
|
|
@ -88,8 +88,8 @@ More detailed help:
|
|||
the available topics are:
|
||||
|
||||
all, automation, paths, security, testing, or any of the subcommands or
|
||||
plugins (certonly, install, register, nginx, apache, standalone, webroot,
|
||||
etc.)
|
||||
plugins (certonly, renew, install, register, nginx, apache, standalone,
|
||||
webroot, etc.)
|
||||
"""
|
||||
|
||||
|
||||
|
|
@ -393,8 +393,7 @@ class HelpfulArgumentParser(object):
|
|||
if getattr(parsed_args, arg):
|
||||
raise errors.Error(
|
||||
("Conflicting values for displayer."
|
||||
" {0} conflicts with dialog_mode").format(arg)
|
||||
)
|
||||
" {0} conflicts with dialog_mode").format(arg))
|
||||
elif parsed_args.verbose_count > flag_default("verbose_count"):
|
||||
parsed_args.text_mode = True
|
||||
|
||||
|
|
@ -502,16 +501,25 @@ class HelpfulArgumentParser(object):
|
|||
pass
|
||||
return True
|
||||
|
||||
def add(self, topic, *args, **kwargs):
|
||||
def add(self, topics, *args, **kwargs):
|
||||
"""Add a new command line argument.
|
||||
|
||||
:param str: help topic this should be listed under, can be None for
|
||||
"always documented"
|
||||
:param topics: str or [str] help topic(s) this should be listed under,
|
||||
or None for "always documented". The first entry
|
||||
determines where the flag lives in the "--help all"
|
||||
output (None -> "optional arguments").
|
||||
:param list *args: the names of this argument flag
|
||||
:param dict **kwargs: various argparse settings for this argument
|
||||
|
||||
"""
|
||||
|
||||
if isinstance(topics, list):
|
||||
# if this flag can be listed in multiple sections, try to pick the one
|
||||
# that the user has asked for help about
|
||||
topic = self.help_arg if self.help_arg in topics else topics[0]
|
||||
else:
|
||||
topic = topics # there's only one
|
||||
|
||||
if self.detect_defaults:
|
||||
kwargs = self.modify_kwargs_for_default_detection(**kwargs)
|
||||
|
||||
|
|
@ -612,6 +620,36 @@ class HelpfulArgumentParser(object):
|
|||
else:
|
||||
return dict([(t, t == chosen_topic) for t in self.help_topics])
|
||||
|
||||
def _add_all_groups(helpful):
|
||||
helpful.add_group("automation", description="Arguments for automating execution & other tweaks")
|
||||
helpful.add_group("security", description="Security parameters & server settings")
|
||||
helpful.add_group(
|
||||
"testing", description="The following flags are meant for "
|
||||
"testing purposes only! Do NOT change them, unless you "
|
||||
"really know what you're doing!")
|
||||
# VERBS
|
||||
helpful.add_group(
|
||||
"renew", description="The 'renew' subcommand will attempt to renew all"
|
||||
" certificates (or more precisely, certificate lineages) you have"
|
||||
" previously obtained if they are close to expiry, and print a"
|
||||
" summary of the results. By default, 'renew' will reuse the options"
|
||||
" used to create obtain or most recently successfully renew each"
|
||||
" certificate lineage. You can try it with `--dry-run` first. For"
|
||||
" more fine-grained control, you can renew individual lineages with"
|
||||
" the `certonly` subcommand. Hooks are available to run commands"
|
||||
" before and after renewal; see"
|
||||
" https://certbot.eff.org/docs/using.html#renewal for more"
|
||||
" information on these.")
|
||||
|
||||
helpful.add_group("certonly", description="Options for modifying how a cert is obtained")
|
||||
helpful.add_group("install", description="Options for modifying how a cert is deployed")
|
||||
helpful.add_group("revoke", description="Options for revocation of certs")
|
||||
helpful.add_group("rollback", description="Options for reverting config changes")
|
||||
helpful.add_group("plugins", description='Options for the "plugins" subcommand')
|
||||
helpful.add_group("config_changes",
|
||||
description="Options for showing a history of config changes")
|
||||
helpful.add_group("paths", description="Arguments changing execution paths & servers")
|
||||
|
||||
|
||||
def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: disable=too-many-statements
|
||||
"""Returns parsed command line arguments.
|
||||
|
|
@ -627,6 +665,7 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
|
|||
# pylint: disable=too-many-statements
|
||||
|
||||
helpful = HelpfulArgumentParser(args, plugins, detect_defaults)
|
||||
_add_all_groups(helpful)
|
||||
|
||||
# --help is automatically provided by argparse
|
||||
helpful.add(
|
||||
|
|
@ -638,16 +677,25 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
|
|||
None, "-t", "--text", dest="text_mode", action="store_true",
|
||||
help="Use the text output instead of the curses UI.")
|
||||
helpful.add(
|
||||
None, "-n", "--non-interactive", "--noninteractive",
|
||||
[None, "automation"], "-n", "--non-interactive", "--noninteractive",
|
||||
dest="noninteractive_mode", action="store_true",
|
||||
help="Run without ever asking for user input. This may require "
|
||||
"additional command line flags; the client will try to explain "
|
||||
"which ones are required if it finds one missing")
|
||||
helpful.add(
|
||||
None, "--dialog", dest="dialog_mode", action="store_true",
|
||||
help="Run using dialog")
|
||||
help="Run using interactive dialog menus")
|
||||
helpful.add(
|
||||
None, "--dry-run", action="store_true", dest="dry_run",
|
||||
[None, "run", "certonly"],
|
||||
"-d", "--domains", "--domain", dest="domains",
|
||||
metavar="DOMAIN", action=_DomainsAction, default=[],
|
||||
help="Domain names to apply. For multiple domains you can use "
|
||||
"multiple -d flags or enter a comma separated list of domains "
|
||||
"as a parameter.")
|
||||
|
||||
helpful.add(
|
||||
[None, "testing", "renew", "certonly"],
|
||||
"--dry-run", action="store_true", dest="dry_run",
|
||||
help="Perform a test run of the client, obtaining test (invalid) certs"
|
||||
" but not saving them to disk. This can currently only be used"
|
||||
" with the 'certonly' and 'renew' subcommands. \nNote: Although --dry-run"
|
||||
|
|
@ -659,7 +707,7 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
|
|||
" if they are defined because they may be necessary to accurately simulate"
|
||||
" renewal. --renew-hook commands are not called.")
|
||||
helpful.add(
|
||||
None, "--register-unsafely-without-email", action="store_true",
|
||||
["register", "automation"], "--register-unsafely-without-email", action="store_true",
|
||||
help="Specifying this flag enables registering an account with no "
|
||||
"email address. This is strongly discouraged, because in the "
|
||||
"event of key loss or account compromise you will irrevocably "
|
||||
|
|
@ -674,20 +722,9 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
|
|||
"with an existing registration, such as the e-mail address, "
|
||||
"should be updated, rather than registering a new account.")
|
||||
helpful.add(None, "-m", "--email", help=config_help("email"))
|
||||
# positional arg shadows --domains, instead of appending, and
|
||||
# --domains is useful, because it can be stored in config
|
||||
#for subparser in parser_run, parser_auth, parser_install:
|
||||
# subparser.add_argument("domains", nargs="*", metavar="domain")
|
||||
helpful.add(None, "-d", "--domains", "--domain", dest="domains",
|
||||
metavar="DOMAIN", action=_DomainsAction, default=[],
|
||||
help="Domain names to apply. For multiple domains you can use "
|
||||
"multiple -d flags or enter a comma separated list of domains "
|
||||
"as a parameter.")
|
||||
helpful.add_group(
|
||||
"automation",
|
||||
description="Arguments for automating execution & other tweaks")
|
||||
helpful.add(
|
||||
"automation", "--keep-until-expiring", "--keep", "--reinstall",
|
||||
["automation", "renew", "certonly", "run"],
|
||||
"--keep-until-expiring", "--keep", "--reinstall",
|
||||
dest="reinstall", action="store_true",
|
||||
help="If the requested cert matches an existing cert, always keep the "
|
||||
"existing one until it is due for renewal (for the "
|
||||
|
|
@ -701,14 +738,16 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
|
|||
version="%(prog)s {0}".format(certbot.__version__),
|
||||
help="show program's version number and exit")
|
||||
helpful.add(
|
||||
"automation", "--force-renewal", "--renew-by-default",
|
||||
["automation", "renew"],
|
||||
"--force-renewal", "--renew-by-default",
|
||||
action="store_true", dest="renew_by_default", help="If a certificate "
|
||||
"already exists for the requested domains, renew it now, "
|
||||
"regardless of whether it is near expiry. (Often "
|
||||
"--keep-until-expiring is more appropriate). Also implies "
|
||||
"--expand.")
|
||||
helpful.add(
|
||||
"automation", "--allow-subset-of-names", action="store_true",
|
||||
["automation", "renew", "certonly"],
|
||||
"--allow-subset-of-names", action="store_true",
|
||||
help="When performing domain validation, do not consider it a failure "
|
||||
"if authorizations can not be obtained for a strict subset of "
|
||||
"the requested domains. This may be useful for allowing renewals for "
|
||||
|
|
@ -732,14 +771,14 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
|
|||
help="(certbot-auto only) prevent the certbot-auto script from"
|
||||
" upgrading itself to newer released versions")
|
||||
helpful.add(
|
||||
"automation", "-q", "--quiet", dest="quiet", action="store_true",
|
||||
["automation", "renew", "certonly"],
|
||||
"-q", "--quiet", dest="quiet", action="store_true",
|
||||
help="Silence all output except errors. Useful for automation via cron."
|
||||
" Implies --non-interactive.")
|
||||
|
||||
helpful.add_group(
|
||||
"testing", description="The following flags are meant for "
|
||||
"testing purposes only! Do NOT change them, unless you "
|
||||
"really know what you're doing!")
|
||||
# overwrites server, handled in HelpfulArgumentParser.parse_args()
|
||||
helpful.add("testing", "--test-cert", "--staging", action='store_true', dest='staging',
|
||||
help='Use the staging server to obtain test (invalid) certs; equivalent'
|
||||
' to --server ' + constants.STAGING_URI)
|
||||
helpful.add(
|
||||
"testing", "--debug", action="store_true",
|
||||
help="Show tracebacks in case of errors, and allow certbot-auto "
|
||||
|
|
@ -759,8 +798,6 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
|
|||
"testing", "--break-my-certs", action="store_true",
|
||||
help="Be willing to replace or renew valid certs with invalid "
|
||||
"(testing/staging) certs")
|
||||
helpful.add_group(
|
||||
"security", description="Security parameters & server settings")
|
||||
helpful.add(
|
||||
"security", "--rsa-key-size", type=int, metavar="N",
|
||||
default=flag_default("rsa_key_size"), help=config_help("rsa_key_size"))
|
||||
|
|
@ -803,50 +840,38 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
|
|||
"security", "--no-staple-ocsp", action="store_false",
|
||||
help="Do not automatically enable OCSP Stapling.",
|
||||
dest="staple", default=None)
|
||||
|
||||
|
||||
helpful.add(
|
||||
"security", "--strict-permissions", action="store_true",
|
||||
help="Require that all configuration files are owned by the current "
|
||||
"user; only needed if your config is somewhere unsafe like /tmp/")
|
||||
|
||||
helpful.add_group(
|
||||
"renew", description="The 'renew' subcommand will attempt to renew all"
|
||||
" certificates (or more precisely, certificate lineages) you have"
|
||||
" previously obtained if they are close to expiry, and print a"
|
||||
" summary of the results. By default, 'renew' will reuse the options"
|
||||
" used to create obtain or most recently successfully renew each"
|
||||
" certificate lineage. You can try it with `--dry-run` first. For"
|
||||
" more fine-grained control, you can renew individual lineages with"
|
||||
" the `certonly` subcommand. Hooks are available to run commands "
|
||||
" before and after renewal; see"
|
||||
" https://certbot.eff.org/docs/using.html#renewal for more information on these.")
|
||||
|
||||
helpful.add(
|
||||
"renew", "--pre-hook",
|
||||
help="Command to be run in a shell before obtaining any certificates. Intended"
|
||||
" primarily for renewal, where it can be used to temporarily shut down a"
|
||||
" webserver that might conflict with the standalone plugin. This will "
|
||||
" only be called if a certificate is actually to be obtained/renewed. ")
|
||||
help="Command to be run in a shell before obtaining any certificates."
|
||||
" Intended primarily for renewal, where it can be used to temporarily"
|
||||
" shut down a webserver that might conflict with the standalone"
|
||||
" plugin. This will only be called if a certificate is actually to be"
|
||||
" obtained/renewed.")
|
||||
helpful.add(
|
||||
"renew", "--post-hook",
|
||||
help="Command to be run in a shell after attempting to obtain/renew "
|
||||
" certificates. Can be used to deploy renewed certificates, or to restart"
|
||||
" any servers that were stopped by --pre-hook. This is only run if"
|
||||
" an attempt was made to obtain/renew a certificate.")
|
||||
help="Command to be run in a shell after attempting to obtain/renew"
|
||||
" certificates. Can be used to deploy renewed certificates, or to"
|
||||
" restart any servers that were stopped by --pre-hook. This is only"
|
||||
" run if an attempt was made to obtain/renew a certificate.")
|
||||
helpful.add(
|
||||
"renew", "--renew-hook",
|
||||
help="Command to be run in a shell once for each successfully renewed certificate."
|
||||
"For this command, the shell variable $RENEWED_LINEAGE will point to the"
|
||||
"config live subdirectory containing the new certs and keys; the shell variable "
|
||||
"$RENEWED_DOMAINS will contain a space-delimited list of renewed cert domains")
|
||||
help="Command to be run in a shell once for each successfully renewed"
|
||||
" certificate. For this command, the shell variable $RENEWED_LINEAGE"
|
||||
" will point to the config live subdirectory containing the new certs"
|
||||
" and keys; the shell variable $RENEWED_DOMAINS will contain a"
|
||||
" space-delimited list of renewed cert domains")
|
||||
helpful.add(
|
||||
"renew", "--disable-hook-validation",
|
||||
action='store_false', dest='validate_hooks', default=True,
|
||||
help="Ordinarily the commands specified for --pre-hook/--post-hook/--renew-hook"
|
||||
" will be checked for validity, to see if the programs being run are in the $PATH,"
|
||||
" so that mistakes can be caught early, even when the hooks aren't being run just yet."
|
||||
" The validation is rather simplistic and fails if you use more advanced"
|
||||
help="Ordinarily the commands specified for"
|
||||
" --pre-hook/--post-hook/--renew-hook will be checked for validity, to"
|
||||
" see if the programs being run are in the $PATH, so that mistakes can"
|
||||
" be caught early, even when the hooks aren't being run just yet. The"
|
||||
" validation is rather simplistic and fails if you use more advanced"
|
||||
" shell constructs, so you can use this switch to disable it.")
|
||||
|
||||
helpful.add_deprecated_argument("--agree-dev-preview", 0)
|
||||
|
|
@ -864,13 +889,6 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
|
|||
|
||||
|
||||
def _create_subparsers(helpful):
|
||||
helpful.add_group("certonly", description="Options for modifying how a cert is obtained")
|
||||
helpful.add_group("install", description="Options for modifying how a cert is deployed")
|
||||
helpful.add_group("revoke", description="Options for revocation of certs")
|
||||
helpful.add_group("rollback", description="Options for reverting config changes")
|
||||
helpful.add_group("plugins", description="Plugin options")
|
||||
helpful.add_group("config_changes",
|
||||
description="Options for showing a history of config changes")
|
||||
helpful.add("config_changes", "--num", type=int,
|
||||
help="How many past revisions you want to be displayed")
|
||||
helpful.add(
|
||||
|
|
@ -906,8 +924,6 @@ def _paths_parser(helpful):
|
|||
verb = helpful.verb
|
||||
if verb == "help":
|
||||
verb = helpful.help_arg
|
||||
helpful.add_group(
|
||||
"paths", description="Arguments changing execution paths & servers")
|
||||
|
||||
cph = "Path to where cert is saved (with auth --csr), installed from or revoked."
|
||||
section = "paths"
|
||||
|
|
@ -946,19 +962,17 @@ def _paths_parser(helpful):
|
|||
help="Logs directory.")
|
||||
add("paths", "--server", default=flag_default("server"),
|
||||
help=config_help("server"))
|
||||
# overwrites server, handled in HelpfulArgumentParser.parse_args()
|
||||
add("testing", "--test-cert", "--staging", action='store_true', dest='staging',
|
||||
help='Use the staging server to obtain test (invalid) certs; equivalent'
|
||||
' to --server ' + constants.STAGING_URI)
|
||||
|
||||
|
||||
def _plugins_parsing(helpful, plugins):
|
||||
# It's nuts, but there are two "plugins" topics. Somehow this works
|
||||
helpful.add_group(
|
||||
"plugins", description="Certbot client supports an "
|
||||
"plugins", description="Plugin Selection: Certbot client supports an "
|
||||
"extensible plugins architecture. See '%(prog)s plugins' for a "
|
||||
"list of all installed plugins and their names. You can force "
|
||||
"a particular plugin by setting options provided below. Running "
|
||||
"--help <plugin_name> will list flags specific to that plugin.")
|
||||
|
||||
helpful.add(
|
||||
"plugins", "-a", "--authenticator", help="Authenticator plugin name.")
|
||||
helpful.add(
|
||||
|
|
@ -967,15 +981,17 @@ def _plugins_parsing(helpful, plugins):
|
|||
"plugins", "--configurator", help="Name of the plugin that is "
|
||||
"both an authenticator and an installer. Should not be used "
|
||||
"together with --authenticator or --installer.")
|
||||
helpful.add("plugins", "--apache", action="store_true",
|
||||
helpful.add(["plugins", "certonly", "run", "install"],
|
||||
"--apache", action="store_true",
|
||||
help="Obtain and install certs using Apache")
|
||||
helpful.add("plugins", "--nginx", action="store_true",
|
||||
helpful.add(["plugins", "certonly", "run", "install"],
|
||||
"--nginx", action="store_true",
|
||||
help="Obtain and install certs using Nginx")
|
||||
helpful.add("plugins", "--standalone", action="store_true",
|
||||
helpful.add(["plugins", "certonly"], "--standalone", action="store_true",
|
||||
help='Obtain certs using a "standalone" webserver.')
|
||||
helpful.add("plugins", "--manual", action="store_true",
|
||||
helpful.add(["plugins", "certonly"], "--manual", action="store_true",
|
||||
help='Provide laborious manual instructions for obtaining a cert')
|
||||
helpful.add("plugins", "--webroot", action="store_true",
|
||||
helpful.add(["plugins", "certonly"], "--webroot", action="store_true",
|
||||
help='Obtain certs by placing files in a webroot directory.')
|
||||
|
||||
# things should not be reorder past/pre this comment:
|
||||
|
|
|
|||
|
|
@ -246,8 +246,7 @@ class Client(object):
|
|||
domains,
|
||||
self.config.allow_subset_of_names)
|
||||
|
||||
auth_domains = set(a.body.identifier.value.encode('ascii')
|
||||
for a in authzr)
|
||||
auth_domains = set(a.body.identifier.value for a in authzr)
|
||||
domains = [d for d in domains if d in auth_domains]
|
||||
|
||||
# Create CSR from names
|
||||
|
|
@ -317,7 +316,7 @@ class Client(object):
|
|||
self.config.strict_permissions)
|
||||
|
||||
cert_pem = OpenSSL.crypto.dump_certificate(
|
||||
OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped)
|
||||
OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped).decode('ascii')
|
||||
|
||||
cert_file, abs_cert_path = _open_pem_file('cert_path', cert_path)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import traceback
|
|||
|
||||
import OpenSSL
|
||||
import pyrfc3339
|
||||
import six
|
||||
import zope.component
|
||||
|
||||
from acme import crypto_util as acme_crypto_util
|
||||
|
|
@ -115,16 +116,16 @@ def make_csr(key_str, domains, must_staple=False):
|
|||
# TODO: put SAN if len(domains) > 1
|
||||
extensions = [
|
||||
OpenSSL.crypto.X509Extension(
|
||||
"subjectAltName",
|
||||
b"subjectAltName",
|
||||
critical=False,
|
||||
value=", ".join("DNS:%s" % d for d in domains)
|
||||
value=", ".join("DNS:%s" % d for d in domains).encode('ascii')
|
||||
)
|
||||
]
|
||||
if must_staple:
|
||||
extensions.append(OpenSSL.crypto.X509Extension(
|
||||
"1.3.6.1.5.5.7.1.24",
|
||||
b"1.3.6.1.5.5.7.1.24",
|
||||
critical=False,
|
||||
value="DER:30:03:02:01:05"))
|
||||
value=b"DER:30:03:02:01:05"))
|
||||
req.add_extensions(extensions)
|
||||
req.set_version(2)
|
||||
req.set_pubkey(pkey)
|
||||
|
|
@ -350,7 +351,7 @@ def dump_pyopenssl_chain(chain, filetype=OpenSSL.crypto.FILETYPE_PEM):
|
|||
if isinstance(cert, jose.ComparableX509):
|
||||
# pylint: disable=protected-access
|
||||
cert = cert.wrapped
|
||||
return OpenSSL.crypto.dump_certificate(filetype, cert)
|
||||
return OpenSSL.crypto.dump_certificate(filetype, cert).decode('ascii')
|
||||
|
||||
# assumes that OpenSSL.crypto.dump_certificate includes ending
|
||||
# newline character
|
||||
|
|
@ -395,8 +396,14 @@ def _notAfterBefore(cert_path, method):
|
|||
with open(cert_path) as f:
|
||||
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
|
||||
f.read())
|
||||
# pyopenssl always returns bytes
|
||||
timestamp = method(x509)
|
||||
reformatted_timestamp = [timestamp[0:4], "-", timestamp[4:6], "-",
|
||||
timestamp[6:8], "T", timestamp[8:10], ":",
|
||||
timestamp[10:12], ":", timestamp[12:]]
|
||||
return pyrfc3339.parse("".join(reformatted_timestamp))
|
||||
reformatted_timestamp = [timestamp[0:4], b"-", timestamp[4:6], b"-",
|
||||
timestamp[6:8], b"T", timestamp[8:10], b":",
|
||||
timestamp[10:12], b":", timestamp[12:]]
|
||||
timestamp_str = b"".join(reformatted_timestamp)
|
||||
# pyrfc3339 uses "native" strings. That is, bytes on Python 2 and unicode
|
||||
# on Python 3
|
||||
if six.PY3:
|
||||
timestamp_str = timestamp_str.decode('ascii')
|
||||
return pyrfc3339.parse(timestamp_str)
|
||||
|
|
|
|||
|
|
@ -180,7 +180,12 @@ def _choose_names_manually():
|
|||
try:
|
||||
domain_list[i] = util.enforce_domain_sanity(domain)
|
||||
except errors.ConfigurationError as e:
|
||||
invalid_domains[domain] = e.message
|
||||
try: # Python 2
|
||||
# pylint: disable=no-member
|
||||
err_msg = e.message.encode('utf-8')
|
||||
except AttributeError:
|
||||
err_msg = str(e)
|
||||
invalid_domains[domain] = err_msg
|
||||
|
||||
if len(invalid_domains):
|
||||
retry_message = (
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import os
|
|||
import textwrap
|
||||
|
||||
import dialog
|
||||
import six
|
||||
import zope.interface
|
||||
|
||||
from certbot import interfaces
|
||||
|
|
@ -82,7 +83,7 @@ class NcursesDisplay(object):
|
|||
|
||||
def __init__(self, width=WIDTH, height=HEIGHT):
|
||||
super(NcursesDisplay, self).__init__()
|
||||
self.dialog = dialog.Dialog()
|
||||
self.dialog = dialog.Dialog(autowidgetsize=True)
|
||||
assert OK == self.dialog.DIALOG_OK, "What kind of absurdity is this?"
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
|
@ -101,7 +102,7 @@ class NcursesDisplay(object):
|
|||
:param bool pause: Not applicable to NcursesDisplay
|
||||
|
||||
"""
|
||||
self.dialog.msgbox(message, height, width=self.width)
|
||||
self.dialog.msgbox(message)
|
||||
|
||||
def menu(self, message, choices, ok_label="OK", cancel_label="Cancel",
|
||||
help_label="", **unused_kwargs):
|
||||
|
|
@ -170,11 +171,7 @@ class NcursesDisplay(object):
|
|||
`string` - input entered by the user
|
||||
|
||||
"""
|
||||
sections = message.split("\n")
|
||||
# each section takes at least one line, plus extras if it's longer than self.width
|
||||
wordlines = [1 + (len(section) / self.width) for section in sections]
|
||||
height = 6 + sum(wordlines) + len(sections)
|
||||
return _clean(self.dialog.inputbox(message, width=self.width, height=height))
|
||||
return self.dialog.inputbox(message)
|
||||
|
||||
def yesno(self, message, yes_label="Yes", no_label="No", **unused_kwargs):
|
||||
"""Display a Yes/No dialog box.
|
||||
|
|
@ -191,8 +188,7 @@ class NcursesDisplay(object):
|
|||
|
||||
"""
|
||||
return self.dialog.DIALOG_OK == self.dialog.yesno(
|
||||
message, self.height, self.width,
|
||||
yes_label=yes_label, no_label=no_label)
|
||||
message, yes_label=yes_label, no_label=no_label)
|
||||
|
||||
def checklist(self, message, tags, default_status=True, **unused_kwargs):
|
||||
"""Displays a checklist.
|
||||
|
|
@ -210,8 +206,7 @@ class NcursesDisplay(object):
|
|||
|
||||
"""
|
||||
choices = [(tag, "", default_status) for tag in tags]
|
||||
return _clean(self.dialog.checklist(
|
||||
message, width=self.width, height=self.height, choices=choices))
|
||||
return self.dialog.checklist(message, choices=choices)
|
||||
|
||||
def directory_select(self, message, **unused_kwargs):
|
||||
"""Display a directory selection screen.
|
||||
|
|
@ -224,9 +219,8 @@ class NcursesDisplay(object):
|
|||
|
||||
"""
|
||||
root_directory = os.path.abspath(os.sep)
|
||||
return _clean(self.dialog.dselect(
|
||||
filepath=root_directory, width=self.width,
|
||||
height=self.height, help_button=True, title=message))
|
||||
return self.dialog.dselect(
|
||||
filepath=root_directory, help_button=True, title=message)
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IDisplay)
|
||||
|
|
@ -253,7 +247,7 @@ class FileDisplay(object):
|
|||
"{line}{frame}{line}{msg}{line}{frame}{line}".format(
|
||||
line=os.linesep, frame=side_frame, msg=message))
|
||||
if pause:
|
||||
raw_input("Press Enter to Continue")
|
||||
six.moves.input("Press Enter to Continue")
|
||||
|
||||
def menu(self, message, choices, ok_label="", cancel_label="",
|
||||
help_label="", **unused_kwargs):
|
||||
|
|
@ -295,7 +289,7 @@ class FileDisplay(object):
|
|||
:rtype: tuple
|
||||
|
||||
"""
|
||||
ans = raw_input(
|
||||
ans = six.moves.input(
|
||||
textwrap.fill(
|
||||
"%s (Enter 'c' to cancel): " % message,
|
||||
80,
|
||||
|
|
@ -330,7 +324,7 @@ class FileDisplay(object):
|
|||
os.linesep, frame=side_frame, msg=message))
|
||||
|
||||
while True:
|
||||
ans = raw_input("{yes}/{no}: ".format(
|
||||
ans = six.moves.input("{yes}/{no}: ".format(
|
||||
yes=_parens_around_char(yes_label),
|
||||
no=_parens_around_char(no_label)))
|
||||
|
||||
|
|
@ -468,7 +462,7 @@ class FileDisplay(object):
|
|||
input_msg = ("Press 1 [enter] to confirm the selection "
|
||||
"(press 'c' to cancel): ")
|
||||
while selection < 1:
|
||||
ans = raw_input(input_msg)
|
||||
ans = six.moves.input(input_msg)
|
||||
if ans.startswith("c") or ans.startswith("C"):
|
||||
return CANCEL, -1
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ class IConfig(zope.interface.Interface):
|
|||
"Location of renewal configuration file.")
|
||||
|
||||
no_verify_ssl = zope.interface.Attribute(
|
||||
"Disable SSL certificate verification.")
|
||||
"Disable verification of the ACME server's certificate.")
|
||||
tls_sni_01_port = zope.interface.Attribute(
|
||||
"Port number to perform tls-sni-01 challenge. "
|
||||
"Boulder in testing mode defaults to 5001.")
|
||||
|
|
|
|||
|
|
@ -255,4 +255,4 @@ class PluginsRegistry(collections.Mapping):
|
|||
def __str__(self):
|
||||
if not self._plugins:
|
||||
return "No plugins"
|
||||
return "\n\n".join(str(p_ep) for p_ep in self._plugins.itervalues())
|
||||
return "\n\n".join(str(p_ep) for p_ep in six.itervalues(self._plugins))
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import unittest
|
|||
|
||||
import mock
|
||||
import pkg_resources
|
||||
import six
|
||||
import zope.interface
|
||||
|
||||
from certbot import errors
|
||||
|
|
@ -50,14 +51,12 @@ class PluginEntryPointTest(unittest.TestCase):
|
|||
EP_SA: "sa",
|
||||
}
|
||||
|
||||
for entry_point, name in names.iteritems():
|
||||
for entry_point, name in six.iteritems(names):
|
||||
self.assertEqual(
|
||||
name, PluginEntryPoint.entry_point_to_plugin_name(entry_point))
|
||||
|
||||
def test_description(self):
|
||||
self.assertEqual(
|
||||
"Automatically use a temporary webserver",
|
||||
self.plugin_ep.description)
|
||||
self.assertTrue("temporary webserver" in self.plugin_ep.description)
|
||||
|
||||
def test_description_with_name(self):
|
||||
self.plugin_ep.plugin_cls = mock.MagicMock(description="Desc")
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class AuthenticatorTest(unittest.TestCase):
|
|||
@mock.patch("certbot.plugins.manual.zope.component.getUtility")
|
||||
@mock.patch("certbot.plugins.manual.sys.stdout")
|
||||
@mock.patch("acme.challenges.HTTP01Response.simple_verify")
|
||||
@mock.patch("__builtin__.raw_input")
|
||||
@mock.patch("six.moves.input")
|
||||
def test_perform(self, mock_raw_input, mock_verify, mock_stdout, mock_interaction):
|
||||
mock_verify.return_value = True
|
||||
mock_interaction().yesno.return_value = True
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from __future__ import print_function
|
|||
import os
|
||||
import logging
|
||||
|
||||
import six
|
||||
import zope.component
|
||||
|
||||
from certbot import errors
|
||||
|
|
@ -78,7 +79,7 @@ def pick_plugin(config, default, plugins, question, ifaces):
|
|||
|
||||
if len(prepared) > 1:
|
||||
logger.debug("Multiple candidate plugins: %s", prepared)
|
||||
plugin_ep = choose_plugin(prepared.values(), question)
|
||||
plugin_ep = choose_plugin(list(six.itervalues(prepared)), question)
|
||||
if plugin_ep is None:
|
||||
return None
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ class Authenticator(common.Plugin):
|
|||
rely on any existing server program.
|
||||
"""
|
||||
|
||||
description = "Automatically use a temporary webserver"
|
||||
description = "Spin up a temporary webserver"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Authenticator, self).__init__(*args, **kwargs)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class AlreadyListeningTestNoPsutil(unittest.TestCase):
|
|||
def test_ports_available(self, mock_getutil):
|
||||
import certbot.plugins.util as plugins_util
|
||||
# Ensure we don't get error
|
||||
with mock.patch("socket._socketobject.bind"):
|
||||
with mock.patch("socket.socket.bind"):
|
||||
self.assertFalse(plugins_util.already_listening(80))
|
||||
self.assertFalse(plugins_util.already_listening(80, True))
|
||||
self.assertEqual(mock_getutil.call_count, 0)
|
||||
|
|
@ -73,7 +73,7 @@ class AlreadyListeningTestNoPsutil(unittest.TestCase):
|
|||
sys.modules["psutil"] = None
|
||||
import certbot.plugins.util as plugins_util
|
||||
import socket
|
||||
with mock.patch("socket._socketobject.bind", side_effect=socket.error):
|
||||
with mock.patch("socket.socket.bind", side_effect=socket.error):
|
||||
self.assertTrue(plugins_util.already_listening(80))
|
||||
self.assertTrue(plugins_util.already_listening(80, True))
|
||||
with mock.patch("socket.socket", side_effect=socket.error):
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ to serve all files under specified web root ({0})."""
|
|||
old_umask = os.umask(0o022)
|
||||
|
||||
try:
|
||||
with open(validation_path, "w") as validation_file:
|
||||
with open(validation_path, "wb") as validation_file:
|
||||
validation_file.write(validation.encode())
|
||||
finally:
|
||||
os.umask(old_umask)
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ def _restore_plugin_configs(config, renewalparams):
|
|||
if renewalparams.get("installer", None) is not None:
|
||||
plugin_prefixes.append(renewalparams["installer"])
|
||||
for plugin_prefix in set(plugin_prefixes):
|
||||
plugin_prefix = plugin_prefix.replace('-', '_')
|
||||
for config_item, config_value in six.iteritems(renewalparams):
|
||||
if config_item.startswith(plugin_prefix + "_") and not cli.set_by_cli(config_item):
|
||||
# Values None, True, and False need to be treated specially,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import shutil
|
|||
import time
|
||||
import traceback
|
||||
|
||||
|
||||
import six
|
||||
import zope.component
|
||||
|
||||
from certbot import constants
|
||||
|
|
@ -310,7 +310,9 @@ class Reverter(object):
|
|||
|
||||
def _run_undo_commands(self, filepath): # pylint: disable=no-self-use
|
||||
"""Run all commands in a file."""
|
||||
with open(filepath, 'rb') as csvfile:
|
||||
# NOTE: csv module uses native strings. That is, bytes on Python 2 and
|
||||
# unicode on Python 3
|
||||
with open(filepath, 'r') as csvfile:
|
||||
csvreader = csv.reader(csvfile)
|
||||
for command in reversed(list(csvreader)):
|
||||
try:
|
||||
|
|
@ -408,9 +410,9 @@ class Reverter(object):
|
|||
command_file = None
|
||||
try:
|
||||
if os.path.isfile(commands_fp):
|
||||
command_file = open(commands_fp, "ab")
|
||||
command_file = open(commands_fp, "a")
|
||||
else:
|
||||
command_file = open(commands_fp, "wb")
|
||||
command_file = open(commands_fp, "w")
|
||||
|
||||
csvwriter = csv.writer(command_file)
|
||||
csvwriter.writerow(command)
|
||||
|
|
@ -569,7 +571,7 @@ class Reverter(object):
|
|||
# It is possible save checkpoints faster than 1 per second resulting in
|
||||
# collisions in the naming convention.
|
||||
|
||||
for _ in xrange(2):
|
||||
for _ in six.moves.range(2):
|
||||
timestamp = self._checkpoint_timestamp()
|
||||
final_dir = os.path.join(self.config.backup_dir, timestamp)
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ def write_renewal_config(o_filename, n_filename, target, relevant_data):
|
|||
# TODO: add human-readable comments explaining other available
|
||||
# parameters
|
||||
logger.debug("Writing new config %s.", n_filename)
|
||||
with open(n_filename, "w") as f:
|
||||
with open(n_filename, "wb") as f:
|
||||
config.write(outfile=f)
|
||||
return config
|
||||
|
||||
|
|
|
|||
|
|
@ -131,8 +131,8 @@ class AccountFileStorageTest(unittest.TestCase):
|
|||
for file_name in "regr.json", "meta.json", "private_key.json":
|
||||
self.assertTrue(os.path.exists(
|
||||
os.path.join(account_path, file_name)))
|
||||
self.assertEqual("0400", oct(os.stat(os.path.join(
|
||||
account_path, "private_key.json"))[stat.ST_MODE] & 0o777))
|
||||
self.assertTrue(oct(os.stat(os.path.join(
|
||||
account_path, "private_key.json"))[stat.ST_MODE] & 0o777) in ("0400", "0o400"))
|
||||
|
||||
# restore
|
||||
self.assertEqual(self.acc, self.storage.load(self.acc.id))
|
||||
|
|
@ -179,14 +179,14 @@ class AccountFileStorageTest(unittest.TestCase):
|
|||
self.storage.save(self.acc)
|
||||
mock_open = mock.mock_open()
|
||||
mock_open.side_effect = IOError
|
||||
with mock.patch("__builtin__.open", mock_open):
|
||||
with mock.patch("six.moves.builtins.open", mock_open):
|
||||
self.assertRaises(
|
||||
errors.AccountStorageError, self.storage.load, self.acc.id)
|
||||
|
||||
def test_save_ioerrors(self):
|
||||
mock_open = mock.mock_open()
|
||||
mock_open.side_effect = IOError # TODO: [None, None, IOError]
|
||||
with mock.patch("__builtin__.open", mock_open):
|
||||
with mock.patch("six.moves.builtins.open", mock_open):
|
||||
self.assertRaises(
|
||||
errors.AccountStorageError, self.storage.save, self.acc)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"""ACME utilities for testing."""
|
||||
import datetime
|
||||
import itertools
|
||||
|
||||
import six
|
||||
|
||||
from acme import challenges
|
||||
from acme import jose
|
||||
|
|
@ -13,10 +14,10 @@ KEY = test_util.load_rsa_private_key('rsa512_key.pem')
|
|||
|
||||
# Challenges
|
||||
HTTP01 = challenges.HTTP01(
|
||||
token="evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ+PCt92wr+oA")
|
||||
token=b"evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ+PCt92wr+oA")
|
||||
TLSSNI01 = challenges.TLSSNI01(
|
||||
token=jose.b64decode(b"evaGxfADs6pSRb2LAv9IZf17Dt3juxGJyPCt92wrDoA"))
|
||||
DNS = challenges.DNS(token="17817c66b60ce2e4012dfad92657527a")
|
||||
DNS = challenges.DNS(token=b"17817c66b60ce2e4012dfad92657527a")
|
||||
|
||||
CHALLENGES = [HTTP01, TLSSNI01, DNS]
|
||||
|
||||
|
|
@ -62,7 +63,7 @@ def gen_authzr(authz_status, domain, challs, statuses, combos=True):
|
|||
# pylint: disable=redefined-outer-name
|
||||
challbs = tuple(
|
||||
chall_to_challb(chall, status)
|
||||
for chall, status in itertools.izip(challs, statuses)
|
||||
for chall, status in six.moves.zip(challs, statuses)
|
||||
)
|
||||
authz_kwargs = {
|
||||
"identifier": messages.Identifier(
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import logging
|
|||
import unittest
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
from acme import challenges
|
||||
from acme import client as acme_client
|
||||
|
|
@ -93,7 +94,7 @@ class GetAuthorizationsTest(unittest.TestCase):
|
|||
|
||||
self.assertEqual(mock_poll.call_count, 1)
|
||||
chall_update = mock_poll.call_args[0][0]
|
||||
self.assertEqual(chall_update.keys(), ["0"])
|
||||
self.assertEqual(list(six.iterkeys(chall_update)), ["0"])
|
||||
self.assertEqual(len(chall_update.values()), 1)
|
||||
|
||||
self.assertEqual(self.mock_auth.cleanup.call_count, 1)
|
||||
|
|
@ -118,7 +119,7 @@ class GetAuthorizationsTest(unittest.TestCase):
|
|||
|
||||
self.assertEqual(mock_poll.call_count, 1)
|
||||
chall_update = mock_poll.call_args[0][0]
|
||||
self.assertEqual(chall_update.keys(), ["0"])
|
||||
self.assertEqual(list(six.iterkeys(chall_update)), ["0"])
|
||||
self.assertEqual(len(chall_update.values()), 1)
|
||||
|
||||
self.assertEqual(self.mock_auth.cleanup.call_count, 1)
|
||||
|
|
@ -143,12 +144,12 @@ class GetAuthorizationsTest(unittest.TestCase):
|
|||
# Check poll call
|
||||
self.assertEqual(mock_poll.call_count, 1)
|
||||
chall_update = mock_poll.call_args[0][0]
|
||||
self.assertEqual(len(chall_update.keys()), 3)
|
||||
self.assertTrue("0" in chall_update.keys())
|
||||
self.assertEqual(len(list(six.iterkeys(chall_update))), 3)
|
||||
self.assertTrue("0" in list(six.iterkeys(chall_update)))
|
||||
self.assertEqual(len(chall_update["0"]), 1)
|
||||
self.assertTrue("1" in chall_update.keys())
|
||||
self.assertTrue("1" in list(six.iterkeys(chall_update)))
|
||||
self.assertEqual(len(chall_update["1"]), 1)
|
||||
self.assertTrue("2" in chall_update.keys())
|
||||
self.assertTrue("2" in list(six.iterkeys(chall_update)))
|
||||
self.assertEqual(len(chall_update["2"]), 1)
|
||||
|
||||
self.assertEqual(self.mock_auth.cleanup.call_count, 1)
|
||||
|
|
@ -167,7 +168,7 @@ class GetAuthorizationsTest(unittest.TestCase):
|
|||
self.assertRaises(errors.AuthorizationError, self.handler.get_authorizations, [])
|
||||
|
||||
def _validate_all(self, unused_1, unused_2):
|
||||
for dom in self.handler.authzr.keys():
|
||||
for dom in six.iterkeys(self.handler.authzr):
|
||||
azr = self.handler.authzr[dom]
|
||||
self.handler.authzr[dom] = acme_util.gen_authzr(
|
||||
messages.STATUS_VALID,
|
||||
|
|
@ -317,7 +318,7 @@ class GenChallengePathTest(unittest.TestCase):
|
|||
|
||||
"""
|
||||
def setUp(self):
|
||||
logging.disable(logging.fatal)
|
||||
logging.disable(logging.FATAL)
|
||||
|
||||
def tearDown(self):
|
||||
logging.disable(logging.NOTSET)
|
||||
|
|
|
|||
|
|
@ -113,7 +113,15 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
out = self._help_output(['--help', 'plugins'])
|
||||
self.assertTrue("--manual-test-mode" not in out)
|
||||
self.assertTrue("--prepare" in out)
|
||||
self.assertTrue("Plugin options" in out)
|
||||
self.assertTrue('"plugins" subcommand' in out)
|
||||
|
||||
# test multiple topics
|
||||
out = self._help_output(['-h', 'renew'])
|
||||
self.assertTrue("--keep" in out)
|
||||
out = self._help_output(['-h', 'automation'])
|
||||
self.assertTrue("--keep" in out)
|
||||
out = self._help_output(['-h', 'revoke'])
|
||||
self.assertTrue("--keep" not in out)
|
||||
|
||||
out = self._help_output(['--help', 'install'])
|
||||
self.assertTrue("--cert-path" in out)
|
||||
|
|
@ -136,7 +144,8 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
try:
|
||||
with mock.patch('certbot.main.sys.stderr'):
|
||||
main.main(self.standard_args + args[:]) # NOTE: parser can alter its args!
|
||||
except errors.MissingCommandlineFlag as exc:
|
||||
except errors.MissingCommandlineFlag as exc_:
|
||||
exc = exc_
|
||||
self.assertTrue(message in str(exc))
|
||||
self.assertTrue(exc is not None)
|
||||
|
||||
|
|
@ -263,7 +272,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
flags = ['--init', '--prepare', '--authenticators', '--installers']
|
||||
for args in itertools.chain(
|
||||
*(itertools.combinations(flags, r)
|
||||
for r in xrange(len(flags)))):
|
||||
for r in six.moves.range(len(flags)))):
|
||||
self._call(['plugins'] + list(args))
|
||||
|
||||
@mock.patch('certbot.main.plugins_disco')
|
||||
|
|
@ -332,7 +341,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
self._call(['-a', 'bad_auth', 'certonly'])
|
||||
assert False, "Exception should have been raised"
|
||||
except errors.PluginSelectionError as e:
|
||||
self.assertTrue('The requested bad_auth plugin does not appear' in e.message)
|
||||
self.assertTrue('The requested bad_auth plugin does not appear' in str(e))
|
||||
|
||||
def test_check_config_sanity_domain(self):
|
||||
# Punycode
|
||||
|
|
@ -427,9 +436,9 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
"The following flags didn't conflict with "
|
||||
'--server: {0}'.format(', '.join(conflicting_args)))
|
||||
except errors.Error as error:
|
||||
self.assertTrue('--server' in error.message)
|
||||
self.assertTrue('--server' in str(error))
|
||||
for arg in conflicting_args:
|
||||
self.assertTrue(arg in error.message)
|
||||
self.assertTrue(arg in str(error))
|
||||
|
||||
def test_must_staple_flag(self):
|
||||
parse = self._get_argument_parser()
|
||||
|
|
@ -855,10 +864,10 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
server = 'foo.bar'
|
||||
self._call_no_clientmock(['--cert-path', CERT, '--key-path', KEY,
|
||||
'--server', server, 'revoke'])
|
||||
with open(KEY) as f:
|
||||
with open(KEY, 'rb') as f:
|
||||
mock_acme_client.Client.assert_called_once_with(
|
||||
server, key=jose.JWK.load(f.read()), net=mock.ANY)
|
||||
with open(CERT) as f:
|
||||
with open(CERT, 'rb') as f:
|
||||
cert = crypto_util.pyopenssl_load_certificate(f.read())[0]
|
||||
mock_revoke = mock_acme_client.Client().revoke
|
||||
mock_revoke.assert_called_once_with(jose.ComparableX509(cert))
|
||||
|
|
@ -885,7 +894,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
config.verbose_count = 1
|
||||
main._handle_exception(
|
||||
Exception, exc_value=exception, trace=None, config=None)
|
||||
mock_open().write.assert_called_once_with(''.join(
|
||||
mock_open().write.assert_any_call(''.join(
|
||||
traceback.format_exception_only(Exception, exception)))
|
||||
error_msg = mock_sys.exit.call_args_list[0][0][0]
|
||||
self.assertTrue('unexpected error' in error_msg)
|
||||
|
|
@ -935,8 +944,8 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
self.assertRaises(
|
||||
argparse.ArgumentTypeError, cli.read_file, rel_test_path)
|
||||
|
||||
test_contents = 'bar\n'
|
||||
with open(rel_test_path, 'w') as f:
|
||||
test_contents = b'bar\n'
|
||||
with open(rel_test_path, 'wb') as f:
|
||||
f.write(test_contents)
|
||||
|
||||
path, contents = cli.read_file(rel_test_path)
|
||||
|
|
@ -1106,7 +1115,7 @@ class DuplicativeCertsTest(storage_test.BaseRenewableCertTest):
|
|||
def test_find_duplicative_names(self, unused_makedir):
|
||||
from certbot.main import _find_duplicative_certs
|
||||
test_cert = test_util.load_vector('cert-san.pem')
|
||||
with open(self.test_rc.cert, 'w') as f:
|
||||
with open(self.test_rc.cert, 'wb') as f:
|
||||
f.write(test_cert)
|
||||
|
||||
# No overlap at all
|
||||
|
|
|
|||
|
|
@ -232,11 +232,11 @@ class ClientTest(unittest.TestCase):
|
|||
self.assertEqual(os.path.dirname(fullchain_path),
|
||||
os.path.dirname(candidate_fullchain_path))
|
||||
|
||||
with open(cert_path, "r") as cert_file:
|
||||
with open(cert_path, "rb") as cert_file:
|
||||
cert_contents = cert_file.read()
|
||||
self.assertEqual(cert_contents, test_util.load_vector(certs[0]))
|
||||
|
||||
with open(chain_path, "r") as chain_file:
|
||||
with open(chain_path, "rb") as chain_file:
|
||||
chain_contents = chain_file.read()
|
||||
self.assertEqual(chain_contents, test_util.load_vector(certs[1]) +
|
||||
test_util.load_vector(certs[2]))
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ class NamespaceConfigTest(unittest.TestCase):
|
|||
config_base = "foo"
|
||||
work_base = "bar"
|
||||
logs_base = "baz"
|
||||
server = "mock.server"
|
||||
|
||||
mock_namespace = mock.MagicMock(spec=['config_dir', 'work_dir',
|
||||
'logs_dir', 'http01_port',
|
||||
|
|
@ -68,6 +69,7 @@ class NamespaceConfigTest(unittest.TestCase):
|
|||
mock_namespace.config_dir = config_base
|
||||
mock_namespace.work_dir = work_base
|
||||
mock_namespace.logs_dir = logs_base
|
||||
mock_namespace.server = server
|
||||
config = NamespaceConfig(mock_namespace)
|
||||
|
||||
self.assertTrue(os.path.isabs(config.config_dir))
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ class MakeCSRTest(unittest.TestCase):
|
|||
# OpenSSL.crypto.X509Extension doesn't give us the extension's raw OID,
|
||||
# and the shortname field is just "UNDEF"
|
||||
must_staple_exts = [e for e in csr.get_extensions()
|
||||
if e.get_data() == "0\x03\x02\x01\x05"]
|
||||
if e.get_data() == b"0\x03\x02\x01\x05"]
|
||||
self.assertEqual(len(must_staple_exts), 1,
|
||||
"Expected exactly one Must Staple extension")
|
||||
|
||||
|
|
@ -341,7 +341,7 @@ class CertLoaderTest(unittest.TestCase):
|
|||
|
||||
def test_load_invalid_cert(self):
|
||||
from certbot.crypto_util import pyopenssl_load_certificate
|
||||
bad_cert_data = CERT.replace("BEGIN CERTIFICATE", "ASDFASDFASDF!!!")
|
||||
bad_cert_data = CERT.replace(b"BEGIN CERTIFICATE", b"ASDFASDFASDF!!!")
|
||||
self.assertRaises(
|
||||
errors.Error, pyopenssl_load_certificate, bad_cert_data)
|
||||
|
||||
|
|
|
|||
|
|
@ -107,8 +107,7 @@ class NcursesDisplayTest(unittest.TestCase):
|
|||
self.assertTrue(self.displayer.yesno("message"))
|
||||
|
||||
mock_yesno.assert_called_with(
|
||||
"message", display_util.HEIGHT, display_util.WIDTH,
|
||||
yes_label="Yes", no_label="No")
|
||||
"message", yes_label="Yes", no_label="No")
|
||||
|
||||
@mock.patch("certbot.display.util."
|
||||
"dialog.Dialog.checklist")
|
||||
|
|
@ -121,9 +120,7 @@ class NcursesDisplayTest(unittest.TestCase):
|
|||
(TAGS[1], "", True),
|
||||
(TAGS[2], "", True),
|
||||
]
|
||||
mock_checklist.assert_called_with(
|
||||
"message", width=display_util.WIDTH, height=display_util.HEIGHT,
|
||||
choices=choices)
|
||||
mock_checklist.assert_called_with("message", choices=choices)
|
||||
|
||||
@mock.patch("certbot.display.util.dialog.Dialog.dselect")
|
||||
def test_directory_select(self, mock_dselect):
|
||||
|
|
@ -151,7 +148,7 @@ class FileOutputDisplayTest(unittest.TestCase):
|
|||
self.assertTrue("message" in string)
|
||||
|
||||
def test_notification_pause(self):
|
||||
with mock.patch("__builtin__.raw_input", return_value="enter"):
|
||||
with mock.patch("six.moves.input", return_value="enter"):
|
||||
self.displayer.notification("message")
|
||||
|
||||
self.assertTrue("message" in self.mock_stdout.write.call_args[0][0])
|
||||
|
|
@ -164,31 +161,31 @@ class FileOutputDisplayTest(unittest.TestCase):
|
|||
self.assertEqual(ret, (display_util.OK, 0))
|
||||
|
||||
def test_input_cancel(self):
|
||||
with mock.patch("__builtin__.raw_input", return_value="c"):
|
||||
with mock.patch("six.moves.input", return_value="c"):
|
||||
code, _ = self.displayer.input("message")
|
||||
|
||||
self.assertTrue(code, display_util.CANCEL)
|
||||
|
||||
def test_input_normal(self):
|
||||
with mock.patch("__builtin__.raw_input", return_value="domain.com"):
|
||||
with mock.patch("six.moves.input", return_value="domain.com"):
|
||||
code, input_ = self.displayer.input("message")
|
||||
|
||||
self.assertEqual(code, display_util.OK)
|
||||
self.assertEqual(input_, "domain.com")
|
||||
|
||||
def test_yesno(self):
|
||||
with mock.patch("__builtin__.raw_input", return_value="Yes"):
|
||||
with mock.patch("six.moves.input", return_value="Yes"):
|
||||
self.assertTrue(self.displayer.yesno("message"))
|
||||
with mock.patch("__builtin__.raw_input", return_value="y"):
|
||||
with mock.patch("six.moves.input", return_value="y"):
|
||||
self.assertTrue(self.displayer.yesno("message"))
|
||||
with mock.patch("__builtin__.raw_input", side_effect=["maybe", "y"]):
|
||||
with mock.patch("six.moves.input", side_effect=["maybe", "y"]):
|
||||
self.assertTrue(self.displayer.yesno("message"))
|
||||
with mock.patch("__builtin__.raw_input", return_value="No"):
|
||||
with mock.patch("six.moves.input", return_value="No"):
|
||||
self.assertFalse(self.displayer.yesno("message"))
|
||||
with mock.patch("__builtin__.raw_input", side_effect=["cancel", "n"]):
|
||||
with mock.patch("six.moves.input", side_effect=["cancel", "n"]):
|
||||
self.assertFalse(self.displayer.yesno("message"))
|
||||
|
||||
with mock.patch("__builtin__.raw_input", return_value="a"):
|
||||
with mock.patch("six.moves.input", return_value="a"):
|
||||
self.assertTrue(self.displayer.yesno("msg", yes_label="Agree"))
|
||||
|
||||
@mock.patch("certbot.display.util.FileDisplay.input")
|
||||
|
|
@ -275,11 +272,11 @@ class FileOutputDisplayTest(unittest.TestCase):
|
|||
|
||||
def test_get_valid_int_ans_valid(self):
|
||||
# pylint: disable=protected-access
|
||||
with mock.patch("__builtin__.raw_input", return_value="1"):
|
||||
with mock.patch("six.moves.input", return_value="1"):
|
||||
self.assertEqual(
|
||||
self.displayer._get_valid_int_ans(1), (display_util.OK, 1))
|
||||
ans = "2"
|
||||
with mock.patch("__builtin__.raw_input", return_value=ans):
|
||||
with mock.patch("six.moves.input", return_value=ans):
|
||||
self.assertEqual(
|
||||
self.displayer._get_valid_int_ans(3),
|
||||
(display_util.OK, int(ans)))
|
||||
|
|
@ -292,7 +289,7 @@ class FileOutputDisplayTest(unittest.TestCase):
|
|||
["c"],
|
||||
]
|
||||
for ans in answers:
|
||||
with mock.patch("__builtin__.raw_input", side_effect=ans):
|
||||
with mock.patch("six.moves.input", side_effect=ans):
|
||||
self.assertEqual(
|
||||
self.displayer._get_valid_int_ans(3),
|
||||
(display_util.CANCEL, -1))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
"""Test certbot.reverter."""
|
||||
import csv
|
||||
import itertools
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
|
|
@ -8,6 +7,7 @@ import tempfile
|
|||
import unittest
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
from certbot import errors
|
||||
|
||||
|
|
@ -153,7 +153,7 @@ class ReverterCheckpointLocalTest(unittest.TestCase):
|
|||
|
||||
act_coms = get_undo_commands(self.config.temp_checkpoint_dir)
|
||||
|
||||
for a_com, com in itertools.izip(act_coms, coms):
|
||||
for a_com, com in six.moves.zip(act_coms, coms):
|
||||
self.assertEqual(a_com, com)
|
||||
|
||||
def test_bad_register_undo_command(self):
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import unittest
|
|||
import configobj
|
||||
import mock
|
||||
import pytz
|
||||
import six
|
||||
|
||||
import certbot
|
||||
from certbot import cli
|
||||
|
|
@ -92,8 +93,8 @@ class BaseRenewableCertTest(unittest.TestCase):
|
|||
os.symlink(os.path.join(os.path.pardir, os.path.pardir, "archive",
|
||||
"example.org", "{0}{1}.pem".format(kind, ver)),
|
||||
link)
|
||||
with open(link, "w") as f:
|
||||
f.write(kind if value is None else value)
|
||||
with open(link, "wb") as f:
|
||||
f.write(kind.encode('ascii') if value is None else value)
|
||||
|
||||
def _write_out_ex_kinds(self):
|
||||
for kind in ALL_FOUR:
|
||||
|
|
@ -235,7 +236,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
self.assertEqual(self.test_rc.current_version("cert"), None)
|
||||
|
||||
def test_latest_and_next_versions(self):
|
||||
for ver in xrange(1, 6):
|
||||
for ver in six.moves.range(1, 6):
|
||||
for kind in ALL_FOUR:
|
||||
self._write_out_kind(kind, ver)
|
||||
self.assertEqual(self.test_rc.latest_common_version(), 5)
|
||||
|
|
@ -258,7 +259,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
self.assertEqual(self.test_rc.next_free_version(), 18)
|
||||
|
||||
def test_update_link_to(self):
|
||||
for ver in xrange(1, 6):
|
||||
for ver in six.moves.range(1, 6):
|
||||
for kind in ALL_FOUR:
|
||||
self._write_out_kind(kind, ver)
|
||||
self.assertEqual(ver, self.test_rc.current_version(kind))
|
||||
|
|
@ -285,12 +286,12 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
os.path.basename(self.test_rc.version("cert", 8)))
|
||||
|
||||
def test_update_all_links_to_success(self):
|
||||
for ver in xrange(1, 6):
|
||||
for ver in six.moves.range(1, 6):
|
||||
for kind in ALL_FOUR:
|
||||
self._write_out_kind(kind, ver)
|
||||
self.assertEqual(ver, self.test_rc.current_version(kind))
|
||||
self.assertEqual(self.test_rc.latest_common_version(), 5)
|
||||
for ver in xrange(1, 6):
|
||||
for ver in six.moves.range(1, 6):
|
||||
self.test_rc.update_all_links_to(ver)
|
||||
for kind in ALL_FOUR:
|
||||
self.assertEqual(ver, self.test_rc.current_version(kind))
|
||||
|
|
@ -330,11 +331,11 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
self.assertEqual(self.test_rc.current_version(kind), 11)
|
||||
|
||||
def test_has_pending_deployment(self):
|
||||
for ver in xrange(1, 6):
|
||||
for ver in six.moves.range(1, 6):
|
||||
for kind in ALL_FOUR:
|
||||
self._write_out_kind(kind, ver)
|
||||
self.assertEqual(ver, self.test_rc.current_version(kind))
|
||||
for ver in xrange(1, 6):
|
||||
for ver in six.moves.range(1, 6):
|
||||
self.test_rc.update_all_links_to(ver)
|
||||
for kind in ALL_FOUR:
|
||||
self.assertEqual(ver, self.test_rc.current_version(kind))
|
||||
|
|
@ -373,10 +374,10 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
self._write_out_ex_kinds()
|
||||
|
||||
self.test_rc.update_all_links_to(12)
|
||||
with open(self.test_rc.cert, "w") as f:
|
||||
with open(self.test_rc.cert, "wb") as f:
|
||||
f.write(test_cert)
|
||||
self.test_rc.update_all_links_to(11)
|
||||
with open(self.test_rc.cert, "w") as f:
|
||||
with open(self.test_rc.cert, "wb") as f:
|
||||
f.write(test_cert)
|
||||
|
||||
mock_datetime.timedelta = datetime.timedelta
|
||||
|
|
@ -426,7 +427,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
self.assertFalse(self.test_rc.should_autodeploy())
|
||||
self.test_rc.configuration["autodeploy"] = "1"
|
||||
# No pending deployment
|
||||
for ver in xrange(1, 6):
|
||||
for ver in six.moves.range(1, 6):
|
||||
for kind in ALL_FOUR:
|
||||
self._write_out_kind(kind, ver)
|
||||
self.assertFalse(self.test_rc.should_autodeploy())
|
||||
|
|
@ -461,7 +462,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
# (to avoid instantiating parser)
|
||||
mock_rv.side_effect = lambda x: x
|
||||
|
||||
for ver in xrange(1, 6):
|
||||
for ver in six.moves.range(1, 6):
|
||||
for kind in ALL_FOUR:
|
||||
self._write_out_kind(kind, ver)
|
||||
self.test_rc.update_all_links_to(3)
|
||||
|
|
@ -492,7 +493,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
self.test_rc.version("privkey", i))))
|
||||
|
||||
for kind in ALL_FOUR:
|
||||
self.assertEqual(self.test_rc.available_versions(kind), range(1, 9))
|
||||
self.assertEqual(self.test_rc.available_versions(kind), list(six.moves.range(1, 9)))
|
||||
self.assertEqual(self.test_rc.current_version(kind), 3)
|
||||
# Test updating from latest version rather than old version
|
||||
self.test_rc.update_all_links_to(8)
|
||||
|
|
@ -501,7 +502,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
"attempt", self.cli_config))
|
||||
for kind in ALL_FOUR:
|
||||
self.assertEqual(self.test_rc.available_versions(kind),
|
||||
range(1, 10))
|
||||
list(six.moves.range(1, 10)))
|
||||
self.assertEqual(self.test_rc.current_version(kind), 8)
|
||||
with open(self.test_rc.version("fullchain", 9)) as f:
|
||||
self.assertEqual(f.read(), "last" + "attempt")
|
||||
|
|
|
|||
|
|
@ -189,6 +189,12 @@ class UniqueFileTest(unittest.TestCase):
|
|||
self.assertTrue(basename3.endswith("foo.txt"))
|
||||
|
||||
|
||||
try:
|
||||
file_type = file
|
||||
except NameError:
|
||||
import io
|
||||
file_type = io.TextIOWrapper
|
||||
|
||||
class UniqueLineageNameTest(unittest.TestCase):
|
||||
"""Tests for certbot.util.unique_lineage_name."""
|
||||
|
||||
|
|
@ -204,13 +210,13 @@ class UniqueLineageNameTest(unittest.TestCase):
|
|||
|
||||
def test_basic(self):
|
||||
f, path = self._call("wow")
|
||||
self.assertTrue(isinstance(f, file))
|
||||
self.assertTrue(isinstance(f, file_type))
|
||||
self.assertEqual(os.path.join(self.root_path, "wow.conf"), path)
|
||||
|
||||
def test_multiple(self):
|
||||
for _ in xrange(10):
|
||||
for _ in six.moves.range(10):
|
||||
f, name = self._call("wow")
|
||||
self.assertTrue(isinstance(f, file))
|
||||
self.assertTrue(isinstance(f, file_type))
|
||||
self.assertTrue(isinstance(name, str))
|
||||
self.assertTrue("wow-0009.conf" in name)
|
||||
|
||||
|
|
|
|||
|
|
@ -402,18 +402,27 @@ def enforce_domain_sanity(domain):
|
|||
:returns: The domain cast to `str`, with ASCII-only contents
|
||||
:rtype: str
|
||||
"""
|
||||
if isinstance(domain, six.text_type):
|
||||
wildcard_marker = u"*."
|
||||
punycode_marker = u"xn--"
|
||||
else:
|
||||
wildcard_marker = b"*."
|
||||
punycode_marker = b"xn--"
|
||||
|
||||
# Check if there's a wildcard domain
|
||||
if domain.startswith("*."):
|
||||
if domain.startswith(wildcard_marker):
|
||||
raise errors.ConfigurationError(
|
||||
"Wildcard domains are not supported: {0}".format(domain))
|
||||
# Punycode
|
||||
if "xn--" in domain:
|
||||
if punycode_marker in domain:
|
||||
raise errors.ConfigurationError(
|
||||
"Punycode domains are not presently supported: {0}".format(domain))
|
||||
|
||||
# Unicode
|
||||
try:
|
||||
domain = domain.encode('ascii').lower()
|
||||
if isinstance(domain, six.binary_type):
|
||||
domain = domain.decode('utf-8')
|
||||
domain.encode('ascii')
|
||||
except UnicodeError:
|
||||
error_fmt = (u"Internationalized domain names "
|
||||
"are not presently supported: {0}")
|
||||
|
|
@ -422,11 +431,10 @@ def enforce_domain_sanity(domain):
|
|||
else:
|
||||
raise errors.ConfigurationError(str(error_fmt).format(domain))
|
||||
|
||||
if six.PY3:
|
||||
domain = domain.decode('ascii')
|
||||
domain = domain.lower()
|
||||
|
||||
# Remove trailing dot
|
||||
domain = domain[:-1] if domain.endswith('.') else domain
|
||||
domain = domain[:-1] if domain.endswith(u'.') else domain
|
||||
|
||||
# Explain separately that IP addresses aren't allowed (apart from not
|
||||
# being FQDNs) because hope springs eternal concerning this point
|
||||
|
|
|
|||
410
docs/using.rst
410
docs/using.rst
|
|
@ -5,6 +5,7 @@ User Guide
|
|||
.. contents:: Table of Contents
|
||||
:local:
|
||||
|
||||
.. _installation:
|
||||
|
||||
System Requirements
|
||||
===================
|
||||
|
|
@ -20,21 +21,15 @@ but for most users who want to avoid running an ACME client as root, either
|
|||
`letsencrypt-nosudo <https://github.com/diafygi/letsencrypt-nosudo>`_ or
|
||||
`simp_le <https://github.com/kuba/simp_le>`_ are more appropriate choices.
|
||||
|
||||
The Apache plugin currently requires a Debian-based OS with augeas version
|
||||
1.0; this includes Ubuntu 12.04+ and Debian 7+.
|
||||
The Apache plugin currently requires OS with augeas version 1.0; currently `it
|
||||
supports
|
||||
<https://github.com/certbot/certbot/blob/master/certbot-apache/certbot_apache/constants.py>`_
|
||||
modern OSes based on Debian, Fedora, SUSE, Gentoo and Darwin.
|
||||
|
||||
|
||||
Getting Certbot
|
||||
===============
|
||||
|
||||
To get specific instructions for installing Certbot on your OS,
|
||||
visit certbot.eff.org_. This is the easiest way to learn how to get
|
||||
Certbot up and running on your system.
|
||||
|
||||
If you're offline, you can find some general
|
||||
instructions under `Quick Installation <install.html>`__.
|
||||
|
||||
__ installation_
|
||||
.. _certbot.eff.org: https://certbot.eff.org
|
||||
|
||||
.. _certbot-auto: https://certbot.eff.org/docs/using.html#certbot-auto
|
||||
|
|
@ -47,9 +42,208 @@ to, equivalently, as "subcommands") to request specific actions such as
|
|||
obtaining, renewing, or revoking certificates. Some of the most important
|
||||
and most commonly-used commands will be discussed throughout this
|
||||
document; an exhaustive list also appears near the end of the document.
|
||||
|
||||
Plugins
|
||||
=======
|
||||
Certbot is packaged for many common operating systems and web servers. Check whether
|
||||
``certbot`` (or ``letsencrypt``) is packaged for your web server's OS by visiting
|
||||
certbot.eff.org_, where you will also find the correct installation instructions for
|
||||
your system.
|
||||
|
||||
.. Note:: Unless you have very specific requirements, we kindly suggest that you use the Certbot packages provided by your package manager (see certbot.eff.org_). If such packages are not available, we recommend using ``certbot-auto``, which automates the process of installing Certbot on your system.
|
||||
|
||||
The ``certbot`` script on your web server might be named ``letsencrypt`` if your system uses an older package, or ``certbot-auto`` if you used an alternate installation method. Throughout the docs, whenever you see ``certbot``, swap in the correct name as needed.
|
||||
|
||||
|
||||
Other installation methods
|
||||
--------------------------
|
||||
If you are offline or your operating system doesn't provide a package, you can use
|
||||
an alternate method fo install ``certbot``.
|
||||
|
||||
Certbot-Auto
|
||||
^^^^^^^^^^^^
|
||||
The ``certbot-auto`` wrapper script installs Certbot, obtaining some dependencies
|
||||
from your web server OS and putting others in a python virtual environment. You can
|
||||
download and run it as follows::
|
||||
|
||||
user@webserver:~$ wget https://dl.eff.org/certbot-auto
|
||||
user@webserver:~$ chmod a+x ./certbot-auto
|
||||
user@webserver:~$ ./certbot-auto --help
|
||||
|
||||
.. hint:: The certbot-auto download is protected by HTTPS, which is pretty good, but if you'd like to
|
||||
double check the integrity of the ``certbot-auto`` script, you can use these steps for verification before running it::
|
||||
|
||||
user@server:~$ wget -N https://dl.eff.org/certbot-auto.asc
|
||||
user@server:~$ gpg2 --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2
|
||||
user@server:~$ gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.asc certbot-auto
|
||||
|
||||
The ``certbot-auto`` command updates to the latest client release automatically.
|
||||
Since ``certbot-auto`` is a wrapper to ``certbot``, it accepts exactly
|
||||
the same command line flags and arguments. For more information, see
|
||||
`Certbot command-line options <https://certbot.eff.org/docs/using.html#command-line-options>`_.
|
||||
|
||||
Running with Docker
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Docker_ is an amazingly simple and quick way to obtain a
|
||||
certificate. However, this mode of operation is unable to install
|
||||
certificates or configure your webserver, because our installer
|
||||
plugins cannot reach your webserver from inside the Docker container.
|
||||
|
||||
Most users should use the operating system packages (see instructions at
|
||||
certbot.eff.org_) or, as a fallback, ``certbot-auto``. You should only
|
||||
use Docker if you are sure you know what you are doing and have a
|
||||
good reason to do so.
|
||||
|
||||
You should definitely read the :ref:`where-certs` section, in order to
|
||||
know how to manage the certs
|
||||
manually. `Our ciphersuites page <ciphers.html>`__
|
||||
provides some information about recommended ciphersuites. If none of
|
||||
these make much sense to you, you should definitely use the
|
||||
certbot-auto_ method, which enables you to use installer plugins
|
||||
that cover both of those hard topics.
|
||||
|
||||
If you're still not convinced and have decided to use this method,
|
||||
from the server that the domain you're requesting a cert for resolves
|
||||
to, `install Docker`_, then issue the following command:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo docker run -it --rm -p 443:443 -p 80:80 --name certbot \
|
||||
-v "/etc/letsencrypt:/etc/letsencrypt" \
|
||||
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
|
||||
quay.io/letsencrypt/letsencrypt:latest certonly
|
||||
|
||||
Running Certbot with the ``certonly`` command will obtain a certificate and place it in the directory
|
||||
``/etc/letsencrypt/live`` on your system. Because Certonly cannot install the certificate from
|
||||
within Docker, you must install the certificate manually according to the procedure
|
||||
recommended by the provider of your webserver.
|
||||
|
||||
For more information about the layout
|
||||
of the ``/etc/letsencrypt`` directory, see :ref:`where-certs`.
|
||||
|
||||
.. _Docker: https://docker.com
|
||||
.. _`install Docker`: https://docs.docker.com/userguide/
|
||||
|
||||
|
||||
Operating System Packages
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**FreeBSD**
|
||||
|
||||
* Port: ``cd /usr/ports/security/py-certbot && make install clean``
|
||||
* Package: ``pkg install py27-certbot``
|
||||
|
||||
**OpenBSD**
|
||||
|
||||
* Port: ``cd /usr/ports/security/letsencrypt/client && make install clean``
|
||||
* Package: ``pkg_add letsencrypt``
|
||||
|
||||
**Arch Linux**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo pacman -S certbot
|
||||
|
||||
**Debian**
|
||||
|
||||
If you run Debian Stretch or Debian Sid, you can install certbot packages.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install certbot python-certbot-apache
|
||||
|
||||
If you don't want to use the Apache plugin, you can omit the
|
||||
``python-certbot-apache`` package.
|
||||
|
||||
Packages exist for Debian Jessie via backports. First you'll have to follow the
|
||||
instructions at http://backports.debian.org/Instructions/ to enable the Jessie backports
|
||||
repo, if you have not already done so. Then run:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get install letsencrypt python-letsencrypt-apache -t jessie-backports
|
||||
|
||||
**Fedora**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo dnf install letsencrypt
|
||||
|
||||
**Gentoo**
|
||||
|
||||
The official Certbot client is available in Gentoo Portage. If you
|
||||
want to use the Apache plugin, it has to be installed separately:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
emerge -av app-crypt/letsencrypt
|
||||
emerge -av app-crypt/letsencrypt-apache
|
||||
|
||||
Currently, only the Apache plugin is included in Portage. However, if you
|
||||
Warning!
|
||||
You can use Layman to add the mrueg overlay which does include a package for the
|
||||
Certbot Nginx plugin, however, this plugin is known to be buggy and should only
|
||||
be used with caution after creating a backup up your Nginx configuration.
|
||||
We strongly recommend you use the app-crypt/letsencrypt package instead until
|
||||
the Nginx plugin is ready.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
emerge -av app-portage/layman
|
||||
layman -S
|
||||
layman -a mrueg
|
||||
emerge -av app-crypt/letsencrypt-nginx
|
||||
|
||||
When using the Apache plugin, you will run into a "cannot find a cert or key
|
||||
directive" error if you're sporting the default Gentoo ``httpd.conf``.
|
||||
You can fix this by commenting out two lines in ``/etc/apache2/httpd.conf``
|
||||
as follows:
|
||||
|
||||
Change
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
<IfDefine SSL>
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
</IfDefine>
|
||||
|
||||
to
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
#<IfDefine SSL>
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
#</IfDefine>
|
||||
|
||||
For the time being, this is the only way for the Apache plugin to recognise
|
||||
the appropriate directives when installing the certificate.
|
||||
Note: this change is not required for the other plugins.
|
||||
|
||||
**Other Operating Systems**
|
||||
|
||||
OS packaging is an ongoing effort. If you'd like to package
|
||||
Certbot for your distribution of choice please have a
|
||||
look at the :doc:`packaging`.
|
||||
|
||||
|
||||
Installing from source
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Installation from source is only supported for developers and the
|
||||
whole process is described in the :doc:`contributing`.
|
||||
|
||||
.. warning:: Please do **not** use ``python setup.py install`` or
|
||||
``python pip install .``. Please do **not** attempt the
|
||||
installation commands as superuser/root and/or without virtual
|
||||
environment, e.g. ``sudo python setup.py install``, ``sudo pip
|
||||
install``, ``sudo ./venv/bin/...``. These modes of operation might
|
||||
corrupt your operating system and are **not supported** by the
|
||||
Certbot team!
|
||||
|
||||
.. _plugins:
|
||||
|
||||
Getting certificates
|
||||
====================
|
||||
|
||||
The Certbot client supports a number of different "plugins" that can be
|
||||
used to obtain and/or install certificates.
|
||||
|
|
@ -86,7 +280,7 @@ manual_ Y N Helps you obtain a cert by giving you instructions to perf
|
|||
nginx_ Y Y Very experimental and not included in certbot-auto_.
|
||||
=========== ==== ==== ===============================================================
|
||||
|
||||
There are many third-party-plugins_ available. Below we describe in more detail
|
||||
There are also many third-party-plugins_ available. Below we describe in more detail
|
||||
the circumstances in which each plugin can be used, and how to use it.
|
||||
|
||||
Apache
|
||||
|
|
@ -265,8 +459,10 @@ the Let's Encrypt CA's rate limit policies treat the issuance of a new
|
|||
certificate under these circumstances more generously. More details about
|
||||
the use of ``certbot renew`` are provided below.
|
||||
|
||||
Renewal
|
||||
=======
|
||||
.. _renewal:
|
||||
|
||||
Renewing certificates
|
||||
=====================
|
||||
|
||||
.. note:: Let's Encrypt CA issues short-lived certificates (90
|
||||
days). Make sure you renew the certificates at least once in 3
|
||||
|
|
@ -346,8 +542,8 @@ commands into your individual environment.
|
|||
|
||||
.. _command-line:
|
||||
|
||||
Command line options
|
||||
====================
|
||||
Certbot command-line options
|
||||
============================
|
||||
|
||||
Certbot supports a lot of command line options. Here's the full list, from
|
||||
``certbot --help all``:
|
||||
|
|
@ -466,184 +662,4 @@ give us as much information as possible:
|
|||
- your operating system, including specific version
|
||||
- specify which installation method you've chosen
|
||||
|
||||
Other methods of installation
|
||||
=============================
|
||||
|
||||
Running with Docker
|
||||
-------------------
|
||||
|
||||
Docker_ is an amazingly simple and quick way to obtain a
|
||||
certificate. However, this mode of operation is unable to install
|
||||
certificates or configure your webserver, because our installer
|
||||
plugins cannot reach your webserver from inside the Docker container.
|
||||
|
||||
Most users should use the operating system packages (see instructions at
|
||||
certbot.eff.org_) or, as a fallback, ``certbot-auto``. You should only
|
||||
use Docker if you are sure you know what you are doing and have a
|
||||
good reason to do so.
|
||||
|
||||
You should definitely read the :ref:`where-certs` section, in order to
|
||||
know how to manage the certs
|
||||
manually. `Our ciphersuites page <ciphers.html>`__
|
||||
provides some information about recommended ciphersuites. If none of
|
||||
these make much sense to you, you should definitely use the
|
||||
certbot-auto_ method, which enables you to use installer plugins
|
||||
that cover both of those hard topics.
|
||||
|
||||
If you're still not convinced and have decided to use this method,
|
||||
from the server that the domain you're requesting a cert for resolves
|
||||
to, `install Docker`_, then issue the following command:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo docker run -it --rm -p 443:443 -p 80:80 --name certbot \
|
||||
-v "/etc/letsencrypt:/etc/letsencrypt" \
|
||||
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
|
||||
quay.io/letsencrypt/letsencrypt:latest certonly
|
||||
|
||||
Running Certbot with the ``certonly`` command will obtain a certificate and place it in the directory
|
||||
``/etc/letsencrypt/live`` on your system. Because Certonly cannot install the certificate from
|
||||
within Docker, you must install the certificate manually according to the procedure
|
||||
recommended by the provider of your webserver.
|
||||
|
||||
For more information about the layout
|
||||
of the ``/etc/letsencrypt`` directory, see :ref:`where-certs`.
|
||||
|
||||
.. _Docker: https://docker.com
|
||||
.. _`install Docker`: https://docs.docker.com/userguide/
|
||||
|
||||
|
||||
Operating System Packages
|
||||
--------------------------
|
||||
|
||||
**FreeBSD**
|
||||
|
||||
* Port: ``cd /usr/ports/security/py-certbot && make install clean``
|
||||
* Package: ``pkg install py27-certbot``
|
||||
|
||||
**OpenBSD**
|
||||
|
||||
* Port: ``cd /usr/ports/security/letsencrypt/client && make install clean``
|
||||
* Package: ``pkg_add letsencrypt``
|
||||
|
||||
**Arch Linux**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo pacman -S certbot
|
||||
|
||||
**Debian**
|
||||
|
||||
If you run Debian Stretch or Debian Sid, you can install certbot packages.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install certbot python-certbot-apache
|
||||
|
||||
If you don't want to use the Apache plugin, you can omit the
|
||||
``python-certbot-apache`` package.
|
||||
|
||||
Packages exist for Debian Jessie via backports. First you'll have to follow the
|
||||
instructions at http://backports.debian.org/Instructions/ to enable the Jessie backports
|
||||
repo, if you have not already done so. Then run:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get install letsencrypt python-letsencrypt-apache -t jessie-backports
|
||||
|
||||
**Fedora**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo dnf install letsencrypt
|
||||
|
||||
**Gentoo**
|
||||
|
||||
The official Certbot client is available in Gentoo Portage. If you
|
||||
want to use the Apache plugin, it has to be installed separately:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
emerge -av app-crypt/letsencrypt
|
||||
emerge -av app-crypt/letsencrypt-apache
|
||||
|
||||
Currently, only the Apache plugin is included in Portage. However, if you
|
||||
Warning!
|
||||
You can use Layman to add the mrueg overlay which does include a package for the
|
||||
Certbot Nginx plugin, however, this plugin is known to be buggy and should only
|
||||
be used with caution after creating a backup up your Nginx configuration.
|
||||
We strongly recommend you use the app-crypt/letsencrypt package instead until
|
||||
the Nginx plugin is ready.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
emerge -av app-portage/layman
|
||||
layman -S
|
||||
layman -a mrueg
|
||||
emerge -av app-crypt/letsencrypt-nginx
|
||||
|
||||
When using the Apache plugin, you will run into a "cannot find a cert or key
|
||||
directive" error if you're sporting the default Gentoo ``httpd.conf``.
|
||||
You can fix this by commenting out two lines in ``/etc/apache2/httpd.conf``
|
||||
as follows:
|
||||
|
||||
Change
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
<IfDefine SSL>
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
</IfDefine>
|
||||
|
||||
to
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
#<IfDefine SSL>
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
#</IfDefine>
|
||||
|
||||
For the time being, this is the only way for the Apache plugin to recognise
|
||||
the appropriate directives when installing the certificate.
|
||||
Note: this change is not required for the other plugins.
|
||||
|
||||
**Other Operating Systems**
|
||||
|
||||
OS packaging is an ongoing effort. If you'd like to package
|
||||
Certbot for your distribution of choice please have a
|
||||
look at the :doc:`packaging`.
|
||||
|
||||
|
||||
From source
|
||||
-----------
|
||||
|
||||
Installation from source is only supported for developers and the
|
||||
whole process is described in the :doc:`contributing`.
|
||||
|
||||
.. warning:: Please do **not** use ``python setup.py install`` or
|
||||
``python pip install .``. Please do **not** attempt the
|
||||
installation commands as superuser/root and/or without virtual
|
||||
environment, e.g. ``sudo python setup.py install``, ``sudo pip
|
||||
install``, ``sudo ./venv/bin/...``. These modes of operation might
|
||||
corrupt your operating system and are **not supported** by the
|
||||
Certbot team!
|
||||
|
||||
|
||||
Comparison of different methods
|
||||
-------------------------------
|
||||
|
||||
Unless you have very specific requirements, we kindly suggest that you use
|
||||
the Certbot packages provided by your package manager (see certbot.eff.org_).
|
||||
If such packages are not available, we recommend using ``certbot-auto``, which
|
||||
automates the process of installing Certbot on your system.
|
||||
|
||||
Beyond the methods discussed here, other methods may be possible, such as
|
||||
installing Certbot directly with pip from PyPI or downloading a ZIP
|
||||
archive from GitHub may be technically possible but are not presently
|
||||
recommended or supported.
|
||||
|
||||
.. include:: ../README.rst
|
||||
:start-after: tag:features-begin
|
||||
:end-before: tag:features-end
|
||||
.. include:: ../CHANGES.rst
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@ set -xe
|
|||
# Check out special branch until latest docker changes land in Boulder master.
|
||||
git clone -b docker-integration https://github.com/letsencrypt/boulder $BOULDERPATH
|
||||
cd $BOULDERPATH
|
||||
sed -i 's/FAKE_DNS: .*/FAKE_DNS: 172.17.42.1/' docker-compose.yml
|
||||
FAKE_DNS=$(ifconfig docker0 | grep "inet addr:" | cut -d: -f2 | awk '{ print $1}')
|
||||
sed -i "s/FAKE_DNS: .*/FAKE_DNS: $FAKE_DNS/" docker-compose.yml
|
||||
docker-compose up -d
|
||||
|
||||
|
|
|
|||
|
|
@ -5,5 +5,6 @@
|
|||
# Check out special branch until latest docker changes land in Boulder master.
|
||||
git clone -b docker-integration https://github.com/letsencrypt/boulder $BOULDERPATH
|
||||
cd $BOULDERPATH
|
||||
sed -i 's/FAKE_DNS: .*/FAKE_DNS: 172.17.42.1/' docker-compose.yml
|
||||
FAKE_DNS=$(ifconfig docker0 | grep "inet addr:" | cut -d: -f2 | awk '{ print $1}')
|
||||
sed -i "s/FAKE_DNS: .*/FAKE_DNS: $FAKE_DNS/" docker-compose.yml
|
||||
docker-compose up -d
|
||||
|
|
|
|||
29
tox.ini
29
tox.ini
|
|
@ -35,21 +35,28 @@ deps =
|
|||
py{26,27}-oldest: psutil==2.1.0
|
||||
py{26,27}-oldest: PyOpenSSL==0.13
|
||||
py{26,27}-oldest: python2-pythondialog==3.2.2rc1
|
||||
py{26,27}-oldest: dnspython>=1.12
|
||||
|
||||
[testenv:py33]
|
||||
commands =
|
||||
pip install -e acme[dns,dev]
|
||||
nosetests -v acme
|
||||
pip install -e .[dev]
|
||||
nosetests -v certbot
|
||||
|
||||
[testenv:py34]
|
||||
commands =
|
||||
pip install -e acme[dns,dev]
|
||||
nosetests -v acme
|
||||
pip install -e .[dev]
|
||||
nosetests -v certbot
|
||||
|
||||
[testenv:py35]
|
||||
commands =
|
||||
pip install -e acme[dns,dev]
|
||||
nosetests -v acme
|
||||
pip install -e .[dev]
|
||||
nosetests -v certbot
|
||||
|
||||
[testenv:cover]
|
||||
basepython = python2.7
|
||||
|
|
@ -79,6 +86,10 @@ commands =
|
|||
pip install -e acme -e .[dev] -e certbot-apache -e certbot-nginx -e certbot-compatibility-test -e letshelp-certbot
|
||||
{toxinidir}/certbot-apache/certbot_apache/tests/apache-conf-files/apache-conf-test --debian-modules
|
||||
|
||||
[testenv:nginxroundtrip]
|
||||
commands =
|
||||
pip install -e acme[dev] -e .[dev] -e certbot-nginx
|
||||
python certbot-compatibility-test/nginx/roundtrip.py certbot-compatibility-test/nginx/nginx-roundtrip-testdata
|
||||
|
||||
[testenv:le_auto]
|
||||
# At the moment, this tests under Python 2.7 only, as only that version is
|
||||
|
|
@ -89,3 +100,21 @@ commands =
|
|||
whitelist_externals =
|
||||
docker
|
||||
passenv = DOCKER_*
|
||||
|
||||
[testenv:apache_compat]
|
||||
commands =
|
||||
docker build -t certbot-compatibility-test -f certbot-compatibility-test/Dockerfile .
|
||||
docker build -t apache-compat -f certbot-compatibility-test/Dockerfile-apache .
|
||||
docker run --rm -it apache-compat -c apache.tar.gz -vvvv
|
||||
whitelist_externals =
|
||||
docker
|
||||
passenv = DOCKER_*
|
||||
|
||||
[testenv:nginx_compat]
|
||||
commands =
|
||||
docker build -t certbot-compatibility-test -f certbot-compatibility-test/Dockerfile .
|
||||
docker build -t nginx-compat -f certbot-compatibility-test/Dockerfile-nginx .
|
||||
docker run --rm -it nginx-compat -c nginx.tar.gz -vvvv
|
||||
whitelist_externals =
|
||||
docker
|
||||
passenv = DOCKER_*
|
||||
|
|
|
|||
Loading…
Reference in a new issue