Compare commits

..

122 Commits

Author SHA1 Message Date
Erica Portnoy
15b3f7bc6a Add changelog entry about the removal 2019-11-22 18:23:42 -08:00
Erica Portnoy
d607276b6c Remove unused nginx docs 2019-11-21 15:11:51 -08:00
Brad Warren
4f3010ef3f fixes #7553 (#7560) 2019-11-14 14:26:01 -08:00
Brad Warren
2692b862d2 Update pinned dependencies (#7558)
Fixes #7184.

I updated #7358 to track the issue of unpinning all of these dependencies.

* pin back configargparse

* Pin back zope packages.

* update deps

* Add changelog entry.

* run build.py
2019-11-13 13:44:36 -08:00
ohemorange
4d4c83d4d8 Internalize modules called by internal plugins (#7543)
* Move hooks.py to _internal

* Move cli.py to _internal
2019-11-13 11:14:46 -08:00
Brad Warren
57148b7593 Fix shebang in rebuild_deps (#7557)
When you try to run this script, it crashes with:
```
standard_init_linux.go:211: exec user process caused "exec format error"
```
This is caused by the script being written to have the contents:
```
\
#!/bin/sh
set -e
...
```
This fixes the problem by removing the slash and moving the shebang to the first line of the string.
2019-11-13 11:14:26 -08:00
Amjad Mashaal
4a8ede2562 Deprecate certbot register --update-registration (#7556)
Closes #7452.
2019-11-13 10:24:37 -08:00
ohemorange
46d5f7a860 Move configuration.py to _internal (#7542)
Part of #5775. Methodology similar to #7528. Also refactors NGINX test util to use certbot.tests.util.ConfigTestCase.

* refactor nginx tests to no longer rely on certbot.configuration internals

* Move configuration.py to _internal
2019-11-13 10:19:27 -08:00
Adrien Ferrand
595b1b212e [Windows] Avoid letsencrypt.log permissions error during scheduled certbot renew task (#7537)
While coding for #7536, I ran into another issue. It appears that Certbot logs generated during the scheduled task execution have wrong permissions that make them almost unusable: they do not have an owner, and their ACL contains nonsense values (non existant accounts name).

The class `logging.handler.RotatingFileHandler` is responsible for these logs, and become mad when it is in a Python process run under a scheduled task owned by `SYSTEM`. This is precisely our case here.

This PR avoids (but not fix) the issue, by changing the owner of the scheduled task from `SYSTEM` to the `Administrators` group, that appears to work fine.

* Use Administrators group instead of SYSTEM to run the certbot renew task
2019-11-13 10:04:45 -08:00
Adrien Ferrand
75acdeb645 [Windows] Fix certbot renew task failure under NT AUTHORITY\SYSTEM account (#7536)
Turned out that the scheduled task that runs `certbot renew` twice a day, is failing. Without any kind of log of course, otherwise it would not be fun.

It can be revealed by opening a powershell under the `NT AUTHORITY\SYSTEM` account, under which the scheduled task is run. Under theses circumstances, the bug is revealed: Certbot breaks when trying to invoke `certbot.compat.filesystem._get_current_user()`. Indeed the logic there implied to call `win32api.GetUserNameEx(win32api.NameSamCompatible)` and this function does not return always a useful value.

For normal account, it will be typically `DOMAIN_OR_MACHINE_NAME\YOUR_USER_NAME` (e.g. `My Machine\Adrien Ferrand`). But for the account `NT AUTHORITY\SYSTEM`, it will return `MACHINE_NAME\DOMAIN$`, which is a nonsense and makes fail the resolution of the actual SID of the account at the end of `_get_current_user()`.

This PR fixes this behavior by using an explicit construction of the account name that works both for normal users and `SYSTEM`.

* Use a different way to resolve current user account, that works both for normal users and SYSTEM.

* Add a comment to run Certbot under NT AUTHORITY\SYSTEM
2019-11-13 09:43:50 -08:00
Adrien Ferrand
c26d459d0f Remove python2 and certbot-auto references in how to set up a Certbot build environment. (#7549)
Fixes #7548.

This PR udpdates installation instructions to get rid of python2 and certbot-auto in the how-to explaining the Certbot development environment setup.

Instead, Python 3 is used, and appropriate instructions for APT and RPM based distributions are provided.
2019-11-12 13:52:44 -08:00
ohemorange
4792e1ee21 Move constants.py to _internal (#7534)
* Don't call core constants from nginx plugin

* Move constants.py to _internal/

* Move ENHANCEMENTS from now-internal constants to public plugins.enhancements

* Update display.enhancements.ask from its 2015 comment
2019-11-11 15:41:40 -08:00
ohemorange
08c1de34bd Move items in certbot/plugins to _internal (#7533)
* Create and initialize _internal/plugins

* Move plugins/manual.py to _internal/

* Move plugins/disco.py to _internal/

* Move plugins/selection.py to _internal/

* Move plugins/webroot.py to _internal/

* Move plugins/null.py to _internal/

* Move plugins/standalone.py to _internal/

* add missed internalization

* shorten line

* Update outdated init comment
2019-11-11 15:14:18 -08:00
Brad Warren
641b60b8f0 Remove TLS-SNI objects in ACME (#7535)
* fixes #7214

* update changelog

* remove unused import
2019-11-11 23:04:26 +01:00
ohemorange
d290fe464e Move eff.py to _internal (#7530)
* Move eff.py to _internal

* missed a few certbot.effs in tests

* remove sublime autocompletion

* fix messy scripting
2019-11-11 10:20:05 -08:00
ohemorange
e38aa65cae Move items in certbot/display to _internal (#7532)
* Move display/completer.py to _internal/

* Move display/dummy_readline.py to _internal/

* Move display/enhancements.py to _internal/

* Create __init__.py in _internal/display
2019-11-11 10:19:28 -08:00
ohemorange
8fb9e9adde Move log.py to _internal (#7531)
Part of #5775. Methodology similar to #7528, but slightly more manual.
2019-11-11 10:17:16 -08:00
ohemorange
96e02d614b Make uncomplicated modules private (#7528)
* Create _internal package for Certbot's non-public modules

* Move account.py to _internal

* Move auth_handler.py to _internal

* Move cert_manager.py to _internal

* Move client.py to _internal

* Move error_handler.py to _internal

* Move lock.py to _internal

* Move main.py to _internal

* Move notify.py to _internal

* Move ocsp.py to _internal

* Move renewal.py to _internal

* Move reporter.py to _internal

* Move storage.py to _internal

* Move updater.py to _internal

* update apache and nginx oldest requirements

* Keep the lock file as certbot.lock

* nginx oldest tests still need to rely on newer certbot

* python doesn't have good dependency resolution, so specify the transitive dependency

* update required minimum versions in nginx setup.py
2019-11-08 16:19:21 -08:00
Brad Warren
0a48d7bf7e remove get_systemd_os_info (#7526)
Fixes #7500.
2019-11-08 11:11:03 -08:00
Brad Warren
4b488614cf Remove tls sni common (#7527)
* fixes #7478

* add changelog entry
2019-11-08 15:11:09 +01:00
Shell Chen
f4f16605ed dns-rfc2136: use TCP to query SOA records (#7503)
* Use tcp query on dns-rfc2136 plugin

To improve network robust; fixes #7502.

* Update CHANGELOG.md

* Fix dns-rfc2136 test cases

* Add UDP fallback to dns-rfc2136
2019-11-07 18:37:11 +01:00
ohemorange
b84edfd39a Merge pull request #7515 from certbot/candidate-0.40.1
Candidate 0.40.1
2019-11-06 12:01:59 -08:00
ohemorange
88d9a31cf9 Merge branch 'master' into candidate-0.40.1 2019-11-06 11:47:28 -08:00
Amjad Mashaal
1dff022d05 Deprecate config_changes (#7469)
Closes #7454

* Deprecate config_changes

* Error on config_changes

* Fix tests for main.py

* Fix CHANGELOG entry

* Remove remnants of config_changes

* Fix CHANGELOG and add removed functions
2019-11-06 11:29:07 -08:00
Brad Warren
2b4c2a7f55 Match our Travis logic in Azure. (#7514)
In Travis, the full test suite doesn't run on PRs for point release branches, just on commits for them. I think this behavior makes sense because what we actually want to test before a point release is the exact commit we want to release after any squashing/merging has been done. This PR modifies Azure to match this behavior.

After this PR lands, I need to update the tests required to pass on GitHub.
2019-11-06 10:45:17 -08:00
Adrien Ferrand
baf43a2dbc Pin all build dependencies for the Windows installer (#7504)
This PR uses pipstrap to bootstrap the venv used to build Windows installers. This effectively pin all build dependencies, since pynsist is already installed through pip_install.py script.

* Use pipstrap

* Pin also NSIS version
2019-11-06 10:17:53 -08:00
Brad Warren
ebce0adb5a Merge branch 'master' into candidate-0.40.1 2019-11-05 19:49:27 -08:00
Erica Portnoy
61f77c35c0 Bump version to 1.0.0 2019-11-05 18:32:22 -08:00
Erica Portnoy
1b76faada6 Add contents to CHANGELOG.md for next version 2019-11-05 18:32:22 -08:00
Erica Portnoy
b79bcd0bf2 Release 0.40.1 2019-11-05 18:32:20 -08:00
Erica Portnoy
5f6ab47a7b Update changelog for 0.40.1 release 2019-11-05 18:24:52 -08:00
Brad Warren
d87c905c06 Add back Python 3.4 support (#7510) (#7511)
* Revert "Deprecation warnings for Python 3.4 (#7378)"

This reverts commit 6fcdfb0e50.

* Revert "Migrate certbot-auto users on CentOS 6 to Python 3.6 (#7268)"

This reverts commit e19b2e04c7.

* add changelog entry

* keep mona in authors

(cherry picked from commit 9b848b1d65)
2019-11-05 17:11:23 -08:00
Brad Warren
9b848b1d65 Add back Python 3.4 support (#7510)
* Revert "Deprecation warnings for Python 3.4 (#7378)"

This reverts commit 6fcdfb0e50.

* Revert "Migrate certbot-auto users on CentOS 6 to Python 3.6 (#7268)"

This reverts commit e19b2e04c7.

* add changelog entry

* keep mona in authors
2019-11-05 16:45:08 -08:00
Brad Warren
f555e4bf1f Merge pull request #7505 from certbot/candidate-0.40.0
Release 0.40.0
2019-11-05 13:55:40 -08:00
Erica Portnoy
0de2645a8f Bump version to 0.41.0 2019-11-05 12:53:16 -08:00
Erica Portnoy
fcecdfbcc5 Add contents to CHANGELOG.md for next version 2019-11-05 12:53:16 -08:00
Erica Portnoy
73cd5aa81c Release 0.40.0 2019-11-05 12:52:26 -08:00
Erica Portnoy
3d9d212040 Update changelog for 0.40.0 release 2019-11-05 12:35:33 -08:00
Brad Warren
78deca4f60 Don't use --agree-dev-preview in tests. (#7501) 2019-11-05 17:34:46 +01:00
Adrien Ferrand
3c24ff88cc Build Windows installers with pinned dependencies (#7498)
* Consume constraints file

* Independent pywin32 dependency definition in setup.py and construct.py
2019-11-04 14:20:42 -08:00
alexzorin
08d91b456b Use fresh authorizations in dry runs (#7442)
* acme: re-populate uri in deactivate_authorization

* Use fresh authorizations in dry runs

--dry-run now deactivates 'valid' authorizations if it encounters them
when creating a new order.

Resolves #5116.

* remove unused code

* typo in local-oldest-requirements

* better error handling

* certbot-ci: AUTHREUSE to 100 + unskip dry-run test

* improve test coverage for error cases

* restore newline to local-oldest-requirements.txt
2019-11-04 21:23:25 +01:00
Brandon Moore
1c05b9bd07 Dropped deprecated flags from commands (#7482)
This pull request addresses #7451 by removing the deprecated flags.

* Dropped deprecated flags from commands

* Updated changelog for dropped flags and deleted outdated tests

* removed init-script part of apache test
2019-11-04 09:50:57 -08:00
Brad Warren
fffa74edb2 Clarify when the changelog should be modified (#7491) 2019-11-01 16:40:31 -07:00
Brad Warren
8956de6bee Describe distributed Certbot components. (#7493) 2019-11-01 15:05:41 -07:00
Brad Warren
9bc4286a27 Deprecate more code related to TLS-SNI-01 (#7483)
I tried to finish up #7214 by removing the code in acme but we can't really do that until #7478 is resolved which we cannot do until we release 0.40.0.

Since we have to wait, this PR adds deprecation warnings for code that uses the TLS-SNI-01 code or was only used by the long deprecated TLS-SNI-01 code.

I'd like this PR to land before our next release.

* Deprecate more code related to TLS-SNI-01.

* Assert about warning message.
2019-11-01 15:00:22 -07:00
Brad Warren
3e848b8fce Remove changelog entry about unpackaged scripts. (#7490)
We don't package rebuild_dependencies.py so I don't think we need to mention changes to it in our changelog which is primarily read by users and packagers.
2019-11-01 13:59:17 -07:00
Joona Hoikkala
fb1aafb5d2 Use distro library for all OS version detection (#7467)
This pull request ensures that we use distro package in all the distribution version detection. It also replaces the custom systemd /etc/os-release parsing and adds a few version fingerprints to Apache override selection.

Fixes: #7405

* Revert "Try to use platform.linux_distribution() before distro equivalent (#7403)"

This reverts commit ca3077d034.

* Use distro for all os detection code

* Address review comments

* Add changelog entry

* Added tests

* Fix tests to return a consistent os name

* Do not crash on non-linux systems

* Minor fixes to distro compatibility checks

* Make the tests OS independent

* Update certbot/util.py

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Skip linux specific tests on other platforms

* Test fixes

* Better test state handling

* Lower the coverage target for Windows tests
2019-11-01 10:51:21 -07:00
Brad Warren
f8ff881d23 Don't use acme.test_util outside of acme. (#7484)
`certbot-compatibility-test` is using code in `acme` that I proposed making private and not trivially importable in https://github.com/certbot/certbot/issues/5775.

To fix it, I switched to using Certbot's test utilities which I proposed keeping public to help with writing tests for plugins. When doing this I had to change the name of the key because `rsa1024_key.pem` doesn't exist in Certbot.

I also deleted the keys in `certbot-compatibility-test`'s testdata because because they are unused.
2019-11-01 10:06:32 -07:00
Brad Warren
ef3f8888b5 Don't use dev version of 3.8. (#7485)
Now that Python 3.8 is out, we don't need to use the development version.
2019-11-01 10:06:10 -07:00
Mickaël Schoentgen
a45efcd40d Fix invalid escape sequence \. rebuild_dependencies.py (#7486)
Signed-off-by: Mickaël Schoentgen <contact@tiger-222.fr>
2019-11-01 17:27:18 +01:00
Brad Warren
63d673a3e0 Remove references to TLS-SNI-01 outside of ACME (#7479)
This is a big part of #7214. It removes all references to TLS-SNI-01 outside of acme (and pytest.ini). Those changes will come in a subsequent PR. I thought this one was getting big enough.

* Remove references to TLS-SNI-01 in Apache plugin

* Remove references to TLS-SNI-01 from certbot-nginx

* Remove references to TLS-SNI from Certbot.

* Remove TLS-SNI reference from docs

* add certbot changelog

* Clarify test behavior
2019-10-31 10:17:29 -07:00
Brad Warren
9796128fee Polish changelog (#7476)
I wanted to polish the changelog a bit. Changes made are:

* We don't ship our test farm tests so including info about them in our changelog seems unnecessary.
* I combined and expanded the info about the deprecation of Python 3.4.
2019-10-30 17:07:36 -07:00
Brad Warren
de6b56bec0 Deprecate certbot.plugins.common.TLSSNI01 (#7477)
While working on #7214, I noticed that certbot.plugins.common.TLSSNI01 wasn't printing a deprecation warning and it was still being used in our Apache plugin. This PR fixes that.
2019-10-30 15:19:38 -07:00
James Renken
6f711d9ae8 change random sleep to use fractional seconds (#7473)
If we use fractional instead of whole seconds for the random sleep before renewing, it will reduce bunching of requests to Let's Encrypt's API.
2019-10-30 12:06:30 -07:00
sydneyli
6fcdfb0e50 Deprecation warnings for Python 3.4 (#7378)
Fixes #7367

* Deprecation warnings for Python 3.4 users

* CHANGELOG.md and AUTHORS.md

* double equals typo
2019-10-30 10:57:46 -07:00
Adrien Ferrand
e19b2e04c7 Migrate certbot-auto users on CentOS 6 to Python 3.6 (#7268)
Fixes #7007

Python 3.4 is [EOL](https://www.python.org/dev/peps/pep-0429/), and only Python 3.x version available for CentOS 6 through EPEL is this version, and so is used by `certbot-auto`, the only official way to install Certbot on this platform.

This unpleasant situation becomes a little more uncomfortable, considering that the newest `pip` version (19.2) [just dropped Python 3.4 support](https://github.com/pypa/pip/issues/6685) and will refuse to start on this Python version. We can expect a lot of dependencies to follow this path now.

One direct result of this situation is that a fix to support correctly the ARM platforms requires to upgrade `pip` to 19.2 for `certbot-auto`. So this is not possible right now.

Then, let's upgrade Certbot instances on CentOS 6 to a supported version of Python 3.

This PR proposes a new bootstrap approach for CentOS 6 platform, `BootstrapRpmPython3Legacy`, that will install Python 3.6 from [SCL](https://www.softwarecollections.org) (the latest one available for now on CentOS 6). In term of Python 3 specific bootstrap methods, I take the occasion here to completely separate the bootstrap of CentOS 6 as a legacy system, from the RPM-based newest systems (like Fedora 29+) that are simply dropping support for Python 2.x. This is in prevision of future migration for all systems on Python 3.x, that is a different problematic than supporting old systems.

* Add logic

* Rebuilt letsencrypt-auto

* Fix logic

* Focus on specific packages

* Maintain PATH for further invocations of letsencrypt-auto after bootstrap.

* Various corrections

* Fix farm test for RHEL6

* Working centos6 letsencrypt-auto self tests

* Fix test_sdist for CentOS 6

* Corrections

* Work in progress

* Working configuration

* Fix typo

* Remove EPEL. Add a test.

* Update letsencrypt-auto-source/letsencrypt-auto.template

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Improvements after review

* Improvements

* Add a comment

* Add a test

* Update a test

* Corrections

* Update function return

* Work in progress

* Correct behavior on oracle linux 6.

* Corrections

* Rebuild script

* Add letsencrypt-auto tests for oraclelinux6

* Update tox.ini

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update letsencrypt-auto-source/letsencrypt-auto

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update letsencrypt-auto-source/tests/oraclelinux6_tests.sh

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update letsencrypt-auto-source/letsencrypt-auto.template

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update letsencrypt-auto-source/letsencrypt-auto

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update letsencrypt-auto-source/letsencrypt-auto

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update letsencrypt-auto-source/letsencrypt-auto.template

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update letsencrypt-auto-source/tests/oraclelinux6_tests.sh

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Remove specific code for scientific linux

* Change some variables names

* Update letsencrypt-auto-source/tests/oraclelinux6_tests.sh

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Various corrections

* Fix tests

* Add a comment

* Update message

* Fix test message

* Update letsencrypt-auto-source/letsencrypt-auto.template

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update letsencrypt-auto-source/letsencrypt-auto

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update letsencrypt-auto-source/letsencrypt-auto

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update scripts

* More focused assertion

* Add back a test

* Update script

* Update letsencrypt-auto-source/letsencrypt-auto.template

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update letsencrypt-auto-source/letsencrypt-auto.template

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Check quiet mode

* Add changelog

* Update letsencrypt-auto-source/tests/oraclelinux6_tests.sh

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>
2019-10-30 10:39:45 -07:00
Adrien Ferrand
2dbe47f3a7 Create a release pipeline on Azure for Windows installer (#7441)
This PR creates a pipeline triggered on tag push matching v0.* (eg. v0.40.0).

Once triggered, this pipeline will build the windows installer, and run integration tests on it, like for the pipeline run nightly.

I also add a simple script to extract from CHANGELOG.md file to extract the relevant part to put it in the body of the GitHub release. I believe it makes things nicer.

* Create release pipeline

* Relax condition on tags

* Put beta keyword

* Update job name

* Fix release pipeline
2019-10-30 10:19:10 -07:00
Brad Warren
0f31d9b7ac Remove skip_unless cruft (#7410)
* Remove skip_unless cruft.

* remove unused import
2019-10-24 14:46:55 +02:00
Brad Warren
60673e8a81 Remove AppVeyor. (#7440) 2019-10-24 12:48:00 +02:00
Brad Warren
3132c32c26 Update pluggy pinning. (#7459) 2019-10-23 10:50:18 +02:00
Brad Warren
db46326e95 Run at 4:00AM UTC not 0:04AM UTC. (#7460)
Fixes [cron syntax](https://docs.microsoft.com/en-us/azure/devops/pipelines/build/triggers?view=azure-devops&tabs=yaml#supported-cron-syntax) to get the behavior I had in mind in https://github.com/certbot/certbot/pull/7377#discussion_r331295897.
2019-10-21 14:42:51 -07:00
Brad Warren
44cc8d7a3c Require newer versions of oauth2client (#7458)
Over the weekend, nightly tests on Windows failed for certbot-dns-google: https://dev.azure.com/certbot/web/build.aspx?pcguid=74ef9c03-9faf-405b-9d03-9acf8c43e8d6&builduri=vstfs%3a%2f%2f%2fBuild%2fBuild%2f72

The error occurred inside `oauth2client`'s locking code and the failure seems spurious as it did not reproduce this morning: https://dev.azure.com/certbot/certbot/_build/results?buildId=73

I could not find a relevant changelog entry in `oauth2client` saying they've fixed the problem, but the problematic code no longer exists in `oauth2client>=4.0`. This PR updates our minimum dependency required in an attempt to avoid spurious failures for us in the future. The only downside I am aware of is it'll make it harder for certbot-dns-google to be packaged in Debian Old Stable or Ubuntu 16.04, but I don't expect either of those things to happen anytime soon.

* bump oauth2client dep

* Update dev_constraints.txt.

* Add changelog entry for packagers.
2019-10-21 13:54:17 -07:00
Brad Warren
f8e097a061 Remove warning about rename. (#7453) 2019-10-19 08:09:08 +02:00
Brad Warren
37b3c22dee Run nightly on Azure even if no commits landed. (#7455) 2019-10-19 08:06:37 +02:00
Victor Shih
032178bea0 Clarify possible existence of /etc/letsencrypt/cli.ini (#7449) 2019-10-18 13:36:45 -07:00
alexzorin
118cb3c9b1 cli: allow --dry-run to be combined with --server (#7436)
The value of --server will now be respected, except when it is the
default value, in which case it will be changed to the staging server,
preserving Certbot's existing behavior.
2019-10-10 00:09:25 +02:00
Brad Warren
717afebcff Upload coverage for integration tests (#7433)
* Upload coverage for integration tests.

* Use in not containsValue.
2019-10-09 23:39:49 +02:00
Adrien Ferrand
ec3ec9068c Upgrade to pywin32>=225 and fix unit tests (#7429)
Fixes #7426
2019-10-08 16:17:08 -07:00
Brad Warren
f755cfef48 Add final newlines to files. (#7432)
More conventional and makes it nicer when doing things like running cat to quickly look at the file like I was doing when I noticed this.
2019-10-08 16:16:04 -07:00
Brad Warren
c1f4b86d34 Use shared variable group (#7431)
When setting up Azure Pipelines, I didn't like having to define codecov_token for each pipeline. This works around it by using a shared variable group.

You can see this working successfully at https://dev.azure.com/certbot/certbot/_build/results?buildId=3.

* Use certbot-common.

* update instructions
2019-10-08 16:12:02 -07:00
Adrien Ferrand
fcc398831b Create a new CI for Certbot on Windows using Azure Pipelines (#7377)
This PR defines pipelines that can be run on Azure Pipelines. Currently there are two:
* `.azure-pipelines/main.yml` is the main one, executed on PRs for master, and pushes to master,
* `.azure-pipelines/advanced.yml` add installer testing on top of the main pipeline, and is executed for `test-*` branches, release branches, and nightly run for master.

These two pipelines covers all existing stuff done by AppVeyor currently, and so AppVeyor can be decommissioned once Azure Pipelines is operational.

You can see working pipeline in my fork:
* a PR for `master` (so using main pipeline): https://github.com/adferrand/certbot/pull/65
* a PR for `test-something` (so using advanced pipeline): https://github.com/adferrand/certbot/pull/66
* uploaded coverage from Azure Pipelines: 499aa2cbf2/build

Once this PR is merged, we need to enable Azure Pipelines for Certbot. Instructions are written in `azure-pipelines/INSTALL.md`. This document also references all access rights required to Azure Pipelines onto GitHub to make the CI process work.

Future work for future PRs:
* create a CD pipeline for the releases that will push the installer to GitHub releases
* implement a solution to generate notification on IRC or Mattermost when a nightly build fails

* Define pipelines

* Update locations

* Update nightly

* Use x86

* Update nightly.yml for Azure Pipelines

* Run script

* Use script

* Update install

* Use local installation

* Register warnings

* Fix pywin32 loading

* Clean context

* Enable coverage publication

* Consume codecov token

* Document installation

* Update tool to upload coverage

* Prepare pipeline artifacts

* Update artifact ignore

* Protect against codecov failures

* Add a comment about codecov

* Add a comment on RW access asked by Azure

* Add instructions

* Rename pipeline file

* Update instructions

* Update .azure-pipelines/templates/tests-suite.yml

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update .azure-pipelines/INSTALL.md

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Modified scheduled pipeline

* Add comment

* Remove dynamic version-based installer name
2019-10-08 14:40:17 -07:00
Andrzej Górski
9da07590bd Remove --fast from the test farm tests (#7427) 2019-10-08 21:24:55 +02:00
Brad Warren
0cfedbc5f5 Add test farm tests for Debian 10 (#7421)
Fixes #7225.

I got the AMI ID from https://wiki.debian.org/Cloud/AmazonEC2Image/Buster.

You can see all test farm tests including test_tests.sh passing with these changes at https://travis-ci.com/certbot/certbot/builds/130318446.
2019-10-03 15:08:24 -07:00
Jacob Hoffman-Andrews
3608abb01a Remove unnecessary account ID match check. (#7416)
* Remove unnecessary account ID match check.

Right now the Account object calculates an ID using md5. This is
unnecessary and causes problems on FIPS systems that forbid md5. It's
just as good to pick a random series of bytes for the ID, since the ID
gets read out of renewal/foo.conf.

However, if we switched the algorithm right now, we could wind up
breaking forward compatibility / downgradeability, since older versions
would run into this check.

Removing this check now lays the ground to change the ID-calculation
algorithm in the future.

Related to #1948 and
https://github.com/certbot/certbot/pull/1013#issuecomment-149983479.

* Remove test.

* Remove unused import.
2019-10-02 14:44:25 -07:00
Brad Warren
4739a0616d Merge pull request #7415 from certbot/candidate-0.39.0
Candidate 0.39.0
2019-10-01 13:34:47 -07:00
Erica Portnoy
6e38ad9cce Bump version to 0.40.0 2019-10-01 13:04:10 -07:00
Erica Portnoy
4599aff07f Add contents to CHANGELOG.md for next version 2019-10-01 13:04:10 -07:00
Erica Portnoy
0b605333d9 Release 0.39.0 2019-10-01 13:04:08 -07:00
Erica Portnoy
9c18de993d Update changelog for 0.39.0 release 2019-10-01 12:48:40 -07:00
Brad Warren
e3dbd9ce4a Keep compatibility with IE11 in the Nginx plugin (#7414)
As discussed at https://github.com/mozilla/server-side-tls/issues/263, Mozilla's current intermediate recommendations drop support for some non-EOL'd versions of IE. [Their TLS recommendations were updated to suggest a couple possible workarounds for people who need this support](https://github.com/mozilla/server-side-tls/pull/264) and [April suggested that we make this change in Certbot](https://github.com/mozilla/server-side-tls/issues/263#issuecomment-537085728).

We know `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA` translates to `ECDHE-RSA-AES128-SHA` because [nginx uses the same cipher format as OpenSSL](https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_ciphers) and the translation is shown in the table at https://github.com/mozilla/server-side-tls/blob/gh-pages/Cipher_Suites.mediawiki.

The risk of regressions making this change is low as we always had this ciphersuite enabled just a few releases ago: https://github.com/certbot/certbot/tree/v0.36.0/certbot-nginx/certbot_nginx

* Keep compatibility with IE11

* update changelog
2019-10-01 10:34:11 -07:00
Brad Warren
c2480b29f7 Add CentOS 8 support to certbot-auto. (#7406)
Fixes #7396.
2019-09-30 09:19:05 -07:00
Brad Warren
6ac8633363 Remove listing for broken icecast plugin. (#7408)
The repo description for the [3rd party Icecast plugin](https://github.com/e00E/lets-encrypt-icecast) says that the plugin isn't currently working and the repository hasn't been updated since 2017. Since it seems broken and unmaintained, let's remove it from the list of third party plugins.

I would happily add it again to the list of third party plugins if people fix and maintain it.
2019-09-27 12:47:12 -07:00
Brad Warren
8a4c2f505f Remove listing for broken heroku plugin (#7409)
The README for the [3rd party heroku plugin](https://github.com/gboudreau/certbot-heroku) says it has been deprecated. Because of this, let's remove it from the list of third party plugins.
2019-09-27 12:46:56 -07:00
Joona Hoikkala
ca3077d034 Try to use platform.linux_distribution() before distro equivalent (#7403)
Try to primarily fall back to using `platform.linux_distribution()` if `/etc/os-release` isn't available. Only use `distro.linux_distribution()` on Python >= 3.8.

* Try to use platform.linux_distribution() before distro equivalent

* Fix tests for py38

* Added changelog entry
2019-09-27 09:50:38 -07:00
Kenichi Maehashi
6c89aa5227 Fix to run with Apache on RHEL 6 (#7401)
This PR fixes a regression in #7337 (0.38.0) that certbot cannot run with Apache on RHEL 6.

In RHEL 6, `distro.linux_distribution()` returns `RedHatEnterpriseServer`.

In RHEL 6:

```py
>>> import distro
>>> distro.linux_distribution()
(u'RedHatEnterpriseServer', u'6.10', u'Santiago')

>>> import platform
>>> platform.linux_distribution()
('Red Hat Enterprise Linux Server', '6.10', 'Santiago')
```

In RHEL 7:

```py
>>> import distro
>>> distro.linux_distribution()
('Red Hat Enterprise Linux Server', '7.6', 'Maipo')

>>> import platform
>>> platform.linux_distribution()
('Red Hat Enterprise Linux Server', '7.6', 'Maipo')
```

* fix to run with Apache on RHEL 6

* fix docs
2019-09-26 13:25:48 -07:00
Brad Warren
8cb57566c0 List support for Python 3.8 (#7392)
Fixes #7368.

When updating the changelog, I replaced the line about running tests on Python 3.8 because I personally think that support for Python 3.8 is the most relevant information for our users/packagers about our changes in this area.

* List support for Python 3.8.

* Update changelog.
2019-09-24 11:38:38 -07:00
ohemorange
18e6c6c2a8 Don't send OCSP requests for expired certificates (#7387)
Fixes #7152.

* don't check ocsp if cert is expired when getting cert information

* don't check ocsp if the cert is expired in ocsp_revoked

* update tests

* update changelog

* move pytz import to the top of the test file
2019-09-23 17:20:11 -07:00
Adrien Ferrand
e402993c34 [Windows] Create a certbot renew scheduled task using the installer (#7371)
This PR implements the item "register a scheduled task for certificate renewal" from the list of requirements described in #7365.

This PR adds required instructions in the NSIS installer for Certbot to create a task, named "Certbot Renew Task" in the Windows Scheduler. This task is run twice a day, to execute the command certbot renew and keep the certificates up-to-date.

Uninstalling Certbot will also remove this scheduled task.

* Implementation

* Corrections

* Update template.nsi

* Improve scripts

* Add a random delay of 12 hours

* Synchronize template against default one in pynsist 2.4

* Clean config of scheduled task

* Install only in AllUsers mode

* Add comments

* Remove the logic of single user install
2019-09-23 12:29:18 -07:00
Brad Warren
754c34c120 Fix Windows sdist. (#7384) 2019-09-20 17:21:07 +02:00
Brad Warren
2883ca839e Use xenial globally (#7380)
As described at https://github.com/certbot/certbot/pull/7372#discussion_r323592366, Travis is transitioning people to Xenial, but it seems this transition still may not be complete as some of our jobs ran on Trusty with all references to `dist` removed as seen at https://travis-ci.com/certbot/certbot/builds/127960999.

This PR sets `dist: xenial` globally and overrides it as needed for the oldest tests.

* Set xenial globally.

* Use trusty in all oldest tests.
2019-09-17 15:24:53 -07:00
ohemorange
fb6aad28bd Get integration tests working on python 3.8 (#7372)
* Get integration tests working on python 3.8

* Run unit tests on py38

* Update coveragercs to use coverage 4.5+ format

* remove line added to tox.ini

* update changelog

* xenial is the new travis default; no need to specify in .travis.yml
2019-09-16 14:14:26 -04:00
Adrien Ferrand
ab76834100 [Windows|Linux] Forbid os.stat and os.fstat (#7325)
Fixes #7212

This PR forbid os.stat and os.fstat, and fix or provide alternatives to avoid its usage in certbot outside of certbot.compat.filesystem.

* Reimplement private key mode propagation

* Remove other os.stat

* Remove last call of os.stat in certbot package

* Forbid stat and fstat

* Implement mode comparison checks

* Add unit tests

* Update certbot/compat/filesystem.py

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update certbot/compat/filesystem.py

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Handle case where multiple ace concerns a given SID in has_min_permissions

* Add a new test scenario

* Add a simple test for has_same_ownership

* Fix name function

* Add a comment explaining an ACE structure

* Move a test in its dedicated class

* Improve a message error

* Calculate has_min_permission result using effective permission rights to be more generic.

* Change an exception message

* Add comments, avoid to skip a test.

* Update certbot/compat/filesystem.py

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>
2019-09-06 14:30:25 -07:00
Brad Warren
ada2f5c767 Simplify testing of RHEL 8. (#7323) 2019-09-06 08:59:24 +02:00
ohemorange
e4af1f3319 Disable TLS session tickets in Nginx (#7355)
* Find OpenSSL version

* Create and update various config files

* Update logic to use new version constraints

* SSL_OPTIONS_HASHES_NEW and SSL_OPTIONS_HASHES_MEDIUM were just being used for testing, and maintaining them is becoming untenable, so remove them.

* if we don't know the openssl version, we can't turn off session tickets

* add unit test for _get_openssl_version

* add unit tests

* placate lint

* Fix docs and tests and clean up code

* use python correctly

* update changelog

* Lint

* make comment a comment
2019-09-05 13:51:56 -07:00
ohemorange
ab0e382829 Merge pull request #7364 from certbot/candidate-0.38.0
Update files from 0.38.0 release
2019-09-04 18:23:50 -04:00
Adrien Ferrand
ed0b8e4af5 [Windows] Create an installer for Certbot (#7324)
This PR is the first step to create an official distribution channel of Certbot for Windows. It consists essentially in creating a proper Certbot Windows installer.

Usually distributing an application requires, in a way or another, to stabilize the application logic and its dependencies around a given version. On Windows, this usually takes the form of a freezed application, that vendors its dependencies into a single executable.

There are two well-known solutions to create an executable shipping a Python application on Windows: [py2exe](http://www.py2exe.org/) and [pyinstaller](https://www.pyinstaller.org/). However these solutions create self-executable `.EXE` files: you run the `.EXE` file that launches immediately the software.

This is not a end-user solution. Indeed when a Windows user wants to install a piece of software, he expects to find and download an installer. When run the installer would interface with Windows to setup configuration entries in the Registry, update the environment variable, add shortcuts in the Start Menu, and declare a uninstaller entry into the Uninstaller Manager. Quite similarly, this is what you would get from a `.deb` or `.rpm` package.

A solution that builds proper installers is [pynsis](https://pynsist.readthedocs.io/en/latest/). It is a Python project that constructs installers for Python software using [NSIS](https://sourceforge.net/projects/nsis/), the most known free Windows installer builder solution.

This PR uses pynsist to build a Windows installer. The Python script to launch the installer build is `.\windows-installer\construct.py`. Once finished, the installer is located in `.\windows-installer\build\nsis`.

This installer will do the following operations during the installation:
* copy in the install path a full python distribution used exclusively for Certbot
* copy all Python requirements gathered from the `setup.py` of relevant certbot projects
* copy `certbot` and `acme`
* pre-build python binary assets
* register the existence of the application correctly in Windows Registry
* prepare a procedure to uninstall Certbot
* and of course, expose `certbot` executable to the Windows command line, like on Linux, to be able to launch it as any CLI application from Batch or Powershell

This installer support updates: downloading a new version of it and running it on a Windows with existing installation of Certbot will replace it with the new version.

Future capabilities not included in this PR:
* auto-update of Certbot when a new release is available
* online documentation for Windows
* register a scheduled task for certificate renewal
* installer distribution (continuous deployment + distribution channels)
* method to check the downloaded installer is untampered

* Setup config

* Fix shortcut

* Various improvments

* Update windows-installer/construct.py

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Split into several method

* Change installer name

* Remove DNS plugins for now

* Add a comment about administrator privileges

* Update welcome

* Control python version

* Control bitness

* Update windows-installer/construct.py

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update windows-installer/construct.py

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>

* Update windows-installer/construct.py

Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>
2019-09-03 16:30:13 -07:00
Brad Warren
8a570b18e9 Bump version to 0.39.0 2019-09-03 12:49:30 -07:00
Brad Warren
deb0168c09 Add contents to CHANGELOG.md for next version 2019-09-03 12:49:29 -07:00
Brad Warren
46a12d0127 Release 0.38.0 2019-09-03 12:49:28 -07:00
Brad Warren
6d4baec955 Update changelog for 0.38.0 release 2019-09-03 12:42:35 -07:00
Brad Warren
4eaa06d58e list py37 support (#7360)
These plugins also support Python 3.7. You can see tests passing at https://travis-ci.com/certbot/certbot/jobs/228820500.
2019-08-28 11:10:13 -07:00
ohemorange
0fe28a6459 Replace platform.linux_distribution with distro.linux_distribution (#7337)
Smallest possible fix for #7106 

* Replace platform.linux_dependencies with distro.linux_dependencies

* run build.py

* Add minimum version of 1.0.1

* Pin back requests package

* Update changelog
2019-08-27 18:31:35 -07:00
Adrien Ferrand
aaeb4582e2 Fix PYTHONPATH in integration tests (#7357)
This PR supersedes #7353.

It fixes the execution of nginx oldest tests when these tests are executed on top of the modifications made in #7337. This execution failure revealed the fact that in some cases, the wrong version of certbot logic was used during integration tests (namely the logic lying in the codebase of the branch built, instead of the logic from the version of certbot declared by certbot-nginx for instance).

I let you appreciate my inline comment for the explanation and the workaround.

Thanks a lot to @bmw who found this python/pytest madness.

You can see the oldest tests succeeding with the logic of #7337 + this PR here: https://travis-ci.com/certbot/certbot/builds/124816254

* Remove certbot root from PYTHONPATH during integration tests

* Add a biiiiig comment.
2019-08-27 16:25:31 -07:00
schoen
fdb0a14812 Merge pull request #7336 from certbot/update-debian-instructions
Update Debian instructions in docs
2019-08-23 13:39:55 -07:00
Adrien Ferrand
0324d1740e Ensure relpath is executed on paths in the same drive (#7335)
On Windows you can have several drives (`C:`, `D:`, ...), that is the roughly (really roughly) equivalent of mount points, since each drive is usually associated to a specific physical partition.

So you can have paths like `C:\one\path`, `D:\another\path`.

In parallel, `os.path.relpath(path, start='.')` calculates the relative path between the given `path` and a `start` path (current directory if not provided). In recent versions of Python, `os.path.relpath` will fail if `path` and `start` are not on the same drive, because a relative path between two paths like `C:\one\path`, `D:\another\path` is not possible.

In saw unit tests failing because of this in two locations. This occurs when the certbot codebase that is tested is on a given drive (like `D:`) while the default temporary directory used by `tempfile` is on another drive (most of the time located in `C:` drive).

This PR fixes that.
2019-08-23 12:53:30 -07:00
Brad Warren
ce325db4e4 address review comments 2019-08-23 12:43:05 -07:00
Brad Warren
74e6736c79 use latest RHEL 7 AMI (#7349) 2019-08-22 09:28:57 -07:00
ohemorange
2ed7608ed3 Merge pull request #7347 from certbot/candidate-0.37.2
Release 0.37.2
2019-08-21 16:21:23 -07:00
ohemorange
eb02acfc4b Merge branch 'master' into candidate-0.37.2 2019-08-21 16:03:51 -07:00
Erica Portnoy
4f19d516d6 Bump version to 0.38.0 2019-08-21 15:23:15 -07:00
Erica Portnoy
3dd918b024 Add contents to CHANGELOG.md for next version 2019-08-21 15:23:15 -07:00
Erica Portnoy
8320018978 Release 0.37.2 2019-08-21 15:23:14 -07:00
Erica Portnoy
c17f2ff6b0 Update changelog for 0.37.2 release 2019-08-21 14:48:40 -07:00
Brad Warren
46a2ef8ba1 Stop turning session tickets off in Nginx (#7344) (#7345)
Related to #7322.

* Stop turning session tickets off in Nginx

* update changelog

(cherry picked from commit 17c1d016c1)
2019-08-21 14:44:09 -07:00
ohemorange
17c1d016c1 Stop turning session tickets off in Nginx (#7344)
Related to #7322.

* Stop turning session tickets off in Nginx

* update changelog
2019-08-21 14:29:10 -07:00
Brad Warren
70ed791709 Update Debian instructions in docs. 2019-08-16 11:42:34 -07:00
Adrien Ferrand
d39f63feca Use travis_retry for farm tests (#7327)
* Use travis_retry in travis builds to retry the farm tests

* travis_retry is a bash function, so it can be called only from current bash

* Update .travis.yml

* Update .travis.yml
2019-08-16 14:55:45 +02:00
Adrien Ferrand
6882f006ac [Windows] Fix closing files descriptors during unit tests (#7326)
* Fix file descriptor cleanup during tests on Windows

* Fix lint

* Remove useless tearDown

* Clean pylint
2019-08-16 11:08:42 +02:00
Adrien Ferrand
9a047a6996 Clean travis config (#7328)
This PR removes some useless capabilities in .travis.yml that are associated to the jobs. This concerns mainly sudo and docker.
2019-08-15 16:41:51 -07:00
Matthias Bilger
a8bd839223 Added DNS plugin for ISPConfig to list (#7332) 2019-08-15 14:43:14 -07:00
tyborr
a1aef4c15c Fix Certbot's Apache plugin doesn't work on Scientific Linux (#7294)
This PR adds OVERRIDE_CLASS in certbot-apache/entrypoint.py for Scientific Linux. Fixes #7248.

* add OVERRIDE_CLASS for Scientific Linux os name

* add entry for Scientific Linux using "scientific" as key

* Update changelog
2019-08-12 12:59:29 -07:00
ohemorange
cb7598b007 Merge pull request #7320 from certbot/merge-cand-0.37.1
Merge cand 0.37.1
2019-08-08 18:01:27 -07:00
258 changed files with 3507 additions and 5000 deletions

119
.azure-pipelines/INSTALL.md Normal file
View File

@@ -0,0 +1,119 @@
# Configuring Azure Pipelines with Certbot
Let's begin. All pipelines are defined in `.azure-pipelines`. Currently there are two:
* `.azure-pipelines/main.yml` is the main one, executed on PRs for master, and pushes to master,
* `.azure-pipelines/advanced.yml` add installer testing on top of the main pipeline, and is executed for `test-*` branches, release branches, and nightly run for master.
Several templates are defined in `.azure-pipelines/templates`. These YAML files aggregate common jobs configuration that can be reused in several pipelines.
Unlike Travis, where CodeCov is working without any action required, CodeCov supports Azure Pipelines
using the coverage-bash utility (not python-coverage for now) only if you provide the Codecov repo token
using the `CODECOV_TOKEN` environment variable. So `CODECOV_TOKEN` needs to be set as a secured
environment variable to allow the main pipeline to publish coverage reports to CodeCov.
This INSTALL.md file explains how to configure Azure Pipelines with Certbot in order to execute the CI/CD logic defined in `.azure-pipelines` folder with it.
During this installation step, warnings describing user access and legal comitments will be displayed like this:
```
!!! ACCESS REQUIRED !!!
```
This document suppose that the Azure DevOps organization is named _certbot_, and the Azure DevOps project is also _certbot_.
## Useful links
* https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema
* https://www.azuredevopslabs.com/labs/azuredevops/github-integration/
* https://docs.microsoft.com/en-us/azure/devops/pipelines/ecosystems/python?view=azure-devops
## Prerequisites
### Having a GitHub account
Use your GitHub user for a normal GitHub account, or a user that has administrative rights to the GitHub organization if relevant.
### Having an Azure DevOps account
- Go to https://dev.azure.com/, click "Start free with GitHub"
- Login to GitHub
```
!!! ACCESS REQUIRED !!!
Personal user data (email + profile info, in read-only)
```
- Microsoft will create a Live account using the email referenced for the GitHub account. This account is also linked to GitHub account (meaning you can log it using GitHub authentication)
- Proceed with account registration (birth date, country), add details about name and email contact
```
!!! ACCESS REQUIRED !!!
Microsoft proposes to send commercial links to this mail
Azure DevOps terms of service need to be accepted
```
_Logged to Azure DevOps, account is ready._
### Installing Azure Pipelines to GitHub
- On GitHub, go to Marketplace
- Select Azure Pipeline, and "Set up a plan"
- Select Free, then "Install it for free"
- Click "Complete order and begin installation"
```
!!! ACCESS !!!
Azure Pipeline needs RW on code, RO on metadata, RW on checks, commit statuses, deployments, issues, pull requests.
RW access here is required to allow update of the pipelines YAML files from Azure DevOps interface, and to
update the status of builds and PRs on GitHub side when Azure Pipelines are triggered.
Note however that no admin access is defined here: this means that Azure Pipelines cannot do anything with
protected branches, like master, and cannot modify the security context around this on GitHub.
Access can be defined for all or only selected repositories, which is nice.
```
- Redirected to Azure DevOps, select the account created in _Having an Azure DevOps account_ section.
- Select the organization, and click "Create a new project" (let's name it the same than the targetted github repo)
- The Visibility is public, to profit from 10 parallel jobs
```
!!! ACCESS !!!
Azure Pipelines needs access to the GitHub account (in term of beeing able to check it is valid), and the Resources shared between the GitHub account and Azure Pipelines.
```
_Done. We can move to pipelines configuration._
## Import an existing pipelines from `.azure-pipelines` folder
- On Azure DevOps, go to your organization (eg. _certbot_) then your project (eg. _certbot_)
- Click "Pipelines" tab
- Click "New pipeline"
- Where is your code?: select "__Use the classic editor__"
__Warning: Do not choose the GitHub option in Where is your code? section. Indeed, this option will trigger an OAuth
grant permissions from Azure Pipelines to GitHub in order to setup a GitHub OAuth Application. The permissions asked
then are way too large (admin level on almost everything), while the classic approach does not add any more
permissions, and works perfectly well.__
- Select GitHub in "Select your repository section", choose certbot/certbot in Repository, master in default branch.
- Click on YAML option for "Select a template"
- Choose a name for the pipeline (eg. test-pipeline), and browse to the actual pipeline YAML definition in the
"YAML file path" input (eg. `.azure-pipelines/test-pipeline.yml`)
- Click "Save & queue", choose the master branch to build the first pipeline, and click "Save and run" button.
_Done. Pipeline is operational. Repeat to add more pipelines from existing YAML files in `.azure-pipelines`._
## Add a secret variable to a pipeline (like `CODECOV_TOKEN`)
__NB: Following steps suppose that you already setup the YAML pipeline file to
consume the secret variable that these steps will create as an environment variable.
For a variable named `CODECOV_TOKEN` consuming the variable `codecov_token`,
in the YAML file this setup would take the form of the following:
```
steps:
- script: ./do_something_that_consumes_CODECOV_TOKEN # Eg. `codecov -F windows`
env:
CODECOV_TOKEN: $(codecov_token)
```
To set up a variable that is shared between pipelines, follow the instructions
at
https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups.
When adding variables to a group, don't forget to tick "Keep this value secret"
if it shouldn't be shared publcily.

View File

@@ -0,0 +1,20 @@
# Advanced pipeline for isolated checks and release purpose
trigger:
- test-*
- '*.x'
pr:
- test-*
# This pipeline is also nightly run on master
schedules:
- cron: "0 4 * * *"
displayName: Nightly build
branches:
include:
- master
always: true
jobs:
# Any addition here should be reflected in the release pipeline.
# It is advised to declare all jobs here as templates to improve maintainability.
- template: templates/tests-suite.yml
- template: templates/installer-tests.yml

12
.azure-pipelines/main.yml Normal file
View File

@@ -0,0 +1,12 @@
trigger:
# apache-parser-v2 is a temporary branch for doing work related to
# rewriting the parser in the Apache plugin.
- apache-parser-v2
- master
pr:
- apache-parser-v2
- master
- '*.x'
jobs:
- template: templates/tests-suite.yml

View File

@@ -0,0 +1,13 @@
# Release pipeline to build and deploy Certbot for Windows for GitHub release tags
trigger:
tags:
include:
- v*
pr: none
jobs:
# Any addition here should be reflected in the advanced pipeline.
# It is advised to declare all jobs here as templates to improve maintainability.
- template: templates/tests-suite.yml
- template: templates/installer-tests.yml
- template: templates/changelog.yml

View File

@@ -0,0 +1,14 @@
jobs:
- job: changelog
pool:
vmImage: vs2017-win2016
steps:
- bash: |
CERTBOT_VERSION="$(python -c "import certbot; print(certbot.__version__)")"
"${BUILD_REPOSITORY_LOCALPATH}\tools\extract_changelog.py" "${CERTBOT_VERSION}" >> "${BUILD_ARTIFACTSTAGINGDIRECTORY}/release_notes.md"
displayName: Prepare changelog
- task: PublishPipelineArtifact@1
inputs:
path: $(Build.ArtifactStagingDirectory)
artifact: changelog
displayName: Publish changelog

View File

@@ -0,0 +1,32 @@
jobs:
- job: installer
pool:
vmImage: vs2017-win2016
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: 3.7
architecture: x86
addToPath: true
- script: python windows-installer/construct.py
displayName: Build Certbot installer
- task: CopyFiles@2
inputs:
sourceFolder: $(System.DefaultWorkingDirectory)/windows-installer/build/nsis
contents: '*.exe'
targetFolder: $(Build.ArtifactStagingDirectory)
- task: PublishPipelineArtifact@1
inputs:
path: $(Build.ArtifactStagingDirectory)
artifact: windows-installer
displayName: Publish Windows installer
- script: $(Build.ArtifactStagingDirectory)\certbot-beta-installer-win32.exe /S
displayName: Install Certbot
- script: |
python -m venv venv
venv\Scripts\python tools\pip_install.py -e certbot-ci
displayName: Prepare Certbot-CI
- script: |
set PATH=%ProgramFiles(x86)%\Certbot\bin;%PATH%
venv\Scripts\python -m pytest certbot-ci\certbot_integration_tests\certbot_tests -n 4
displayName: Run integration tests

View File

@@ -0,0 +1,38 @@
jobs:
- job: test
pool:
vmImage: vs2017-win2016
strategy:
matrix:
py35:
PYTHON_VERSION: 3.5
TOXENV: py35
py37-cover:
PYTHON_VERSION: 3.7
TOXENV: py37-cover
integration-certbot:
PYTHON_VERSION: 3.7
TOXENV: integration-certbot
PYTEST_ADDOPTS: --numprocesses 4
variables:
- group: certbot-common
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: $(PYTHON_VERSION)
addToPath: true
- script: python tools/pip_install.py -U tox coverage
displayName: Install dependencies
- script: python -m tox
displayName: Run tox
# We do not require codecov report upload to succeed. So to avoid to break the pipeline if
# something goes wrong, each command is suffixed with a command that hides any non zero exit
# codes and echoes an informative message instead.
- bash: |
curl -s https://codecov.io/bash -o codecov-bash || echo "Failed to download codecov-bash"
chmod +x codecov-bash || echo "Failed to apply execute permissions on codecov-bash"
./codecov-bash -F windows || echo "Codecov did not collect coverage reports"
condition: in(variables['TOXENV'], 'py37-cover', 'integration-certbot')
env:
CODECOV_TOKEN: $(codecov_token)
displayName: Publish coverage

View File

@@ -6,13 +6,13 @@ coverage:
flags: linux
# Fixed target instead of auto set by #7173, can
# be removed when flags in Codecov are added back.
target: 97.5
target: 97.4
threshold: 0.1
base: auto
windows:
flags: windows
# Fixed target instead of auto set by #7173, can
# be removed when flags in Codecov are added back.
target: 97.6
target: 97.4
threshold: 0.1
base: auto

View File

@@ -1,2 +1,5 @@
[run]
omit = */setup.py
[report]
omit = */setup.py

View File

@@ -41,7 +41,7 @@ load-plugins=linter_plugin
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=fixme,locally-disabled,locally-enabled,abstract-class-not-used,abstract-class-little-used,bad-continuation,too-few-public-methods,no-self-use,invalid-name,too-many-instance-attributes,cyclic-import,duplicate-code
disable=fixme,locally-disabled,locally-enabled,abstract-class-not-used,abstract-class-little-used,bad-continuation,no-self-use,invalid-name,cyclic-import,duplicate-code,design
# abstract-class-not-used cannot be disabled locally (at least in
# pylint 1.4.1), same for abstract-class-little-used
@@ -297,40 +297,6 @@ valid-classmethod-first-arg=cls
valid-metaclass-classmethod-first-arg=mcs
[DESIGN]
# Maximum number of arguments for function / method
max-args=6
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=(unused)?_.*|dummy
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of statements in function / method body
max-statements=50
# Maximum number of parents for a class (see R0901).
max-parents=12
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to

View File

@@ -1,4 +1,5 @@
language: python
dist: xenial
cache:
directories:
@@ -8,6 +9,8 @@ before_script:
- 'if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ulimit -n 1024 ; fi'
# On Travis, the fastest parallelization for integration tests has proved to be 4.
- 'if [[ "$TOXENV" == *"integration"* ]]; then export PYTEST_ADDOPTS="--numprocesses 4"; fi'
# Use Travis retry feature for farm tests since they are flaky
- 'if [[ "$TOXENV" == "travis-test-farm"* ]]; then export TRAVIS_RETRY=travis_retry; fi'
- export TOX_TESTENV_PASSENV=TRAVIS
# Only build pushes to the master branch, PRs, and branches beginning with
@@ -37,8 +40,6 @@ matrix:
# Main test suite
- python: "2.7"
env: ACME_SERVER=pebble TOXENV=integration
sudo: required
services: docker
<<: *not-on-master
# This job is always executed, including on master
@@ -60,19 +61,15 @@ matrix:
# OpenSSL in Xenial or newer.
dist: trusty
env: TOXENV='py27-{acme,apache,certbot,dns,nginx}-oldest'
sudo: required
services: docker
<<: *not-on-master
- python: "3.4"
env: TOXENV=py34
sudo: required
services: docker
<<: *not-on-master
- python: "3.7"
dist: xenial
env: TOXENV=py37
sudo: required
services: docker
<<: *not-on-master
- python: "3.8"
env: TOXENV=py38
<<: *not-on-master
- sudo: required
env: TOXENV=apache_compat
@@ -86,8 +83,6 @@ matrix:
<<: *not-on-master
- python: "2.7"
env: TOXENV=apacheconftest-with-pebble
sudo: required
services: docker
<<: *not-on-master
- python: "2.7"
env: TOXENV=nginxroundtrip
@@ -123,7 +118,6 @@ matrix:
- secure: "f+j/Lj9s1lcuKo5sEFrlRd1kIAMnIJI4z0MTI7QF8jl9Fkmbx7KECGzw31TNgzrOSzxSapHbcueFYvNCLKST+kE/8ogMZBbwqXfEDuKpyF6BY3uYoJn+wPVE5pIb8Hhe08xPte8TTDSMIyHI3EyTfcAKrIreauoArePvh/cRvSw="
<<: *extended-test-suite
- python: "3.7"
dist: xenial
env: TOXENV=py37 CERTBOT_NO_PIN=1
<<: *extended-test-suite
- python: "2.7"
@@ -138,21 +132,37 @@ matrix:
<<: *extended-test-suite
- python: "2.7"
env: ACME_SERVER=boulder-v1 TOXENV=integration-certbot-oldest
# Ubuntu Trusty or older must be used because the oldest version of
# cryptography we support cannot be compiled against the version of
# OpenSSL in Xenial or newer.
dist: trusty
sudo: required
services: docker
<<: *extended-test-suite
- python: "2.7"
env: ACME_SERVER=boulder-v2 TOXENV=integration-certbot-oldest
# Ubuntu Trusty or older must be used because the oldest version of
# cryptography we support cannot be compiled against the version of
# OpenSSL in Xenial or newer.
dist: trusty
sudo: required
services: docker
<<: *extended-test-suite
- python: "2.7"
env: ACME_SERVER=boulder-v1 TOXENV=integration-nginx-oldest
# Ubuntu Trusty or older must be used because the oldest version of
# cryptography we support cannot be compiled against the version of
# OpenSSL in Xenial or newer.
dist: trusty
sudo: required
services: docker
<<: *extended-test-suite
- python: "2.7"
env: ACME_SERVER=boulder-v2 TOXENV=integration-nginx-oldest
# Ubuntu Trusty or older must be used because the oldest version of
# cryptography we support cannot be compiled against the version of
# OpenSSL in Xenial or newer.
dist: trusty
sudo: required
services: docker
<<: *extended-test-suite
@@ -166,9 +176,11 @@ matrix:
env: TOXENV=py36
<<: *extended-test-suite
- python: "3.7"
dist: xenial
env: TOXENV=py37
<<: *extended-test-suite
- python: "3.8-dev"
env: TOXENV=py38
<<: *extended-test-suite
- python: "3.4"
env: ACME_SERVER=boulder-v1 TOXENV=integration
sudo: required
@@ -200,17 +212,21 @@ matrix:
services: docker
<<: *extended-test-suite
- python: "3.7"
dist: xenial
env: ACME_SERVER=boulder-v1 TOXENV=integration
sudo: required
services: docker
<<: *extended-test-suite
- python: "3.7"
dist: xenial
env: ACME_SERVER=boulder-v2 TOXENV=integration
sudo: required
services: docker
<<: *extended-test-suite
- python: "3.8-dev"
env: ACME_SERVER=boulder-v1 TOXENV=integration
<<: *extended-test-suite
- python: "3.8-dev"
env: ACME_SERVER=boulder-v2 TOXENV=integration
<<: *extended-test-suite
- sudo: required
env: TOXENV=le_auto_jessie
services: docker
@@ -273,8 +289,12 @@ addons:
# virtualenv is listed here explicitly to make sure it is upgraded when
# CERTBOT_NO_PIN is set to work around failures we've seen when using an older
# version of virtualenv.
install: "tools/pip_install.py -U codecov tox virtualenv"
script: tox
install: 'tools/pip_install.py -U codecov tox virtualenv'
# Most of the time TRAVIS_RETRY is an empty string, and has no effect on the
# script command. It is set only to `travis_retry` during farm tests, in
# order to trigger the Travis retry feature, and compensate the inherent
# flakiness of these specific tests.
script: '$TRAVIS_RETRY tox'
after_success: '[ "$TOXENV" == "py27-cover" ] && codecov -F linux'

View File

@@ -18,6 +18,7 @@ Authors
* [Alex Zorin](https://github.com/alexzorin)
* [Amjad Mashaal](https://github.com/TheNavigat)
* [Andrew Murray](https://github.com/radarhere)
* [Andrzej Górski](https://github.com/andrzej3393)
* [Anselm Levskaya](https://github.com/levskaya)
* [Antoine Jacoutot](https://github.com/ajacoutot)
* [asaph](https://github.com/asaph)
@@ -127,6 +128,7 @@ Authors
* [Joubin Jabbari](https://github.com/joubin)
* [Juho Juopperi](https://github.com/jkjuopperi)
* [Kane York](https://github.com/riking)
* [Kenichi Maehashi](https://github.com/kmaehashi)
* [Kenneth Skovhede](https://github.com/kenkendk)
* [Kevin Burke](https://github.com/kevinburke)
* [Kevin London](https://github.com/kevinlondon)
@@ -165,6 +167,7 @@ Authors
* [Michael Watters](https://github.com/blackknight36)
* [Michal Moravec](https://github.com/https://github.com/Majkl578)
* [Michal Papis](https://github.com/mpapis)
* [Mickaël Schoentgen](https://github.com/BoboTiG)
* [Minn Soe](https://github.com/MinnSoe)
* [Min RK](https://github.com/minrk)
* [Miquel Ruiz](https://github.com/miquelruiz)
@@ -228,6 +231,7 @@ Authors
* [Stavros Korokithakis](https://github.com/skorokithakis)
* [Stefan Weil](https://github.com/stweil)
* [Steve Desmond](https://github.com/stevedesmond-ca)
* [sydneyli](https://github.com/sydneyli)
* [Tan Jay Jun](https://github.com/jayjun)
* [Tapple Gao](https://github.com/tapple)
* [Telepenin Nikolay](https://github.com/telepenin)

View File

@@ -2,7 +2,49 @@
Certbot adheres to [Semantic Versioning](https://semver.org/).
## 0.38.0 - master
## 1.0.0 - master
### Added
*
### Removed
* The `docs` extras for the `certbot-apache` and `certbot-nginx` packages
have been removed.
### Changed
* certbot-auto has deprecated support for systems using OpenSSL 1.0.1 that are
not running on x86-64. This primarily affects RHEL 6 based systems.
* Certbot's `config_changes` subcommand has been removed
* `certbot.plugins.common.TLSSNI01` has been removed.
* Deprecated attributes related to the TLS-SNI-01 challenge in
`acme.challenges` and `acme.standalone`
have been removed.
* The functions `certbot.client.view_config_changes`,
`certbot.main.config_changes`,
`certbot.plugins.common.Installer.view_config_changes`,
`certbot.reverter.Reverter.view_config_changes`, and
`certbot.util.get_systemd_os_info` have been removed
* Certbot's `register --update-registration` subcommand has been removed
### Fixed
*
More details about these changes can be found on our GitHub repo.
## 0.40.1 - 2019-11-05
### Changed
* Added back support for Python 3.4 to Certbot components and certbot-auto due
to a bug when requiring Python 2.7 or 3.5+ on RHEL 6 based systems.
More details about these changes can be found on our GitHub repo.
## 0.40.0 - 2019-11-05
### Added
@@ -10,9 +52,29 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
### Changed
* If Certbot fails to rollback your server configuration, the error message
links to the Let's Encrypt forum. Change the link to the Help category now
that the Server category has been closed.
* We deprecated support for Python 3.4 in Certbot and its ACME library. Support
for Python 3.4 will be removed in the next major release of Certbot.
certbot-auto users on RHEL 6 based systems will be asked to enable Software
Collections (SCL) repository so Python 3.6 can be installed. certbot-auto can
enable the SCL repo for you on CentOS 6 while users on other RHEL 6 based
systems will be asked to do this manually.
* `--server` may now be combined with `--dry-run`. Certbot will, as before, use the
staging server instead of the live server when `--dry-run` is used.
* `--dry-run` now requests fresh authorizations every time, fixing the issue
where it was prone to falsely reporting success.
* Updated certbot-dns-google to depend on newer versions of
google-api-python-client and oauth2client.
* The OS detection logic again uses distro library for Linux OSes
* certbot.plugins.common.TLSSNI01 has been deprecated and will be removed in a
future release.
* CLI flags --tls-sni-01-port and --tls-sni-01-address have been removed.
* The values tls-sni and tls-sni-01 for the --preferred-challenges flag are no
longer accepted.
* Removed the flags: `--agree-dev-preview`, `--dialog`, and `--apache-init-script`
* acme.standalone.BaseRequestHandlerWithLogging and
acme.standalone.simple_tls_sni_01_server have been deprecated and will be
removed in a future release of the library.
* certbot-dns-rfc2136 now use TCP to query SOA records.
### Fixed
@@ -20,6 +82,52 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
More details about these changes can be found on our GitHub repo.
## 0.39.0 - 2019-10-01
### Added
* Support for Python 3.8 was added to Certbot and all of its components.
* Support for CentOS 8 was added to certbot-auto.
### Changed
* Don't send OCSP requests for expired certificates
* Return to using platform.linux_distribution instead of distro.linux_distribution in OS fingerprinting for Python < 3.8
* Updated the Nginx plugin's TLS configuration to keep support for some versions of IE11.
### Fixed
* Fixed OS detection in the Apache plugin on RHEL 6.
More details about these changes can be found on our GitHub repo.
## 0.38.0 - 2019-09-03
### Added
* Disable session tickets for Nginx users when appropriate.
### Changed
* If Certbot fails to rollback your server configuration, the error message
links to the Let's Encrypt forum. Change the link to the Help category now
that the Server category has been closed.
* Replace platform.linux_distribution with distro.linux_distribution as a step
towards Python 3.8 support in Certbot.
### Fixed
* Fixed OS detection in the Apache plugin on Scientific Linux.
More details about these changes can be found on our GitHub repo.
## 0.37.2 - 2019-08-21
* Stop disabling TLS session tickets in Nginx as it caused TLS failures on
some systems.
More details about these changes can be found on our GitHub repo.
## 0.37.1 - 2019-08-08
### Fixed

View File

@@ -21,30 +21,3 @@ for mod in list(sys.modules):
# preserved (acme.jose.* is josepy.*)
if mod == 'josepy' or mod.startswith('josepy.'):
sys.modules['acme.' + mod.replace('josepy', 'jose', 1)] = sys.modules[mod]
# This class takes a similar approach to the cryptography project to deprecate attributes
# in public modules. See the _ModuleWithDeprecation class here:
# https://github.com/pyca/cryptography/blob/91105952739442a74582d3e62b3d2111365b0dc7/src/cryptography/utils.py#L129
class _TLSSNI01DeprecationModule(object):
"""
Internal class delegating to a module, and displaying warnings when
attributes related to TLS-SNI-01 are accessed.
"""
def __init__(self, module):
self.__dict__['_module'] = module
def __getattr__(self, attr):
if 'TLSSNI01' in attr:
warnings.warn('{0} attribute is deprecated, and will be removed soon.'.format(attr),
DeprecationWarning, stacklevel=2)
return getattr(self._module, attr)
def __setattr__(self, attr, value): # pragma: no cover
setattr(self._module, attr, value)
def __delattr__(self, attr): # pragma: no cover
delattr(self._module, attr)
def __dir__(self): # pragma: no cover
return ['_module'] + dir(self._module)

View File

@@ -3,19 +3,13 @@ import abc
import functools
import hashlib
import logging
import socket
import sys
from cryptography.hazmat.primitives import hashes # type: ignore
import josepy as jose
import OpenSSL
import requests
import six
from acme import errors
from acme import crypto_util
from acme import fields
from acme import _TLSSNI01DeprecationModule
logger = logging.getLogger(__name__)
@@ -237,7 +231,7 @@ class DNS01Response(KeyAuthorizationChallengeResponse):
return verified
@Challenge.register # pylint: disable=too-many-ancestors
@Challenge.register
class DNS01(KeyAuthorizationChallenge):
"""ACME dns-01 challenge."""
response_cls = DNS01Response
@@ -327,7 +321,7 @@ class HTTP01Response(KeyAuthorizationChallengeResponse):
return True
@Challenge.register # pylint: disable=too-many-ancestors
@Challenge.register
class HTTP01(KeyAuthorizationChallenge):
"""ACME http-01 challenge."""
response_cls = HTTP01Response
@@ -367,148 +361,6 @@ class HTTP01(KeyAuthorizationChallenge):
return self.key_authorization(account_key)
@ChallengeResponse.register
class TLSSNI01Response(KeyAuthorizationChallengeResponse):
"""ACME tls-sni-01 challenge response."""
typ = "tls-sni-01"
DOMAIN_SUFFIX = b".acme.invalid"
"""Domain name suffix."""
PORT = 443
"""Verification port as defined by the protocol.
You can override it (e.g. for testing) by passing ``port`` to
`simple_verify`.
"""
@property
def z(self): # pylint: disable=invalid-name
"""``z`` value used for verification.
:rtype bytes:
"""
return hashlib.sha256(
self.key_authorization.encode("utf-8")).hexdigest().lower().encode()
@property
def z_domain(self):
"""Domain name used for verification, generated from `z`.
:rtype bytes:
"""
return self.z[:32] + b'.' + self.z[32:] + self.DOMAIN_SUFFIX
def gen_cert(self, key=None, bits=2048):
"""Generate tls-sni-01 certificate.
:param OpenSSL.crypto.PKey key: Optional private key used in
certificate generation. If not provided (``None``), then
fresh key will be generated.
:param int bits: Number of bits for newly generated key.
:rtype: `tuple` of `OpenSSL.crypto.X509` and `OpenSSL.crypto.PKey`
"""
if key is None:
key = OpenSSL.crypto.PKey()
key.generate_key(OpenSSL.crypto.TYPE_RSA, bits)
return crypto_util.gen_ss_cert(key, [
# z_domain is too big to fit into CN, hence first dummy domain
'dummy', self.z_domain.decode()], force_san=True), key
def probe_cert(self, domain, **kwargs):
"""Probe tls-sni-01 challenge certificate.
:param unicode domain:
"""
# TODO: domain is not necessary if host is provided
if "host" not in kwargs:
host = socket.gethostbyname(domain)
logger.debug('%s resolved to %s', domain, host)
kwargs["host"] = host
kwargs.setdefault("port", self.PORT)
kwargs["name"] = self.z_domain
# TODO: try different methods?
return crypto_util.probe_sni(**kwargs)
def verify_cert(self, cert):
"""Verify tls-sni-01 challenge certificate.
:param OpensSSL.crypto.X509 cert: Challenge certificate.
:returns: Whether the certificate was successfully verified.
:rtype: bool
"""
# pylint: disable=protected-access
sans = crypto_util._pyopenssl_cert_or_req_san(cert)
logger.debug('Certificate %s. SANs: %s', cert.digest('sha256'), sans)
return self.z_domain.decode() in sans
def simple_verify(self, chall, domain, account_public_key,
cert=None, **kwargs):
"""Simple verify.
Verify ``validation`` using ``account_public_key``, optionally
probe tls-sni-01 certificate and check using `verify_cert`.
:param .challenges.TLSSNI01 chall: Corresponding challenge.
:param str domain: Domain name being validated.
:param JWK account_public_key:
:param OpenSSL.crypto.X509 cert: Optional certificate. If not
provided (``None``) certificate will be retrieved using
`probe_cert`.
:param int port: Port used to probe the certificate.
:returns: ``True`` iff client's control of the domain has been
verified.
:rtype: bool
"""
if not self.verify(chall, account_public_key):
logger.debug("Verification of key authorization in response failed")
return False
if cert is None:
try:
cert = self.probe_cert(domain=domain, **kwargs)
except errors.Error as error:
logger.debug(str(error), exc_info=True)
return False
return self.verify_cert(cert)
@Challenge.register # pylint: disable=too-many-ancestors
class TLSSNI01(KeyAuthorizationChallenge):
"""ACME tls-sni-01 challenge."""
response_cls = TLSSNI01Response
typ = response_cls.typ
# boulder#962, ietf-wg-acme#22
#n = jose.Field("n", encoder=int, decoder=int)
def validation(self, account_key, **kwargs):
"""Generate validation.
:param JWK account_key:
:param OpenSSL.crypto.PKey cert_key: Optional private key used
in certificate generation. If not provided (``None``), then
fresh key will be generated.
:rtype: `tuple` of `OpenSSL.crypto.X509` and `OpenSSL.crypto.PKey`
"""
return self.response(account_key).gen_cert(key=kwargs.get('cert_key'))
@ChallengeResponse.register
class TLSALPN01Response(KeyAuthorizationChallengeResponse):
"""ACME TLS-ALPN-01 challenge response.
@@ -520,7 +372,7 @@ class TLSALPN01Response(KeyAuthorizationChallengeResponse):
typ = "tls-alpn-01"
@Challenge.register # pylint: disable=too-many-ancestors
@Challenge.register
class TLSALPN01(KeyAuthorizationChallenge):
"""ACME tls-alpn-01 challenge.
@@ -617,7 +469,3 @@ class DNSResponse(ChallengeResponse):
"""
return chall.check_validation(self.validation, account_public_key)
# Patching ourselves to warn about TLS-SNI challenge deprecation and removal.
sys.modules[__name__] = _TLSSNI01DeprecationModule(sys.modules[__name__])

View File

@@ -3,12 +3,10 @@ import unittest
import josepy as jose
import mock
import OpenSSL
import requests
from six.moves.urllib import parse as urllib_parse # pylint: disable=relative-import
from acme import errors
from acme import test_util
CERT = test_util.load_comparable_cert('cert.pem')
@@ -77,7 +75,6 @@ class KeyAuthorizationChallengeResponseTest(unittest.TestCase):
class DNS01ResponseTest(unittest.TestCase):
# pylint: disable=too-many-instance-attributes
def setUp(self):
from acme.challenges import DNS01Response
@@ -149,7 +146,6 @@ class DNS01Test(unittest.TestCase):
class HTTP01ResponseTest(unittest.TestCase):
# pylint: disable=too-many-instance-attributes
def setUp(self):
from acme.challenges import HTTP01Response
@@ -259,152 +255,7 @@ class HTTP01Test(unittest.TestCase):
self.msg.update(token=b'..').good_token)
class TLSSNI01ResponseTest(unittest.TestCase):
# pylint: disable=too-many-instance-attributes
def setUp(self):
from acme.challenges import TLSSNI01
self.chall = TLSSNI01(
token=jose.b64decode(b'a82d5ff8ef740d12881f6d3c2277ab2e'))
self.response = self.chall.response(KEY)
self.jmsg = {
'resource': 'challenge',
'type': 'tls-sni-01',
'keyAuthorization': self.response.key_authorization,
}
# pylint: disable=invalid-name
label1 = b'dc38d9c3fa1a4fdcc3a5501f2d38583f'
label2 = b'b7793728f084394f2a1afd459556bb5c'
self.z = label1 + label2
self.z_domain = label1 + b'.' + label2 + b'.acme.invalid'
self.domain = 'foo.com'
def test_z_and_domain(self):
self.assertEqual(self.z, self.response.z)
self.assertEqual(self.z_domain, self.response.z_domain)
def test_to_partial_json(self):
self.assertEqual({k: v for k, v in self.jmsg.items() if k != 'keyAuthorization'},
self.response.to_partial_json())
def test_from_json(self):
from acme.challenges import TLSSNI01Response
self.assertEqual(self.response, TLSSNI01Response.from_json(self.jmsg))
def test_from_json_hashable(self):
from acme.challenges import TLSSNI01Response
hash(TLSSNI01Response.from_json(self.jmsg))
@mock.patch('acme.challenges.socket.gethostbyname')
@mock.patch('acme.challenges.crypto_util.probe_sni')
def test_probe_cert(self, mock_probe_sni, mock_gethostbyname):
mock_gethostbyname.return_value = '127.0.0.1'
self.response.probe_cert('foo.com')
mock_gethostbyname.assert_called_once_with('foo.com')
mock_probe_sni.assert_called_once_with(
host='127.0.0.1', port=self.response.PORT,
name=self.z_domain)
self.response.probe_cert('foo.com', host='8.8.8.8')
mock_probe_sni.assert_called_with(
host='8.8.8.8', port=mock.ANY, name=mock.ANY)
self.response.probe_cert('foo.com', port=1234)
mock_probe_sni.assert_called_with(
host=mock.ANY, port=1234, name=mock.ANY)
self.response.probe_cert('foo.com', bar='baz')
mock_probe_sni.assert_called_with(
host=mock.ANY, port=mock.ANY, name=mock.ANY, bar='baz')
self.response.probe_cert('foo.com', name=b'xxx')
mock_probe_sni.assert_called_with(
host=mock.ANY, port=mock.ANY,
name=self.z_domain)
def test_gen_verify_cert(self):
key1 = test_util.load_pyopenssl_private_key('rsa512_key.pem')
cert, key2 = self.response.gen_cert(key1)
self.assertEqual(key1, key2)
self.assertTrue(self.response.verify_cert(cert))
def test_gen_verify_cert_gen_key(self):
cert, key = self.response.gen_cert()
self.assertTrue(isinstance(key, OpenSSL.crypto.PKey))
self.assertTrue(self.response.verify_cert(cert))
def test_verify_bad_cert(self):
self.assertFalse(self.response.verify_cert(
test_util.load_cert('cert.pem')))
def test_simple_verify_bad_key_authorization(self):
key2 = jose.JWKRSA.load(test_util.load_vector('rsa256_key.pem'))
self.response.simple_verify(self.chall, "local", key2.public_key())
@mock.patch('acme.challenges.TLSSNI01Response.verify_cert', autospec=True)
def test_simple_verify(self, mock_verify_cert):
mock_verify_cert.return_value = mock.sentinel.verification
self.assertEqual(
mock.sentinel.verification, self.response.simple_verify(
self.chall, self.domain, KEY.public_key(),
cert=mock.sentinel.cert))
mock_verify_cert.assert_called_once_with(
self.response, mock.sentinel.cert)
@mock.patch('acme.challenges.TLSSNI01Response.probe_cert')
def test_simple_verify_false_on_probe_error(self, mock_probe_cert):
mock_probe_cert.side_effect = errors.Error
self.assertFalse(self.response.simple_verify(
self.chall, self.domain, KEY.public_key()))
class TLSSNI01Test(unittest.TestCase):
def setUp(self):
self.jmsg = {
'type': 'tls-sni-01',
'token': 'a82d5ff8ef740d12881f6d3c2277ab2e',
}
from acme.challenges import TLSSNI01
self.msg = TLSSNI01(
token=jose.b64decode('a82d5ff8ef740d12881f6d3c2277ab2e'))
def test_to_partial_json(self):
self.assertEqual(self.jmsg, self.msg.to_partial_json())
def test_from_json(self):
from acme.challenges import TLSSNI01
self.assertEqual(self.msg, TLSSNI01.from_json(self.jmsg))
def test_from_json_hashable(self):
from acme.challenges import TLSSNI01
hash(TLSSNI01.from_json(self.jmsg))
def test_from_json_invalid_token_length(self):
from acme.challenges import TLSSNI01
self.jmsg['token'] = jose.encode_b64jose(b'abcd')
self.assertRaises(
jose.DeserializationError, TLSSNI01.from_json, self.jmsg)
@mock.patch('acme.challenges.TLSSNI01Response.gen_cert')
def test_validation(self, mock_gen_cert):
mock_gen_cert.return_value = ('cert', 'key')
self.assertEqual(('cert', 'key'), self.msg.validation(
KEY, cert_key=mock.sentinel.cert_key))
mock_gen_cert.assert_called_once_with(key=mock.sentinel.cert_key)
def test_deprecation_message(self):
with mock.patch('acme.warnings.warn') as mock_warn:
from acme.challenges import TLSSNI01
assert TLSSNI01
self.assertEqual(mock_warn.call_count, 1)
self.assertTrue('deprecated' in mock_warn.call_args[0][0])
class TLSALPN01ResponseTest(unittest.TestCase):
# pylint: disable=too-many-instance-attributes
def setUp(self):
from acme.challenges import TLSALPN01Response

View File

@@ -44,7 +44,7 @@ DEFAULT_NETWORK_TIMEOUT = 45
DER_CONTENT_TYPE = 'application/pkix-cert'
class ClientBase(object): # pylint: disable=too-many-instance-attributes
class ClientBase(object):
"""ACME client base object.
:ivar messages.Directory directory:
@@ -136,7 +136,8 @@ class ClientBase(object): # pylint: disable=too-many-instance-attributes
"""
body = messages.UpdateAuthorization(status='deactivated')
response = self._post(authzr.uri, body)
return self._authzr_from_response(response)
return self._authzr_from_response(response,
authzr.body.identifier, authzr.uri)
def _authzr_from_response(self, response, identifier=None, uri=None):
authzr = messages.AuthorizationResource(
@@ -253,7 +254,6 @@ class Client(ClientBase):
URI from which the resource will be downloaded.
"""
# pylint: disable=too-many-arguments
self.key = key
if net is None:
net = ClientNetwork(key, alg=alg, verify_ssl=verify_ssl)
@@ -434,7 +434,6 @@ class Client(ClientBase):
was marked by the CA as invalid
"""
# pylint: disable=too-many-locals
assert max_attempts > 0
attempts = collections.defaultdict(int) # type: Dict[messages.AuthorizationResource, int]
exhausted = set()
@@ -946,7 +945,7 @@ class BackwardsCompatibleClientV2(object):
return self.client.external_account_required()
class ClientNetwork(object): # pylint: disable=too-many-instance-attributes
class ClientNetwork(object):
"""Wrapper around requests that signs POSTs for authentication.
Also adds user agent, and handles Content-Type.
@@ -972,7 +971,6 @@ class ClientNetwork(object): # pylint: disable=too-many-instance-attributes
def __init__(self, key, account=None, alg=jose.RS256, verify_ssl=True,
user_agent='acme-python', timeout=DEFAULT_NETWORK_TIMEOUT,
source_address=None):
# pylint: disable=too-many-arguments
self.key = key
self.account = account
self.alg = alg
@@ -1080,7 +1078,6 @@ class ClientNetwork(object): # pylint: disable=too-many-instance-attributes
return response
def _send_request(self, method, url, *args, **kwargs):
# pylint: disable=too-many-locals
"""Send HTTP request.
Makes sure that `verify_ssl` is respected. Logs request and

View File

@@ -318,7 +318,6 @@ class BackwardsCompatibleClientV2Test(ClientTestBase):
class ClientTest(ClientTestBase):
"""Tests for acme.client.Client."""
# pylint: disable=too-many-instance-attributes,too-many-public-methods
def setUp(self):
super(ClientTest, self).setUp()
@@ -888,7 +887,7 @@ class ClientV2Test(ClientTestBase):
new_nonce_url='https://www.letsencrypt-demo.org/acme/new-nonce')
self.client.net.get.assert_not_called()
class FakeError(messages.Error): # pylint: disable=too-many-ancestors
class FakeError(messages.Error):
"""Fake error to reproduce a malformed request ACME error"""
def __init__(self): # pylint: disable=super-init-not-called
pass
@@ -917,7 +916,6 @@ class MockJSONDeSerializable(jose.JSONDeSerializable):
class ClientNetworkTest(unittest.TestCase):
"""Tests for acme.client.ClientNetwork."""
# pylint: disable=too-many-public-methods
def setUp(self):
self.verify_ssl = mock.MagicMock()
@@ -1123,7 +1121,6 @@ class ClientNetworkTest(unittest.TestCase):
class ClientNetworkWithMockedResponseTest(unittest.TestCase):
"""Tests for acme.client.ClientNetwork which mock out response."""
# pylint: disable=too-many-instance-attributes
def setUp(self):
from acme.client import ClientNetwork

View File

@@ -28,7 +28,7 @@ logger = logging.getLogger(__name__)
_DEFAULT_SSL_METHOD = SSL.SSLv23_METHOD # type: ignore
class SSLSocket(object): # pylint: disable=too-few-public-methods
class SSLSocket(object):
"""SSL wrapper for sockets.
:ivar socket sock: Original wrapped socket.
@@ -74,7 +74,7 @@ class SSLSocket(object): # pylint: disable=too-few-public-methods
class FakeConnection(object):
"""Fake OpenSSL.SSL.Connection."""
# pylint: disable=too-few-public-methods,missing-docstring
# pylint: disable=missing-docstring
def __init__(self, connection):
self._wrapped = connection

View File

@@ -30,7 +30,6 @@ class SSLSocketAndProbeSNITest(unittest.TestCase):
class _TestServer(socketserver.TCPServer):
# pylint: disable=too-few-public-methods
# six.moves.* | pylint: disable=attribute-defined-outside-init,no-init
def server_bind(self): # pylint: disable=missing-docstring

View File

@@ -43,7 +43,7 @@ class JWS(jose.JWS):
__slots__ = jose.JWS._orig_slots # pylint: disable=no-member
@classmethod
# pylint: disable=arguments-differ,too-many-arguments
# pylint: disable=arguments-differ
def sign(cls, payload, key, alg, nonce, url=None, kid=None):
# Per ACME spec, jwk and kid are mutually exclusive, so only include a
# jwk field if kid is not provided.

View File

@@ -1,29 +1,23 @@
"""Support for standalone client challenge solvers. """
import argparse
import collections
import functools
import logging
import os
import socket
import sys
import threading
from six.moves import BaseHTTPServer # type: ignore # pylint: disable=import-error
from six.moves import http_client # pylint: disable=import-error
from six.moves import socketserver # type: ignore # pylint: disable=import-error
import OpenSSL
from acme import challenges
from acme import crypto_util
from acme.magic_typing import List # pylint: disable=unused-import, no-name-in-module
from acme import _TLSSNI01DeprecationModule
logger = logging.getLogger(__name__)
# six.moves.* | pylint: disable=no-member,attribute-defined-outside-init
# pylint: disable=too-few-public-methods,no-init
# pylint: disable=no-init
class TLSServer(socketserver.TCPServer):
@@ -132,35 +126,6 @@ class BaseDualNetworkedServers(object):
self.threads = []
class TLSSNI01Server(TLSServer, ACMEServerMixin):
"""TLSSNI01 Server."""
def __init__(self, server_address, certs, ipv6=False):
TLSServer.__init__(
self, server_address, BaseRequestHandlerWithLogging, certs=certs, ipv6=ipv6)
class TLSSNI01DualNetworkedServers(BaseDualNetworkedServers):
"""TLSSNI01Server Wrapper. Tries everything for both. Failures for one don't
affect the other."""
def __init__(self, *args, **kwargs):
BaseDualNetworkedServers.__init__(self, TLSSNI01Server, *args, **kwargs)
class BaseRequestHandlerWithLogging(socketserver.BaseRequestHandler):
"""BaseRequestHandler with logging."""
def log_message(self, format, *args): # pylint: disable=redefined-builtin
"""Log arbitrary message."""
logger.debug("%s - - %s", self.client_address[0], format % args)
def handle(self):
"""Handle request."""
self.log_message("Incoming request")
socketserver.BaseRequestHandler.handle(self)
class HTTPServer(BaseHTTPServer.HTTPServer):
"""Generic HTTP Server."""
@@ -263,43 +228,3 @@ class HTTP01RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""
return functools.partial(
cls, simple_http_resources=simple_http_resources)
def simple_tls_sni_01_server(cli_args, forever=True):
"""Run simple standalone TLSSNI01 server."""
logging.basicConfig(level=logging.DEBUG)
parser = argparse.ArgumentParser()
parser.add_argument(
"-p", "--port", default=0, help="Port to serve at. By default "
"picks random free port.")
args = parser.parse_args(cli_args[1:])
certs = {}
_, hosts, _ = next(os.walk('.')) # type: ignore # https://github.com/python/mypy/issues/465
for host in hosts:
with open(os.path.join(host, "cert.pem")) as cert_file:
cert_contents = cert_file.read()
with open(os.path.join(host, "key.pem")) as key_file:
key_contents = key_file.read()
certs[host.encode()] = (
OpenSSL.crypto.load_privatekey(
OpenSSL.crypto.FILETYPE_PEM, key_contents),
OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_PEM, cert_contents))
server = TLSSNI01Server(('', int(args.port)), certs=certs)
logger.info("Serving at https://%s:%s...", *server.socket.getsockname()[:2])
if forever: # pragma: no cover
server.serve_forever()
else:
server.handle_request()
# Patching ourselves to warn about TLS-SNI challenge deprecation and removal.
sys.modules[__name__] = _TLSSNI01DeprecationModule(sys.modules[__name__])
if __name__ == "__main__":
sys.exit(simple_tls_sni_01_server(sys.argv)) # pragma: no cover

View File

@@ -1,13 +1,7 @@
"""Tests for acme.standalone."""
import multiprocessing
import os
import shutil
import socket
import threading
import tempfile
import unittest
import time
from contextlib import closing
from six.moves import http_client # pylint: disable=import-error
from six.moves import socketserver # type: ignore # pylint: disable=import-error
@@ -17,8 +11,6 @@ import mock
import requests
from acme import challenges
from acme import crypto_util
from acme import errors
from acme import test_util
from acme.magic_typing import Set # pylint: disable=unused-import, no-name-in-module
@@ -41,32 +33,6 @@ class TLSServerTest(unittest.TestCase):
server.server_close()
class TLSSNI01ServerTest(unittest.TestCase):
"""Test for acme.standalone.TLSSNI01Server."""
def setUp(self):
self.certs = {b'localhost': (
test_util.load_pyopenssl_private_key('rsa2048_key.pem'),
test_util.load_cert('rsa2048_cert.pem'),
)}
from acme.standalone import TLSSNI01Server
self.server = TLSSNI01Server(('localhost', 0), certs=self.certs)
self.thread = threading.Thread(target=self.server.serve_forever)
self.thread.start()
def tearDown(self):
self.server.shutdown()
self.thread.join()
def test_it(self):
host, port = self.server.socket.getsockname()[:2]
cert = crypto_util.probe_sni(
b'localhost', host=host, port=port, timeout=1)
self.assertEqual(jose.ComparableX509(cert),
jose.ComparableX509(self.certs[b'localhost'][1]))
class HTTP01ServerTest(unittest.TestCase):
"""Tests for acme.standalone.HTTP01Server."""
@@ -170,33 +136,6 @@ class BaseDualNetworkedServersTest(unittest.TestCase):
prev_port = port
class TLSSNI01DualNetworkedServersTest(unittest.TestCase):
"""Test for acme.standalone.TLSSNI01DualNetworkedServers."""
def setUp(self):
self.certs = {b'localhost': (
test_util.load_pyopenssl_private_key('rsa2048_key.pem'),
test_util.load_cert('rsa2048_cert.pem'),
)}
from acme.standalone import TLSSNI01DualNetworkedServers
self.servers = TLSSNI01DualNetworkedServers(('localhost', 0), certs=self.certs)
self.servers.serve_forever()
def tearDown(self):
self.servers.shutdown_and_server_close()
def test_connect(self):
socknames = self.servers.getsocknames()
# connect to all addresses
for sockname in socknames:
host, port = sockname[:2]
cert = crypto_util.probe_sni(
b'localhost', host=host, port=port, timeout=1)
self.assertEqual(jose.ComparableX509(cert),
jose.ComparableX509(self.certs[b'localhost'][1]))
class HTTP01DualNetworkedServersTest(unittest.TestCase):
"""Tests for acme.standalone.HTTP01DualNetworkedServers."""
@@ -247,60 +186,5 @@ class HTTP01DualNetworkedServersTest(unittest.TestCase):
self.assertFalse(self._test_http01(add=False))
class TestSimpleTLSSNI01Server(unittest.TestCase):
"""Tests for acme.standalone.simple_tls_sni_01_server."""
def setUp(self):
# mirror ../examples/standalone
self.test_cwd = tempfile.mkdtemp()
localhost_dir = os.path.join(self.test_cwd, 'localhost')
os.makedirs(localhost_dir)
shutil.copy(test_util.vector_path('rsa2048_cert.pem'),
os.path.join(localhost_dir, 'cert.pem'))
shutil.copy(test_util.vector_path('rsa2048_key.pem'),
os.path.join(localhost_dir, 'key.pem'))
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
sock.bind(('', 0))
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.port = sock.getsockname()[1]
from acme.standalone import simple_tls_sni_01_server
self.process = multiprocessing.Process(target=simple_tls_sni_01_server,
args=(['path', '-p', str(self.port)],))
self.old_cwd = os.getcwd()
os.chdir(self.test_cwd)
def tearDown(self):
os.chdir(self.old_cwd)
if self.process.is_alive():
self.process.terminate()
self.process.join(timeout=5)
# Check that we didn't timeout waiting for the process to
# terminate.
self.assertNotEqual(self.process.exitcode, None)
shutil.rmtree(self.test_cwd)
@mock.patch('acme.standalone.TLSSNI01Server.handle_request')
def test_mock(self, handle):
from acme.standalone import simple_tls_sni_01_server
simple_tls_sni_01_server(cli_args=['path', '-p', str(self.port)], forever=False)
self.assertEqual(handle.call_count, 1)
def test_live(self):
self.process.start()
cert = None
for _ in range(50):
time.sleep(0.1)
try:
cert = crypto_util.probe_sni(b'localhost', b'127.0.0.1', self.port)
break
except errors.Error: # pragma: no cover
pass
self.assertEqual(jose.ComparableX509(cert),
test_util.load_comparable_cert('rsa2048_cert.pem'))
if __name__ == "__main__":
unittest.main() # pragma: no cover

View File

@@ -4,7 +4,6 @@
"""
import os
import unittest
import pkg_resources
from cryptography.hazmat.backends import default_backend
@@ -13,12 +12,6 @@ import josepy as jose
from OpenSSL import crypto
def vector_path(*names):
"""Path to a test vector."""
return pkg_resources.resource_filename(
__name__, os.path.join('testdata', *names))
def load_vector(*names):
"""Load contents of a test vector."""
# luckily, resource_string opens file in binary mode
@@ -73,23 +66,3 @@ def load_pyopenssl_private_key(*names):
loader = _guess_loader(
names[-1], crypto.FILETYPE_PEM, crypto.FILETYPE_ASN1)
return crypto.load_privatekey(loader, load_vector(*names))
def skip_unless(condition, reason): # pragma: no cover
"""Skip tests unless a condition holds.
This implements the basic functionality of unittest.skipUnless
which is only available on Python 2.7+.
:param bool condition: If ``False``, the test will be skipped
:param str reason: the reason for skipping the test
:rtype: callable
:returns: decorator that hides tests unless condition is ``True``
"""
if hasattr(unittest, "skipUnless"):
return unittest.skipUnless(condition, reason)
elif condition:
return lambda cls: cls
return lambda cls: None

View File

@@ -3,7 +3,7 @@ from setuptools import find_packages
from setuptools.command.test import test as TestCommand
import sys
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
@@ -73,6 +73,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
],

View File

@@ -1,47 +0,0 @@
image: Visual Studio 2015
environment:
matrix:
- TOXENV: py35
- TOXENV: py37-cover
- TOXENV: integration-certbot
branches:
only:
# apache-parser-v2 is a temporary branch for doing work related to
# rewriting the parser in the Apache plugin.
- apache-parser-v2
- master
- /^\d+\.\d+\.x$/ # Version branches like X.X.X
- /^test-.*$/
init:
# Since master can receive only commits from PR that have already been tested, following
# condition avoid to launch all jobs except the coverage one for commits pushed to master.
- ps: |
if (-Not $Env:APPVEYOR_PULL_REQUEST_NUMBER -And $Env:APPVEYOR_REPO_BRANCH -Eq 'master' `
-And -Not ($Env:TOXENV -Like '*-cover'))
{ $Env:APPVEYOR_SKIP_FINALIZE_ON_EXIT = 'true'; Exit-AppVeyorBuild }
install:
# Use Python 3.7 by default
- SET PATH=C:\\Python37;C:\\Python37\\Scripts;%PATH%
# Using 4 processes is proven to be the most efficient integration tests config for AppVeyor
- IF %TOXENV%==integration-certbot SET PYTEST_ADDOPTS=--numprocesses=4
# Check env
- python --version
# Upgrade pip to avoid warnings
- python -m pip install --upgrade pip
# Ready to install tox and coverage
# tools/pip_install.py is used to pin packages to a known working version.
- python tools\\pip_install.py tox codecov
build: off
test_script:
- set TOX_TESTENV_PASSENV=APPVEYOR
# Test env is set by TOXENV env variable
- tox
on_success:
- if exist .coverage codecov -F windows

View File

@@ -1,192 +0,0 @@
""" Tests for ParserNode interface """
from certbot_apache import interfaces
from acme.magic_typing import Dict, Tuple # pylint: disable=unused-import, no-name-in-module
class AugeasCommentNode(interfaces.CommentNode):
""" Augeas implementation of CommentNode interface """
ancestor = None
comment = ""
dirty = False
_metadata = dict() # type: Dict[str, object]
def __init__(self, comment, ancestor=None):
self.comment = comment
self.ancestor = ancestor
def save(self, msg): # pragma: no cover
pass
# Apache specific functionality
def get_metadata(self, key):
""" Returns a metadata object
:param str key: Metadata object name to return
:returns: Requested metadata object
"""
try:
return self._metadata[key]
except KeyError:
return None
class AugeasDirectiveNode(interfaces.DirectiveNode):
""" Augeas implementation of DirectiveNode interface """
ancestor = None
parameters = tuple() # type: Tuple[str, ...]
dirty = False
enabled = True
name = ""
_metadata = dict() # type: Dict[str, object]
def __init__(self, name, parameters=tuple(), ancestor=None):
self.name = name
self.parameters = parameters
self.ancestor = ancestor
def save(self, msg): # pragma: no cover
pass
def set_parameters(self, parameters): # pragma: no cover
self.parameters = tuple("CERTBOT_PASS_ASSERT")
# Apache specific functionality
def get_filename(self):
"""Returns the filename where this directive exists on disk
:returns: File path to this node.
:rtype: str
"""
# Following is the real implementation when everything else is in place:
# return apache_util.get_file_path(
# self.parser.aug.get("/augeas/files%s/path" % apache_util.get_file_path(path)))
return "CERTBOT_PASS_ASSERT"
def get_metadata(self, key):
""" Returns a metadata object
:param str key: Metadata object name to return
:returns: Requested metadata object
"""
try:
return self._metadata[key]
except KeyError:
return None
def has_parameter(self, parameter, position=None):
"""Checks if this ParserNode object has a supplied parameter. This check
is case insensitive.
:param str parameter: Parameter value to look for
:param position: Optional explicit position of parameter to look for
:returns: True if parameter is found
:rtype: bool
"""
if position != None:
return parameter.lower() == self.parameters[position].lower()
for param in self.parameters:
if param.lower() == parameter.lower():
return True
return False
class AugeasBlockNode(interfaces.BlockNode):
""" Augeas implementation of BlockNode interface """
ancestor = None
parameters = tuple() # type: Tuple[str, ...]
children = tuple() # type: Tuple[interfaces.ParserNode, ...]
dirty = False
enabled = True
name = ""
_metadata = dict() # type: Dict[str, object]
def __init__(self, name, parameters=tuple(), ancestor=None):
self.name = name
self.parameters = parameters
self.ancestor = ancestor
def save(self, msg): # pragma: no cover
pass
def add_child_block(self, name, parameters=None, position=None): # pragma: no cover
new_block = AugeasBlockNode("CERTBOT_PASS_ASSERT", ancestor=self)
self.children += (new_block,)
return new_block
def add_child_directive(self, name, parameters=None, position=None): # pragma: no cover
new_dir = AugeasDirectiveNode("CERTBOT_PASS_ASSERT", ancestor=self)
self.children += (new_dir,)
return new_dir
def add_child_comment(self, comment="", position=None): # pragma: no cover
new_comment = AugeasCommentNode("CERTBOT_PASS_ASSERT", ancestor=self)
self.children += (new_comment,)
return new_comment
def find_blocks(self, name, exclude=True): # pragma: no cover
return [AugeasBlockNode("CERTBOT_PASS_ASSERT", ancestor=self)]
def find_directives(self, name, exclude=True): # pragma: no cover
return [AugeasDirectiveNode("CERTBOT_PASS_ASSERT", ancestor=self)]
def find_comments(self, comment, exact=False): # pragma: no cover
return [AugeasCommentNode("CERTBOT_PASS_ASSERT", ancestor=self)]
def delete_child(self, child): # pragma: no cover
pass
def set_parameters(self, parameters): # pragma: no cover
self.parameters = tuple("CERTBOT_PASS_ASSERT")
def unsaved_files(self): # pragma: no cover
return ["CERTBOT_PASS_ASSERT"]
# Apache specific functionality
def get_filename(self):
"""Returns the filename where this directive exists on disk
:returns: File path to this node.
:rtype: str
"""
# Following is the real implementation when everything else is in place:
# return apache_util.get_file_path(
# self.parser.aug.get("/augeas/files%s/path" %
# apache_util.get_file_path(self.get_metadata("augeas_path")))
return "CERTBOT_PASS_ASSERT"
def get_metadata(self, key):
""" Returns a metadata object
:param str key: Metadata object name to return
:returns: Requested metadata object
"""
try:
return self._metadata[key]
except KeyError:
return None
def has_parameter(self, parameter, position=None):
"""Checks if this ParserNode object has a supplied parameter. This check
is case insensitive.
:param str parameter: Parameter value to look for
:param position: Optional explicit position of parameter to look for
:returns: True if parameter is found
:rtype: bool
"""
if position != None:
return parameter.lower() == self.parameters[position].lower()
for param in self.parameters:
if param.lower() == parameter.lower():
return True
return False

View File

@@ -71,7 +71,6 @@ logger = logging.getLogger(__name__)
@zope.interface.implementer(interfaces.IAuthenticator, interfaces.IInstaller)
@zope.interface.provider(interfaces.IPluginFactory)
class ApacheConfigurator(common.Installer):
# pylint: disable=too-many-instance-attributes,too-many-public-methods
"""Apache configurator.
:ivar config: Configuration.
@@ -174,8 +173,6 @@ class ApacheConfigurator(common.Installer):
"(Only Ubuntu/Debian currently)")
add("ctl", default=DEFAULTS["ctl"],
help="Full path to Apache control script")
util.add_deprecated_argument(
add, argument_name="init-script", nargs=1)
def __init__(self, *args, **kwargs):
"""Initialize an Apache Configurator.
@@ -810,28 +807,6 @@ class ApacheConfigurator(common.Installer):
return (servername, serveraliases)
def _populate_vhost_names_v2(self, vhost):
"""Helper function that populates the VirtualHost names.
:param host: In progress vhost whose names will be added
:type host: :class:`~certbot_apache.obj.VirtualHost`
"""
servername_match = vhost.node.find_directives("ServerName",
exclude=False)
serveralias_match = vhost.node.find_directives("ServerAlias",
exclude=False)
if servername_match:
servername = servername_match[-1].parameters[-1]
if not vhost.modmacro:
for alias in serveralias_match:
for serveralias in alias.parameters:
vhost.aliases.add(serveralias)
vhost.name = servername
def _add_servernames(self, host):
"""Helper function for get_virtual_hosts().
@@ -893,52 +868,6 @@ class ApacheConfigurator(common.Installer):
self._add_servernames(vhost)
return vhost
def _create_vhost_v2(self, node):
"""Used by get_virtual_hosts to create vhost objects using ParserNode
interfaces.
:param interfaces.BlockNode node: The BlockNode object of VirtualHost block
:returns: newly created vhost
:rtype: :class:`~certbot_apache.obj.VirtualHost`
"""
addrs = set()
for param in node.parameters:
addrs.add(obj.Addr.fromstring(param))
is_ssl = False
sslengine = node.find_directives("SSLEngine")
if sslengine:
for directive in sslengine:
# TODO: apache-parser-v2
# This search should be made wiser. (using other identificators)
if directive.has_parameter("on", 0):
is_ssl = True
# "SSLEngine on" might be set outside of <VirtualHost>
# Treat vhosts with port 443 as ssl vhosts
for addr in addrs:
if addr.get_port() == "443":
is_ssl = True
filename = node.get_filename()
if filename is None:
return None
macro = False
if node.find_directives("Macro"):
macro = True
vhost_enabled = self.parser.parsed_in_original(filename)
vhost = obj.VirtualHost(filename, node.get_metadata("augeas_path"),
addrs, is_ssl, vhost_enabled, modmacro=macro,
node=node)
self._populate_vhost_names_v2(vhost)
return vhost
def get_virtual_hosts(self):
"""Returns list of virtual hosts found in the Apache configuration.
@@ -1186,7 +1115,7 @@ class ApacheConfigurator(common.Installer):
if "ssl_module" not in self.parser.modules:
self.enable_mod("ssl", temp=temp)
def make_vhost_ssl(self, nonssl_vhost): # pylint: disable=too-many-locals
def make_vhost_ssl(self, nonssl_vhost):
"""Makes an ssl_vhost version of a nonssl_vhost.
Duplicates vhost and adds default ssl options
@@ -1682,9 +1611,9 @@ class ApacheConfigurator(common.Installer):
:param str domain: domain to enhance
:param str enhancement: enhancement type defined in
:const:`~certbot.constants.ENHANCEMENTS`
:const:`~certbot.plugins.enhancements.ENHANCEMENTS`
:param options: options for the enhancement
See :const:`~certbot.constants.ENHANCEMENTS`
See :const:`~certbot.plugins.enhancements.ENHANCEMENTS`
documentation for appropriate parameter.
:raises .errors.PluginError: If Enhancement is not supported, or if
@@ -2415,7 +2344,7 @@ class ApacheConfigurator(common.Installer):
Enable the AutoHSTS enhancement for defined domains
:param _unused_lineage: Certificate lineage object, unused
:type _unused_lineage: certbot.storage.RenewableCert
:type _unused_lineage: certbot._internal.storage.RenewableCert
:param domains: List of domains in certificate to enhance
:type domains: str
@@ -2540,7 +2469,7 @@ class ApacheConfigurator(common.Installer):
and changes the HSTS max-age to a high value.
:param lineage: Certificate lineage object
:type lineage: certbot.storage.RenewableCert
:type lineage: certbot._internal.storage.RenewableCert
"""
self._autohsts_fetch_state()
if not self._autohsts:

View File

@@ -16,6 +16,7 @@ from certbot_apache import override_suse
OVERRIDE_CLASSES = {
"arch": override_arch.ArchConfigurator,
"cloudlinux": override_centos.CentOSConfigurator,
"darwin": override_darwin.DarwinConfigurator,
"debian": override_debian.DebianConfigurator,
"ubuntu": override_debian.DebianConfigurator,
@@ -23,7 +24,10 @@ OVERRIDE_CLASSES = {
"centos linux": override_centos.CentOSConfigurator,
"fedora_old": override_centos.CentOSConfigurator,
"fedora": override_fedora.FedoraConfigurator,
"linuxmint": override_debian.DebianConfigurator,
"ol": override_centos.CentOSConfigurator,
"oracle": override_centos.CentOSConfigurator,
"redhatenterpriseserver": override_centos.CentOSConfigurator,
"red hat enterprise linux server": override_centos.CentOSConfigurator,
"rhel": override_centos.CentOSConfigurator,
"amazon": override_centos.CentOSConfigurator,
@@ -31,6 +35,9 @@ OVERRIDE_CLASSES = {
"gentoo base system": override_gentoo.GentooConfigurator,
"opensuse": override_suse.OpenSUSEConfigurator,
"suse": override_suse.OpenSUSEConfigurator,
"sles": override_suse.OpenSUSEConfigurator,
"scientific": override_centos.CentOSConfigurator,
"scientific linux": override_centos.CentOSConfigurator,
}

View File

@@ -14,7 +14,7 @@ from certbot_apache.parser import get_aug_path
logger = logging.getLogger(__name__)
class ApacheHttp01(common.TLSSNI01):
class ApacheHttp01(common.ChallengePerformer):
"""Class that performs HTTP-01 challenges within the Apache configurator."""
CONFIG_TEMPLATE22_PRE = """\

View File

@@ -1,476 +0,0 @@
"""ParserNode interface for interacting with configuration tree.
General description
-------------------
The ParserNode interfaces are designed to be able to contain all the parsing logic,
while allowing their users to interact with the configuration tree in a Pythonic
and well structured manner.
The structure allows easy traversal of the tree of ParserNodes. Each ParserNode
stores a reference to its ancestor and immediate children, allowing the user to
traverse the tree using built in interface methods as well as accessing the interface
properties directly.
ParserNode interface implementation should stand between the actual underlying
parser functionality and the business logic within Configurator code, interfacing
with both. The ParserNode tree is a result of configuration parsing action.
ParserNode tree will be in charge of maintaining the parser state and hence the
abstract syntax tree (AST). Interactions between ParserNode tree and underlying
parser should involve only parsing the configuration files to this structure, and
writing it back to the filesystem - while preserving the format including whitespaces.
For some implementations (Apache for example) it's important to keep track of and
to use state information while parsing conditional blocks and directives. This
allows the implementation to set a flag to parts of the parsed configuration
structure as not being in effect in a case of unmatched conditional block. It's
important to store these blocks in the tree as well in order to not to conduct
destructive actions (failing to write back parts of the configuration) while writing
the AST back to the filesystem.
The ParserNode tree is in charge of maintaining the its own structure while every
child node fetched with find - methods or by iterating its list of children can be
changed in place. When making changes the affected nodes should be flagged as "dirty"
in order for the parser implementation to figure out the parts of the configuration
that need to be written back to disk during the save() operation.
Metadata
--------
The metadata holds all the implementation specific attributes of the ParserNodes -
things like the positional information related to the AST, file paths, whitespacing,
and any other information relevant to the underlying parser engine.
Access to the metadata should be handled by implementation specific methods, allowing
the Configurator functionality to access the underlying information where needed.
A good example of this is file path of a node - something that is needed by the
reverter functionality within the Configurator.
Apache implementation
---------------------
The Apache implementation of ParserNode interface requires some implementation
specific functionalities that are not described by the interface itself.
Conditional blocks
Apache configuration can have conditional blocks, for example: <IfModule ...>,
resulting the directives and subblocks within it being either enabled or disabled.
While find_* interface methods allow including the disabled parts of the configuration
tree in searches a special care needs to be taken while parsing the structure in
order to reflect the active state of configuration.
Whitespaces
Each ParserNode object is responsible of storing its prepending whitespace characters
in order to be able to write the AST back to filesystem like it was, preserving the
format, this applies for parameters of BlockNode and DirectiveNode as well.
When parameters of ParserNode are changed, the pre-existing whitespaces in the
parameter sequence are discarded, as the general reason for storing them is to
maintain the ability to write the configuration back to filesystem exactly like
it was. This loses its meaning when we have to change the directives or blocks
parameters for other reasons.
Searches and matching
Apache configuration is largely case insensitive, so the Apache implementation of
ParserNode interface needs to provide the user means to match block and directive
names and parameters in case insensitive manner. This does not apply to everything
however, for example the parameters of a conditional statement may be case sensitive.
For this reason the internal representation of data should not ignore the case.
"""
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class ParserNode(object):
"""
ParserNode is the basic building block of the tree of such nodes,
representing the structure of the configuration. It is largely meant to keep
the structure information intact and idiomatically accessible.
The root node as well as the child nodes of it should be instances of ParserNode.
Nodes keep track of their differences to on-disk representation of configuration
by marking modified ParserNodes as dirty to enable partial write-to-disk for
different files in the configuration structure.
While for the most parts the usage and the child types are obvious, "include"-
and similar directives are an exception to this rule. This is because of the
nature of include directives - which unroll the contents of another file or
configuration block to their place. While we could unroll the included nodes
to the parent tree, it remains important to keep the context of include nodes
separate in order to write back the original configuration as it was.
For parsers that require the implementation to keep track of the whitespacing,
it's responsibility of each ParserNode object itself to store its prepending
whitespaces in order to be able to reconstruct the complete configuration file
as it was when originally read from the disk.
"""
@property
@abc.abstractmethod
def ancestor(self): # pragma: no cover
"""
This property contains a reference to ancestor node, or None if the node
is the root node of the configuration tree.
:returns: The ancestor BlockNode object, or None for root node.
:rtype: ParserNode
"""
raise NotImplementedError
@property
@abc.abstractmethod
def dirty(self): # pragma: no cover
"""
This property contains a boolean value of the information if this node has
been modified since last save (or after the initial parse).
:returns: True if this node has had changes that have not yet been written
to disk.
:rtype: bool
"""
raise NotImplementedError
@abc.abstractmethod
def save(self, msg):
"""
Save traverses the children, and attempts to write the AST to disk for
all the objects that are marked dirty. The actual operation of course
depends on the underlying implementation. save() shouldn't be called
from the Configurator outside of its designated save() method in order
to ensure that the Reverter checkpoints are created properly.
Note: this approach of keeping internal structure of the configuration
within the ParserNode tree does not represent the file inclusion structure
of actual configuration files that reside in the filesystem. To handle
file writes properly, the file specific temporary trees should be extracted
from the full ParserNode tree where necessary when writing to disk.
"""
@six.add_metaclass(abc.ABCMeta)
class CommentNode(ParserNode):
"""
CommentNode class is used for representation of comments within the parsed
configuration structure. Because of the nature of comments, it is not able
to have child nodes and hence it is always treated as a leaf node.
CommentNode stores its contents in class variable 'comment' and does not
have a specific name.
"""
@property
@abc.abstractmethod
def comment(self): # pragma: no cover
"""
Comment property contains the contents of the comment without the comment
directives (typically # or /* ... */).
:returns: A string containing the comment
:rtype: str
"""
raise NotImplementedError
@six.add_metaclass(abc.ABCMeta)
class DirectiveNode(ParserNode):
"""
DirectiveNode class represents a configuration directive within the configuration.
It can have zero or more parameters attached to it. Because of the nature of
single directives, it is not able to have child nodes and hence it is always
treated as a leaf node.
"""
@property
@abc.abstractmethod
def enabled(self): # pragma: no cover
"""
Configuration blocks may have conditional statements enabling or disabling
their contents. This property returns the state of this DirectiveNode.
:returns: True if the DirectiveNode is parsed and enabled in the configuration.
:rtype: bool
"""
raise NotImplementedError
@property
@abc.abstractmethod
def name(self): # pragma: no cover
"""
Name property contains the name of the directive.
:returns: Name of this node
:rtype: str
"""
raise NotImplementedError
@property
@abc.abstractmethod
def parameters(self): # pragma: no cover
"""
This property contains a tuple of parameters of this ParserNode object
excluding whitespaces.
:returns: A tuple of parameters for this node
:rtype: tuple
"""
raise NotImplementedError
@abc.abstractmethod
def set_parameters(self, parameters):
"""
Sets the sequence of parameters for this ParserNode object without
whitespaces. While the whitespaces for parameters are discarded when using
this method, the whitespacing preceeding the ParserNode itself should be
kept intact.
:param list parameters: sequence of parameters
"""
@six.add_metaclass(abc.ABCMeta)
class BlockNode(ParserNode):
"""
BlockNode class represents a block of nested configuration directives, comments
and other blocks as its children. A BlockNode can have zero or more parameters
attached to it.
Configuration blocks typically consist of one or more child nodes of all possible
types. Because of this, the BlockNode class has various discovery and structure
management methods.
Lists of parameters used as an optional argument for some of the methods should
be lists of strings that are applicable parameters for each specific BlockNode
or DirectiveNode type. As an example, for a following configuration example:
<VirtualHost *:80>
...
</VirtualHost>
The node type would be BlockNode, name would be 'VirtualHost' and its parameters
would be: ['*:80'].
While for the following example:
LoadModule alias_module /usr/lib/apache2/modules/mod_alias.so
The node type would be DirectiveNode, name would be 'LoadModule' and its
parameters would be: ['alias_module', '/usr/lib/apache2/modules/mod_alias.so']
The applicable parameters are dependent on the underlying configuration language
and its grammar.
"""
@abc.abstractmethod
def add_child_block(self, name, parameters=None, position=None):
"""
Adds a new BlockNode child node with provided values and marks the callee
BlockNode dirty. This is used to add new children to the AST. The preceeding
whitespaces should not be added based on the ancestor or siblings for the
newly created object. This is to match the current behavior of the legacy
parser implementation.
:param str name: The name of the child node to add
:param list parameters: list of parameters for the node
:param int position: Position in the list of children to add the new child
node to. Defaults to None, which appends the newly created node to the list.
If an integer is given, the child is inserted before that index in the
list similar to list().insert.
:returns: BlockNode instance of the created child block
"""
@abc.abstractmethod
def add_child_directive(self, name, parameters=None, position=None):
"""
Adds a new DirectiveNode child node with provided values and marks the
callee BlockNode dirty. This is used to add new children to the AST. The
preceeding whitespaces should not be added based on the ancestor or siblings
for the newly created object. This is to match the current behavior of the
legacy parser implementation.
:param str name: The name of the child node to add
:param list parameters: list of parameters for the node
:param int position: Position in the list of children to add the new child
node to. Defaults to None, which appends the newly created node to the list.
If an integer is given, the child is inserted before that index in the
list similar to list().insert.
:returns: DirectiveNode instance of the created child directive
"""
@abc.abstractmethod
def add_child_comment(self, comment="", position=None):
"""
Adds a new CommentNode child node with provided value and marks the
callee BlockNode dirty. This is used to add new children to the AST. The
preceeding whitespaces should not be added based on the ancestor or siblings
for the newly created object. This is to match the current behavior of the
legacy parser implementation.
:param str comment: Comment contents
:param int position: Position in the list of children to add the new child
node to. Defaults to None, which appends the newly created node to the list.
If an integer is given, the child is inserted before that index in the
list similar to list().insert.
:returns: CommentNode instance of the created child comment
"""
@property
@abc.abstractmethod
def children(self): # pragma: no cover
"""
This property contains a list ParserNode objects that are the children
for this node. The order of children is the same as that of the parsed
configuration block.
:returns: A tuple of this block's children
:rtype: tuple
"""
raise NotImplementedError
@property
@abc.abstractmethod
def enabled(self):
"""
Configuration blocks may have conditional statements enabling or disabling
their contents. This property returns the state of this configuration block.
In case of unmatched conditional statement in block, this block itself should
be set enabled while its children should be set disabled.
:returns: True if the BlockNode is parsed and enabled in the configuration.
:rtype: bool
"""
@abc.abstractmethod
def find_blocks(self, name, exclude=True):
"""
Find a configuration block by name. This method walks the child tree of
ParserNodes under the instance it was called from. This way it is possible
to search for the whole configuration tree, when starting from root node or
to do a partial search when starting from a specified branch. The lookup
should be case insensitive.
:param str name: The name of the directive to search for
:param bool exclude: If the search results should exclude the contents of
ParserNode objects that reside within conditional blocks and because
of current state are not enabled.
:returns: A list of found BlockNode objects.
"""
@abc.abstractmethod
def find_directives(self, name, exclude=True):
"""
Find a directive by name. This method walks the child tree of ParserNodes
under the instance it was called from. This way it is possible to search
for the whole configuration tree, when starting from root node, or to do
a partial search when starting from a specified branch. The lookup should
be case insensitive.
:param str name: The name of the directive to search for
:param bool exclude: If the search results should exclude the contents of
ParserNode objects that reside within conditional blocks and because
of current state are not enabled.
:returns: A list of found DirectiveNode objects.
"""
@abc.abstractmethod
def find_comments(self, comment, exact=False):
"""
Find comments with value containing or being exactly the same as search term.
This method walks the child tree of ParserNodes under the instance it was
called from. This way it is possible to search for the whole configuration
tree, when starting from root node, or to do a partial search when starting
from a specified branch. The lookup should be case sensitive.
:param str comment: The content of comment to search for
:param bool exact: If the comment needs to exactly match the search term
:returns: A list of found CommentNode objects.
"""
@abc.abstractmethod
def delete_child(self, child):
"""
Remove a specified child node from the list of children of the called
BlockNode object.
:param ParserNode child: Child ParserNode object to remove from the list
of children of the callee.
"""
@property
@abc.abstractmethod
def name(self): # pragma: no cover
"""
Name property contains the name of the block. As an example for config:
<VirtualHost *:80> ... </VirtualHost>
the name would be "VirtualHost".
:returns: Name of this node
:rtype: str
"""
raise NotImplementedError
@property
@abc.abstractmethod
def parameters(self): # pragma: no cover
"""
This property contains a tuple of parameters of this ParserNode object
excluding whitespaces.
:returns: A tuple of parameters for this node
:rtype: tuple
"""
raise NotImplementedError
@abc.abstractmethod
def set_parameters(self, parameters):
"""
Sets the sequence of parameters for this ParserNode object without
whitespaces. While the whitespaces for parameters are discarded when using
this method, the whitespacing preceeding the ParserNode itself should be
kept intact.
:param list parameters: sequence of parameters
"""
@abc.abstractmethod
def unsaved_files(self):
"""
Returns a list of file paths that have been changed since the last save
(or the initial configuration parse). The intended use for this method
is to tell the Reverter which files need to be included in a checkpoint.
This is typically called for the root of the ParserNode tree.
:returns: list of file paths of files that have been changed but not yet
saved to disk.
"""

View File

@@ -98,7 +98,7 @@ class Addr(common.Addr):
return self.get_addr_obj(port)
class VirtualHost(object): # pylint: disable=too-few-public-methods
class VirtualHost(object):
"""Represents an Apache Virtualhost.
:ivar str filep: file path of VH
@@ -124,9 +124,8 @@ class VirtualHost(object): # pylint: disable=too-few-public-methods
strip_name = re.compile(r"^(?:.+://)?([^ :$]*)")
def __init__(self, filep, path, addrs, ssl, enabled, name=None,
aliases=None, modmacro=False, ancestor=None, node=None):
aliases=None, modmacro=False, ancestor=None):
# pylint: disable=too-many-arguments
"""Initialize a VH."""
self.filep = filep
self.path = path
@@ -137,7 +136,6 @@ class VirtualHost(object): # pylint: disable=too-few-public-methods
self.enabled = enabled
self.modmacro = modmacro
self.ancestor = ancestor
self.node = node
def get_names(self):
"""Return a set of all names."""

View File

@@ -19,7 +19,6 @@ logger = logging.getLogger(__name__)
class ApacheParser(object):
# pylint: disable=too-many-public-methods
"""Class handles the fine details of parsing the Apache Configuration.
.. todo:: Make parsing general... remove sites-available etc...

View File

@@ -1,4 +1,4 @@
# pylint: disable=too-many-public-methods,too-many-lines
# pylint: disable=too-many-lines
"""Test for certbot_apache.configurator AutoHSTS functionality"""
import re
import unittest

View File

@@ -1,4 +1,4 @@
# pylint: disable=too-many-public-methods,too-many-lines
# pylint: disable=too-many-lines
"""Test for certbot_apache.configurator."""
import copy
import shutil
@@ -108,13 +108,9 @@ class MultipleVhostsTest(util.ApacheTest):
exp[k.replace("_", "-")] = ApacheConfigurator.OS_DEFAULTS[k]
# Special cases
exp["vhost-root"] = None
exp["init-script"] = None
found = set()
for call in mock_add.call_args_list:
# init-script is a special case: deprecated argument
if call[0][0] != "init-script":
self.assertEqual(exp[call[0][0]], call[1]['default'])
found.add(call[0][0])
# Make sure that all (and only) the expected values exist
@@ -1296,13 +1292,13 @@ class MultipleVhostsTest(util.ApacheTest):
account_key = self.rsa512jwk
achall1 = achallenges.KeyAuthorizationAnnotatedChallenge(
challb=acme_util.chall_to_challb(
challenges.TLSSNI01(
challenges.HTTP01(
token=b"jIq_Xy1mXGN37tb4L6Xj_es58fW571ZNyXekdZzhh7Q"),
"pending"),
domain="encryption-example.demo", account_key=account_key)
achall2 = achallenges.KeyAuthorizationAnnotatedChallenge(
challb=acme_util.chall_to_challb(
challenges.TLSSNI01(
challenges.HTTP01(
token=b"uqnaPzxtrndteOqtrXb0Asl5gOJfWAnnx6QJyvcmlDU"),
"pending"),
domain="certbot.demo", account_key=account_key)

View File

@@ -7,6 +7,7 @@ from acme.magic_typing import List # pylint: disable=unused-import, no-name-in-
from certbot import achallenges
from certbot import errors
from certbot.compat import filesystem
from certbot.compat import os
from certbot.tests import acme_util
@@ -180,7 +181,7 @@ class ApacheHttp01Test(util.ApacheTest):
self.assertEqual(self.http.perform(), expected_response)
self.assertTrue(os.path.isdir(self.http.challenge_dir))
self._has_min_permissions(self.http.challenge_dir, 0o755)
self.assertTrue(filesystem.has_min_permissions(self.http.challenge_dir, 0o755))
self._test_challenge_conf()
for achall in achalls:
@@ -218,15 +219,10 @@ class ApacheHttp01Test(util.ApacheTest):
name = os.path.join(self.http.challenge_dir, achall.chall.encode("token"))
validation = achall.validation(self.account_key)
self._has_min_permissions(name, 0o644)
self.assertTrue(filesystem.has_min_permissions(name, 0o644))
with open(name, 'rb') as f:
self.assertEqual(f.read(), validation.encode())
def _has_min_permissions(self, path, min_mode):
"""Tests the given file has at least the permissions in mode."""
st_mode = os.stat(path).st_mode
self.assertEqual(st_mode, st_mode | min_mode)
if __name__ == "__main__":
unittest.main() # pragma: no cover

View File

@@ -1,4 +1,3 @@
# pylint: disable=too-many-public-methods
"""Tests for certbot_apache.parser."""
import shutil
import unittest

View File

@@ -1,232 +0,0 @@
""" Tests for ParserNode interface """
import unittest
import mock
from acme.magic_typing import Dict, Tuple # pylint: disable=unused-import, no-name-in-module
from certbot_apache import augeasparser
from certbot_apache import interfaces
from certbot_apache.tests import util
class DummyCommentNode(interfaces.CommentNode):
""" A dummy class implementing CommentNode interface """
ancestor = None
comment = ""
dirty = False
def save(self, msg): # pragma: no cover
pass
class DummyDirectiveNode(interfaces.DirectiveNode):
""" A dummy class implementing DirectiveNode interface """
ancestor = None
parameters = tuple() # type: Tuple[str, ...]
dirty = False
enabled = True
name = ""
def save(self, msg): # pragma: no cover
pass
def set_parameters(self, parameters): # pragma: no cover
pass
class DummyBlockNode(interfaces.BlockNode):
""" A dummy class implementing BlockNode interface """
ancestor = None
parameters = tuple() # type: Tuple[str, ...]
children = tuple() # type: Tuple[interfaces.ParserNode, ...]
dirty = False
enabled = True
name = ""
def save(self, msg): # pragma: no cover
pass
def add_child_block(self, name, parameters=None, position=None): # pragma: no cover
pass
def add_child_directive(self, name, parameters=None, position=None): # pragma: no cover
pass
def add_child_comment(self, comment="", position=None): # pragma: no cover
pass
def find_blocks(self, name, exclude=True): # pragma: no cover
pass
def find_directives(self, name, exclude=True): # pragma: no cover
pass
def find_comments(self, comment, exact=False): # pragma: no cover
pass
def delete_child(self, child): # pragma: no cover
pass
def set_parameters(self, parameters): # pragma: no cover
pass
def unsaved_files(self): # pragma: no cover
pass
class ParserNodeTest(util.ApacheTest):
"""Test cases for ParserNode interface"""
def __init__(self, *args, **kwargs):
super(ParserNodeTest, self).__init__(*args, **kwargs)
self.mock_nodes = dict() # type: Dict[str, interfaces.ParserNode]
def setUp(self): # pylint: disable=arguments-differ
super(ParserNodeTest, self).setUp()
self.config = util.get_apache_configurator(
self.config_path, self.vhost_path, self.config_dir, self.work_dir)
self.vh_truth = util.get_vh_truth(
self.temp_dir, "debian_apache_2_4/multiple_vhosts")
def test_dummy(self):
dummyblock = DummyBlockNode()
dummydirective = DummyDirectiveNode()
dummycomment = DummyCommentNode()
def _create_mock_vhost_nodes(self, servername, serveraliases, addrs):
"""Create a mock VirtualHost nodes"""
nodes = {
"VirtualHost": augeasparser.AugeasBlockNode("VirtualHost", tuple(addrs)),
"ServerName": augeasparser.AugeasDirectiveNode("ServerName",
(servername,)),
"ServerAlias": augeasparser.AugeasDirectiveNode("ServerAlias",
tuple(serveraliases)),
"Macro": augeasparser.AugeasDirectiveNode("Macro", ("variable", "value",)),
"SSLEngine": augeasparser.AugeasDirectiveNode("SSLEngine", ("on",))
}
return nodes
def mock_find_directives(self, name, exclude=True): # pylint: disable=unused-argument
"""
Mocks BlockNode.find_directives() and returns values defined in class
variable self.mock_nodes, set by the test case
"""
try:
return self.mock_nodes[name]
except KeyError:
return []
def test_create_vhost_v2_nonssl(self):
nodes = self._create_mock_vhost_nodes("example.com",
["a1.example.com", "a2.example.com"],
["*:80"])
nodes["VirtualHost"].find_directives = self.mock_find_directives
self.mock_nodes = {"ServerName": [nodes["ServerName"]],
"ServerAlias": [nodes["ServerAlias"]]}
vhost = self.config._create_vhost_v2(nodes["VirtualHost"]) # pylint: disable=protected-access
self.assertEqual(vhost.name, "example.com")
self.assertTrue("a1.example.com" in vhost.aliases)
self.assertTrue("a2.example.com" in vhost.aliases)
self.assertEqual(len(vhost.aliases), 2)
self.assertEqual(len(vhost.addrs), 1)
self.assertFalse(vhost.ssl)
self.assertFalse(vhost.modmacro)
def test_create_vhost_v2_macro(self):
nodes = self._create_mock_vhost_nodes("example.com",
["a1.example.com", "a2.example.com"],
["*:80"])
nodes["VirtualHost"].find_directives = self.mock_find_directives
self.mock_nodes = {"ServerName": [nodes["ServerName"]],
"ServerAlias": [nodes["ServerAlias"]],
"Macro": [nodes["Macro"]]}
vhost = self.config._create_vhost_v2(nodes["VirtualHost"]) # pylint: disable=protected-access
self.assertEqual(vhost.name, None)
self.assertEqual(vhost.aliases, set())
self.assertFalse(vhost.ssl)
self.assertTrue(vhost.modmacro)
def test_create_vhost_v2_ssl_port(self):
nodes = self._create_mock_vhost_nodes("example.com",
["a1.example.com", "a2.example.com"],
["*:443"])
nodes["VirtualHost"].find_directives = self.mock_find_directives
self.mock_nodes = {"ServerName": [nodes["ServerName"]],
"ServerAlias": [nodes["ServerAlias"]]}
vhost = self.config._create_vhost_v2(nodes["VirtualHost"]) # pylint: disable=protected-access
self.assertTrue(vhost.ssl)
self.assertFalse(vhost.modmacro)
def test_create_vhost_v2_sslengine(self):
nodes = self._create_mock_vhost_nodes("example.com",
["a1.example.com", "a2.example.com"],
["*:80"])
nodes["VirtualHost"].find_directives = self.mock_find_directives
self.mock_nodes = {"ServerName": [nodes["ServerName"]],
"ServerAlias": [nodes["ServerAlias"]],
"SSLEngine": [nodes["SSLEngine"]]}
vhost = self.config._create_vhost_v2(nodes["VirtualHost"]) # pylint: disable=protected-access
self.assertTrue(vhost.ssl)
self.assertFalse(vhost.modmacro)
def test_create_vhost_v2_no_filename(self):
nodes = self._create_mock_vhost_nodes("example.com",
["a1.example.com", "a2.example.com"],
["*:80"])
nodes["VirtualHost"].find_directives = self.mock_find_directives
self.mock_nodes = {"ServerName": [nodes["ServerName"]],
"ServerAlias": [nodes["ServerAlias"]],
"SSLEngine": [nodes["SSLEngine"]]}
filename = "certbot_apache.augeasparser.AugeasBlockNode.get_filename"
with mock.patch(filename) as mock_filename:
mock_filename.return_value = None
vhost = self.config._create_vhost_v2(nodes["VirtualHost"]) # pylint: disable=protected-access
self.assertEqual(vhost, None)
def test_comment_node_creation(self):
comment = augeasparser.AugeasCommentNode("This is a comment")
comment._metadata["augeas_path"] = "/whatever" # pylint: disable=protected-access
self.assertEqual(comment.get_metadata("augeas_path"), "/whatever")
self.assertEqual(comment.get_metadata("something_else"), None)
self.assertEqual(comment.comment, "This is a comment")
def test_directive_node_creation(self):
directive = augeasparser.AugeasDirectiveNode("DIRNAME", ("p1", "p2",))
directive._metadata["augeas_path"] = "/whatever" # pylint: disable=protected-access
self.assertEqual(directive.get_metadata("augeas_path"), "/whatever")
self.assertEqual(directive.get_metadata("something_else"), None)
self.assertEqual(directive.name, "DIRNAME")
self.assertEqual(directive.parameters, ("p1", "p2",))
self.assertTrue(directive.has_parameter("P1", 0))
self.assertFalse(directive.has_parameter("P2", 0))
self.assertFalse(directive.has_parameter("P3"))
self.assertTrue(directive.has_parameter("P2"))
self.assertEqual(directive.get_filename(), "CERTBOT_PASS_ASSERT")
def test_block_node_creation(self):
block = augeasparser.AugeasBlockNode("BLOCKNAME", ("first", "SECOND",))
block._metadata["augeas_path"] = "/whatever" # pylint: disable=protected-access
self.assertEqual(block.get_metadata("augeas_path"), "/whatever")
self.assertEqual(block.get_metadata("something_else"), None)
self.assertEqual(block.name, "BLOCKNAME")
self.assertEqual(block.parameters, ("first", "SECOND",))
self.assertFalse(block.has_parameter("second", 0))
self.assertFalse(block.has_parameter("SECOND", 0))
self.assertFalse(block.has_parameter("third"))
self.assertTrue(block.has_parameter("FIRST"))
self.assertEqual(block.get_filename(), "CERTBOT_PASS_ASSERT")
if __name__ == "__main__":
unittest.main() # pragma: no cover

View File

@@ -18,7 +18,7 @@ from certbot_apache import entrypoint
from certbot_apache import obj
class ApacheTest(unittest.TestCase): # pylint: disable=too-few-public-methods
class ApacheTest(unittest.TestCase):
def setUp(self, test_dir="debian_apache_2_4/multiple_vhosts",
config_root="debian_apache_2_4/multiple_vhosts/apache2",
@@ -81,7 +81,7 @@ class ParserTest(ApacheTest):
self.config_path, self.vhost_path, configurator=self.config)
def get_apache_configurator( # pylint: disable=too-many-arguments, too-many-locals
def get_apache_configurator(
config_path, vhost_path,
config_dir, work_dir, version=(2, 4, 7),
os_info="generic",

View File

@@ -1,5 +0,0 @@
:mod:`certbot_apache.tls_sni_01`
------------------------------------
.. automodule:: certbot_apache.tls_sni_01
:members:

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
certbot[dev]==0.37.0
certbot[dev]==0.39.0

View File

@@ -4,13 +4,13 @@ from setuptools.command.test import test as TestCommand
import sys
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.37.0',
'certbot>=0.39.0',
'mock',
'python-augeas',
'setuptools',
@@ -62,6 +62,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="0.37.1"
LE_AUTO_VERSION="0.40.1"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@@ -775,6 +775,8 @@ elif [ -f /etc/redhat-release ]; then
RPM_USE_PYTHON_3=1
elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then
RPM_USE_PYTHON_3=1
elif [ "$RPM_DIST_NAME" = "centos" -a "$RPM_DIST_VERSION" -ge 8 ]; then
RPM_USE_PYTHON_3=1
else
RPM_USE_PYTHON_3=0
fi
@@ -1134,73 +1136,76 @@ if [ "$1" = "--le-auto-phase2" ]; then
# To generate this, do (with docker and package hashin installed):
# ```
# letsencrypt-auto-source/rebuild_dependencies.py \
# letsencrypt-auto-sources/pieces/dependency-requirements.txt
# letsencrypt-auto-source/pieces/dependency-requirements.txt
# ```
# If you want to update a single dependency, run commands similar to these:
# ```
# pip install hashin
# hashin -r dependency-requirements.txt cryptography==1.5.2
# ```
ConfigArgParse==0.14.0 \
--hash=sha256:2e2efe2be3f90577aca9415e32cb629aa2ecd92078adbe27b53a03e53ff12e91
asn1crypto==0.24.0 \
--hash=sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87 \
--hash=sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49
certifi==2019.3.9 \
--hash=sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5 \
--hash=sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae
cffi==1.12.2 \
--hash=sha256:00b97afa72c233495560a0793cdc86c2571721b4271c0667addc83c417f3d90f \
--hash=sha256:0ba1b0c90f2124459f6966a10c03794082a2f3985cd699d7d63c4a8dae113e11 \
--hash=sha256:0bffb69da295a4fc3349f2ec7cbe16b8ba057b0a593a92cbe8396e535244ee9d \
--hash=sha256:21469a2b1082088d11ccd79dd84157ba42d940064abbfa59cf5f024c19cf4891 \
--hash=sha256:2e4812f7fa984bf1ab253a40f1f4391b604f7fc424a3e21f7de542a7f8f7aedf \
--hash=sha256:2eac2cdd07b9049dd4e68449b90d3ef1adc7c759463af5beb53a84f1db62e36c \
--hash=sha256:2f9089979d7456c74d21303c7851f158833d48fb265876923edcb2d0194104ed \
--hash=sha256:3dd13feff00bddb0bd2d650cdb7338f815c1789a91a6f68fdc00e5c5ed40329b \
--hash=sha256:4065c32b52f4b142f417af6f33a5024edc1336aa845b9d5a8d86071f6fcaac5a \
--hash=sha256:51a4ba1256e9003a3acf508e3b4f4661bebd015b8180cc31849da222426ef585 \
--hash=sha256:59888faac06403767c0cf8cfb3f4a777b2939b1fbd9f729299b5384f097f05ea \
--hash=sha256:59c87886640574d8b14910840327f5cd15954e26ed0bbd4e7cef95fa5aef218f \
--hash=sha256:610fc7d6db6c56a244c2701575f6851461753c60f73f2de89c79bbf1cc807f33 \
--hash=sha256:70aeadeecb281ea901bf4230c6222af0248c41044d6f57401a614ea59d96d145 \
--hash=sha256:71e1296d5e66c59cd2c0f2d72dc476d42afe02aeddc833d8e05630a0551dad7a \
--hash=sha256:8fc7a49b440ea752cfdf1d51a586fd08d395ff7a5d555dc69e84b1939f7ddee3 \
--hash=sha256:9b5c2afd2d6e3771d516045a6cfa11a8da9a60e3d128746a7fe9ab36dfe7221f \
--hash=sha256:9c759051ebcb244d9d55ee791259ddd158188d15adee3c152502d3b69005e6bd \
--hash=sha256:b4d1011fec5ec12aa7cc10c05a2f2f12dfa0adfe958e56ae38dc140614035804 \
--hash=sha256:b4f1d6332339ecc61275bebd1f7b674098a66fea11a00c84d1c58851e618dc0d \
--hash=sha256:c030cda3dc8e62b814831faa4eb93dd9a46498af8cd1d5c178c2de856972fd92 \
--hash=sha256:c2e1f2012e56d61390c0e668c20c4fb0ae667c44d6f6a2eeea5d7148dcd3df9f \
--hash=sha256:c37c77d6562074452120fc6c02ad86ec928f5710fbc435a181d69334b4de1d84 \
--hash=sha256:c8149780c60f8fd02752d0429246088c6c04e234b895c4a42e1ea9b4de8d27fb \
--hash=sha256:cbeeef1dc3c4299bd746b774f019de9e4672f7cc666c777cd5b409f0b746dac7 \
--hash=sha256:e113878a446c6228669144ae8a56e268c91b7f1fafae927adc4879d9849e0ea7 \
--hash=sha256:e21162bf941b85c0cda08224dade5def9360f53b09f9f259adb85fc7dd0e7b35 \
--hash=sha256:fb6934ef4744becbda3143d30c6604718871495a5e36c408431bf33d9c146889
certifi==2019.6.16 \
--hash=sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939 \
--hash=sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695
cffi==1.12.3 \
--hash=sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774 \
--hash=sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d \
--hash=sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90 \
--hash=sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b \
--hash=sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63 \
--hash=sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45 \
--hash=sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25 \
--hash=sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3 \
--hash=sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b \
--hash=sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647 \
--hash=sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016 \
--hash=sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4 \
--hash=sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb \
--hash=sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753 \
--hash=sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7 \
--hash=sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9 \
--hash=sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f \
--hash=sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8 \
--hash=sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f \
--hash=sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc \
--hash=sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42 \
--hash=sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3 \
--hash=sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909 \
--hash=sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45 \
--hash=sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d \
--hash=sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512 \
--hash=sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff \
--hash=sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201
chardet==3.0.4 \
--hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
--hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
configobj==5.0.6 \
--hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902
cryptography==2.6.1 \
--hash=sha256:066f815f1fe46020877c5983a7e747ae140f517f1b09030ec098503575265ce1 \
--hash=sha256:210210d9df0afba9e000636e97810117dc55b7157c903a55716bb73e3ae07705 \
--hash=sha256:26c821cbeb683facb966045e2064303029d572a87ee69ca5a1bf54bf55f93ca6 \
--hash=sha256:2afb83308dc5c5255149ff7d3fb9964f7c9ee3d59b603ec18ccf5b0a8852e2b1 \
--hash=sha256:2db34e5c45988f36f7a08a7ab2b69638994a8923853dec2d4af121f689c66dc8 \
--hash=sha256:409c4653e0f719fa78febcb71ac417076ae5e20160aec7270c91d009837b9151 \
--hash=sha256:45a4f4cf4f4e6a55c8128f8b76b4c057027b27d4c67e3fe157fa02f27e37830d \
--hash=sha256:48eab46ef38faf1031e58dfcc9c3e71756a1108f4c9c966150b605d4a1a7f659 \
--hash=sha256:6b9e0ae298ab20d371fc26e2129fd683cfc0cfde4d157c6341722de645146537 \
--hash=sha256:6c4778afe50f413707f604828c1ad1ff81fadf6c110cb669579dea7e2e98a75e \
--hash=sha256:8c33fb99025d353c9520141f8bc989c2134a1f76bac6369cea060812f5b5c2bb \
--hash=sha256:9873a1760a274b620a135054b756f9f218fa61ca030e42df31b409f0fb738b6c \
--hash=sha256:9b069768c627f3f5623b1cbd3248c5e7e92aec62f4c98827059eed7053138cc9 \
--hash=sha256:9e4ce27a507e4886efbd3c32d120db5089b906979a4debf1d5939ec01b9dd6c5 \
--hash=sha256:acb424eaca214cb08735f1a744eceb97d014de6530c1ea23beb86d9c6f13c2ad \
--hash=sha256:c8181c7d77388fe26ab8418bb088b1a1ef5fde058c6926790c8a0a3d94075a4a \
--hash=sha256:d4afbb0840f489b60f5a580a41a1b9c3622e08ecb5eec8614d4fb4cd914c4460 \
--hash=sha256:d9ed28030797c00f4bc43c86bf819266c76a5ea61d006cd4078a93ebf7da6bfd \
--hash=sha256:e603aa7bb52e4e8ed4119a58a03b60323918467ef209e6ff9db3ac382e5cf2c6
# Package enum34 needs to be explicitly limited to Python2.x, in order to avoid
# certbot-auto failures on Python 3.6+ which enum34 doesn't support. See #5456.
enum34==1.1.6 ; python_version < '3.4' \
cryptography==2.7 \
--hash=sha256:24b61e5fcb506424d3ec4e18bca995833839bf13c59fc43e530e488f28d46b8c \
--hash=sha256:25dd1581a183e9e7a806fe0543f485103232f940fcfc301db65e630512cce643 \
--hash=sha256:3452bba7c21c69f2df772762be0066c7ed5dc65df494a1d53a58b683a83e1216 \
--hash=sha256:41a0be220dd1ed9e998f5891948306eb8c812b512dc398e5a01846d855050799 \
--hash=sha256:5751d8a11b956fbfa314f6553d186b94aa70fdb03d8a4d4f1c82dcacf0cbe28a \
--hash=sha256:5f61c7d749048fa6e3322258b4263463bfccefecb0dd731b6561cb617a1d9bb9 \
--hash=sha256:72e24c521fa2106f19623a3851e9f89ddfdeb9ac63871c7643790f872a305dfc \
--hash=sha256:7b97ae6ef5cba2e3bb14256625423413d5ce8d1abb91d4f29b6d1a081da765f8 \
--hash=sha256:961e886d8a3590fd2c723cf07be14e2a91cf53c25f02435c04d39e90780e3b53 \
--hash=sha256:96d8473848e984184b6728e2c9d391482008646276c3ff084a1bd89e15ff53a1 \
--hash=sha256:ae536da50c7ad1e002c3eee101871d93abdc90d9c5f651818450a0d3af718609 \
--hash=sha256:b0db0cecf396033abb4a93c95d1602f268b3a68bb0a9cc06a7cff587bb9a7292 \
--hash=sha256:cfee9164954c186b191b91d4193989ca994703b2fff406f71cf454a2d3c7327e \
--hash=sha256:e6347742ac8f35ded4a46ff835c60e68c22a536a8ae5c4422966d06946b6d4c6 \
--hash=sha256:f27d93f0139a3c056172ebb5d4f9056e770fdf0206c2f422ff2ebbad142e09ed \
--hash=sha256:f57b76e46a58b63d1c6375017f4564a28f19a5ca912691fd2e4261b3414b618d
distro==1.4.0 \
--hash=sha256:362dde65d846d23baee4b5c058c8586f219b5a54be1cf5fc6ff55c4578392f57 \
--hash=sha256:eedf82a470ebe7d010f1872c17237c79ab04097948800029994fa458e52fb4b4
enum34==1.1.6 \
--hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \
--hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \
--hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \
@@ -1216,18 +1221,18 @@ idna==2.8 \
ipaddress==1.0.22 \
--hash=sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794 \
--hash=sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c
josepy==1.1.0 \
--hash=sha256:1309a25aac3caeff5239729c58ff9b583f7d022ffdb1553406ddfc8e5b52b76e \
--hash=sha256:fb5c62c77d26e04df29cb5ecd01b9ce69b6fcc9e521eb1ca193b7faa2afa7086
josepy==1.2.0 \
--hash=sha256:8ea15573203f28653c00f4ac0142520777b1c59d9eddd8da3f256c6ba3cac916 \
--hash=sha256:9cec9a839fe9520f0420e4f38e7219525daccce4813296627436fe444cd002d3
mock==1.3.0 \
--hash=sha256:1e247dbecc6ce057299eb7ee019ad68314bb93152e81d9a6110d35f4d5eca0f6 \
--hash=sha256:3f573a18be94de886d1191f27c168427ef693e8dcfcecf95b170577b2eb69cbb
parsedatetime==2.4 \
--hash=sha256:3d817c58fb9570d1eec1dd46fa9448cd644eeed4fb612684b02dfda3a79cb84b \
--hash=sha256:9ee3529454bf35c40a77115f5a596771e59e1aee8c53306f346c461b8e913094
pbr==5.1.3 \
--hash=sha256:8257baf496c8522437e8a6cfe0f15e00aedc6c0e0e7c9d55eeeeab31e0853843 \
--hash=sha256:8c361cc353d988e4f5b998555c88098b9d5964c2e11acf7b0d21925a66bb5824
pbr==5.4.2 \
--hash=sha256:56e52299170b9492513c64be44736d27a512fa7e606f21942160b68ce510b4bc \
--hash=sha256:9b321c204a88d8ab5082699469f52cc94c5da45c51f114113d01b3d993c24cdf
pyOpenSSL==19.0.0 \
--hash=sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200 \
--hash=sha256:c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6
@@ -1236,14 +1241,14 @@ pyRFC3339==1.1 \
--hash=sha256:81b8cbe1519cdb79bed04910dd6fa4e181faf8c88dff1e1b987b5f7ab23a5b1a
pycparser==2.19 \
--hash=sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3
pyparsing==2.3.1 \
--hash=sha256:66c9268862641abcac4a96ba74506e594c884e3f57690a696d21ad8210ed667a \
--hash=sha256:f6c5ef0d7480ad048c054c37632c67fca55299990fff127850181659eea33fc3
pyparsing==2.4.2 \
--hash=sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80 \
--hash=sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4
python-augeas==0.5.0 \
--hash=sha256:67d59d66cdba8d624e0389b87b2a83a176f21f16a87553b50f5703b23f29bac2
pytz==2018.9 \
--hash=sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9 \
--hash=sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c
pytz==2019.2 \
--hash=sha256:26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32 \
--hash=sha256:c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7
requests==2.21.0 \
--hash=sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e \
--hash=sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b
@@ -1253,15 +1258,15 @@ requests-toolbelt==0.9.1 \
six==1.12.0 \
--hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
--hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73
urllib3==1.24.2 \
--hash=sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0 \
--hash=sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3
urllib3==1.24.3 \
--hash=sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4 \
--hash=sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb
zope.component==4.5 \
--hash=sha256:6edfd626c3b593b72895a8cfcf79bff41f4619194ce996a85bce31ac02b94e55 \
--hash=sha256:984a06ba3def0b02b1117fa4c45b56e772e8c29c0340820fbf367e440a93a3a4
zope.deferredimport==4.3 \
--hash=sha256:2ddef5a7ecfff132a2dd796253366ecf9748a446e30f1a0b3a636aec9d9c05c5 \
--hash=sha256:4aae9cbacb2146cca58e62be0a914f0cec034d3b2d41135ea212ca8a96f4b5ec
zope.deferredimport==4.3.1 \
--hash=sha256:57b2345e7b5eef47efcd4f634ff16c93e4265de3dcf325afc7315ade48d909e1 \
--hash=sha256:9a0c211df44aa95f1c4e6d2626f90b400f56989180d3ef96032d708da3d23e0a
zope.deprecation==4.4.0 \
--hash=sha256:0d453338f04bacf91bbfba545d8bcdf529aa829e67b705eac8c1a7fdce66e2df \
--hash=sha256:f1480b74995958b24ce37b0ef04d3663d2683e5d6debc96726eff18acf4ea113
@@ -1309,18 +1314,18 @@ zope.interface==4.6.0 \
--hash=sha256:d788a3999014ddf416f2dc454efa4a5dbeda657c6aba031cf363741273804c6b \
--hash=sha256:eed88ae03e1ef3a75a0e96a55a99d7937ed03e53d0cffc2451c208db445a2966 \
--hash=sha256:f99451f3a579e73b5dd58b1b08d1179791d49084371d9a47baad3b22417f0317
zope.proxy==4.3.1 \
--hash=sha256:0cbcfcafaa3b5fde7ba7a7b9a2b5f09af25c9b90087ad65f9e61359fed0ca63b \
--hash=sha256:3de631dd5054a3a20b9ebff0e375f39c0565f1fb9131200d589a6a8f379214cd \
--hash=sha256:5429134d04d42262f4dac25f6dea907f6334e9a751ffc62cb1d40226fb52bdeb \
--hash=sha256:563c2454b2d0f23bca54d2e0e4d781149b7b06cb5df67e253ca3620f37202dd2 \
--hash=sha256:5bcf773345016b1461bb07f70c635b9386e5eaaa08e37d3939dcdf12d3fdbec5 \
--hash=sha256:8d84b7aef38c693874e2f2084514522bf73fd720fde0ce2a9352a51315ffa475 \
--hash=sha256:90de9473c05819b36816b6cb957097f809691836ed3142648bf62da84b4502fe \
--hash=sha256:dd592a69fe872445542a6e1acbefb8e28cbe6b4007b8f5146da917e49b155cc3 \
--hash=sha256:e7399ab865399fce322f9cefc6f2f3e4099d087ba581888a9fea1bbe1db42a08 \
--hash=sha256:e7d1c280d86d72735a420610df592aac72332194e531a8beff43a592c3a1b8eb \
--hash=sha256:e90243fee902adb0c39eceb3c69995c0f2004bc3fdb482fbf629efc656d124ed
zope.proxy==4.3.2 \
--hash=sha256:320a7619992e42142549ebf61e14ce27683b4d14b0cbc45f7c037ba64edb560c \
--hash=sha256:824d4dbabbb7deb84f25fdb96ea1eeca436a1802c3c8d323b3eb4ac9d527d41c \
--hash=sha256:8a32eb9c94908f3544da2dae3f4a9e6961d78819b88ac6b6f4a51cee2d65f4a0 \
--hash=sha256:96265fd3bc3ea646f98482e16307a69de21402eeaaaaf4b841c1161ac2f71bb0 \
--hash=sha256:ab6d6975d9c51c13cac828ff03168de21fb562b0664c59bcdc4a4b10f39a5b17 \
--hash=sha256:af10cb772391772463f65a58348e2de5ecc06693c16d2078be276dc068bcbb54 \
--hash=sha256:b8fd3a3de3f7b6452775e92af22af5977b17b69ac86a38a3ddfe870e40a0d05f \
--hash=sha256:bb7088f1bed3b8214284a5e425dc23da56f2f28e8815b7580bfed9e245b6c0b6 \
--hash=sha256:bc29b3665eac34f14c4aef5224bef045efcfb1a7d12d78c8685858de5fbf21c0 \
--hash=sha256:c39fa6a159affeae5fe31b49d9f5b12bd674fe77271a9a324408b271440c50a7 \
--hash=sha256:e946a036ac5b9f897e986ac9dc950a34cffc857d88eae6727b8434fbc4752366
# Contains the requirements for the letsencrypt package.
#
@@ -1333,18 +1338,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.37.1 \
--hash=sha256:84dbdad204327b8d8ef9ab5b040f2be1e427a9f7e087affcc9a6051ea1b03fe7 \
--hash=sha256:aace73e63b0c11cdb4b0bd33e1780c1fbe0ce5669dc72e80c3aa9500145daf16
acme==0.37.1 \
--hash=sha256:83a4f6f3c5eb6a85233d5ba87714b426f2d096df58d711f8a2fc4071eb3fd3fc \
--hash=sha256:c069a761990751f7c4bf51d2e87ae10319bf460de6629d2908c9fa6f69e97111
certbot-apache==0.37.1 \
--hash=sha256:3ea832408877b12b3a60d17e8b2ee3387364f8c3023ac267161c25b99087cd42 \
--hash=sha256:e46c2644451101c0e216aa1f525a577cc903efaf871e0e4da277224a4439040c
certbot-nginx==0.37.1 \
--hash=sha256:1f9af389d26f06634e2eefaace3354e7679dabb4295e1d55d05a4ee7e23a64bd \
--hash=sha256:02a7ec15bd388d0f0e94a34c86a8f8d618ec7d5ffde0c206039bb4c46b294ce4
certbot==0.40.1 \
--hash=sha256:afe4d7edc61d4cab8b6f7ab7611d66aaba67d9f0404fa2760bd1cc430b2ec9ec \
--hash=sha256:8dc81b3044cf401c55fa36c30893887fcb92657df1d76a8848059683df3b10d1
acme==0.40.1 \
--hash=sha256:a85387c26fb4fc24511b2579b8c61177b3175fd25e130c5be95a840d9f67d54f \
--hash=sha256:33bf8686408d5b6b79886a9a43aee691ca754408deaec4fb2bb17b9af48a5ffc
certbot-apache==0.40.1 \
--hash=sha256:6c4a4e21a17bd8120056595e5670c9a0f86756da0ad269196e8d56fc1b9fec82 \
--hash=sha256:16404e9e404f0b98c18bd752fad812a45ef7f9b0efa9bbc8589f24a94e67de7c
certbot-nginx==0.40.1 \
--hash=sha256:acdbfc4ab75ebc810264ee1248332f8e857c5e7776717b7cd53c4ceceb2b4d34 \
--hash=sha256:014fdda80647ad9e67019b16c7cdaee5d21a750b393bcb98e1300615cc930f4f
UNLIKELY_EOF
# -------------------------------------------------------------------------

View File

@@ -2,6 +2,7 @@
# Avoid false warnings because certbot packages are not installed in the thread that executes
# the coverage: indeed, certbot is launched as a CLI from a subprocess.
disable_warnings = module-not-imported,no-data-collected
omit = **/*_test.py,**/tests/*,**/dns_common*,**/certbot_nginx/parser_obj.py
[report]
# Exclude unit tests in coverage during integration tests.

View File

@@ -62,11 +62,6 @@ def test_registration_override(context):
context.certbot(['unregister'])
context.certbot(['register', '--email', 'ex1@domain.org,ex2@domain.org'])
# TODO: When `certbot register --update-registration` is fully deprecated,
# delete the two following deprecated uses
context.certbot(['register', '--update-registration', '--email', 'ex1@domain.org'])
context.certbot(['register', '--update-registration', '--email', 'ex1@domain.org,ex2@domain.org'])
context.certbot(['update_account', '--email', 'example@domain.org'])
context.certbot(['update_account', '--email', 'ex1@domain.org,ex2@domain.org'])
@@ -594,3 +589,21 @@ def test_ocsp_status_live(context):
assert output.count('INVALID') == 1, 'Expected {0} to be INVALID'.format(cert)
assert output.count('REVOKED') == 1, 'Expected {0} to be REVOKED'.format(cert)
def test_dry_run_deactivate_authzs(context):
"""Test that Certbot deactivates authorizations when performing a dry run"""
name = context.get_domain('dry-run-authz-deactivation')
args = ['certonly', '--cert-name', name, '-d', name, '--dry-run']
log_line = 'Recreating order after authz deactivation'
# First order will not need deactivation
context.certbot(args)
with open(join(context.workspace, 'logs', 'letsencrypt.log'), 'r') as f:
assert log_line not in f.read(), 'First order should not have had any authz reuse'
# Second order will require deactivation
context.certbot(args)
with open(join(context.workspace, 'logs', 'letsencrypt.log'), 'r') as f:
assert log_line in f.read(), 'Second order should have been recreated due to authz reuse'

View File

@@ -125,6 +125,7 @@ class ACMEServer(object):
environ = os.environ.copy()
environ['PEBBLE_VA_NOSLEEP'] = '1'
environ['PEBBLE_WFE_NONCEREJECT'] = '0'
environ['PEBBLE_AUTHZREUSE'] = '100'
self._launch_process(
[pebble_path, '-config', pebble_config_path, '-dnsserver', '127.0.0.1:8053'],

View File

@@ -6,7 +6,7 @@ import subprocess
import sys
import os
from certbot_integration_tests.utils import misc
import certbot_integration_tests
from certbot_integration_tests.utils.constants import *
@@ -33,18 +33,58 @@ def certbot_test(certbot_args, directory_url, http_01_port, tls_alpn_01_port,
return subprocess.check_output(command, universal_newlines=True, cwd=workspace, env=env)
def _prepare_args_env(certbot_args, directory_url, http_01_port, tls_alpn_01_port,
config_dir, workspace, force_renew):
def _prepare_environ(workspace):
new_environ = os.environ.copy()
new_environ['TMPDIR'] = workspace
# So, pytest is nice, and a little too nice for our usage.
# In order to help user to call seamlessly any piece of python code without requiring to
# install it as a full-fledged setuptools distribution for instance, it may inject the path
# to the test files into the PYTHONPATH. This allows the python interpreter to import
# as modules any python file available at this path.
# See https://docs.pytest.org/en/3.2.5/pythonpath.html for the explanation and description.
# However this behavior is not good in integration tests, in particular the nginx oldest ones.
# Indeed during these kind of tests certbot is installed as a transitive dependency to
# certbot-nginx. Here is the trick: this certbot version is not necessarily the same as
# the certbot codebase lying in current working directory. For instance in oldest tests
# certbot==0.36.0 may be installed while the codebase corresponds to certbot==0.37.0.dev0.
# Then during a pytest run, PYTHONPATH contains the path to the Certbot codebase, so invoking
# certbot will import the modules from the codebase (0.37.0.dev0), not from the
# required/installed version (0.36.0).
# This will lead to funny and totally incomprehensible errors. To avoid that, we ensure that
# if PYTHONPATH is set, it does not contain the path to the root of the codebase.
if new_environ.get('PYTHONPATH'):
# certbot_integration_tests.__file__ is:
# '/path/to/certbot/certbot-ci/certbot_integration_tests/__init__.pyc'
# ... and we want '/path/to/certbot'
certbot_root = os.path.dirname(os.path.dirname(os.path.dirname(certbot_integration_tests.__file__)))
python_paths = [path for path in new_environ['PYTHONPATH'].split(':') if path != certbot_root]
new_environ['PYTHONPATH'] = ':'.join(python_paths)
return new_environ
def _compute_additional_args(workspace, environ, force_renew):
additional_args = []
if misc.get_certbot_version() >= LooseVersion('0.30.0'):
output = subprocess.check_output(['certbot', '--version'],
universal_newlines=True, stderr=subprocess.STDOUT,
cwd=workspace, env=environ)
version_str = output.split(' ')[1].strip() # Typical response is: output = 'certbot 0.31.0.dev0'
if LooseVersion(version_str) >= LooseVersion('0.30.0'):
additional_args.append('--no-random-sleep-on-renew')
if force_renew:
additional_args.append('--renew-by-default')
return additional_args
def _prepare_args_env(certbot_args, directory_url, http_01_port, tls_alpn_01_port,
config_dir, workspace, force_renew):
new_environ = _prepare_environ(workspace)
additional_args = _compute_additional_args(workspace, new_environ, force_renew)
command = [
'certbot',
'--server', directory_url,

View File

@@ -209,18 +209,6 @@ shutil.rmtree(well_known)
shutil.rmtree(tempdir)
def get_certbot_version():
"""
Find the version of the certbot available in PATH.
:return str: the certbot version
"""
output = subprocess.check_output(['certbot', '--version'],
universal_newlines=True, stderr=subprocess.STDOUT)
# Typical response is: output = 'certbot 0.31.0.dev0'
version_str = output.split(' ')[1].strip()
return LooseVersion(version_str)
def generate_csr(domains, key_path, csr_path, key_type=RSA_KEY_TYPE):
"""
Generate a private key, and a CSR for the given domains using this key.

View File

@@ -51,6 +51,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
],

View File

@@ -6,7 +6,7 @@ import subprocess
import mock
import zope.interface
from certbot import configuration
from certbot._internal import configuration
from certbot import errors as le_errors
from certbot import util as certbot_util
from certbot_apache import entrypoint
@@ -18,7 +18,6 @@ from certbot_compatibility_test.configurators import common as configurators_com
@zope.interface.implementer(interfaces.IConfiguratorProxy)
class Proxy(configurators_common.Proxy):
# pylint: disable=too-many-instance-attributes
"""A common base for Apache test configurators"""
def __init__(self, args):

View File

@@ -4,7 +4,7 @@ import os
import shutil
import tempfile
from certbot import constants
from certbot._internal import constants
from certbot_compatibility_test import errors
from certbot_compatibility_test import util
@@ -13,7 +13,6 @@ logger = logging.getLogger(__name__)
class Proxy(object):
# pylint: disable=too-many-instance-attributes
"""A common base for compatibility test configurators"""
@classmethod

View File

@@ -7,7 +7,7 @@ import zope.interface
from acme.magic_typing import Set # pylint: disable=unused-import, no-name-in-module
from certbot import configuration
from certbot._internal import configuration
from certbot_nginx import configurator
from certbot_nginx import constants
from certbot_compatibility_test import errors
@@ -18,7 +18,6 @@ from certbot_compatibility_test.configurators import common as configurators_com
@zope.interface.implementer(interfaces.IConfiguratorProxy)
class Proxy(configurators_common.Proxy):
# pylint: disable=too-many-instance-attributes
"""A common base for Nginx test configurators"""
def load_config(self):

View File

@@ -1,15 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCsREbM+UcfsgDy2w56AVGyxsO0HVsbEZHHoEzv7qksIwFgRYMp
rowwIxD450RQQqjvw9IoXlMVmr1t5szn5KXn9JRO9T5KNCCy3VPx75WBcp6kzd9Q
2HS1OEOtpilNnDkZ+TJfdgFWPUBYj2o4Md1hPmcvagiIJY5U6speka2bjwIDAQAB
AoGANCMZ9pF/mDUsmlP4Rq69hkkoFAxKdZ/UqkF256so4mXZ1cRUFTpxzWPfkCWW
hGAYdzCiG3uo08IYkPmojIqkN1dk5Hcq5eQAmshaPkQHQCHjmPjjcNvgjIXQoGUf
TpDU2hbY4UAlJlj4ZLh+jGP5Zq8/WrNi8RsI3v9Nagfp/FECQQDgi2q8p1gX0TNh
d1aEKmSXkR3bxkyFk6oS+pBrAG3+yX27ZayN6Rx6DOs/FcBsOu7fX3PYBziDeEWe
Lkf1P743AkEAxGYT/LY3puglSz4iJZZzWmRCrVOg41yhfQ+F1BRX43/2vtoU5GyM
2lUn1vQ2e/rfmnAvfJxc90GeZCIHB1ihaQJBALH8UMLxMtbOMJgVbDKfF9U8ZhqK
+KT5A1q/2jG2yXmoZU1hroFeQgBMtTvwFfK0VBwjIUQflSBA+Y4EyW0Q9ckCQGvd
jHitM1+N/H2YwHRYbz5j9mLvnVuCEod3MQ9LpQGj1Eb5y6OxIqL/RgQ+2HW7UXem
yc3sqvp5pZ5lOesE+JECQETPI64gqxlTIs3nErNMpMynUuTWpaElOcIJTT6icLzB
Xix67kKXjROO5D58GEYkM0Yi5k7YdUPoQBW7MoIrSIA=
-----END RSA PRIVATE KEY-----

View File

@@ -1,15 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDCzejLjo8wsz0avrylt7HQyF0+vsKritF70EGmc64cV0XfkCTR
o+vMXBXMuUY6Kv3hTXV7klgkNYmL7gXAsFGQ4B9qeMnkYn0GcQdI51u076y/26Fu
37uJg45Q6eApKInJSsyLVMcAT4HUJ6fFnUodFAKR7vTzOQryNW7Et4gA4wIDAQAB
AoGAKiAU40/krwdTg2ETslJS5W8ums7tkeLnAfs69x+02vQUbA/jpmHoL70KCcdW
5GU/mWUCrsIqxUm+gL/sBosaV/TF256qUBt2qQCZTN8MbDaNSYiiMnucOfbWdIqx
Zgls6GUoXQvPic9RUoFSlgfSjo5ezz6el5ihvRMp+wbk24ECQQD3oz4hN029DSZo
Y3+flmBn77gA0BMUvLa6hmt9b3xT5U/ToCLfbmUvpx7zV1g5era2y9qt/o3UtAbW
1zCVETgzAkEAyWHv/+RnSXp8/D4YwTVWyeWi862uNBPkuLGP/0zASdwBfBK3uBls
+VumfSCtp0kt2AXXmScg1fkHdeAVT6AkkQJBAJb2XRnCrRFiwtdAULzo3zx9Vp6o
OfmaUYrEByMgo5pBYLiSFrA+jFDQgH238YCY3mnxPA517+CLHuA5rtQw+yECQCfm
gL/pyFE1tLfhsdPuNpDwL9YqLl7hJis1+zrxQRQhRCYKK16NoxrQ/u7B38ZKaIvp
tGsC5q2elszTJkXNjBECQCVE9QCVx056vHVdPWM8z3GAeV3sJQ01HLLjebTEEz6G
jH54gk+YYPp4kjCvVUykbnB58BY2n88GQt5Jj5eLuMo=
-----END RSA PRIVATE KEY-----

View File

@@ -8,13 +8,13 @@ import tarfile
import josepy as jose
from acme import test_util
from certbot import constants
from certbot.tests import util as test_util
from certbot._internal import constants
from certbot_compatibility_test import errors
_KEY_BASE = "rsa1024_key.pem"
_KEY_BASE = "rsa2048_key.pem"
KEY_PATH = test_util.vector_path(_KEY_BASE)
KEY = test_util.load_pyopenssl_private_key(_KEY_BASE)
JWK = jose.JWKRSA(key=test_util.load_rsa_private_key(_KEY_BASE))

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
install_requires = [
'certbot',
@@ -47,6 +47,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
],

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0

View File

@@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'cloudflare>=1.5.1',
'mock',
'setuptools',
@@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0

View File

@@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',
@@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0

View File

@@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'mock',
'python-digitalocean>=1.11',
'setuptools',
@@ -44,6 +44,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0

View File

@@ -3,13 +3,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'mock',
'setuptools',
'zope.interface',
@@ -55,6 +55,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0

View File

@@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',
@@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0

View File

@@ -2,12 +2,12 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'dns-lexicon>=2.1.22',
'mock',
'setuptools',
@@ -41,6 +41,8 @@ setup(
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0

View File

@@ -2,18 +2,16 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.34.0',
# 1.5 is the first version that supports oauth2client>=2.0
'google-api-python-client>=1.5',
'certbot>=0.39.0',
'google-api-python-client>=1.5.5',
'mock',
# for oauth2client.service_account.ServiceAccountCredentials
'oauth2client>=2.0',
'oauth2client>=4.0',
'setuptools',
'zope.interface',
# already a dependency of google-api-python-client, but added for consistency
@@ -48,6 +46,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,4 +1,4 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0
dns-lexicon==2.2.3

View File

@@ -1,12 +1,12 @@
from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'dns-lexicon>=2.2.3',
'mock',
'setuptools',
@@ -41,6 +41,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0

View File

@@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',
@@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0

View File

@@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',
@@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,4 +1,4 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0
dns-lexicon==2.7.14

View File

@@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'dns-lexicon>=2.7.14', # Correct proxy use on OVH provider
'mock',
'setuptools',
@@ -42,6 +42,8 @@ setup(
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -206,7 +206,11 @@ class _RFC2136Client(object):
request.flags ^= dns.flags.RD
try:
response = dns.query.udp(request, self.server, port=self.port)
try:
response = dns.query.tcp(request, self.server, port=self.port)
except OSError as e:
logger.debug('TCP query failed, fallback to UDP: %s', e)
response = dns.query.udp(request, self.server, port=self.port)
rcode = response.rcode()
# Authoritative Answer bit should be set

View File

@@ -162,7 +162,7 @@ class RFC2136ClientTest(unittest.TestCase):
self.rfc2136_client._find_domain,
'foo.bar.'+DOMAIN)
@mock.patch("dns.query.udp")
@mock.patch("dns.query.tcp")
def test_query_soa_found(self, query_mock):
query_mock.return_value = mock.MagicMock(answer=[mock.MagicMock()], flags=dns.flags.AA)
query_mock.return_value.rcode.return_value = dns.rcode.NOERROR
@@ -173,7 +173,7 @@ class RFC2136ClientTest(unittest.TestCase):
query_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
self.assertTrue(result)
@mock.patch("dns.query.udp")
@mock.patch("dns.query.tcp")
def test_query_soa_not_found(self, query_mock):
query_mock.return_value.rcode.return_value = dns.rcode.NXDOMAIN
@@ -183,7 +183,7 @@ class RFC2136ClientTest(unittest.TestCase):
query_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
self.assertFalse(result)
@mock.patch("dns.query.udp")
@mock.patch("dns.query.tcp")
def test_query_soa_wraps_errors(self, query_mock):
query_mock.side_effect = Exception
@@ -193,6 +193,20 @@ class RFC2136ClientTest(unittest.TestCase):
self.rfc2136_client._query_soa,
DOMAIN)
@mock.patch("dns.query.udp")
@mock.patch("dns.query.tcp")
def test_query_soa_fallback_to_udp(self, tcp_mock, udp_mock):
tcp_mock.side_effect = OSError
udp_mock.return_value = mock.MagicMock(answer=[mock.MagicMock()], flags=dns.flags.AA)
udp_mock.return_value.rcode.return_value = dns.rcode.NOERROR
# _query_soa | pylint: disable=protected-access
result = self.rfc2136_client._query_soa(DOMAIN)
tcp_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
udp_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
self.assertTrue(result)
if __name__ == "__main__":
unittest.main() # pragma: no cover

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0

View File

@@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'dnspython',
'mock',
'setuptools',
@@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0

View File

@@ -1,13 +1,13 @@
from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'boto3',
'mock',
'setuptools',
@@ -37,6 +37,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
certbot[dev]==0.39.0

View File

@@ -2,12 +2,12 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '1.0.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0',
'dns-lexicon>=2.1.23',
'mock',
'setuptools',
@@ -41,6 +41,8 @@ setup(
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -1,5 +1,4 @@
include LICENSE.txt
include README.rst
recursive-include docs *
recursive-include certbot_nginx/tests/testdata *
recursive-include certbot_nginx/tls_configs *.conf

View File

@@ -1,4 +1,6 @@
"""Nginx Configuration"""
# https://github.com/PyCQA/pylint/issues/73
from distutils.version import LooseVersion # pylint: disable=no-name-in-module,import-error
import logging
import re
import socket
@@ -15,7 +17,6 @@ from acme import challenges
from acme import crypto_util as acme_crypto_util
from acme.magic_typing import List, Dict, Set # pylint: disable=unused-import, no-name-in-module
from certbot import constants as core_constants
from certbot import crypto_util
from certbot import errors
from certbot import interfaces
@@ -43,7 +44,6 @@ logger = logging.getLogger(__name__)
@zope.interface.implementer(interfaces.IAuthenticator, interfaces.IInstaller)
@zope.interface.provider(interfaces.IPluginFactory)
class NginxConfigurator(common.Installer):
# pylint: disable=too-many-instance-attributes,too-many-public-methods
"""Nginx configurator.
.. todo:: Add proper support for comments in the config. Currently,
@@ -91,13 +91,14 @@ class NginxConfigurator(common.Installer):
:param tup version: version of Nginx as a tuple (1, 4, 7)
(used mostly for unittesting)
:param tup openssl_version: version of OpenSSL linked to Nginx as a tuple (1, 4, 7)
(used mostly for unittesting)
"""
version = kwargs.pop("version", None)
openssl_version = kwargs.pop("openssl_version", None)
super(NginxConfigurator, self).__init__(*args, **kwargs)
# Verify that all directories and files exist with proper permissions
self._verify_setup()
# Files to save
self.save_notes = ""
@@ -115,6 +116,7 @@ class NginxConfigurator(common.Installer):
# These will be set in the prepare function
self.parser = None
self.version = version
self.openssl_version = openssl_version
self._enhance_func = {"redirect": self._enable_redirect,
"ensure-http-header": self._set_http_header,
"staple-ocsp": self._enable_ocsp_stapling}
@@ -124,11 +126,33 @@ class NginxConfigurator(common.Installer):
@property
def mod_ssl_conf_src(self):
"""Full absolute path to SSL configuration file source."""
config_filename = "options-ssl-nginx.conf"
if self.version < (1, 5, 9):
config_filename = "options-ssl-nginx-old.conf"
elif self.version < (1, 13, 0):
config_filename = "options-ssl-nginx-tls12-only.conf"
# Why all this complexity? Well, we want to support Mozilla's intermediate
# recommendations. But TLS1.3 is only supported by newer versions of Nginx.
# And as for session tickets, our ideal is to turn them off across the board.
# But! Turning them off at all is only supported with new enough versions of
# Nginx. And older versions of OpenSSL have a bug that leads to browser errors
# given certain configurations. While we'd prefer to have forward secrecy, we'd
# rather fail open than error out. Unfortunately, Nginx can be compiled against
# many versions of OpenSSL. So we have to check both for the two different features,
# leading to four different combinations of options.
# For a complete history, check out https://github.com/certbot/certbot/issues/7322
use_tls13 = self.version >= (1, 13, 0)
session_tix_off = self.version >= (1, 5, 9) and self.openssl_version and\
LooseVersion(self.openssl_version) >= LooseVersion('1.0.2l')
if use_tls13:
if session_tix_off:
config_filename = "options-ssl-nginx.conf"
else:
config_filename = "options-ssl-nginx-tls13-session-tix-on.conf"
else:
if session_tix_off:
config_filename = "options-ssl-nginx-tls12-only.conf"
else:
config_filename = "options-ssl-nginx-old.conf"
return pkg_resources.resource_filename(
"certbot_nginx", os.path.join("tls_configs", config_filename))
@@ -169,6 +193,9 @@ class NginxConfigurator(common.Installer):
if self.version is None:
self.version = self.get_version()
if self.openssl_version is None:
self.openssl_version = self._get_openssl_version()
self.install_ssl_options_conf(self.mod_ssl_conf, self.updated_mod_ssl_conf_digest)
self.install_ssl_dhparams()
@@ -676,9 +703,9 @@ class NginxConfigurator(common.Installer):
:param str domain: domain to enhance
:param str enhancement: enhancement type defined in
:const:`~certbot.constants.ENHANCEMENTS`
:const:`~certbot.plugins.enhancements.ENHANCEMENTS`
:param options: options for the enhancement
See :const:`~certbot.constants.ENHANCEMENTS`
See :const:`~certbot.plugins.enhancements.ENHANCEMENTS`
documentation for appropriate parameter.
"""
@@ -897,17 +924,27 @@ class NginxConfigurator(common.Installer):
except errors.SubprocessError as err:
raise errors.MisconfigurationError(str(err))
def _verify_setup(self):
"""Verify the setup to ensure safe operating environment.
def _nginx_version(self):
"""Return results of nginx -V
Make sure that files/directories are setup with appropriate permissions
Aim for defensive coding... make sure all input files
have permissions of root.
:returns: version text
:rtype: str
:raises .PluginError:
Unable to run Nginx version command
"""
util.make_or_verify_dir(self.config.work_dir, core_constants.CONFIG_DIRS_MODE)
util.make_or_verify_dir(self.config.backup_dir, core_constants.CONFIG_DIRS_MODE)
util.make_or_verify_dir(self.config.config_dir, core_constants.CONFIG_DIRS_MODE)
try:
proc = subprocess.Popen(
[self.conf('ctl'), "-c", self.nginx_conf, "-V"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
text = proc.communicate()[1] # nginx prints output to stderr
except (OSError, ValueError) as error:
logger.debug(str(error), exc_info=True)
raise errors.PluginError(
"Unable to run %s -V" % self.conf('ctl'))
return text
def get_version(self):
"""Return version of Nginx Server.
@@ -921,17 +958,7 @@ class NginxConfigurator(common.Installer):
Unable to find Nginx version or version is unsupported
"""
try:
proc = subprocess.Popen(
[self.conf('ctl'), "-c", self.nginx_conf, "-V"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
text = proc.communicate()[1] # nginx prints output to stderr
except (OSError, ValueError) as error:
logger.debug(str(error), exc_info=True)
raise errors.PluginError(
"Unable to run %s -V" % self.conf('ctl'))
text = self._nginx_version()
version_regex = re.compile(r"nginx version: ([^/]+)/([0-9\.]*)", re.IGNORECASE)
version_matches = version_regex.findall(text)
@@ -964,6 +991,28 @@ class NginxConfigurator(common.Installer):
return nginx_version
def _get_openssl_version(self):
"""Return version of OpenSSL linked to Nginx.
Version is returned as string. If no version can be found, empty string is returned.
:returns: openssl_version
:rtype: str
:raises .PluginError:
Unable to run Nginx version command
"""
text = self._nginx_version()
matches = re.findall(r"running with OpenSSL ([^ ]+) ", text)
if not matches:
matches = re.findall(r"built with OpenSSL ([^ ]+) ", text)
if not matches:
logger.warning("NGINX configured with OpenSSL alternatives is not officially"
"supported by Certbot.")
return ""
return matches[0]
def more_info(self):
"""Human-readable string to help understand the module"""
return (
@@ -1041,7 +1090,7 @@ class NginxConfigurator(common.Installer):
###########################################################################
def get_chall_pref(self, unused_domain): # pylint: disable=no-self-use
"""Return list of challenge preferences."""
return [challenges.HTTP01, challenges.TLSSNI01]
return [challenges.HTTP01]
# Entry point in main.py for performing challenges
def perform(self, achalls):

View File

@@ -22,19 +22,6 @@ MOD_SSL_CONF_DEST = "options-ssl-nginx.conf"
UPDATED_MOD_SSL_CONF_DIGEST = ".updated-options-ssl-nginx-conf-digest.txt"
"""Name of the hash of the updated or informed mod_ssl_conf as saved in `IConfig.config_dir`."""
SSL_OPTIONS_HASHES_NEW = [
'108c4555058a087496a3893aea5d9e1cee0f20a3085d44a52dc1a66522299ac3',
]
"""SHA256 hashes of the contents of versions of MOD_SSL_CONF_SRC for nginx >= 1.13.0"""
SSL_OPTIONS_HASHES_MEDIUM = [
'63e2bddebb174a05c9d8a7cf2adf72f7af04349ba59a1a925fe447f73b2f1abf',
'2901debc7ecbc10917edd9084c05464c9c5930b463677571eaf8c94bffd11ae2',
'30baca73ed9a5b0e9a69ea40e30482241d8b1a7343aa79b49dc5d7db0bf53b6c',
]
"""SHA256 hashes of the contents of versions of MOD_SSL_CONF_SRC for nginx >= 1.5.9
and nginx < 1.13.0"""
ALL_SSL_OPTIONS_HASHES = [
'0f81093a1465e3d4eaa8b0c14e77b2a2e93568b0fc1351c2b87893a95f0de87c',
'9a7b32c49001fed4cff8ad24353329472a50e86ade1ef9b2b9e43566a619612e',
@@ -44,7 +31,17 @@ ALL_SSL_OPTIONS_HASHES = [
'4b16fec2bcbcd8a2f3296d886f17f9953ffdcc0af54582452ca1e52f5f776f16',
'c052ffff0ad683f43bffe105f7c606b339536163490930e2632a335c8d191cc4',
'02329eb19930af73c54b3632b3165d84571383b8c8c73361df940cb3894dd426',
] + SSL_OPTIONS_HASHES_MEDIUM + SSL_OPTIONS_HASHES_NEW
'63e2bddebb174a05c9d8a7cf2adf72f7af04349ba59a1a925fe447f73b2f1abf',
'2901debc7ecbc10917edd9084c05464c9c5930b463677571eaf8c94bffd11ae2',
'30baca73ed9a5b0e9a69ea40e30482241d8b1a7343aa79b49dc5d7db0bf53b6c',
'02329eb19930af73c54b3632b3165d84571383b8c8c73361df940cb3894dd426',
'108c4555058a087496a3893aea5d9e1cee0f20a3085d44a52dc1a66522299ac3',
'd5e021706ecdccc7090111b0ae9a29ef61523e927f020e410caf0a1fd7063981',
'ef11e3fb17213e74d3e1816cde0ec37b8b95b4167cf21e7b8ff1eaa9c6f918ee',
'af85f6193808a44789a1d293e6cffa249cad9a21135940800958b8e3c72dbc69',
'a2a612fd21b02abaa32d9d11ac63d987d6e3054dbfa356de5800eea0d7ce17f3',
'2d9648302e3588a172c318e46bff88ade46fc7a16d6afc85322776a04800d473',
]
"""SHA256 hashes of the contents of all versions of MOD_SSL_CONF_SRC"""
def os_constant(key):

View File

@@ -29,10 +29,10 @@ class NginxHttp01(common.ChallengePerformer):
:param list indices: Meant to hold indices of challenges in a
larger array. NginxHttp01 is capable of solving many challenges
at once which causes an indexing issue within NginxConfigurator
who must return all responses in order. Imagine NginxConfigurator
maintaining state about where all of the http-01 Challenges,
TLS-SNI-01 Challenges belong in the response array. This is an
optional utility.
who must return all responses in order. Imagine
NginxConfigurator maintaining state about where all of the
challenges, possibly of different types, belong in the response
array. This is an optional utility.
"""

View File

@@ -63,7 +63,6 @@ class RawNginxParser(object):
return self.parse().asList()
class RawNginxDumper(object):
# pylint: disable=too-few-public-methods
"""A class that dumps nginx configuration from the provided tree."""
def __init__(self, blocks):
self.blocks = blocks

View File

@@ -37,7 +37,6 @@ class Addr(common.Addr):
CANONICAL_UNSPECIFIED_ADDRESS = UNSPECIFIED_IPV4_ADDRESSES[0]
def __init__(self, host, port, ssl, default, ipv6, ipv6only):
# pylint: disable=too-many-arguments
super(Addr, self).__init__((host, port))
self.ssl = ssl
self.default = default
@@ -145,7 +144,7 @@ class Addr(common.Addr):
return False
class VirtualHost(object): # pylint: disable=too-few-public-methods
class VirtualHost(object):
"""Represents an Nginx Virtualhost.
:ivar str filep: file path of VH
@@ -162,7 +161,6 @@ class VirtualHost(object): # pylint: disable=too-few-public-methods
"""
def __init__(self, filep, addrs, ssl, enabled, names, raw, path):
# pylint: disable=too-many-arguments
"""Initialize a VH."""
self.filep = filep
self.addrs = addrs

View File

@@ -1,4 +1,3 @@
# pylint: disable=too-many-public-methods
"""Test for certbot_nginx.configurator."""
import unittest
@@ -27,7 +26,7 @@ class NginxConfiguratorTest(util.NginxTest):
def setUp(self):
super(NginxConfiguratorTest, self).setUp()
self.config = util.get_nginx_configurator(
self.config = self.get_nginx_configurator(
self.config_path, self.config_dir, self.work_dir, self.logs_dir)
@mock.patch("certbot_nginx.configurator.util.exe_exists")
@@ -97,7 +96,7 @@ class NginxConfiguratorTest(util.NginxTest):
errors.PluginError, self.config.enhance, 'myhost', 'unknown_enhancement')
def test_get_chall_pref(self):
self.assertEqual([challenges.HTTP01, challenges.TLSSNI01],
self.assertEqual([challenges.HTTP01],
self.config.get_chall_pref('myhost'))
def test_save(self):
@@ -394,6 +393,68 @@ class NginxConfiguratorTest(util.NginxTest):
mock_popen.side_effect = OSError("Can't find program")
self.assertRaises(errors.PluginError, self.config.get_version)
@mock.patch("certbot_nginx.configurator.subprocess.Popen")
def test_get_openssl_version(self, mock_popen):
# pylint: disable=protected-access
mock_popen().communicate.return_value = (
"", """
nginx version: nginx/1.15.5
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
built with OpenSSL 1.0.2g 1 Mar 2016
TLS SNI support enabled
configure arguments:
""")
self.assertEqual(self.config._get_openssl_version(), "1.0.2g")
mock_popen().communicate.return_value = (
"", """
nginx version: nginx/1.15.5
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
built with OpenSSL 1.0.2-beta1 1 Mar 2016
TLS SNI support enabled
configure arguments:
""")
self.assertEqual(self.config._get_openssl_version(), "1.0.2-beta1")
mock_popen().communicate.return_value = (
"", """
nginx version: nginx/1.15.5
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
built with OpenSSL 1.0.2 1 Mar 2016
TLS SNI support enabled
configure arguments:
""")
self.assertEqual(self.config._get_openssl_version(), "1.0.2")
mock_popen().communicate.return_value = (
"", """
nginx version: nginx/1.15.5
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
built with OpenSSL 1.0.2g 1 Mar 2016 (running with OpenSSL 1.0.2a 1 Mar 2016)
TLS SNI support enabled
configure arguments:
""")
self.assertEqual(self.config._get_openssl_version(), "1.0.2a")
mock_popen().communicate.return_value = (
"", """
nginx version: nginx/1.15.5
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
built with LibreSSL 2.2.2
TLS SNI support enabled
configure arguments:
""")
self.assertEqual(self.config._get_openssl_version(), "")
mock_popen().communicate.return_value = (
"", """
nginx version: nginx/1.15.5
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
TLS SNI support enabled
configure arguments:
""")
self.assertEqual(self.config._get_openssl_version(), "")
@mock.patch("certbot_nginx.configurator.subprocess.Popen")
def test_nginx_restart(self, mock_popen):
mocked = mock_popen()
@@ -873,7 +934,7 @@ class InstallSslOptionsConfTest(util.NginxTest):
def setUp(self):
super(InstallSslOptionsConfTest, self).setUp()
self.config = util.get_nginx_configurator(
self.config = self.get_nginx_configurator(
self.config_path, self.config_dir, self.work_dir, self.logs_dir)
def _call(self):
@@ -920,13 +981,12 @@ class InstallSslOptionsConfTest(util.NginxTest):
self._assert_current_file()
def test_prev_file_updates_to_current_old_nginx(self):
from certbot_nginx.constants import ALL_SSL_OPTIONS_HASHES, SSL_OPTIONS_HASHES_NEW
from certbot_nginx.constants import ALL_SSL_OPTIONS_HASHES
self.config.version = (1, 5, 8)
with mock.patch('certbot.crypto_util.sha256sum',
new=self._mock_hash_except_ssl_conf_src(ALL_SSL_OPTIONS_HASHES[0])):
self._call()
self._assert_current_file()
self.assertTrue(self._current_ssl_options_hash() not in SSL_OPTIONS_HASHES_NEW)
def test_manually_modified_current_file_does_not_update(self):
with open(self.config.mod_ssl_conf, "a") as mod_ssl_conf:
@@ -987,11 +1047,13 @@ class InstallSslOptionsConfTest(util.NginxTest):
def test_nginx_version_uses_correct_config(self):
self.config.version = (1, 5, 8)
self.config.openssl_version = "1.0.2g" # shouldn't matter
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
"options-ssl-nginx-old.conf")
self._call()
self._assert_current_file()
self.config.version = (1, 5, 9)
self.config.openssl_version = "1.0.2l"
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
"options-ssl-nginx-tls12-only.conf")
self._call()
@@ -999,6 +1061,12 @@ class InstallSslOptionsConfTest(util.NginxTest):
self.config.version = (1, 13, 0)
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
"options-ssl-nginx.conf")
self._call()
self._assert_current_file()
self.config.version = (1, 13, 0)
self.config.openssl_version = "1.0.2k"
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
"options-ssl-nginx-tls13-session-tix-on.conf")
class DetermineDefaultServerRootTest(certbot_test_util.ConfigTestCase):

View File

@@ -47,7 +47,7 @@ class HttpPerformTest(util.NginxTest):
def setUp(self):
super(HttpPerformTest, self).setUp()
config = util.get_nginx_configurator(
config = self.get_nginx_configurator(
self.config_path, self.config_dir, self.work_dir, self.logs_dir)
from certbot_nginx import http_01
@@ -73,11 +73,11 @@ class HttpPerformTest(util.NginxTest):
self.http01.add_chall(achall)
acme_responses.append(achall.response(self.account_key))
sni_responses = self.http01.perform()
http_responses = self.http01.perform()
self.assertEqual(len(sni_responses), 4)
self.assertEqual(len(http_responses), 4)
for i in six.moves.range(4):
self.assertEqual(sni_responses[i], acme_responses[i])
self.assertEqual(http_responses[i], acme_responses[i])
def test_mod_config(self):
self.http01.add_chall(self.achalls[0])

View File

@@ -15,7 +15,7 @@ from certbot_nginx import parser
from certbot_nginx.tests import util
class NginxParserTest(util.NginxTest): #pylint: disable=too-many-public-methods
class NginxParserTest(util.NginxTest):
"""Nginx Parser Test."""
def tearDown(self):
@@ -30,8 +30,16 @@ class NginxParserTest(util.NginxTest): #pylint: disable=too-many-public-methods
self.assertEqual(nparser.root, self.config_path)
def test_root_absolute(self):
nparser = parser.NginxParser(os.path.relpath(self.config_path))
self.assertEqual(nparser.root, self.config_path)
curr_dir = os.getcwd()
try:
# On Windows current directory may be on a different drive than self.tempdir.
# However a relative path between two different drives is invalid. So we move to
# self.tempdir to ensure that we stay on the same drive.
os.chdir(self.temp_dir)
nparser = parser.NginxParser(os.path.relpath(self.config_path))
self.assertEqual(nparser.root, self.config_path)
finally:
os.chdir(curr_dir)
def test_root_no_trailing_slash(self):
nparser = parser.NginxParser(self.config_path + os.path.sep)

View File

@@ -2,15 +2,13 @@
import copy
import shutil
import tempfile
import unittest
import warnings
import josepy as jose
import mock
import pkg_resources
import zope.component
from certbot import configuration
from certbot import util
from certbot.compat import os
from certbot.plugins import common
from certbot.tests import util as test_util
@@ -19,11 +17,14 @@ from certbot_nginx import configurator
from certbot_nginx import nginxparser
class NginxTest(unittest.TestCase): # pylint: disable=too-few-public-methods
class NginxTest(test_util.ConfigTestCase):
def setUp(self):
super(NginxTest, self).setUp()
self.configuration = self.config
self.config = None
self.temp_dir, self.config_dir, self.work_dir = common.dir_setup(
"etc_nginx", "certbot_nginx.tests")
self.logs_dir = tempfile.mkdtemp('logs')
@@ -34,20 +35,51 @@ class NginxTest(unittest.TestCase): # pylint: disable=too-few-public-methods
"rsa512_key.pem"))
def tearDown(self):
# On Windows we have various files which are not correctly closed at the time of tearDown.
# For know, we log them until a proper file close handling is written.
# Useful for development only, so no warning when we are on a CI process.
def onerror_handler(_, path, excinfo):
"""On error handler"""
if not os.environ.get('APPVEYOR'): # pragma: no cover
message = ('Following error occurred when deleting path {0}'
'during tearDown process: {1}'.format(path, str(excinfo)))
warnings.warn(message)
# Cleanup opened resources after a test. This is usually done through atexit handlers in
# Certbot, but during tests, atexit will not run registered functions before tearDown is
# called and instead will run them right before the entire test process exits.
# It is a problem on Windows, that does not accept to clean resources before closing them.
util._release_locks() # pylint: disable=protected-access
shutil.rmtree(self.temp_dir, onerror=onerror_handler)
shutil.rmtree(self.config_dir, onerror=onerror_handler)
shutil.rmtree(self.work_dir, onerror=onerror_handler)
shutil.rmtree(self.logs_dir, onerror=onerror_handler)
shutil.rmtree(self.temp_dir)
shutil.rmtree(self.config_dir)
shutil.rmtree(self.work_dir)
shutil.rmtree(self.logs_dir)
def get_nginx_configurator(self, config_path, config_dir, work_dir, logs_dir,
version=(1, 6, 2), openssl_version="1.0.2g"):
"""Create an Nginx Configurator with the specified options."""
backups = os.path.join(work_dir, "backups")
self.configuration.nginx_server_root = config_path
self.configuration.le_vhost_ext = "-le-ssl.conf"
self.configuration.config_dir = config_dir
self.configuration.work_dir = work_dir
self.configuration.logs_dir = logs_dir
self.configuration.backup_dir = backups
self.configuration.temp_checkpoint_dir = os.path.join(work_dir, "temp_checkpoints")
self.configuration.in_progress_dir = os.path.join(backups, "IN_PROGRESS")
self.configuration.server = "https://acme-server.org:443/new"
self.configuration.http01_port = 80
self.configuration.https_port = 5001
with mock.patch("certbot_nginx.configurator.NginxConfigurator."
"config_test"):
with mock.patch("certbot_nginx.configurator.util."
"exe_exists") as mock_exe_exists:
mock_exe_exists.return_value = True
config = configurator.NginxConfigurator(
self.configuration,
name="nginx",
version=version,
openssl_version=openssl_version)
config.prepare()
# Provide general config utility.
zope.component.provideUtility(self.configuration)
return config
def get_data_filename(filename):
@@ -57,42 +89,6 @@ def get_data_filename(filename):
"testdata", "etc_nginx", filename))
def get_nginx_configurator(
config_path, config_dir, work_dir, logs_dir, version=(1, 6, 2)):
"""Create an Nginx Configurator with the specified options."""
backups = os.path.join(work_dir, "backups")
with mock.patch("certbot_nginx.configurator.NginxConfigurator."
"config_test"):
with mock.patch("certbot_nginx.configurator.util."
"exe_exists") as mock_exe_exists:
mock_exe_exists.return_value = True
config = configurator.NginxConfigurator(
config=mock.MagicMock(
nginx_server_root=config_path,
le_vhost_ext="-le-ssl.conf",
config_dir=config_dir,
work_dir=work_dir,
logs_dir=logs_dir,
backup_dir=backups,
temp_checkpoint_dir=os.path.join(work_dir, "temp_checkpoints"),
in_progress_dir=os.path.join(backups, "IN_PROGRESS"),
server="https://acme-server.org:443/new",
http01_port=80,
https_port=5001,
),
name="nginx",
version=version)
config.prepare()
# Provide general config utility.
nsconfig = configuration.NamespaceConfig(config.config)
zope.component.provideUtility(nsconfig)
return config
def filter_comments(tree):
"""Filter comment nodes from parsed configurations."""

View File

@@ -10,4 +10,4 @@ ssl_session_timeout 1440m;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA";

View File

@@ -11,4 +11,4 @@ ssl_session_tickets off;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA";

View File

@@ -0,0 +1,13 @@
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA";

View File

@@ -11,4 +11,4 @@ ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA";

Some files were not shown because too many files have changed in this diff Show More