mirror of
https://github.com/certbot/certbot.git
synced 2026-07-27 08:09:10 +02:00
Merge remote-tracking branch 'upstream/master' into multios_apache
This commit is contained in:
@@ -1 +0,0 @@
|
||||
letsencrypt/DISCLAIMER
|
||||
+1
-1
@@ -33,7 +33,7 @@ RUN /opt/letsencrypt/src/ubuntu.sh && \
|
||||
# Dockerfile we make sure we cache as much as possible
|
||||
|
||||
# py26reqs.txt not installed!
|
||||
COPY setup.py README.rst CHANGES.rst MANIFEST.in DISCLAIMER linter_plugin.py tox.cover.sh tox.ini pep8.travis.sh .pep8 .pylintrc /opt/letsencrypt/src/
|
||||
COPY setup.py README.rst CHANGES.rst MANIFEST.in linter_plugin.py tox.cover.sh tox.ini pep8.travis.sh .pep8 .pylintrc /opt/letsencrypt/src/
|
||||
|
||||
# all above files are necessary for setup.py, however, package source
|
||||
# code directory has to be copied separately to a subdirectory...
|
||||
|
||||
@@ -4,7 +4,6 @@ include CHANGES.rst
|
||||
include CONTRIBUTING.md
|
||||
include LICENSE.txt
|
||||
include linter_plugin.py
|
||||
include letsencrypt/DISCLAIMER
|
||||
recursive-include docs *
|
||||
recursive-include examples *
|
||||
recursive-include letsencrypt/tests/testdata *
|
||||
|
||||
+20
-2
@@ -27,7 +27,7 @@ If ``letsencrypt`` is packaged for your OS, you can install it from there, and
|
||||
run it by typing ``letsencrypt``. Because not all operating systems have
|
||||
packages yet, we provide a temporary solution via the ``letsencrypt-auto``
|
||||
wrapper script, which obtains some dependencies from your OS and puts others
|
||||
in an python virtual environment::
|
||||
in a python virtual environment::
|
||||
|
||||
user@webserver:~$ git clone https://github.com/letsencrypt/letsencrypt
|
||||
user@webserver:~$ cd letsencrypt
|
||||
@@ -118,6 +118,24 @@ email to client-dev+subscribe@letsencrypt.org)
|
||||
|
||||
.. _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 be added after the Public Beta
|
||||
launch. 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+.
|
||||
|
||||
|
||||
Current Features
|
||||
================
|
||||
@@ -145,5 +163,5 @@ Current Features
|
||||
* Free and Open Source Software, made with Python.
|
||||
|
||||
|
||||
.. _Freenode: https://freenode.net
|
||||
.. _Freenode: https://webchat.freenode.net?channels=%23letsencrypt
|
||||
.. _client-dev: https://groups.google.com/a/letsencrypt.org/forum/#!forum/client-dev
|
||||
|
||||
@@ -194,7 +194,7 @@ class JSONDeSerializable(object):
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
return self.json_dumps(sort_keys=True, indent=4)
|
||||
return self.json_dumps(sort_keys=True, indent=4, separators=(',', ': '))
|
||||
|
||||
@classmethod
|
||||
def json_dump_default(cls, python_object):
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
"""Tests for acme.jose.interfaces."""
|
||||
import unittest
|
||||
|
||||
import six
|
||||
|
||||
|
||||
class JSONDeSerializableTest(unittest.TestCase):
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
@@ -92,9 +90,8 @@ class JSONDeSerializableTest(unittest.TestCase):
|
||||
self.assertEqual('["foo1", "foo2"]', self.seq.json_dumps())
|
||||
|
||||
def test_json_dumps_pretty(self):
|
||||
filler = ' ' if six.PY2 else ''
|
||||
self.assertEqual(self.seq.json_dumps_pretty(),
|
||||
'[\n "foo1",{0}\n "foo2"\n]'.format(filler))
|
||||
'[\n "foo1",\n "foo2"\n]')
|
||||
|
||||
def test_json_dump_default(self):
|
||||
from acme.jose.interfaces import JSONDeSerializable
|
||||
|
||||
@@ -22,12 +22,14 @@ class Error(jose.JSONObjectWithFields, errors.Error):
|
||||
('urn:acme:error:' + name, description) for name, description in (
|
||||
('badCSR', 'The CSR is unacceptable (e.g., due to a short key)'),
|
||||
('badNonce', 'The client sent an unacceptable anti-replay nonce'),
|
||||
('connection', 'The server could not connect to the client for DV'),
|
||||
('connection', 'The server could not connect to the client to '
|
||||
'verify the domain'),
|
||||
('dnssec', 'The server could not validate a DNSSEC signed domain'),
|
||||
('malformed', 'The request message was malformed'),
|
||||
('rateLimited', 'There were too many requests of a given type'),
|
||||
('serverInternal', 'The server experienced an internal error'),
|
||||
('tls', 'The server experienced a TLS error during DV'),
|
||||
('tls', 'The server experienced a TLS error during domain '
|
||||
'verification'),
|
||||
('unauthorized', 'The client lacks sufficient authorization'),
|
||||
('unknownHost', 'The server could not resolve a domain name'),
|
||||
)
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.1.0.dev0'
|
||||
version = '0.2.0.dev0'
|
||||
|
||||
install_requires = [
|
||||
# load_pem_private/public_key (>=0.6)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Tested with:
|
||||
# - Fedora 22, 23 (x64)
|
||||
# - Centos 7 (x64: onD igitalOcean droplet)
|
||||
# - Centos 7 (x64: on DigitalOcean droplet)
|
||||
|
||||
if type dnf 2>/dev/null
|
||||
then
|
||||
|
||||
+150
-103
@@ -28,13 +28,8 @@ Firstly, please `install Git`_ and run the following commands:
|
||||
git clone https://github.com/letsencrypt/letsencrypt
|
||||
cd letsencrypt
|
||||
|
||||
.. warning:: Alternatively you could `download the ZIP archive`_ and
|
||||
extract the snapshot of our repository, but it's strongly
|
||||
recommended to use the above method instead.
|
||||
|
||||
.. _`install Git`: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git
|
||||
.. _`download the ZIP archive`:
|
||||
https://github.com/letsencrypt/letsencrypt/archive/master.zip
|
||||
|
||||
To install and run the client you just need to type:
|
||||
|
||||
@@ -61,107 +56,48 @@ or for full help, type:
|
||||
|
||||
./letsencrypt-auto --help all
|
||||
|
||||
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 it from inside the Docker container.
|
||||
|
||||
You should definitely read the :ref:`where-certs` section, in order to
|
||||
know how to manage the certs
|
||||
manually. https://github.com/letsencrypt/letsencrypt/wiki/Ciphersuite-guidance
|
||||
provides some information about recommended ciphersuites. If none of
|
||||
these make much sense to you, you should definitely use the
|
||||
letsencrypt-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 letsencrypt \
|
||||
-v "/etc/letsencrypt:/etc/letsencrypt" \
|
||||
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
|
||||
quay.io/letsencrypt/letsencrypt:latest auth
|
||||
|
||||
and follow the instructions (note that ``auth`` command is explicitly
|
||||
used - no installer plugins involved). Your new cert will be available
|
||||
in ``/etc/letsencrypt/live`` on the host.
|
||||
|
||||
.. _Docker: https://docker.com
|
||||
.. _`install Docker`: https://docs.docker.com/userguide/
|
||||
|
||||
|
||||
Operating System Packages
|
||||
--------------------------
|
||||
|
||||
**FreeBSD**
|
||||
|
||||
* Port: ``cd /usr/ports/security/py-letsencrypt && make install clean``
|
||||
* Package: ``pkg install py27-letsencrypt``
|
||||
|
||||
**Arch Linux**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo pacman -S letsencrypt letsencrypt-apache
|
||||
|
||||
**Other Operating Systems**
|
||||
|
||||
Unfortunately, this is an ongoing effort. If you'd like to package
|
||||
Let's Encrypt client 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
|
||||
Let's Encrypt team!
|
||||
|
||||
|
||||
Comparison of different methods
|
||||
-------------------------------
|
||||
|
||||
Unless you have a very specific requirements, we kindly ask you to use
|
||||
the letsencrypt-auto_ method. It's the fastest, the most thoroughly
|
||||
tested and the most reliable way of getting our software and the free
|
||||
SSL certificates!
|
||||
``letsencrypt-auto`` is the recommended method of running the Let's Encrypt
|
||||
client beta releases on systems that don't have a packaged version. Debian
|
||||
experimental, Arch linux and FreeBSD now have native packages, so on those
|
||||
systems you can just install ``letsencrypt`` (and perhaps
|
||||
``letsencrypt-apache``). If you'd like to run the latest copy from Git, or
|
||||
run your own locally modified copy of the client, follow the instructions in
|
||||
the :doc:`contributing`. Some `other methods of installation`_ are discussed
|
||||
below.
|
||||
|
||||
|
||||
Plugins
|
||||
=======
|
||||
|
||||
=========== = = ===============================================================
|
||||
Plugin A I Notes
|
||||
=========== = = ===============================================================
|
||||
apache_ Y Y Automates obtaining and installing a cert with Apache 2.4 on
|
||||
Debian-based distributions with ``libaugeas0`` 1.0+.
|
||||
standalone_ Y N Uses a "standalone" webserver to obtain a cert.
|
||||
webroot_ Y N Obtains a cert using an already running webserver.
|
||||
manual_ Y N Helps you obtain a cert by giving you instructions to perform
|
||||
domain validation yourself.
|
||||
nginx_ Y Y Very experimental and not included in letsencrypt-auto_.
|
||||
=========== = = ===============================================================
|
||||
The Let's Encrypt client supports a number of different "plugins" that can be
|
||||
used to obtain and/or install certificates. Plugins that can obtain a cert
|
||||
are called "authenticators" and can be used with the "certonly" command.
|
||||
Plugins that can install a cert are called "installers". Plugins that do both
|
||||
can be used with the "letsencrypt run" command, which is the default.
|
||||
|
||||
=========== ==== ==== ===============================================================
|
||||
Plugin Auth Inst Notes
|
||||
=========== ==== ==== ===============================================================
|
||||
apache_ Y Y Automates obtaining and installing a cert with Apache 2.4 on
|
||||
Debian-based distributions with ``libaugeas0`` 1.0+.
|
||||
standalone_ Y N Uses a "standalone" webserver to obtain a cert.
|
||||
webroot_ Y N Obtains a cert by writing to the webroot directory of an
|
||||
already running webserver.
|
||||
manual_ Y N Helps you obtain a cert by giving you instructions to perform
|
||||
domain validation yourself.
|
||||
nginx_ Y Y Very experimental and not included in letsencrypt-auto_.
|
||||
=========== ==== ==== ===============================================================
|
||||
|
||||
Future plugins for IMAP servers, SMTP servers, IRC servers, etc, are likely to
|
||||
be installers but not authenticators.
|
||||
|
||||
Apache
|
||||
------
|
||||
|
||||
If you're running Apache 2.4 on a Debian-based OS with version 1.0+ of
|
||||
the ``libaugeas0`` package available, you can use the Apache plugin.
|
||||
This automates both obtaining and installing certs on an Apache
|
||||
This automates both obtaining *and* installing certs on an Apache
|
||||
webserver. To specify this plugin on the command line, simply include
|
||||
``--apache``.
|
||||
|
||||
@@ -184,13 +120,22 @@ Webroot
|
||||
If you're running a webserver that you don't want to stop to use
|
||||
standalone, you can use the webroot plugin to obtain a cert by
|
||||
including ``certonly`` and ``--webroot`` on the command line. In
|
||||
addition, you'll need to specify ``--webroot-path`` with the root
|
||||
addition, you'll need to specify ``--webroot-path`` or ``-w`` with the root
|
||||
directory of the files served by your webserver. For example,
|
||||
``--webroot-path /var/www/html`` or
|
||||
``--webroot-path /usr/share/nginx/html`` are two common webroot paths.
|
||||
If multiple domains are specified, they must all use the same path.
|
||||
Additionally, your server must be configured to serve files from
|
||||
hidden directories.
|
||||
|
||||
If you're getting a certificate for many domains at once, each domain will use
|
||||
the most recent ``--webroot-path``. So for instance:
|
||||
|
||||
``letsencrypt certonly --webroot -w /var/www/example/ -d www.example.com -d example.com -w /var/www/eg -d eg.is -d www.eg.is``
|
||||
|
||||
Would obtain a single certificate for all of those names, using the
|
||||
``/var/www/example`` webroot directory for the first two, and
|
||||
``/var/www/eg`` for the second two.
|
||||
|
||||
Note that to use the webroot plugin, your server must be configured to serve
|
||||
files from hidden directories.
|
||||
|
||||
Manual
|
||||
------
|
||||
@@ -228,10 +173,11 @@ Renewal
|
||||
In order to renew certificates simply call the ``letsencrypt`` (or
|
||||
letsencrypt-auto_) again, and use the same values when prompted. You
|
||||
can automate it slightly by passing necessary flags on the CLI (see
|
||||
`--help all`), or even further using the :ref:`config-file`. If you're
|
||||
sure that UI doesn't prompt for any details you can add the command to
|
||||
``crontab`` (make it less than every 90 days to avoid problems, say
|
||||
every month).
|
||||
`--help all`), or even further using the :ref:`config-file`. The
|
||||
``--renew-by-default`` flag may be helpful for automating renewal. If
|
||||
you're sure that UI doesn't prompt for any details you can add the
|
||||
command to ``crontab`` (make it less than every 90 days to avoid
|
||||
problems, say every month).
|
||||
|
||||
Please note that the CA will send notification emails to the address
|
||||
you provide if you do not renew certificates that are about to expire.
|
||||
@@ -341,7 +287,7 @@ get support on our `forums <https://community.letsencrypt.org>`_.
|
||||
If you find a bug in the software, please do report it in our `issue
|
||||
tracker
|
||||
<https://github.com/letsencrypt/letsencrypt/issues>`_. Remember to
|
||||
give us us as much information as possible:
|
||||
give us as much information as possible:
|
||||
|
||||
- copy and paste exact command line used and the output (though mind
|
||||
that the latter might include some personally identifiable
|
||||
@@ -352,6 +298,107 @@ give us 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 it from inside the Docker container.
|
||||
|
||||
You should definitely read the :ref:`where-certs` section, in order to
|
||||
know how to manage the certs
|
||||
manually. https://github.com/letsencrypt/letsencrypt/wiki/Ciphersuite-guidance
|
||||
provides some information about recommended ciphersuites. If none of
|
||||
these make much sense to you, you should definitely use the
|
||||
letsencrypt-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 letsencrypt \
|
||||
-v "/etc/letsencrypt:/etc/letsencrypt" \
|
||||
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
|
||||
quay.io/letsencrypt/letsencrypt:latest auth
|
||||
|
||||
and follow the instructions (note that ``auth`` command is explicitly
|
||||
used - no installer plugins involved). Your new cert will be available
|
||||
in ``/etc/letsencrypt/live`` on the host.
|
||||
|
||||
.. _Docker: https://docker.com
|
||||
.. _`install Docker`: https://docs.docker.com/userguide/
|
||||
|
||||
|
||||
Operating System Packages
|
||||
--------------------------
|
||||
|
||||
**FreeBSD**
|
||||
|
||||
* Port: ``cd /usr/ports/security/py-letsencrypt && make install clean``
|
||||
* Package: ``pkg install py27-letsencrypt``
|
||||
|
||||
**Arch Linux**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo pacman -S letsencrypt letsencrypt-apache
|
||||
|
||||
**Debian Experimental**
|
||||
|
||||
If you run Debian unstable, you can install experimental letsencrypt packages.
|
||||
Add the line ``deb http://ftp.us.debian.org/debian/ experimental main`` (or
|
||||
the equivalent for your country) to ``/etc/apt/sources.list``, then run
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get -t experimental install letsencrypt python-letsencrypt-apache
|
||||
|
||||
If you don't want to use the Apache plugin, you can ommit the
|
||||
``python-letsencrypt-apache`` package.
|
||||
|
||||
**Other Operating Systems**
|
||||
|
||||
OS packaging is an ongoing effort. If you'd like to package
|
||||
Let's Encrypt client 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
|
||||
Let's Encrypt team!
|
||||
|
||||
|
||||
Comparison of different methods
|
||||
-------------------------------
|
||||
|
||||
Unless you have a very specific requirements, we kindly ask you to use
|
||||
the letsencrypt-auto_ method. It's the fastest, the most thoroughly
|
||||
tested and the most reliable way of getting our software and the free
|
||||
SSL certificates!
|
||||
|
||||
Beyond the methods discussed here, other methods may be possible, such as
|
||||
installing Let's Encrypt directly with pip from PyPI or downloading a ZIP
|
||||
archive from GitHub may be technically possible but are not presently
|
||||
recommended or supported.
|
||||
|
||||
|
||||
.. rubric:: Footnotes
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ server = https://acme-staging.api.letsencrypt.org/directory
|
||||
# Uncomment and update to register with the specified e-mail address
|
||||
# email = foo@example.com
|
||||
|
||||
# Uncomment and update to generate certificates for the specified
|
||||
# domains.
|
||||
# domains = example.com, www.example.com
|
||||
|
||||
# Uncomment to use a text interface instead of ncurses
|
||||
# text = True
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ email = foo@example.com
|
||||
domains = example.com
|
||||
|
||||
text = True
|
||||
agree-dev-preview = True
|
||||
agree-tos = True
|
||||
debug = True
|
||||
# Unfortunately, it's not possible to specify "verbose" multiple times
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Let's Encrypt includes the very latest Augeas lenses in order to ship bug fixes
|
||||
to Apacche configuration handling bugs as quickly as possible
|
||||
to Apache configuration handling bugs as quickly as possible
|
||||
|
||||
@@ -59,8 +59,10 @@ let empty = Util.empty_dos
|
||||
let indent = Util.indent
|
||||
|
||||
(* borrowed from shellvars.aug *)
|
||||
let char_arg_dir = /([^\\ '"\t\r\n]|[^\\ '"\t\r\n][^ '"\t\r\n]*[^\\ '"\t\r\n])|\\\\"|\\\\'/
|
||||
let char_arg_dir = /([^\\ '"{\t\r\n]|[^ '"{\t\r\n]+[^\\ '"\t\r\n])|\\\\"|\\\\'/
|
||||
let char_arg_sec = /[^ '"\t\r\n>]|\\\\"|\\\\'/
|
||||
let char_arg_wl = /([^\\ '"},\t\r\n]|[^ '"},\t\r\n]+[^\\ '"},\t\r\n])/
|
||||
|
||||
let cdot = /\\\\./
|
||||
let cl = /\\\\\n/
|
||||
let dquot =
|
||||
@@ -77,11 +79,19 @@ let comp = /[<>=]?=/
|
||||
|
||||
let arg_dir = [ label "arg" . store (char_arg_dir+|dquot|squot) ]
|
||||
let arg_sec = [ label "arg" . store (char_arg_sec+|comp|dquot|squot) ]
|
||||
let arg_wl = [ label "arg" . store (char_arg_wl+|dquot|squot) ]
|
||||
|
||||
(* comma-separated wordlist as permitted in the SSLRequire directive *)
|
||||
let arg_wordlist =
|
||||
let wl_start = Util.del_str "{" in
|
||||
let wl_end = Util.del_str "}" in
|
||||
let wl_sep = del /[ \t]*,[ \t]*/ ", "
|
||||
in [ label "wordlist" . wl_start . arg_wl . (wl_sep . arg_wl)* . wl_end ]
|
||||
|
||||
let argv (l:lens) = l . (sep_spc . l)*
|
||||
|
||||
let directive = [ indent . label "directive" . store word .
|
||||
(sep_spc . argv arg_dir)? . eol ]
|
||||
(sep_spc . argv (arg_dir|arg_wordlist))? . eol ]
|
||||
|
||||
let section (body:lens) =
|
||||
(* opt_eol includes empty lines *)
|
||||
@@ -91,7 +101,7 @@ let section (body:lens) =
|
||||
indent . dels "</" in
|
||||
let kword = key word in
|
||||
let dword = del word "a" in
|
||||
[ indent . dels "<" . square kword inner dword . del ">" ">" . eol ]
|
||||
[ indent . dels "<" . square kword inner dword . del />[ \t\n\r]*/ ">\n" ]
|
||||
|
||||
let rec content = section (content|directive)
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
self.version = version
|
||||
self.vhosts = None
|
||||
self._enhance_func = {"redirect": self._enable_redirect,
|
||||
"ensure-http-header": self._set_http_header}
|
||||
"ensure-http-header": self._set_http_header}
|
||||
|
||||
@property
|
||||
def mod_ssl_conf(self):
|
||||
@@ -558,21 +558,43 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
|
||||
# Check for Listen <port>
|
||||
# Note: This could be made to also look for ip:443 combo
|
||||
if not self.parser.find_dir("Listen", port):
|
||||
logger.debug("No Listen %s directive found. Setting the "
|
||||
"Apache Server to Listen on port %s", port, port)
|
||||
|
||||
if port == "443":
|
||||
args = [port]
|
||||
listens = [self.parser.get_arg(x).split()[0] for x in self.parser.find_dir("Listen")]
|
||||
# In case no Listens are set (which really is a broken apache config)
|
||||
if not listens:
|
||||
listens = ["80"]
|
||||
for listen in listens:
|
||||
# For any listen statement, check if the machine also listens on Port 443.
|
||||
# If not, add such a listen statement.
|
||||
if len(listen.split(":")) == 1:
|
||||
# Its listening to all interfaces
|
||||
if port not in listens:
|
||||
if port == "443":
|
||||
args = [port]
|
||||
else:
|
||||
# Non-standard ports should specify https protocol
|
||||
args = [port, "https"]
|
||||
self.parser.add_dir_to_ifmodssl(
|
||||
parser.get_aug_path(
|
||||
self.parser.loc["listen"]), "Listen", args)
|
||||
self.save_notes += "Added Listen %s directive to %s\n" % (
|
||||
port, self.parser.loc["listen"])
|
||||
listens.append(port)
|
||||
else:
|
||||
# Non-standard ports should specify https protocol
|
||||
args = [port, "https"]
|
||||
|
||||
self.parser.add_dir_to_ifmodssl(
|
||||
parser.get_aug_path(
|
||||
self.parser.loc["listen"]), "Listen", args)
|
||||
self.save_notes += "Added Listen %s directive to %s\n" % (
|
||||
port, self.parser.loc["listen"])
|
||||
# The Listen statement specifies an ip
|
||||
_, ip = listen[::-1].split(":", 1)
|
||||
ip = ip[::-1]
|
||||
if "%s:%s" % (ip, port) not in listens:
|
||||
if port == "443":
|
||||
args = ["%s:%s" % (ip, port)]
|
||||
else:
|
||||
# Non-standard ports should specify https protocol
|
||||
args = ["%s:%s" % (ip, port), "https"]
|
||||
self.parser.add_dir_to_ifmodssl(
|
||||
parser.get_aug_path(
|
||||
self.parser.loc["listen"]), "Listen", args)
|
||||
self.save_notes += "Added Listen %s:%s directive to %s\n" % (
|
||||
ip, port, self.parser.loc["listen"])
|
||||
listens.append("%s:%s" % (ip, port))
|
||||
|
||||
def make_addrs_sni_ready(self, addrs):
|
||||
"""Checks to see if the server is ready for SNI challenges.
|
||||
|
||||
@@ -391,6 +391,39 @@ class TwoVhost80Test(util.ApacheTest):
|
||||
|
||||
self.assertEqual(mock_add_dir.call_count, 2)
|
||||
|
||||
def test_prepare_server_https_named_listen(self):
|
||||
mock_find = mock.Mock()
|
||||
mock_find.return_value = ["test1", "test2", "test3"]
|
||||
mock_get = mock.Mock()
|
||||
mock_get.side_effect = ["1.2.3.4:80", "[::1]:80", "1.1.1.1:443"]
|
||||
mock_add_dir = mock.Mock()
|
||||
mock_enable = mock.Mock()
|
||||
|
||||
self.config.parser.find_dir = mock_find
|
||||
self.config.parser.get_arg = mock_get
|
||||
self.config.parser.add_dir_to_ifmodssl = mock_add_dir
|
||||
self.config.enable_mod = mock_enable
|
||||
|
||||
# Test Listen statements with specific ip listeed
|
||||
self.config.prepare_server_https("443")
|
||||
# Should only be 2 here, as the third interface already listens to the correct port
|
||||
self.assertEqual(mock_add_dir.call_count, 2)
|
||||
|
||||
# Check argument to new Listen statements
|
||||
self.assertEqual(mock_add_dir.call_args_list[0][0][2], ["1.2.3.4:443"])
|
||||
self.assertEqual(mock_add_dir.call_args_list[1][0][2], ["[::1]:443"])
|
||||
|
||||
# Reset return lists and inputs
|
||||
mock_add_dir.reset_mock()
|
||||
mock_get.side_effect = ["1.2.3.4:80", "[::1]:80", "1.1.1.1:443"]
|
||||
|
||||
# Test
|
||||
self.config.prepare_server_https("8080", temp=True)
|
||||
self.assertEqual(mock_add_dir.call_count, 3)
|
||||
self.assertEqual(mock_add_dir.call_args_list[0][0][2], ["1.2.3.4:8080", "https"])
|
||||
self.assertEqual(mock_add_dir.call_args_list[1][0][2], ["[::1]:8080", "https"])
|
||||
self.assertEqual(mock_add_dir.call_args_list[2][0][2], ["1.1.1.1:8080", "https"])
|
||||
|
||||
def test_make_vhost_ssl(self):
|
||||
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0])
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.1.0.dev0'
|
||||
version = '0.2.0.dev0'
|
||||
|
||||
install_requires = [
|
||||
'acme=={0}'.format(version),
|
||||
|
||||
+2
-2
@@ -147,9 +147,9 @@ then
|
||||
elif uname | grep -iq FreeBSD ; then
|
||||
ExperimentalBootstrap "FreeBSD" freebsd.sh "$SUDO"
|
||||
elif uname | grep -iq Darwin ; then
|
||||
ExperimentalBootstrap "Mac OS X" mac.sh
|
||||
ExperimentalBootstrap "Mac OS X" mac.sh # homebrew doesn't normally run as root
|
||||
elif grep -iq "Amazon Linux" /etc/issue ; then
|
||||
ExperimentalBootstrap "Amazon Linux" _rpm_common.sh
|
||||
ExperimentalBootstrap "Amazon Linux" _rpm_common.sh "$SUDO"
|
||||
else
|
||||
echo "Sorry, I don't know how to bootstrap Let's Encrypt on your operating system!"
|
||||
echo
|
||||
|
||||
@@ -4,7 +4,7 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.1.0.dev0'
|
||||
version = '0.2.0.dev0'
|
||||
|
||||
install_requires = [
|
||||
'letsencrypt=={0}'.format(version),
|
||||
|
||||
@@ -4,7 +4,7 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.1.0.dev0'
|
||||
version = '0.2.0.dev0'
|
||||
|
||||
install_requires = [
|
||||
'acme=={0}'.format(version),
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
This is a PREVIEW RELEASE of a client application for the Let's Encrypt certificate authority and other services using the ACME protocol. The Let's Encrypt certificate authority is NOT YET ISSUING CERTIFICATES TO THE PUBLIC.
|
||||
|
||||
Until publicly-trusted certificates can be issued by Let's Encrypt, this software CANNOT OBTAIN A PUBLICLY-TRUSTED CERTIFICATE FOR YOUR WEB SERVER. You should only use this program if you are a developer interested in experimenting with the ACME protocol or in helping to improve this software. If you want to configure your web site with HTTPS in the meantime, please obtain a certificate from a different authority.
|
||||
|
||||
For updates on the status of Let's Encrypt, please visit the Let's Encrypt home page at https://letsencrypt.org/.
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Let's Encrypt client."""
|
||||
|
||||
# version number like 1.2.3a0, must have at least 2 parts, like 1.2
|
||||
__version__ = '0.1.0.dev0'
|
||||
__version__ = '0.2.0.dev0'
|
||||
|
||||
+31
-14
@@ -9,7 +9,6 @@ import json
|
||||
import logging
|
||||
import logging.handlers
|
||||
import os
|
||||
import pkg_resources
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
@@ -304,6 +303,14 @@ def _report_new_cert(cert_path, fullchain_path):
|
||||
.format(and_chain, path, expiry))
|
||||
reporter_util.add_message(msg, reporter_util.MEDIUM_PRIORITY)
|
||||
|
||||
def _suggest_donate():
|
||||
"Suggest a donation to support Let's Encrypt"
|
||||
reporter_util = zope.component.getUtility(interfaces.IReporter)
|
||||
msg = ("If you like Let's Encrypt, please consider supporting our work by:\n\n"
|
||||
"Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n"
|
||||
"Donating to EFF: https://eff.org/donate-le\n\n")
|
||||
reporter_util.add_message(msg, reporter_util.LOW_PRIORITY)
|
||||
|
||||
|
||||
def _auth_from_domains(le_client, config, domains):
|
||||
"""Authenticate and enroll certificate."""
|
||||
@@ -473,6 +480,8 @@ def run(args, config, plugins): # pylint: disable=too-many-branches,too-many-lo
|
||||
else:
|
||||
display_ops.success_renewal(domains)
|
||||
|
||||
_suggest_donate()
|
||||
|
||||
|
||||
def obtain_cert(args, config, plugins):
|
||||
"""Authenticate & obtain cert, but do not install it."""
|
||||
@@ -502,6 +511,8 @@ def obtain_cert(args, config, plugins):
|
||||
domains = _find_domains(args, installer)
|
||||
_auth_from_domains(le_client, config, domains)
|
||||
|
||||
_suggest_donate()
|
||||
|
||||
|
||||
def install(args, config, plugins):
|
||||
"""Install a previously obtained cert in a server."""
|
||||
@@ -750,6 +761,20 @@ class HelpfulArgumentParser(object):
|
||||
kwargs["help"] = argparse.SUPPRESS
|
||||
self.parser.add_argument(*args, **kwargs)
|
||||
|
||||
def add_deprecated_argument(self, argument_name, num_args):
|
||||
"""Adds a deprecated argument with the name argument_name.
|
||||
|
||||
Deprecated arguments are not shown in the help. If they are used
|
||||
on the command line, a warning is shown stating that the
|
||||
argument is deprecated and no other action is taken.
|
||||
|
||||
:param str argument_name: Name of deprecated argument.
|
||||
:param int nargs: Number of arguments the option takes.
|
||||
|
||||
"""
|
||||
le_util.add_deprecated_argument(
|
||||
self.parser.add_argument, argument_name, num_args)
|
||||
|
||||
def add_group(self, topic, **kwargs):
|
||||
"""
|
||||
|
||||
@@ -830,7 +855,7 @@ def prepare_and_parse_args(plugins, args):
|
||||
"email address. This is strongly discouraged, because in the "
|
||||
"event of key loss or account compromise you will irrevocably "
|
||||
"lose access to your account. You will also be unable to receive "
|
||||
"notice about impending expiration of revocation of your "
|
||||
"notice about impending expiration or revocation of your "
|
||||
"certificates. Updates to the Subscriber Agreement will still "
|
||||
"affect you, and will be effective 14 days after posting an "
|
||||
"update to the web site.")
|
||||
@@ -858,10 +883,7 @@ def prepare_and_parse_args(plugins, args):
|
||||
helpful.add(
|
||||
"automation", "--renew-by-default", action="store_true",
|
||||
help="Select renewal by default when domains are a superset of a "
|
||||
"a previously attained cert")
|
||||
helpful.add(
|
||||
"automation", "--agree-dev-preview", action="store_true",
|
||||
help="Agree to the Let's Encrypt Developer Preview Disclaimer")
|
||||
"previously attained cert")
|
||||
helpful.add(
|
||||
"automation", "--agree-tos", dest="tos", action="store_true",
|
||||
help="Agree to the Let's Encrypt Subscriber Agreement")
|
||||
@@ -926,6 +948,8 @@ def prepare_and_parse_args(plugins, args):
|
||||
help="Require that all configuration files are owned by the current "
|
||||
"user; only needed if your config is somewhere unsafe like /tmp/")
|
||||
|
||||
helpful.add_deprecated_argument("--agree-dev-preview", 0)
|
||||
|
||||
_create_subparsers(helpful)
|
||||
_paths_parser(helpful)
|
||||
# _plugins_parsing should be the last thing to act upon the main
|
||||
@@ -1055,7 +1079,7 @@ def _plugins_parsing(helpful, plugins):
|
||||
helpful.add("webroot", "-w", "--webroot-path", action=WebrootPathProcessor,
|
||||
help="public_html / webroot path. This can be specified multiple times to "
|
||||
"handle different domains; each domain will have the webroot path that"
|
||||
" precededed it. For instance: `-w /var/www/example -d example.com -d "
|
||||
" preceded it. For instance: `-w /var/www/example -d example.com -d "
|
||||
"www.example.com -w /var/www/thing -d thing.net -d m.thing.net`")
|
||||
parse_dict = lambda s: dict(json.loads(s))
|
||||
# --webroot-map still has some awkward properties, so it is undocumented
|
||||
@@ -1245,13 +1269,6 @@ def main(cli_args=sys.argv[1:]):
|
||||
zope.component.provideUtility(report)
|
||||
atexit.register(report.atexit_print_messages)
|
||||
|
||||
# TODO: remove developer preview prompt for the launch
|
||||
if not config.agree_dev_preview:
|
||||
disclaimer = pkg_resources.resource_string("letsencrypt", "DISCLAIMER")
|
||||
if not zope.component.getUtility(interfaces.IDisplay).yesno(
|
||||
disclaimer, "Agree", "Cancel"):
|
||||
raise errors.Error("Must agree to TOS")
|
||||
|
||||
if not os.geteuid() == 0:
|
||||
logger.warning(
|
||||
"Root (sudo) is required to run most of letsencrypt functionality.")
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
"""Let's Encrypt user-supplied configuration."""
|
||||
import os
|
||||
import urlparse
|
||||
import re
|
||||
|
||||
import zope.interface
|
||||
|
||||
from letsencrypt import constants
|
||||
from letsencrypt import errors
|
||||
from letsencrypt import interfaces
|
||||
from letsencrypt import le_util
|
||||
|
||||
|
||||
class NamespaceConfig(object):
|
||||
@@ -123,31 +123,5 @@ def check_config_sanity(config):
|
||||
|
||||
# Domain checks
|
||||
if config.namespace.domains is not None:
|
||||
_check_config_domain_sanity(config.namespace.domains)
|
||||
|
||||
|
||||
def _check_config_domain_sanity(domains):
|
||||
"""Helper method for check_config_sanity which validates
|
||||
domain flag values and errors out if the requirements are not met.
|
||||
|
||||
:param domains: List of domains
|
||||
:type domains: `list` of `string`
|
||||
:raises ConfigurationError: for invalid domains and cases where Let's
|
||||
Encrypt currently will not issue certificates
|
||||
|
||||
"""
|
||||
# Check if there's a wildcard domain
|
||||
if any(d.startswith("*.") for d in domains):
|
||||
raise errors.ConfigurationError(
|
||||
"Wildcard domains are not supported")
|
||||
# Punycode
|
||||
if any("xn--" in d for d in domains):
|
||||
raise errors.ConfigurationError(
|
||||
"Punycode domains are not supported")
|
||||
# FQDN checks from
|
||||
# http://www.mkyong.com/regular-expressions/domain-name-regular-expression-example/
|
||||
# Characters used, domain parts < 63 chars, tld > 1 < 64 chars
|
||||
# first and last char is not "-"
|
||||
fqdn = re.compile("^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,63}$")
|
||||
if any(True for d in domains if not fqdn.match(d)):
|
||||
raise errors.ConfigurationError("Requested domain is not a FQDN")
|
||||
for domain in config.namespace.domains:
|
||||
le_util.check_domain_sanity(domain)
|
||||
|
||||
@@ -16,7 +16,7 @@ CLI_DEFAULTS = dict(
|
||||
"letsencrypt", "cli.ini"),
|
||||
],
|
||||
verbose_count=-(logging.WARNING / 10),
|
||||
server="https://acme-staging.api.letsencrypt.org/directory",
|
||||
server="https://acme-v01.api.letsencrypt.org/directory",
|
||||
rsa_key_size=2048,
|
||||
rollback_checkpoints=1,
|
||||
config_dir="/etc/letsencrypt",
|
||||
|
||||
@@ -4,6 +4,7 @@ import os
|
||||
|
||||
import zope.component
|
||||
|
||||
from letsencrypt import errors
|
||||
from letsencrypt import interfaces
|
||||
from letsencrypt import le_util
|
||||
from letsencrypt.display import util as display_util
|
||||
@@ -186,7 +187,8 @@ def choose_names(installer):
|
||||
logger.debug("No installer, picking names manually")
|
||||
return _choose_names_manually()
|
||||
|
||||
names = list(installer.get_all_names())
|
||||
domains = list(installer.get_all_names())
|
||||
names = get_valid_domains(domains)
|
||||
|
||||
if not names:
|
||||
manual = util(interfaces.IDisplay).yesno(
|
||||
@@ -207,6 +209,22 @@ def choose_names(installer):
|
||||
else:
|
||||
return []
|
||||
|
||||
def get_valid_domains(domains):
|
||||
"""Helper method for choose_names that implements basic checks
|
||||
on domain names
|
||||
|
||||
:param list domains: Domain names to validate
|
||||
:return: List of valid domains
|
||||
:rtype: list
|
||||
"""
|
||||
valid_domains = []
|
||||
for domain in domains:
|
||||
try:
|
||||
le_util.check_domain_sanity(domain)
|
||||
valid_domains.append(domain)
|
||||
except errors.ConfigurationError:
|
||||
continue
|
||||
return valid_domains
|
||||
|
||||
def _filter_names(names):
|
||||
"""Determine which names the user would like to select from a list.
|
||||
@@ -245,7 +263,7 @@ def success_installation(domains):
|
||||
|
||||
"""
|
||||
util(interfaces.IDisplay).notification(
|
||||
"Congratulations! You have successfully enabled {0}!{1}{1}"
|
||||
"Congratulations! You have successfully enabled {0}{1}{1}"
|
||||
"You should test your configuration at:{1}{2}".format(
|
||||
_gen_https_names(domains),
|
||||
os.linesep,
|
||||
|
||||
@@ -280,3 +280,37 @@ def add_deprecated_argument(add_argument, argument_name, nargs):
|
||||
|
||||
add_argument(argument_name, action=ShowWarning,
|
||||
help=argparse.SUPPRESS, nargs=nargs)
|
||||
|
||||
def check_domain_sanity(domain):
|
||||
"""Method which validates domain value and errors out if
|
||||
the requirements are not met.
|
||||
|
||||
:param domain: Domain to check
|
||||
:type domains: `string`
|
||||
:raises ConfigurationError: for invalid domains and cases where Let's
|
||||
Encrypt currently will not issue certificates
|
||||
|
||||
"""
|
||||
# Check if there's a wildcard domain
|
||||
if domain.startswith("*."):
|
||||
raise errors.ConfigurationError(
|
||||
"Wildcard domains are not supported")
|
||||
# Punycode
|
||||
if "xn--" in domain:
|
||||
raise errors.ConfigurationError(
|
||||
"Punycode domains are not presently supported")
|
||||
|
||||
# Unicode
|
||||
try:
|
||||
domain.encode('ascii')
|
||||
except UnicodeDecodeError:
|
||||
raise errors.ConfigurationError(
|
||||
"Internationalized domain names are not presently supported")
|
||||
|
||||
# FQDN checks from
|
||||
# http://www.mkyong.com/regular-expressions/domain-name-regular-expression-example/
|
||||
# Characters used, domain parts < 63 chars, tld > 1 < 64 chars
|
||||
# first and last char is not "-"
|
||||
fqdn = re.compile("^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,63}$")
|
||||
if not fqdn.match(domain):
|
||||
raise errors.ConfigurationError("Requested domain is not a FQDN")
|
||||
|
||||
@@ -39,25 +39,27 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
self.config_dir = os.path.join(self.tmp_dir, 'config')
|
||||
self.work_dir = os.path.join(self.tmp_dir, 'work')
|
||||
self.logs_dir = os.path.join(self.tmp_dir, 'logs')
|
||||
self.standard_args = ['--text', '--config-dir', self.config_dir,
|
||||
'--work-dir', self.work_dir, '--logs-dir',
|
||||
self.logs_dir, '--agree-dev-preview']
|
||||
self.standard_args = ['--config-dir', self.config_dir,
|
||||
'--work-dir', self.work_dir,
|
||||
'--logs-dir', self.logs_dir, '--text']
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.tmp_dir)
|
||||
|
||||
def _call(self, args):
|
||||
"Run the cli with output streams and actual client mocked out"
|
||||
with mock.patch('letsencrypt.cli.client') as client:
|
||||
ret, stdout, stderr = self._call_no_clientmock(args)
|
||||
return ret, stdout, stderr, client
|
||||
with mock.patch('letsencrypt.cli._suggest_donate'):
|
||||
with mock.patch('letsencrypt.cli.client') as client:
|
||||
ret, stdout, stderr = self._call_no_clientmock(args)
|
||||
return ret, stdout, stderr, client
|
||||
|
||||
def _call_no_clientmock(self, args):
|
||||
"Run the client with output streams mocked out"
|
||||
args = self.standard_args + args
|
||||
with mock.patch('letsencrypt.cli.sys.stdout') as stdout:
|
||||
with mock.patch('letsencrypt.cli.sys.stderr') as stderr:
|
||||
ret = cli.main(args[:]) # NOTE: parser can alter its args!
|
||||
with mock.patch('letsencrypt.cli._suggest_donate'):
|
||||
with mock.patch('letsencrypt.cli.sys.stdout') as stdout:
|
||||
with mock.patch('letsencrypt.cli.sys.stderr') as stderr:
|
||||
ret = cli.main(args[:]) # NOTE: parser can alter its args!
|
||||
return ret, stdout, stderr
|
||||
|
||||
def _call_stdout(self, args):
|
||||
@@ -66,9 +68,10 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
caller.
|
||||
"""
|
||||
args = self.standard_args + args
|
||||
with mock.patch('letsencrypt.cli.sys.stderr') as stderr:
|
||||
with mock.patch('letsencrypt.cli.client') as client:
|
||||
ret = cli.main(args[:]) # NOTE: parser can alter its args!
|
||||
with mock.patch('letsencrypt.cli._suggest_donate'):
|
||||
with mock.patch('letsencrypt.cli.sys.stderr') as stderr:
|
||||
with mock.patch('letsencrypt.cli.client') as client:
|
||||
ret = cli.main(args[:]) # NOTE: parser can alter its args!
|
||||
return ret, None, stderr, client
|
||||
|
||||
def test_no_flags(self):
|
||||
@@ -180,8 +183,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
def test_configurator_selection(self, mock_exe_exists):
|
||||
mock_exe_exists.return_value = True
|
||||
real_plugins = disco.PluginsRegistry.find_all()
|
||||
args = ['--agree-dev-preview', '--apache',
|
||||
'--authenticator', 'standalone']
|
||||
args = ['--apache', '--authenticator', 'standalone']
|
||||
|
||||
# This needed two calls to find_all(), which we're avoiding for now
|
||||
# because of possible side effects:
|
||||
@@ -360,9 +362,10 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
namespace = cli.prepare_and_parse_args(plugins, webroot_map_args)
|
||||
self.assertEqual(namespace.webroot_map, {u"eg.com": u"/tmp"})
|
||||
|
||||
@mock.patch('letsencrypt.cli._suggest_donate')
|
||||
@mock.patch('letsencrypt.crypto_util.notAfter')
|
||||
@mock.patch('letsencrypt.cli.zope.component.getUtility')
|
||||
def test_certonly_new_request_success(self, mock_get_utility, mock_notAfter):
|
||||
def test_certonly_new_request_success(self, mock_get_utility, mock_notAfter, _suggest):
|
||||
cert_path = '/etc/letsencrypt/live/foo.bar'
|
||||
date = '1970-01-01'
|
||||
mock_notAfter().date.return_value = date
|
||||
@@ -391,10 +394,11 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
mock_init.return_value = mock_client
|
||||
self._call(['-d', 'foo.bar', '-a', 'standalone', 'certonly'])
|
||||
|
||||
@mock.patch('letsencrypt.cli._suggest_donate')
|
||||
@mock.patch('letsencrypt.cli.zope.component.getUtility')
|
||||
@mock.patch('letsencrypt.cli._treat_as_renewal')
|
||||
@mock.patch('letsencrypt.cli._init_le_client')
|
||||
def test_certonly_renewal(self, mock_init, mock_renewal, mock_get_utility):
|
||||
def test_certonly_renewal(self, mock_init, mock_renewal, mock_get_utility, _suggest):
|
||||
cert_path = '/etc/letsencrypt/live/foo.bar/cert.pem'
|
||||
chain_path = '/etc/letsencrypt/live/foo.bar/fullchain.pem'
|
||||
|
||||
@@ -416,13 +420,14 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
self.assertTrue(
|
||||
chain_path in mock_get_utility().add_message.call_args[0][0])
|
||||
|
||||
@mock.patch('letsencrypt.cli._suggest_donate')
|
||||
@mock.patch('letsencrypt.crypto_util.notAfter')
|
||||
@mock.patch('letsencrypt.cli.display_ops.pick_installer')
|
||||
@mock.patch('letsencrypt.cli.zope.component.getUtility')
|
||||
@mock.patch('letsencrypt.cli._init_le_client')
|
||||
@mock.patch('letsencrypt.cli.record_chosen_plugins')
|
||||
def test_certonly_csr(self, _rec, mock_init, mock_get_utility,
|
||||
mock_pick_installer, mock_notAfter):
|
||||
mock_pick_installer, mock_notAfter, _suggest):
|
||||
cert_path = '/etc/letsencrypt/live/blahcert.pem'
|
||||
date = '1970-01-01'
|
||||
mock_notAfter().date.return_value = date
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# coding=utf-8
|
||||
"""Test letsencrypt.display.ops."""
|
||||
import os
|
||||
import sys
|
||||
@@ -385,6 +386,17 @@ class ChooseNamesTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual(self._call(self.mock_install), [])
|
||||
|
||||
def test_get_valid_domains(self):
|
||||
from letsencrypt.display.ops import get_valid_domains
|
||||
all_valid = ["example.com", "second.example.com",
|
||||
"also.example.com"]
|
||||
all_invalid = ["xn--ls8h.tld", "*.wildcard.com", "notFQDN",
|
||||
"uniçodé.com"]
|
||||
two_valid = ["example.com", "xn--ls8h.tld", "also.example.com"]
|
||||
self.assertEqual(get_valid_domains(all_valid), all_valid)
|
||||
self.assertEqual(get_valid_domains(all_invalid), [])
|
||||
self.assertEqual(len(get_valid_domains(two_valid)), 2)
|
||||
|
||||
|
||||
class SuccessInstallationTest(unittest.TestCase):
|
||||
# pylint: disable=too-few-public-methods
|
||||
|
||||
@@ -4,7 +4,7 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.1.0.dev0'
|
||||
version = '0.2.0.dev0'
|
||||
|
||||
install_requires = [
|
||||
'setuptools', # pkg_resources
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
SSLRequire %{SSL_CLIENT_S_DN_CN} in {"foo@bar.com", "bar@foo.com"}
|
||||
@@ -0,0 +1,28 @@
|
||||
<IfModule mod_ssl.c>
|
||||
<VirtualHost *:443>
|
||||
ServerAdmin info@somethingnewentertainment.com
|
||||
ServerName somethingnewentertainment.com
|
||||
DocumentRoot /var/www/html
|
||||
|
||||
ErrorLog /var/log/apache2/error.log
|
||||
CustomLog /var/log/apache2/access.log combined
|
||||
|
||||
SSLEngine on
|
||||
SSLProtocol all -SSLv2 -SSLv3
|
||||
SSLHonorCipherOrder on
|
||||
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EEC DH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRS A RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"
|
||||
|
||||
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
|
||||
|
||||
<FilesMatch "\.(cgi|shtml|phtml|php)$">
|
||||
SSLOptions +StdEnvVars
|
||||
</FilesMatch>
|
||||
<Directory /usr/lib/cgi-bin>
|
||||
SSLOptions +StdEnvVars
|
||||
</Directory>
|
||||
BrowserMatch "MSIE [2-6]" \
|
||||
nokeepalive ssl-unclean-shutdown \
|
||||
downgrade-1.0 force-response-1.0
|
||||
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
|
||||
</VirtualHost> </IfModule>
|
||||
@@ -21,7 +21,6 @@ letsencrypt_test () {
|
||||
$store_flags \
|
||||
--text \
|
||||
--no-redirect \
|
||||
--agree-dev-preview \
|
||||
--agree-tos \
|
||||
--register-unsafely-without-email \
|
||||
--renew-by-default \
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ fi
|
||||
|
||||
cover () {
|
||||
if [ "$1" = "letsencrypt" ]; then
|
||||
min=98
|
||||
min=97
|
||||
elif [ "$1" = "acme" ]; then
|
||||
min=100
|
||||
elif [ "$1" = "letsencrypt_apache" ]; then
|
||||
|
||||
Reference in New Issue
Block a user