mirror of
https://github.com/certbot/certbot.git
synced 2026-01-26 07:41:33 +03:00
Merge remote-tracking branch 'origin/master' into faster-testfarm
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -22,3 +22,7 @@ letsencrypt.log
|
||||
|
||||
# auth --cert-path --chain-path
|
||||
/*.pem
|
||||
|
||||
# letstest
|
||||
tests/letstest/letest-*/
|
||||
tests/letstest/*.pem
|
||||
|
||||
@@ -49,7 +49,6 @@ COPY letsencrypt-apache /opt/letsencrypt/src/letsencrypt-apache/
|
||||
COPY letsencrypt-nginx /opt/letsencrypt/src/letsencrypt-nginx/
|
||||
|
||||
|
||||
# py26reqs.txt not installed!
|
||||
RUN virtualenv --no-site-packages -p python2 /opt/letsencrypt/venv && \
|
||||
/opt/letsencrypt/venv/bin/pip install \
|
||||
-e /opt/letsencrypt/src/acme \
|
||||
|
||||
@@ -32,7 +32,6 @@ RUN /opt/letsencrypt/src/ubuntu.sh && \
|
||||
# the above is not likely to change, so by putting it further up the
|
||||
# Dockerfile we make sure we cache as much as possible
|
||||
|
||||
# py26reqs.txt not installed!
|
||||
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
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
include py26reqs.txt
|
||||
include README.rst
|
||||
include CHANGES.rst
|
||||
include CONTRIBUTING.md
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
"""ACME protocol implementation.
|
||||
|
||||
This module is an implementation of the `ACME protocol`_. Latest
|
||||
supported version: `v02`_.
|
||||
supported version: `draft-ietf-acme-01`_.
|
||||
|
||||
.. _`ACME protocol`: https://github.com/letsencrypt/acme-spec
|
||||
.. _`ACME protocol`: https://github.com/ietf-wg-acme/acme/
|
||||
|
||||
.. _`v02`:
|
||||
https://github.com/letsencrypt/acme-spec/commit/d328fea2d507deb9822793c512830d827a4150c4
|
||||
.. _`draft-ietf-acme-01`:
|
||||
https://github.com/ietf-wg-acme/acme/tree/draft-ietf-acme-acme-01
|
||||
|
||||
|
||||
"""
|
||||
|
||||
@@ -10,8 +10,6 @@ install_requires = [
|
||||
# load_pem_private/public_key (>=0.6)
|
||||
# rsa_recover_prime_factors (>=0.8)
|
||||
'cryptography>=0.8',
|
||||
'ndg-httpsclient', # urllib3 InsecurePlatformWarning (#304)
|
||||
'pyasn1', # urllib3 InsecurePlatformWarning (#304)
|
||||
# Connection.set_tlsext_host_name (>=0.13), X509Req.get_extensions (>=0.15)
|
||||
'PyOpenSSL>=0.15',
|
||||
'pyrfc3339',
|
||||
@@ -32,6 +30,11 @@ if sys.version_info < (2, 7):
|
||||
else:
|
||||
install_requires.append('mock')
|
||||
|
||||
if sys.version_info < (2, 7, 9):
|
||||
# For secure SSL connexion with Python 2.7 (InsecurePlatformWarning)
|
||||
install_requires.append('ndg-httpsclient')
|
||||
install_requires.append('pyasn1')
|
||||
|
||||
docs_extras = [
|
||||
'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags
|
||||
'sphinx_rtd_theme',
|
||||
|
||||
@@ -2,6 +2,5 @@ This directory contains scripts that install necessary OS-specific
|
||||
prerequisite dependencies (see docs/using.rst).
|
||||
|
||||
General dependencies:
|
||||
- git-core: py26reqs.txt git+https://*
|
||||
- ca-certificates: communication with demo ACMO server at
|
||||
https://www.letsencrypt-demo.org, py26reqs.txt git+https://*
|
||||
https://www.letsencrypt-demo.org
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
# ./bootstrap/dev/_common_venv.sh
|
||||
|
||||
deps="
|
||||
git
|
||||
python2
|
||||
python-virtualenv
|
||||
gcc
|
||||
|
||||
@@ -24,26 +24,56 @@ apt-get update
|
||||
# distro version (#346)
|
||||
|
||||
virtualenv=
|
||||
if apt-cache show virtualenv > /dev/null ; then
|
||||
if apt-cache show virtualenv > /dev/null 2>&1; then
|
||||
virtualenv="virtualenv"
|
||||
fi
|
||||
|
||||
if apt-cache show python-virtualenv > /dev/null ; then
|
||||
if apt-cache show python-virtualenv > /dev/null 2>&1; then
|
||||
virtualenv="$virtualenv python-virtualenv"
|
||||
fi
|
||||
|
||||
augeas_pkg=libaugeas0
|
||||
AUGVERSION=`apt-cache show --no-all-versions libaugeas0 | grep ^Version: | cut -d" " -f2`
|
||||
|
||||
if dpkg --compare-versions 1.0 gt "$AUGVERSION" ; then
|
||||
if lsb_release -a | grep -q wheezy ; then
|
||||
if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q wheezy-backports ; then
|
||||
# This can theoretically error if sources.list.d is empty, but in that case we don't care.
|
||||
if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q wheezy-backports ; then
|
||||
/bin/echo -n "Installing augeas from wheezy-backports in 3 seconds..."
|
||||
sleep 1s
|
||||
/bin/echo -ne "\e[0K\rInstalling augeas from wheezy-backports in 2 seconds..."
|
||||
sleep 1s
|
||||
/bin/echo -e "\e[0K\rInstalling augeas from wheezy-backports in 1 second ..."
|
||||
sleep 1s
|
||||
/bin/echo '(Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports")'
|
||||
|
||||
echo deb http://http.debian.net/debian wheezy-backports main >> /etc/apt/sources.list.d/wheezy-backports.list
|
||||
apt-get update
|
||||
fi
|
||||
fi
|
||||
apt-get install -y --no-install-recommends -t wheezy-backports libaugeas0
|
||||
augeas_pkg=
|
||||
else
|
||||
echo "No libaugeas0 version is available that's new enough to run the"
|
||||
echo "Let's Encrypt apache plugin..."
|
||||
fi
|
||||
# XXX add a case for ubuntu PPAs
|
||||
fi
|
||||
|
||||
apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
python \
|
||||
python-dev \
|
||||
$virtualenv \
|
||||
gcc \
|
||||
dialog \
|
||||
libaugeas0 \
|
||||
$augeas_pkg \
|
||||
libssl-dev \
|
||||
libffi-dev \
|
||||
ca-certificates \
|
||||
|
||||
|
||||
|
||||
if ! command -v virtualenv > /dev/null ; then
|
||||
echo Failed to install a working \"virtualenv\" command, exiting
|
||||
exit 1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
PACKAGES="dev-vcs/git
|
||||
PACKAGES="
|
||||
dev-lang/python:2.7
|
||||
dev-python/virtualenv
|
||||
dev-util/dialog
|
||||
|
||||
@@ -33,9 +33,7 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
# "git-core" seems to be an alias for "git" in CentOS 7 (yum search fails)
|
||||
if ! $tool install -y \
|
||||
git-core \
|
||||
gcc \
|
||||
dialog \
|
||||
augeas-libs \
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# SLE12 don't have python-virtualenv
|
||||
|
||||
zypper -nq in -l git-core \
|
||||
zypper -nq in -l \
|
||||
python \
|
||||
python-devel \
|
||||
python-virtualenv \
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
export VENV_ARGS="--python python2"
|
||||
|
||||
./bootstrap/dev/_venv_common.sh \
|
||||
-r py26reqs.txt \
|
||||
-e acme[testing] \
|
||||
-e .[dev,docs,testing] \
|
||||
-e letsencrypt-apache \
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/bin/sh -xe
|
||||
|
||||
pkg install -Ay \
|
||||
git \
|
||||
python \
|
||||
py27-virtualenv \
|
||||
augeas \
|
||||
|
||||
@@ -20,7 +20,7 @@ fi
|
||||
pip install -U setuptools
|
||||
pip install -U pip
|
||||
|
||||
pip install -U -r py26reqs.txt letsencrypt letsencrypt-apache # letsencrypt-nginx
|
||||
pip install -U letsencrypt letsencrypt-apache # letsencrypt-nginx
|
||||
|
||||
echo
|
||||
echo "Congratulations, Let's Encrypt has been successfully installed/updated!"
|
||||
|
||||
@@ -371,7 +371,7 @@ If you run Debian Stretch or Debian Sid, you can install letsencrypt packages.
|
||||
sudo apt-get update
|
||||
sudo apt-get install letsencrypt python-letsencrypt-apache
|
||||
|
||||
If you don't want to use the Apache plugin, you can ommit the
|
||||
If you don't want to use the Apache plugin, you can omit the
|
||||
``python-letsencrypt-apache`` package.
|
||||
|
||||
Packages for Debian Jessie are coming in the next few weeks.
|
||||
|
||||
@@ -542,7 +542,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
"""
|
||||
if "ssl_module" not in self.parser.modules:
|
||||
self.enable_mod("ssl", temp=temp)
|
||||
|
||||
if self.version >= (2, 4) and "socache_shmcb_module" not in self.parser.modules:
|
||||
self.enable_mod("socache_shmcb", temp=temp)
|
||||
# Check for Listen <port>
|
||||
# Note: This could be made to also look for ip:443 combo
|
||||
listens = [self.parser.get_arg(x).split()[0] for x in self.parser.find_dir("Listen")]
|
||||
@@ -1271,6 +1272,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
|
||||
"""
|
||||
self.config_test()
|
||||
logger.debug(self.reverter.view_config_changes())
|
||||
self._reload()
|
||||
|
||||
def _reload(self):
|
||||
@@ -1399,7 +1401,7 @@ def _get_mod_deps(mod_name):
|
||||
|
||||
"""
|
||||
deps = {
|
||||
"ssl": ["setenvif", "mime", "socache_shmcb"]
|
||||
"ssl": ["setenvif", "mime"]
|
||||
}
|
||||
return deps.get(mod_name, [])
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ REWRITE_HTTPS_ARGS_WITH_END = [
|
||||
https vhost"""
|
||||
|
||||
HSTS_ARGS = ["always", "set", "Strict-Transport-Security",
|
||||
"\"max-age=31536000; includeSubDomains\""]
|
||||
"\"max-age=31536000\""]
|
||||
"""Apache header arguments for HSTS"""
|
||||
|
||||
UIR_ARGS = ["always", "set", "Content-Security-Policy",
|
||||
|
||||
@@ -19,7 +19,6 @@ class ApacheParser(object):
|
||||
|
||||
:ivar str root: Normalized absolute path to the server root
|
||||
directory. Without trailing slash.
|
||||
:ivar str root: Server root
|
||||
:ivar set modules: All module names that are currently enabled.
|
||||
:ivar dict loc: Location to place directives, root - configuration origin,
|
||||
default - user config file, name - NameVirtualHost,
|
||||
@@ -36,6 +35,7 @@ class ApacheParser(object):
|
||||
# https://httpd.apache.org/docs/2.4/mod/core.html#ifdefine
|
||||
# This only handles invocation parameters and Define directives!
|
||||
self.variables = {}
|
||||
self.unparsable = False
|
||||
self.update_runtime_variables(ctl)
|
||||
|
||||
self.aug = aug
|
||||
@@ -60,6 +60,11 @@ class ApacheParser(object):
|
||||
# Sites-available is not included naturally in configuration
|
||||
self._parse_file(os.path.join(self.root, "sites-available") + "/*")
|
||||
|
||||
#check to see if there were unparsed define statements
|
||||
if self.unparsable:
|
||||
if self.find_dir("Define", exclude=False):
|
||||
raise errors.PluginError("Error parsing runtime variables")
|
||||
|
||||
def init_modules(self):
|
||||
"""Iterates on the configuration until no new modules are loaded.
|
||||
|
||||
@@ -101,7 +106,8 @@ class ApacheParser(object):
|
||||
try:
|
||||
matches.remove("DUMP_RUN_CFG")
|
||||
except ValueError:
|
||||
raise errors.PluginError("Unable to parse runtime variables")
|
||||
self.unparsable = True
|
||||
return
|
||||
|
||||
for match in matches:
|
||||
if match.count("=") > 1:
|
||||
|
||||
@@ -28,10 +28,21 @@ class TwoVhost80Test(util.ApacheTest):
|
||||
|
||||
self.config = util.get_apache_configurator(
|
||||
self.config_path, self.config_dir, self.work_dir)
|
||||
|
||||
self.config = self.mock_deploy_cert(self.config)
|
||||
self.vh_truth = util.get_vh_truth(
|
||||
self.temp_dir, "debian_apache_2_4/two_vhost_80")
|
||||
|
||||
def mock_deploy_cert(self, config):
|
||||
"""A test for a mock deploy cert"""
|
||||
self.config.real_deploy_cert = self.config.deploy_cert
|
||||
def mocked_deploy_cert(*args, **kwargs):
|
||||
"""a helper to mock a deployed cert"""
|
||||
with mock.patch(
|
||||
"letsencrypt_apache.configurator.ApacheConfigurator.enable_mod"):
|
||||
config.real_deploy_cert(*args, **kwargs)
|
||||
self.config.deploy_cert = mocked_deploy_cert
|
||||
return self.config
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.temp_dir)
|
||||
shutil.rmtree(self.config_dir)
|
||||
@@ -251,6 +262,7 @@ class TwoVhost80Test(util.ApacheTest):
|
||||
|
||||
# Get the default 443 vhost
|
||||
self.config.assoc["random.demo"] = self.vh_truth[1]
|
||||
self.config = self.mock_deploy_cert(self.config)
|
||||
self.config.deploy_cert(
|
||||
"random.demo", "example/cert.pem", "example/key.pem",
|
||||
"example/cert_chain.pem", "example/fullchain.pem")
|
||||
@@ -277,6 +289,7 @@ class TwoVhost80Test(util.ApacheTest):
|
||||
def test_deploy_cert_newssl_no_fullchain(self):
|
||||
self.config = util.get_apache_configurator(
|
||||
self.config_path, self.config_dir, self.work_dir, version=(2, 4, 16))
|
||||
self.config = self.mock_deploy_cert(self.config)
|
||||
|
||||
self.config.parser.modules.add("ssl_module")
|
||||
self.config.parser.modules.add("mod_ssl.c")
|
||||
@@ -290,6 +303,7 @@ class TwoVhost80Test(util.ApacheTest):
|
||||
def test_deploy_cert_old_apache_no_chain(self):
|
||||
self.config = util.get_apache_configurator(
|
||||
self.config_path, self.config_dir, self.work_dir, version=(2, 4, 7))
|
||||
self.config = self.mock_deploy_cert(self.config)
|
||||
|
||||
self.config.parser.modules.add("ssl_module")
|
||||
self.config.parser.modules.add("mod_ssl.c")
|
||||
|
||||
@@ -151,8 +151,8 @@ class BasicParserTest(util.ParserTest):
|
||||
@mock.patch("letsencrypt_apache.parser.ApacheParser._get_runtime_cfg")
|
||||
def test_update_runtime_vars_bad_output(self, mock_cfg):
|
||||
mock_cfg.return_value = "Define: TLS=443=24"
|
||||
self.assertRaises(
|
||||
errors.PluginError, self.parser.update_runtime_variables, "ctl")
|
||||
self.parser.update_runtime_variables("ctl")
|
||||
self.assertTrue(self.parser.unparsable)
|
||||
|
||||
mock_cfg.return_value = "Define: DUMP_RUN_CFG\nDefine: TLS=443=24"
|
||||
self.assertRaises(
|
||||
@@ -185,6 +185,21 @@ class ParserInitTest(util.ApacheTest):
|
||||
shutil.rmtree(self.config_dir)
|
||||
shutil.rmtree(self.work_dir)
|
||||
|
||||
@mock.patch("letsencrypt_apache.parser.ApacheParser._get_runtime_cfg")
|
||||
def test_unparsable(self, mock_cfg):
|
||||
from letsencrypt_apache.parser import ApacheParser
|
||||
def unparsable_true(self, arg):
|
||||
"""a helper to set the self unparsabale to true"""
|
||||
print "side effect has passed in arg: %s", arg
|
||||
self.unparsable = True
|
||||
with mock.patch.object(ApacheParser, 'update_runtime_variables', autospec=True) as urv:
|
||||
urv.side_effect = unparsable_true
|
||||
mock_cfg.return_value = ('Define: TEST')
|
||||
self.assertRaises(
|
||||
errors.PluginError,
|
||||
ApacheParser, self.aug, os.path.relpath(self.config_path), "ctl")
|
||||
self.assertEquals(1, 1)
|
||||
|
||||
def test_root_normalized(self):
|
||||
from letsencrypt_apache.parser import ApacheParser
|
||||
|
||||
|
||||
@@ -78,7 +78,9 @@ class TlsSniPerformTest(util.ApacheTest):
|
||||
# pylint: disable=protected-access
|
||||
self.sni._setup_challenge_cert = mock_setup_cert
|
||||
|
||||
sni_responses = self.sni.perform()
|
||||
with mock.patch(
|
||||
"letsencrypt_apache.configurator.ApacheConfigurator.enable_mod"):
|
||||
sni_responses = self.sni.perform()
|
||||
|
||||
self.assertEqual(mock_setup_cert.call_count, 2)
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
"""A class that performs TLS-SNI-01 challenges for Apache"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
|
||||
from letsencrypt.plugins import common
|
||||
|
||||
from letsencrypt_apache import obj
|
||||
from letsencrypt_apache import parser
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class ApacheTlsSni01(common.TLSSNI01):
|
||||
"""Class that performs TLS-SNI-01 challenges within the Apache configurator
|
||||
@@ -104,6 +106,7 @@ class ApacheTlsSni01(common.TLSSNI01):
|
||||
self.configurator.reverter.register_file_creation(
|
||||
True, self.challenge_conf)
|
||||
|
||||
logger.debug("writing a config file with text: %s", config_text)
|
||||
with open(self.challenge_conf, "w") as new_conf:
|
||||
new_conf.write(config_text)
|
||||
|
||||
|
||||
@@ -47,13 +47,13 @@ if test "`id -u`" -ne "0" ; then
|
||||
args=""
|
||||
# This `while` loop iterates over all parameters given to this function.
|
||||
# For each parameter, all `'` will be replace by `'"'"'`, and the escaped string
|
||||
# will be wrap in a pair of `'`, then append to `$args` string
|
||||
# will be wrapped in a pair of `'`, then appended to `$args` string
|
||||
# For example, `echo "It's only 1\$\!"` will be escaped to:
|
||||
# 'echo' 'It'"'"'s only 1$!'
|
||||
# │ │└┼┘│
|
||||
# │ │ │ └── `'s only 1$!'` the literal string
|
||||
# │ │ └── `\"'\"` is a single quote (as a string)
|
||||
# │ └── `'It'`, to be concatenated with the strings followed it
|
||||
# │ └── `'It'`, to be concatenated with the strings following it
|
||||
# └── `echo` wrapped in a pair of `'`, it's totally fine for the shell command itself
|
||||
while [ $# -ne 0 ]; do
|
||||
args="$args'$(printf "%s" "$1" | sed -e "s/'/'\"'\"'/g")' "
|
||||
@@ -176,7 +176,7 @@ if [ "$VERBOSE" = 1 ] ; then
|
||||
echo
|
||||
$VENV_BIN/pip install -U setuptools
|
||||
$VENV_BIN/pip install -U pip
|
||||
$VENV_BIN/pip install -r "$LEA_PATH"/py26reqs.txt -U letsencrypt letsencrypt-apache
|
||||
$VENV_BIN/pip install -U letsencrypt letsencrypt-apache
|
||||
# nginx is buggy / disabled for now, but upgrade it if the user has
|
||||
# installed it manually
|
||||
if $VENV_BIN/pip freeze | grep -q letsencrypt-nginx ; then
|
||||
@@ -188,8 +188,6 @@ else
|
||||
$VENV_BIN/pip install -U pip > /dev/null
|
||||
printf .
|
||||
# nginx is buggy / disabled for now...
|
||||
$VENV_BIN/pip install -r "$LEA_PATH"/py26reqs.txt > /dev/null
|
||||
printf .
|
||||
$VENV_BIN/pip install -U letsencrypt > /dev/null
|
||||
printf .
|
||||
$VENV_BIN/pip install -U letsencrypt-apache > /dev/null
|
||||
@@ -202,5 +200,5 @@ fi
|
||||
|
||||
# Explain what's about to happen, for the benefit of those getting sudo
|
||||
# password prompts...
|
||||
echo "Running with virtualenv:" $SUDO $VENV_BIN/letsencrypt "$@"
|
||||
echo "Requesting root privileges to run with virtualenv:" $SUDO $VENV_BIN/letsencrypt "$@"
|
||||
$SUDO $VENV_BIN/letsencrypt "$@"
|
||||
|
||||
@@ -15,11 +15,12 @@ from acme import crypto_util
|
||||
from acme import messages
|
||||
from letsencrypt import achallenges
|
||||
from letsencrypt import errors as le_errors
|
||||
from letsencrypt import validator
|
||||
from letsencrypt.tests import acme_util
|
||||
|
||||
from letsencrypt_compatibility_test import errors
|
||||
from letsencrypt_compatibility_test import util
|
||||
from letsencrypt_compatibility_test import validator
|
||||
|
||||
from letsencrypt_compatibility_test.configurators.apache import apache24
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Tests for letsencrypt.validator."""
|
||||
"""Tests for letsencrypt_compatibility_test.validator."""
|
||||
import requests
|
||||
import unittest
|
||||
|
||||
@@ -6,28 +6,31 @@ import mock
|
||||
import OpenSSL
|
||||
|
||||
from acme import errors as acme_errors
|
||||
from letsencrypt import validator
|
||||
from letsencrypt_compatibility_test import validator
|
||||
|
||||
|
||||
class ValidatorTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.validator = validator.Validator()
|
||||
|
||||
@mock.patch("letsencrypt.validator.crypto_util.probe_sni")
|
||||
@mock.patch(
|
||||
"letsencrypt_compatibility_test.validator.crypto_util.probe_sni")
|
||||
def test_certificate_success(self, mock_probe_sni):
|
||||
cert = OpenSSL.crypto.X509()
|
||||
mock_probe_sni.return_value = cert
|
||||
self.assertTrue(self.validator.certificate(
|
||||
cert, "test.com", "127.0.0.1"))
|
||||
|
||||
@mock.patch("letsencrypt.validator.crypto_util.probe_sni")
|
||||
@mock.patch(
|
||||
"letsencrypt_compatibility_test.validator.crypto_util.probe_sni")
|
||||
def test_certificate_error(self, mock_probe_sni):
|
||||
cert = OpenSSL.crypto.X509()
|
||||
mock_probe_sni.side_effect = [acme_errors.Error]
|
||||
self.assertFalse(self.validator.certificate(
|
||||
cert, "test.com", "127.0.0.1"))
|
||||
|
||||
@mock.patch("letsencrypt.validator.crypto_util.probe_sni")
|
||||
@mock.patch(
|
||||
"letsencrypt_compatibility_test.validator.crypto_util.probe_sni")
|
||||
def test_certificate_failure(self, mock_probe_sni):
|
||||
cert = OpenSSL.crypto.X509()
|
||||
cert.set_serial_number(1337)
|
||||
@@ -35,67 +38,67 @@ class ValidatorTest(unittest.TestCase):
|
||||
self.assertFalse(self.validator.certificate(
|
||||
cert, "test.com", "127.0.0.1"))
|
||||
|
||||
@mock.patch("letsencrypt.validator.requests.get")
|
||||
@mock.patch("letsencrypt_compatibility_test.validator.requests.get")
|
||||
def test_succesful_redirect(self, mock_get_request):
|
||||
mock_get_request.return_value = create_response(
|
||||
301, {"location": "https://test.com"})
|
||||
self.assertTrue(self.validator.redirect("test.com"))
|
||||
|
||||
@mock.patch("letsencrypt.validator.requests.get")
|
||||
@mock.patch("letsencrypt_compatibility_test.validator.requests.get")
|
||||
def test_redirect_with_headers(self, mock_get_request):
|
||||
mock_get_request.return_value = create_response(
|
||||
301, {"location": "https://test.com"})
|
||||
self.assertTrue(self.validator.redirect(
|
||||
"test.com", headers={"Host": "test.com"}))
|
||||
|
||||
@mock.patch("letsencrypt.validator.requests.get")
|
||||
@mock.patch("letsencrypt_compatibility_test.validator.requests.get")
|
||||
def test_redirect_missing_location(self, mock_get_request):
|
||||
mock_get_request.return_value = create_response(301)
|
||||
self.assertFalse(self.validator.redirect("test.com"))
|
||||
|
||||
@mock.patch("letsencrypt.validator.requests.get")
|
||||
@mock.patch("letsencrypt_compatibility_test.validator.requests.get")
|
||||
def test_redirect_wrong_status_code(self, mock_get_request):
|
||||
mock_get_request.return_value = create_response(
|
||||
201, {"location": "https://test.com"})
|
||||
self.assertFalse(self.validator.redirect("test.com"))
|
||||
|
||||
@mock.patch("letsencrypt.validator.requests.get")
|
||||
@mock.patch("letsencrypt_compatibility_test.validator.requests.get")
|
||||
def test_redirect_wrong_redirect_code(self, mock_get_request):
|
||||
mock_get_request.return_value = create_response(
|
||||
303, {"location": "https://test.com"})
|
||||
self.assertFalse(self.validator.redirect("test.com"))
|
||||
|
||||
@mock.patch("letsencrypt.validator.requests.get")
|
||||
@mock.patch("letsencrypt_compatibility_test.validator.requests.get")
|
||||
def test_hsts_empty(self, mock_get_request):
|
||||
mock_get_request.return_value = create_response(
|
||||
headers={"strict-transport-security": ""})
|
||||
self.assertFalse(self.validator.hsts("test.com"))
|
||||
|
||||
@mock.patch("letsencrypt.validator.requests.get")
|
||||
@mock.patch("letsencrypt_compatibility_test.validator.requests.get")
|
||||
def test_hsts_malformed(self, mock_get_request):
|
||||
mock_get_request.return_value = create_response(
|
||||
headers={"strict-transport-security": "sdfal"})
|
||||
self.assertFalse(self.validator.hsts("test.com"))
|
||||
|
||||
@mock.patch("letsencrypt.validator.requests.get")
|
||||
@mock.patch("letsencrypt_compatibility_test.validator.requests.get")
|
||||
def test_hsts_bad_max_age(self, mock_get_request):
|
||||
mock_get_request.return_value = create_response(
|
||||
headers={"strict-transport-security": "max-age=not-an-int"})
|
||||
self.assertFalse(self.validator.hsts("test.com"))
|
||||
|
||||
@mock.patch("letsencrypt.validator.requests.get")
|
||||
@mock.patch("letsencrypt_compatibility_test.validator.requests.get")
|
||||
def test_hsts_expire(self, mock_get_request):
|
||||
mock_get_request.return_value = create_response(
|
||||
headers={"strict-transport-security": "max-age=3600"})
|
||||
self.assertFalse(self.validator.hsts("test.com"))
|
||||
|
||||
@mock.patch("letsencrypt.validator.requests.get")
|
||||
@mock.patch("letsencrypt_compatibility_test.validator.requests.get")
|
||||
def test_hsts(self, mock_get_request):
|
||||
mock_get_request.return_value = create_response(
|
||||
headers={"strict-transport-security": "max-age=31536000"})
|
||||
self.assertTrue(self.validator.hsts("test.com"))
|
||||
|
||||
@mock.patch("letsencrypt.validator.requests.get")
|
||||
@mock.patch("letsencrypt_compatibility_test.validator.requests.get")
|
||||
def test_hsts_include_subdomains(self, mock_get_request):
|
||||
mock_get_request.return_value = create_response(
|
||||
headers={"strict-transport-security":
|
||||
@@ -10,6 +10,7 @@ install_requires = [
|
||||
'letsencrypt=={0}'.format(version),
|
||||
'letsencrypt-apache=={0}'.format(version),
|
||||
'docker-py',
|
||||
'requests',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -18,6 +19,11 @@ if sys.version_info < (2, 7):
|
||||
else:
|
||||
install_requires.append('mock')
|
||||
|
||||
if sys.version_info < (2, 7, 9):
|
||||
# For secure SSL connexion with Python 2.7 (InsecurePlatformWarning)
|
||||
install_requires.append('ndg-httpsclient')
|
||||
install_requires.append('pyasn1')
|
||||
|
||||
docs_extras = [
|
||||
'repoze.sphinx.autointerface',
|
||||
'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags
|
||||
|
||||
@@ -1189,7 +1189,7 @@ def _plugins_parsing(helpful, plugins):
|
||||
|
||||
# These would normally be a flag within the webroot plugin, but because
|
||||
# they are parsed in conjunction with --domains, they live here for
|
||||
# legibiility. helpful.add_plugin_ags must be called first to add the
|
||||
# legibility. helpful.add_plugin_ags must be called first to add the
|
||||
# "webroot" topic
|
||||
helpful.add("webroot", "-w", "--webroot-path", action=WebrootPathProcessor,
|
||||
help="public_html / webroot path. This can be specified multiple times to "
|
||||
|
||||
@@ -66,8 +66,16 @@ class AuthenticatorTest(unittest.TestCase):
|
||||
|
||||
def test_prepare_reraises_other_errors(self):
|
||||
self.auth.full_path = os.path.join(self.path, "null")
|
||||
permission_canary = os.path.join(self.path, "rnd")
|
||||
with open(permission_canary, "w") as f:
|
||||
f.write("thingimy")
|
||||
os.chmod(self.path, 0o000)
|
||||
self.assertRaises(errors.PluginError, self.auth.prepare)
|
||||
try:
|
||||
open(permission_canary, "r")
|
||||
print "Warning, running tests as root skips permissions tests..."
|
||||
except IOError:
|
||||
# ok, permissions work, test away...
|
||||
self.assertRaises(errors.PluginError, self.auth.prepare)
|
||||
os.chmod(self.path, 0o700)
|
||||
|
||||
@mock.patch("letsencrypt.plugins.webroot.os.chown")
|
||||
|
||||
@@ -116,6 +116,7 @@ def renew(cert, old_version):
|
||||
def _cli_log_handler(args, level, fmt): # pylint: disable=unused-argument
|
||||
handler = colored_logging.StreamHandler()
|
||||
handler.setFormatter(logging.Formatter(fmt))
|
||||
handler.setLevel(level)
|
||||
return handler
|
||||
|
||||
|
||||
|
||||
@@ -450,12 +450,15 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
||||
:param int version: the desired version number
|
||||
:returns: the subject names
|
||||
:rtype: `list` of `str`
|
||||
:raises .CertStorageError: if could not find cert file.
|
||||
|
||||
"""
|
||||
if version is None:
|
||||
target = self.current_target("cert")
|
||||
else:
|
||||
target = self.version("cert", version)
|
||||
if target is None:
|
||||
raise errors.CertStorageError("could not find cert file")
|
||||
with open(target) as f:
|
||||
return crypto_util.get_sans_from_cert(f.read())
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# https://github.com/bw2/ConfigArgParse/issues/17
|
||||
git+https://github.com/kuba/ConfigArgParse.git@python2.6-0.9.3#egg=ConfigArgParse
|
||||
8
setup.py
8
setup.py
@@ -32,7 +32,6 @@ version = meta['version']
|
||||
|
||||
install_requires = [
|
||||
'acme=={0}'.format(version),
|
||||
'ConfigArgParse',
|
||||
'configobj',
|
||||
'cryptography>=0.7', # load_pem_x509_certificate
|
||||
'parsedatetime',
|
||||
@@ -41,7 +40,6 @@ install_requires = [
|
||||
'pyrfc3339',
|
||||
'python2-pythondialog>=3.2.2rc1', # Debian squeeze support, cf. #280
|
||||
'pytz',
|
||||
'requests',
|
||||
'setuptools', # pkg_resources
|
||||
'six',
|
||||
'zope.component',
|
||||
@@ -53,10 +51,14 @@ if sys.version_info < (2, 7):
|
||||
install_requires.extend([
|
||||
# only some distros recognize stdlib argparse as already satisfying
|
||||
'argparse',
|
||||
'ConfigArgParse>=0.10.0', # python2.6 support, upstream #17
|
||||
'mock<1.1.0',
|
||||
])
|
||||
else:
|
||||
install_requires.append('mock')
|
||||
install_requires.extend([
|
||||
'ConfigArgParse',
|
||||
'mock',
|
||||
])
|
||||
|
||||
dev_extras = [
|
||||
# Pin astroid==1.3.5, pylint==1.4.2 as a workaround for #289
|
||||
|
||||
7
tests/apache-conf-files/passing/rewrite-quote-1960.conf
Normal file
7
tests/apache-conf-files/passing/rewrite-quote-1960.conf
Normal file
@@ -0,0 +1,7 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_URI} ^.*(,|;|:|<|>|">|"<|/|\\\.\.\\).* [NC,OR]
|
||||
RewriteCond %{REQUEST_URI} ^.*(\=|\@|\[|\]|\^|\`|\{|\}|\~).* [NC,OR]
|
||||
RewriteCond %{REQUEST_URI} ^.*(\'|%0A|%0D|%27|%3C|%3E|%00).* [NC]
|
||||
RewriteRule ^(.*)$ - [F,L]
|
||||
</IfModule>
|
||||
@@ -86,7 +86,7 @@ SetVersion() {
|
||||
done
|
||||
sed -i "s/^__version.*/__version__ = '$ver'/" letsencrypt/__init__.py
|
||||
|
||||
git add -p $SUBPKGS # interactive user input
|
||||
git add -p letsencrypt $SUBPKGS # interactive user input
|
||||
}
|
||||
SetVersion "$version"
|
||||
git commit --gpg-sign="$RELEASE_GPG_KEY" -m "Release $version"
|
||||
|
||||
2
tox.ini
2
tox.ini
@@ -17,7 +17,7 @@ envlist = py26,py27,py33,py34,py35,cover,lint
|
||||
commands =
|
||||
pip install -e acme[testing]
|
||||
nosetests -v acme
|
||||
pip install -r py26reqs.txt -e .[testing]
|
||||
pip install -e .[testing]
|
||||
nosetests -v letsencrypt
|
||||
pip install -e letsencrypt-apache
|
||||
nosetests -v letsencrypt_apache
|
||||
|
||||
Reference in New Issue
Block a user