Full Code of norbusan/certbot-debian for AI

master 43897c1541d9 cached
243 files
1.5 MB
368.7k tokens
2271 symbols
1 requests
Download .txt
Showing preview only (1,591K chars total). Download the full file or copy to clipboard to get everything.
Repository: norbusan/certbot-debian
Branch: master
Commit: 43897c1541d9
Files: 243
Total size: 1.5 MB

Directory structure:
gitextract_z7q7eth2/

├── .gitignore
├── CHANGELOG.md
├── LICENSE.txt
├── MANIFEST.in
├── PKG-INFO
├── README.rst
├── certbot/
│   ├── __init__.py
│   ├── _internal/
│   │   ├── __init__.py
│   │   ├── account.py
│   │   ├── auth_handler.py
│   │   ├── cert_manager.py
│   │   ├── cli/
│   │   │   ├── __init__.py
│   │   │   ├── cli_constants.py
│   │   │   ├── cli_utils.py
│   │   │   ├── group_adder.py
│   │   │   ├── helpful.py
│   │   │   ├── paths_parser.py
│   │   │   ├── plugins_parsing.py
│   │   │   ├── report_config_interaction.py
│   │   │   ├── subparsers.py
│   │   │   └── verb_help.py
│   │   ├── client.py
│   │   ├── configuration.py
│   │   ├── constants.py
│   │   ├── display/
│   │   │   ├── __init__.py
│   │   │   ├── completer.py
│   │   │   ├── dummy_readline.py
│   │   │   └── enhancements.py
│   │   ├── eff.py
│   │   ├── error_handler.py
│   │   ├── hooks.py
│   │   ├── lock.py
│   │   ├── log.py
│   │   ├── main.py
│   │   ├── plugins/
│   │   │   ├── __init__.py
│   │   │   ├── disco.py
│   │   │   ├── manual.py
│   │   │   ├── null.py
│   │   │   ├── selection.py
│   │   │   ├── standalone.py
│   │   │   └── webroot.py
│   │   ├── renewal.py
│   │   ├── reporter.py
│   │   ├── storage.py
│   │   └── updater.py
│   ├── achallenges.py
│   ├── compat/
│   │   ├── __init__.py
│   │   ├── _path.py
│   │   ├── filesystem.py
│   │   ├── misc.py
│   │   └── os.py
│   ├── crypto_util.py
│   ├── display/
│   │   ├── __init__.py
│   │   ├── ops.py
│   │   └── util.py
│   ├── errors.py
│   ├── interfaces.py
│   ├── main.py
│   ├── ocsp.py
│   ├── plugins/
│   │   ├── __init__.py
│   │   ├── common.py
│   │   ├── dns_common.py
│   │   ├── dns_common_lexicon.py
│   │   ├── dns_test_common.py
│   │   ├── dns_test_common_lexicon.py
│   │   ├── enhancements.py
│   │   ├── storage.py
│   │   └── util.py
│   ├── reverter.py
│   ├── ssl-dhparams.pem
│   ├── tests/
│   │   ├── __init__.py
│   │   ├── acme_util.py
│   │   ├── testdata/
│   │   │   ├── README
│   │   │   ├── cert-5sans_512.pem
│   │   │   ├── cert-nosans_nistp256.pem
│   │   │   ├── cert-san_512.pem
│   │   │   ├── cert_2048.pem
│   │   │   ├── cert_512.pem
│   │   │   ├── cert_512_bad.pem
│   │   │   ├── cert_fullchain_2048.pem
│   │   │   ├── cli.ini
│   │   │   ├── csr-6sans_512.conf
│   │   │   ├── csr-6sans_512.pem
│   │   │   ├── csr-nonames_512.pem
│   │   │   ├── csr-nosans_512.conf
│   │   │   ├── csr-nosans_512.pem
│   │   │   ├── csr-nosans_nistp256.pem
│   │   │   ├── csr-san_512.pem
│   │   │   ├── csr_512.der
│   │   │   ├── csr_512.pem
│   │   │   ├── nistp256_key.pem
│   │   │   ├── ocsp_certificate.pem
│   │   │   ├── ocsp_issuer_certificate.pem
│   │   │   ├── ocsp_responder_certificate.pem
│   │   │   ├── os-release
│   │   │   ├── rsa2048_key.pem
│   │   │   ├── rsa256_key.pem
│   │   │   ├── rsa512_key.pem
│   │   │   ├── sample-archive/
│   │   │   │   ├── cert1.pem
│   │   │   │   ├── chain1.pem
│   │   │   │   ├── fullchain1.pem
│   │   │   │   └── privkey1.pem
│   │   │   ├── sample-renewal-ancient.conf
│   │   │   ├── sample-renewal.conf
│   │   │   └── webrootconftest.ini
│   │   └── util.py
│   └── util.py
├── certbot.egg-info/
│   ├── PKG-INFO
│   ├── SOURCES.txt
│   ├── dependency_links.txt
│   ├── entry_points.txt
│   ├── requires.txt
│   └── top_level.txt
├── debian/
│   ├── README.source
│   ├── certbot.cron.d
│   ├── certbot.docs
│   ├── certbot.links
│   ├── certbot.logrotate
│   ├── certbot.manpages
│   ├── certbot.postrm
│   ├── certbot.service
│   ├── certbot.timer
│   ├── changelog
│   ├── cli.ini
│   ├── control
│   ├── copyright
│   ├── patches/
│   │   ├── 0001-remove-external-images.patch
│   │   └── series
│   ├── pydist-overrides
│   ├── python-certbot-doc.doc-base
│   ├── python-certbot-doc.docs
│   ├── python-certbot-doc.examples
│   ├── python3-certbot.lintian-overrides
│   ├── rules
│   ├── source/
│   │   └── format
│   ├── tests/
│   │   ├── certs/
│   │   │   ├── README.md
│   │   │   ├── cert.pem
│   │   │   └── key.pem
│   │   ├── control
│   │   ├── http-01
│   │   └── pebble-config.json
│   ├── upstream/
│   │   └── signing-key.asc
│   └── watch
├── docs/
│   ├── .gitignore
│   ├── Makefile
│   ├── _static/
│   │   └── .gitignore
│   ├── _templates/
│   │   └── footer.html
│   ├── api/
│   │   ├── certbot.achallenges.rst
│   │   ├── certbot.compat.filesystem.rst
│   │   ├── certbot.compat.misc.rst
│   │   ├── certbot.compat.os.rst
│   │   ├── certbot.compat.rst
│   │   ├── certbot.crypto_util.rst
│   │   ├── certbot.display.ops.rst
│   │   ├── certbot.display.rst
│   │   ├── certbot.display.util.rst
│   │   ├── certbot.errors.rst
│   │   ├── certbot.interfaces.rst
│   │   ├── certbot.main.rst
│   │   ├── certbot.ocsp.rst
│   │   ├── certbot.plugins.common.rst
│   │   ├── certbot.plugins.dns_common.rst
│   │   ├── certbot.plugins.dns_common_lexicon.rst
│   │   ├── certbot.plugins.dns_test_common.rst
│   │   ├── certbot.plugins.dns_test_common_lexicon.rst
│   │   ├── certbot.plugins.enhancements.rst
│   │   ├── certbot.plugins.rst
│   │   ├── certbot.plugins.storage.rst
│   │   ├── certbot.plugins.util.rst
│   │   ├── certbot.reverter.rst
│   │   ├── certbot.rst
│   │   ├── certbot.tests.acme_util.rst
│   │   ├── certbot.tests.rst
│   │   ├── certbot.tests.util.rst
│   │   └── certbot.util.rst
│   ├── api.rst
│   ├── challenges.rst
│   ├── ciphers.rst
│   ├── cli-help.txt
│   ├── compatibility.rst
│   ├── conf.py
│   ├── contributing.rst
│   ├── index.rst
│   ├── install.rst
│   ├── intro.rst
│   ├── make.bat
│   ├── man/
│   │   └── certbot.rst
│   ├── packaging.rst
│   ├── resources.rst
│   ├── using.rst
│   └── what.rst
├── examples/
│   ├── .gitignore
│   ├── cli.ini
│   ├── dev-cli.ini
│   ├── generate-csr.sh
│   ├── openssl.cnf
│   └── plugins/
│       ├── certbot_example_plugins.py
│       └── setup.py
├── setup.cfg
├── setup.py
└── tests/
    ├── account_test.py
    ├── auth_handler_test.py
    ├── cert_manager_test.py
    ├── cli_test.py
    ├── client_test.py
    ├── compat/
    │   ├── __init__.py
    │   ├── filesystem_test.py
    │   └── os_test.py
    ├── configuration_test.py
    ├── crypto_util_test.py
    ├── display/
    │   ├── __init__.py
    │   ├── completer_test.py
    │   ├── enhancements_test.py
    │   ├── ops_test.py
    │   └── util_test.py
    ├── eff_test.py
    ├── error_handler_test.py
    ├── errors_test.py
    ├── helpful_test.py
    ├── hook_test.py
    ├── lock_test.py
    ├── log_test.py
    ├── main_test.py
    ├── ocsp_test.py
    ├── plugins/
    │   ├── __init__.py
    │   ├── common_test.py
    │   ├── disco_test.py
    │   ├── dns_common_lexicon_test.py
    │   ├── dns_common_test.py
    │   ├── enhancements_test.py
    │   ├── manual_test.py
    │   ├── null_test.py
    │   ├── selection_test.py
    │   ├── standalone_test.py
    │   ├── storage_test.py
    │   ├── util_test.py
    │   └── webroot_test.py
    ├── renewal_test.py
    ├── renewupdater_test.py
    ├── reporter_test.py
    ├── reverter_test.py
    ├── storage_test.py
    └── util_test.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.pc/

================================================
FILE: CHANGELOG.md
================================================
# Certbot change log

Certbot adheres to [Semantic Versioning](https://semver.org/).

## 1.3.0 - 2020-03-03

### Added

* Added certbot.ocsp Certbot's API. The certbot.ocsp module can be used to 
  determine the OCSP status of certificates.
* Don't verify the existing certificate in HTTP01Response.simple_verify, for 
  compatibility with the real-world ACME challenge checks.

### Changed

* Certbot will now renew certificates early if they have been revoked according
  to OCSP.
* Fix acme module warnings when response Content-Type includes params (e.g. charset).
* Fixed issue where webroot plugin would incorrectly raise `Read-only file system` 
  error when creating challenge directories (issue #7165).

### Fixed

*

More details about these changes can be found on our GitHub repo.

## 1.2.0 - 2020-02-04

### Added

* Added support for Cloudflare's limited-scope API Tokens
* Added support for `$hostname` in nginx `server_name` directive

### Changed

* Add directory field to error message when field is missing.
* If MD5 hasher is not available, try it in non-security mode (fix for FIPS systems) -- [#1948](https://github.com/certbot/certbot/issues/1948)
* Disable old SSL versions and ciphersuites and remove `SSLCompression off` setting to follow Mozilla recommendations in Apache.
* Remove ECDHE-RSA-AES128-SHA from NGINX ciphers list now that Windows 2008 R2 and Windows 7 are EOLed
* Support for Python 3.4 has been removed.

### Fixed

* Fix collections.abc imports for Python 3.9.
* Fix Apache plugin to use less restrictive umask for making the challenge directory when a restrictive umask was set when certbot was started.

More details about these changes can be found on our GitHub repo.

## 1.1.0 - 2020-01-14

### Added

*

### Changed

* Removed the fallback introduced with 0.34.0 in `acme` to retry a POST-as-GET
  request as a GET request when the targeted ACME CA server seems to not support
  POST-as-GET requests.
* certbot-auto no longer supports architectures other than x86_64 on RHEL 6
  based systems. Existing certbot-auto installations affected by this will
  continue to work, but they will no longer receive updates. To install a
  newer version of Certbot on these systems, you should update your OS.
* Support for Python 3.4 in Certbot and its ACME library is deprecated and will be
  removed in the next release of Certbot. certbot-auto users on x86_64 systems running
  RHEL 6 or derivatives 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.

### Fixed

*

More details about these changes can be found on our GitHub repo.

## 1.0.0 - 2019-12-03

### 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
* When possible, default to automatically configuring the webserver so all requests
  redirect to secure HTTPS access. This is mostly relevant when running Certbot
  in non-interactive mode. Previously, the default was to not redirect all requests.

### 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

*

### Changed

* 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

*

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

* Stop disabling TLS session tickets in Apache as it caused TLS failures on
  some systems.

More details about these changes can be found on our GitHub repo.

## 0.37.0 - 2019-08-07

### Added

* Turn off session tickets for apache plugin by default
* acme: Authz deactivation added to `acme` module.

### Changed

* Follow updated Mozilla recommendations for Nginx ssl_protocols, ssl_ciphers,
  and ssl_prefer_server_ciphers

### Fixed

* Fix certbot-auto failures on RHEL 8.

More details about these changes can be found on our GitHub repo.

## 0.36.0 - 2019-07-11

### Added

* Turn off session tickets for nginx plugin by default
* Added missing error types from RFC8555 to acme

### Changed

* Support for Ubuntu 14.04 Trusty has been removed.
* Update the 'manage your account' help to be more generic.
* The error message when Certbot's Apache plugin is unable to modify your
  Apache configuration has been improved.
* Certbot's config_changes subcommand has been deprecated and will be
  removed in a future release.
* `certbot config_changes` no longer accepts a --num parameter.
* The functions `certbot.plugins.common.Installer.view_config_changes` and
  `certbot.reverter.Reverter.view_config_changes` have been deprecated and will
  be removed in a future release.

### Fixed

* Replace some unnecessary platform-specific line separation.

More details about these changes can be found on our GitHub repo.

## 0.35.1 - 2019-06-10

### Fixed

* Support for specifying an authoritative base domain in our dns-rfc2136 plugin
  has been removed. This feature was added in our last release but had a bug
  which caused the plugin to fail so the feature has been removed until it can
  be added properly.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* certbot-dns-rfc2136

More details about these changes can be found on our GitHub repo.

## 0.35.0 - 2019-06-05

### Added

* dns_rfc2136 plugin now supports explicitly specifying an authoritative
  base domain for cases when the automatic method does not work (e.g.
  Split horizon DNS)

### Changed

*

### Fixed

* Renewal parameter `webroot_path` is always saved, avoiding some regressions
  when `webroot` authenticator plugin is invoked with no challenge to perform.
* Certbot now accepts OCSP responses when an explicit authorized
  responder, different from the issuer, is used to sign OCSP
  responses.
* Scripts in Certbot hook directories are no longer executed when their
  filenames end in a tilde.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* certbot
* certbot-dns-rfc2136

More details about these changes can be found on our GitHub repo.

## 0.34.2 - 2019-05-07

### Fixed

* certbot-auto no longer writes a check_permissions.py script at the root
  of the filesystem.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
changes in this release were to certbot-auto.

More details about these changes can be found on our GitHub repo.

## 0.34.1 - 2019-05-06

### Fixed

* certbot-auto no longer prints a blank line when there are no permissions
  problems.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
changes in this release were to certbot-auto.

More details about these changes can be found on our GitHub repo.

## 0.34.0 - 2019-05-01

### Changed

* Apache plugin now tries to restart httpd on Fedora using systemctl if a
  configuration test error is detected. This has to be done due to the way
  Fedora now generates the self signed certificate files upon first
  restart.
* Updated Certbot and its plugins to improve the handling of file system permissions
  on Windows as a step towards adding proper Windows support to Certbot.
* Updated urllib3 to 1.24.2 in certbot-auto.
* Removed the fallback introduced with 0.32.0 in `acme` to retry a challenge response
  with a `keyAuthorization` if sending the response without this field caused a
  `malformed` error to be received from the ACME server.
* Linode DNS plugin now supports api keys created from their new panel
  at [cloud.linode.com](https://cloud.linode.com)

### Fixed

* Fixed Google DNS Challenge issues when private zones exist
* Adding a warning noting that future versions of Certbot will automatically configure the
  webserver so that all requests redirect to secure HTTPS access. You can control this
  behavior and disable this warning with the --redirect and --no-redirect flags.
* certbot-auto now prints warnings when run as root with insecure file system
  permissions. If you see these messages, you should fix the problem by
  following the instructions at
  https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/,
  however, these warnings can be disabled as necessary with the flag
  --no-permissions-check.
* `acme` module uses now a POST-as-GET request to retrieve the registration
  from an ACME v2 server
* Convert the tsig algorithm specified in the certbot_dns_rfc2136 configuration file to
  all uppercase letters before validating. This makes the value in the config case
  insensitive.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* acme
* certbot
* certbot-apache
* certbot-dns-cloudflare
* certbot-dns-cloudxns
* certbot-dns-digitalocean
* certbot-dns-dnsimple
* certbot-dns-dnsmadeeasy
* certbot-dns-gehirn
* certbot-dns-google
* certbot-dns-linode
* certbot-dns-luadns
* certbot-dns-nsone
* certbot-dns-ovh
* certbot-dns-rfc2136
* certbot-dns-route53
* certbot-dns-sakuracloud
* certbot-nginx

More details about these changes can be found on our GitHub repo.

## 0.33.1 - 2019-04-04

### Fixed

* A bug causing certbot-auto to print warnings or crash on some RHEL based
  systems has been resolved.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
changes in this release were to certbot-auto.

More details about these changes can be found on our GitHub repo.

## 0.33.0 - 2019-04-03

### Added

* Fedora 29+ is now supported by certbot-auto. Since Python 2.x is on a deprecation
  path in Fedora, certbot-auto will install and use Python 3.x on Fedora 29+.
* CLI flag `--https-port` has been added for Nginx plugin exclusively, and replaces
  `--tls-sni-01-port`. It defines the HTTPS port the Nginx plugin will use while
  setting up a new SSL vhost. By default the HTTPS port is 443.

### Changed

* Support for TLS-SNI-01 has been removed from all official Certbot plugins.
* Attributes related to the TLS-SNI-01 challenge in `acme.challenges` and `acme.standalone`
  modules are deprecated and will be removed soon.
* CLI flags `--tls-sni-01-port` and `--tls-sni-01-address` are now no-op, will
  generate a deprecation warning if used, and will be removed soon.
* Options `tls-sni` and `tls-sni-01` in `--preferred-challenges` flag are now no-op,
  will generate a deprecation warning if used, and will be removed soon.
* CLI flag `--standalone-supported-challenges` has been removed.

### Fixed

* Certbot uses the Python library cryptography for OCSP when cryptography>=2.5
  is installed. We fixed a bug in Certbot causing it to interpret timestamps in
  the OCSP response as being in the local timezone rather than UTC.
* Issue causing the default CentOS 6 TLS configuration to ignore some of the
  HTTPS VirtualHosts created by Certbot. mod_ssl loading is now moved to main
  http.conf for this environment where possible.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* acme
* certbot
* certbot-apache
* certbot-nginx

More details about these changes can be found on our GitHub repo.

## 0.32.0 - 2019-03-06

### Added

* If possible, Certbot uses built-in support for OCSP from recent cryptography
  versions instead of the OpenSSL binary: as a consequence Certbot does not need
  the OpenSSL binary to be installed anymore if cryptography>=2.5 is installed.

### Changed

* Certbot and its acme module now depend on josepy>=1.1.0 to avoid printing the
  warnings described at https://github.com/certbot/josepy/issues/13.
* Apache plugin now respects CERTBOT_DOCS environment variable when adding
  command line defaults.
* The running of manual plugin hooks is now always included in Certbot's log
  output.
* Tests execution for certbot, certbot-apache and certbot-nginx packages now relies on pytest.
* An ACME CA server may return a "Retry-After" HTTP header on authorization polling, as
  specified in the ACME protocol, to indicate when the next polling should occur. Certbot now
  reads this header if set and respect its value.
* The `acme` module avoids sending the `keyAuthorization` field in the JWS
  payload when responding to a challenge as the field is not included in the
  current ACME protocol. To ease the migration path for ACME CA servers,
  Certbot and its `acme` module will first try the request without the
  `keyAuthorization` field but will temporarily retry the request with the
  field included if a `malformed` error is received. This fallback will be
  removed in version 0.34.0.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* acme
* certbot
* certbot-apache
* certbot-nginx

More details about these changes can be found on our GitHub repo.

## 0.31.0 - 2019-02-07

### Added

* Avoid reprocessing challenges that are already validated
  when a certificate is issued.
* Support for initiating (but not solving end-to-end) TLS-ALPN-01 challenges
  with the `acme` module.

### Changed

* Certbot's official Docker images are now based on Alpine Linux 3.9 rather
  than 3.7. The new version comes with OpenSSL 1.1.1.
* Lexicon-based DNS plugins are now fully compatible with Lexicon 3.x (support
  on 2.x branch is maintained).
* Apache plugin now attempts to configure all VirtualHosts matching requested
  domain name instead of only a single one when answering the HTTP-01 challenge.

### Fixed

* Fixed accessing josepy contents through acme.jose when the full acme.jose
  path is used.
* Clarify behavior for deleting certs as part of revocation.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* acme
* certbot
* certbot-apache
* certbot-dns-cloudxns
* certbot-dns-dnsimple
* certbot-dns-dnsmadeeasy
* certbot-dns-gehirn
* certbot-dns-linode
* certbot-dns-luadns
* certbot-dns-nsone
* certbot-dns-ovh
* certbot-dns-sakuracloud

More details about these changes can be found on our GitHub repo.

## 0.30.2 - 2019-01-25

### Fixed

* Update the version of setuptools pinned in certbot-auto to 40.6.3 to
  solve installation problems on newer OSes.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, this
release only affects certbot-auto.

More details about these changes can be found on our GitHub repo.

## 0.30.1 - 2019-01-24

### Fixed

* Always download the pinned version of pip in pipstrap to address breakages
* Rename old,default.conf to old-and-default.conf to address commas in filenames
  breaking recent versions of pip.
* Add VIRTUALENV_NO_DOWNLOAD=1 to all calls to virtualenv to address breakages
  from venv downloading the latest pip

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* certbot-apache

More details about these changes can be found on our GitHub repo.

## 0.30.0 - 2019-01-02

### Added

* Added the `update_account` subcommand for account management commands.

### Changed

* Copied account management functionality from the `register` subcommand
  to the `update_account` subcommand.
* Marked usage `register --update-registration` for deprecation and
  removal in a future release.

### Fixed

* Older modules in the josepy library can now be accessed through acme.jose
  like it could in previous versions of acme. This is only done to preserve
  backwards compatibility and support for doing this with new modules in josepy
  will not be added. Users of the acme library should switch to using josepy
  directly if they haven't done so already.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* acme

More details about these changes can be found on our GitHub repo.

## 0.29.1 - 2018-12-05

### Added

*

### Changed

*

### Fixed

* The default work and log directories have been changed back to
  /var/lib/letsencrypt and /var/log/letsencrypt respectively.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* certbot

More details about these changes can be found on our GitHub repo.

## 0.29.0 - 2018-12-05

### Added

* Noninteractive renewals with `certbot renew` (those not started from a
  terminal) now randomly sleep 1-480 seconds before beginning work in
  order to spread out load spikes on the server side.
* Added External Account Binding support in cli and acme library.
  Command line arguments --eab-kid and --eab-hmac-key added.

### Changed

* Private key permissioning changes: Renewal preserves existing group mode
  & gid of previous private key material. Private keys for new
  lineages (i.e. new certs, not renewed) default to 0o600.

### Fixed

* Update code and dependencies to clean up Resource and Deprecation Warnings.
* Only depend on imgconverter extension for Sphinx >= 1.6

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* acme
* certbot
* certbot-apache
* certbot-dns-cloudflare
* certbot-dns-digitalocean
* certbot-dns-google
* certbot-nginx

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/62?closed=1

## 0.28.0 - 2018-11-7

### Added

* `revoke` accepts `--cert-name`, and doesn't accept both `--cert-name` and `--cert-path`.
* Use the ACMEv2 newNonce endpoint when a new nonce is needed, and newNonce is available in the directory.

### Changed

* Removed documentation mentions of `#letsencrypt` IRC on Freenode.
* Write README to the base of (config-dir)/live directory
* `--manual` will explicitly warn users that earlier challenges should remain in place when setting up subsequent challenges.
* Warn when using deprecated acme.challenges.TLSSNI01
* Log warning about TLS-SNI deprecation in Certbot
* Stop preferring TLS-SNI in the Apache, Nginx, and standalone plugins
* OVH DNS plugin now relies on Lexicon>=2.7.14 to support HTTP proxies
* Default time the Linode plugin waits for DNS changes to propagate is now 1200 seconds.

### Fixed

* Match Nginx parser update in allowing variable names to start with `${`.
* Fix ranking of vhosts in Nginx so that all port-matching vhosts come first
* Correct OVH integration tests on machines without internet access.
* Stop caching the results of ipv6_info in http01.py
* Test fix for Route53 plugin to prevent boto3 making outgoing connections.
* The grammar used by Augeas parser in Apache plugin was updated to fix various parsing errors.
* The CloudXNS, DNSimple, DNS Made Easy, Gehirn, Linode, LuaDNS, NS1, OVH, and
  Sakura Cloud DNS plugins are now compatible with Lexicon 3.0+.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* acme
* certbot
* certbot-apache
* certbot-dns-cloudxns
* certbot-dns-dnsimple
* certbot-dns-dnsmadeeasy
* certbot-dns-gehirn
* certbot-dns-linode
* certbot-dns-luadns
* certbot-dns-nsone
* certbot-dns-ovh
* certbot-dns-route53
* certbot-dns-sakuracloud
* certbot-nginx

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/59?closed=1

## 0.27.1 - 2018-09-06

### Fixed

* Fixed parameter name in OpenSUSE overrides for default parameters in the
  Apache plugin. Certbot on OpenSUSE works again.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* certbot-apache

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/60?closed=1

## 0.27.0 - 2018-09-05

### Added

* The Apache plugin now accepts the parameter --apache-ctl which can be
  used to configure the path to the Apache control script.

### Changed

* When using `acme.client.ClientV2` (or
 `acme.client.BackwardsCompatibleClientV2` with an ACME server that supports a
 newer version of the ACME protocol), an `acme.errors.ConflictError` will be
 raised if you try to create an ACME account with a key that has already been
 used. Previously, a JSON parsing error was raised in this scenario when using
 the library with Let's Encrypt's ACMEv2 endpoint.

### Fixed

* When Apache is not installed, Certbot's Apache plugin no longer prints
  messages about being unable to find apachectl to the terminal when the plugin
  is not selected.
* If you're using the Apache plugin with the --apache-vhost-root flag set to a
  directory containing a disabled virtual host for the domain you're requesting
  a certificate for, the virtual host will now be temporarily enabled if
  necessary to pass the HTTP challenge.
* The documentation for the Certbot package can now be built using Sphinx 1.6+.
* You can now call `query_registration` without having to first call
  `new_account` on `acme.client.ClientV2` objects.
* The requirement of `setuptools>=1.0` has been removed from `certbot-dns-ovh`.
* Names in certbot-dns-sakuracloud's tests have been updated to refer to Sakura
  Cloud rather than NS1 whose plugin certbot-dns-sakuracloud was based on.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:

* acme
* certbot
* certbot-apache
* certbot-dns-ovh
* certbot-dns-sakuracloud

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/57?closed=1

## 0.26.1 - 2018-07-17

### Fixed

* Fix a bug that was triggered when users who had previously manually set `--server` to get ACMEv2 certs tried to renew ACMEv1 certs.

Despite us having broken lockstep, we are continuing to release new versions of all Certbot components during releases for the time being, however, the only package with changes other than its version number was:

* certbot

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/58?closed=1

## 0.26.0 - 2018-07-11

### Added

* A new security enhancement which we're calling AutoHSTS has been added to
  Certbot's Apache plugin. This enhancement configures your webserver to send a
  HTTP Strict Transport Security header with a low max-age value that is slowly
  increased over time. The max-age value is not increased to a large value
  until you've successfully managed to renew your certificate. This enhancement
  can be requested with the --auto-hsts flag.
* New official DNS plugins have been created for Gehirn Infrastructure Service,
  Linode, OVH, and Sakura Cloud. These plugins can be found on our Docker Hub
  page at https://hub.docker.com/u/certbot and on PyPI.
* The ability to reuse ACME accounts from Let's Encrypt's ACMEv1 endpoint on
  Let's Encrypt's ACMEv2 endpoint has been added.
* Certbot and its components now support Python 3.7.
* Certbot's install subcommand now allows you to interactively choose which
  certificate to install from the list of certificates managed by Certbot.
* Certbot now accepts the flag `--no-autorenew` which causes any obtained
  certificates to not be automatically renewed when it approaches expiration.
* Support for parsing the TLS-ALPN-01 challenge has been added back to the acme
  library.

### Changed

* Certbot's default ACME server has been changed to Let's Encrypt's ACMEv2
  endpoint. By default, this server will now be used for both new certificate
  lineages and renewals.
* The Nginx plugin is no longer marked labeled as an "Alpha" version.
* The `prepare` method of Certbot's plugins is no longer called before running
  "Updater" enhancements that are run on every invocation of `certbot renew`.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
packages with functional changes were:

* acme
* certbot
* certbot-apache
* certbot-dns-gehirn
* certbot-dns-linode
* certbot-dns-ovh
* certbot-dns-sakuracloud
* certbot-nginx

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/55?closed=1

## 0.25.1 - 2018-06-13

### Fixed

* TLS-ALPN-01 support has been removed from our acme library. Using our current
  dependencies, we are unable to provide a correct implementation of this
  challenge so we decided to remove it from the library until we can provide
  proper support.
* Issues causing test failures when running the tests in the acme package with
  pytest<3.0 has been resolved.
* certbot-nginx now correctly depends on acme>=0.25.0.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
packages with changes other than their version number were:

* acme
* certbot-nginx

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/56?closed=1

## 0.25.0 - 2018-06-06

### Added

* Support for the ready status type was added to acme. Without this change,
  Certbot and acme users will begin encountering errors when using Let's
  Encrypt's ACMEv2 API starting on June 19th for the staging environment and
  July 5th for production. See
  https://community.letsencrypt.org/t/acmev2-order-ready-status/62866 for more
  information.
* Certbot now accepts the flag --reuse-key which will cause the same key to be
  used in the certificate when the lineage is renewed rather than generating a
  new key.
* You can now add multiple email addresses to your ACME account with Certbot by
  providing a comma separated list of emails to the --email flag.
* Support for Let's Encrypt's upcoming TLS-ALPN-01 challenge was added to acme.
  For more information, see
  https://community.letsencrypt.org/t/tls-alpn-validation-method/63814/1.
* acme now supports specifying the source address to bind to when sending
  outgoing connections. You still cannot specify this address using Certbot.
* If you run Certbot against Let's Encrypt's ACMEv2 staging server but don't
  already have an account registered at that server URL, Certbot will
  automatically reuse your staging account from Let's Encrypt's ACMEv1 endpoint
  if it exists.
* Interfaces were added to Certbot allowing plugins to be called at additional
  points. The `GenericUpdater` interface allows plugins to perform actions
  every time `certbot renew` is run, regardless of whether any certificates are
  due for renewal, and the `RenewDeployer` interface allows plugins to perform
  actions when a certificate is renewed. See `certbot.interfaces` for more
  information.

### Changed

* When running Certbot with --dry-run and you don't already have a staging
  account, the created account does not contain an email address even if one
  was provided to avoid expiration emails from Let's Encrypt's staging server.
* certbot-nginx does a better job of automatically detecting the location of
  Nginx's configuration files when run on BSD based systems.
* acme now requires and uses pytest when running tests with setuptools with
  `python setup.py test`.
* `certbot config_changes` no longer waits for user input before exiting.

### Fixed

* Misleading log output that caused users to think that Certbot's standalone
  plugin failed to bind to a port when performing a challenge has been
  corrected.
* An issue where certbot-nginx would fail to enable HSTS if the server block
  already had an `add_header` directive has been resolved.
* certbot-nginx now does a better job detecting the server block to base the
  configuration for TLS-SNI challenges on.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
packages with functional changes were:

* acme
* certbot
* certbot-apache
* certbot-nginx

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/54?closed=1

## 0.24.0 - 2018-05-02

### Added

* certbot now has an enhance subcommand which allows you to configure security
  enhancements like HTTP to HTTPS redirects, OCSP stapling, and HSTS without
  reinstalling a certificate.
* certbot-dns-rfc2136 now allows the user to specify the port to use to reach
  the DNS server in its credentials file.
* acme now parses the wildcard field included in authorizations so it can be
  used by users of the library.

### Changed

* certbot-dns-route53 used to wait for each DNS update to propagate before
  sending the next one, but now it sends all updates before waiting which
  speeds up issuance for multiple domains dramatically.
* Certbot's official Docker images are now based on Alpine Linux 3.7 rather
  than 3.4 because 3.4 has reached its end-of-life.
* We've doubled the time Certbot will spend polling authorizations before
  timing out.
* The level of the message logged when Certbot is being used with
  non-standard paths warning that crontabs for renewal included in Certbot
  packages from OS package managers may not work has been reduced. This stops
  the message from being written to stderr every time `certbot renew` runs.

### Fixed

* certbot-auto now works with Python 3.6.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
packages with changes other than their version number were:

* acme
* certbot
* certbot-apache
* certbot-dns-digitalocean (only style improvements to tests)
* certbot-dns-rfc2136

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/52?closed=1

## 0.23.0 - 2018-04-04

### Added

* Support for OpenResty was added to the Nginx plugin.

### Changed

* The timestamps in Certbot's logfiles now use the system's local time zone
  rather than UTC.
* Certbot's DNS plugins that use Lexicon now rely on Lexicon>=2.2.1 to be able
  to create and delete multiple TXT records on a single domain.
* certbot-dns-google's test suite now works without an internet connection.

### Fixed

* Removed a small window that if during which an error occurred, Certbot
  wouldn't clean up performed challenges.
* The parameters `default` and `ipv6only` are now removed from `listen`
  directives when creating a new server block in the Nginx plugin.
* `server_name` directives enclosed in quotation marks in Nginx are now properly
  supported.
* Resolved an issue preventing the Apache plugin from starting Apache when it's
  not currently running on RHEL and Gentoo based systems.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
packages with changes other than their version number were:

* certbot
* certbot-apache
* certbot-dns-cloudxns
* certbot-dns-dnsimple
* certbot-dns-dnsmadeeasy
* certbot-dns-google
* certbot-dns-luadns
* certbot-dns-nsone
* certbot-dns-rfc2136
* certbot-nginx

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/50?closed=1

## 0.22.2 - 2018-03-19

### Fixed

* A type error introduced in 0.22.1 that would occur during challenge cleanup
  when a Certbot plugin raises an exception while trying to complete the
  challenge was fixed.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
packages with changes other than their version number were:

* certbot

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/53?closed=1

## 0.22.1 - 2018-03-19

### Changed

* The ACME server used with Certbot's --dry-run and --staging flags is now
  Let's Encrypt's ACMEv2 staging server which allows people to also test ACMEv2
  features with these flags.

### Fixed

* The HTTP Content-Type header is now set to the correct value during
  certificate revocation with new versions of the ACME protocol.
* When using Certbot with Let's Encrypt's ACMEv2 server, it would add a blank
  line to the top of chain.pem and between the certificates in fullchain.pem
  for each lineage. These blank lines have been removed.
* Resolved a bug that caused Certbot's --allow-subset-of-names flag not to
  work.
* Fixed a regression in acme.client.Client that caused the class to not work
  when it was initialized without a ClientNetwork which is done by some of the
  other projects using our ACME library.

Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
packages with changes other than their version number were:

* acme
* certbot

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/51?closed=1

## 0.22.0 - 2018-03-07

### Added

* Support for obtaining wildcard certificates and a newer version of the ACME
  protocol such as the one implemented by Let's Encrypt's upcoming ACMEv2
  endpoint was added to Certbot and its ACME library. Certbot still works with
  older ACME versions and will automatically change the version of the protocol
  used based on the version the ACME CA implements.
* The Apache and Nginx plugins are now able to automatically install a wildcard
  certificate to multiple virtual hosts that you select from your server
  configuration.
* The `certbot install` command now accepts the `--cert-name` flag for
  selecting a certificate.
* `acme.client.BackwardsCompatibleClientV2` was added to Certbot's ACME library
  which automatically handles most of the differences between new and old ACME
  versions. `acme.client.ClientV2` is also available for people who only want
  to support one version of the protocol or want to handle the differences
  between versions themselves.
* certbot-auto now supports the flag --install-only which has the script
  install Certbot and its dependencies and exit without invoking Certbot.
* Support for issuing a single certificate for a wildcard and base domain was
  added to our Google Cloud DNS plugin. To do this, we now require your API
  credentials have additional permissions, however, your credentials will
  already have these permissions unless you defined a custom role with fewer
  permissions than the standard DNS administrator role provided by Google.
  These permissions are also only needed for the case described above so it
  will continue to work for existing users. For more information about the
  permissions changes, see the documentation in the plugin.

### Changed

* We have broken lockstep between our ACME library, Certbot, and its plugins.
  This means that the different components do not need to be the same version
  to work together like they did previously. This makes packaging easier
  because not every piece of Certbot needs to be repackaged to ship a change to
  a subset of its components.
* Support for Python 2.6 and Python 3.3 has been removed from ACME, Certbot,
  Certbot's plugins, and certbot-auto. If you are using certbot-auto on a RHEL
  6 based system, it will walk you through the process of installing Certbot
  with Python 3 and refuse to upgrade to a newer version of Certbot until you
  have done so.
* Certbot's components now work with older versions of setuptools to simplify
  packaging for EPEL 7.

### Fixed

* Issues caused by Certbot's Nginx plugin adding multiple ipv6only directives
  has been resolved.
* A problem where Certbot's Apache plugin would add redundant include
  directives for the TLS configuration managed by Certbot has been fixed.
* Certbot's webroot plugin now properly deletes any directories it creates.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/48?closed=1

## 0.21.1 - 2018-01-25

### Fixed

* When creating an HTTP to HTTPS redirect in Nginx, we now ensure the Host
  header of the request is set to an expected value before redirecting users to
  the domain found in the header. The previous way Certbot configured Nginx
  redirects was a potential security issue which you can read more about at
  https://community.letsencrypt.org/t/security-issue-with-redirects-added-by-certbots-nginx-plugin/51493.
* Fixed a problem where Certbot's Apache plugin could fail HTTP-01 challenges
  if basic authentication is configured for the domain you request a
  certificate for.
* certbot-auto --no-bootstrap now properly tries to use Python 3.4 on RHEL 6
  based systems rather than Python 2.6.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/49?closed=1

## 0.21.0 - 2018-01-17

### Added

* Support for the HTTP-01 challenge type was added to our Apache and Nginx
  plugins. For those not aware, Let's Encrypt disabled the TLS-SNI-01 challenge
  type which was what was previously being used by our Apache and Nginx plugins
  last week due to a security issue. For more information about Let's Encrypt's
  change, click
  [here](https://community.letsencrypt.org/t/2018-01-11-update-regarding-acme-tls-sni-and-shared-hosting-infrastructure/50188).
  Our Apache and Nginx plugins will automatically switch to use HTTP-01 so no
  changes need to be made to your Certbot configuration, however, you should
  make sure your server is accessible on port 80 and isn't behind an external
  proxy doing things like redirecting all traffic from HTTP to HTTPS. HTTP to
  HTTPS redirects inside Apache and Nginx are fine.
* IPv6 support was added to the Nginx plugin.
* Support for automatically creating server blocks based on the default server
  block was added to the Nginx plugin.
* The flags --delete-after-revoke and --no-delete-after-revoke were added
  allowing users to control whether the revoke subcommand also deletes the
  certificates it is revoking.

### Changed

* We deprecated support for Python 2.6 and Python 3.3 in Certbot and its ACME
  library. Support for these versions of Python will be removed in the next
  major release of Certbot. If you are using certbot-auto on a RHEL 6 based
  system, it will guide you through the process of installing Python 3.
* We split our implementation of JOSE (Javascript Object Signing and
  Encryption) out of our ACME library and into a separate package named josepy.
  This package is available on [PyPI](https://pypi.python.org/pypi/josepy) and
  on [GitHub](https://github.com/certbot/josepy).
* We updated the ciphersuites used in Apache to the new [values recommended by
  Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29).
  The major change here is adding ChaCha20 to the list of supported
  ciphersuites.

### Fixed

* An issue with our Apache plugin on Gentoo due to differences in their
  apache2ctl command have been resolved.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/47?closed=1

## 0.20.0 - 2017-12-06

### Added

* Certbot's ACME library now recognizes URL fields in challenge objects in
  preparation for Let's Encrypt's new ACME endpoint. The value is still
  accessible in our ACME library through the name "uri".

### Changed

* The Apache plugin now parses some distro specific Apache configuration files
  on non-Debian systems allowing it to get a clearer picture on the running
  configuration. Internally, these changes were structured so that external
  contributors can easily write patches to make the plugin work in new Apache
  configurations.
* Certbot better reports network failures by removing information about
  connection retries from the error output.
* An unnecessary question when using Certbot's webroot plugin interactively has
  been removed.

### Fixed

* Certbot's NGINX plugin no longer sometimes incorrectly reports that it was
  unable to deploy a HTTP->HTTPS redirect when requesting Certbot to enable a
  redirect for multiple domains.
* Problems where the Apache plugin was failing to find directives and
  duplicating existing directives on openSUSE have been resolved.
* An issue running the test shipped with Certbot and some our DNS plugins with
  older versions of mock have been resolved.
* On some systems, users reported strangely interleaved output depending on
  when stdout and stderr were flushed. This problem was resolved by having
  Certbot regularly flush these streams.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/44?closed=1

## 0.19.0 - 2017-10-04

### Added

* Certbot now has renewal hook directories where executable files can be placed
  for Certbot to run with the renew subcommand. Pre-hooks, deploy-hooks, and
  post-hooks can be specified in the renewal-hooks/pre, renewal-hooks/deploy,
  and renewal-hooks/post directories respectively in Certbot's configuration
  directory (which is /etc/letsencrypt by default). Certbot will automatically
  create these directories when it is run if they do not already exist.
* After revoking a certificate with the revoke subcommand, Certbot will offer
  to delete the lineage associated with the certificate. When Certbot is run
  with --non-interactive, it will automatically try to delete the associated
  lineage.
* When using Certbot's Google Cloud DNS plugin on Google Compute Engine, you no
  longer have to provide a credential file to Certbot if you have configured
  sufficient permissions for the instance which Certbot can automatically
  obtain using Google's metadata service.

### Changed

* When deleting certificates interactively using the delete subcommand, Certbot
  will now allow you to select multiple lineages to be deleted at once.
* Certbot's Apache plugin no longer always parses Apache's sites-available on
  Debian based systems and instead only parses virtual hosts included in your
  Apache configuration. You can provide an additional directory for Certbot to
  parse using the command line flag --apache-vhost-root.

### Fixed

* The plugins subcommand can now be run without root access.
* certbot-auto now includes a timeout when updating itself so it no longer
  hangs indefinitely when it is unable to connect to the external server.
* An issue where Certbot's Apache plugin would sometimes fail to deploy a
  certificate on Debian based systems if mod_ssl wasn't already enabled has
  been resolved.
* A bug in our Docker image where the certificates subcommand could not report
  if certificates maintained by Certbot had been revoked has been fixed.
* Certbot's RFC 2136 DNS plugin (for use with software like BIND) now properly
  performs DNS challenges when the domain being verified contains a CNAME
  record.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/43?closed=1

## 0.18.2 - 2017-09-20

### Fixed

* An issue where Certbot's ACME module would raise an AttributeError trying to
  create self-signed certificates when used with pyOpenSSL 17.3.0 has been
  resolved. For Certbot users with this version of pyOpenSSL, this caused
  Certbot to crash when performing a TLS SNI challenge or when the Nginx plugin
  tried to create an SSL server block.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/46?closed=1

## 0.18.1 - 2017-09-08

### Fixed

* If certbot-auto was running as an unprivileged user and it upgraded from
  0.17.0 to 0.18.0, it would crash with a permissions error and would need to
  be run again to successfully complete the upgrade. This has been fixed and
  certbot-auto should upgrade cleanly to 0.18.1.
* Certbot usually uses "certbot-auto" or "letsencrypt-auto" in error messages
  and the User-Agent string instead of "certbot" when you are using one of
  these wrapper scripts. Proper detection of this was broken with Certbot's new
  installation path in /opt in 0.18.0 but this problem has been resolved.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/45?closed=1

## 0.18.0 - 2017-09-06

### Added

* The Nginx plugin now configures Nginx to use 2048-bit Diffie-Hellman
  parameters. Java 6 clients do not support Diffie-Hellman parameters larger
  than 1024 bits, so if you need to support these clients you will need to
  manually modify your Nginx configuration after using the Nginx installer.

### Changed

* certbot-auto now installs Certbot in directories under `/opt/eff.org`. If you
  had an existing installation from certbot-auto, a symlink is created to the
  new directory. You can configure certbot-auto to use a different path by
  setting the environment variable VENV_PATH.
* The Nginx plugin can now be selected in Certbot's interactive output.
* Output verbosity of renewal failures when running with `--quiet` has been
  reduced.
* The default revocation reason shown in Certbot help output now is a human
  readable string instead of a numerical code.
* Plugin selection is now included in normal terminal output.

### Fixed

* A newer version of ConfigArgParse is now installed when using certbot-auto
  causing values set to false in a Certbot INI configuration file to be handled
  intuitively. Setting a boolean command line flag to false is equivalent to
  not including it in the configuration file at all.
* New naming conventions preventing certbot-auto from installing OS
  dependencies on Fedora 26 have been resolved.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/42?closed=1

## 0.17.0 - 2017-08-02

### Added

* Support in our nginx plugin for modifying SSL server blocks that do
  not contain certificate or key directives.
* A `--max-log-backups` flag to allow users to configure or even completely
  disable Certbot's built in log rotation.
* A `--user-agent-comment` flag to allow people who build tools around Certbot
  to differentiate their user agent string by adding a comment to its default
  value.

### Changed

* Due to some awesome work by
  [cryptography project](https://github.com/pyca/cryptography), compilation can
  now be avoided on most systems when using certbot-auto. This eliminates many
  problems people have had in the past such as running out of memory, having
  invalid headers/libraries, and changes to the OS packages on their system
  after compilation breaking Certbot.
* The `--renew-hook` flag has been hidden in favor of `--deploy-hook`. This new
  flag works exactly the same way except it is always run when a certificate is
  issued rather than just when it is renewed.
* We have started printing deprecation warnings in certbot-auto for
  experimentally supported systems with OS packages available.
* A certificate lineage's name is included in error messages during renewal.

### Fixed

* Encoding errors that could occur when parsing error messages from the ACME
  server containing Unicode have been resolved.
* certbot-auto no longer prints misleading messages about there being a newer
  pip version available when installation fails.
* Certbot's ACME library now properly extracts domains from critical SAN
  extensions.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.17.0+is%3Aclosed

## 0.16.0 - 2017-07-05

### Added

* A plugin for performing DNS challenges using dynamic DNS updates as defined
  in RFC 2316. This plugin is packaged separately from Certbot and is available
  at https://pypi.python.org/pypi/certbot-dns-rfc2136. It supports Python 2.6,
  2.7, and 3.3+. At this time, there isn't a good way to install this plugin
  when using certbot-auto, but this should change in the near future.
* Plugins for performing DNS challenges for the providers
  [DNS Made Easy](https://pypi.python.org/pypi/certbot-dns-dnsmadeeasy) and
  [LuaDNS](https://pypi.python.org/pypi/certbot-dns-luadns). These plugins are
  packaged separately from Certbot and support Python 2.7 and 3.3+. Currently,
  there isn't a good way to install these plugins when using certbot-auto,
  but that should change soon.
* Support for performing TLS-SNI-01 challenges when using the manual plugin.
* Automatic detection of Arch Linux in the Apache plugin providing better
  default settings for the plugin.

### Changed

* The text of the interactive question about whether a redirect from HTTP to
  HTTPS should be added by Certbot has been rewritten to better explain the
  choices to the user.
* Simplified HTTP challenge instructions in the manual plugin.

### Fixed

* Problems performing a dry run when using the Nginx plugin have been fixed.
* Resolved an issue where certbot-dns-digitalocean's test suite would sometimes
  fail when ran using Python 3.
* On some systems, previous versions of certbot-auto would error out with a
  message about a missing hash for setuptools. This has been fixed.
* A bug where Certbot would sometimes not print a space at the end of an
  interactive prompt has been resolved.
* Nonfatal tracebacks are no longer shown in rare cases where Certbot
  encounters an exception trying to close its TCP connection with the ACME
  server.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.16.0+is%3Aclosed

## 0.15.0 - 2017-06-08

### Added

* Plugins for performing DNS challenges for popular providers. Like the Apache
  and Nginx plugins, these plugins are packaged separately and not included in
  Certbot by default. So far, we have plugins for
  [Amazon Route 53](https://pypi.python.org/pypi/certbot-dns-route53),
  [Cloudflare](https://pypi.python.org/pypi/certbot-dns-cloudflare),
  [DigitalOcean](https://pypi.python.org/pypi/certbot-dns-digitalocean), and
  [Google Cloud](https://pypi.python.org/pypi/certbot-dns-google) which all
  work on Python 2.6, 2.7, and 3.3+. Additionally, we have plugins for
  [CloudXNS](https://pypi.python.org/pypi/certbot-dns-cloudxns),
  [DNSimple](https://pypi.python.org/pypi/certbot-dns-dnsimple),
  [NS1](https://pypi.python.org/pypi/certbot-dns-nsone) which work on Python
  2.7 and 3.3+ (and not 2.6). Currently, there isn't a good way to install
  these plugins when using `certbot-auto`, but that should change soon.
* IPv6 support in the standalone plugin. When performing a challenge, the
  standalone plugin automatically handles listening for IPv4/IPv6 traffic based
  on the configuration of your system.
* A mechanism for keeping your Apache and Nginx SSL/TLS configuration up to
  date. When the Apache or Nginx plugins are used, they place SSL/TLS
  configuration options in the root of Certbot's config directory
  (`/etc/letsencrypt` by default). Now when a new version of these plugins run
  on your system, they will automatically update the file to the newest
  version if it is unmodified. If you manually modified the file, Certbot will
  display a warning giving you a path to the updated file which you can use as
  a reference to manually update your modified copy.
* `--http-01-address` and `--tls-sni-01-address` flags for controlling the
  address Certbot listens on when using the standalone plugin.
* The command `certbot certificates` that lists certificates managed by Certbot
  now performs additional validity checks to notify you if your files have
  become corrupted.

### Changed

* Messages custom hooks print to `stdout` are now displayed by Certbot when not
  running in `--quiet` mode.
* `jwk` and `alg` fields in JWS objects have been moved into the protected
  header causing Certbot to more closely follow the latest version of the ACME
  spec.

### Fixed

* Permissions on renewal configuration files are now properly preserved when
  they are updated.
* A bug causing Certbot to display strange defaults in its help output when
  using Python <= 2.7.4 has been fixed.
* Certbot now properly handles mixed case domain names found in custom CSRs.
* A number of poorly worded prompts and error messages.

### Removed

* Support for OpenSSL 1.0.0 in `certbot-auto` has been removed as we now pin a
  newer version of `cryptography` which dropped support for this version.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.15.0+is%3Aclosed

## 0.14.2 - 2017-05-25

### Fixed

* Certbot 0.14.0 included a bug where Certbot would create a temporary log file
(usually in /tmp) if the program exited during argument parsing. If a user
provided -h/--help/help, --version, or an invalid command line argument,
Certbot would create this temporary log file. This was especially bothersome to
certbot-auto users as certbot-auto runs `certbot --version` internally to see
if the script needs to upgrade causing it to create at least one of these files
on every run. This problem has been resolved.

More details about this change can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.14.2+is%3Aclosed

## 0.14.1 - 2017-05-16

### Fixed

* Certbot now works with configargparse 0.12.0.
* Issues with the Apache plugin and Augeas 1.7+ have been resolved.
* A problem where the Nginx plugin would fail to install certificates on
systems that had the plugin's SSL/TLS options file from 7+ months ago has been
fixed.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.14.1+is%3Aclosed

## 0.14.0 - 2017-05-04

### Added

* Python 3.3+ support for all Certbot packages. `certbot-auto` still currently
only supports Python 2, but the `acme`, `certbot`, `certbot-apache`, and
`certbot-nginx` packages on PyPI now fully support Python 2.6, 2.7, and 3.3+.
* Certbot's Apache plugin now handles multiple virtual hosts per file.
* Lockfiles to prevent multiple versions of Certbot running simultaneously.

### Changed

* When converting an HTTP virtual host to HTTPS in Apache, Certbot only copies
the virtual host rather than the entire contents of the file it's contained
in.
* The Nginx plugin now includes SSL/TLS directives in a separate file located
in Certbot's configuration directory rather than copying the contents of the
file into every modified `server` block.

### Fixed

* Ensure logging is configured before parts of Certbot attempt to log any
messages.
* Support for the `--quiet` flag in `certbot-auto`.
* Reverted a change made in a previous release to make the `acme` and `certbot`
packages always depend on `argparse`. This dependency is conditional again on
the user's Python version.
* Small bugs in the Nginx plugin such as properly handling empty `server`
blocks and setting `server_names_hash_bucket_size` during challenges.

As always, a more complete list of changes can be found on GitHub:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.14.0+is%3Aclosed

## 0.13.0 - 2017-04-06

### Added

* `--debug-challenges` now pauses Certbot after setting up challenges for debugging.
* The Nginx parser can now handle all valid directives in configuration files.
* Nginx ciphersuites have changed to Mozilla Intermediate.
* `certbot-auto --no-bootstrap` provides the option to not install OS dependencies.

### Fixed

* `--register-unsafely-without-email` now respects `--quiet`.
* Hyphenated renewal parameters are now saved in renewal config files.
* `--dry-run` no longer persists keys and csrs.
* Certbot no longer hangs when trying to start Nginx in Arch Linux.
* Apache rewrite rules no longer double-encode characters.

A full list of changes is available on GitHub:
https://github.com/certbot/certbot/issues?q=is%3Aissue%20milestone%3A0.13.0%20is%3Aclosed%20

## 0.12.0 - 2017-03-02

### Added

* Certbot now allows non-camelcase Apache VirtualHost names.
* Certbot now allows more log messages to be silenced.

### Fixed

* Fixed a regression around using `--cert-name` when getting new certificates

More information about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue%20milestone%3A0.12.0

## 0.11.1 - 2017-02-01

### Fixed

* Resolved a problem where Certbot would crash while parsing command line
arguments in some cases.
* Fixed a typo.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/pulls?q=is%3Apr%20milestone%3A0.11.1%20is%3Aclosed

## 0.11.0 - 2017-02-01

### Added

* When using the standalone plugin while running Certbot interactively
and a required port is bound by another process, Certbot will give you
the option to retry to grab the port rather than immediately exiting.
* You are now able to deactivate your account with the Let's Encrypt
server using the `unregister` subcommand.
* When revoking a certificate using the `revoke` subcommand, you now
have the option to provide the reason the certificate is being revoked
to Let's Encrypt with `--reason`.

### Changed

* Providing `--quiet` to `certbot-auto` now silences package manager output.

### Removed

* Removed the optional `dnspython` dependency in our `acme` package.
Now the library does not support client side verification of the DNS
challenge.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.11.0+is%3Aclosed

## 0.10.2 - 2017-01-25

### Added

* If Certbot receives a request with a `badNonce` error, it now
automatically retries the request. Since nonces from Let's Encrypt expire,
this helps people performing the DNS challenge with the `manual` plugin
who may have to wait an extended period of time for their DNS changes to
propagate.

### Fixed

* Certbot now saves the `--preferred-challenges` values for renewal. Previously
these values were discarded causing a different challenge type to be used when
renewing certs in some cases.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.10.2+is%3Aclosed

## 0.10.1 - 2017-01-13

### Fixed

* Resolve problems where when asking Certbot to update a certificate at
an existing path to include different domain names, the old names would
continue to be used.
* Fix issues successfully running our unit test suite on some systems.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.10.1+is%3Aclosed

## 0.10.0 - 2017-01-11

## Added

* Added the ability to customize and automatically complete DNS and HTTP
domain validation challenges with the manual plugin. The flags
`--manual-auth-hook` and `--manual-cleanup-hook` can now be provided
when using the manual plugin to execute commands provided by the user to
perform and clean up challenges provided by the CA. This is best used in
complicated setups where the DNS challenge must be used or Certbot's
existing plugins cannot be used to perform HTTP challenges. For more
information on how this works, see `certbot --help manual`.
* Added a `--cert-name` flag for specifying the name to use for the
certificate in Certbot's configuration directory. Using this flag in
combination with `-d/--domains`, a user can easily request a new
certificate with different domains and save it with the name provided by
`--cert-name`. Additionally, `--cert-name` can be used to select a
certificate with the `certonly` and `run` subcommands so a full list of
domains in the certificate does not have to be provided.
* Added subcommand `certificates` for listing the certificates managed by
Certbot and their properties.
* Added the `delete` subcommand for removing certificates managed by Certbot
from the configuration directory.
* Certbot now supports requesting internationalized domain names (IDNs).
* Hooks provided to Certbot are now saved to be reused during renewal.
If you run Certbot with `--pre-hook`, `--renew-hook`, or `--post-hook`
flags when obtaining a certificate, the provided commands will
automatically be saved and executed again when renewing the certificate.
A pre-hook and/or post-hook can also be given to the `certbot renew`
command either on the command line or in a [configuration
file](https://certbot.eff.org/docs/using.html#configuration-file) to run
an additional command before/after any certificate is renewed. Hooks
will only be run if a certificate is renewed.
* Support Busybox in certbot-auto.

### Changed

* Recategorized `-h/--help` output to improve documentation and
discoverability.

### Removed

* Removed the ncurses interface. This change solves problems people
were having on many systems, reduces the number of Certbot
dependencies, and simplifies our code. Certbot's only interface now is
the text interface which was available by providing `-t/--text` to
earlier versions of Certbot.

### Fixed

* Many small bug fixes.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.10.0is%3Aclosed

## 0.9.3 - 2016-10-13

### Added

* The Apache plugin uses information about your OS to help determine the
layout of your Apache configuration directory. We added a patch to
ensure this code behaves the same way when testing on different systems
as the tests were failing in some cases.

### Changed

* Certbot adopted more conservative behavior about reporting a needed port as
unavailable when using the standalone plugin.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/27?closed=1

## 0.9.2 - 2016-10-12

### Added

* Certbot stopped requiring that all possibly required ports are available when
using the standalone plugin. It now only verifies that the ports are available
when they are necessary.

### Fixed

* Certbot now verifies that our optional dependencies version matches what is
required by Certbot.
* Certnot now properly copies the `ssl on;` directives as necessary when
performing domain validation in the Nginx plugin.
* Fixed problem where symlinks were becoming files when they were
packaged, causing errors during testing and OS packaging.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/26?closed=1

## 0.9.1 - 2016-10-06

### Fixed

* Fixed a bug that was introduced in version 0.9.0 where the command
line flag -q/--quiet wasn't respected in some cases.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/25?closed=1

## 0.9.0 - 2016-10-05

### Added

* Added an alpha version of the Nginx plugin. This plugin fully automates the
process of obtaining and installing certificates with Nginx.
Additionally, it is able to automatically configure security
enhancements such as an HTTP to HTTPS redirect and OCSP stapling. To use
this plugin, you must have the `certbot-nginx` package installed (which
is installed automatically when using `certbot-auto`) and provide
`--nginx` on the command line. This plugin is still in its early stages
so we recommend you use it with some caution and make sure you have a
backup of your Nginx configuration.
* Added support for the `DNS` challenge in the `acme` library and `DNS` in
Certbot's `manual` plugin. This allows you to create DNS records to
prove to Let's Encrypt you control the requested domain name. To use
this feature, include `--manual --preferred-challenges dns` on the
command line.
* Certbot now helps with enabling Extra Packages for Enterprise Linux (EPEL) on
CentOS 6 when using `certbot-auto`. To use `certbot-auto` on CentOS 6,
the EPEL repository has to be enabled. `certbot-auto` will now prompt
users asking them if they would like the script to enable this for them
automatically. This is done without prompting users when using
`letsencrypt-auto` or if `-n/--non-interactive/--noninteractive` is
included on the command line.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.9.0+is%3Aclosed

## 0.8.1 - 2016-06-14

### Added

* Certbot now preserves a certificate's common name when using `renew`.
* Certbot now saves webroot values for renewal when they are entered interactively.
* Certbot now gracefully reports that the Apache plugin isn't usable when Augeas is not installed.
* Added experimental support for Mageia has been added to `certbot-auto`.

### Fixed

* Fixed problems with an invalid user-agent string on OS X.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.8.1+

## 0.8.0 - 2016-06-02

### Added

* Added the `register` subcommand which can be used to register an account
with the Let's Encrypt CA.
* You can now run `certbot register --update-registration` to
change the e-mail address associated with your registration.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.8.0+

## 0.7.0 - 2016-05-27

### Added

* Added `--must-staple` to request certificates from Let's Encrypt
with the OCSP must staple extension.
* Certbot now automatically configures OSCP stapling for Apache.
* Certbot now allows requesting certificates for domains found in the common name
of a custom CSR.

### Fixed

* Fixed a number of miscellaneous bugs

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=milestone%3A0.7.0+is%3Aissue

## 0.6.0 - 2016-05-12

### Added

* Versioned the datetime dependency in setup.py.

### Changed

* Renamed the client from `letsencrypt` to `certbot`.

### Fixed

* Fixed a small json deserialization error.
* Certbot now preserves domain order in generated CSRs.
* Fixed some minor bugs.

More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/issues?q=is%3Aissue%20milestone%3A0.6.0%20is%3Aclosed%20

## 0.5.0 - 2016-04-05

### Added

* Added the ability to use the webroot plugin interactively.
* Added the flags --pre-hook, --post-hook, and --renew-hook which can be used with
the renew subcommand to register shell commands to run in response to
renewal events. Pre-hook commands will be run before any certs are
renewed, post-hook commands will be run after any certs are renewed,
and renew-hook commands will be run after each cert is renewed. If no
certs are due for renewal, no command is run.
* Added a -q/--quiet flag which silences all output except errors.
* Added an --allow-subset-of-domains flag which can be used with the renew
command to prevent renewal failures for a subset of the requested
domains from causing the client to exit.

### Changed

* Certbot now uses renewal configuration files. In /etc/letsencrypt/renewal
by default, these files can be used to control what parameters are
used when renewing a specific certificate.

More details about these changes can be found on our GitHub repo:
https://github.com/letsencrypt/letsencrypt/issues?q=milestone%3A0.5.0+is%3Aissue

## 0.4.2 - 2016-03-03

### Fixed

* Resolved problems encountered when compiling letsencrypt
against the new OpenSSL release.
* Fixed problems encountered when using `letsencrypt renew` with configuration files
from the private beta.

More details about these changes can be found on our GitHub repo:
https://github.com/letsencrypt/letsencrypt/issues?q=is%3Aissue+milestone%3A0.4.2

## 0.4.1 - 2016-02-29

### Fixed

* Fixed Apache parsing errors encountered with some configurations.
* Fixed Werkzeug dependency problems encountered on some Red Hat systems.
* Fixed bootstrapping failures when using letsencrypt-auto with --no-self-upgrade.
* Fixed problems with parsing renewal config files from private beta.

More details about these changes can be found on our GitHub repo:
https://github.com/letsencrypt/letsencrypt/issues?q=is:issue+milestone:0.4.1

## 0.4.0 - 2016-02-10

### Added

* Added the verb/subcommand `renew` which can be used to renew your existing
certificates as they approach expiration. Running `letsencrypt renew`
will examine all existing certificate lineages and determine if any are
less than 30 days from expiration. If so, the client will use the
settings provided when you previously obtained the certificate to renew
it. The subcommand finishes by printing a summary of which renewals were
successful, failed, or not yet due.
* Added a `--dry-run` flag to help with testing configuration
without affecting production rate limits. Currently supported by the
`renew` and `certonly` subcommands, providing `--dry-run` on the command
line will obtain certificates from the staging server without saving the
resulting certificates to disk.
* Added major improvements to letsencrypt-auto. This script
has been rewritten to include full support for Python 2.6, the ability
for letsencrypt-auto to update itself, and improvements to the
stability, security, and performance of the script.
* Added support for Apache 2.2 to the Apache plugin.

More details about these changes can be found on our GitHub repo:
https://github.com/letsencrypt/letsencrypt/issues?q=is%3Aissue+milestone%3A0.4.0

## 0.3.0 - 2016-01-27

### Added

* Added a non-interactive mode which can be enabled by including `-n` or
`--non-interactive` on the command line. This can be used to guarantee
the client will not prompt when run automatically using cron/systemd.
* Added preparation for the new letsencrypt-auto script. Over the past
couple months, we've been working on increasing the reliability and
security of letsencrypt-auto. A number of changes landed in this
release to prepare for the new version of this script.

More details about these changes can be found on our GitHub repo:
https://github.com/letsencrypt/letsencrypt/issues?q=is%3Aissue+milestone%3A0.3.0

## 0.2.0 - 2016-01-14

### Added

* Added Apache plugin support for non-Debian based systems. Support has been
added for modern Red Hat based systems such as Fedora 23, Red Hat 7,
and CentOS 7 running Apache 2.4. In theory, this plugin should be
able to be configured to run on any Unix-like OS running Apache 2.4.
* Relaxed PyOpenSSL version requirements. This adds support for systems
with PyOpenSSL versions 0.13 or 0.14.
* Improved error messages from the client.

### Fixed

* Resolved issues with the Apache plugin enabling an HTTP to HTTPS
redirect on some systems.

More details about these changes can be found on our GitHub repo:
https://github.com/letsencrypt/letsencrypt/issues?q=is%3Aissue+milestone%3A0.2.0

## 0.1.1 - 2015-12-15

### Added

* Added a check that avoids attempting to issue for unqualified domain names like
"localhost".

### Fixed

* Fixed a confusing UI path that caused some users to repeatedly renew
their certs while experimenting with the client, in some cases hitting
issuance rate limits.
* Fixed numerous Apache configuration parser problems
* Fixed --webroot permission handling for non-root users

More details about these changes can be found on our GitHub repo:
https://github.com/letsencrypt/letsencrypt/issues?q=milestone%3A0.1.1


================================================
FILE: LICENSE.txt
================================================
Certbot ACME Client
Copyright (c) Electronic Frontier Foundation and others
Licensed Apache Version 2.0

The nginx plugin incorporates code from nginxparser
Copyright (c) 2014 Fatih Erikli
Licensed MIT


Text of Apache License
======================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.


Text of MIT License
===================
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: MANIFEST.in
================================================
include README.rst
include CHANGELOG.md
include LICENSE.txt
recursive-include docs *
recursive-include examples *
recursive-include certbot/tests/testdata *
recursive-include tests *.py
include certbot/ssl-dhparams.pem
global-exclude __pycache__
global-exclude *.py[cod]


================================================
FILE: PKG-INFO
================================================
Metadata-Version: 2.1
Name: certbot
Version: 1.3.0
Summary: ACME client
Home-page: https://github.com/letsencrypt/letsencrypt
Author: Certbot Project
Author-email: client-dev@letsencrypt.org
License: Apache License 2.0
Description: .. This file contains a series of comments that are used to include sections of this README in other files. Do not modify these comments unless you know what you are doing. tag:intro-begin
        
        Certbot is part of EFF’s effort to encrypt the entire Internet. Secure communication over the Web relies on HTTPS, which requires the use of a digital certificate that lets browsers verify the identity of web servers (e.g., is that really google.com?). Web servers obtain their certificates from trusted third parties called certificate authorities (CAs). Certbot is an easy-to-use client that fetches a certificate from Let’s Encrypt—an open certificate authority launched by the EFF, Mozilla, and others—and deploys it to a web server.
        
        Anyone who has gone through the trouble of setting up a secure website knows what a hassle getting and maintaining a certificate is. Certbot and Let’s Encrypt can automate away the pain and let you turn on and manage HTTPS with simple commands. Using Certbot and Let's Encrypt is free, so there’s no need to arrange payment.
        
        How you use Certbot depends on the configuration of your web server. The best way to get started is to use our `interactive guide <https://certbot.eff.org>`_. It generates instructions based on your configuration settings. In most cases, you’ll need `root or administrator access <https://certbot.eff.org/faq/#does-certbot-require-root-administrator-privileges>`_ to your web server to run Certbot.
        
        Certbot is meant to be run directly on your web server, not on your personal computer. If you’re using a hosted service and don’t have direct access to your web server, you might not be able to use Certbot. Check with your hosting provider for documentation about uploading certificates or using certificates issued by Let’s Encrypt.
        
        Certbot is a fully-featured, extensible client for the Let's
        Encrypt CA (or any other CA that speaks the `ACME
        <https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md>`_
        protocol) that can automate the tasks of obtaining certificates and
        configuring webservers to use them. This client runs on Unix-based operating
        systems.
        
        To see the changes made to Certbot between versions please refer to our
        `changelog <https://github.com/certbot/certbot/blob/master/certbot/CHANGELOG.md>`_.
        
        Until May 2016, Certbot was named simply ``letsencrypt`` or ``letsencrypt-auto``,
        depending on install method. Instructions on the Internet, and some pieces of the
        software, may still refer to this older name.
        
        Contributing
        ------------
        
        If you'd like to contribute to this project please read `Developer Guide
        <https://certbot.eff.org/docs/contributing.html>`_.
        
        This project is governed by `EFF's Public Projects Code of Conduct <https://www.eff.org/pages/eppcode>`_.
        
        .. _installation:
        
        How to run the client
        ---------------------
        
        The easiest way to install and run Certbot is by visiting `certbot.eff.org`_,
        where you can find the correct instructions for many web server and OS
        combinations.  For more information, see `Get Certbot
        <https://certbot.eff.org/docs/install.html>`_.
        
        .. _certbot.eff.org: https://certbot.eff.org/
        
        Understanding the client in more depth
        --------------------------------------
        
        To understand what the client is doing in detail, it's important to
        understand the way it uses plugins.  Please see the `explanation of
        plugins <https://certbot.eff.org/docs/using.html#plugins>`_ in
        the User Guide.
        
        Links
        =====
        
        .. Do not modify this comment unless you know what you're doing. tag:links-begin
        
        Documentation: https://certbot.eff.org/docs
        
        Software project: https://github.com/certbot/certbot
        
        Notes for developers: https://certbot.eff.org/docs/contributing.html
        
        Main Website: https://certbot.eff.org
        
        Let's Encrypt Website: https://letsencrypt.org
        
        Community: https://community.letsencrypt.org
        
        ACME spec: http://ietf-wg-acme.github.io/acme/
        
        ACME working area in github: https://github.com/ietf-wg-acme/acme
        
        |build-status| |container|
        
        .. |build-status| image:: https://travis-ci.com/certbot/certbot.svg?branch=master
           :target: https://travis-ci.com/certbot/certbot
           :alt: Travis CI status
        
        .. |container| image:: https://quay.io/repository/letsencrypt/letsencrypt/status
           :target: https://quay.io/repository/letsencrypt/letsencrypt
           :alt: Docker Repository on Quay.io
        
        .. Do not modify this comment unless you know what you're doing. tag:links-end
        
        System Requirements
        ===================
        
        See https://certbot.eff.org/docs/install.html#system-requirements.
        
        .. Do not modify this comment unless you know what you're doing. tag:intro-end
        
        .. Do not modify this comment unless you know what you're doing. tag:features-begin
        
        Current Features
        =====================
        
        * Supports multiple web servers:
        
          - apache/2.x
          - nginx/0.8.48+
          - webroot (adds files to webroot directories in order to prove control of
            domains and obtain certs)
          - standalone (runs its own simple webserver to prove you control a domain)
          - other server software via `third party plugins <https://certbot.eff.org/docs/using.html#third-party-plugins>`_
        
        * The private key is generated locally on your system.
        * Can talk to the Let's Encrypt CA or optionally to other ACME
          compliant services.
        * Can get domain-validated (DV) certificates.
        * Can revoke certificates.
        * Adjustable RSA key bit-length (2048 (default), 4096, ...).
        * Can optionally install a http -> https redirect, so your site effectively
          runs https only (Apache only)
        * Fully automated.
        * Configuration changes are logged and can be reverted.
        * Supports an interactive text UI, or can be driven entirely from the
          command line.
        * Free and Open Source Software, made with Python.
        
        .. Do not modify this comment unless you know what you're doing. tag:features-end
        
        For extensive documentation on using and contributing to Certbot, go to https://certbot.eff.org/docs. If you would like to contribute to the project or run the latest code from git, you should read our `developer guide <https://certbot.eff.org/docs/contributing.html>`_.
        
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Environment :: Console :: Curses
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Security
Classifier: Topic :: System :: Installation/Setup
Classifier: Topic :: System :: Networking
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Utilities
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
Provides-Extra: dev3
Provides-Extra: docs
Provides-Extra: dev


================================================
FILE: README.rst
================================================
.. This file contains a series of comments that are used to include sections of this README in other files. Do not modify these comments unless you know what you are doing. tag:intro-begin

Certbot is part of EFF’s effort to encrypt the entire Internet. Secure communication over the Web relies on HTTPS, which requires the use of a digital certificate that lets browsers verify the identity of web servers (e.g., is that really google.com?). Web servers obtain their certificates from trusted third parties called certificate authorities (CAs). Certbot is an easy-to-use client that fetches a certificate from Let’s Encrypt—an open certificate authority launched by the EFF, Mozilla, and others—and deploys it to a web server.

Anyone who has gone through the trouble of setting up a secure website knows what a hassle getting and maintaining a certificate is. Certbot and Let’s Encrypt can automate away the pain and let you turn on and manage HTTPS with simple commands. Using Certbot and Let's Encrypt is free, so there’s no need to arrange payment.

How you use Certbot depends on the configuration of your web server. The best way to get started is to use our `interactive guide <https://certbot.eff.org>`_. It generates instructions based on your configuration settings. In most cases, you’ll need `root or administrator access <https://certbot.eff.org/faq/#does-certbot-require-root-administrator-privileges>`_ to your web server to run Certbot.

Certbot is meant to be run directly on your web server, not on your personal computer. If you’re using a hosted service and don’t have direct access to your web server, you might not be able to use Certbot. Check with your hosting provider for documentation about uploading certificates or using certificates issued by Let’s Encrypt.

Certbot is a fully-featured, extensible client for the Let's
Encrypt CA (or any other CA that speaks the `ACME
<https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md>`_
protocol) that can automate the tasks of obtaining certificates and
configuring webservers to use them. This client runs on Unix-based operating
systems.

To see the changes made to Certbot between versions please refer to our
`changelog <https://github.com/certbot/certbot/blob/master/certbot/CHANGELOG.md>`_.

Until May 2016, Certbot was named simply ``letsencrypt`` or ``letsencrypt-auto``,
depending on install method. Instructions on the Internet, and some pieces of the
software, may still refer to this older name.

Contributing
------------

If you'd like to contribute to this project please read `Developer Guide
<https://certbot.eff.org/docs/contributing.html>`_.

This project is governed by `EFF's Public Projects Code of Conduct <https://www.eff.org/pages/eppcode>`_.

.. _installation:

How to run the client
---------------------

The easiest way to install and run Certbot is by visiting `certbot.eff.org`_,
where you can find the correct instructions for many web server and OS
combinations.  For more information, see `Get Certbot
<https://certbot.eff.org/docs/install.html>`_.

.. _certbot.eff.org: https://certbot.eff.org/

Understanding the client in more depth
--------------------------------------

To understand what the client is doing in detail, it's important to
understand the way it uses plugins.  Please see the `explanation of
plugins <https://certbot.eff.org/docs/using.html#plugins>`_ in
the User Guide.

Links
=====

.. Do not modify this comment unless you know what you're doing. tag:links-begin

Documentation: https://certbot.eff.org/docs

Software project: https://github.com/certbot/certbot

Notes for developers: https://certbot.eff.org/docs/contributing.html

Main Website: https://certbot.eff.org

Let's Encrypt Website: https://letsencrypt.org

Community: https://community.letsencrypt.org

ACME spec: http://ietf-wg-acme.github.io/acme/

ACME working area in github: https://github.com/ietf-wg-acme/acme

|build-status| |container|

.. |build-status| image:: https://travis-ci.com/certbot/certbot.svg?branch=master
   :target: https://travis-ci.com/certbot/certbot
   :alt: Travis CI status

.. |container| image:: https://quay.io/repository/letsencrypt/letsencrypt/status
   :target: https://quay.io/repository/letsencrypt/letsencrypt
   :alt: Docker Repository on Quay.io

.. Do not modify this comment unless you know what you're doing. tag:links-end

System Requirements
===================

See https://certbot.eff.org/docs/install.html#system-requirements.

.. Do not modify this comment unless you know what you're doing. tag:intro-end

.. Do not modify this comment unless you know what you're doing. tag:features-begin

Current Features
=====================

* Supports multiple web servers:

  - apache/2.x
  - nginx/0.8.48+
  - webroot (adds files to webroot directories in order to prove control of
    domains and obtain certs)
  - standalone (runs its own simple webserver to prove you control a domain)
  - other server software via `third party plugins <https://certbot.eff.org/docs/using.html#third-party-plugins>`_

* The private key is generated locally on your system.
* Can talk to the Let's Encrypt CA or optionally to other ACME
  compliant services.
* Can get domain-validated (DV) certificates.
* Can revoke certificates.
* Adjustable RSA key bit-length (2048 (default), 4096, ...).
* Can optionally install a http -> https redirect, so your site effectively
  runs https only (Apache only)
* Fully automated.
* Configuration changes are logged and can be reverted.
* Supports an interactive text UI, or can be driven entirely from the
  command line.
* Free and Open Source Software, made with Python.

.. Do not modify this comment unless you know what you're doing. tag:features-end

For extensive documentation on using and contributing to Certbot, go to https://certbot.eff.org/docs. If you would like to contribute to the project or run the latest code from git, you should read our `developer guide <https://certbot.eff.org/docs/contributing.html>`_.


================================================
FILE: certbot/__init__.py
================================================
"""Certbot client."""

# version number like 1.2.3a0, must have at least 2 parts, like 1.2
__version__ = '1.3.0'


================================================
FILE: certbot/_internal/__init__.py
================================================
"""
Modules internal to Certbot.

This package contains modules that are not considered part of Certbot's public
API. They may be changed without updating Certbot's major version.
"""


================================================
FILE: certbot/_internal/account.py
================================================
"""Creates ACME accounts for server."""
import datetime
import functools
import hashlib
import logging
import shutil
import socket

from cryptography.hazmat.primitives import serialization
import josepy as jose
import pyrfc3339
import pytz
import six
import zope.component

from acme import fields as acme_fields
from acme import messages
from certbot import errors
from certbot import interfaces
from certbot import util
from certbot._internal import constants
from certbot.compat import os

logger = logging.getLogger(__name__)


class Account(object):
    """ACME protocol registration.

    :ivar .RegistrationResource regr: Registration Resource
    :ivar .JWK key: Authorized Account Key
    :ivar .Meta: Account metadata
    :ivar str id: Globally unique account identifier.

    """

    class Meta(jose.JSONObjectWithFields):
        """Account metadata

        :ivar datetime.datetime creation_dt: Creation date and time (UTC).
        :ivar str creation_host: FQDN of host, where account has been created.

        .. note:: ``creation_dt`` and ``creation_host`` are useful in
            cross-machine migration scenarios.

        """
        creation_dt = acme_fields.RFC3339Field("creation_dt")
        creation_host = jose.Field("creation_host")

    def __init__(self, regr, key, meta=None):
        self.key = key
        self.regr = regr
        self.meta = self.Meta(
            # pyrfc3339 drops microseconds, make sure __eq__ is sane
            creation_dt=datetime.datetime.now(
                tz=pytz.UTC).replace(microsecond=0),
            creation_host=socket.getfqdn()) if meta is None else meta

        # try MD5, else use MD5 in non-security mode (e.g. for FIPS systems / RHEL)
        try:
            hasher = hashlib.md5()
        except ValueError:
            hasher = hashlib.new('md5', usedforsecurity=False) # type: ignore

        hasher.update(self.key.key.public_key().public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo)
        )

        self.id = hasher.hexdigest()
        # Implementation note: Email? Multiple accounts can have the
        # same email address. Registration URI? Assigned by the
        # server, not guaranteed to be stable over time, nor
        # canonical URI can be generated. ACME protocol doesn't allow
        # account key (and thus its fingerprint) to be updated...

    @property
    def slug(self):
        """Short account identification string, useful for UI."""
        return "{1}@{0} ({2})".format(pyrfc3339.generate(
            self.meta.creation_dt), self.meta.creation_host, self.id[:4])

    def __repr__(self):
        return "<{0}({1}, {2}, {3})>".format(
            self.__class__.__name__, self.regr, self.id, self.meta)

    def __eq__(self, other):
        return (isinstance(other, self.__class__) and
                self.key == other.key and self.regr == other.regr and
                self.meta == other.meta)


def report_new_account(config):
    """Informs the user about their new ACME account."""
    reporter = zope.component.queryUtility(interfaces.IReporter)
    if reporter is None:
        return
    reporter.add_message(
        "Your account credentials have been saved in your Certbot "
        "configuration directory at {0}. You should make a secure backup "
        "of this folder now. This configuration directory will also "
        "contain certificates and private keys obtained by Certbot "
        "so making regular backups of this folder is ideal.".format(
            config.config_dir),
        reporter.MEDIUM_PRIORITY)


class AccountMemoryStorage(interfaces.AccountStorage):
    """In-memory account storage."""

    def __init__(self, initial_accounts=None):
        self.accounts = initial_accounts if initial_accounts is not None else {}

    def find_all(self):
        return list(six.itervalues(self.accounts))

    def save(self, account, client):
        if account.id in self.accounts:
            logger.debug("Overwriting account: %s", account.id)
        self.accounts[account.id] = account

    def load(self, account_id):
        try:
            return self.accounts[account_id]
        except KeyError:
            raise errors.AccountNotFound(account_id)

class RegistrationResourceWithNewAuthzrURI(messages.RegistrationResource):
    """A backwards-compatible RegistrationResource with a new-authz URI.

       Hack: Certbot versions pre-0.11.1 expect to load
       new_authzr_uri as part of the account. Because people
       sometimes switch between old and new versions, we will
       continue to write out this field for some time so older
       clients don't crash in that scenario.
    """
    new_authzr_uri = jose.Field('new_authzr_uri')

class AccountFileStorage(interfaces.AccountStorage):
    """Accounts file storage.

    :ivar .IConfig config: Client configuration

    """
    def __init__(self, config):
        self.config = config
        util.make_or_verify_dir(config.accounts_dir, 0o700, self.config.strict_permissions)

    def _account_dir_path(self, account_id):
        return self._account_dir_path_for_server_path(account_id, self.config.server_path)

    def _account_dir_path_for_server_path(self, account_id, server_path):
        accounts_dir = self.config.accounts_dir_for_server_path(server_path)
        return os.path.join(accounts_dir, account_id)

    @classmethod
    def _regr_path(cls, account_dir_path):
        return os.path.join(account_dir_path, "regr.json")

    @classmethod
    def _key_path(cls, account_dir_path):
        return os.path.join(account_dir_path, "private_key.json")

    @classmethod
    def _metadata_path(cls, account_dir_path):
        return os.path.join(account_dir_path, "meta.json")

    def _find_all_for_server_path(self, server_path):
        accounts_dir = self.config.accounts_dir_for_server_path(server_path)
        try:
            candidates = os.listdir(accounts_dir)
        except OSError:
            return []

        accounts = []
        for account_id in candidates:
            try:
                accounts.append(self._load_for_server_path(account_id, server_path))
            except errors.AccountStorageError:
                logger.debug("Account loading problem", exc_info=True)

        if not accounts and server_path in constants.LE_REUSE_SERVERS:
            # find all for the next link down
            prev_server_path = constants.LE_REUSE_SERVERS[server_path]
            prev_accounts = self._find_all_for_server_path(prev_server_path)
            # if we found something, link to that
            if prev_accounts:
                try:
                    self._symlink_to_accounts_dir(prev_server_path, server_path)
                except OSError:
                    return []
            accounts = prev_accounts
        return accounts

    def find_all(self):
        return self._find_all_for_server_path(self.config.server_path)

    def _symlink_to_account_dir(self, prev_server_path, server_path, account_id):
        prev_account_dir = self._account_dir_path_for_server_path(account_id, prev_server_path)
        new_account_dir = self._account_dir_path_for_server_path(account_id, server_path)
        os.symlink(prev_account_dir, new_account_dir)

    def _symlink_to_accounts_dir(self, prev_server_path, server_path):
        accounts_dir = self.config.accounts_dir_for_server_path(server_path)
        if os.path.islink(accounts_dir):
            os.unlink(accounts_dir)
        else:
            os.rmdir(accounts_dir)
        prev_account_dir = self.config.accounts_dir_for_server_path(prev_server_path)
        os.symlink(prev_account_dir, accounts_dir)

    def _load_for_server_path(self, account_id, server_path):
        account_dir_path = self._account_dir_path_for_server_path(account_id, server_path)
        if not os.path.isdir(account_dir_path): # isdir is also true for symlinks
            if server_path in constants.LE_REUSE_SERVERS:
                prev_server_path = constants.LE_REUSE_SERVERS[server_path]
                prev_loaded_account = self._load_for_server_path(account_id, prev_server_path)
                # we didn't error so we found something, so create a symlink to that
                accounts_dir = self.config.accounts_dir_for_server_path(server_path)
                # If accounts_dir isn't empty, make an account specific symlink
                if os.listdir(accounts_dir):
                    self._symlink_to_account_dir(prev_server_path, server_path, account_id)
                else:
                    self._symlink_to_accounts_dir(prev_server_path, server_path)
                return prev_loaded_account
            raise errors.AccountNotFound(
                "Account at %s does not exist" % account_dir_path)

        try:
            with open(self._regr_path(account_dir_path)) as regr_file:
                regr = messages.RegistrationResource.json_loads(regr_file.read())
            with open(self._key_path(account_dir_path)) as key_file:
                key = jose.JWK.json_loads(key_file.read())
            with open(self._metadata_path(account_dir_path)) as metadata_file:
                meta = Account.Meta.json_loads(metadata_file.read())
        except IOError as error:
            raise errors.AccountStorageError(error)

        return Account(regr, key, meta)

    def load(self, account_id):
        return self._load_for_server_path(account_id, self.config.server_path)

    def save(self, account, client):
        self._save(account, client, regr_only=False)

    def save_regr(self, account, acme):
        """Save the registration resource.

        :param Account account: account whose regr should be saved

        """
        self._save(account, acme, regr_only=True)

    def delete(self, account_id):
        """Delete registration info from disk

        :param account_id: id of account which should be deleted

        """
        account_dir_path = self._account_dir_path(account_id)
        if not os.path.isdir(account_dir_path):
            raise errors.AccountNotFound(
                "Account at %s does not exist" % account_dir_path)
        # Step 1: Delete account specific links and the directory
        self._delete_account_dir_for_server_path(account_id, self.config.server_path)

        # Step 2: Remove any accounts links and directories that are now empty
        if not os.listdir(self.config.accounts_dir):
            self._delete_accounts_dir_for_server_path(self.config.server_path)

    def _delete_account_dir_for_server_path(self, account_id, server_path):
        link_func = functools.partial(self._account_dir_path_for_server_path, account_id)
        nonsymlinked_dir = self._delete_links_and_find_target_dir(server_path, link_func)
        shutil.rmtree(nonsymlinked_dir)

    def _delete_accounts_dir_for_server_path(self, server_path):
        link_func = self.config.accounts_dir_for_server_path
        nonsymlinked_dir = self._delete_links_and_find_target_dir(server_path, link_func)
        os.rmdir(nonsymlinked_dir)

    def _delete_links_and_find_target_dir(self, server_path, link_func):
        """Delete symlinks and return the nonsymlinked directory path.

        :param str server_path: file path based on server
        :param callable link_func: callable that returns possible links
            given a server_path

        :returns: the final, non-symlinked target
        :rtype: str

        """
        dir_path = link_func(server_path)

        # does an appropriate directory link to me? if so, make sure that's gone
        reused_servers = {}
        for k in constants.LE_REUSE_SERVERS:
            reused_servers[constants.LE_REUSE_SERVERS[k]] = k

        # is there a next one up?
        possible_next_link = True
        while possible_next_link:
            possible_next_link = False
            if server_path in reused_servers:
                next_server_path = reused_servers[server_path]
                next_dir_path = link_func(next_server_path)
                if os.path.islink(next_dir_path) and os.readlink(next_dir_path) == dir_path:
                    possible_next_link = True
                    server_path = next_server_path
                    dir_path = next_dir_path

        # if there's not a next one up to delete, then delete me
        # and whatever I link to
        while os.path.islink(dir_path):
            target = os.readlink(dir_path)
            os.unlink(dir_path)
            dir_path = target

        return dir_path

    def _save(self, account, acme, regr_only):
        account_dir_path = self._account_dir_path(account.id)
        util.make_or_verify_dir(account_dir_path, 0o700, self.config.strict_permissions)
        try:
            with open(self._regr_path(account_dir_path), "w") as regr_file:
                regr = account.regr
                # If we have a value for new-authz, save it for forwards
                # compatibility with older versions of Certbot. If we don't
                # have a value for new-authz, this is an ACMEv2 directory where
                # an older version of Certbot won't work anyway.
                if hasattr(acme.directory, "new-authz"):
                    regr = RegistrationResourceWithNewAuthzrURI(
                        new_authzr_uri=acme.directory.new_authz,
                        body={},
                        uri=regr.uri)
                else:
                    regr = messages.RegistrationResource(
                        body={},
                        uri=regr.uri)
                regr_file.write(regr.json_dumps())
            if not regr_only:
                with util.safe_open(self._key_path(account_dir_path),
                                    "w", chmod=0o400) as key_file:
                    key_file.write(account.key.json_dumps())
                with open(self._metadata_path(
                        account_dir_path), "w") as metadata_file:
                    metadata_file.write(account.meta.json_dumps())
        except IOError as error:
            raise errors.AccountStorageError(error)


================================================
FILE: certbot/_internal/auth_handler.py
================================================
"""ACME AuthHandler."""
import datetime
import logging
import time

import zope.component

from acme import challenges
from acme import errors as acme_errors
from acme import messages
from acme.magic_typing import Dict
from acme.magic_typing import List
from acme.magic_typing import Tuple
from certbot import achallenges
from certbot import errors
from certbot import interfaces
from certbot._internal import error_handler

logger = logging.getLogger(__name__)


class AuthHandler(object):
    """ACME Authorization Handler for a client.

    :ivar auth: Authenticator capable of solving
        :class:`~acme.challenges.Challenge` types
    :type auth: :class:`certbot.interfaces.IAuthenticator`

    :ivar acme.client.BackwardsCompatibleClientV2 acme_client: ACME client API.

    :ivar account: Client's Account
    :type account: :class:`certbot._internal.account.Account`

    :ivar list pref_challs: sorted user specified preferred challenges
        type strings with the most preferred challenge listed first

    """
    def __init__(self, auth, acme_client, account, pref_challs):
        self.auth = auth
        self.acme = acme_client

        self.account = account
        self.pref_challs = pref_challs

    def handle_authorizations(self, orderr, best_effort=False, max_retries=30):
        """
        Retrieve all authorizations, perform all challenges required to validate
        these authorizations, then poll and wait for the authorization to be checked.
        :param acme.messages.OrderResource orderr: must have authorizations filled in
        :param bool best_effort: if True, not all authorizations need to be validated (eg. renew)
        :param int max_retries: maximum number of retries to poll authorizations
        :returns: list of all validated authorizations
        :rtype: List

        :raises .AuthorizationError: If unable to retrieve all authorizations
        """
        authzrs = orderr.authorizations[:]
        if not authzrs:
            raise errors.AuthorizationError('No authorization to handle.')

        # Retrieve challenges that need to be performed to validate authorizations.
        achalls = self._choose_challenges(authzrs)
        if not achalls:
            return authzrs

        # Starting now, challenges will be cleaned at the end no matter what.
        with error_handler.ExitHandler(self._cleanup_challenges, achalls):
            # To begin, let's ask the authenticator plugin to perform all challenges.
            try:
                resps = self.auth.perform(achalls)

                # If debug is on, wait for user input before starting the verification process.
                logger.info('Waiting for verification...')
                config = zope.component.getUtility(interfaces.IConfig)
                if config.debug_challenges:
                    notify = zope.component.getUtility(interfaces.IDisplay).notification
                    notify('Challenges loaded. Press continue to submit to CA. '
                           'Pass "-v" for more info about challenges.', pause=True)
            except errors.AuthorizationError as error:
                logger.critical('Failure in setting up challenges.')
                logger.info('Attempting to clean up outstanding challenges...')
                raise error
            # All challenges should have been processed by the authenticator.
            assert len(resps) == len(achalls), 'Some challenges have not been performed.'

            # Inform the ACME CA server that challenges are available for validation.
            for achall, resp in zip(achalls, resps):
                self.acme.answer_challenge(achall.challb, resp)

            # Wait for authorizations to be checked.
            self._poll_authorizations(authzrs, max_retries, best_effort)

            # Keep validated authorizations only. If there is none, no certificate can be issued.
            authzrs_validated = [authzr for authzr in authzrs
                                 if authzr.body.status == messages.STATUS_VALID]
            if not authzrs_validated:
                raise errors.AuthorizationError('All challenges have failed.')

            return authzrs_validated

    def deactivate_valid_authorizations(self, orderr):
        # type: (messages.OrderResource) -> Tuple[List, List]
        """
        Deactivate all `valid` authorizations in the order, so that they cannot be re-used
        in subsequent orders.
        :param messages.OrderResource orderr: must have authorizations filled in
        :returns: tuple of list of successfully deactivated authorizations, and
                  list of unsuccessfully deactivated authorizations.
        :rtype: tuple
        """
        to_deactivate = [authzr for authzr in orderr.authorizations
                         if authzr.body.status == messages.STATUS_VALID]
        deactivated = []
        failed = []

        for authzr in to_deactivate:
            try:
                authzr = self.acme.deactivate_authorization(authzr)
                deactivated.append(authzr)
            except acme_errors.Error as e:
                failed.append(authzr)
                logger.debug('Failed to deactivate authorization %s: %s', authzr.uri, e)

        return (deactivated, failed)

    def _poll_authorizations(self, authzrs, max_retries, best_effort):
        """
        Poll the ACME CA server, to wait for confirmation that authorizations have their challenges
        all verified. The poll may occur several times, until all authorizations are checked
        (valid or invalid), or after a maximum of retries.
        """
        authzrs_to_check = {index: (authzr, None)
                            for index, authzr in enumerate(authzrs)}
        authzrs_failed_to_report = []
        # Give an initial second to the ACME CA server to check the authorizations
        sleep_seconds = 1
        for _ in range(max_retries):
            # Wait for appropriate time (from Retry-After, initial wait, or no wait)
            if sleep_seconds > 0:
                time.sleep(sleep_seconds)
            # Poll all updated authorizations.
            authzrs_to_check = {index: self.acme.poll(authzr) for index, (authzr, _)
                                in authzrs_to_check.items()}
            # Update the original list of authzr with the updated authzrs from server.
            for index, (authzr, _) in authzrs_to_check.items():
                authzrs[index] = authzr

            # Gather failed authorizations
            authzrs_failed = [authzr for authzr, _ in authzrs_to_check.values()
                              if authzr.body.status == messages.STATUS_INVALID]
            for authzr_failed in authzrs_failed:
                logger.warning('Challenge failed for domain %s',
                               authzr_failed.body.identifier.value)
            # Accumulating all failed authzrs to build a consolidated report
            # on them at the end of the polling.
            authzrs_failed_to_report.extend(authzrs_failed)

            # Extract out the authorization already checked for next poll iteration.
            # Poll may stop here because there is no pending authorizations anymore.
            authzrs_to_check = {index: (authzr, resp) for index, (authzr, resp)
                                in authzrs_to_check.items()
                                if authzr.body.status == messages.STATUS_PENDING}
            if not authzrs_to_check:
                # Polling process is finished, we can leave the loop
                break

            # Be merciful with the ACME server CA, check the Retry-After header returned,
            # and wait this time before polling again in next loop iteration.
            # From all the pending authorizations, we take the greatest Retry-After value
            # to avoid polling an authorization before its relevant Retry-After value.
            retry_after = max(self.acme.retry_after(resp, 3)
                              for _, resp in authzrs_to_check.values())
            sleep_seconds = (retry_after - datetime.datetime.now()).total_seconds()

        # In case of failed authzrs, create a report to the user.
        if authzrs_failed_to_report:
            _report_failed_authzrs(authzrs_failed_to_report, self.account.key)
            if not best_effort:
                # Without best effort, having failed authzrs is critical and fail the process.
                raise errors.AuthorizationError('Some challenges have failed.')

        if authzrs_to_check:
            # Here authzrs_to_check is still not empty, meaning we exceeded the max polling attempt.
            raise errors.AuthorizationError('All authorizations were not finalized by the CA.')

    def _choose_challenges(self, authzrs):
        """
        Retrieve necessary and pending challenges to satisfy server.
        NB: Necessary and already validated challenges are not retrieved,
        as they can be reused for a certificate issuance.
        """
        pending_authzrs = [authzr for authzr in authzrs
                           if authzr.body.status != messages.STATUS_VALID]
        achalls = []  # type: List[achallenges.AnnotatedChallenge]
        if pending_authzrs:
            logger.info("Performing the following challenges:")
        for authzr in pending_authzrs:
            authzr_challenges = authzr.body.challenges
            if self.acme.acme_version == 1:
                combinations = authzr.body.combinations
            else:
                combinations = tuple((i,) for i in range(len(authzr_challenges)))

            path = gen_challenge_path(
                authzr_challenges,
                self._get_chall_pref(authzr.body.identifier.value),
                combinations)

            achalls.extend(self._challenge_factory(authzr, path))

        return achalls

    def _get_chall_pref(self, domain):
        """Return list of challenge preferences.

        :param str domain: domain for which you are requesting preferences

        """
        chall_prefs = []
        # Make sure to make a copy...
        plugin_pref = self.auth.get_chall_pref(domain)
        if self.pref_challs:
            plugin_pref_types = set(chall.typ for chall in plugin_pref)
            for typ in self.pref_challs:
                if typ in plugin_pref_types:
                    chall_prefs.append(challenges.Challenge.TYPES[typ])
            if chall_prefs:
                return chall_prefs
            raise errors.AuthorizationError(
                "None of the preferred challenges "
                "are supported by the selected plugin")
        chall_prefs.extend(plugin_pref)
        return chall_prefs

    def _cleanup_challenges(self, achalls):
        """Cleanup challenges.

        :param achalls: annotated challenges to cleanup
        :type achalls: `list` of :class:`certbot.achallenges.AnnotatedChallenge`

        """
        logger.info("Cleaning up challenges")
        self.auth.cleanup(achalls)

    def _challenge_factory(self, authzr, path):
        """Construct Namedtuple Challenges

        :param messages.AuthorizationResource authzr: authorization

        :param list path: List of indices from `challenges`.

        :returns: achalls, list of challenge type
            :class:`certbot.achallenges.Indexed`
        :rtype: list

        :raises .errors.Error: if challenge type is not recognized

        """
        achalls = []

        for index in path:
            challb = authzr.body.challenges[index]
            achalls.append(challb_to_achall(
                challb, self.account.key, authzr.body.identifier.value))

        return achalls


def challb_to_achall(challb, account_key, domain):
    """Converts a ChallengeBody object to an AnnotatedChallenge.

    :param .ChallengeBody challb: ChallengeBody
    :param .JWK account_key: Authorized Account Key
    :param str domain: Domain of the challb

    :returns: Appropriate AnnotatedChallenge
    :rtype: :class:`certbot.achallenges.AnnotatedChallenge`

    """
    chall = challb.chall
    logger.info("%s challenge for %s", chall.typ, domain)

    if isinstance(chall, challenges.KeyAuthorizationChallenge):
        return achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=challb, domain=domain, account_key=account_key)
    elif isinstance(chall, challenges.DNS):
        return achallenges.DNS(challb=challb, domain=domain)
    raise errors.Error(
        "Received unsupported challenge of type: {0}".format(chall.typ))


def gen_challenge_path(challbs, preferences, combinations):
    """Generate a plan to get authority over the identity.

    .. todo:: This can be possibly be rewritten to use resolved_combinations.

    :param tuple challbs: A tuple of challenges
        (:class:`acme.messages.Challenge`) from
        :class:`acme.messages.AuthorizationResource` to be
        fulfilled by the client in order to prove possession of the
        identifier.

    :param list preferences: List of challenge preferences for domain
        (:class:`acme.challenges.Challenge` subclasses)

    :param tuple combinations: A collection of sets of challenges from
        :class:`acme.messages.Challenge`, each of which would
        be sufficient to prove possession of the identifier.

    :returns: tuple of indices from ``challenges``.
    :rtype: tuple

    :raises certbot.errors.AuthorizationError: If a
        path cannot be created that satisfies the CA given the preferences and
        combinations.

    """
    if combinations:
        return _find_smart_path(challbs, preferences, combinations)
    return _find_dumb_path(challbs, preferences)


def _find_smart_path(challbs, preferences, combinations):
    """Find challenge path with server hints.

    Can be called if combinations is included. Function uses a simple
    ranking system to choose the combo with the lowest cost.

    """
    chall_cost = {}
    max_cost = 1
    for i, chall_cls in enumerate(preferences):
        chall_cost[chall_cls] = i
        max_cost += i

    # max_cost is now equal to sum(indices) + 1

    best_combo = None
    # Set above completing all of the available challenges
    best_combo_cost = max_cost

    combo_total = 0
    for combo in combinations:
        for challenge_index in combo:
            combo_total += chall_cost.get(challbs[
                challenge_index].chall.__class__, max_cost)

        if combo_total < best_combo_cost:
            best_combo = combo
            best_combo_cost = combo_total

        combo_total = 0

    if not best_combo:
        _report_no_chall_path(challbs)

    return best_combo


def _find_dumb_path(challbs, preferences):
    """Find challenge path without server hints.

    Should be called if the combinations hint is not included by the
    server. This function either returns a path containing all
    challenges provided by the CA or raises an exception.

    """
    path = []
    for i, challb in enumerate(challbs):
        # supported is set to True if the challenge type is supported
        supported = next((True for pref_c in preferences
                          if isinstance(challb.chall, pref_c)), False)
        if supported:
            path.append(i)
        else:
            _report_no_chall_path(challbs)

    return path


def _report_no_chall_path(challbs):
    """Logs and raises an error that no satisfiable chall path exists.

    :param challbs: challenges from the authorization that can't be satisfied

    """
    msg = ("Client with the currently selected authenticator does not support "
           "any combination of challenges that will satisfy the CA.")
    if len(challbs) == 1 and isinstance(challbs[0].chall, challenges.DNS01):
        msg += (
            " You may need to use an authenticator "
            "plugin that can do challenges over DNS.")
    logger.critical(msg)
    raise errors.AuthorizationError(msg)


_ERROR_HELP_COMMON = (
    "To fix these errors, please make sure that your domain name was entered "
    "correctly and the DNS A/AAAA record(s) for that domain contain(s) the "
    "right IP address.")


_ERROR_HELP = {
    "connection":
        _ERROR_HELP_COMMON + " Additionally, please check that your computer "
        "has a publicly routable IP address and that no firewalls are preventing "
        "the server from communicating with the client. If you're using the "
        "webroot plugin, you should also verify that you are serving files "
        "from the webroot path you provided.",
    "dnssec":
        _ERROR_HELP_COMMON + " Additionally, if you have DNSSEC enabled for "
        "your domain, please ensure that the signature is valid.",
    "malformed":
        "To fix these errors, please make sure that you did not provide any "
        "invalid information to the client, and try running Certbot "
        "again.",
    "serverInternal":
        "Unfortunately, an error on the ACME server prevented you from completing "
        "authorization. Please try again later.",
    "tls":
        _ERROR_HELP_COMMON + " Additionally, please check that you have an "
        "up-to-date TLS configuration that allows the server to communicate "
        "with the Certbot client.",
    "unauthorized": _ERROR_HELP_COMMON,
    "unknownHost": _ERROR_HELP_COMMON,
}


def _report_failed_authzrs(failed_authzrs, account_key):
    """Notifies the user about failed authorizations."""
    problems = {}  # type: Dict[str, List[achallenges.AnnotatedChallenge]]
    failed_achalls = [challb_to_achall(challb, account_key, authzr.body.identifier.value)
                      for authzr in failed_authzrs for challb in authzr.body.challenges
                      if challb.error]

    for achall in failed_achalls:
        problems.setdefault(achall.error.typ, []).append(achall)

    reporter = zope.component.getUtility(interfaces.IReporter)
    for achalls in problems.values():
        reporter.add_message(_generate_failed_chall_msg(achalls), reporter.MEDIUM_PRIORITY)


def _generate_failed_chall_msg(failed_achalls):
    """Creates a user friendly error message about failed challenges.

    :param list failed_achalls: A list of failed
        :class:`certbot.achallenges.AnnotatedChallenge` with the same error
        type.

    :returns: A formatted error message for the client.
    :rtype: str

    """
    error = failed_achalls[0].error
    typ = error.typ
    if messages.is_acme_error(error):
        typ = error.code
    msg = ["The following errors were reported by the server:"]

    for achall in failed_achalls:
        msg.append("\n\nDomain: %s\nType:   %s\nDetail: %s" % (
            achall.domain, typ, achall.error.detail))

    if typ in _ERROR_HELP:
        msg.append("\n\n")
        msg.append(_ERROR_HELP[typ])

    return "".join(msg)


================================================
FILE: certbot/_internal/cert_manager.py
================================================
"""Tools for managing certificates."""
import datetime
import logging
import re
import traceback

import pytz
import zope.component

from acme.magic_typing import List
from certbot import crypto_util
from certbot import errors
from certbot import interfaces
from certbot import ocsp
from certbot import util
from certbot._internal import storage
from certbot.compat import os
from certbot.display import util as display_util

logger = logging.getLogger(__name__)

###################
# Commands
###################

def update_live_symlinks(config):
    """Update the certificate file family symlinks to use archive_dir.

    Use the information in the config file to make symlinks point to
    the correct archive directory.

    .. note:: This assumes that the installation is using a Reverter object.

    :param config: Configuration.
    :type config: :class:`certbot._internal.configuration.NamespaceConfig`

    """
    for renewal_file in storage.renewal_conf_files(config):
        storage.RenewableCert(renewal_file, config, update_symlinks=True)

def rename_lineage(config):
    """Rename the specified lineage to the new name.

    :param config: Configuration.
    :type config: :class:`certbot._internal.configuration.NamespaceConfig`

    """
    disp = zope.component.getUtility(interfaces.IDisplay)

    certname = get_certnames(config, "rename")[0]

    new_certname = config.new_certname
    if not new_certname:
        code, new_certname = disp.input(
            "Enter the new name for certificate {0}".format(certname),
            flag="--updated-cert-name", force_interactive=True)
        if code != display_util.OK or not new_certname:
            raise errors.Error("User ended interaction.")

    lineage = lineage_for_certname(config, certname)
    if not lineage:
        raise errors.ConfigurationError("No existing certificate with name "
            "{0} found.".format(certname))
    storage.rename_renewal_config(certname, new_certname, config)
    disp.notification("Successfully renamed {0} to {1}."
        .format(certname, new_certname), pause=False)

def certificates(config):
    """Display information about certs configured with Certbot

    :param config: Configuration.
    :type config: :class:`certbot._internal.configuration.NamespaceConfig`
    """
    parsed_certs = []
    parse_failures = []
    for renewal_file in storage.renewal_conf_files(config):
        try:
            renewal_candidate = storage.RenewableCert(renewal_file, config)
            crypto_util.verify_renewable_cert(renewal_candidate)
            parsed_certs.append(renewal_candidate)
        except Exception as e:  # pylint: disable=broad-except
            logger.warning("Renewal configuration file %s produced an "
                           "unexpected error: %s. Skipping.", renewal_file, e)
            logger.debug("Traceback was:\n%s", traceback.format_exc())
            parse_failures.append(renewal_file)

    # Describe all the certs
    _describe_certs(config, parsed_certs, parse_failures)

def delete(config):
    """Delete Certbot files associated with a certificate lineage."""
    certnames = get_certnames(config, "delete", allow_multiple=True)
    for certname in certnames:
        storage.delete_files(config, certname)
        disp = zope.component.getUtility(interfaces.IDisplay)
        disp.notification("Deleted all files relating to certificate {0}."
            .format(certname), pause=False)

###################
# Public Helpers
###################

def lineage_for_certname(cli_config, certname):
    """Find a lineage object with name certname."""
    configs_dir = cli_config.renewal_configs_dir
    # Verify the directory is there
    util.make_or_verify_dir(configs_dir, mode=0o755)
    try:
        renewal_file = storage.renewal_file_for_certname(cli_config, certname)
    except errors.CertStorageError:
        return None
    try:
        return storage.RenewableCert(renewal_file, cli_config)
    except (errors.CertStorageError, IOError):
        logger.debug("Renewal conf file %s is broken.", renewal_file)
        logger.debug("Traceback was:\n%s", traceback.format_exc())
        return None

def domains_for_certname(config, certname):
    """Find the domains in the cert with name certname."""
    lineage = lineage_for_certname(config, certname)
    return lineage.names() if lineage else None

def find_duplicative_certs(config, domains):
    """Find existing certs that match the given domain names.

    This function searches for certificates whose domains are equal to
    the `domains` parameter and certificates whose domains are a subset
    of the domains in the `domains` parameter. If multiple certificates
    are found whose names are a subset of `domains`, the one whose names
    are the largest subset of `domains` is returned.

    If multiple certificates' domains are an exact match or equally
    sized subsets, which matching certificates are returned is
    undefined.

    :param config: Configuration.
    :type config: :class:`certbot._internal.configuration.NamespaceConfig`
    :param domains: List of domain names
    :type domains: `list` of `str`

    :returns: lineages representing the identically matching cert and the
        largest subset if they exist
    :rtype: `tuple` of `storage.RenewableCert` or `None`

    """
    def update_certs_for_domain_matches(candidate_lineage, rv):
        """Return cert as identical_names_cert if it matches,
           or subset_names_cert if it matches as subset
        """
        # TODO: Handle these differently depending on whether they are
        #       expired or still valid?
        identical_names_cert, subset_names_cert = rv
        candidate_names = set(candidate_lineage.names())
        if candidate_names == set(domains):
            identical_names_cert = candidate_lineage
        elif candidate_names.issubset(set(domains)):
            # This logic finds and returns the largest subset-names cert
            # in the case where there are several available.
            if subset_names_cert is None:
                subset_names_cert = candidate_lineage
            elif len(candidate_names) > len(subset_names_cert.names()):
                subset_names_cert = candidate_lineage
        return (identical_names_cert, subset_names_cert)

    return _search_lineages(config, update_certs_for_domain_matches, (None, None))

def _archive_files(candidate_lineage, filetype):
    """ In order to match things like:
        /etc/letsencrypt/archive/example.com/chain1.pem.

        Anonymous functions which call this function are eventually passed (in a list) to
        `match_and_check_overlaps` to help specify the acceptable_matches.

        :param `.storage.RenewableCert` candidate_lineage: Lineage whose archive dir is to
            be searched.
        :param str filetype: main file name prefix e.g. "fullchain" or "chain".

        :returns: Files in candidate_lineage's archive dir that match the provided filetype.
        :rtype: list of str or None
    """
    archive_dir = candidate_lineage.archive_dir
    pattern = [os.path.join(archive_dir, f) for f in os.listdir(archive_dir)
                    if re.match("{0}[0-9]*.pem".format(filetype), f)]
    if pattern:
        return pattern
    return None

def _acceptable_matches():
    """ Generates the list that's passed to match_and_check_overlaps. Is its own function to
    make unit testing easier.

    :returns: list of functions
    :rtype: list
    """
    return [lambda x: x.fullchain_path, lambda x: x.cert_path,
            lambda x: _archive_files(x, "cert"), lambda x: _archive_files(x, "fullchain")]

def cert_path_to_lineage(cli_config):
    """ If config.cert_path is defined, try to find an appropriate value for config.certname.

    :param `configuration.NamespaceConfig` cli_config: parsed command line arguments

    :returns: a lineage name
    :rtype: str

    :raises `errors.Error`: If the specified cert path can't be matched to a lineage name.
    :raises `errors.OverlappingMatchFound`: If the matched lineage's archive is shared.
    """
    acceptable_matches = _acceptable_matches()
    match = match_and_check_overlaps(cli_config, acceptable_matches,
            lambda x: cli_config.cert_path[0], lambda x: x.lineagename)
    return match[0]

def match_and_check_overlaps(cli_config, acceptable_matches, match_func, rv_func):
    """ Searches through all lineages for a match, and checks for duplicates.
    If a duplicate is found, an error is raised, as performing operations on lineages
    that have their properties incorrectly duplicated elsewhere is probably a bad idea.

    :param `configuration.NamespaceConfig` cli_config: parsed command line arguments
    :param list acceptable_matches: a list of functions that specify acceptable matches
    :param function match_func: specifies what to match
    :param function rv_func: specifies what to return

    """
    def find_matches(candidate_lineage, return_value, acceptable_matches):
        """Returns a list of matches using _search_lineages."""
        acceptable_matches = [func(candidate_lineage) for func in acceptable_matches]
        acceptable_matches_rv = []  # type: List[str]
        for item in acceptable_matches:
            if isinstance(item, list):
                acceptable_matches_rv += item
            else:
                acceptable_matches_rv.append(item)
        match = match_func(candidate_lineage)
        if match in acceptable_matches_rv:
            return_value.append(rv_func(candidate_lineage))
        return return_value

    matched = _search_lineages(cli_config, find_matches, [], acceptable_matches)
    if not matched:
        raise errors.Error("No match found for cert-path {0}!".format(cli_config.cert_path[0]))
    elif len(matched) > 1:
        raise errors.OverlappingMatchFound()
    return matched


def human_readable_cert_info(config, cert, skip_filter_checks=False):
    """ Returns a human readable description of info about a RenewableCert object"""
    certinfo = []
    checker = ocsp.RevocationChecker()

    if config.certname and cert.lineagename != config.certname and not skip_filter_checks:
        return ""
    if config.domains and not set(config.domains).issubset(cert.names()):
        return ""
    now = pytz.UTC.fromutc(datetime.datetime.utcnow())

    reasons = []
    if cert.is_test_cert:
        reasons.append('TEST_CERT')
    if cert.target_expiry <= now:
        reasons.append('EXPIRED')
    elif checker.ocsp_revoked(cert):
        reasons.append('REVOKED')

    if reasons:
        status = "INVALID: " + ", ".join(reasons)
    else:
        diff = cert.target_expiry - now
        if diff.days == 1:
            status = "VALID: 1 day"
        elif diff.days < 1:
            status = "VALID: {0} hour(s)".format(diff.seconds // 3600)
        else:
            status = "VALID: {0} days".format(diff.days)

    valid_string = "{0} ({1})".format(cert.target_expiry, status)
    certinfo.append("  Certificate Name: {0}\n"
                    "    Domains: {1}\n"
                    "    Expiry Date: {2}\n"
                    "    Certificate Path: {3}\n"
                    "    Private Key Path: {4}".format(
                         cert.lineagename,
                         " ".join(cert.names()),
                         valid_string,
                         cert.fullchain,
                         cert.privkey))
    return "".join(certinfo)

def get_certnames(config, verb, allow_multiple=False, custom_prompt=None):
    """Get certname from flag, interactively, or error out.
    """
    certname = config.certname
    if certname:
        certnames = [certname]
    else:
        disp = zope.component.getUtility(interfaces.IDisplay)
        filenames = storage.renewal_conf_files(config)
        choices = [storage.lineagename_for_filename(name) for name in filenames]
        if not choices:
            raise errors.Error("No existing certificates found.")
        if allow_multiple:
            if not custom_prompt:
                prompt = "Which certificate(s) would you like to {0}?".format(verb)
            else:
                prompt = custom_prompt
            code, certnames = disp.checklist(
                prompt, choices, cli_flag="--cert-name", force_interactive=True)
            if code != display_util.OK:
                raise errors.Error("User ended interaction.")
        else:
            if not custom_prompt:
                prompt = "Which certificate would you like to {0}?".format(verb)
            else:
                prompt = custom_prompt

            code, index = disp.menu(
                prompt, choices, cli_flag="--cert-name", force_interactive=True)

            if code != display_util.OK or index not in range(0, len(choices)):
                raise errors.Error("User ended interaction.")
            certnames = [choices[index]]
    return certnames

###################
# Private Helpers
###################

def _report_lines(msgs):
    """Format a results report for a category of single-line renewal outcomes"""
    return "  " + "\n  ".join(str(msg) for msg in msgs)

def _report_human_readable(config, parsed_certs):
    """Format a results report for a parsed cert"""
    certinfo = []
    for cert in parsed_certs:
        certinfo.append(human_readable_cert_info(config, cert))
    return "\n".join(certinfo)

def _describe_certs(config, parsed_certs, parse_failures):
    """Print information about the certs we know about"""
    out = []  # type: List[str]

    notify = out.append

    if not parsed_certs and not parse_failures:
        notify("No certs found.")
    else:
        if parsed_certs:
            match = "matching " if config.certname or config.domains else ""
            notify("Found the following {0}certs:".format(match))
            notify(_report_human_readable(config, parsed_certs))
        if parse_failures:
            notify("\nThe following renewal configurations "
               "were invalid:")
            notify(_report_lines(parse_failures))

    disp = zope.component.getUtility(interfaces.IDisplay)
    disp.notification("\n".join(out), pause=False, wrap=False)

def _search_lineages(cli_config, func, initial_rv, *args):
    """Iterate func over unbroken lineages, allowing custom return conditions.

    Allows flexible customization of return values, including multiple
    return values and complex checks.

    :param `configuration.NamespaceConfig` cli_config: parsed command line arguments
    :param function func: function used while searching over lineages
    :param initial_rv: initial return value of the function (any type)

    :returns: Whatever was specified by `func` if a match is found.
    """
    configs_dir = cli_config.renewal_configs_dir
    # Verify the directory is there
    util.make_or_verify_dir(configs_dir, mode=0o755)

    rv = initial_rv
    for renewal_file in storage.renewal_conf_files(cli_config):
        try:
            candidate_lineage = storage.RenewableCert(renewal_file, cli_config)
        except (errors.CertStorageError, IOError):
            logger.debug("Renewal conf file %s is broken. Skipping.", renewal_file)
            logger.debug("Traceback was:\n%s", traceback.format_exc())
            continue
        rv = func(candidate_lineage, rv, *args)
    return rv


================================================
FILE: certbot/_internal/cli/__init__.py
================================================
"""Certbot command line argument & config processing."""
# pylint: disable=too-many-lines
from __future__ import print_function
import logging
import logging.handlers
import argparse
import sys
import certbot._internal.plugins.selection as plugin_selection
from certbot._internal.plugins import disco as plugins_disco

from acme.magic_typing import Optional

# pylint: disable=ungrouped-imports
import certbot
from certbot._internal import constants

import certbot.plugins.enhancements as enhancements


from certbot._internal.cli.cli_constants import (
    LEAUTO,
    old_path_fragment,
    new_path_prefix,
    cli_command,
    SHORT_USAGE,
    COMMAND_OVERVIEW,
    HELP_AND_VERSION_USAGE,
    ARGPARSE_PARAMS_TO_REMOVE,
    EXIT_ACTIONS,
    ZERO_ARG_ACTIONS,
    VAR_MODIFIERS
)

from certbot._internal.cli.cli_utils import (
    _Default,
    read_file,
    flag_default,
    config_help,
    HelpfulArgumentGroup,
    CustomHelpFormatter,
    _DomainsAction,
    add_domains,
    CaseInsensitiveList,
    _user_agent_comment_type,
    _EncodeReasonAction,
    parse_preferred_challenges,
    _PrefChallAction,
    _DeployHookAction,
    _RenewHookAction,
    nonnegative_int
)

# These imports depend on cli_constants and cli_utils.
from certbot._internal.cli.report_config_interaction import report_config_interaction
from certbot._internal.cli.verb_help import VERB_HELP, VERB_HELP_MAP
from certbot._internal.cli.group_adder import _add_all_groups
from certbot._internal.cli.subparsers import _create_subparsers
from certbot._internal.cli.paths_parser import _paths_parser
from certbot._internal.cli.plugins_parsing import _plugins_parsing

# These imports depend on some or all of the submodules for cli.
from certbot._internal.cli.helpful import HelpfulArgumentParser
# pylint: enable=ungrouped-imports


logger = logging.getLogger(__name__)


# Global, to save us from a lot of argument passing within the scope of this module
helpful_parser = None  # type: Optional[HelpfulArgumentParser]


def prepare_and_parse_args(plugins, args, detect_defaults=False):
    """Returns parsed command line arguments.

    :param .PluginsRegistry plugins: available plugins
    :param list args: command line arguments with the program name removed

    :returns: parsed command line arguments
    :rtype: argparse.Namespace

    """

    helpful = HelpfulArgumentParser(args, plugins, detect_defaults)
    _add_all_groups(helpful)

    # --help is automatically provided by argparse
    helpful.add(
        None, "-v", "--verbose", dest="verbose_count", action="count",
        default=flag_default("verbose_count"), help="This flag can be used "
        "multiple times to incrementally increase the verbosity of output, "
        "e.g. -vvv.")
    helpful.add(
        None, "-t", "--text", dest="text_mode", action="store_true",
        default=flag_default("text_mode"), help=argparse.SUPPRESS)
    helpful.add(
        None, "--max-log-backups", type=nonnegative_int,
        default=flag_default("max_log_backups"),
        help="Specifies the maximum number of backup logs that should "
             "be kept by Certbot's built in log rotation. Setting this "
             "flag to 0 disables log rotation entirely, causing "
             "Certbot to always append to the same log file.")
    helpful.add(
        [None, "automation", "run", "certonly", "enhance"],
        "-n", "--non-interactive", "--noninteractive",
        dest="noninteractive_mode", action="store_true",
        default=flag_default("noninteractive_mode"),
        help="Run without ever asking for user input. This may require "
              "additional command line flags; the client will try to explain "
              "which ones are required if it finds one missing")
    helpful.add(
        [None, "register", "run", "certonly", "enhance"],
        constants.FORCE_INTERACTIVE_FLAG, action="store_true",
        default=flag_default("force_interactive"),
        help="Force Certbot to be interactive even if it detects it's not "
             "being run in a terminal. This flag cannot be used with the "
             "renew subcommand.")
    helpful.add(
        [None, "run", "certonly", "certificates", "enhance"],
        "-d", "--domains", "--domain", dest="domains",
        metavar="DOMAIN", action=_DomainsAction,
        default=flag_default("domains"),
        help="Domain names to apply. For multiple domains you can use "
             "multiple -d flags or enter a comma separated list of domains "
             "as a parameter. The first domain provided will be the "
             "subject CN of the certificate, and all domains will be "
             "Subject Alternative Names on the certificate. "
             "The first domain will also be used in "
             "some software user interfaces and as the file paths for the "
             "certificate and related material unless otherwise "
             "specified or you already have a certificate with the same "
             "name. In the case of a name collision it will append a number "
             "like 0001 to the file path name. (default: Ask)")
    helpful.add(
        [None, "run", "certonly", "register"],
        "--eab-kid", dest="eab_kid",
        metavar="EAB_KID",
        help="Key Identifier for External Account Binding"
    )
    helpful.add(
        [None, "run", "certonly", "register"],
        "--eab-hmac-key", dest="eab_hmac_key",
        metavar="EAB_HMAC_KEY",
        help="HMAC key for External Account Binding"
    )
    helpful.add(
        [None, "run", "certonly", "manage", "delete", "certificates",
         "renew", "enhance"], "--cert-name", dest="certname",
        metavar="CERTNAME", default=flag_default("certname"),
        help="Certificate name to apply. This name is used by Certbot for housekeeping "
             "and in file paths; it doesn't affect the content of the certificate itself. "
             "To see certificate names, run 'certbot certificates'. "
             "When creating a new certificate, specifies the new certificate's name. "
             "(default: the first provided domain or the name of an existing "
             "certificate on your system for the same domains)")
    helpful.add(
        [None, "testing", "renew", "certonly"],
        "--dry-run", action="store_true", dest="dry_run",
        default=flag_default("dry_run"),
        help="Perform a test run of the client, obtaining test (invalid) certificates"
             " but not saving them to disk. This can currently only be used"
             " with the 'certonly' and 'renew' subcommands. \nNote: Although --dry-run"
             " tries to avoid making any persistent changes on a system, it "
             " is not completely side-effect free: if used with webserver authenticator plugins"
             " like apache and nginx, it makes and then reverts temporary config changes"
             " in order to obtain test certificates, and reloads webservers to deploy and then"
             " roll back those changes.  It also calls --pre-hook and --post-hook commands"
             " if they are defined because they may be necessary to accurately simulate"
             " renewal. --deploy-hook commands are not called.")
    helpful.add(
        ["register", "automation"], "--register-unsafely-without-email", action="store_true",
        default=flag_default("register_unsafely_without_email"),
        help="Specifying this flag enables registering an account with no "
             "email address. This is strongly discouraged, because in the "
             "event of key loss or account compromise you will irrevocably "
             "lose access to your account. You will also be unable to receive "
             "notice about impending expiration or revocation of your "
             "certificates. Updates to the Subscriber Agreement will still "
             "affect you, and will be effective 14 days after posting an "
             "update to the web site.")
    helpful.add(
        ["register", "update_account", "unregister", "automation"], "-m", "--email",
        default=flag_default("email"),
        help=config_help("email"))
    helpful.add(["register", "update_account", "automation"], "--eff-email", action="store_true",
                default=flag_default("eff_email"), dest="eff_email",
                help="Share your e-mail address with EFF")
    helpful.add(["register", "update_account", "automation"], "--no-eff-email",
                action="store_false", default=flag_default("eff_email"), dest="eff_email",
                help="Don't share your e-mail address with EFF")
    helpful.add(
        ["automation", "certonly", "run"],
        "--keep-until-expiring", "--keep", "--reinstall",
        dest="reinstall", action="store_true", default=flag_default("reinstall"),
        help="If the requested certificate matches an existing certificate, always keep the "
             "existing one until it is due for renewal (for the "
             "'run' subcommand this means reinstall the existing certificate). (default: Ask)")
    helpful.add(
        "automation", "--expand", action="store_true", default=flag_default("expand"),
        help="If an existing certificate is a strict subset of the requested names, "
             "always expand and replace it with the additional names. (default: Ask)")
    helpful.add(
        "automation", "--version", action="version",
        version="%(prog)s {0}".format(certbot.__version__),
        help="show program's version number and exit")
    helpful.add(
        ["automation", "renew"],
        "--force-renewal", "--renew-by-default", dest="renew_by_default",
        action="store_true", default=flag_default("renew_by_default"),
        help="If a certificate "
             "already exists for the requested domains, renew it now, "
             "regardless of whether it is near expiry. (Often "
             "--keep-until-expiring is more appropriate). Also implies "
             "--expand.")
    helpful.add(
        "automation", "--renew-with-new-domains", dest="renew_with_new_domains",
        action="store_true", default=flag_default("renew_with_new_domains"),
        help="If a "
             "certificate already exists for the requested certificate name "
             "but does not match the requested domains, renew it now, "
             "regardless of whether it is near expiry.")
    helpful.add(
        "automation", "--reuse-key", dest="reuse_key",
        action="store_true", default=flag_default("reuse_key"),
        help="When renewing, use the same private key as the existing "
             "certificate.")

    helpful.add(
        ["automation", "renew", "certonly"],
        "--allow-subset-of-names", action="store_true",
        default=flag_default("allow_subset_of_names"),
        help="When performing domain validation, do not consider it a failure "
             "if authorizations can not be obtained for a strict subset of "
             "the requested domains. This may be useful for allowing renewals for "
             "multiple domains to succeed even if some domains no longer point "
             "at this system. This option cannot be used with --csr.")
    helpful.add(
        "automation", "--agree-tos", dest="tos", action="store_true",
        default=flag_default("tos"),
        help="Agree to the ACME Subscriber Agreement (default: Ask)")
    helpful.add(
        ["unregister", "automation"], "--account", metavar="ACCOUNT_ID",
        default=flag_default("account"),
        help="Account ID to use")
    helpful.add(
        "automation", "--duplicate", dest="duplicate", action="store_true",
        default=flag_default("duplicate"),
        help="Allow making a certificate lineage that duplicates an existing one "
             "(both can be renewed in parallel)")
    helpful.add(
        "automation", "--os-packages-only", action="store_true",
        default=flag_default("os_packages_only"),
        help="(certbot-auto only) install OS package dependencies and then stop")
    helpful.add(
        "automation", "--no-self-upgrade", action="store_true",
        default=flag_default("no_self_upgrade"),
        help="(certbot-auto only) prevent the certbot-auto script from"
             " upgrading itself to newer released versions (default: Upgrade"
             " automatically)")
    helpful.add(
        "automation", "--no-bootstrap", action="store_true",
        default=flag_default("no_bootstrap"),
        help="(certbot-auto only) prevent the certbot-auto script from"
             " installing OS-level dependencies (default: Prompt to install "
             " OS-wide dependencies, but exit if the user says 'No')")
    helpful.add(
        "automation", "--no-permissions-check", action="store_true",
        default=flag_default("no_permissions_check"),
        help="(certbot-auto only) skip the check on the file system"
             " permissions of the certbot-auto script")
    helpful.add(
        ["automation", "renew", "certonly", "run"],
        "-q", "--quiet", dest="quiet", action="store_true",
        default=flag_default("quiet"),
        help="Silence all output except errors. Useful for automation via cron."
             " Implies --non-interactive.")
    # overwrites server, handled in HelpfulArgumentParser.parse_args()
    helpful.add(["testing", "revoke", "run"], "--test-cert", "--staging",
        dest="staging", action="store_true", default=flag_default("staging"),
        help="Use the staging server to obtain or revoke test (invalid) certificates; equivalent"
             " to --server " + constants.STAGING_URI)
    helpful.add(
        "testing", "--debug", action="store_true", default=flag_default("debug"),
        help="Show tracebacks in case of errors, and allow certbot-auto "
             "execution on experimental platforms")
    helpful.add(
        [None, "certonly", "run"], "--debug-challenges", action="store_true",
        default=flag_default("debug_challenges"),
        help="After setting up challenges, wait for user input before "
             "submitting to CA")
    helpful.add(
        "testing", "--no-verify-ssl", action="store_true",
        help=config_help("no_verify_ssl"),
        default=flag_default("no_verify_ssl"))
    helpful.add(
        ["testing", "standalone", "manual"], "--http-01-port", type=int,
        dest="http01_port",
        default=flag_default("http01_port"), help=config_help("http01_port"))
    helpful.add(
        ["testing", "standalone"], "--http-01-address",
        dest="http01_address",
        default=flag_default("http01_address"), help=config_help("http01_address"))
    helpful.add(
        ["testing", "nginx"], "--https-port", type=int,
        default=flag_default("https_port"),
        help=config_help("https_port"))
    helpful.add(
        "testing", "--break-my-certs", action="store_true",
        default=flag_default("break_my_certs"),
        help="Be willing to replace or renew valid certificates with invalid "
             "(testing/staging) certificates")
    helpful.add(
        "security", "--rsa-key-size", type=int, metavar="N",
        default=flag_default("rsa_key_size"), help=config_help("rsa_key_size"))
    helpful.add(
        "security", "--must-staple", action="store_true",
        dest="must_staple", default=flag_default("must_staple"),
        help=config_help("must_staple"))
    helpful.add(
        ["security", "enhance"],
        "--redirect", action="store_true", dest="redirect",
        default=flag_default("redirect"),
        help="Automatically redirect all HTTP traffic to HTTPS for the newly "
             "authenticated vhost. (default: Ask)")
    helpful.add(
        "security", "--no-redirect", action="store_false", dest="redirect",
        default=flag_default("redirect"),
        help="Do not automatically redirect all HTTP traffic to HTTPS for the newly "
             "authenticated vhost. (default: Ask)")
    helpful.add(
        ["security", "enhance"],
        "--hsts", action="store_true", dest="hsts", default=flag_default("hsts"),
        help="Add the Strict-Transport-Security header to every HTTP response."
             " Forcing browser to always use SSL for the domain."
             " Defends against SSL Stripping.")
    helpful.add(
        "security", "--no-hsts", action="store_false", dest="hsts",
        default=flag_default("hsts"), help=argparse.SUPPRESS)
    helpful.add(
        ["security", "enhance"],
        "--uir", action="store_true", dest="uir", default=flag_default("uir"),
        help='Add the "Content-Security-Policy: upgrade-insecure-requests"'
             ' header to every HTTP response. Forcing the browser to use'
             ' https:// for every http:// resource.')
    helpful.add(
        "security", "--no-uir", action="store_false", dest="uir", default=flag_default("uir"),
        help=argparse.SUPPRESS)
    helpful.add(
        "security", "--staple-ocsp", action="store_true", dest="staple",
        default=flag_default("staple"),
        help="Enables OCSP Stapling. A valid OCSP response is stapled to"
        " the certificate that the server offers during TLS.")
    helpful.add(
        "security", "--no-staple-ocsp", action="store_false", dest="staple",
        default=flag_default("staple"), help=argparse.SUPPRESS)
    helpful.add(
        "security", "--strict-permissions", action="store_true",
        default=flag_default("strict_permissions"),
        help="Require that all configuration files are owned by the current "
             "user; only needed if your config is somewhere unsafe like /tmp/")
    helpful.add(
        ["manual", "standalone", "certonly", "renew"],
        "--preferred-challenges", dest="pref_challs",
        action=_PrefChallAction, default=flag_default("pref_challs"),
        help='A sorted, comma delimited list of the preferred challenge to '
             'use during authorization with the most preferred challenge '
             'listed first (Eg, "dns" or "http,dns"). '
             'Not all plugins support all challenges. See '
             'https://certbot.eff.org/docs/using.html#plugins for details. '
             'ACME Challenges are versioned, but if you pick "http" rather '
             'than "http-01", Certbot will select the latest version '
             'automatically.')
    helpful.add(
        "renew", "--pre-hook",
        help="Command to be run in a shell before obtaining any certificates."
        " Intended primarily for renewal, where it can be used to temporarily"
        " shut down a webserver that might conflict with the standalone"
        " plugin. This will only be called if a certificate is actually to be"
        " obtained/renewed. When renewing several certificates that have"
        " identical pre-hooks, only the first will be executed.")
    helpful.add(
        "renew", "--post-hook",
        help="Command to be run in a shell after attempting to obtain/renew"
        " certificates. Can be used to deploy renewed certificates, or to"
        " restart any servers that were stopped by --pre-hook. This is only"
        " run if an attempt was made to obtain/renew a certificate. If"
        " multiple renewed certificates have identical post-hooks, only"
        " one will be run.")
    helpful.add("renew", "--renew-hook",
                action=_RenewHookAction, help=argparse.SUPPRESS)
    helpful.add(
        "renew", "--no-random-sleep-on-renew", action="store_false",
        default=flag_default("random_sleep_on_renew"), dest="random_sleep_on_renew",
        help=argparse.SUPPRESS)
    helpful.add(
        "renew", "--deploy-hook", action=_DeployHookAction,
        help='Command to be run in a shell once for each successfully'
        ' issued certificate. For this command, the shell variable'
        ' $RENEWED_LINEAGE will point to the config live subdirectory'
        ' (for example, "/etc/letsencrypt/live/example.com") containing'
        ' the new certificates and keys; the shell variable'
        ' $RENEWED_DOMAINS will contain a space-delimited list of'
        ' renewed certificate domains (for example, "example.com'
        ' www.example.com"')
    helpful.add(
        "renew", "--disable-hook-validation",
        action="store_false", dest="validate_hooks",
        default=flag_default("validate_hooks"),
        help="Ordinarily the commands specified for"
        " --pre-hook/--post-hook/--deploy-hook will be checked for"
        " validity, to see if the programs being run are in the $PATH,"
        " so that mistakes can be caught early, even when the hooks"
        " aren't being run just yet. The validation is rather"
        " simplistic and fails if you use more advanced shell"
        " constructs, so you can use this switch to disable it."
        " (default: False)")
    helpful.add(
        "renew", "--no-directory-hooks", action="store_false",
        default=flag_default("directory_hooks"), dest="directory_hooks",
        help="Disable running executables found in Certbot's hook directories"
        " during renewal. (default: False)")
    helpful.add(
        "renew", "--disable-renew-updates", action="store_true",
        default=flag_default("disable_renew_updates"), dest="disable_renew_updates",
        help="Disable automatic updates to your server configuration that"
        " would otherwise be done by the selected installer plugin, and triggered"
        " when the user executes \"certbot renew\", regardless of if the certificate"
        " is renewed. This setting does not apply to important TLS configuration"
        " updates.")
    helpful.add(
        "renew", "--no-autorenew", action="store_false",
        default=flag_default("autorenew"), dest="autorenew",
        help="Disable auto renewal of certificates.")

    # Populate the command line parameters for new style enhancements
    enhancements.populate_cli(helpful.add)

    _create_subparsers(helpful)
    _paths_parser(helpful)
    # _plugins_parsing should be the last thing to act upon the main
    # parser (--help should display plugin-specific options last)
    _plugins_parsing(helpful, plugins)

    if not detect_defaults:
        global helpful_parser # pylint: disable=global-statement
        helpful_parser = helpful
    return helpful.parse_args()


def set_by_cli(var):
    """
    Return True if a particular config variable has been set by the user
    (CLI or config file) including if the user explicitly set it to the
    default.  Returns False if the variable was assigned a default value.
    """
    detector = set_by_cli.detector  # type: ignore
    if detector is None and helpful_parser is not None:
        # Setup on first run: `detector` is a weird version of config in which
        # the default value of every attribute is wrangled to be boolean-false
        plugins = plugins_disco.PluginsRegistry.find_all()
        # reconstructed_args == sys.argv[1:], or whatever was passed to main()
        reconstructed_args = helpful_parser.args + [helpful_parser.verb]
        detector = set_by_cli.detector = prepare_and_parse_args(  # type: ignore
            plugins, reconstructed_args, detect_defaults=True)
        # propagate plugin requests: eg --standalone modifies config.authenticator
        detector.authenticator, detector.installer = (  # type: ignore
            plugin_selection.cli_plugin_requests(detector))

    if not isinstance(getattr(detector, var), _Default):
        logger.debug("Var %s=%s (set by user).", var, getattr(detector, var))
        return True

    for modifier in VAR_MODIFIERS.get(var, []):
        if set_by_cli(modifier):
            logger.debug("Var %s=%s (set by user).",
                var, VAR_MODIFIERS.get(var, []))
            return True

    return False


# static housekeeping var
# functions attributed are not supported by mypy
# https://github.com/python/mypy/issues/2087
set_by_cli.detector = None  # type: ignore


def has_default_value(option, value):
    """Does option have the default value?

    If the default value of option is not known, False is returned.

    :param str option: configuration variable being considered
    :param value: value of the configuration variable named option

    :returns: True if option has the default value, otherwise, False
    :rtype: bool

    """
    if helpful_parser is not None:
        return (option in helpful_parser.defaults and
                helpful_parser.defaults[option] == value)
    return False


def option_was_set(option, value):
    """Was option set by the user or does it differ from the default?

    :param str option: configuration variable being considered
    :param value: value of the configuration variable named option

    :returns: True if the option was set, otherwise, False
    :rtype: bool

    """
    return set_by_cli(option) or not has_default_value(option, value)


def argparse_type(variable):
    """Return our argparse type function for a config variable (default: str)"""
    # pylint: disable=protected-access
    if helpful_parser is not None:
        for action in helpful_parser.parser._actions:
            if action.type is not None and action.dest == variable:
                return action.type
    return str


================================================
FILE: certbot/_internal/cli/cli_constants.py
================================================
"""Certbot command line constants"""
import sys

from certbot.compat import os

# For help strings, figure out how the user ran us.
# When invoked from letsencrypt-auto, sys.argv[0] is something like:
# "/home/user/.local/share/certbot/bin/certbot"
# Note that this won't work if the user set VENV_PATH or XDG_DATA_HOME before
# running letsencrypt-auto (and sudo stops us from seeing if they did), so it
# should only be used for purposes where inability to detect letsencrypt-auto
# fails safely

LEAUTO = "letsencrypt-auto"
if "CERTBOT_AUTO" in os.environ:
    # if we're here, this is probably going to be certbot-auto, unless the
    # user saved the script under a different name
    LEAUTO = os.path.basename(os.environ["CERTBOT_AUTO"])

old_path_fragment = os.path.join(".local", "share", "letsencrypt")
new_path_prefix = os.path.abspath(os.path.join(os.sep, "opt",
                                               "eff.org", "certbot", "venv"))
if old_path_fragment in sys.argv[0] or sys.argv[0].startswith(new_path_prefix):
    cli_command = LEAUTO
else:
    cli_command = "certbot"


# Argparse's help formatting has a lot of unhelpful peculiarities, so we want
# to replace as much of it as we can...

# This is the stub to include in help generated by argparse
SHORT_USAGE = """
  {0} [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...

Certbot can obtain and install HTTPS/TLS/SSL certificates.  By default,
it will attempt to use a webserver both for obtaining and installing the
certificate. """.format(cli_command)

# This section is used for --help and --help all ; it needs information
# about installed plugins to be fully formatted
COMMAND_OVERVIEW = """The most common SUBCOMMANDS and flags are:

obtain, install, and renew certificates:
    (default) run   Obtain & install a certificate in your current webserver
    certonly        Obtain or renew a certificate, but do not install it
    renew           Renew all previously obtained certificates that are near expiry
    enhance         Add security enhancements to your existing configuration
   -d DOMAINS       Comma-separated list of domains to obtain a certificate for

  %s
  --standalone      Run a standalone webserver for authentication
  %s
  --webroot         Place files in a server's webroot folder for authentication
  --manual          Obtain certificates interactively, or using shell script hooks

   -n               Run non-interactively
  --test-cert       Obtain a test certificate from a staging server
  --dry-run         Test "renew" or "certonly" without saving any certificates to disk

manage certificates:
    certificates    Display information about certificates you have from Certbot
    revoke          Revoke a certificate (supply --cert-name or --cert-path)
    delete          Delete a certificate (supply --cert-name)

manage your account:
    register        Create an ACME account
    unregister      Deactivate an ACME account
    update_account  Update an ACME account
  --agree-tos       Agree to the ACME server's Subscriber Agreement
   -m EMAIL         Email address for important account notifications
"""

# This is the short help for certbot --help, where we disable argparse
# altogether
HELP_AND_VERSION_USAGE = """
More detailed help:

  -h, --help [TOPIC]    print this message, or detailed help on a topic;
                        the available TOPICS are:

   all, automation, commands, paths, security, testing, or any of the
   subcommands or plugins (certonly, renew, install, register, nginx,
   apache, standalone, webroot, etc.)
  -h all                print a detailed help page including all topics
  --version             print the version number
"""

# These argparse parameters should be removed when detecting defaults.
ARGPARSE_PARAMS_TO_REMOVE = ("const", "nargs", "type",)


# These sets are used when to help detect options set by the user.
EXIT_ACTIONS = set(("help", "version",))


ZERO_ARG_ACTIONS = set(("store_const", "store_true",
                        "store_false", "append_const", "count",))


# Maps a config option to a set of config options that may have modified it.
# This dictionary is used recursively, so if A modifies B and B modifies C,
# it is determined that C was modified by the user if A was modified.
VAR_MODIFIERS = {"account": set(("server",)),
                 "renew_hook": set(("deploy_hook",)),
                 "server": set(("dry_run", "staging",)),
                 "webroot_map": set(("webroot_path",))}


================================================
FILE: certbot/_internal/cli/cli_utils.py
================================================
"""Certbot command line util function"""
import argparse
import copy

import zope.interface.interface  # pylint: disable=unused-import

from acme import challenges
from certbot import interfaces
from certbot import util
from certbot import errors
from certbot.compat import os
from certbot._internal import constants


class _Default(object):
    """A class to use as a default to detect if a value is set by a user"""

    def __bool__(self):
        return False

    def __eq__(self, other):
        return isinstance(other, _Default)

    def __hash__(self):
        return id(_Default)

    def __nonzero__(self):
        return self.__bool__()


def read_file(filename, mode="rb"):
    """Returns the given file's contents.

    :param str filename: path to file
    :param str mode: open mode (see `open`)

    :returns: absolute path of filename and its contents
    :rtype: tuple

    :raises argparse.ArgumentTypeError: File does not exist or is not readable.

    """
    try:
        filename = os.path.abspath(filename)
        with open(filename, mode) as the_file:
            contents = the_file.read()
        return filename, contents
    except IOError as exc:
        raise argparse.ArgumentTypeError(exc.strerror)


def flag_default(name):
    """Default value for CLI flag."""
    # XXX: this is an internal housekeeping notion of defaults before
    # argparse has been set up; it is not accurate for all flags.  Call it
    # with caution.  Plugin defaults are missing, and some things are using
    # defaults defined in this file, not in constants.py :(
    return copy.deepcopy(constants.CLI_DEFAULTS[name])


def config_help(name, hidden=False):
    """Extract the help message for an `.IConfig` attribute."""
    if hidden:
        return argparse.SUPPRESS
    field = interfaces.IConfig.__getitem__(name)  # type: zope.interface.interface.Attribute
    return field.__doc__


class HelpfulArgumentGroup(object):
    """Emulates an argparse group for use with HelpfulArgumentParser.

    This class is used in the add_group method of HelpfulArgumentParser.
    Command line arguments can be added to the group, but help
    suppression and default detection is applied by
    HelpfulArgumentParser when necessary.

    """
    def __init__(self, helpful_arg_parser, topic):
        self._parser = helpful_arg_parser
        self._topic = topic

    def add_argument(self, *args, **kwargs):
        """Add a new command line argument to the argument group."""
        self._parser.add(self._topic, *args, **kwargs)


class CustomHelpFormatter(argparse.HelpFormatter):
    """This is a clone of ArgumentDefaultsHelpFormatter, with bugfixes.

    In particular we fix https://bugs.python.org/issue28742
    """

    def _get_help_string(self, action):
        helpstr = action.help
        if '%(default)' not in action.help and '(default:' not in action.help:
            if action.default != argparse.SUPPRESS:
                defaulting_nargs = [argparse.OPTIONAL, argparse.ZERO_OR_MORE]
                if action.option_strings or action.nargs in defaulting_nargs:
                    helpstr += ' (default: %(default)s)'
        return helpstr


class _DomainsAction(argparse.Action):
    """Action class for parsing domains."""

    def __call__(self, parser, namespace, domain, option_string=None):
        """Just wrap add_domains in argparseese."""
        add_domains(namespace, domain)


def add_domains(args_or_config, domains):
    """Registers new domains to be used during the current client run.

    Domains are not added to the list of requested domains if they have
    already been registered.

    :param args_or_config: parsed command line arguments
    :type args_or_config: argparse.Namespace or
        configuration.NamespaceConfig
    :param str domain: one or more comma separated domains

    :returns: domains after they have been normalized and validated
    :rtype: `list` of `str`

    """
    validated_domains = []
    for domain in domains.split(","):
        domain = util.enforce_domain_sanity(domain.strip())
        validated_domains.append(domain)
        if domain not in args_or_config.domains:
            args_or_config.domains.append(domain)

    return validated_domains


class CaseInsensitiveList(list):
    """A list that will ignore case when searching.

    This class is passed to the `choices` argument of `argparse.add_arguments`
    through the `helpful` wrapper. It is necessary due to special handling of
    command line arguments by `set_by_cli` in which the `type_func` is not applied."""
    def __contains__(self, element):
        return super(CaseInsensitiveList, self).__contains__(element.lower())


def _user_agent_comment_type(value):
    if "(" in value or ")" in value:
        raise argparse.ArgumentTypeError("may not contain parentheses")
    return value


class _EncodeReasonAction(argparse.Action):
    """Action class for parsing revocation reason."""

    def __call__(self, parser, namespace, reason, option_string=None):
        """Encodes the reason for certificate revocation."""
        code = constants.REVOCATION_REASONS[reason.lower()]
        setattr(namespace, self.dest, code)


def parse_preferred_challenges(pref_challs):
    """Translate and validate preferred challenges.

    :param pref_challs: list of preferred challenge types
    :type pref_challs: `list` of `str`

    :returns: validated list of preferred challenge types
    :rtype: `list` of `str`

    :raises errors.Error: if pref_challs is invalid

    """
    aliases = {"dns": "dns-01", "http": "http-01"}
    challs = [c.strip() for c in pref_challs]
    challs = [aliases.get(c, c) for c in challs]

    unrecognized = ", ".join(name for name in challs
                             if name not in challenges.Challenge.TYPES)
    if unrecognized:
        raise errors.Error(
            "Unrecognized challenges: {0}".format(unrecognized))
    return challs


class _PrefChallAction(argparse.Action):
    """Action class for parsing preferred challenges."""

    def __call__(self, parser, namespace, pref_challs, option_string=None):
        try:
            challs = parse_preferred_challenges(pref_challs.split(","))
        except errors.Error as error:
            raise argparse.ArgumentError(self, str(error))
        namespace.pref_challs.extend(challs)


class _DeployHookAction(argparse.Action):
    """Action class for parsing deploy hooks."""

    def __call__(self, parser, namespace, values, option_string=None):
        renew_hook_set = namespace.deploy_hook != namespace.renew_hook
        if renew_hook_set and namespace.renew_hook != values:
            raise argparse.ArgumentError(
                self, "conflicts with --renew-hook value")
        namespace.deploy_hook = namespace.renew_hook = values


class _RenewHookAction(argparse.Action):
    """Action class for parsing renew hooks."""

    def __call__(self, parser, namespace, values, option_string=None):
        deploy_hook_set = namespace.deploy_hook is not None
        if deploy_hook_set and namespace.deploy_hook != values:
            raise argparse.ArgumentError(
                self, "conflicts with --deploy-hook value")
        namespace.renew_hook = values


def nonnegative_int(value):
    """Converts value to an int and checks that it is not negative.

    This function should used as the type parameter for argparse
    arguments.

    :param str value: value provided on the command line

    :returns: integer representation of value
    :rtype: int

    :raises argparse.ArgumentTypeError: if value isn't a non-negative integer

    """
    try:
        int_value = int(value)
    except ValueError:
        raise argparse.ArgumentTypeError("value must be an integer")

    if int_value < 0:
        raise argparse.ArgumentTypeError("value must be non-negative")
    return int_value


================================================
FILE: certbot/_internal/cli/group_adder.py
================================================
"""This module contains a function to add the groups of arguments for the help
display"""
from certbot._internal.cli import VERB_HELP


def _add_all_groups(helpful):
    helpful.add_group("automation", description="Flags for automating execution & other tweaks")
    helpful.add_group("security", description="Security parameters & server settings")
    helpful.add_group("testing",
        description="The following flags are meant for testing and integration purposes only.")
    helpful.add_group("paths", description="Flags for changing execution paths & servers")
    helpful.add_group("manage",
        description="Various subcommands and flags are available for managing your certificates:",
        verbs=["certificates", "delete", "renew", "revoke", "update_symlinks"])

    # VERBS
    for verb, docs in VERB_HELP:
        name = docs.get("realname", verb)
        helpful.add_group(name, description=docs["opts"])


================================================
FILE: certbot/_internal/cli/helpful.py
================================================
"""Certbot command line argument parser"""
from __future__ import print_function
import argparse
import copy
import glob
import sys
import configargparse
import six
import zope.component
import zope.interface

from zope.interface import interfaces as zope_interfaces

# pylint: disable=unused-import, no-name-in-module
from acme.magic_typing import Any, Dict, Optional
# pylint: enable=unused-import, no-name-in-module

from certbot import crypto_util
from certbot import errors
from certbot import interfaces
from certbot import util
from certbot.compat import os
from certbot._internal import constants
from certbot._internal import hooks

from certbot.display import util as display_util

from certbot._internal.cli import (
    SHORT_USAGE,
    CustomHelpFormatter,
    flag_default,
    VERB_HELP,
    VERB_HELP_MAP,
    COMMAND_OVERVIEW,
    HELP_AND_VERSION_USAGE,
    _Default,
    add_domains,
    EXIT_ACTIONS,
    ZERO_ARG_ACTIONS,
    ARGPARSE_PARAMS_TO_REMOVE,
    HelpfulArgumentGroup
)


class HelpfulArgumentParser(object):
    """Argparse Wrapper.

    This class wraps argparse, adding the ability to make --help less
    verbose, and request help on specific subcategories at a time, eg
    'certbot --help security' for security options.

    """
    def __init__(self, args, plugins, detect_defaults=False):
        from certbot._internal import main
        self.VERBS = {
            "auth": main.certonly,
            "certonly": main.certonly,
            "run": main.run,
            "install": main.install,
            "plugins": main.plugins_cmd,
            "register": main.register,
            "update_account": main.update_account,
            "unregister": main.unregister,
            "renew": main.renew,
            "revoke": main.revoke,
            "rollback": main.rollback,
            "everything": main.run,
            "update_symlinks": main.update_symlinks,
            "certificates": main.certificates,
            "delete": main.delete,
            "enhance": main.enhance,
        }

        # Get notification function for printing
        try:
            self.notify = zope.component.getUtility(
                interfaces.IDisplay).notification
        except zope_interfaces.ComponentLookupError:
            self.notify = display_util.NoninteractiveDisplay(
                sys.stdout).notification


        # List of topics for which additional help can be provided
        HELP_TOPICS = ["all", "security", "paths", "automation", "testing"]
        HELP_TOPICS += list(self.VERBS) + self.COMMANDS_TOPICS + ["manage"]

        plugin_names = list(plugins)
        self.help_topics = HELP_TOPICS + plugin_names + [None]  # type: ignore

        self.detect_defaults = detect_defaults
        self.args = args

        if self.args and self.args[0] == 'help':
            self.args[0] = '--help'

        self.determine_verb()
        help1 = self.prescan_for_flag("-h", self.help_topics)
        help2 = self.prescan_for_flag("--help", self.help_topics)
        if isinstance(help1, bool) and isinstance(help2, bool):
            self.help_arg = help1 or help2
        else:
            self.help_arg = help1 if isinstance(help1, six.string_types) else help2

        short_usage = self._usage_string(plugins, self.help_arg)

        self.visible_topics = self.determine_help_topics(self.help_arg)

        # elements are added by .add_group()
        self.groups = {}  # type: Dict[str, argparse._ArgumentGroup]
        # elements are added by .parse_args()
        self.defaults = {}  # type: Dict[str, Any]

        self.parser = configargparse.ArgParser(
            prog="certbot",
            usage=short_usage,
            formatter_class=CustomHelpFormatter,
            args_for_setting_config_path=["-c", "--config"],
            default_config_files=flag_default("config_files"),
            config_arg_help_message="path to config file (default: {0})".format(
                " and ".join(flag_default("config_files"))))

        # This is the only way to turn off overly verbose config flag documentation
        self.parser._add_config_file_help = False

    # Help that are synonyms for --help subcommands
    COMMANDS_TOPICS = ["command", "commands", "subcommand", "subcommands", "verbs"]

    def _list_subcommands(self):
        longest = max(len(v) for v in VERB_HELP_MAP)

        text = "The full list of available SUBCOMMANDS is:\n\n"
        for verb, props in sorted(VERB_HELP):
            doc = props.get("short", "")
            text += '{0:<{length}}     {1}\n'.format(verb, doc, length=longest)

        text += "\nYou can get more help on a specific subcommand with --help SUBCOMMAND\n"
        return text

    def _usage_string(self, plugins, help_arg):
        """Make usage strings late so that plugins can be initialised late

        :param plugins: all discovered plugins
        :param help_arg: False for none; True for --help; "TOPIC" for --help TOPIC
        :rtype: str
        :returns: a short usage string for the top of --help TOPIC)
        """
        if "nginx" in plugins:
            nginx_doc = "--nginx           Use the Nginx plugin for authentication & installation"
        else:
            nginx_doc = "(the certbot nginx plugin is not installed)"
        if "apache" in plugins:
            apache_doc = "--apache          Use the Apache plugin for authentication & installation"
        else:
            apache_doc = "(the certbot apache plugin is not installed)"

        usage = SHORT_USAGE
        if help_arg is True:
            self.notify(usage + COMMAND_OVERVIEW % (apache_doc, nginx_doc) + HELP_AND_VERSION_USAGE)
            sys.exit(0)
        elif help_arg in self.COMMANDS_TOPICS:
            self.notify(usage + self._list_subcommands())
            sys.exit(0)
        elif help_arg == "all":
            # if we're doing --help all, the OVERVIEW is part of the SHORT_USAGE at
            # the top; if we're doing --help someothertopic, it's OT so it's not
            usage += COMMAND_OVERVIEW % (apache_doc, nginx_doc)
        else:
            custom = VERB_HELP_MAP.get(help_arg, {}).get("usage", None)
            usage = custom if custom else usage

        return usage

    def remove_config_file_domains_for_renewal(self, parsed_args):
        """Make "certbot renew" safe if domains are set in cli.ini."""
        # Works around https://github.com/certbot/certbot/issues/4096
        if self.verb == "renew":
            for source, flags in self.parser._source_to_settings.items(): # pylint: disable=protected-access
                if source.startswith("config_file") and "domains" in flags:
                    parsed_args.domains = _Default() if self.detect_defaults else []

    def parse_args(self):
        """Parses command line arguments and returns the result.

        :returns: parsed command line arguments
        :rtype: argparse.Namespace

        """
        parsed_args = self.parser.parse_args(self.args)
        parsed_args.func = self.VERBS[self.verb]
        parsed_args.verb = self.verb

        self.remove_config_file_domains_for_renewal(parsed_args)

        if self.detect_defaults:
            return parsed_args

        self.defaults = dict((key, copy.deepcopy(self.parser.get_default(key)))
                             for key in vars(parsed_args))

        # Do any post-parsing homework here

        if self.verb == "renew":
            if parsed_args.force_interactive:
                raise errors.Error(
                    "{0} cannot be used with renew".format(
                        constants.FORCE_INTERACTIVE_FLAG))
            parsed_args.noninteractive_mode = True

        if parsed_args.force_interactive and parsed_args.noninteractive_mode:
            raise errors.Error(
                "Flag for non-interactive mode and {0} conflict".format(
                    constants.FORCE_INTERACTIVE_FLAG))

        if parsed_args.staging or parsed_args.dry_run:
            self.set_test_server(parsed_args)

        if parsed_args.csr:
            self.handle_csr(parsed_args)
Download .txt
gitextract_z7q7eth2/

├── .gitignore
├── CHANGELOG.md
├── LICENSE.txt
├── MANIFEST.in
├── PKG-INFO
├── README.rst
├── certbot/
│   ├── __init__.py
│   ├── _internal/
│   │   ├── __init__.py
│   │   ├── account.py
│   │   ├── auth_handler.py
│   │   ├── cert_manager.py
│   │   ├── cli/
│   │   │   ├── __init__.py
│   │   │   ├── cli_constants.py
│   │   │   ├── cli_utils.py
│   │   │   ├── group_adder.py
│   │   │   ├── helpful.py
│   │   │   ├── paths_parser.py
│   │   │   ├── plugins_parsing.py
│   │   │   ├── report_config_interaction.py
│   │   │   ├── subparsers.py
│   │   │   └── verb_help.py
│   │   ├── client.py
│   │   ├── configuration.py
│   │   ├── constants.py
│   │   ├── display/
│   │   │   ├── __init__.py
│   │   │   ├── completer.py
│   │   │   ├── dummy_readline.py
│   │   │   └── enhancements.py
│   │   ├── eff.py
│   │   ├── error_handler.py
│   │   ├── hooks.py
│   │   ├── lock.py
│   │   ├── log.py
│   │   ├── main.py
│   │   ├── plugins/
│   │   │   ├── __init__.py
│   │   │   ├── disco.py
│   │   │   ├── manual.py
│   │   │   ├── null.py
│   │   │   ├── selection.py
│   │   │   ├── standalone.py
│   │   │   └── webroot.py
│   │   ├── renewal.py
│   │   ├── reporter.py
│   │   ├── storage.py
│   │   └── updater.py
│   ├── achallenges.py
│   ├── compat/
│   │   ├── __init__.py
│   │   ├── _path.py
│   │   ├── filesystem.py
│   │   ├── misc.py
│   │   └── os.py
│   ├── crypto_util.py
│   ├── display/
│   │   ├── __init__.py
│   │   ├── ops.py
│   │   └── util.py
│   ├── errors.py
│   ├── interfaces.py
│   ├── main.py
│   ├── ocsp.py
│   ├── plugins/
│   │   ├── __init__.py
│   │   ├── common.py
│   │   ├── dns_common.py
│   │   ├── dns_common_lexicon.py
│   │   ├── dns_test_common.py
│   │   ├── dns_test_common_lexicon.py
│   │   ├── enhancements.py
│   │   ├── storage.py
│   │   └── util.py
│   ├── reverter.py
│   ├── ssl-dhparams.pem
│   ├── tests/
│   │   ├── __init__.py
│   │   ├── acme_util.py
│   │   ├── testdata/
│   │   │   ├── README
│   │   │   ├── cert-5sans_512.pem
│   │   │   ├── cert-nosans_nistp256.pem
│   │   │   ├── cert-san_512.pem
│   │   │   ├── cert_2048.pem
│   │   │   ├── cert_512.pem
│   │   │   ├── cert_512_bad.pem
│   │   │   ├── cert_fullchain_2048.pem
│   │   │   ├── cli.ini
│   │   │   ├── csr-6sans_512.conf
│   │   │   ├── csr-6sans_512.pem
│   │   │   ├── csr-nonames_512.pem
│   │   │   ├── csr-nosans_512.conf
│   │   │   ├── csr-nosans_512.pem
│   │   │   ├── csr-nosans_nistp256.pem
│   │   │   ├── csr-san_512.pem
│   │   │   ├── csr_512.der
│   │   │   ├── csr_512.pem
│   │   │   ├── nistp256_key.pem
│   │   │   ├── ocsp_certificate.pem
│   │   │   ├── ocsp_issuer_certificate.pem
│   │   │   ├── ocsp_responder_certificate.pem
│   │   │   ├── os-release
│   │   │   ├── rsa2048_key.pem
│   │   │   ├── rsa256_key.pem
│   │   │   ├── rsa512_key.pem
│   │   │   ├── sample-archive/
│   │   │   │   ├── cert1.pem
│   │   │   │   ├── chain1.pem
│   │   │   │   ├── fullchain1.pem
│   │   │   │   └── privkey1.pem
│   │   │   ├── sample-renewal-ancient.conf
│   │   │   ├── sample-renewal.conf
│   │   │   └── webrootconftest.ini
│   │   └── util.py
│   └── util.py
├── certbot.egg-info/
│   ├── PKG-INFO
│   ├── SOURCES.txt
│   ├── dependency_links.txt
│   ├── entry_points.txt
│   ├── requires.txt
│   └── top_level.txt
├── debian/
│   ├── README.source
│   ├── certbot.cron.d
│   ├── certbot.docs
│   ├── certbot.links
│   ├── certbot.logrotate
│   ├── certbot.manpages
│   ├── certbot.postrm
│   ├── certbot.service
│   ├── certbot.timer
│   ├── changelog
│   ├── cli.ini
│   ├── control
│   ├── copyright
│   ├── patches/
│   │   ├── 0001-remove-external-images.patch
│   │   └── series
│   ├── pydist-overrides
│   ├── python-certbot-doc.doc-base
│   ├── python-certbot-doc.docs
│   ├── python-certbot-doc.examples
│   ├── python3-certbot.lintian-overrides
│   ├── rules
│   ├── source/
│   │   └── format
│   ├── tests/
│   │   ├── certs/
│   │   │   ├── README.md
│   │   │   ├── cert.pem
│   │   │   └── key.pem
│   │   ├── control
│   │   ├── http-01
│   │   └── pebble-config.json
│   ├── upstream/
│   │   └── signing-key.asc
│   └── watch
├── docs/
│   ├── .gitignore
│   ├── Makefile
│   ├── _static/
│   │   └── .gitignore
│   ├── _templates/
│   │   └── footer.html
│   ├── api/
│   │   ├── certbot.achallenges.rst
│   │   ├── certbot.compat.filesystem.rst
│   │   ├── certbot.compat.misc.rst
│   │   ├── certbot.compat.os.rst
│   │   ├── certbot.compat.rst
│   │   ├── certbot.crypto_util.rst
│   │   ├── certbot.display.ops.rst
│   │   ├── certbot.display.rst
│   │   ├── certbot.display.util.rst
│   │   ├── certbot.errors.rst
│   │   ├── certbot.interfaces.rst
│   │   ├── certbot.main.rst
│   │   ├── certbot.ocsp.rst
│   │   ├── certbot.plugins.common.rst
│   │   ├── certbot.plugins.dns_common.rst
│   │   ├── certbot.plugins.dns_common_lexicon.rst
│   │   ├── certbot.plugins.dns_test_common.rst
│   │   ├── certbot.plugins.dns_test_common_lexicon.rst
│   │   ├── certbot.plugins.enhancements.rst
│   │   ├── certbot.plugins.rst
│   │   ├── certbot.plugins.storage.rst
│   │   ├── certbot.plugins.util.rst
│   │   ├── certbot.reverter.rst
│   │   ├── certbot.rst
│   │   ├── certbot.tests.acme_util.rst
│   │   ├── certbot.tests.rst
│   │   ├── certbot.tests.util.rst
│   │   └── certbot.util.rst
│   ├── api.rst
│   ├── challenges.rst
│   ├── ciphers.rst
│   ├── cli-help.txt
│   ├── compatibility.rst
│   ├── conf.py
│   ├── contributing.rst
│   ├── index.rst
│   ├── install.rst
│   ├── intro.rst
│   ├── make.bat
│   ├── man/
│   │   └── certbot.rst
│   ├── packaging.rst
│   ├── resources.rst
│   ├── using.rst
│   └── what.rst
├── examples/
│   ├── .gitignore
│   ├── cli.ini
│   ├── dev-cli.ini
│   ├── generate-csr.sh
│   ├── openssl.cnf
│   └── plugins/
│       ├── certbot_example_plugins.py
│       └── setup.py
├── setup.cfg
├── setup.py
└── tests/
    ├── account_test.py
    ├── auth_handler_test.py
    ├── cert_manager_test.py
    ├── cli_test.py
    ├── client_test.py
    ├── compat/
    │   ├── __init__.py
    │   ├── filesystem_test.py
    │   └── os_test.py
    ├── configuration_test.py
    ├── crypto_util_test.py
    ├── display/
    │   ├── __init__.py
    │   ├── completer_test.py
    │   ├── enhancements_test.py
    │   ├── ops_test.py
    │   └── util_test.py
    ├── eff_test.py
    ├── error_handler_test.py
    ├── errors_test.py
    ├── helpful_test.py
    ├── hook_test.py
    ├── lock_test.py
    ├── log_test.py
    ├── main_test.py
    ├── ocsp_test.py
    ├── plugins/
    │   ├── __init__.py
    │   ├── common_test.py
    │   ├── disco_test.py
    │   ├── dns_common_lexicon_test.py
    │   ├── dns_common_test.py
    │   ├── enhancements_test.py
    │   ├── manual_test.py
    │   ├── null_test.py
    │   ├── selection_test.py
    │   ├── standalone_test.py
    │   ├── storage_test.py
    │   ├── util_test.py
    │   └── webroot_test.py
    ├── renewal_test.py
    ├── renewupdater_test.py
    ├── reporter_test.py
    ├── reverter_test.py
    ├── storage_test.py
    └── util_test.py
Download .txt
SYMBOL INDEX (2271 symbols across 98 files)

FILE: certbot/_internal/account.py
  class Account (line 27) | class Account(object):
    class Meta (line 37) | class Meta(jose.JSONObjectWithFields):
    method __init__ (line 50) | def __init__(self, regr, key, meta=None):
    method slug (line 78) | def slug(self):
    method __repr__ (line 83) | def __repr__(self):
    method __eq__ (line 87) | def __eq__(self, other):
  function report_new_account (line 93) | def report_new_account(config):
  class AccountMemoryStorage (line 108) | class AccountMemoryStorage(interfaces.AccountStorage):
    method __init__ (line 111) | def __init__(self, initial_accounts=None):
    method find_all (line 114) | def find_all(self):
    method save (line 117) | def save(self, account, client):
    method load (line 122) | def load(self, account_id):
  class RegistrationResourceWithNewAuthzrURI (line 128) | class RegistrationResourceWithNewAuthzrURI(messages.RegistrationResource):
  class AccountFileStorage (line 139) | class AccountFileStorage(interfaces.AccountStorage):
    method __init__ (line 145) | def __init__(self, config):
    method _account_dir_path (line 149) | def _account_dir_path(self, account_id):
    method _account_dir_path_for_server_path (line 152) | def _account_dir_path_for_server_path(self, account_id, server_path):
    method _regr_path (line 157) | def _regr_path(cls, account_dir_path):
    method _key_path (line 161) | def _key_path(cls, account_dir_path):
    method _metadata_path (line 165) | def _metadata_path(cls, account_dir_path):
    method _find_all_for_server_path (line 168) | def _find_all_for_server_path(self, server_path):
    method find_all (line 195) | def find_all(self):
    method _symlink_to_account_dir (line 198) | def _symlink_to_account_dir(self, prev_server_path, server_path, accou...
    method _symlink_to_accounts_dir (line 203) | def _symlink_to_accounts_dir(self, prev_server_path, server_path):
    method _load_for_server_path (line 212) | def _load_for_server_path(self, account_id, server_path):
    method load (line 241) | def load(self, account_id):
    method save (line 244) | def save(self, account, client):
    method save_regr (line 247) | def save_regr(self, account, acme):
    method delete (line 255) | def delete(self, account_id):
    method _delete_account_dir_for_server_path (line 272) | def _delete_account_dir_for_server_path(self, account_id, server_path):
    method _delete_accounts_dir_for_server_path (line 277) | def _delete_accounts_dir_for_server_path(self, server_path):
    method _delete_links_and_find_target_dir (line 282) | def _delete_links_and_find_target_dir(self, server_path, link_func):
    method _save (line 321) | def _save(self, account, acme, regr_only):

FILE: certbot/_internal/auth_handler.py
  class AuthHandler (line 22) | class AuthHandler(object):
    method __init__ (line 38) | def __init__(self, auth, acme_client, account, pref_challs):
    method handle_authorizations (line 45) | def handle_authorizations(self, orderr, best_effort=False, max_retries...
    method deactivate_valid_authorizations (line 101) | def deactivate_valid_authorizations(self, orderr):
    method _poll_authorizations (line 126) | def _poll_authorizations(self, authzrs, max_retries, best_effort):
    method _choose_challenges (line 186) | def _choose_challenges(self, authzrs):
    method _get_chall_pref (line 213) | def _get_chall_pref(self, domain):
    method _cleanup_challenges (line 235) | def _cleanup_challenges(self, achalls):
    method _challenge_factory (line 245) | def _challenge_factory(self, authzr, path):
  function challb_to_achall (line 269) | def challb_to_achall(challb, account_key, domain):
  function gen_challenge_path (line 292) | def gen_challenge_path(challbs, preferences, combinations):
  function _find_smart_path (line 323) | def _find_smart_path(challbs, preferences, combinations):
  function _find_dumb_path (line 360) | def _find_dumb_path(challbs, preferences):
  function _report_no_chall_path (line 381) | def _report_no_chall_path(challbs):
  function _report_failed_authzrs (line 429) | def _report_failed_authzrs(failed_authzrs, account_key):
  function _generate_failed_chall_msg (line 444) | def _generate_failed_chall_msg(failed_achalls):

FILE: certbot/_internal/cert_manager.py
  function update_live_symlinks (line 26) | def update_live_symlinks(config):
  function rename_lineage (line 41) | def rename_lineage(config):
  function certificates (line 68) | def certificates(config):
  function delete (line 90) | def delete(config):
  function lineage_for_certname (line 103) | def lineage_for_certname(cli_config, certname):
  function domains_for_certname (line 119) | def domains_for_certname(config, certname):
  function find_duplicative_certs (line 124) | def find_duplicative_certs(config, domains):
  function _archive_files (line 168) | def _archive_files(candidate_lineage, filetype):
  function _acceptable_matches (line 189) | def _acceptable_matches():
  function cert_path_to_lineage (line 199) | def cert_path_to_lineage(cli_config):
  function match_and_check_overlaps (line 215) | def match_and_check_overlaps(cli_config, acceptable_matches, match_func,...
  function human_readable_cert_info (line 248) | def human_readable_cert_info(config, cert, skip_filter_checks=False):
  function get_certnames (line 291) | def get_certnames(config, verb, allow_multiple=False, custom_prompt=None):
  function _report_lines (line 330) | def _report_lines(msgs):
  function _report_human_readable (line 334) | def _report_human_readable(config, parsed_certs):
  function _describe_certs (line 341) | def _describe_certs(config, parsed_certs, parse_failures):
  function _search_lineages (line 362) | def _search_lineages(cli_config, func, initial_rv, *args):

FILE: certbot/_internal/cli/__init__.py
  function prepare_and_parse_args (line 73) | def prepare_and_parse_args(plugins, args, detect_defaults=False):
  function set_by_cli (line 450) | def set_by_cli(var):
  function has_default_value (line 488) | def has_default_value(option, value):
  function option_was_set (line 506) | def option_was_set(option, value):
  function argparse_type (line 519) | def argparse_type(variable):

FILE: certbot/_internal/cli/cli_utils.py
  class _Default (line 15) | class _Default(object):
    method __bool__ (line 18) | def __bool__(self):
    method __eq__ (line 21) | def __eq__(self, other):
    method __hash__ (line 24) | def __hash__(self):
    method __nonzero__ (line 27) | def __nonzero__(self):
  function read_file (line 31) | def read_file(filename, mode="rb"):
  function flag_default (line 52) | def flag_default(name):
  function config_help (line 61) | def config_help(name, hidden=False):
  class HelpfulArgumentGroup (line 69) | class HelpfulArgumentGroup(object):
    method __init__ (line 78) | def __init__(self, helpful_arg_parser, topic):
    method add_argument (line 82) | def add_argument(self, *args, **kwargs):
  class CustomHelpFormatter (line 87) | class CustomHelpFormatter(argparse.HelpFormatter):
    method _get_help_string (line 93) | def _get_help_string(self, action):
  class _DomainsAction (line 103) | class _DomainsAction(argparse.Action):
    method __call__ (line 106) | def __call__(self, parser, namespace, domain, option_string=None):
  function add_domains (line 111) | def add_domains(args_or_config, domains):
  class CaseInsensitiveList (line 136) | class CaseInsensitiveList(list):
    method __contains__ (line 142) | def __contains__(self, element):
  function _user_agent_comment_type (line 146) | def _user_agent_comment_type(value):
  class _EncodeReasonAction (line 152) | class _EncodeReasonAction(argparse.Action):
    method __call__ (line 155) | def __call__(self, parser, namespace, reason, option_string=None):
  function parse_preferred_challenges (line 161) | def parse_preferred_challenges(pref_challs):
  class _PrefChallAction (line 185) | class _PrefChallAction(argparse.Action):
    method __call__ (line 188) | def __call__(self, parser, namespace, pref_challs, option_string=None):
  class _DeployHookAction (line 196) | class _DeployHookAction(argparse.Action):
    method __call__ (line 199) | def __call__(self, parser, namespace, values, option_string=None):
  class _RenewHookAction (line 207) | class _RenewHookAction(argparse.Action):
    method __call__ (line 210) | def __call__(self, parser, namespace, values, option_string=None):
  function nonnegative_int (line 218) | def nonnegative_int(value):

FILE: certbot/_internal/cli/group_adder.py
  function _add_all_groups (line 6) | def _add_all_groups(helpful):

FILE: certbot/_internal/cli/helpful.py
  class HelpfulArgumentParser (line 45) | class HelpfulArgumentParser(object):
    method __init__ (line 53) | def __init__(self, args, plugins, detect_defaults=False):
    method _list_subcommands (line 128) | def _list_subcommands(self):
    method _usage_string (line 139) | def _usage_string(self, plugins, help_arg):
    method remove_config_file_domains_for_renewal (line 173) | def remove_config_file_domains_for_renewal(self, parsed_args):
    method parse_args (line 181) | def parse_args(self):
    method set_test_server (line 237) | def set_test_server(self, parsed_args):
    method handle_csr (line 266) | def handle_csr(self, parsed_args):
    method determine_verb (line 300) | def determine_verb(self):
    method prescan_for_flag (line 324) | def prescan_for_flag(self, flag, possible_arguments):
    method add (line 345) | def add(self, topics, *args, **kwargs):
    method modify_kwargs_for_default_detection (line 378) | def modify_kwargs_for_default_detection(self, **kwargs):
    method add_deprecated_argument (line 400) | def add_deprecated_argument(self, argument_name, num_args):
    method add_group (line 414) | def add_group(self, topic, verbs=(), **kwargs):
    method add_plugin_args (line 436) | def add_plugin_args(self, plugins):
    method determine_help_topics (line 448) | def determine_help_topics(self, chosen_topic):

FILE: certbot/_internal/cli/paths_parser.py
  function _paths_parser (line 11) | def _paths_parser(helpful):

FILE: certbot/_internal/cli/plugins_parsing.py
  function _plugins_parsing (line 5) | def _plugins_parsing(helpful, plugins):

FILE: certbot/_internal/cli/report_config_interaction.py
  function report_config_interaction (line 8) | def report_config_interaction(modified, modifiers):

FILE: certbot/_internal/cli/subparsers.py
  function _create_subparsers (line 14) | def _create_subparsers(helpful):

FILE: certbot/_internal/client.py
  function acme_from_config_key (line 39) | def acme_from_config_key(config, key, regr=None):
  function determine_user_agent (line 47) | def determine_user_agent(config):
  function ua_flags (line 78) | def ua_flags(config):
  class DummyConfig (line 97) | class DummyConfig(object):
    method __init__ (line 99) | def __init__(self):
    method __getattr__ (line 105) | def __getattr__(self, name):
  function sample_user_agent (line 109) | def sample_user_agent():
  function register (line 115) | def register(config, account_storage, tos_cb=None):
  function perform_registration (line 187) | def perform_registration(acme, config, tos_cb):
  class Client (line 232) | class Client(object):
    method __init__ (line 248) | def __init__(self, config, account_, auth, installer, acme=None):
    method obtain_certificate_from_csr (line 266) | def obtain_certificate_from_csr(self, csr, orderr=None):
    method obtain_certificate (line 296) | def obtain_certificate(self, domains, old_keypath=None):
    method _get_order_and_authorizations (line 363) | def _get_order_and_authorizations(self, csr_pem, best_effort):
    method obtain_and_enroll_certificate (line 393) | def obtain_and_enroll_certificate(self, domains, certname):
    method _choose_lineagename (line 429) | def _choose_lineagename(self, domains, certname):
    method save_certificate (line 448) | def save_certificate(self, cert_pem, chain_pem,
    method deploy_certificate (line 488) | def deploy_certificate(self, domains, privkey_path,
    method enhance_config (line 524) | def enhance_config(self, domains, chain_path, ask_redirect=True):
    method apply_enhancement (line 572) | def apply_enhancement(self, domains, enhancement, options=None):
    method _recovery_routine_with_msg (line 607) | def _recovery_routine_with_msg(self, success_msg):
    method _rollback_and_restart (line 617) | def _rollback_and_restart(self, success_msg):
  function validate_key_csr (line 639) | def validate_key_csr(privkey, csr=None):
  function rollback (line 685) | def rollback(default_installer, checkpoints, config, plugins):
  function _open_pem_file (line 706) | def _open_pem_file(cli_arg_path, pem_path):
  function _save_chain (line 724) | def _save_chain(chain_pem, chain_file):

FILE: certbot/_internal/configuration.py
  class NamespaceConfig (line 16) | class NamespaceConfig(object):
    method __init__ (line 45) | def __init__(self, namespace):
    method __getattr__ (line 55) | def __getattr__(self, name):
    method __setattr__ (line 58) | def __setattr__(self, name, value):
    method server_path (line 62) | def server_path(self):
    method accounts_dir (line 68) | def accounts_dir(self):  # pylint: disable=missing-function-docstring
    method accounts_dir_for_server_path (line 71) | def accounts_dir_for_server_path(self, server_path):
    method backup_dir (line 78) | def backup_dir(self):  # pylint: disable=missing-function-docstring
    method csr_dir (line 82) | def csr_dir(self):  # pylint: disable=missing-function-docstring
    method in_progress_dir (line 86) | def in_progress_dir(self):  # pylint: disable=missing-function-docstring
    method key_dir (line 90) | def key_dir(self):  # pylint: disable=missing-function-docstring
    method temp_checkpoint_dir (line 94) | def temp_checkpoint_dir(self):  # pylint: disable=missing-function-doc...
    method __deepcopy__ (line 98) | def __deepcopy__(self, _memo):
    method default_archive_dir (line 105) | def default_archive_dir(self):  # pylint: disable=missing-function-doc...
    method live_dir (line 109) | def live_dir(self):  # pylint: disable=missing-function-docstring
    method renewal_configs_dir (line 113) | def renewal_configs_dir(self):  # pylint: disable=missing-function-doc...
    method renewal_hooks_dir (line 118) | def renewal_hooks_dir(self):
    method renewal_pre_hooks_dir (line 124) | def renewal_pre_hooks_dir(self):
    method renewal_deploy_hooks_dir (line 130) | def renewal_deploy_hooks_dir(self):
    method renewal_post_hooks_dir (line 136) | def renewal_post_hooks_dir(self):
  function check_config_sanity (line 142) | def check_config_sanity(config):

FILE: certbot/_internal/display/completer.py
  class Completer (line 11) | class Completer(object):
    method __init__ (line 28) | def __init__(self):
    method complete (line 31) | def complete(self, text, state):
    method __enter__ (line 46) | def __enter__(self):
    method __exit__ (line 60) | def __exit__(self, unused_type, unused_value, unused_traceback):

FILE: certbot/_internal/display/dummy_readline.py
  function get_completer (line 4) | def get_completer():
  function get_completer_delims (line 8) | def get_completer_delims():
  function parse_and_bind (line 12) | def parse_and_bind(unused_command):
  function set_completer (line 16) | def set_completer(unused_function=None):
  function set_completer_delims (line 20) | def set_completer_delims(unused_delims):

FILE: certbot/_internal/display/enhancements.py
  function ask (line 16) | def ask(enhancement):
  function redirect_by_default (line 36) | def redirect_by_default():

FILE: certbot/_internal/eff.py
  function handle_subscription (line 13) | def handle_subscription(config):
  function _want_subscription (line 32) | def _want_subscription():
  function subscribe (line 49) | def subscribe(email):
  function _check_response (line 63) | def _check_response(response):
  function _report_failure (line 83) | def _report_failure(reason=None):

FILE: certbot/_internal/error_handler.py
  class ErrorHandler (line 48) | class ErrorHandler(object):
    method __init__ (line 77) | def __init__(self, func, *args, **kwargs):
    method __enter__ (line 86) | def __enter__(self):
    method __exit__ (line 90) | def __exit__(self, exec_type, exec_value, trace):
    method register (line 111) | def register(self, func, *args, **kwargs):
    method _call_registered (line 120) | def _call_registered(self):
    method _set_signal_handlers (line 130) | def _set_signal_handlers(self):
    method _reset_signal_handlers (line 139) | def _reset_signal_handlers(self):
    method _signal_handler (line 145) | def _signal_handler(self, signum, unused_frame):
    method _call_signals (line 158) | def _call_signals(self):
  class ExitHandler (line 164) | class ExitHandler(ErrorHandler):
    method __init__ (line 171) | def __init__(self, func, *args, **kwargs):

FILE: certbot/_internal/hooks.py
  function validate_hooks (line 19) | def validate_hooks(config):
  function _prog (line 27) | def _prog(shell_cmd):
  function validate_hook (line 43) | def validate_hook(shell_cmd, hook_name):
  function pre_hook (line 61) | def pre_hook(config):
  function _run_pre_hook_if_necessary (line 85) | def _run_pre_hook_if_necessary(command):
  function post_hook (line 101) | def post_hook(config):
  function _run_eventually (line 135) | def _run_eventually(command):
  function run_saved_post_hooks (line 148) | def run_saved_post_hooks():
  function deploy_hook (line 154) | def deploy_hook(config, domains, lineage_path):
  function renew_hook (line 168) | def renew_hook(config, domains, lineage_path):
  function _run_deploy_hook (line 200) | def _run_deploy_hook(command, domains, lineage_path, dry_run):
  function _run_hook (line 224) | def _run_hook(cmd_name, shell_cmd):
  function execute (line 236) | def execute(cmd_name, shell_cmd):
  function list_hooks (line 262) | def list_hooks(dir_path):

FILE: certbot/_internal/lock.py
  function lock_dir (line 23) | def lock_dir(dir_path):
  class LockFile (line 41) | class LockFile(object):
    method __init__ (line 55) | def __init__(self, path):
    method __repr__ (line 67) | def __repr__(self):
    method acquire (line 76) | def acquire(self):
    method release (line 84) | def release(self):
    method is_locked (line 91) | def is_locked(self):
  class _BaseLockMechanism (line 100) | class _BaseLockMechanism(object):
    method __init__ (line 101) | def __init__(self, path):
    method is_locked (line 110) | def is_locked(self):
    method acquire (line 118) | def acquire(self):  # pylint: disable=missing-function-docstring
    method release (line 121) | def release(self):  # pylint: disable=missing-function-docstring
  class _UnixLockMechanism (line 125) | class _UnixLockMechanism(_BaseLockMechanism):
    method acquire (line 132) | def acquire(self):
    method _try_lock (line 147) | def _try_lock(self, fd):
    method _lock_success (line 161) | def _lock_success(self, fd):
    method release (line 188) | def release(self):
  class _WindowsLockMechanism (line 213) | class _WindowsLockMechanism(_BaseLockMechanism):
    method acquire (line 229) | def acquire(self):
    method release (line 250) | def release(self):

FILE: certbot/_internal/log.py
  function pre_arg_parse_setup (line 39) | def pre_arg_parse_setup():
  function post_arg_parse_setup (line 77) | def post_arg_parse_setup(config):
  function setup_log_file_handler (line 123) | def setup_log_file_handler(config, logfile, fmt):
  class ColoredStreamHandler (line 154) | class ColoredStreamHandler(logging.StreamHandler):
    method __init__ (line 165) | def __init__(self, stream=None):
    method format (line 171) | def format(self, record):
  class MemoryHandler (line 186) | class MemoryHandler(logging.handlers.MemoryHandler):
    method __init__ (line 193) | def __init__(self, target=None, capacity=10000):
    method close (line 197) | def close(self):
    method flush (line 205) | def flush(self, force=False):  # pylint: disable=arguments-differ
    method shouldFlush (line 218) | def shouldFlush(self, record):
  class TempHandler (line 230) | class TempHandler(logging.StreamHandler):
    method __init__ (line 240) | def __init__(self):
    method emit (line 247) | def emit(self, record):
    method close (line 256) | def close(self):
  function pre_arg_parse_except_hook (line 275) | def pre_arg_parse_except_hook(memory_handler, *args, **kwargs):
  function post_arg_parse_except_hook (line 302) | def post_arg_parse_except_hook(exc_type, exc_value, trace, debug, log_pa...
  function exit_with_log_path (line 337) | def exit_with_log_path(log_path):

FILE: certbot/_internal/main.py
  function _suggest_donation_if_appropriate (line 49) | def _suggest_donation_if_appropriate(config):
  function _report_successful_dry_run (line 69) | def _report_successful_dry_run(config):
  function _get_and_save_cert (line 85) | def _get_and_save_cert(le_client, config, domains=None, certname=None, l...
  function _handle_subset_cert_request (line 132) | def _handle_subset_cert_request(config, domains, cert):
  function _handle_identical_cert_request (line 179) | def _handle_identical_cert_request(config, lineage):
  function _find_lineage_for_domains (line 229) | def _find_lineage_for_domains(config, domains):
  function _find_cert (line 268) | def _find_cert(config, domains, certname):
  function _find_lineage_for_domains_and_certname (line 291) | def _find_lineage_for_domains_and_certname(config, domains, certname):
  function _get_added_removed (line 329) | def _get_added_removed(after, before):
  function _format_list (line 339) | def _format_list(character, strings):
  function _ask_user_to_confirm_new_names (line 351) | def _ask_user_to_confirm_new_names(config, new_domains, certname, old_do...
  function _find_domains_or_certname (line 388) | def _find_domains_or_certname(config, installer, question=None):
  function _report_new_cert (line 429) | def _report_new_cert(config, cert_path, fullchain_path, key_path=None):
  function _determine_account (line 471) | def _determine_account(config):
  function _delete_if_appropriate (line 531) | def _delete_if_appropriate(config):
  function _init_le_client (line 586) | def _init_le_client(config, authenticator, installer):
  function unregister (line 613) | def unregister(config, unused_plugins):
  function register (line 654) | def register(config, unused_plugins):
  function update_account (line 684) | def update_account(config, unused_plugins):
  function _install_cert (line 729) | def _install_cert(config, le_client, domains, lineage=None):
  function install (line 756) | def install(config, plugins):
  function _populate_from_certname (line 815) | def _populate_from_certname(config):
  function _check_certificate_and_key (line 832) | def _check_certificate_and_key(config):
  function plugins_cmd (line 839) | def plugins_cmd(config, plugins):
  function enhance (line 878) | def enhance(config, plugins):
  function rollback (line 937) | def rollback(config, plugins):
  function update_symlinks (line 952) | def update_symlinks(config, unused_plugins):
  function rename (line 970) | def rename(config, unused_plugins):
  function delete (line 988) | def delete(config, unused_plugins):
  function certificates (line 1006) | def certificates(config, unused_plugins):
  function revoke (line 1022) | def revoke(config, unused_plugins):
  function run (line 1067) | def run(config, plugins):
  function _csr_get_and_save_cert (line 1122) | def _csr_get_and_save_cert(config, le_client):
  function renew_cert (line 1150) | def renew_cert(config, plugins, lineage):
  function certonly (line 1192) | def certonly(config, plugins):
  function renew (line 1241) | def renew(config, unused_plugins):
  function make_or_verify_needed_dirs (line 1260) | def make_or_verify_needed_dirs(config):
  function set_displayer (line 1280) | def set_displayer(config):
  function main (line 1302) | def main(cli_args=None):

FILE: certbot/_internal/plugins/disco.py
  class PluginEntryPoint (line 25) | class PluginEntryPoint(object):
    method __init__ (line 52) | def __init__(self, entry_point):
    method entry_point_to_plugin_name (line 60) | def entry_point_to_plugin_name(cls, entry_point):
    method description (line 67) | def description(self):
    method description_with_name (line 72) | def description_with_name(self):
    method long_description (line 77) | def long_description(self):
    method hidden (line 85) | def hidden(self):
    method ifaces (line 89) | def ifaces(self, *ifaces_groups):
    method initialized (line 97) | def initialized(self):
    method init (line 101) | def init(self, config=None):
    method verify (line 108) | def verify(self, ifaces):
    method prepared (line 123) | def prepared(self):
    method prepare (line 129) | def prepare(self):
    method misconfigured (line 150) | def misconfigured(self):
    method problem (line 155) | def problem(self):
    method available (line 162) | def available(self):
    method __repr__ (line 166) | def __repr__(self):
    method __str__ (line 169) | def __str__(self):
  class PluginsRegistry (line 187) | class PluginsRegistry(Mapping):
    method __init__ (line 190) | def __init__(self, plugins):
    method find_all (line 201) | def find_all(cls):
    method __getitem__ (line 220) | def __getitem__(self, name):
    method __iter__ (line 223) | def __iter__(self):
    method __len__ (line 226) | def __len__(self):
    method init (line 229) | def init(self, config):
    method filter (line 234) | def filter(self, pred):
    method visible (line 239) | def visible(self):
    method ifaces (line 243) | def ifaces(self, *ifaces_groups):
    method verify (line 247) | def verify(self, ifaces):
    method prepare (line 251) | def prepare(self):
    method available (line 255) | def available(self):
    method find_init (line 260) | def find_init(self, plugin):
    method __repr__ (line 282) | def __repr__(self):
    method __str__ (line 287) | def __str__(self):

FILE: certbot/_internal/plugins/manual.py
  class Authenticator (line 18) | class Authenticator(common.Plugin):
    method __init__ (line 66) | def __init__(self, *args, **kwargs):
    method add_parser_arguments (line 76) | def add_parser_arguments(cls, add):
    method prepare (line 84) | def prepare(self):  # pylint: disable=missing-function-docstring
    method _validate_hooks (line 92) | def _validate_hooks(self):
    method more_info (line 100) | def more_info(self):  # pylint: disable=missing-function-docstring
    method get_chall_pref (line 106) | def get_chall_pref(self, domain):
    method perform (line 110) | def perform(self, achalls):  # pylint: disable=missing-function-docstring
    method _verify_ip_logging_ok (line 123) | def _verify_ip_logging_ok(self):
    method _perform_achall_with_script (line 137) | def _perform_achall_with_script(self, achall):
    method _perform_achall_manually (line 149) | def _perform_achall_manually(self, achall):
    method cleanup (line 173) | def cleanup(self, achalls):  # pylint: disable=missing-function-docstring
    method _execute_hook (line 183) | def _execute_hook(self, hook_name):

FILE: certbot/_internal/plugins/null.py
  class Installer (line 15) | class Installer(common.Plugin):
    method prepare (line 23) | def prepare(self):
    method more_info (line 26) | def more_info(self):
    method get_all_names (line 29) | def get_all_names(self):
    method deploy_cert (line 32) | def deploy_cert(self, domain, cert_path, key_path,
    method enhance (line 36) | def enhance(self, domain, enhancement, options=None):
    method supported_enhancements (line 39) | def supported_enhancements(self):
    method save (line 42) | def save(self, title=None, temporary=False):
    method rollback_checkpoints (line 45) | def rollback_checkpoints(self, rollback=1):
    method recovery_routine (line 48) | def recovery_routine(self):
    method config_test (line 51) | def config_test(self):
    method restart (line 54) | def restart(self):

FILE: certbot/_internal/plugins/selection.py
  function pick_configurator (line 17) | def pick_configurator(
  function pick_installer (line 27) | def pick_installer(config, default, plugins,
  function pick_authenticator (line 34) | def pick_authenticator(
  function get_unprepared_installer (line 41) | def get_unprepared_installer(config, plugins):
  function pick_plugin (line 70) | def pick_plugin(config, default, plugins, question, ifaces):
  function choose_plugin (line 124) | def choose_plugin(prepared, question):
  function record_chosen_plugins (line 168) | def record_chosen_plugins(config, plugins, auth, inst):
  function choose_configurator_plugins (line 176) | def choose_configurator_plugins(config, plugins, verb):
  function set_configurator (line 239) | def set_configurator(previously, now):
  function cli_plugin_requests (line 255) | def cli_plugin_requests(config):
  function diagnose_configurator_problem (line 310) | def diagnose_configurator_problem(cfg_type, requested, plugins):

FILE: certbot/_internal/plugins/standalone.py
  class ServerManager (line 32) | class ServerManager(object):
    method __init__ (line 45) | def __init__(self, certs, http_01_resources):
    method run (line 50) | def run(self, port, challenge_type, listenaddr=""):
    method stop (line 84) | def stop(self, port):
    method running (line 97) | def running(self):
  class Authenticator (line 112) | class Authenticator(common.Plugin):
    method __init__ (line 123) | def __init__(self, *args, **kwargs):
    method add_parser_arguments (line 139) | def add_parser_arguments(cls, add):
    method more_info (line 142) | def more_info(self):  # pylint: disable=missing-function-docstring
    method prepare (line 148) | def prepare(self):  # pylint: disable=missing-function-docstring
    method get_chall_pref (line 151) | def get_chall_pref(self, domain):
    method perform (line 155) | def perform(self, achalls):  # pylint: disable=missing-function-docstring
    method _try_perform_single (line 158) | def _try_perform_single(self, achall):
    method _perform_single (line 165) | def _perform_single(self, achall):
    method _perform_http_01 (line 170) | def _perform_http_01(self, achall):
    method cleanup (line 180) | def cleanup(self, achalls):  # pylint: disable=missing-function-docstring
  function _handle_perform_error (line 191) | def _handle_perform_error(error):

FILE: certbot/_internal/plugins/webroot.py
  class Authenticator (line 33) | class Authenticator(common.Plugin):
    method more_info (line 44) | def more_info(self):  # pylint: disable=missing-function-docstring
    method add_parser_arguments (line 48) | def add_parser_arguments(cls, add):
    method get_chall_pref (line 65) | def get_chall_pref(self, domain):  # pragma: no cover
    method __init__ (line 69) | def __init__(self, *args, **kwargs):
    method prepare (line 77) | def prepare(self):  # pylint: disable=missing-function-docstring
    method perform (line 80) | def perform(self, achalls):  # pylint: disable=missing-function-docstring
    method _set_webroots (line 87) | def _set_webroots(self, achalls):
    method _prompt_for_webroot (line 109) | def _prompt_for_webroot(self, domain, known_webroots):
    method _prompt_with_webroot_list (line 124) | def _prompt_with_webroot_list(self, domain, known_webroots):
    method _prompt_for_new_webroot (line 139) | def _prompt_for_new_webroot(self, domain, allowraise=False):  # pylint...
    method _create_challenge_dirs (line 152) | def _create_challenge_dirs(self):
    method _get_validation_path (line 196) | def _get_validation_path(self, root_path, achall):  # pylint: no-self-use
    method _perform_single (line 199) | def _perform_single(self, achall):
    method cleanup (line 218) | def cleanup(self, achalls):  # pylint: disable=missing-function-docstring
  class _WebrootMapAction (line 240) | class _WebrootMapAction(argparse.Action):
    method __call__ (line 243) | def __call__(self, parser, namespace, webroot_map, option_string=None):
  class _WebrootPathAction (line 250) | class _WebrootPathAction(argparse.Action):
    method __init__ (line 253) | def __init__(self, *args, **kwargs):
    method __call__ (line 257) | def __call__(self, parser, namespace, webroot_path, option_string=None):
  function _validate_webroot (line 275) | def _validate_webroot(webroot_path):

FILE: certbot/_internal/renewal.py
  function _reconstitute (line 45) | def _reconstitute(config, full_path):
  function _restore_webroot_config (line 102) | def _restore_webroot_config(config, renewalparams):
  function _restore_plugin_configs (line 119) | def _restore_plugin_configs(config, renewalparams):
  function restore_required_config_elements (line 162) | def restore_required_config_elements(config, renewalparams):
  function _restore_pref_challs (line 183) | def _restore_pref_challs(unused_name, value):
  function _restore_bool (line 205) | def _restore_bool(name, value):
  function _restore_int (line 224) | def _restore_int(name, value):
  function _restore_str (line 246) | def _restore_str(unused_name, value):
  function should_renew (line 259) | def should_renew(config, lineage):
  function _avoid_invalidating_lineage (line 274) | def _avoid_invalidating_lineage(config, lineage, original_server):
  function renew_cert (line 296) | def renew_cert(config, domains, le_client, lineage):
  function report (line 319) | def report(msgs, category):
  function _renew_describe_results (line 324) | def _renew_describe_results(config, renew_successes, renew_failures,
  function handle_renewal_request (line 374) | def handle_renewal_request(config):

FILE: certbot/_internal/reporter.py
  class Reporter (line 19) | class Reporter(object):
    method __init__ (line 36) | def __init__(self, config):
    method add_message (line 40) | def add_message(self, msg, priority, on_crash=True):
    method print_messages (line 56) | def print_messages(self):

FILE: certbot/_internal/storage.py
  function renewal_conf_files (line 36) | def renewal_conf_files(config):
  function renewal_file_for_certname (line 49) | def renewal_file_for_certname(config, certname):
  function cert_path_for_cert_name (line 58) | def cert_path_for_cert_name(config, cert_name):
  function config_with_defaults (line 72) | def config_with_defaults(config=None):
  function add_time_interval (line 79) | def add_time_interval(base_time, interval, textparser=parsedatetime.Cale...
  function write_renewal_config (line 103) | def write_renewal_config(o_filename, n_filename, archive_dir, target, re...
  function rename_renewal_config (line 155) | def rename_renewal_config(prev_name, new_name, cli_config):
  function update_configuration (line 173) | def update_configuration(lineagename, archive_dir, target, cli_config):
  function get_link_target (line 201) | def get_link_target(link):
  function _write_live_readme_to (line 222) | def _write_live_readme_to(readme_path, is_base_dir=False):
  function _relevant (line 243) | def _relevant(namespaces, option):
  function relevant_values (line 259) | def relevant_values(all_values):
  function lineagename_for_filename (line 281) | def lineagename_for_filename(config_filename):
  function renewal_filename_for_lineagename (line 289) | def renewal_filename_for_lineagename(config, lineagename):
  function _relpath_from_file (line 294) | def _relpath_from_file(archive_dir, from_file):
  function full_archive_path (line 298) | def full_archive_path(config_obj, cli_config, lineagename):
  function _full_live_path (line 311) | def _full_live_path(cli_config, lineagename):
  function delete_files (line 315) | def delete_files(config, certname):
  class RenewableCert (line 381) | class RenewableCert(interfaces.RenewableCert):
    method __init__ (line 416) | def __init__(self, config_filename, cli_config, update_symlinks=False):
    method key_path (line 469) | def key_path(self):
    method cert_path (line 474) | def cert_path(self):
    method chain_path (line 479) | def chain_path(self):
    method fullchain_path (line 484) | def fullchain_path(self):
    method lineagename (line 489) | def lineagename(self):
    method target_expiry (line 498) | def target_expiry(self):
    method archive_dir (line 507) | def archive_dir(self):
    method relative_archive_dir (line 512) | def relative_archive_dir(self, from_file):
    method is_test_cert (line 520) | def is_test_cert(self):
    method _check_symlinks (line 527) | def _check_symlinks(self):
    method _update_symlinks (line 539) | def _update_symlinks(self):
    method _consistent (line 550) | def _consistent(self):
    method _fix (line 618) | def _fix(self):
    method _previous_symlinks (line 636) | def _previous_symlinks(self):
    method _fix_symlinks (line 651) | def _fix_symlinks(self):
    method current_target (line 670) | def current_target(self, kind):
    method current_version (line 690) | def current_version(self, kind):
    method version (line 717) | def version(self, kind, version):
    method available_versions (line 737) | def available_versions(self, kind):
    method newest_available_version (line 758) | def newest_available_version(self, kind):
    method latest_common_version (line 770) | def latest_common_version(self):
    method next_free_version (line 785) | def next_free_version(self):
    method ensure_deployed (line 799) | def ensure_deployed(self):
    method has_pending_deployment (line 815) | def has_pending_deployment(self):
    method _update_link_to (line 829) | def _update_link_to(self, kind, version):
    method update_all_links_to (line 855) | def update_all_links_to(self, version):
    method names (line 872) | def names(self):
    method ocsp_revoked (line 886) | def ocsp_revoked(self, version):
    method autorenewal_is_enabled (line 914) | def autorenewal_is_enabled(self):
    method should_autorenew (line 926) | def should_autorenew(self):
    method new_lineage (line 964) | def new_lineage(cls, lineagename, cert, privkey, chain, cli_config):
    method save_successor (line 1058) | def save_successor(self, prior_version, new_cert,

FILE: certbot/_internal/updater.py
  function run_generic_updaters (line 11) | def run_generic_updaters(config, lineage, plugins):
  function run_renewal_deployer (line 38) | def run_renewal_deployer(config, lineage, installer):
  function _run_updaters (line 63) | def _run_updaters(lineage, installer, config):
  function _run_enhancement_updaters (line 80) | def _run_enhancement_updaters(lineage, installer, config):
  function _run_enhancement_deployers (line 102) | def _run_enhancement_deployers(lineage, installer, config):

FILE: certbot/achallenges.py
  class AnnotatedChallenge (line 30) | class AnnotatedChallenge(jose.ImmutableMap):
    method __getattr__ (line 42) | def __getattr__(self, name):
  class KeyAuthorizationAnnotatedChallenge (line 46) | class KeyAuthorizationAnnotatedChallenge(AnnotatedChallenge):
    method response_and_validation (line 50) | def response_and_validation(self, *args, **kwargs):
  class DNS (line 56) | class DNS(AnnotatedChallenge):

FILE: certbot/compat/_path.py
  function realpath (line 32) | def realpath(*unused_args, **unused_kwargs):

FILE: certbot/compat/filesystem.py
  function chmod (line 27) | def chmod(file_path, mode):
  function copy_ownership_and_apply_mode (line 57) | def copy_ownership_and_apply_mode(src, dst, mode, copy_user, copy_group):
  function check_mode (line 84) | def check_mode(file_path, mode):
  function check_owner (line 101) | def check_owner(file_path):
  function check_permissions (line 123) | def check_permissions(file_path, mode):
  function open (line 135) | def open(file_path, flags, mode=0o777):  # pylint: disable=redefined-bui...
  function makedirs (line 204) | def makedirs(file_path, mode=0o777):
  function mkdir (line 226) | def mkdir(file_path, mode=0o777):
  function replace (line 257) | def replace(src, dst):
  function realpath (line 273) | def realpath(file_path):
  function is_executable (line 310) | def is_executable(path):
  function has_world_permissions (line 324) | def has_world_permissions(path):
  function compute_private_key_mode (line 345) | def compute_private_key_mode(old_key, base_mode):
  function has_same_ownership (line 366) | def has_same_ownership(path1, path2):
  function has_min_permissions (line 391) | def has_min_permissions(path, min_mode):
  function _win_is_executable (line 436) | def _win_is_executable(path):
  function _apply_win_mode (line 452) | def _apply_win_mode(file_path, mode):
  function _generate_dacl (line 471) | def _generate_dacl(user_sid, mode):
  function _analyze_mode (line 505) | def _analyze_mode(mode):
  function _copy_win_ownership (line 520) | def _copy_win_ownership(src, dst):
  function _generate_windows_flags (line 532) | def _generate_windows_flags(rights_desc):
  function _check_win_mode (line 563) | def _check_win_mode(file_path, mode):
  function _compare_dacls (line 585) | def _compare_dacls(dacl1, dacl2):
  function _get_current_user (line 594) | def _get_current_user():

FILE: certbot/compat/misc.py
  function raise_for_non_administrative_windows_rights (line 25) | def raise_for_non_administrative_windows_rights():
  function readline_with_timeout (line 37) | def readline_with_timeout(timeout, prompt):
  function get_default_folder (line 79) | def get_default_folder(folder_type):
  function underscores_for_unsupported_characters_in_path (line 97) | def underscores_for_unsupported_characters_in_path(path):

FILE: certbot/compat/os.py
  function chmod (line 53) | def chmod(*unused_args, **unused_kwargs):
  function chown (line 62) | def chown(*unused_args, **unused_kwargs):
  function open (line 73) | def open(*unused_args, **unused_kwargs):
  function mkdir (line 81) | def mkdir(*unused_args, **unused_kwargs):
  function makedirs (line 92) | def makedirs(*unused_args, **unused_kwargs):
  function rename (line 100) | def rename(*unused_args, **unused_kwargs):
  function replace (line 108) | def replace(*unused_args, **unused_kwargs):
  function access (line 116) | def access(*unused_args, **unused_kwargs):
  function stat (line 125) | def stat(*unused_args, **unused_kwargs):
  function fstat (line 134) | def fstat(*unused_args, **unused_kwargs):

FILE: certbot/crypto_util.py
  function init_save_key (line 36) | def init_save_key(key_size, key_dir, keyname="key-certbot.pem"):
  function init_save_csr (line 72) | def init_save_csr(privkey, names, path):
  function valid_csr (line 107) | def valid_csr(csr):
  function csr_matches_pubkey (line 127) | def csr_matches_pubkey(csr, privkey):
  function import_csr_file (line 147) | def import_csr_file(csrfile, data):
  function make_key (line 176) | def make_key(bits):
  function valid_privkey (line 191) | def valid_privkey(privkey):
  function verify_renewable_cert (line 207) | def verify_renewable_cert(renewable_cert):
  function verify_renewable_cert_sig (line 225) | def verify_renewable_cert_sig(renewable_cert):
  function verify_signed_payload (line 249) | def verify_signed_payload(public_key, signature, payload, signature_hash...
  function verify_cert_matches_priv_key (line 280) | def verify_cert_matches_priv_key(cert_path, key_path):
  function verify_fullchain (line 302) | def verify_fullchain(renewable_cert):
  function pyopenssl_load_certificate (line 329) | def pyopenssl_load_certificate(data):
  function _load_cert_or_req (line 347) | def _load_cert_or_req(cert_or_req_str, load_func,
  function _get_sans_from_cert_or_req (line 356) | def _get_sans_from_cert_or_req(cert_or_req_str, load_func,
  function get_sans_from_cert (line 363) | def get_sans_from_cert(cert, typ=crypto.FILETYPE_PEM):
  function _get_names_from_cert_or_req (line 377) | def _get_names_from_cert_or_req(cert_or_req, load_func, typ):
  function _get_names_from_loaded_cert_or_req (line 382) | def _get_names_from_loaded_cert_or_req(loaded_cert_or_req):
  function get_names_from_cert (line 387) | def get_names_from_cert(csr, typ=crypto.FILETYPE_PEM):
  function dump_pyopenssl_chain (line 401) | def dump_pyopenssl_chain(chain, filetype=crypto.FILETYPE_PEM):
  function notBefore (line 413) | def notBefore(cert_path):
  function notAfter (line 425) | def notAfter(cert_path):
  function _notAfterBefore (line 437) | def _notAfterBefore(cert_path, method):
  function sha256sum (line 465) | def sha256sum(filename):
  function cert_and_chain_from_fullchain (line 481) | def cert_and_chain_from_fullchain(fullchain_pem):

FILE: certbot/display/ops.py
  function get_email (line 19) | def get_email(invalid=False, optional=True):
  function choose_account (line 73) | def choose_account(accounts):
  function choose_values (line 89) | def choose_values(values, question=None):
  function choose_names (line 104) | def choose_names(installer, question=None):
  function get_valid_domains (line 134) | def get_valid_domains(domains):
  function _sort_names (line 150) | def _sort_names(FQDNs):
  function _filter_names (line 161) | def _filter_names(names, override_question=None):
  function _choose_names_manually (line 183) | def _choose_names_manually(prompt_prefix=""):
  function success_installation (line 237) | def success_installation(domains):
  function success_renewal (line 252) | def success_renewal(domains):
  function success_revocation (line 268) | def success_revocation(cert_path):
  function _gen_ssl_lab_urls (line 282) | def _gen_ssl_lab_urls(domains):
  function _gen_https_names (line 291) | def _gen_https_names(domains):
  function _get_validated (line 312) | def _get_validated(method, validator, message, default=None, **kwargs):
  function validated_input (line 339) | def validated_input(validator, *args, **kwargs):
  function validated_directory (line 354) | def validated_directory(validator, *args, **kwargs):

FILE: certbot/display/util.py
  function _wrap_lines (line 37) | def _wrap_lines(msg):
  function input_with_timeout (line 59) | def input_with_timeout(prompt=None, timeout=36000.0):
  class FileDisplay (line 90) | class FileDisplay(object):
    method __init__ (line 94) | def __init__(self, outfile, force_interactive):
    method notification (line 100) | def notification(self, message, pause=True,
    method menu (line 124) | def menu(self, message, choices, ok_label=None, cancel_label=None,  # ...
    method input (line 157) | def input(self, message, default=None,
    method yesno (line 184) | def yesno(self, message, yes_label="Yes", no_label="No", default=None,
    method checklist (line 226) | def checklist(self, message, tags, default=None,
    method _return_default (line 267) | def _return_default(self, prompt, default, cli_flag, force_interactive):
    method _can_interact (line 296) | def _can_interact(self, force_interactive):
    method directory_select (line 318) | def directory_select(self, message, default=None, cli_flag=None,
    method _scrub_checklist_input (line 336) | def _scrub_checklist_input(self, indices, tags):
    method _print_menu (line 362) | def _print_menu(self, message, choices):
    method _get_valid_int_ans (line 391) | def _get_valid_int_ans(self, max_):
  function assert_valid_call (line 428) | def assert_valid_call(prompt, default, cli_flag, force_interactive):
  class NoninteractiveDisplay (line 447) | class NoninteractiveDisplay(object):
    method __init__ (line 450) | def __init__(self, outfile, *unused_args, **unused_kwargs):
    method _interaction_fail (line 454) | def _interaction_fail(self, message, cli_flag, extra=""):
    method notification (line 464) | def notification(self, message, pause=False, wrap=True, **unused_kwarg...
    method menu (line 479) | def menu(self, message, choices, ok_label=None, cancel_label=None,
    method input (line 503) | def input(self, message, default=None, cli_flag=None, **unused_kwargs):
    method yesno (line 519) | def yesno(self, message, yes_label=None, no_label=None,  # pylint: dis...
    method checklist (line 535) | def checklist(self, message, tags, default=None,
    method directory_select (line 553) | def directory_select(self, message, default=None,
  function separate_list_input (line 574) | def separate_list_input(input_):
  function _parens_around_char (line 589) | def _parens_around_char(label):

FILE: certbot/errors.py
  class Error (line 4) | class Error(Exception):
  class AccountStorageError (line 8) | class AccountStorageError(Error):
  class AccountNotFound (line 12) | class AccountNotFound(AccountStorageError):
  class ReverterError (line 16) | class ReverterError(Error):
  class SubprocessError (line 20) | class SubprocessError(Error):
  class CertStorageError (line 24) | class CertStorageError(Error):
  class HookCommandNotFound (line 28) | class HookCommandNotFound(Error):
  class SignalExit (line 32) | class SignalExit(Error):
  class OverlappingMatchFound (line 35) | class OverlappingMatchFound(Error):
  class LockError (line 38) | class LockError(Error):
  class AuthorizationError (line 43) | class AuthorizationError(Error):
  class FailedChallenges (line 47) | class FailedChallenges(AuthorizationError):
    method __init__ (line 53) | def __init__(self, failed_achalls):
    method __str__ (line 58) | def __str__(self):
  class PluginError (line 66) | class PluginError(Error):
  class PluginEnhancementAlreadyPresent (line 70) | class PluginEnhancementAlreadyPresent(Error):
  class PluginSelectionError (line 74) | class PluginSelectionError(Error):
  class NoInstallationError (line 78) | class NoInstallationError(PluginError):
  class MisconfigurationError (line 82) | class MisconfigurationError(PluginError):
  class NotSupportedError (line 86) | class NotSupportedError(PluginError):
  class PluginStorageError (line 90) | class PluginStorageError(PluginError):
  class StandaloneBindError (line 94) | class StandaloneBindError(Error):
    method __init__ (line 97) | def __init__(self, socket_error, port):
  class ConfigurationError (line 104) | class ConfigurationError(Error):
  class MissingCommandlineFlag (line 109) | class MissingCommandlineFlag(Error):

FILE: certbot/interfaces.py
  class AccountStorage (line 11) | class AccountStorage(object):
    method find_all (line 15) | def find_all(self):  # pragma: no cover
    method load (line 25) | def load(self, account_id):  # pragma: no cover
    method save (line 35) | def save(self, account, client):  # pragma: no cover
  class IPluginFactory (line 44) | class IPluginFactory(zope.interface.Interface):
    method __call__ (line 76) | def __call__(config, name):  # pylint: disable=signature-differs
    method inject_parser_options (line 84) | def inject_parser_options(parser, name):
  class IPlugin (line 99) | class IPlugin(zope.interface.Interface):
    method prepare (line 102) | def prepare():  # type: ignore
    method more_info (line 121) | def more_info():  # type: ignore
  class IAuthenticator (line 132) | class IAuthenticator(IPlugin):
    method get_chall_pref (line 140) | def get_chall_pref(domain):
    method perform (line 153) | def perform(achalls):
    method cleanup (line 173) | def cleanup(achalls):
  class IConfig (line 188) | class IConfig(zope.interface.Interface):
  class IInstaller (line 257) | class IInstaller(IPlugin):
    method get_all_names (line 272) | def get_all_names():  # type: ignore
    method deploy_cert (line 279) | def deploy_cert(domain, cert_path, key_path, chain_path, fullchain_path):
    method enhance (line 293) | def enhance(domain, enhancement, options=None):
    method supported_enhancements (line 309) | def supported_enhancements():  # type: ignore
    method save (line 318) | def save(title=None, temporary=False):
    method rollback_checkpoints (line 340) | def rollback_checkpoints(rollback=1):
    method recovery_routine (line 347) | def recovery_routine():  # type: ignore
    method config_test (line 358) | def config_test():  # type: ignore
    method restart (line 365) | def restart():  # type: ignore
  class IDisplay (line 373) | class IDisplay(zope.interface.Interface):
    method notification (line 377) | def notification(message, pause, wrap=True, force_interactive=False):
    method menu (line 389) | def menu(message, choices, ok_label=None,
    method input (line 419) | def input(message, default=None, cli_args=None, force_interactive=False):
    method yesno (line 440) | def yesno(message, yes_label="Yes", no_label="No", default=None,
    method checklist (line 463) | def checklist(message, tags, default=None, cli_args=None, force_intera...
    method directory_select (line 486) | def directory_select(self, message, default=None,
  class IReporter (line 509) | class IReporter(zope.interface.Interface):
    method add_message (line 519) | def add_message(self, msg, priority, on_crash=True):
    method print_messages (line 532) | def print_messages(self):
  class RenewableCert (line 537) | class RenewableCert(object):
    method cert_path (line 541) | def cert_path(self):
    method key_path (line 549) | def key_path(self):
    method chain_path (line 557) | def chain_path(self):
    method fullchain_path (line 565) | def fullchain_path(self):
    method lineagename (line 575) | def lineagename(self):
    method names (line 583) | def names(self):
  class GenericUpdater (line 603) | class GenericUpdater(object):
    method generic_updates (line 619) | def generic_updates(self, lineage, *args, **kwargs):
  class RenewDeployer (line 636) | class RenewDeployer(object):
    method renew_deploy (line 648) | def renew_deploy(self, lineage, *args, **kwargs):

FILE: certbot/main.py
  function main (line 5) | def main(cli_args=None):

FILE: certbot/ocsp.py
  class RevocationChecker (line 38) | class RevocationChecker(object):
    method __init__ (line 41) | def __init__(self, enforce_openssl_binary_usage=False):
    method ocsp_revoked (line 60) | def ocsp_revoked(self, cert):
    method ocsp_revoked_by_paths (line 73) | def ocsp_revoked_by_paths(self, cert_path, chain_path):
    method _check_ocsp_openssl_bin (line 102) | def _check_ocsp_openssl_bin(self, cert_path, chain_path, host, url):
  function _determine_ocsp_server (line 124) | def _determine_ocsp_server(cert_path):
  function _check_ocsp_cryptography (line 155) | def _check_ocsp_cryptography(cert_path, chain_path, url):
  function _check_ocsp_response (line 204) | def _check_ocsp_response(response_ocsp, request_ocsp, issuer_cert, cert_...
  function _check_ocsp_response_signature (line 238) | def _check_ocsp_response_signature(response_ocsp, issuer_cert, cert_path):
  function _translate_ocsp_query (line 287) | def _translate_ocsp_query(cert_path, ocsp_output, ocsp_errors):

FILE: certbot/plugins/common.py
  function option_namespace (line 27) | def option_namespace(name):
  function dest_namespace (line 32) | def dest_namespace(name):
  class Plugin (line 45) | class Plugin(object):
    method __init__ (line 50) | def __init__(self, config, name):
    method add_parser_arguments (line 55) | def add_parser_arguments(cls, add):
    method inject_parser_options (line 69) | def inject_parser_options(cls, parser, name):
    method option_namespace (line 83) | def option_namespace(self):
    method option_name (line 87) | def option_name(self, name):
    method dest_namespace (line 92) | def dest_namespace(self):
    method dest (line 96) | def dest(self, var):
    method conf (line 102) | def conf(self, var):
  class Installer (line 107) | class Installer(Plugin):
    method __init__ (line 113) | def __init__(self, *args, **kwargs):
    method add_to_checkpoint (line 118) | def add_to_checkpoint(self, save_files, save_notes, temporary=False):
    method finalize_checkpoint (line 140) | def finalize_checkpoint(self, title):
    method recovery_routine (line 153) | def recovery_routine(self):
    method revert_temporary_config (line 166) | def revert_temporary_config(self):
    method rollback_checkpoints (line 177) | def rollback_checkpoints(self, rollback=1):
    method ssl_dhparams (line 192) | def ssl_dhparams(self):
    method updated_ssl_dhparams_digest (line 197) | def updated_ssl_dhparams_digest(self):
    method install_ssl_dhparams (line 201) | def install_ssl_dhparams(self):
  class Addr (line 210) | class Addr(object):
    method __init__ (line 217) | def __init__(self, tup, ipv6=False):
    method fromstring (line 222) | def fromstring(cls, str_addr):
    method __str__ (line 236) | def __str__(self):
    method normalized_tuple (line 241) | def normalized_tuple(self):
    method __eq__ (line 248) | def __eq__(self, other):
    method __hash__ (line 256) | def __hash__(self):
    method get_addr (line 259) | def get_addr(self):
    method get_port (line 263) | def get_port(self):
    method get_addr_obj (line 267) | def get_addr_obj(self, port):
    method _normalize_ipv6 (line 271) | def _normalize_ipv6(self, addr):
    method get_ipv6_exploded (line 277) | def get_ipv6_exploded(self):
    method _explode_ipv6 (line 283) | def _explode_ipv6(self, addr):
  class ChallengePerformer (line 308) | class ChallengePerformer(object):
    method __init__ (line 320) | def __init__(self, configurator):
    method add_chall (line 325) | def add_chall(self, achall, idx=None):
    method perform (line 337) | def perform(self):
  function install_version_controlled_file (line 348) | def install_version_controlled_file(dest_path, digest_path, src_path, al...
  function dir_setup (line 398) | def dir_setup(test_dir, pkg):  # pragma: no cover
  class _TLSSNI01DeprecationModule (line 431) | class _TLSSNI01DeprecationModule(object):
    method __init__ (line 436) | def __init__(self, module):
    method __getattr__ (line 439) | def __getattr__(self, attr):
    method __setattr__ (line 445) | def __setattr__(self, attr, value):  # pragma: no cover
    method __delattr__ (line 448) | def __delattr__(self, attr):  # pragma: no cover
    method __dir__ (line 451) | def __dir__(self):  # pragma: no cover

FILE: certbot/plugins/dns_common.py
  class DNSAuthenticator (line 24) | class DNSAuthenticator(common.Plugin):
    method __init__ (line 27) | def __init__(self, config, name):
    method add_parser_arguments (line 33) | def add_parser_arguments(cls, add, default_propagation_seconds=10):  #...
    method get_chall_pref (line 40) | def get_chall_pref(self, unused_domain):  # pylint: disable=missing-fu...
    method prepare (line 43) | def prepare(self): # pylint: disable=missing-function-docstring
    method perform (line 46) | def perform(self, achalls): # pylint: disable=missing-function-docstring
    method cleanup (line 69) | def cleanup(self, achalls):  # pylint: disable=missing-function-docstring
    method _setup_credentials (line 79) | def _setup_credentials(self):  # pragma: no cover
    method _perform (line 86) | def _perform(self, domain, validation_name, validation):  # pragma: no...
    method _cleanup (line 98) | def _cleanup(self, domain, validation_name, validation):  # pragma: no...
    method _configure (line 110) | def _configure(self, key, label):
    method _configure_file (line 126) | def _configure_file(self, key, label, validator=None):
    method _configure_credentials (line 142) | def _configure_credentials(self, key, label, required_variables=None, ...
    method _prompt_for_data (line 180) | def _prompt_for_data(label):
    method _prompt_for_file (line 203) | def _prompt_for_file(label, validator=None):
  class CredentialsConfiguration (line 236) | class CredentialsConfiguration(object):
    method __init__ (line 239) | def __init__(self, filename, mapper=lambda x: x):
    method require (line 255) | def require(self, required_variables):
    method conf (line 280) | def conf(self, var):
    method _has (line 290) | def _has(self, var):
    method _get (line 293) | def _get(self, var):
  function validate_file (line 297) | def validate_file(filename):
  function validate_file_permissions (line 307) | def validate_file_permissions(filename):
  function base_domain_name_guesses (line 316) | def base_domain_name_guesses(domain):

FILE: certbot/plugins/dns_common_lexicon.py
  class LexiconClient (line 26) | class LexiconClient(object):
    method __init__ (line 31) | def __init__(self):
    method add_txt_record (line 34) | def add_txt_record(self, domain, record_name, record_content):
    method del_txt_record (line 51) | def del_txt_record(self, domain, record_name, record_content):
    method _find_domain_id (line 72) | def _find_domain_id(self, domain):
    method _handle_http_error (line 108) | def _handle_http_error(self, e, domain_name):
    method _handle_general_error (line 112) | def _handle_general_error(self, e, domain_name):
  function build_lexicon_config (line 119) | def build_lexicon_config(lexicon_provider_name, lexicon_options, provide...

FILE: certbot/plugins/dns_test_common.py
  class BaseAuthenticatorTest (line 18) | class BaseAuthenticatorTest(object):
    method test_more_info (line 30) | def test_more_info(self):
    method test_get_chall_pref (line 33) | def test_get_chall_pref(self):
    method test_parser_arguments (line 36) | def test_parser_arguments(self):
  function write (line 43) | def write(values, path):

FILE: certbot/plugins/dns_test_common_lexicon.py
  class BaseLexiconAuthenticatorTest (line 18) | class BaseLexiconAuthenticatorTest(dns_test_common.BaseAuthenticatorTest):
    method test_perform (line 20) | def test_perform(self):
    method test_cleanup (line 26) | def test_cleanup(self):
  class BaseLexiconClientTest (line 34) | class BaseLexiconClientTest(object):
    method test_add_txt_record (line 44) | def test_add_txt_record(self):
    method test_add_txt_record_try_twice_to_find_domain (line 51) | def test_add_txt_record_try_twice_to_find_domain(self):
    method test_add_txt_record_fail_to_find_domain (line 60) | def test_add_txt_record_fail_to_find_domain(self):
    method test_add_txt_record_fail_to_authenticate (line 69) | def test_add_txt_record_fail_to_authenticate(self):
    method test_add_txt_record_fail_to_authenticate_with_unknown_error (line 76) | def test_add_txt_record_fail_to_authenticate_with_unknown_error(self):
    method test_add_txt_record_error_finding_domain (line 83) | def test_add_txt_record_error_finding_domain(self):
    method test_add_txt_record_error_adding_record (line 90) | def test_add_txt_record_error_adding_record(self):
    method test_del_txt_record (line 97) | def test_del_txt_record(self):
    method test_del_txt_record_fail_to_find_domain (line 104) | def test_del_txt_record_fail_to_find_domain(self):
    method test_del_txt_record_fail_to_authenticate (line 111) | def test_del_txt_record_fail_to_authenticate(self):
    method test_del_txt_record_fail_to_authenticate_with_unknown_error (line 116) | def test_del_txt_record_fail_to_authenticate_with_unknown_error(self):
    method test_del_txt_record_error_finding_domain (line 121) | def test_del_txt_record_error_finding_domain(self):
    method test_del_txt_record_error_deleting_record (line 126) | def test_del_txt_record_error_deleting_record(self):

FILE: certbot/plugins/enhancements.py
  function enabled_enhancements (line 22) | def enabled_enhancements(config):
  function are_requested (line 33) | def are_requested(config):
  function are_supported (line 43) | def are_supported(config, installer):
  function enable (line 62) | def enable(lineage, domains, installer, config):
  function populate_cli (line 81) | def populate_cli(add):
  class AutoHSTSEnhancement (line 95) | class AutoHSTSEnhancement(object):
    method update_autohsts (line 122) | def update_autohsts(self, lineage, *args, **kwargs):
    method deploy_autohsts (line 136) | def deploy_autohsts(self, lineage, *args, **kwargs):
    method enable_autohsts (line 146) | def enable_autohsts(self, lineage, domains, *args, **kwargs):

FILE: certbot/plugins/storage.py
  class PluginStorage (line 14) | class PluginStorage(object):
    method __init__ (line 17) | def __init__(self, config, classkey):
    method _initialize_storage (line 32) | def _initialize_storage(self):
    method _load (line 40) | def _load(self):
    method save (line 70) | def save(self):
    method put (line 100) | def put(self, key, value):
    method fetch (line 113) | def fetch(self, key):

FILE: certbot/plugins/util.py
  function get_prefixes (line 11) | def get_prefixes(path):
  function path_surgery (line 32) | def path_surgery(cmd):

FILE: certbot/reverter.py
  class Reverter (line 21) | class Reverter(object):
    method __init__ (line 63) | def __init__(self, config):
    method revert_temporary_config (line 69) | def revert_temporary_config(self):
    method rollback_checkpoints (line 89) | def rollback_checkpoints(self, rollback=1):
    method add_to_temp_checkpoint (line 131) | def add_to_temp_checkpoint(self, save_files, save_notes):
    method add_to_checkpoint (line 141) | def add_to_checkpoint(self, save_files, save_notes):
    method _add_to_checkpoint_dir (line 153) | def _add_to_checkpoint_dir(self, cp_dir, save_files, save_notes):
    method _read_and_append (line 198) | def _read_and_append(self, filepath):
    method _recover_checkpoint (line 214) | def _recover_checkpoint(self, cp_dir):
    method _run_undo_commands (line 253) | def _run_undo_commands(self, filepath):
    method _check_tempfile_saves (line 269) | def _check_tempfile_saves(self, save_files):
    method register_file_creation (line 299) | def register_file_creation(self, temporary, *files):
    method register_undo_command (line 338) | def register_undo_command(self, temporary, command):
    method _get_cp_dir (line 376) | def _get_cp_dir(self, temporary):
    method recovery_routine (line 388) | def recovery_routine(self):
    method _remove_contained_files (line 416) | def _remove_contained_files(self, file_list):
    method finalize_checkpoint (line 454) | def finalize_checkpoint(self, title):
    method _checkpoint_timestamp (line 495) | def _checkpoint_timestamp(self):
    method _timestamp_progress_dir (line 516) | def _timestamp_progress_dir(self):

FILE: certbot/tests/acme_util.py
  function gen_combos (line 24) | def gen_combos(challbs):
  function chall_to_challb (line 30) | def chall_to_challb(chall, status):
  function gen_authzr (line 60) | def gen_authzr(authz_status, domain, challs, statuses, combos=True):

FILE: certbot/tests/util.py
  function vector_path (line 30) | def vector_path(*names):
  function load_vector (line 36) | def load_vector(*names):
  function _guess_loader (line 50) | def _guess_loader(filename, loader_pem, loader_der):
  function load_cert (line 59) | def load_cert(*names):
  function load_csr (line 66) | def load_csr(*names):
  function load_comparable_csr (line 73) | def load_comparable_csr(*names):
  function load_rsa_private_key (line 78) | def load_rsa_private_key(*names):
  function load_pyopenssl_private_key (line 86) | def load_pyopenssl_private_key(*names):
  function make_lineage (line 93) | def make_lineage(config_dir, testfile):
  function patch_get_utility (line 137) | def patch_get_utility(target='zope.component.getUtility'):
  function patch_get_utility_with_stdout (line 152) | def patch_get_utility_with_stdout(target='zope.component.getUtility',
  class FreezableMock (line 176) | class FreezableMock(object):
    method __init__ (line 189) | def __init__(self, frozen=False, func=None, return_value=mock.sentinel...
    method freeze (line 197) | def freeze(self):
    method __call__ (line 201) | def __call__(self, *args, **kwargs):
    method __getattribute__ (line 206) | def __getattribute__(self, name):
    method __setattr__ (line 219) | def __setattr__(self, name, value):
  function _create_get_utility_mock (line 244) | def _create_get_utility_mock():
  function _create_get_utility_mock_with_stdout (line 255) | def _create_get_utility_mock_with_stdout(stdout):
  function _assert_valid_call (line 286) | def _assert_valid_call(*args, **kwargs):
  class TempDirTestCase (line 297) | class TempDirTestCase(unittest.TestCase):
    method setUp (line 300) | def setUp(self):
    method tearDown (line 304) | def tearDown(self):
  class ConfigTestCase (line 319) | class ConfigTestCase(TempDirTestCase):
    method setUp (line 321) | def setUp(self):
  function _handle_lock (line 336) | def _handle_lock(event_in, event_out, path):
  function lock_and_call (line 355) | def lock_and_call(callback, path_to_lock):
  function skip_on_windows (line 381) | def skip_on_windows(reason):
  function temp_join (line 389) | def temp_join(path):

FILE: certbot/util.py
  function run_script (line 64) | def run_script(params, log=logger.error):
  function exe_exists (line 94) | def exe_exists(exe):
  function lock_dir_until_exit (line 113) | def lock_dir_until_exit(dir_path):
  function _release_locks (line 128) | def _release_locks():
  function set_up_core_dir (line 138) | def set_up_core_dir(directory, mode, strict):
  function make_or_verify_dir (line 157) | def make_or_verify_dir(directory, mode=0o755, strict=False):
  function safe_open (line 184) | def safe_open(path, mode="w", chmod=None):
  function _unique_file (line 201) | def _unique_file(path, filename_pat, count, chmod, mode):
  function unique_file (line 214) | def unique_file(path, chmod=0o777, mode="w"):
  function unique_lineage_name (line 230) | def unique_lineage_name(path, filename, chmod=0o644, mode="w"):
  function safely_remove (line 257) | def safely_remove(path):
  function get_filtered_names (line 266) | def get_filtered_names(all_names):
  function get_os_info (line 283) | def get_os_info():
  function get_os_info_ua (line 293) | def get_os_info_ua():
  function get_systemd_os_like (line 307) | def get_systemd_os_like():
  function get_var_from_file (line 320) | def get_var_from_file(varname, filepath="/etc/os-release"):
  function _normalize_string (line 342) | def _normalize_string(orig):
  function get_python_os_info (line 349) | def get_python_os_info(pretty=False):
  function safe_email (line 405) | def safe_email(email):
  class _ShowWarning (line 413) | class _ShowWarning(argparse.Action):
    method __call__ (line 415) | def __call__(self, unused1, unused2, unused3, option_string=None):
  function add_deprecated_argument (line 419) | def add_deprecated_argument(add_argument, argument_name, nargs):
  function enforce_le_validity (line 445) | def enforce_le_validity(domain):
  function enforce_domain_sanity (line 477) | def enforce_domain_sanity(domain):
  function is_wildcard_domain (line 542) | def is_wildcard_domain(domain):
  function get_strict_version (line 560) | def get_strict_version(normalized):
  function is_staging (line 573) | def is_staging(srv):
  function atexit_register (line 584) | def atexit_register(func, *args, **kwargs):
  function _atexit_call (line 596) | def _atexit_call(func, *args, **kwargs):

FILE: examples/plugins/certbot_example_plugins.py
  class Authenticator (line 14) | class Authenticator(common.Plugin):
  class Installer (line 25) | class Installer(common.Plugin):

FILE: setup.py
  function read_file (line 20) | def read_file(filename, encoding='utf8'):
  class PyTest (line 102) | class PyTest(TestCommand):
    method initialize_options (line 105) | def initialize_options(self):
    method run_tests (line 109) | def run_tests(self):

FILE: tests/account_test.py
  class AccountTest (line 20) | class AccountTest(unittest.TestCase):
    method setUp (line 23) | def setUp(self):
    method test_init (line 39) | def test_init(self):
    method test_id (line 44) | def test_id(self):
    method test_slug (line 48) | def test_slug(self):
    method test_repr (line 52) | def test_repr(self):
  class ReportNewAccountTest (line 56) | class ReportNewAccountTest(test_util.ConfigTestCase):
    method _call (line 59) | def _call(self):
    method test_no_reporter (line 64) | def test_no_reporter(self, mock_zope):
    method test_it (line 69) | def test_it(self, mock_zope):
  class AccountMemoryStorageTest (line 75) | class AccountMemoryStorageTest(unittest.TestCase):
    method setUp (line 78) | def setUp(self):
    method test_it (line 82) | def test_it(self):
  class AccountFileStorageTest (line 93) | class AccountFileStorageTest(test_util.ConfigTestCase):
    method setUp (line 96) | def setUp(self):
    method test_init_creates_dir (line 112) | def test_init_creates_dir(self):
    method test_save_and_restore (line 116) | def test_save_and_restore(self):
    method test_save_and_restore_old_version (line 130) | def test_save_and_restore_old_version(self):
    method test_save_regr (line 138) | def test_save_regr(self):
    method test_find_all (line 148) | def test_find_all(self):
    method test_find_all_none_empty_list (line 152) | def test_find_all_none_empty_list(self):
    method test_find_all_accounts_dir_absent (line 155) | def test_find_all_accounts_dir_absent(self):
    method test_find_all_load_skips (line 159) | def test_find_all_load_skips(self):
    method test_load_non_existent_raises_error (line 167) | def test_load_non_existent_raises_error(self):
    method _set_server (line 170) | def _set_server(self, server):
    method test_find_all_neither_exists (line 175) | def test_find_all_neither_exists(self):
    method test_find_all_find_before_save (line 181) | def test_find_all_find_before_save(self):
    method test_find_all_save_before_find (line 192) | def test_find_all_save_before_find(self):
    method test_find_all_server_downgrade (line 202) | def test_find_all_server_downgrade(self):
    method test_upgrade_version_staging (line 211) | def test_upgrade_version_staging(self):
    method test_upgrade_version_production (line 217) | def test_upgrade_version_production(self):
    method test_corrupted_account (line 224) | def test_corrupted_account(self, mock_rmdir):
    method test_upgrade_load (line 234) | def test_upgrade_load(self):
    method test_upgrade_load_single_account (line 242) | def test_upgrade_load_single_account(self):
    method test_load_ioerror (line 250) | def test_load_ioerror(self):
    method test_save_ioerrors (line 258) | def test_save_ioerrors(self):
    method test_delete (line 266) | def test_delete(self):
    method test_delete_no_account (line 271) | def test_delete_no_account(self):
    method _assert_symlinked_account_removed (line 274) | def _assert_symlinked_account_removed(self):
    method _test_delete_folders (line 283) | def _test_delete_folders(self, server_url):
    method test_delete_folders_up (line 300) | def test_delete_folders_up(self):
    method test_delete_folders_down (line 304) | def test_delete_folders_down(self):
    method _set_server_and_stop_symlink (line 308) | def _set_server_and_stop_symlink(self, server_path):
    method test_delete_shared_account_up (line 313) | def test_delete_shared_account_up(self):
    method test_delete_shared_account_down (line 317) | def test_delete_shared_account_down(self):

FILE: tests/auth_handler_test.py
  class ChallengeFactoryTest (line 21) | class ChallengeFactoryTest(unittest.TestCase):
    method setUp (line 24) | def setUp(self):
    method test_all (line 34) | def test_all(self):
    method test_one_http (line 41) | def test_one_http(self):
    method test_unrecognized (line 47) | def test_unrecognized(self):
  class HandleAuthorizationsTest (line 57) | class HandleAuthorizationsTest(unittest.TestCase):
    method setUp (line 64) | def setUp(self):
    method tearDown (line 89) | def tearDown(self):
    method _test_name1_http_01_1_common (line 92) | def _test_name1_http_01_1_common(self, combos):
    method test_name1_http_01_1_acme_1 (line 117) | def test_name1_http_01_1_acme_1(self):
    method test_name1_http_01_1_acme_2 (line 120) | def test_name1_http_01_1_acme_2(self):
    method test_name1_http_01_1_dns_1_acme_1 (line 124) | def test_name1_http_01_1_dns_1_acme_1(self):
    method test_name1_http_01_1_dns_1_acme_2 (line 144) | def test_name1_http_01_1_dns_1_acme_2(self):
    method _test_name3_http_01_3_common (line 165) | def _test_name3_http_01_3_common(self, combos):
    method test_name3_http_01_3_common_acme_1 (line 186) | def test_name3_http_01_3_common_acme_1(self):
    method test_name3_http_01_3_common_acme_2 (line 189) | def test_name3_http_01_3_common_acme_2(self):
    method test_debug_challenges (line 193) | def test_debug_challenges(self):
    method test_perform_failure (line 206) | def test_perform_failure(self):
    method test_max_retries_exceeded (line 215) | def test_max_retries_exceeded(self):
    method test_no_domains (line 227) | def test_no_domains(self):
    method _test_preferred_challenge_choice_common (line 231) | def _test_preferred_challenge_choice_common(self, combos):
    method test_preferred_challenge_choice_common_acme_1 (line 247) | def test_preferred_challenge_choice_common_acme_1(self):
    method test_preferred_challenge_choice_common_acme_2 (line 250) | def test_preferred_challenge_choice_common_acme_2(self):
    method _test_preferred_challenges_not_supported_common (line 254) | def _test_preferred_challenges_not_supported_common(self, combos):
    method test_preferred_challenges_not_supported_acme_1 (line 261) | def test_preferred_challenges_not_supported_acme_1(self):
    method test_preferred_challenges_not_supported_acme_2 (line 264) | def test_preferred_challenges_not_supported_acme_2(self):
    method test_dns_only_challenge_not_supported (line 268) | def test_dns_only_challenge_not_supported(self):
    method test_perform_error (line 274) | def test_perform_error(self):
    method test_answer_error (line 285) | def test_answer_error(self):
    method test_incomplete_authzr_error (line 297) | def test_incomplete_authzr_error(self):
    method test_best_effort (line 310) | def test_best_effort(self):
    method test_validated_challenge_not_rerun (line 343) | def test_validated_challenge_not_rerun(self):
    method test_valid_authzrs_deactivated (line 364) | def test_valid_authzrs_deactivated(self):
  function _gen_mock_on_poll (line 398) | def _gen_mock_on_poll(status=messages.STATUS_VALID, retry=0, wait_value=1):
  class ChallbToAchallTest (line 414) | class ChallbToAchallTest(unittest.TestCase):
    method _call (line 417) | def _call(self, challb):
    method test_it (line 421) | def test_it(self):
  class GenChallengePathTest (line 430) | class GenChallengePathTest(unittest.TestCase):
    method setUp (line 436) | def setUp(self):
    method tearDown (line 439) | def tearDown(self):
    method _call (line 443) | def _call(cls, challbs, preferences, combinations):
    method test_common_case (line 447) | def test_common_case(self):
    method test_not_supported (line 460) | def test_not_supported(self):
  class ReportFailedAuthzrsTest (line 473) | class ReportFailedAuthzrsTest(unittest.TestCase):
    method setUp (line 477) | def setUp(self):
    method test_same_error_and_domain (line 505) | def test_same_error_and_domain(self, mock_zope):
    method test_different_errors_and_domains (line 514) | def test_different_errors_and_domains(self, mock_zope):
  function gen_auth_resp (line 521) | def gen_auth_resp(chall_list):
  function gen_dom_authzr (line 527) | def gen_dom_authzr(domain, challs, combos=True):

FILE: tests/cert_manager_test.py
  class BaseCertManagerTest (line 22) | class BaseCertManagerTest(test_util.ConfigTestCase):
    method setUp (line 25) | def setUp(self):
    method _set_up_config (line 44) | def _set_up_config(self, domain, custom_archive):
  class UpdateLiveSymlinksTest (line 66) | class UpdateLiveSymlinksTest(BaseCertManagerTest):
    method test_update_live_symlinks (line 69) | def test_update_live_symlinks(self):
  class DeleteTest (line 105) | class DeleteTest(storage_test.BaseRenewableCertTest):
    method _call (line 109) | def _call(self):
    method test_delete_from_config (line 116) | def test_delete_from_config(self, mock_delete_files, mock_lineage_for_...
    method test_delete_interactive_single (line 127) | def test_delete_interactive_single(self, mock_delete_files, mock_linea...
    method test_delete_interactive_multiple (line 138) | def test_delete_interactive_multiple(self, mock_delete_files, mock_lin...
  class CertificatesTest (line 149) | class CertificatesTest(BaseCertManagerTest):
    method _certificates (line 152) | def _certificates(self, *args, **kwargs):
    method test_certificates_parse_fail (line 158) | def test_certificates_parse_fail(self, mock_utility, mock_logger):
    method test_certificates_quiet (line 165) | def test_certificates_quiet(self, mock_utility, mock_logger):
    method test_certificates_parse_success (line 176) | def test_certificates_parse_success(self, mock_report, mock_renewable_...
    method test_certificates_no_files (line 188) | def test_certificates_no_files(self, mock_utility, mock_logger):
    method test_report_human_readable (line 204) | def test_report_human_readable(self, mock_revoked):
  class SearchLineagesTest (line 272) | class SearchLineagesTest(BaseCertManagerTest):
    method test_cert_storage_error (line 278) | def test_cert_storage_error(self, mock_renewable_cert, mock_renewal_co...
  class LineageForCertnameTest (line 288) | class LineageForCertnameTest(BaseCertManagerTest):
    method test_found_match (line 294) | def test_found_match(self, mock_renewable_cert, mock_renewal_conf_file,
    method test_no_match (line 305) | def test_no_match(self, mock_renewal_conf_file, mock_make_or_verify_dir):
    method test_no_renewal_file (line 313) | def test_no_renewal_file(self, mock_renewal_conf_file, mock_make_or_ve...
  class DomainsForCertnameTest (line 320) | class DomainsForCertnameTest(BaseCertManagerTest):
    method test_found_match (line 326) | def test_found_match(self, mock_renewable_cert, mock_renewal_conf_file,
    method test_no_match (line 340) | def test_no_match(self, mock_renewal_conf_file, mock_make_or_verify_dir):
  class RenameLineageTest (line 347) | class RenameLineageTest(BaseCertManagerTest):
    method setUp (line 350) | def setUp(self):
    method _call (line 355) | def _call(self, *args, **kwargs):
    method test_no_certname (line 361) | def test_no_certname(self, mock_get_utility, mock_renewal_conf_files):
    method test_no_new_certname (line 378) | def test_no_new_certname(self, mock_get_utility):
    method test_no_existing_certname (line 391) | def test_no_existing_certname(self, mock_lineage_for_certname, unused_...
    method test_rename_cert (line 400) | def test_rename_cert(self, mock_check, unused_get_utility):
    method test_rename_cert_interactive_certname (line 410) | def test_rename_cert_interactive_certname(self, mock_check, mock_get_u...
    method test_rename_cert_bad_new_certname (line 423) | def test_rename_cert_bad_new_certname(self, mock_check, unused_get_uti...
  class DuplicativeCertsTest (line 434) | class DuplicativeCertsTest(storage_test.BaseRenewableCertTest):
    method setUp (line 437) | def setUp(self):
    method test_find_duplicative_names (line 443) | def test_find_duplicative_names(self, unused_makedir):
  class CertPathToLineageTest (line 472) | class CertPathToLineageTest(storage_test.BaseRenewableCertTest):
    method setUp (line 475) | def setUp(self):
    method _call (line 483) | def _call(self, cli_config):
    method _archive_files (line 487) | def _archive_files(self, cli_config, filetype):
    method test_basic_match (line 491) | def test_basic_match(self):
    method test_no_match_exists (line 494) | def test_no_match_exists(self):
    method test_options_fullchain (line 501) | def test_options_fullchain(self, mock_acceptable_matches):
    method test_options_cert_path (line 507) | def test_options_cert_path(self, mock_acceptable_matches):
    method test_options_archive_cert (line 515) | def test_options_archive_cert(self, mock_acceptable_matches):
    method test_options_archive_fullchain (line 523) | def test_options_archive_fullchain(self, mock_acceptable_matches):
  class MatchAndCheckOverlaps (line 531) | class MatchAndCheckOverlaps(storage_test.BaseRenewableCertTest):
    method setUp (line 535) | def setUp(self):
    method _call (line 543) | def _call(self, cli_config, acceptable_matches, match_func, rv_func):
    method test_basic_match (line 547) | def test_basic_match(self):
    method test_no_matches (line 553) | def test_no_matches(self, mock_search_lineages):
    method test_too_many_matches (line 558) | def test_too_many_matches(self, mock_search_lineages):
  class GetCertnameTest (line 563) | class GetCertnameTest(unittest.TestCase):
    method setUp (line 566) | def setUp(self):
    method test_get_certnames (line 575) | def test_get_certnames(self, mock_name, mock_files):
    method test_get_certnames_custom_prompt (line 589) | def test_get_certnames_custom_prompt(self, mock_name, mock_files):
    method test_get_certnames_user_abort (line 604) | def test_get_certnames_user_abort(self, mock_name, mock_files):
    method test_get_certnames_allow_multiple (line 616) | def test_get_certnames_allow_multiple(self, mock_name, mock_files):
    method test_get_certnames_allow_multiple_custom_prompt (line 631) | def test_get_certnames_allow_multiple_custom_prompt(self, mock_name, m...
    method test_get_certnames_allow_multiple_user_abort (line 648) | def test_get_certnames_allow_multiple_user_abort(self, mock_name, mock...

FILE: tests/cli_test.py
  class TestReadFile (line 24) | class TestReadFile(TempDirTestCase):
    method test_read_file (line 26) | def test_read_file(self):
  class FlagDefaultTest (line 56) | class FlagDefaultTest(unittest.TestCase):
    method test_default_directories (line 59) | def test_default_directories(self):
  class ParseTest (line 70) | class ParseTest(unittest.TestCase):
    method setUp (line 74) | def setUp(self):
    method _unmocked_parse (line 78) | def _unmocked_parse(*args, **kwargs):
    method parse (line 83) | def parse(*args, **kwargs):
    method _help_output (line 88) | def _help_output(self, args):
    method test_cli_ini_domains (line 105) | def test_cli_ini_domains(self, mock_flag_default):
    method test_no_args (line 125) | def test_no_args(self):
    method test_install_abspath (line 130) | def test_install_abspath(self):
    method test_help (line 146) | def test_help(self):
    method test_help_no_dashes (line 205) | def test_help_no_dashes(self):
    method test_parse_domains (line 224) | def test_parse_domains(self):
    method test_preferred_challenges (line 250) | def test_preferred_challenges(self):
    method test_server_flag (line 263) | def test_server_flag(self):
    method test_must_staple_flag (line 267) | def test_must_staple_flag(self):
    method _check_server_conflict_message (line 273) | def _check_server_conflict_message(self, parser_args, conflicting_args):
    method test_staging_flag (line 284) | def test_staging_flag(self):
    method _assert_dry_run_flag_worked (line 293) | def _assert_dry_run_flag_worked(self, namespace, existing_account):
    method test_dry_run_flag (line 306) | def test_dry_run_flag(self):
    method test_option_was_set (line 345) | def test_option_was_set(self):
    method test_encode_revocation_reason (line 359) | def test_encode_revocation_reason(self):
    method test_force_interactive (line 367) | def test_force_interactive(self):
    method test_deploy_hook_conflict (line 373) | def test_deploy_hook_conflict(self):
    method test_deploy_hook_matches_renew_hook (line 378) | def test_deploy_hook_matches_renew_hook(self):
    method test_deploy_hook_sets_renew_hook (line 386) | def test_deploy_hook_sets_renew_hook(self):
    method test_renew_hook_conflict (line 393) | def test_renew_hook_conflict(self):
    method test_renew_hook_matches_deploy_hook (line 398) | def test_renew_hook_matches_deploy_hook(self):
    method test_renew_hook_does_not_set_renew_hook (line 406) | def test_renew_hook_does_not_set_renew_hook(self):
    method test_max_log_backups_error (line 413) | def test_max_log_backups_error(self):
    method test_max_log_backups_success (line 420) | def test_max_log_backups_success(self):
    method test_unchanging_defaults (line 425) | def test_unchanging_defaults(self):
    method test_no_directory_hooks_set (line 437) | def test_no_directory_hooks_set(self):
    method test_no_directory_hooks_unset (line 440) | def test_no_directory_hooks_unset(self):
    method test_delete_after_revoke (line 443) | def test_delete_after_revoke(self):
    method test_delete_after_revoke_default (line 447) | def test_delete_after_revoke_default(self):
    method test_no_delete_after_revoke (line 451) | def test_no_delete_after_revoke(self):
    method test_allow_subset_with_wildcard (line 455) | def test_allow_subset_with_wildcard(self):
    method test_route53_no_revert (line 459) | def test_route53_no_revert(self):
    method test_no_permissions_check_accepted (line 464) | def test_no_permissions_check_accepted(self):
  class DefaultTest (line 469) | class DefaultTest(unittest.TestCase):
    method setUp (line 473) | def setUp(self):
    method test_boolean (line 478) | def test_boolean(self):
    method test_equality (line 482) | def test_equality(self):
    method test_hash (line 485) | def test_hash(self):
  class SetByCliTest (line 489) | class SetByCliTest(unittest.TestCase):
    method setUp (line 493) | def setUp(self):
    method test_deploy_hook (line 496) | def test_deploy_hook(self):
    method test_webroot_map (line 500) | def test_webroot_map(self):
    method test_report_config_interaction_str (line 505) | def test_report_config_interaction_str(self):
    method test_report_config_interaction_iterable (line 512) | def test_report_config_interaction_iterable(self):
    method _test_report_config_interaction_common (line 519) | def _test_report_config_interaction_common(self):
  function _call_set_by_cli (line 543) | def _call_set_by_cli(var, args, verb):

FILE: tests/client_test.py
  class DetermineUserAgentTest (line 22) | class DetermineUserAgentTest(test_util.ConfigTestCase):
    method _call (line 25) | def _call(self):
    method test_docs_value (line 30) | def test_docs_value(self):
    method test_real_values (line 34) | def test_real_values(self):
    method _test (line 37) | def _test(self, expect_doc_values):
  class RegisterTest (line 54) | class RegisterTest(test_util.ConfigTestCase):
    method setUp (line 57) | def setUp(self):
    method _call (line 64) | def _call(self):
    method _public_key_mock (line 70) | def _public_key_mock():
    method _new_acct_dir_mock (line 76) | def _new_acct_dir_mock():
    method _true_mock (line 80) | def _true_mock():
    method _false_mock (line 84) | def _false_mock():
    method test_no_tos (line 87) | def test_no_tos(self):
    method test_it (line 101) | def test_it(self):
    method test_email_retry (line 110) | def test_email_retry(self, _rep, mock_get_email):
    method test_email_invalid_noninteractive (line 124) | def test_email_invalid_noninteractive(self, _rep):
    method test_needs_email (line 135) | def test_needs_email(self):
    method test_without_email (line 140) | def test_without_email(self, mock_logger):
    method test_dry_run_no_staging_account (line 154) | def test_dry_run_no_staging_account(self, _rep, mock_get_email):
    method test_with_eab_arguments (line 167) | def test_with_eab_arguments(self):
    method test_without_eab_arguments (line 182) | def test_without_eab_arguments(self):
    method test_external_account_required_without_eab_arguments (line 194) | def test_external_account_required_without_eab_arguments(self):
    method test_unsupported_error (line 205) | def test_unsupported_error(self):
  class ClientTestCommon (line 220) | class ClientTestCommon(test_util.ConfigTestCase):
    method setUp (line 223) | def setUp(self):
  class ClientTest (line 239) | class ClientTest(ClientTestCommon):
    method setUp (line 242) | def setUp(self):
    method test_init_acme_verify_ssl (line 252) | def test_init_acme_verify_ssl(self):
    method _mock_obtain_certificate (line 256) | def _mock_obtain_certificate(self):
    method _check_obtain_certificate (line 264) | def _check_obtain_certificate(self, auth_count=1):
    method test_obtain_certificate_from_csr (line 278) | def test_obtain_certificate_from_csr(self, unused_mock_get_utility,
    method test_obtain_certificate (line 312) | def test_obtain_certificate(self, mock_crypto_util):
    method test_obtain_certificate_partial_success (line 329) | def test_obtain_certificate_partial_success(self, mock_remove, mock_cr...
    method test_obtain_certificate_dry_run (line 347) | def test_obtain_certificate_dry_run(self, mock_acme_crypto, mock_crypto):
    method test_obtain_certificate_dry_run_authz_deactivations_failed (line 367) | def test_obtain_certificate_dry_run_authz_deactivations_failed(self, m...
    method _set_mock_from_fullchain (line 405) | def _set_mock_from_fullchain(self, mock_from_fullchain):
    method _authzr_from_domains (line 412) | def _authzr_from_domains(self, domains):
    method _test_obtain_certificate_common (line 424) | def _test_obtain_certificate_common(self, key, csr, authzr_ret=None, a...
    method test_obtain_and_enroll_certificate (line 445) | def test_obtain_and_enroll_certificate(self,
    method test_save_certificate (line 465) | def test_save_certificate(self, mock_parser):
    method test_deploy_certificate_success (line 502) | def test_deploy_certificate_success(self):
    method test_deploy_certificate_failure (line 520) | def test_deploy_certificate_failure(self):
    method test_deploy_certificate_save_failure (line 529) | def test_deploy_certificate_save_failure(self):
    method test_deploy_certificate_restart_failure (line 539) | def test_deploy_certificate_restart_failure(self, mock_get_utility):
    method test_deploy_certificate_restart_failure2 (line 551) | def test_deploy_certificate_restart_failure2(self, mock_get_utility):
  class EnhanceConfigTest (line 564) | class EnhanceConfigTest(ClientTestCommon):
    method setUp (line 567) | def setUp(self):
    method test_no_installer (line 576) | def test_no_installer(self):
    method test_unsupported (line 581) | def test_unsupported(self, mock_enhancements):
    method test_already_exists_header (line 594) | def test_already_exists_header(self, mock_log):
    method test_already_exists_redirect (line 602) | def test_already_exists_redirect(self, mock_log):
    method test_config_set_no_warning_redirect (line 610) | def test_config_set_no_warning_redirect(self, mock_log):
    method test_warn_redirect (line 617) | def test_warn_redirect(self, mock_log, mock_ask):
    method test_no_ask_hsts (line 624) | def test_no_ask_hsts(self):
    method test_no_ask_redirect (line 630) | def test_no_ask_redirect(self):
    method test_no_ask_staple (line 636) | def test_no_ask_staple(self):
    method test_no_ask_uir (line 642) | def test_no_ask_uir(self):
    method test_enhance_failure (line 648) | def test_enhance_failure(self):
    method test_save_failure (line 654) | def test_save_failure(self):
    method test_restart_failure (line 661) | def test_restart_failure(self):
    method test_restart_failure2 (line 666) | def test_restart_failure2(self):
    method test_ask (line 674) | def test_ask(self, mock_ask):
    method _test_error_with_rollback (line 679) | def _test_error_with_rollback(self):
    method _test_error (line 683) | def _test_error(self):
    method _test_with_all_supported (line 690) | def _test_with_all_supported(self):
    method _test_with_already_existing (line 699) | def _test_with_already_existing(self):
  class RollbackTest (line 707) | class RollbackTest(unittest.TestCase):
    method setUp (line 710) | def setUp(self):
    method _call (line 714) | def _call(cls, checkpoints, side_effect):
    method test_no_problems (line 720) | def test_no_problems(self):
    method test_no_installer (line 725) | def test_no_installer(self):

FILE: tests/compat/filesystem_test.py
  class WindowsChmodTests (line 33) | class WindowsChmodTests(TempDirTestCase):
    method setUp (line 35) | def setUp(self):
    method test_symlink_resolution (line 39) | def test_symlink_resolution(self):
    method test_world_permission (line 54) | def test_world_permission(self):
    method test_group_permissions_noop (line 69) | def test_group_permissions_noop(self):
    method test_admin_permissions (line 78) | def test_admin_permissions(self):
    method test_read_flag (line 96) | def test_read_flag(self):
    method test_execute_flag (line 99) | def test_execute_flag(self):
    method test_write_flag (line 102) | def test_write_flag(self):
    method test_full_flag (line 107) | def test_full_flag(self):
    method _test_flag (line 110) | def _test_flag(self, everyone_mode, windows_flag):
    method test_user_admin_dacl_consistency (line 127) | def test_user_admin_dacl_consistency(self):
  class ComputePrivateKeyModeTest (line 152) | class ComputePrivateKeyModeTest(TempDirTestCase):
    method setUp (line 153) | def setUp(self):
    method test_compute_private_key_mode (line 157) | def test_compute_private_key_mode(self):
  class WindowsOpenTest (line 171) | class WindowsOpenTest(TempDirTestCase):
    method test_new_file_correct_permissions (line 172) | def test_new_file_correct_permissions(self):
    method test_existing_file_correct_permissions (line 184) | def test_existing_file_correct_permissions(self):
    method test_create_file_on_open (line 197) | def test_create_file_on_open(self):
    method _test_one_creation (line 227) | def _test_one_creation(self, num, file_exist, flags):
  class WindowsMkdirTests (line 242) | class WindowsMkdirTests(test_util.TempDirTestCase):
    method test_mkdir_correct_permissions (line 244) | def test_mkdir_correct_permissions(self):
    method test_makedirs_correct_permissions (line 255) | def test_makedirs_correct_permissions(self):
    method test_makedirs_switch_os_mkdir (line 267) | def test_makedirs_switch_os_mkdir(self):
  class OwnershipTest (line 282) | class OwnershipTest(test_util.TempDirTestCase):
    method setUp (line 284) | def setUp(self):
    method test_copy_ownership_windows (line 289) | def test_copy_ownership_windows(self):
    method test_copy_ownership_linux (line 315) | def test_copy_ownership_linux(self):
    method test_has_same_ownership (line 327) | def test_has_same_ownership(self):
  class CheckPermissionsTest (line 337) | class CheckPermissionsTest(test_util.TempDirTestCase):
    method setUp (line 339) | def setUp(self):
    method test_check_mode (line 343) | def test_check_mode(self):
    method test_check_owner_windows (line 350) | def test_check_owner_windows(self):
    method test_check_owner_linux (line 362) | def test_check_owner_linux(self):
    method test_check_permissions (line 374) | def test_check_permissions(self):
    method test_check_min_permissions (line 385) | def test_check_min_permissions(self):
    method test_is_world_reachable (line 395) | def test_is_world_reachable(self):
  class OsReplaceTest (line 403) | class OsReplaceTest(test_util.TempDirTestCase):
    method test_os_replace_to_existing_file (line 405) | def test_os_replace_to_existing_file(self):
  class RealpathTest (line 419) | class RealpathTest(test_util.TempDirTestCase):
    method setUp (line 421) | def setUp(self):
    method test_symlink_resolution (line 425) | def test_symlink_resolution(self):
    method test_symlink_loop_mitigation (line 448) | def test_symlink_loop_mitigation(self):
  class IsExecutableTest (line 461) | class IsExecutableTest(test_util.TempDirTestCase):
    method test_not_executable (line 463) | def test_not_executable(self):
    method test_full_path (line 490) | def test_full_path(self, mock_access, mock_isfile):
    method test_rel_path (line 498) | def test_rel_path(self, mock_access, mock_isfile):
    method test_not_found (line 506) | def test_not_found(self, mock_access, mock_isfile):
  function _fix_windows_runtime (line 514) | def _fix_windows_runtime():
  function _get_security_dacl (line 525) | def _get_security_dacl(target):
  function _get_security_owner (line 529) | def _get_security_owner(target):
  function _set_owner (line 533) | def _set_owner(target, security_owner, user):
  function _create_probe (line 539) | def _create_probe(tempdir):

FILE: tests/compat/os_test.py
  class OsTest (line 7) | class OsTest(unittest.TestCase):
    method test_forbidden_methods (line 9) | def test_forbidden_methods(self):

FILE: tests/configuration_test.py
  class NamespaceConfigTest (line 13) | class NamespaceConfigTest(test_util.ConfigTestCase):
    method setUp (line 16) | def setUp(self):
    method test_init_same_ports (line 23) | def test_init_same_ports(self):
    method test_proxy_getattr (line 28) | def test_proxy_getattr(self):
    method test_server_path (line 32) | def test_server_path(self):
    method test_dynamic_dirs (line 42) | def test_dynamic_dirs(self, mock_constants):
    method test_absolute_paths (line 72) | def test_absolute_paths(self):
    method test_renewal_dynamic_dirs (line 107) | def test_renewal_dynamic_dirs(self, mock_constants):
    method test_renewal_absolute_paths (line 120) | def test_renewal_absolute_paths(self):
    method test_get_and_set_attr (line 140) | def test_get_and_set_attr(self):
    method test_hook_directories (line 146) | def test_hook_directories(self):

FILE: tests/crypto_util_test.py
  class InitSaveKeyTest (line 28) | class InitSaveKeyTest(test_util.TempDirTestCase):
    method setUp (line 30) | def setUp(self):
    method tearDown (line 40) | def tearDown(self):
    method _call (line 46) | def _call(cls, key_size, key_dir):
    method test_success (line 51) | def test_success(self, mock_make):
    method test_key_failure (line 59) | def test_key_failure(self, mock_make):
  class InitSaveCSRTest (line 64) | class InitSaveCSRTest(test_util.TempDirTestCase):
    method setUp (line 67) | def setUp(self):
    method test_it (line 75) | def test_it(self, unused_mock_verify, mock_csr):
  class ValidCSRTest (line 87) | class ValidCSRTest(unittest.TestCase):
    method _call (line 91) | def _call(cls, csr):
    method test_valid_pem_true (line 95) | def test_valid_pem_true(self):
    method test_valid_pem_san_true (line 98) | def test_valid_pem_san_true(self):
    method test_valid_der_false (line 101) | def test_valid_der_false(self):
    method test_empty_false (line 104) | def test_empty_false(self):
    method test_random_false (line 107) | def test_random_false(self):
  class CSRMatchesPubkeyTest (line 111) | class CSRMatchesPubkeyTest(unittest.TestCase):
    method _call (line 115) | def _call(cls, *args, **kwargs):
    method test_valid_true (line 119) | def test_valid_true(self):
    method test_invalid_false (line 123) | def test_invalid_false(self):
  class ImportCSRFileTest (line 128) | class ImportCSRFileTest(unittest.TestCase):
    method _call (line 132) | def _call(cls, *args, **kwargs):
    method test_der_csr (line 136) | def test_der_csr(self):
    method test_pem_csr (line 149) | def test_pem_csr(self):
    method test_bad_csr (line 161) | def test_bad_csr(self):
  class MakeKeyTest (line 167) | class MakeKeyTest(unittest.TestCase):
    method test_it (line 170) | def test_it(self):  # pylint: disable=no-self-use
  class VerifyCertSetup (line 177) | class VerifyCertSetup(unittest.TestCase):
    method setUp (line 180) | def setUp(self):
  class VerifyRenewableCertTest (line 195) | class VerifyRenewableCertTest(VerifyCertSetup):
    method _call (line 198) | def _call(self, renewable_cert):
    method test_verify_renewable_cert (line 202) | def test_verify_renewable_cert(self):
    method test_verify_renewable_cert_failure (line 206) | def test_verify_renewable_cert_failure(self, unused_verify_renewable_c...
  class VerifyRenewableCertSigTest (line 210) | class VerifyRenewableCertSigTest(VerifyCertSetup):
    method _call (line 213) | def _call(self, renewable_cert):
    method test_cert_sig_match (line 217) | def test_cert_sig_match(self):
    method test_cert_sig_match_ec (line 220) | def test_cert_sig_match_ec(self):
    method test_cert_sig_mismatch (line 227) | def test_cert_sig_mismatch(self):
  class VerifyFullchainTest (line 232) | class VerifyFullchainTest(VerifyCertSetup):
    method _call (line 235) | def _call(self, renewable_cert):
    method test_fullchain_matches (line 239) | def test_fullchain_matches(self):
    method test_fullchain_mismatch (line 242) | def test_fullchain_mismatch(self):
    method test_fullchain_ioerror (line 245) | def test_fullchain_ioerror(self):
  class VerifyCertMatchesPrivKeyTest (line 250) | class VerifyCertMatchesPrivKeyTest(VerifyCertSetup):
    method _call (line 253) | def _call(self, renewable_cert):
    method test_cert_priv_key_match (line 257) | def test_cert_priv_key_match(self):
    method test_cert_priv_key_mismatch (line 262) | def test_cert_priv_key_mismatch(self):
  class ValidPrivkeyTest (line 269) | class ValidPrivkeyTest(unittest.TestCase):
    method _call (line 273) | def _call(cls, privkey):
    method test_valid_true (line 277) | def test_valid_true(self):
    method test_empty_false (line 280) | def test_empty_false(self):
    method test_random_false (line 283) | def test_random_false(self):
  class GetSANsFromCertTest (line 287) | class GetSANsFromCertTest(unittest.TestCase):
    method _call (line 291) | def _call(cls, *args, **kwargs):
    method test_single (line 295) | def test_single(self):
    method test_san (line 298) | def test_san(self):
  class GetNamesFromCertTest (line 304) | class GetNamesFromCertTest(unittest.TestCase):
    method _call (line 308) | def _call(cls, *args, **kwargs):
    method test_single (line 312) | def test_single(self):
    method test_san (line 317) | def test_san(self):
    method test_common_name_sans_order (line 322) | def test_common_name_sans_order(self):
    method test_parse_non_cert (line 329) | def test_parse_non_cert(self):
  class CertLoaderTest (line 333) | class CertLoaderTest(unittest.TestCase):
    method test_load_valid_cert (line 336) | def test_load_valid_cert(self):
    method test_load_invalid_cert (line 343) | def test_load_invalid_cert(self):
  class NotBeforeTest (line 350) | class NotBeforeTest(unittest.TestCase):
    method test_notBefore (line 353) | def test_notBefore(self):
  class NotAfterTest (line 359) | class NotAfterTest(unittest.TestCase):
    method test_notAfter (line 362) | def test_notAfter(self):
  class Sha256sumTest (line 368) | class Sha256sumTest(unittest.TestCase):
    method test_sha256sum (line 370) | def test_sha256sum(self):
  class CertAndChainFromFullchainTest (line 376) | class CertAndChainFromFullchainTest(unittest.TestCase):
    method test_cert_and_chain_from_fullchain (line 379) | def test_cert_and_chain_from_fullchain(self):

FILE: tests/display/completer_test.py
  class CompleterTest (line 19) | class CompleterTest(test_util.TempDirTestCase):
    method setUp (line 22) | def setUp(self):
    method test_complete (line 41) | def test_complete(self):
    method test_import_error (line 57) | def test_import_error(self):
    method test_context_manager_with_unmocked_readline (line 65) | def test_context_manager_with_unmocked_readline(self):
    method test_context_manager_libedit (line 79) | def test_context_manager_libedit(self, mock_readline):
    method test_context_manager_readline (line 84) | def test_context_manager_readline(self, mock_readline):
    method _test_context_manager_with_mock_readline (line 88) | def _test_context_manager_with_mock_readline(self, mock_readline):
  function enable_tab_completion (line 99) | def enable_tab_completion(unused_command):

FILE: tests/display/enhancements_test.py
  class AskTest (line 11) | class AskTest(unittest.TestCase):
    method setUp (line 13) | def setUp(self):
    method tearDown (line 16) | def tearDown(self):
    method _call (line 20) | def _call(cls, enhancement):
    method test_redirect (line 25) | def test_redirect(self, mock_util):
    method test_key_error (line 29) | def test_key_error(self):
  class RedirectTest (line 33) | class RedirectTest(unittest.TestCase):
    method _call (line 36) | def _call(cls):
    method test_secure (line 41) | def test_secure(self, mock_util):
    method test_cancel (line 46) | def test_cancel(self, mock_util):
    method test_easy (line 51) | def test_easy(self, mock_util):

FILE: tests/display/ops_test.py
  class GetEmailTest (line 22) | class GetEmailTest(unittest.TestCase):
    method _call (line 26) | def _call(cls, **kwargs):
    method test_cancel_none (line 31) | def test_cancel_none(self, mock_get_utility):
    method test_ok_safe (line 38) | def test_ok_safe(self, mock_get_utility):
    method test_ok_not_safe (line 46) | def test_ok_not_safe(self, mock_get_utility):
    method test_invalid_flag (line 54) | def test_invalid_flag(self, mock_get_utility):
    method test_optional_flag (line 66) | def test_optional_flag(self, mock_get_utility):
    method test_optional_invalid_unsafe (line 77) | def test_optional_invalid_unsafe(self, mock_get_utility):
  class ChooseAccountTest (line 87) | class ChooseAccountTest(test_util.TempDirTestCase):
    method setUp (line 89) | def setUp(self):
    method _call (line 112) | def _call(cls, accounts):
    method test_one (line 116) | def test_one(self, mock_util):
    method test_two (line 121) | def test_two(self, mock_util):
    method test_cancel (line 126) | def test_cancel(self, mock_util):
  class GenSSLLabURLs (line 131) | class GenSSLLabURLs(unittest.TestCase):
    method setUp (line 133) | def setUp(self):
    method _call (line 138) | def _call(cls, domains):
    method test_zero (line 142) | def test_zero(self):
    method test_two (line 145) | def test_two(self):
  class GenHttpsNamesTest (line 151) | class GenHttpsNamesTest(unittest.TestCase):
    method setUp (line 153) | def setUp(self):
    method _call (line 158) | def _call(cls, domains):
    method test_zero (line 162) | def test_zero(self):
    method test_one (line 165) | def test_one(self):
    method test_two (line 173) | def test_two(self):
    method test_three (line 183) | def test_three(self):
    method test_four (line 191) | def test_four(self):
  class ChooseNamesTest (line 199) | class ChooseNamesTest(unittest.TestCase):
    method setUp (line 201) | def setUp(self):
    method _call (line 207) | def _call(cls, installer, question=None):
    method test_no_installer (line 212) | def test_no_installer(self, mock_manual):
    method test_no_installer_cancel (line 217) | def test_no_installer_cancel(self, mock_util):
    method test_no_names_choose (line 222) | def test_no_names_choose(self, mock_util):
    method test_sort_names_trivial (line 233) | def test_sort_names_trivial(self):
    method test_sort_names_many (line 253) | def test_sort_names_many(self):
    method test_filter_names_valid_return (line 273) | def test_filter_names_valid_return(self, mock_util):
    method test_filter_namees_override_question (line 282) | def test_filter_namees_override_question(self, mock_util):
    method test_filter_names_nothing_selected (line 291) | def test_filter_names_nothing_selected(self, mock_util):
    method test_filter_names_cancel (line 298) | def test_filter_names_cancel(self, mock_util):
    method test_get_valid_domains (line 305) | def test_get_valid_domains(self):
    method test_choose_manually (line 317) | def test_choose_manually(self, mock_util):
    method test_choose_manually_retry (line 344) | def test_choose_manually_retry(self, mock_util):
  class SuccessInstallationTest (line 355) | class SuccessInstallationTest(unittest.TestCase):
    method _call (line 358) | def _call(cls, names):
    method test_success_installation (line 363) | def test_success_installation(self, mock_util):
  class SuccessRenewalTest (line 376) | class SuccessRenewalTest(unittest.TestCase):
    method _call (line 379) | def _call(cls, names):
    method test_success_renewal (line 384) | def test_success_renewal(self, mock_util):
  class SuccessRevocationTest (line 396) | class SuccessRevocationTest(unittest.TestCase):
    method _call (line 399) | def _call(cls, path):
    method test_success_revocation (line 404) | def test_success_revocation(self, mock_util):
  class ValidatorTests (line 416) | class ValidatorTests(unittest.TestCase):
    method __validator (line 425) | def __validator(m):
    method test_input_blank_with_validator (line 430) | def test_input_blank_with_validator(self, mock_util):
    method test_input_validation_with_default (line 441) | def test_input_validation_with_default(self, mock_util):
    method test_input_validation_with_bad_default (line 448) | def test_input_validation_with_bad_default(self, mock_util):
    method test_input_cancel_with_validator (line 456) | def test_input_cancel_with_validator(self, mock_util):
    method test_directory_select_validation (line 463) | def test_directory_select_validation(self, mock_util):
    method test_directory_select_validation_with_default (line 472) | def test_directory_select_validation_with_default(self, mock_util):
    method test_directory_select_validation_with_bad_default (line 479) | def test_directory_select_validation_with_bad_default(self, mock_util):
  class ChooseValuesTest (line 487) | class ChooseValuesTest(unittest.TestCase):
    method _call (line 490) | def _call(cls, values, question):
    method test_choose_names_success (line 495) | def test_choose_names_success(self, mock_util):
    method test_choose_names_success_question (line 504) | def test_choose_names_success_question(self, mock_util):
    method test_choose_names_user_cancel (line 514) | def test_choose_names_user_cancel(self, mock_util):

FILE: tests/display/util_test.py
  class InputWithTimeoutTest (line 19) | class InputWithTimeoutTest(unittest.TestCase):
    method _call (line 22) | def _call(cls, *args, **kwargs):
    method test_eof (line 26) | def test_eof(self):
    method test_input (line 31) | def test_input(self, prompt=None):
    method test_input_with_prompt (line 39) | def test_input_with_prompt(self, mock_stdout):
    method test_timeout (line 45) | def test_timeout(self):
  class FileOutputDisplayTest (line 54) | class FileOutputDisplayTest(unittest.TestCase):
    method setUp (line 61) | def setUp(self):
    method test_notification_no_pause (line 66) | def test_notification_no_pause(self):
    method test_notification_pause (line 72) | def test_notification_pause(self):
    method test_notification_noninteractive (line 79) | def test_notification_noninteractive(self):
    method test_notification_noninteractive2 (line 84) | def test_notification_noninteractive2(self):
    method test_menu (line 99) | def test_menu(self, mock_ans):
    method test_menu_noninteractive (line 104) | def test_menu_noninteractive(self):
    method test_input_cancel (line 110) | def test_input_cancel(self):
    method test_input_normal (line 117) | def test_input_normal(self):
    method test_input_noninteractive (line 125) | def test_input_noninteractive(self):
    method test_input_assertion_fail (line 133) | def test_input_assertion_fail(self):
    method test_input_assertion_fail2 (line 139) | def test_input_assertion_fail2(self):
    method test_yesno (line 144) | def test_yesno(self):
    method test_yesno_noninteractive (line 166) | def test_yesno_noninteractive(self):
    method test_checklist_valid (line 171) | def test_checklist_valid(self, mock_input):
    method test_checklist_empty (line 179) | def test_checklist_empty(self, mock_input):
    method test_checklist_miss_valid (line 186) | def test_checklist_miss_valid(self, mock_input):
    method test_checklist_miss_quit (line 193) | def test_checklist_miss_quit(self, mock_input):
    method test_checklist_noninteractive (line 199) | def test_checklist_noninteractive(self):
    method test_scrub_checklist_input_valid (line 207) | def test_scrub_checklist_input_valid(self):
    method test_directory_select (line 225) | def test_directory_select(self, mock_input):
    method test_directory_select_noninteractive (line 233) | def test_directory_select_noninteractive(self):
    method _force_noninteractive (line 241) | def _force_noninteractive(self, func, *args, **kwargs):
    method test_scrub_checklist_input_invalid (line 256) | def test_scrub_checklist_input_invalid(self):
    method test_print_menu (line 269) | def test_print_menu(self):
    method test_wrap_lines (line 275) | def test_wrap_lines(self):
    method test_get_valid_int_ans_valid (line 285) | def test_get_valid_int_ans_valid(self):
    method test_get_valid_int_ans_invalid (line 297) | def test_get_valid_int_ans_invalid(self):
    method test_methods_take_force_interactive (line 311) | def test_methods_take_force_interactive(self):
  class NoninteractiveDisplayTest (line 323) | class NoninteractiveDisplayTest(unittest.TestCase):
    method setUp (line 325) | def setUp(self):
    method test_notification_no_pause (line 330) | def test_notification_no_pause(self):
    method test_input (line 336) | def test_input(self):
    method test_menu (line 342) | def test_menu(self):
    method test_yesno (line 347) | def test_yesno(self):
    method test_checklist (line 353) | def test_checklist(self):
    method test_directory_select (line 359) | def test_directory_select(self):
    method test_methods_take_kwargs (line 368) | def test_methods_take_kwargs(self):
  class SeparateListInputTest (line 386) | class SeparateListInputTest(unittest.TestCase):
    method setUp (line 388) | def setUp(self):
    method _call (line 392) | def _call(cls, input_):
    method test_commas (line 396) | def test_commas(self):
    method test_spaces (line 399) | def test_spaces(self):
    method test_both (line 402) | def test_both(self):
    method test_mess (line 405) | def test_mess(self):
  class PlaceParensTest (line 416) | class PlaceParensTest(unittest.TestCase):
    method _call (line 418) | def _call(cls, label):  # pylint: disable=protected-access
    method test_single_letter (line 422) | def test_single_letter(self):
    method test_multiple (line 425) | def test_multiple(self):

FILE: tests/eff_test.py
  class HandleSubscriptionTest (line 11) | class HandleSubscriptionTest(test_util.ConfigTestCase):
    method setUp (line 13) | def setUp(self):
    method _call (line 19) | def _call(self):
    method test_failure (line 25) | def test_failure(self, mock_subscribe, mock_get_utility):
    method test_no_subscribe_with_no_prompt (line 36) | def test_no_subscribe_with_no_prompt(self, mock_subscribe):
    method test_subscribe_with_no_prompt (line 45) | def test_subscribe_with_no_prompt(self, mock_subscribe, mock_get_utili...
    method _assert_no_get_utility_calls (line 51) | def _assert_no_get_utility_calls(self, mock_get_utility):
    method test_subscribe_with_prompt (line 57) | def test_subscribe_with_prompt(self, mock_subscribe, mock_get_utility):
    method _assert_subscribed (line 64) | def _assert_subscribed(self, mock_subscribe):
    method test_no_subscribe_with_prompt (line 70) | def test_no_subscribe_with_prompt(self, mock_subscribe, mock_get_utili...
    method _assert_correct_yesno_call (line 77) | def _assert_correct_yesno_call(self, mock_get_utility):
  class SubscribeTest (line 86) | class SubscribeTest(unittest.TestCase):
    method setUp (line 88) | def setUp(self):
    method _call (line 95) | def _call(self, mock_post):
    method _check_post_call (line 102) | def _check_post_call(self, mock_post):
    method test_bad_status (line 112) | def test_bad_status(self, mock_get_utility):
    method test_not_ok (line 120) | def test_not_ok(self, mock_get_utility):
    method test_response_not_json (line 129) | def test_response_not_json(self, mock_get_utility):
    method test_response_json_missing_status_element (line 137) | def test_response_json_missing_status_element(self, mock_get_utility):
    method _get_reported_message (line 144) | def _get_reported_message(self, mock_get_utility):
    method test_subscribe (line 149) | def test_subscribe(self, mock_get_utility):

FILE: tests/error_handler_test.py
  function get_signals (line 15) | def get_signals(signums):
  function set_signals (line 20) | def set_signals(sig_handler_dict):
  function signal_receiver (line 27) | def signal_receiver(signums):
  function send_signal (line 36) | def send_signal(signum):
  class ErrorHandlerTest (line 41) | class ErrorHandlerTest(unittest.TestCase):
    method setUp (line 44) | def setUp(self):
    method test_context_manager (line 57) | def test_context_manager(self):
    method test_context_manager_with_signal (line 69) | def test_context_manager_with_signal(self):
    method test_bad_recovery (line 89) | def test_bad_recovery(self):
    method test_bad_recovery_with_signal (line 101) | def test_bad_recovery_with_signal(self):
    method test_sysexit_ignored (line 116) | def test_sysexit_ignored(self):
    method test_regular_exit (line 124) | def test_regular_exit(self):
  class ExitHandlerTest (line 133) | class ExitHandlerTest(ErrorHandlerTest):
    method setUp (line 136) | def setUp(self):
    method test_regular_exit (line 143) | def test_regular_exit(self):

FILE: tests/errors_test.py
  class FailedChallengesTest (line 11) | class FailedChallengesTest(unittest.TestCase):
    method setUp (line 14) | def setUp(self):
    method test_str (line 21) | def test_str(self):
    method test_unicode (line 26) | def test_unicode(self):
  class StandaloneBindErrorTest (line 39) | class StandaloneBindErrorTest(unittest.TestCase):
    method setUp (line 42) | def setUp(self):
    method test_instance_args (line 46) | def test_instance_args(self):
    method test_str (line 50) | def test_str(self):

FILE: tests/helpful_test.py
  class TestScanningFlags (line 10) | class TestScanningFlags(unittest.TestCase):
    method test_prescan_no_help_flag (line 12) | def test_prescan_no_help_flag(self):
    method test_prescan_unvalid_topic (line 21) | def test_prescan_unvalid_topic(self):
    method test_prescan_valid_topic (line 30) | def test_prescan_valid_topic(self):
  class TestDetermineVerbs (line 39) | class TestDetermineVerbs(unittest.TestCase):
    method test_determine_verb_wrong_verb (line 41) | def test_determine_verb_wrong_verb(self):
    method test_determine_verb_help (line 46) | def test_determine_verb_help(self):
    method test_determine_verb (line 56) | def test_determine_verb(self):
  class TestAdd (line 70) | class TestAdd(unittest.TestCase):
    method test_add_trivial_argument (line 72) | def test_add_trivial_argument(self):
    method test_add_expected_argument (line 80) | def test_add_expected_argument(self):
  class TestAddGroup (line 92) | class TestAddGroup(unittest.TestCase):
    method test_add_group_no_input (line 94) | def test_add_group_no_input(self):
    method test_add_group_topic_not_visible (line 98) | def test_add_group_topic_not_visible(self):
    method test_add_group_topic_requested_help (line 106) | def test_add_group_topic_requested_help(self):
  class TestParseArgsErrors (line 116) | class TestParseArgsErrors(unittest.TestCase):
    method test_parse_args_renew_force_interactive (line 119) | def test_parse_args_renew_force_interactive(self):
    method test_parse_args_non_interactive_and_force_interactive (line 128) | def test_parse_args_non_interactive_and_force_interactive(self):
    method test_parse_args_subset_names_wildcard_domain (line 141) | def test_parse_args_subset_names_wildcard_domain(self):
    method test_parse_args_hosts_and_auto_hosts (line 167) | def test_parse_args_hosts_and_auto_hosts(self):

FILE: tests/hook_test.py
  class ValidateHooksTest (line 14) | class ValidateHooksTest(unittest.TestCase):
    method _call (line 18) | def _call(cls, *args, **kwargs):
    method test_it (line 23) | def test_it(self, mock_validate_hook):
  class ValidateHookTest (line 33) | class ValidateHookTest(test_util.TempDirTestCase):
    method _call (line 37) | def _call(cls, *args, **kwargs):
    method test_hook_not_executable (line 41) | def test_hook_not_executable(self):
    method test_not_found (line 51) | def test_not_found(self, mock_exe_exists):
    method test_unset (line 58) | def test_unset(self, mock_prog):
  class HookTest (line 63) | class HookTest(test_util.ConfigTestCase):
    method _call (line 67) | def _call(cls, *args, **kwargs):  # pragma: no cover
    method _call_with_mock_execute (line 72) | def _call_with_mock_execute(cls, *args, **kwargs):
  class PreHookTest (line 85) | class PreHookTest(HookTest):
    method _call (line 89) | def _call(cls, *args, **kwargs):
    method setUp (line 93) | def setUp(self):
    method tearDown (line 104) | def tearDown(self):
    method _reset_pre_hook_already (line 109) | def _reset_pre_hook_already(self):
    method test_certonly (line 113) | def test_certonly(self):
    method test_run (line 117) | def test_run(self):
    method _test_nonrenew_common (line 121) | def _test_nonrenew_common(self):
    method test_no_hooks (line 126) | def test_no_hooks(self):
    method test_renew_disabled_dir_hooks (line 136) | def test_renew_disabled_dir_hooks(self):
    method test_renew_no_overlap (line 142) | def test_renew_no_overlap(self):
    method test_renew_with_overlap (line 149) | def test_renew_with_overlap(self):
    method _test_no_executions_common (line 156) | def _test_no_executions_common(self):
  class PostHookTest (line 163) | class PostHookTest(HookTest):
    method _call (line 167) | def _call(cls, *args, **kwargs):
    method setUp (line 171) | def setUp(self):
    method tearDown (line 182) | def tearDown(self):
    method _reset_post_hook_eventually (line 187) | def _reset_post_hook_eventually(self):
    method test_certonly_and_run_with_hook (line 191) | def test_certonly_and_run_with_hook(self):
    method test_cert_only_and_run_without_hook (line 198) | def test_cert_only_and_run_without_hook(self):
    method test_renew_disabled_dir_hooks (line 205) | def test_renew_disabled_dir_hooks(self):
    method test_renew_no_config_hook (line 209) | def test_renew_no_config_hook(self):
    method test_renew_no_dir_hook (line 213) | def test_renew_no_dir_hook(self):
    method test_renew_no_hooks (line 217) | def test_renew_no_hooks(self):
    method test_renew_no_overlap (line 222) | def test_renew_no_overlap(self):
    method test_renew_with_overlap (line 230) | def test_renew_with_overlap(self):
    method _test_renew_common (line 234) | def _test_renew_common(self, expected):
    method _get_eventually (line 241) | def _get_eventually(self):
  class RunSavedPostHooksTest (line 246) | class RunSavedPostHooksTest(HookTest):
    method _call (line 250) | def _call(cls, *args, **kwargs):
    method _call_with_mock_execute_and_eventually (line 254) | def _call_with_mock_execute_and_eventually(self, *args, **kwargs):
    method setUp (line 266) | def setUp(self):
    method test_empty (line 270) | def test_empty(self):
    method test_multiple (line 273) | def test_multiple(self):
    method test_single (line 281) | def test_single(self):
  class RenewalHookTest (line 287) | class RenewalHookTest(HookTest):
    method _call_with_mock_execute (line 292) | def _call_with_mock_execute(self, *args, **kwargs):
    method setUp (line 319) | def setUp(self):
    method tearDown (line 325) | def tearDown(self):
  class DeployHookTest (line 331) | class DeployHookTest(RenewalHookTest):
    method _call (line 335) | def _call(cls, *args, **kwargs):
    method test_dry_run (line 340) | def test_dry_run(self, mock_logger):
    method test_no_hook (line 349) | def test_no_hook(self, mock_logger):
    method test_success (line 356) | def test_success(self):
  class RenewHookTest (line 365) | class RenewHookTest(RenewalHookTest):
    method _call (line 369) | def _call(cls, *args, **kwargs):
    method setUp (line 373) | def setUp(self):
    method test_disabled_dir_hooks (line 382) | def test_disabled_dir_hooks(self):
    method test_dry_run (line 389) | def test_dry_run(self, mock_logger):
    method test_no_hooks (line 396) | def test_no_hooks(self):
    method test_overlap (line 406) | def test_overlap(self):
    method test_no_overlap (line 412) | def test_no_overlap(self):
  class ExecuteTest (line 419) | class ExecuteTest(unittest.TestCase):
    method _call (line 423) | def _call(cls, *args, **kwargs):
    method test_it (line 427) | def test_it(self):
    method _test_common (line 433) | def _test_common(self, returncode, stdout, stderr):
  class ListHooksTest (line 455) | class ListHooksTest(test_util.TempDirTestCase):
    method _call (line 459) | def _call(cls, *args, **kwargs):
    method test_empty (line 463) | def test_empty(self):
    method test_multiple (line 466) | def test_multiple(self):
    method test_single (line 476) | def test_single(self):
    method test_ignore_tilde (line 482) | def test_ignore_tilde(self):
  function create_hook (line 489) | def create_hook(file_path):

FILE: tests/lock_test.py
  class LockDirTest (line 22) | class LockDirTest(test_util.TempDirTestCase):
    method _call (line 25) | def _call(cls, *args, **kwargs):
    method test_it (line 29) | def test_it(self):
  class LockFileTest (line 36) | class LockFileTest(test_util.TempDirTestCase):
    method _call (line 39) | def _call(cls, *args, **kwargs):
    method setUp (line 43) | def setUp(self):
    method test_acquire_without_deletion (line 47) | def test_acquire_without_deletion(self):
    method test_contention (line 59) | def test_contention(self):
    method test_locked_repr (line 64) | def test_locked_repr(self):
    method test_released_repr (line 73) | def test_released_repr(self):
    method _test_repr_common (line 80) | def _test_repr_common(self, lock_file, lock_repr):
    method test_race (line 86) | def test_race(self):
    method test_removed (line 104) | def test_removed(self):
    method test_unexpected_lockf_or_locking_err (line 109) | def test_unexpected_lockf_or_locking_err(self):
    method test_unexpected_os_err (line 124) | def test_unexpected_os_err(self):

FILE: tests/log_test.py
  class PreArgParseSetupTest (line 21) | class PreArgParseSetupTest(unittest.TestCase):
    method _call (line 25) | def _call(cls, *args, **kwargs):  # pylint: disable=unused-argument
    method test_it (line 33) | def test_it(self, mock_register, mock_get, mock_except_hook, mock_sys):
  class PostArgParseSetupTest (line 59) | class PostArgParseSetupTest(test_util.ConfigTestCase):
    method _call (line 63) | def _call(cls, *args, **kwargs):
    method setUp (line 67) | def setUp(self):
    method tearDown (line 84) | def tearDown(self):
    method test_common (line 91) | def test_common(self):
    method test_debug (line 116) | def test_debug(self):
    method test_quiet (line 120) | def test_quiet(self):
  class SetupLogFileHandlerTest (line 125) | class SetupLogFileHandlerTest(test_util.ConfigTestCase):
    method _call (line 129) | def _call(cls, *args, **kwargs):
    method setUp (line 133) | def setUp(self):
    method test_failure (line 138) | def test_failure(self, mock_handler):
    method test_success_with_rollover (line 148) | def test_success_with_rollover(self):
    method test_success_without_rollover (line 151) | def test_success_without_rollover(self):
    method _test_success_common (line 155) | def _test_success_common(self, should_rollover):
    method test_max_log_backups_used (line 170) | def test_max_log_backups_used(self, mock_handler):
  class ColoredStreamHandlerTest (line 176) | class ColoredStreamHandlerTest(unittest.TestCase):
    method setUp (line 179) | def setUp(self):
    method tearDown (line 189) | def tearDown(self):
    method test_format (line 192) | def test_format(self):
    method test_format_and_red_level (line 197) | def test_format_and_red_level(self):
  class MemoryHandlerTest (line 208) | class MemoryHandlerTest(unittest.TestCase):
    method setUp (line 210) | def setUp(self):
    method tearDown (line 221) | def tearDown(self):
    method test_flush (line 225) | def test_flush(self):
    method test_not_flushed (line 230) | def test_not_flushed(self):
    method test_target_reset (line 236) | def test_target_reset(self):
    method _test_log_debug (line 247) | def _test_log_debug(self):
  class TempHandlerTest (line 251) | class TempHandlerTest(unittest.TestCase):
    method setUp (line 253) | def setUp(self):
    method tearDown (line 258) | def tearDown(self):
    method test_permissions (line 261) | def test_permissions(self):
    method test_delete (line 264) | def test_delete(self):
    method test_no_delete (line 268) | def test_no_delete(self):
  class PreArgParseExceptHookTest (line 275) | class PreArgParseExceptHookTest(unittest.TestCase):
    method _call (line 278) | def _call(cls, *args, **kwargs):
    method test_it (line 283) | def test_it(self, mock_post_arg_parse_except_hook):
  class PostArgParseExceptHookTest (line 295) | class PostArgParseExceptHookTest(unittest.TestCase):
    method _call (line 298) | def _call(cls, *args, **kwargs):
    method setUp (line 302) | def setUp(self):
    method test_base_exception (line 306) | def test_base_exception(self):
    method test_debug (line 312) | def test_debug(self):
    method test_custom_error (line 318) | def test_custom_error(self):
    method test_acme_error (line 324) | def test_acme_error(self):
    method test_other_error (line 337) | def test_other_error(self):
    method _test_common (line 343) | def _test_common(self, error_type, debug):
    method _assert_exception_logged (line 369) | def _assert_exception_logged(self, log_func, exc_type):
    method _assert_logfile_output (line 378) | def _assert_logfile_output(self, output):
    method _assert_quiet_output (line 382) | def _assert_quiet_output(self, mock_logger, output):
  class ExitWithLogPathTest (line 388) | class ExitWithLogPathTest(test_util.TempDirTestCase):
    method _call (line 391) | def _call(cls, *args, **kwargs):
    method test_log_file (line 395) | def test_log_file(self):
    method test_log_dir (line 403) | def test_log_dir(self):
    method _test_common (line 409) | def _test_common(self, *args, **kwargs):

FILE: tests/main_test.py
  class TestHandleIdenticalCerts (line 49) | class TestHandleIdenticalCerts(unittest.TestCase):
    method test_handle_identical_cert_request_pending (line 51) | def test_handle_identical_cert_request_pending(self):
  class RunTest (line 59) | class RunTest(test_util.ConfigTestCase):
    method setUp (line 62) | def setUp(self):
    method _call (line 84) | def _call(self):
    method test_newcert_success (line 93) | def test_newcert_success(self):
    method test_reinstall_success (line 99) | def test_reinstall_success(self):
    method test_renewal_success (line 105) | def test_renewal_success(self):
    method test_run_enhancement_not_supported (line 112) | def test_run_enhancement_not_supported(self, mock_choose):
  class CertonlyTest (line 121) | class CertonlyTest(unittest.TestCase):
    method setUp (line 124) | def setUp(self):
    method tearDown (line 128) | def tearDown(self):
    method _call (line 131) | def _call(self, args):
    method test_no_reinstall_text_pause (line 145) | def test_no_reinstall_text_pause(self, unused_report, mock_auth,
    method _assert_no_pause (line 153) | def _assert_no_pause(self, message, pause=True):  # pylint: disable=un...
    method test_find_lineage_for_domains_and_certname (line 160) | def test_find_lineage_for_domains_and_certname(self, mock_report_cert,
    method test_find_lineage_for_domains_new_certname (line 189) | def test_find_lineage_for_domains_new_certname(self, mock_report_cert,
  class FindDomainsOrCertnameTest (line 205) | class FindDomainsOrCertnameTest(unittest.TestCase):
    method test_display_ops (line 209) | def test_display_ops(self, mock_choose_names):
    method test_no_results (line 217) | def test_no_results(self, mock_choose_names):
    method test_grab_domains (line 224) | def test_grab_domains(self, mock_domains):
  class RevokeTest (line 232) | class RevokeTest(test_util.TempDirTestCase):
    method setUp (line 235) | def setUp(self):
    method _call (line 268) | def _call(self, args=None):
    method test_revoke_with_reason (line 281) | def test_revoke_with_reason(self, mock_acme_client,
    method test_revoke_by_certname (line 298) | def test_revoke_by_certname(self, mock_cert_path_for_cert_name,
    method test_revocation_success (line 307) | def test_revocation_success(self, mock_delete_if_appropriate):
    method test_revocation_error (line 312) | def test_revocation_error(self):
    method test_revocation_with_prompt (line 321) | def test_revocation_with_prompt(self, mock_get_utility,
  class DeleteIfAppropriateTest (line 328) | class DeleteIfAppropriateTest(test_util.ConfigTestCase):
    method _call (line 331) | def _call(self, mock_config):
    method _test_delete_opt_out_common (line 335) | def _test_delete_opt_out_common(self, mock_get_utility):
    method test_delete_flag_opt_out (line 342) | def test_delete_flag_opt_out(self, mock_get_utility):
    method test_delete_prompt_opt_out (line 347) | def test_delete_prompt_opt_out(self, mock_get_utility):
    method test_overlapping_archive_dirs (line 358) | def test_overlapping_archive_dirs(self, mock_get_utility,
    method test_cert_path_only (line 377) | def test_cert_path_only(self, mock_get_utility,
    method test_noninteractive_deletion (line 395) | def test_noninteractive_deletion(self, mock_get_utility, mock_delete,
    method test_opt_in_deletion (line 415) | def test_opt_in_deletion(self, mock_get_utility, mock_delete,
  class DetermineAccountTest (line 431) | class DetermineAccountTest(test_util.ConfigTestCase):
    method setUp (line 434) | def setUp(self):
    method _call (line 445) | def _call(self):
    method test_args_account_set (line 452) | def test_args_account_set(self):
    method test_single_account (line 459) | def test_single_account(self):
    method test_multiple_accounts (line 466) | def test_multiple_accounts(self, mock_choose_accounts):
    method test_no_accounts_no_email (line 477) | def test_no_accounts_no_email(self, mock_get_email):
    method test_no_accounts_email (line 490) | def test_no_accounts_email(self):
  class MainTest (line 499) | class MainTest(test_util.ConfigTestCase):
    method setUp (line 502) | def setUp(self):
    method tearDown (line 512) | def tearDown(self):
    method _call (line 518) | def _call(self, args, stdout=None, mockisfile=False):
    method _call_no_clientmock (line 543) | def _call_no_clientmock(self, args, stdout=None):
    method test_no_flags (line 554) | def test_no_flags(self):
    method test_version_string_program_name (line 559) | def test_version_string_program_name(self):
    method _cli_missing_flag (line 572) | def _cli_missing_flag(self, args, message):
    method test_noninteractive (line 584) | def test_noninteractive(self, _):
    method test_user_agent (line 596) | def test_user_agent(self, gsc, _obt, det, _client, _, __):
    method test_installer_selection (line 623) | def test_installer_selection(self, mock_pick_installer, _rec):
    method test_installer_certname (line 631) | def test_installer_certname(self, _inst, _rec, mock_install):
    method test_installer_param_override (line 649) | def test_installer_param_override(self, _inst, _rec, mock_install, _):
    method test_installer_param_error (line 675) | def test_installer_param_error(self, _inst, _rec):
    method test_installer_select_cert (line 685) | def test_installer_select_cert(self, mock_inst, mock_getcert, _inst, _...
    method test_configurator_selection (line 699) | def test_configurator_selection(self, mock_exe_exists, _, __):
    method test_rollback (line 737) | def test_rollback(self, _):
    method test_update_symlinks (line 746) | def test_update_symlinks(self, mock_cert_manager):
    method test_certificates (line 751) | def test_certificates(self, mock_cert_manager):
    method test_delete (line 756) | def test_delete(self, mock_cert_manager):
    method test_plugins (line 761) | def test_plugins(self, _):
    method test_plugins_no_args (line 770) | def test_plugins_no_args(self, _det, mock_disco):
    method test_plugins_no_args_unprivileged (line 785) | def test_plugins_no_args_unprivileged(self, _det, mock_disco):
    method test_plugins_init (line 807) | def test_plugins_init(self, _det, mock_disco):
    method test_plugins_prepare (line 825) | def test_plugins_prepare(self, _det, mock_disco):
    method test_certonly_abspath (line 844) | def test_certonly_abspath(self):
    method test_certonly_bad_args (line 861) | def test_certonly_bad_args(self):
    method test_check_config_sanity_domain (line 868) | def test_check_config_sanity_domain(self):
    method test_csr_with_besteffort (line 882) | def test_csr_with_besteffort(self):
    method test_run_with_csr (line 887) | def test_run_with_csr(self):
    method test_csr_with_no_domains (line 896) | def test_csr_with_no_domains(self):
    method test_csr_with_inconsistent_domains (line 902) | def test_csr_with_inconsistent_domains(self):
    method _certonly_new_request_common (line 907) | def _certonly_new_request_common(self, mock_client, args=None):
    method test_certonly_dry_run_new_request_success (line 919) | def test_certonly_dry_run_new_request_success(self, mock_get_utility):
    method test_certonly_new_request_success (line 932) | def test_certonly_new_request_success(self, mock_get_utility, mock_not...
    method test_certonly_new_request_failure (line 952) | def test_certonly_new_request_failure(self):
    method _test_renewal_common (line 958) | def _test_renewal_common(self, due_for_renewal, extra_args, log_out=None,
    method test_certonly_renewal (line 1034) | def test_certonly_renewal(self, _):
    method test_certonly_renewal_triggers (line 1045) | def test_certonly_renewal_triggers(self, _, __):
    method _dump_log (line 1059) | def _dump_log(self):
    method test_renew_verb (line 1066) | def test_renew_verb(self):
    method test_reuse_key (line 1071) | def test_reuse_key(self):
    method test_reuse_key_no_dry_run (line 1077) | def test_reuse_key_no_dry_run(self, unused_save_successor):
    method test_noninteractive_renewal_delay (line 1083) | def test_noninteractive_renewal_delay(self, stdin):
    method test_interactive_no_renewal_delay (line 1095) | def test_interactive_no_renewal_delay(self, stdin):
    method test_renew_skips_recent_certs (line 1103) | def test_renew_skips_recent_certs(self, should_renew):
    method test_quiet_renew (line 1113) | def test_quiet_renew(self, _):
    method test_renew_hook_validation (line 1126) | def test_renew_hook_validation(self):
    method test_renew_no_hook_validation (line 1132) | def test_renew_no_hook_validation(self):
    method test_renew_verb_empty_config (line 1140) | def test_renew_verb_empty_config(self):
    method test_renew_with_certname (line 1149) | def test_renew_with_certname(self):
    method test_renew_with_bad_certname (line 1154) | def test_renew_with_bad_certname(self):
    method _make_dummy_renewal_config (line 1159) | def _make_dummy_renewal_config(self):
    method _test_renew_common (line 1165) | def _test_renew_common(self, renewalparams=None, names=None,
    method test_renew_no_renewalparams (line 1186) | def test_renew_no_renewalparams(self):
    method test_renew_no_authenticator (line 1189) | def test_renew_no_authenticator(self):
    method test_renew_with_bad_int (line 1193) | def test_renew_with_bad_int(self):
    method test_renew_with_nonetype_http01 (line 1199) | def test_renew_with_nonetype_http01(self):
    method test_renew_with_bad_domain (line 1205) | def test_renew_with_bad_domain(self):
    method test_renew_with_configurator (line 1212) | def test_renew_with_configurator(self, mock_sel):
    method test_renew_plugin_config_restoration (line 1219) | def test_renew_plugin_config_restoration(self):
    method test_renew_with_webroot_map (line 1226) | def test_renew_with_webroot_map(self):
    method test_renew_reconstitute_error (line 1232) | def test_renew_reconstitute_error(self):
    method test_renew_obtain_cert_error (line 1238) | def test_renew_obtain_cert_error(self):
    method test_renew_with_bad_cli_args (line 1251) | def test_renew_with_bad_cli_args(self):
    method test_no_renewal_with_hooks (line 1257) | def test_no_renewal_with_hooks(self):
    method test_certonly_reinstall (line 1268) | def test_certonly_reinstall(self, mock_init, mock_renewal, mock_get_ut...
    method _test_certonly_csr_common (line 1277) | def _test_certonly_csr_common(self, extra_args=None):
    method test_certonly_csr (line 1311) | def test_certonly_csr(self):
    method test_certonly_csr_dry_run (line 1319) | def test_certonly_csr_dry_run(self):
    method test_revoke_with_key (line 1327) | def test_revoke_with_key(self, mock_acme_client,
    method test_revoke_with_key_mismatch (line 1343) | def test_revoke_with_key_mismatch(self):
    method test_revoke_without_key (line 1351) | def test_revoke_without_key(self, mock_determine_account,
    method test_register (line 1364) | def test_register(self, _):
    method test_update_account_no_existing_accounts (line 1380) | def test_update_account_no_existing_accounts(self):
    method test_update_account_with_email (line 1393) | def test_update_account_with_email(self, mock_utility, mock_email):
    method test_plugin_selection_error (line 1423) | def test_plugin_selection_error(self, mock_run, mock_choose):
  class UnregisterTest (line 1435) | class UnregisterTest(unittest.TestCase):
    method setUp (line 1436) | def setUp(self):
    method tearDown (line 1444) | def tearDown(self):
    method test_abort_unregister (line 1448) | def test_abort_unregister(self):
    method test_unregister (line 1460) | def test_unregister(self):
    method test_unregister_no_account (line 1480) | def test_unregister_no_account(self):
  class MakeOrVerifyNeededDirs (line 1497) | class MakeOrVerifyNeededDirs(test_util.ConfigTestCase):
    method test_it (line 1501) | def test_it(self, mock_util):
  class EnhanceTest (line 1518) | class EnhanceTest(test_util.ConfigTestCase):
    method setUp (line 1521) | def setUp(self):
    method tearDown (line 1527) | def tearDown(self):
    method _call (line 1530) | def _call(self, args):
    method test_selection_question (line 1550) | def test_selection_question(self, mock_find, mock_choose, mock_lineage...
    method test_selection_auth_warning (line 1564) | def test_selection_auth_warning(self, mock_find, mock_choose, mock_lin...
    method test_enhance_config_call (line 1578) | def test_enhance_config_call(self, _rec, mock_choose, mock_lineage):
    method test_enhance_noninteractive (line 1596) | def test_enhance_noninteractive(self, _rec, mock_choose, mock_lineage):
    method test_user_abort_domains (line 1608) | def test_user_abort_domains(self, _rec, mock_choose):
    method test_no_enhancements_defined (line 1615) | def test_no_enhancements_defined(self):
    method test_plugin_selection_error (line 1622) | def test_plugin_selection_error(self, _rec, mock_choose, mock_pick):
    method test_enhancement_enable (line 1634) | def test_enhancement_enable(self, _, _rec, mock_inst, mock_choose, moc...
    method test_enhancement_enable_not_supported (line 1648) | def test_enhancement_enable_not_supported(self, _, _rec, mock_inst, mo...
    method test_enhancement_enable_conflict (line 1656) | def test_enhancement_enable_conflict(self):
  class InstallTest (line 1662) | class InstallTest(test_util.ConfigTestCase):
    method setUp (line 1665) | def setUp(self):
    method test_install_enhancement_not_supported (line 1671) | def test_install_enhancement_not_supported(self, mock_inst, _rec):
    method test_install_enhancement_no_certname (line 1682) | def test_install_enhancement_no_certname(self, mock_inst, _rec):

FILE: tests/ocsp_test.py
  class OCSPTestOpenSSL (line 33) | class OCSPTestOpenSSL(unittest.TestCase):
    method setUp (line 38) | def setUp(self):
    method tearDown (line 48) | def tearDown(self):
    method test_init (line 54) | def test_init(self, mock_exists, mock_popen, mock_log):
    method test_ocsp_revoked (line 80) | def test_ocsp_revoked(self, mock_run, mock_na, mock_determine):
    method test_determine_ocsp_server (line 109) | def test_determine_ocsp_server(self):
    method test_translate_ocsp (line 118) | def test_translate_ocsp(self, mock_run, mock_log):
  class OSCPTestCryptography (line 143) | class OSCPTestCryptography(unittest.TestCase):
    method setUp (line 148) | def setUp(self):
    method test_ensure_cryptography_toggled (line 165) | def test_ensure_cryptography_toggled(self, mock_revoke, mock_determine):
    method test_revoke (line 171) | def test_revoke(self):
    method test_responder_is_issuer (line 176) | def test_responder_is_issuer(self):
    method test_responder_is_authorized_delegate (line 190) | def test_responder_is_authorized_delegate(self):
    method test_revoke_resiliency (line 208) | def test_revoke_resiliency(self):
  function _ocsp_mock (line 281) | def _ocsp_mock(certificate_status, response_status,
  function _construct_mock_ocsp_response (line 299) | def _construct_mock_ocsp_response(certificate_status, response_status):

FILE: tests/plugins/common_test.py
  class NamespaceFunctionsTest (line 24) | class NamespaceFunctionsTest(unittest.TestCase):
    method test_option_namespace (line 27) | def test_option_namespace(self):
    method test_dest_namespace (line 31) | def test_dest_namespace(self):
    method test_dest_namespace_with_dashes (line 35) | def test_dest_namespace_with_dashes(self):
  class PluginTest (line 40) | class PluginTest(unittest.TestCase):
    method setUp (line 43) | def setUp(self):
    method test_init (line 55) | def test_init(self):
    method test_option_namespace (line 59) | def test_option_namespace(self):
    method test_option_name (line 62) | def test_option_name(self):
    method test_dest_namespace (line 65) | def test_dest_namespace(self):
    method test_dest (line 68) | def test_dest(self):
    method test_conf (line 72) | def test_conf(self):
    method test_inject_parser_options (line 75) | def test_inject_parser_options(self):
  class InstallerTest (line 84) | class InstallerTest(test_util.ConfigTestCase):
    method setUp (line 87) | def setUp(self):
    method test_add_to_real_checkpoint (line 96) | def test_add_to_real_checkpoint(self):
    method test_add_to_real_checkpoint2 (line 101) | def test_add_to_real_checkpoint2(self):
    method test_add_to_temporary_checkpoint (line 104) | def test_add_to_temporary_checkpoint(self):
    method _test_add_to_checkpoint_common (line 107) | def _test_add_to_checkpoint_common(self, temporary):
    method test_finalize_checkpoint (line 121) | def test_finalize_checkpoint(self):
    method test_recovery_routine (line 124) | def test_recovery_routine(self):
    method test_revert_temporary_config (line 127) | def test_revert_temporary_config(self):
    method test_rollback_checkpoints (line 130) | def test_rollback_checkpoints(self):
    method _test_wrapped_method (line 133) | def _test_wrapped_method(self, name, *args, **kwargs):
    method _test_adapted_method (line 144) | def _test_adapted_method(self, installer_func,
    method test_install_ssl_dhparams (line 164) | def test_install_ssl_dhparams(self):
    method _current_ssl_dhparams_hash (line 168) | def _current_ssl_dhparams_hash(self):
    method test_current_file_hash_in_all_hashes (line 172) | def test_current_file_hash_in_all_hashes(self):
  class AddrTest (line 179) | class AddrTest(unittest.TestCase):
    method setUp (line 182) | def setUp(self):
    method test_fromstring (line 193) | def test_fromstring(self):
    method test_str (line 214) | def test_str(self):
    method test_get_addr_obj (line 222) | def test_get_addr_obj(self):
    method test_eq (line 230) | def test_eq(self):
    method test_set_inclusion (line 243) | def test_set_inclusion(self):
  class ChallengePerformerTest (line 260) | class ChallengePerformerTest(unittest.TestCase):
    method setUp (line 263) | def setUp(self):
    method test_add_chall (line 269) | def test_add_chall(self):
    method test_perform (line 274) | def test_perform(self):
  class InstallVersionControlledFileTest (line 278) | class InstallVersionControlledFileTest(test_util.TempDirTestCase):
    method setUp (line 281) | def setUp(self):
    method _call (line 293) | def _call(self):
    method _current_file_hash (line 300) | def _current_file_hash(self):
    method _assert_current_file (line 303) | def _assert_current_file(self):
    method test_no_file (line 308) | def test_no_file(self):
    method test_current_file (line 313) | def test_current_file(self):
    method test_prev_file_updates_to_current (line 319) | def test_prev_file_updates_to_current(self):
    method test_manually_modified_current_file_does_not_update (line 324) | def test_manually_modified_current_file_does_not_update(self):
    method test_manually_modified_past_file_warns (line 337) | def test_manually_modified_past_file_warns(self):

FILE: tests/plugins/disco_test.py
  class PluginEntryPointTest (line 27) | class PluginEntryPointTest(unittest.TestCase):
    method setUp (line 30) | def setUp(self):
    method test_entry_point_to_plugin_name (line 45) | def test_entry_point_to_plugin_name(self):
    method test_description (line 60) | def test_description(self):
    method test_description_with_name (line 63) | def test_description_with_name(self):
    method test_long_description (line 68) | def test_long_description(self):
    method test_long_description_nonexistent (line 74) | def test_long_description_nonexistent(self):
    method test_ifaces (line 80) | def test_ifaces(self):
    method test__init__ (line 86) | def test__init__(self):
    method test_init (line 97) | def test_init(self):
    method test_verify (line 113) | def test_verify(self):
    method test_prepare (line 136) | def test_prepare(self):
    method test_prepare_misconfigured (line 146) | def test_prepare_misconfigured(self):
    method test_prepare_no_installation (line 159) | def test_prepare_no_installation(self):
    method test_prepare_generic_plugin_error (line 170) | def test_prepare_generic_plugin_error(self):
    method test_repr (line 180) | def test_repr(self):
  class PluginsRegistryTest (line 184) | class PluginsRegistryTest(unittest.TestCase):
    method _create_new_registry (line 188) | def _create_new_registry(cls, plugins):
    method setUp (line 192) | def setUp(self):
    method test_find_all (line 199) | def test_find_all(self):
    method test_getitem (line 210) | def test_getitem(self):
    method test_iter (line 213) | def test_iter(self):
    method test_len (line 216) | def test_len(self):
    method test_init (line 220) | def test_init(self):
    method test_filter (line 225) | def test_filter(self):
    method test_ifaces (line 232) | def test_ifaces(self):
    method test_verify (line 239) | def test_verify(self):
    method test_prepare (line 247) | def test_prepare(self):
    method test_prepare_order (line 252) | def test_prepare_order(self):
    method test_available (line 263) | def test_available(self):
    method test_find_init (line 270) | def test_find_init(self):
    method test_repr (line 276) | def test_repr(self):
    method test_str (line 281) | def test_str(self):

FILE: tests/plugins/dns_common_lexicon_test.py
  class LexiconClientTest (line 11) | class LexiconClientTest(unittest.TestCase, dns_test_common_lexicon.BaseL...
    class _FakeLexiconClient (line 13) | class _FakeLexiconClient(dns_common_lexicon.LexiconClient):
    method setUp (line 16) | def setUp(self):

FILE: tests/plugins/dns_common_test.py
  class DNSAuthenticatorTest (line 18) | class DNSAuthenticatorTest(test_util.TempDirTestCase, dns_test_common.Ba...
    class _FakeDNSAuthenticator (line 21) | class _FakeDNSAuthenticator(dns_common.DNSAuthenticator):
      method more_info (line 26) | def more_info(self):  # pylint: disable=missing-docstring,no-self-use
    class _FakeConfig (line 29) | class _FakeConfig(object):
    method setUp (line 35) | def setUp(self):
    method test_perform (line 42) | def test_perform(self):
    method test_cleanup (line 47) | def test_cleanup(self):
    method test_prompt (line 55) | def test_prompt(self, mock_get_utility):
    method test_prompt_canceled (line 64) | def test_prompt_canceled(self, mock_get_utility):
    method test_prompt_file (line 71) | def test_prompt_file(self, mock_get_utility):
    method test_prompt_file_canceled (line 85) | def test_prompt_file_canceled(self, mock_get_utility):
    method test_configure_credentials (line 91) | def test_configure_credentials(self):
    method test_prompt_credentials (line 101) | def test_prompt_credentials(self, mock_get_utility):
  class CredentialsConfigurationTest (line 120) | class CredentialsConfigurationTest(test_util.TempDirTestCase):
    class _MockLoggingHandler (line 121) | class _MockLoggingHandler(logging.Handler):
      method __init__ (line 124) | def __init__(self, *args, **kwargs):
      method emit (line 128) | def emit(self, record):
      method reset (line 131) | def reset(self):
    method test_valid_file (line 135) | def test_valid_file(self):
    method test_nonexistent_file (line 144) | def test_nonexistent_file(self):
    method test_valid_file_with_unsafe_permissions (line 149) | def test_valid_file_with_unsafe_permissions(self):
  class CredentialsConfigurationRequireTest (line 161) | class CredentialsConfigurationRequireTest(test_util.TempDirTestCase):
    method setUp (line 163) | def setUp(self):
    method _write (line 168) | def _write(self, values):
    method test_valid (line 171) | def test_valid(self):
    method test_valid_but_extra (line 177) | def test_valid_but_extra(self):
    method test_valid_empty (line 183) | def test_valid_empty(self):
    method test_missing (line 189) | def test_missing(self):
    method test_blank (line 195) | def test_blank(self):
    method test_typo (line 201) | def test_typo(self):
  class DomainNameGuessTest (line 208) | class DomainNameGuessTest(unittest.TestCase):
    method test_simple_case (line 210) | def test_simple_case(self):
    method test_sub_domain (line 216) | def test_sub_domain(self):
    method test_second_level_domain (line 222) | def test_second_level_domain(self):

FILE: tests/plugins/enhancements_test.py
  class EnhancementTest (line 11) | class EnhancementTest(test_util.ConfigTestCase):
    method setUp (line 14) | def setUp(self):
    method test_enhancement_enabled_enhancements (line 20) | def test_enhancement_enabled_enhancements(self, _):
    method test_are_requested (line 39) | def test_are_requested(self):
    method test_are_supported (line 46) | def test_are_supported(self):
    method test_enable (line 52) | def test_enable(self):

FILE: tests/plugins/manual_test.py
  class AuthenticatorTest (line 16) | class AuthenticatorTest(test_util.TempDirTestCase):
    method setUp (line 19) | def setUp(self):
    method test_prepare_no_hook_noninteractive (line 44) | def test_prepare_no_hook_noninteractive(self):
    method test_prepare_bad_hook (line 48) | def test_prepare_bad_hook(self):
    method test_more_info (line 53) | def test_more_info(self):
    method test_get_chall_pref (line 56) | def test_get_chall_pref(self):
    method test_ip_logging_not_ok (line 61) | def test_ip_logging_not_ok(self, mock_get_utility):
    method test_ip_logging_ok (line 66) | def test_ip_logging_ok(self, mock_get_utility):
    method test_script_perform (line 71) | def test_script_perform(self):
    method test_manual_perform (line 97) | def test_manual_perform(self, mock_get_utility):
    method test_cleanup (line 108) | def test_cleanup(self):

FILE: tests/plugins/null_test.py
  class InstallerTest (line 8) | class InstallerTest(unittest.TestCase):
    method setUp (line 11) | def setUp(self):
    method test_it (line 15) | def test_it(self):

FILE: tests/plugins/selection_test.py
  class ConveniencePickPluginTest (line 17) | class ConveniencePickPluginTest(unittest.TestCase):
    method _test (line 20) | def _test(self, fun, ifaces):
    method test_authenticator (line 31) | def test_authenticator(self):
    method test_installer (line 35) | def test_installer(self):
    method test_configurator (line 39) | def test_configurator(self):
  class PickPluginTest (line 45) | class PickPluginTest(unittest.TestCase):
    method setUp (line 48) | def setUp(self):
    method _call (line 55) | def _call(self):
    method test_default_provided (line 60) | def test_default_provided(self):
    method test_no_default (line 65) | def test_no_default(self):
    method test_no_candidate (line 69) | def test_no_candidate(self):
    method test_single (line 72) | def test_single(self):
    method test_single_misconfigured (line 81) | def test_single_misconfigured(self):
    method test_multiple (line 90) | def test_multiple(self):
    method test_choose_plugin_none (line 103) | def test_choose_plugin_none(self):
  class ChoosePluginTest (line 114) | class ChoosePluginTest(unittest.TestCase):
    method setUp (line 117) | def setUp(self):
    method _call (line 131) | def _call(self):
    method test_selection (line 136) | def test_selection(self, mock_util):
    method test_more_info (line 143) | def test_more_info(self, mock_util):
    method test_no_choice (line 151) | def test_no_choice(self, mock_util):
    method test_new_interaction_avoidance (line 156) | def test_new_interaction_avoidance(self, mock_util):
  class GetUnpreparedInstallerTest (line 175) | class GetUnpreparedInstallerTest(test_util.ConfigTestCase):
    method setUp (line 178) | def setUp(self):
    method _call (line 193) | def _call(self):
    method test_no_installer_defined (line 197) | def test_no_installer_defined(self):
    method test_no_available_installers (line 201) | def test_no_available_installers(self):
    method test_get_plugin (line 206) | def test_get_plugin(self):
    method test_multiple_installers_returned (line 211) | def test_multiple_installers_returned(self):

FILE: tests/plugins/standalone_test.py
  class ServerManagerTest (line 23) | class ServerManagerTest(unittest.TestCase):
    method setUp (line 26) | def setUp(self):
    method test_init (line 33) | def test_init(self):
    method _test_run_stop (line 38) | def _test_run_stop(self, challenge_type):
    method test_run_stop_http_01 (line 45) | def test_run_stop_http_01(self):
    method test_run_idempotent (line 48) | def test_run_idempotent(self):
    method test_run_bind_error (line 57) | def test_run_bind_error(self):
  function get_open_port (line 74) | def get_open_port():
  class AuthenticatorTest (line 83) | class AuthenticatorTest(unittest.TestCase):
    method setUp (line 86) | def setUp(self):
    method test_more_info (line 93) | def test_more_info(self):
    method test_get_chall_pref (line 96) | def test_get_chall_pref(self):
    method test_perform (line 100) | def test_perform(self):
    method test_perform_eaddrinuse_retry (line 108) | def test_perform_eaddrinuse_retry(self, mock_get_utility):
    method test_perform_eaddrinuse_no_retry (line 120) | def test_perform_eaddrinuse_no_retry(self, mock_get_utility):
    method _assert_correct_yesno_call (line 129) | def _assert_correct_yesno_call(self, mock_yesno):
    method test_perform_eacces (line 134) | def test_perform_eacces(self):
    method test_perform_unexpected_socket_error (line 138) | def test_perform_unexpected_socket_error(self):
    method _fail_perform (line 143) | def _fail_perform(self, errno):
    method _get_achalls (line 149) | def _get_achalls(cls):
    method test_cleanup (line 157) | def test_cleanup(self):

FILE: tests/plugins/storage_test.py
  class PluginStorageTest (line 14) | class PluginStorageTest(test_util.ConfigTestCase):
    method setUp (line 17) | def setUp(self):
    method test_load_errors_cant_read (line 24) | def test_load_errors_cant_read(self):
    method test_load_errors_empty (line 39) | def test_load_errors_empty(self):
    method test_load_errors_corrupted (line 51) | def test_load_errors_corrupted(self):
    method test_save_errors_cant_serialize (line 63) | def test_save_errors_cant_serialize(self):
    method test_save_errors_unable_to_write_file (line 73) | def test_save_errors_unable_to_write_file(self):
    method test_save_uninitialized (line 84) | def test_save_uninitialized(self):
    method test_namespace_isolation (line 89) | def test_namespace_isolation(self):
    method test_saved_state (line 101) | def test_saved_state(self):

FILE: tests/plugins/util_test.py
  class GetPrefixTest (line 9) | class GetPrefixTest(unittest.TestCase):
    method test_get_prefix (line 11) | def test_get_prefix(self):
  class PathSurgeryTest (line 20) | class PathSurgeryTest(unittest.TestCase):
    method test_path_surgery (line 24) | def test_path_surgery(self, mock_debug):

FILE: tests/plugins/webroot_test.py
  class AuthenticatorTest (line 28) | class AuthenticatorTest(unittest.TestCase):
    method setUp (line 34) | def setUp(self):
    method tearDown (line 54) | def tearDown(self):
    method test_more_info (line 57) | def test_more_info(self):
    method test_add_parser_arguments (line 62) | def test_add_parser_arguments(self):
    method test_prepare (line 67) | def test_prepare(self):
    method test_webroot_from_list (line 71) | def test_webroot_from_list(self, mock_get_utility):
    method test_webroot_from_list_help_and_cancel (line 88) | def test_webroot_from_list_help_and_cancel(self, mock_get_utility):
    method test_new_webroot (line 103) | def test_new_webroot(self, mock_get_utility):
    method test_new_webroot_empty_map_cancel (line 118) | def test_new_webroot_empty_map_cancel(self, mock_get_utility):
    method test_perform_missing_root (line 130) | def test_perform_missing_root(self):
    method test_perform_reraises_other_errors (line 135) | def test_perform_reraises_other_errors(self):
    method test_failed_chown (line 150) | def test_failed_chown(self, mock_ownership):
    method test_perform_new_webroot_not_in_map (line 155) | def test_perform_new_webroot_not_in_map(self, mock_get_utility):
    method test_perform_permissions (line 169) | def test_perform_permissions(self):
    method test_perform_cleanup (line 185) | def test_perform_cleanup(self):
    method test_perform_cleanup_existing_dirs (line 202) | def test_perform_cleanup_existing_dirs(self):
    method test_perform_cleanup_multiple_challenges (line 212) | def test_perform_cleanup_multiple_challenges(self):
    method test_cleanup_leftovers (line 230) | def test_cleanup_leftovers(self):
    method test_cleanup_failure (line 244) | def test_cleanup_failure(self, mock_rmdir):
  class WebrootActionTest (line 257) | class WebrootActionTest(unittest.TestCase):
    method setUp (line 263) | def setUp(self):
    method test_webroot_map_action (line 271) | def test_webroot_map_action(self):
    method test_domain_before_webroot (line 276) | def test_domain_before_webroot(self):
    method test_domain_before_webroot_error (line 282) | def test_domain_before_webroot_error(self):
    method test_multiwebroot (line 288) | def test_multiwebroot(self):
    method test_webroot_map_partial_without_perform (line 296) | def test_webroot_map_partial_without_perform(self):
    method _get_config_after_perform (line 309) | def _get_config_after_perform(self, config):

FILE: tests/renewal_test.py
  class RenewalTest (line 13) | class RenewalTest(test_util.ConfigTestCase):
    method test_ancient_webroot_renewal_conf (line 15) | def test_ancient_webroot_renewal_conf(self, mock_set_by_cli):
    method test_webroot_params_conservation (line 31) | def test_webroot_params_conservation(self, mock_set_by_cli):
  class RestoreRequiredConfigElementsTest (line 55) | class RestoreRequiredConfigElementsTest(test_util.ConfigTestCase):
    method _call (line 58) | def _call(cls, *args, **kwargs):
    method test_allow_subset_of_names_success (line 63) | def test_allow_subset_of_names_success(self, mock_set_by_cli):
    method test_allow_subset_of_names_failure (line 69) | def test_allow_subset_of_names_failure(self, mock_set_by_cli):
    method test_pref_challs_list (line 76) | def test_pref_challs_list(self, mock_set_by_cli):
    method test_pref_challs_str (line 84) | def test_pref_challs_str(self, mock_set_by_cli):
    method test_pref_challs_failure (line 92) | def test_pref_challs_failure(self, mock_set_by_cli):
    method test_must_staple_success (line 98) | def test_must_staple_success(self, mock_set_by_cli):
    method test_must_staple_failure (line 104) | def test_must_staple_failure(self, mock_set_by_cli):

FILE: tests/renewupdater_test.py
  class RenewUpdaterTest (line 13) | class RenewUpdaterTest(test_util.ConfigTestCase):
    method setUp (line 16) | def setUp(self):
    method test_server_updates (line 27) | def test_server_updates(self, _, mock_geti, mock_select, mock_getsave):
    method test_renew_deployer (line 44) | def test_renew_deployer(self):
    method test_updater_skip_dry_run (line 51) | def test_updater_skip_dry_run(self, mock_log):
    method test_deployer_skip_dry_run (line 59) | def test_deployer_skip_dry_run(self, mock_log):
    method test_enhancement_updates (line 67) | def test_enhancement_updates(self, mock_geti):
    method test_enhancement_deployer (line 73) | def test_enhancement_deployer(self):
    method test_enhancement_updates_not_called (line 79) | def test_enhancement_updates_not_called(self, mock_geti):
    method test_enhancement_deployer_not_called (line 85) | def test_enhancement_deployer_not_called(self):
    method test_enhancement_no_updater (line 92) | def test_enhancement_no_updater(self, mock_geti):
    method test_enhancement_no_deployer (line 107) | def test_enhancement_no_deployer(self):

FILE: tests/reporter_test.py
  class ReporterTest (line 9) | class ReporterTest(unittest.TestCase):
    method setUp (line 11) | def setUp(self):
    method tearDown (line 18) | def tearDown(self):
    method test_multiline_message (line 21) | def test_multiline_message(self):
    method test_tty_print_empty (line 28) | def test_tty_print_empty(self):
    method test_no_tty_print_empty (line 32) | def test_no_tty_print_empty(self):
    method test_tty_successful_exit (line 41) | def test_tty_successful_exit(self):
    method test_no_tty_successful_exit (line 45) | def test_no_tty_successful_exit(self):
    method test_tty_unsuccessful_exit (line 48) | def test_tty_unsuccessful_exit(self):
    method test_no_tty_unsuccessful_exit (line 52) | def test_no_tty_unsuccessful_exit(self):
    method _successful_exit_common (line 55) | def _successful_exit_common(self):
    method _unsuccessful_exit_common (line 64) | def _unsuccessful_exit_common(self):
    method _add_messages (line 76) | def _add_messages(self):

FILE: tests/reverter_test.py
  class ReverterCheckpointLocalTest (line 16) | class ReverterCheckpointLocalTest(test_util.ConfigTestCase):
    method setUp (line 18) | def setUp(self):
    method tearDown (line 30) | def tearDown(self):
    method test_no_change (line 38) | def test_no_change(self, mock_read):
    method test_basic_add_to_temp_checkpoint (line 51) | def test_basic_add_to_temp_checkpoint(self):
    method test_add_to_checkpoint_copy_failure (line 66) | def test_add_to_checkpoint_copy_failure(self):
    method test_checkpoint_conflict (line 73) | def test_checkpoint_conflict(self):
    method test_multiple_saves_and_temp_revert (line 92) | def test_multiple_saves_and_temp_revert(self):
    method test_multiple_registration_fail_and_revert (line 101) | def test_multiple_registration_fail_and_revert(self):
    method test_multiple_registration_same_file (line 121) | def test_multiple_registration_same_file(self):
    method test_register_file_creation_write_error (line 131) | def test_register_file_creation_write_error(self):
    method test_bad_registration (line 139) | def test_bad_registration(self):
    method test_register_undo_command (line 145) | def test_register_undo_command(self):
    method test_bad_register_undo_command (line 159) | def test_bad_register_undo_command(self):
    method test_run_undo_commands (line 168) | def test_run_undo_commands(self, mock_run):
    method test_recovery_routine_in_progress_failure (line 181) | def test_recovery_routine_in_progress_failure(self):
    method test_recover_checkpoint_revert_temp_failures (line 189) | def test_recover_checkpoint_revert_temp_failures(self):
    method test_recover_checkpoint_rollback_failure (line 202) | def test_recover_checkpoint_rollback_failure(self):
    method test_recover_checkpoint_copy_failure (line 214) | def test_recover_checkpoint_copy_failure(self):
    method test_recover_checkpoint_rm_failure (line 222) | def test_recover_checkpoint_rm_failure(self):
    method test_recover_checkpoint_missing_new_files (line 231) | def test_recover_checkpoint_missing_new_files(self, mock_warn):
    method test_recover_checkpoint_remove_failure (line 238) | def test_recover_checkpoint_remove_failure(self, mock_remove):
    method test_recovery_routine_temp_and_perm (line 244) | def test_recovery_routine_temp_and_perm(self):
  class TestFullCheckpointsReverter (line 278) | class TestFullCheckpointsReverter(test_util.ConfigTestCase):
    method setUp (line 280) | def setUp(self):
    method tearDown (line 291) | def tearDown(self):
    method test_rollback_improper_inputs (line 298) | def test_rollback_improper_inputs(self):
    method test_rollback_finalize_checkpoint_valid_inputs (line 306) | def test_rollback_finalize_checkpoint_valid_inputs(self):
    method test_finalize_checkpoint_no_in_progress (line 336) | def test_finalize_checkpoint_no_in_progress(self):
    method test_finalize_checkpoint_cannot_title (line 341) | def test_finalize_checkpoint_cannot_title(self, mock_move):
    method test_finalize_checkpoint_no_rename_directory (line 349) | def test_finalize_checkpoint_no_rename_directory(self, mock_replace):
    method test_rollback_too_many (line 358) | def test_rollback_too_many(self, mock_logger):
    method test_multi_rollback (line 369) | def test_multi_rollback(self):
    method _setup_three_checkpoints (line 377) | def _setup_three_checkpoints(self):
  function setup_test_files (line 406) | def setup_test_files():
  function get_save_notes (line 424) | def get_save_notes(dire):
  function get_filepaths (line 429) | def get_filepaths(dire):
  function get_new_files (line 434) | def get_new_files(dire):
  function get_undo_commands (line 439) | def get_undo_commands(dire):
  function read_in (line 445) | def read_in(path):
  function update_file (line 451) | def update_file(filename, string):

FILE: tests/storage_test.py
  function unlink_all (line 23) | def unlink_all(rc_object):
  function fill_with_sample_data (line 29) | def fill_with_sample_data(rc_object):
  class RelevantValuesTest (line 36) | class RelevantValuesTest(unittest.TestCase):
    method setUp (line 39) | def setUp(self):
    method _call (line 42) | def _call(self, *args, **kwargs):
    method test_namespace (line 48) | def test_namespace(self, mock_find_all, mock_option_was_set):
    method test_option_set (line 57) | def test_option_set(self, mock_option_was_set):
    method test_option_unset (line 69) | def test_option_unset(self, mock_option_was_set):
  class BaseRenewableCertTest (line 78) | class BaseRenewableCertTest(test_util.ConfigTestCase):
    method setUp (line 86) | def setUp(self):
    method _write_out_kind (line 124) | def _write_out_kind(self, kind, ver, value=None):
    method _write_out_ex_kinds (line 136) | def _write_out_ex_kinds(self):
  class RenewableCertTests (line 142) | class RenewableCertTests(BaseRenewableCertTest):
    method test_initialization (line 145) | def test_initialization(self):
    method test_renewal_bad_config (line 152) | def test_renewal_bad_config(self):
    method test_renewal_incomplete_config (line 167) | def test_renewal_incomplete_config(self):
    method test_no_renewal_version (line 181) | def test_no_renewal_version(self):
    method test_renewal_newer_version (line 191) | def test_renewal_newer_version(self):
    method test_consistent (line 203) | def test_consistent(self):
    method test_current_target (line 245) | def test_current_target(self):
    method test_current_version (line 263) | def test_current_version(self):
    method test_no_current_version (line 271) | def test_no_current_version(self):
    method test_latest_and_next_versions (line 274) | def test_latest_and_next_versions(self):
    method test_ensure_deployed (line 298) | def test_ensure_deployed(self, mock_logger):
    method test_update_link_to (line 314) | def test_update_link_to(self):
    method test_version (line 333) | def test_version(self):
    method test_update_all_links_to_success (line 341) | def test_update_all_links_to_success(self):
    method test_update_all_links_to_partial_failure (line 353) | def test_update_all_links_to_partial_failure(self):
    method test_update_all_links_to_full_failure (line 369) | def test_update_all_links_to_full_failure(self):
    method test_has_pending_deployment (line 384) | def test_has_pending_deployment(self):
    method test_names (line 398) | def test_names(self):
    method test_time_interval_judgments (line 411) | def test_time_interval_judgments(self, mock_datetime, mock_cli):
    method test_autorenewal_is_enabled (line 455) | def test_autorenewal_is_enabled(self):
    method test_should_autorenew (line 466) | def test_should_autorenew(self, mock_ocsp, mock_cli):
    method test_save_successor (line 482) | def test_save_successor(self, mock_rv):
    method test_save_successor_maintains_group_mode (line 546) | def test_save_successor_maintains_group_mode(self, mock_rv):
    method test_save_successor_maintains_gid (line 568) | def test_save_successor_maintains_gid(self, mock_ownership, mock_rv):
    method test_new_lineage (line 581) | def test_new_lineage(self, mock_rv):
    method test_new_lineage_nonexistent_dirs (line 628) | def test_new_lineage_nonexistent_dirs(self, mock_rv):
    method test_invalid_config_filename (line 650) | def test_invalid_config_filename(self, mock_uln):
    method test_bad_kind (line 657) | def test_bad_kind(self):
    method test_ocsp_revoked (line 676) | def test_ocsp_revoked(self, mock_checker):
    method test_add_time_interval (line 705) | def test_add_time_interval(self):
    method test_is_test_cert (line 747) | def test_is_test_cert(self):
    method test_missing_cert (line 760) | def test_missing_cert(self):
    method test_write_renewal_config (line 770) | def test_write_renewal_config(self):
    method test_update_symlinks (line 803) | def test_update_symlinks(self):
  class DeleteFilesTest (line 818) | class DeleteFilesTest(BaseRenewableCertTest):
    method setUp (line 820) | def setUp(self):
    method _call (line 836) | def _call(self):
    method test_delete_all_files (line 841) | def test_delete_all_files(self):
    method test_bad_renewal_config (line 851) | def test_bad_renewal_config(self):
    method test_no_renewal_config (line 861) | def test_no_renewal_config(self):
    method test_no_cert_file (line 868) | def test_no_cert_file(self):
    method test_no_readme_file (line 878) | def test_no_readme_file(self):
    method test_livedir_not_empty (line 888) | def test_livedir_not_empty(self):
    method test_no_archive (line 899) | def test_no_archive(self):
  class CertPathForCertNameTest (line 908) | class CertPathForCertNameTest(BaseRenewableCertTest):
    method setUp (line 910) | def setUp(self):
    method _call (line 918) | def _call(self, cli_config, certname):
    method test_simple_cert_name (line 922) | def test_simple_cert_name(self):
    method test_no_such_cert_name (line 925) | def test_no_such_cert_name(self):

FILE: tests/util_test.py
  class RunScriptTest (line 17) | class RunScriptTest(unittest.TestCase):
    method _call (line 20) | def _call(cls, params):
    method test_default (line 25) | def test_default(self, mock_popen):
    method test_bad_process (line 35) | def test_bad_process(self, mock_popen):
    method test_failure (line 41) | def test_failure(self, mock_popen):
  class ExeExistsTest (line 48) | class ExeExistsTest(unittest.TestCase):
    method _call (line 52) | def _call(cls, exe):
    method test_exe_exists (line 56) | def test_exe_exists(self):
    method test_exe_not_exists (line 60) | def test_exe_not_exists(self):
  class LockDirUntilExit (line 65) | class LockDirUntilExit(test_util.TempDirTestCase):
    method _call (line 68) | def _call(cls, *args, **kwargs):
    method setUp (line 72) | def setUp(self):
    method test_it (line 80) | def test_it(self, mock_register, mock_logger):
  class SetUpCoreDirTest (line 100) | class SetUpCoreDirTest(test_util.TempDirTestCase):
    method _call (line 103) | def _call(self, *args, **kwargs):
    method test_success (line 108) | def test_success(self, mock_lock):
    method test_failure (line 115) | def test_failure(self, mock_make_or_verify):
  class MakeOrVerifyDirTest (line 120) | class MakeOrVerifyDirTest(test_util.TempDirTestCase):
    method setUp (line 128) | def setUp(self):
    method _call (line 134) | def _call(self, directory, mode):
    method test_creates_dir_when_missing (line 138) | def test_creates_dir_when_missing(self):
    method test_existing_correct_mode_does_not_fail (line 144) | def test_existing_correct_mode_does_not_fail(self):
    method test_existing_wrong_mode_fails (line 148) | def test_existing_wrong_mode_fails(self):
    method test_reraises_os_error (line 151) | def test_reraises_os_error(self):
  class UniqueFileTest (line 157) | class UniqueFileTest(test_util.TempDirTestCase):
    method setUp (line 160) | def setUp(self):
    method _call (line 165) | def _call(self, mode=0o600):
    method test_returns_fd_for_writing (line 169) | def test_returns_fd_for_writing(self):
    method test_right_mode (line 176) | def test_right_mode(self):
    method test_default_exists (line 184) | def test_default_exists(self):
  class UniqueLineageNameTest (line 216) | class UniqueLineageNameTest(test_util.TempDirTestCase):
    method _call (line 219) | def _call(self, filename, mode=0o777):
    method test_basic (line 223) | def test_basic(self):
    method test_multiple (line 229) | def test_multiple(self):
    method test_failure (line 240) | def test_failure(self):
  class SafelyRemoveTest (line 245) | class SafelyRemoveTest(test_util.TempDirTestCase):
    method setUp (line 248) | def setUp(self):
    method _call (line 253) | def _call(self):
    method test_exists (line 257) | def test_exists(self):
    method test_missing (line 263) | def test_missing(self):
    method test_other_error_passthrough (line 268) | def test_other_error_passthrough(self):
  class SafeEmailTest (line 274) | class SafeEmailTest(unittest.TestCase):
    method _call (line 277) | def _call(cls, addr):
    method test_valid_emails (line 281) | def test_valid_emails(self):
    method test_invalid_emails (line 290) | def test_invalid_emails(self):
  class AddDeprecatedArgumentTest (line 300) | class AddDeprecatedArgumentTest(unittest.TestCase):
    method setUp (line 302) | def setUp(self):
    method _call (line 305) | def _call(self, argument_name, nargs):
    method test_warning_no_arg (line 309) | def test_warning_no_arg(self):
    method test_warning_with_arg (line 317) | def test_warning_with_arg(self):
    method test_help (line 325) | def test_help(self):
    method test_set_constant (line 335) | def test_set_constant(self):
    method test_tuple_constant (line 343) | def test_tuple_constant(self):
    method _test_constant_common (line 351) | def _test_constant_common(self, typ):
  class EnforceLeValidity (line 360) | class EnforceLeValidity(unittest.TestCase):
    method _call (line 362) | def _call(self, domain):
    method test_sanity (line 366) | def test_sanity(self):
    method test_invalid_chars (line 369) | def test_invalid_chars(self):
    method test_leading_hyphen (line 373) | def test_leading_hyphen(self):
    method test_trailing_hyphen (line 377) | def test_trailing_hyphen(self):
    method test_one_label (line 381) | def test_one_label(self):
    method test_valid_domain (line 384) | def test_valid_domain(self):
    method test_input_with_scheme (line 387) | def test_input_with_scheme(self):
    method test_valid_input_with_scheme_name (line 391) | def test_valid_input_with_scheme_name(self):
  class EnforceDomainSanityTest (line 395) | class EnforceDomainSanityTest(unittest.TestCase):
    method _call (line 398) | def _call(self, domain):
    method test_nonascii_str (line 402) | def test_nonascii_str(self):
    method test_nonascii_unicode (line 406) | def test_nonascii_unicode(self):
    method test_too_long (line 410) | def test_too_long(self):
    method test_not_too_long (line 415) | def test_not_too_long(self):
    method test_empty_label (line 419) | def test_empty_label(self):
    method test_empty_trailing_label (line 424) | def test_empty_trailing_label(self):
    method test_long_label_1 (line 429) | def test_long_label_1(self):
    method test_long_label_2 (line 434) | def test_long_label_2(self):
    method test_not_long_label (line 439) | def test_not_long_label(self):
    method test_empty_domain (line 443) | def test_empty_domain(self):
    method test_punycode_ok (line 448) | def test_punycode_ok(self):
  class IsWildcardDomainTest (line 454) | class IsWildcardDomainTest(unittest.TestCase):
    method setUp (line 457) | def setUp(self):
    method _call (line 461) | def _call(self, domain):
    method test_no_wildcard (line 465) | def test_no_wildcard(self):
    method test_wildcard (line 469) | def test_wildcard(self):
  class OsInfoTest (line 474) | class OsInfoTest(unittest.TestCase):
    method test_systemd_os_release_like (line 479) | def test_systemd_os_release_like(self, m_distro):
    method test_get_os_info_ua (line 488) | def test_get_os_info_ua(self, m_distro):
    method test_get_os_info (line 503) | def test_get_os_info(self, m_distro):
    method test_non_systemd_os_info (line 514) | def test_non_systemd_os_info(self, popen_mock):
    method test_python_os_info_notfound (line 544) | def test_python_os_info_notfound(self, m_distro):
    method test_python_os_info_custom (line 551) | def test_python_os_info_custom(self, m_distro):
  class AtexitRegisterTest (line 557) | class AtexitRegisterTest(unittest.TestCase):
    method setUp (line 559) | def setUp(self):
    method _call (line 565) | def _call(cls, *args, **kwargs):
    method test_called (line 569) | def test_called(self):
    method test_not_called (line 573) | def test_not_called(self):
    method _test_common (line 577) | def _test_common(self, initial_pid):
Condensed preview — 243 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,619K chars).
[
  {
    "path": ".gitignore",
    "chars": 4,
    "preview": ".pc/"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 76647,
    "preview": "# Certbot change log\n\nCertbot adheres to [Semantic Versioning](https://semver.org/).\n\n## 1.3.0 - 2020-03-03\n\n### Added\n\n"
  },
  {
    "path": "LICENSE.txt",
    "chars": 11456,
    "preview": "Certbot ACME Client\nCopyright (c) Electronic Frontier Foundation and others\nLicensed Apache Version 2.0\n\nThe nginx plugi"
  },
  {
    "path": "MANIFEST.in",
    "chars": 271,
    "preview": "include README.rst\ninclude CHANGELOG.md\ninclude LICENSE.txt\nrecursive-include docs *\nrecursive-include examples *\nrecurs"
  },
  {
    "path": "PKG-INFO",
    "chars": 8313,
    "preview": "Metadata-Version: 2.1\nName: certbot\nVersion: 1.3.0\nSummary: ACME client\nHome-page: https://github.com/letsencrypt/letsen"
  },
  {
    "path": "README.rst",
    "chars": 6009,
    "preview": ".. This file contains a series of comments that are used to include sections of this README in other files. Do not modif"
  },
  {
    "path": "certbot/__init__.py",
    "chars": 113,
    "preview": "\"\"\"Certbot client.\"\"\"\n\n# version number like 1.2.3a0, must have at least 2 parts, like 1.2\n__version__ = '1.3.0'\n"
  },
  {
    "path": "certbot/_internal/__init__.py",
    "chars": 184,
    "preview": "\"\"\"\nModules internal to Certbot.\n\nThis package contains modules that are not considered part of Certbot's public\nAPI. Th"
  },
  {
    "path": "certbot/_internal/account.py",
    "chars": 14133,
    "preview": "\"\"\"Creates ACME accounts for server.\"\"\"\nimport datetime\nimport functools\nimport hashlib\nimport logging\nimport shutil\nimp"
  },
  {
    "path": "certbot/_internal/auth_handler.py",
    "chars": 18819,
    "preview": "\"\"\"ACME AuthHandler.\"\"\"\nimport datetime\nimport logging\nimport time\n\nimport zope.component\n\nfrom acme import challenges\nf"
  },
  {
    "path": "certbot/_internal/cert_manager.py",
    "chars": 15354,
    "preview": "\"\"\"Tools for managing certificates.\"\"\"\nimport datetime\nimport logging\nimport re\nimport traceback\n\nimport pytz\nimport zop"
  },
  {
    "path": "certbot/_internal/cli/__init__.py",
    "chars": 25261,
    "preview": "\"\"\"Certbot command line argument & config processing.\"\"\"\n# pylint: disable=too-many-lines\nfrom __future__ import print_f"
  },
  {
    "path": "certbot/_internal/cli/cli_constants.py",
    "chars": 4485,
    "preview": "\"\"\"Certbot command line constants\"\"\"\nimport sys\n\nfrom certbot.compat import os\n\n# For help strings, figure out how the u"
  },
  {
    "path": "certbot/_internal/cli/cli_utils.py",
    "chars": 7870,
    "preview": "\"\"\"Certbot command line util function\"\"\"\nimport argparse\nimport copy\n\nimport zope.interface.interface  # pylint: disable"
  },
  {
    "path": "certbot/_internal/cli/group_adder.py",
    "chars": 927,
    "preview": "\"\"\"This module contains a function to add the groups of arguments for the help\ndisplay\"\"\"\nfrom certbot._internal.cli imp"
  },
  {
    "path": "certbot/_internal/cli/helpful.py",
    "chars": 18189,
    "preview": "\"\"\"Certbot command line argument parser\"\"\"\nfrom __future__ import print_function\nimport argparse\nimport copy\nimport glob"
  },
  {
    "path": "certbot/_internal/cli/paths_parser.py",
    "chars": 2047,
    "preview": "\"\"\"This is a module that adds configuration to the argument parser regarding\npaths for certificates\"\"\"\nfrom certbot.comp"
  },
  {
    "path": "certbot/_internal/cli/plugins_parsing.py",
    "chars": 6187,
    "preview": "\"\"\"This is a module that handles parsing of plugins for the argument parser\"\"\"\nfrom certbot._internal.cli import flag_de"
  },
  {
    "path": "certbot/_internal/cli/report_config_interaction.py",
    "chars": 930,
    "preview": "\"\"\"This is a module that reports config option interaction that should be\nchecked by set_by_cli\"\"\"\nimport six\n\nfrom cert"
  },
  {
    "path": "certbot/_internal/cli/subparsers.py",
    "chars": 3957,
    "preview": "\"\"\"This module creates subparsers for the argument parser\"\"\"\nfrom certbot import interfaces\nfrom certbot._internal impor"
  },
  {
    "path": "certbot/_internal/cli/verb_help.py",
    "chars": 5225,
    "preview": "\"\"\"This module contain help information for verbs supported by certbot\"\"\"\nfrom certbot.compat import os\nfrom certbot._in"
  },
  {
    "path": "certbot/_internal/client.py",
    "chars": 29872,
    "preview": "\"\"\"Certbot client API.\"\"\"\nimport datetime\nimport logging\nimport platform\n\nfrom cryptography.hazmat.backends import defau"
  },
  {
    "path": "certbot/_internal/configuration.py",
    "chars": 5887,
    "preview": "\"\"\"Certbot user-supplied configuration.\"\"\"\nimport copy\n\nfrom six.moves.urllib import parse\nimport zope.interface\n\nfrom c"
  },
  {
    "path": "certbot/_internal/constants.py",
    "chars": 6354,
    "preview": "\"\"\"Certbot constants.\"\"\"\nimport logging\n\nimport pkg_resources\n\nfrom acme import challenges\nfrom certbot.compat import mi"
  },
  {
    "path": "certbot/_internal/display/__init__.py",
    "chars": 33,
    "preview": "\"\"\"Certbot display utilities.\"\"\"\n"
  },
  {
    "path": "certbot/_internal/display/completer.py",
    "chars": 2175,
    "preview": "\"\"\"Provides Tab completion when prompting users for a path.\"\"\"\nimport glob\n\n# readline module is not available on all sy"
  },
  {
    "path": "certbot/_internal/display/dummy_readline.py",
    "chars": 570,
    "preview": "\"\"\"A dummy module with no effect for use on systems without readline.\"\"\"\n\n\ndef get_completer():\n    \"\"\"An empty implemen"
  },
  {
    "path": "certbot/_internal/display/enhancements.py",
    "chars": 1833,
    "preview": "\"\"\"Certbot Enhancement Display\"\"\"\nimport logging\n\nimport zope.component\n\nfrom certbot import errors\nfrom certbot import "
  },
  {
    "path": "certbot/_internal/eff.py",
    "chars": 3147,
    "preview": "\"\"\"Subscribes users to the EFF newsletter.\"\"\"\nimport logging\n\nimport requests\nimport zope.component\n\nfrom certbot import"
  },
  {
    "path": "certbot/_internal/error_handler.py",
    "chars": 7098,
    "preview": "\"\"\"Registers functions to be called if an exception or signal occurs.\"\"\"\nimport functools\nimport logging\nimport signal\ni"
  },
  {
    "path": "certbot/_internal/hooks.py",
    "chars": 9049,
    "preview": "\"\"\"Facilities for implementing hooks that call shell commands.\"\"\"\nfrom __future__ import print_function\n\nimport logging\n"
  },
  {
    "path": "certbot/_internal/lock.py",
    "chars": 9688,
    "preview": "\"\"\"Implements file locks compatible with Linux and Windows for locking files and directories.\"\"\"\nimport errno\nimport log"
  },
  {
    "path": "certbot/_internal/log.py",
    "chars": 12843,
    "preview": "\"\"\"Logging utilities for Certbot.\n\nThe best way to use this module is through `pre_arg_parse_setup` and\n`post_arg_parse_"
  },
  {
    "path": "certbot/_internal/main.py",
    "chars": 48541,
    "preview": "\"\"\"Certbot main entry point.\"\"\"\n# pylint: disable=too-many-lines\nfrom __future__ import print_function\n\nimport functools"
  },
  {
    "path": "certbot/_internal/plugins/__init__.py",
    "chars": 23,
    "preview": "\"\"\"Certbot plugins.\"\"\"\n"
  },
  {
    "path": "certbot/_internal/plugins/disco.py",
    "chars": 10144,
    "preview": "\"\"\"Utilities for plugins discovery and selection.\"\"\"\nimport collections\nimport itertools\nimport logging\n\nimport pkg_reso"
  },
  {
    "path": "certbot/_internal/plugins/manual.py",
    "chars": 8043,
    "preview": "\"\"\"Manual authenticator plugin\"\"\"\nimport zope.component\nimport zope.interface\n\nfrom acme import challenges\nfrom acme.mag"
  },
  {
    "path": "certbot/_internal/plugins/null.py",
    "chars": 1295,
    "preview": "\"\"\"Null plugin.\"\"\"\nimport logging\n\nimport zope.component\nimport zope.interface\n\nfrom certbot import interfaces\nfrom cert"
  },
  {
    "path": "certbot/_internal/plugins/selection.py",
    "chars": 13812,
    "preview": "\"\"\"Decide which plugins to use for authentication & installation\"\"\"\nfrom __future__ import print_function\n\nimport loggin"
  },
  {
    "path": "certbot/_internal/plugins/standalone.py",
    "chars": 7934,
    "preview": "\"\"\"Standalone Authenticator.\"\"\"\nimport collections\nimport logging\nimport socket\n# https://github.com/python/typeshed/blo"
  },
  {
    "path": "certbot/_internal/plugins/webroot.py",
    "chars": 12489,
    "preview": "\"\"\"Webroot plugin.\"\"\"\nimport argparse\nimport collections\nimport json\nimport logging\n\nimport six\nimport zope.component\nim"
  },
  {
    "path": "certbot/_internal/renewal.py",
    "chars": 20666,
    "preview": "\"\"\"Functionality for autorenewal and associated juggling of configurations\"\"\"\nfrom __future__ import print_function\n\nimp"
  },
  {
    "path": "certbot/_internal/reporter.py",
    "chars": 3514,
    "preview": "\"\"\"Collects and displays information to the user.\"\"\"\nfrom __future__ import print_function\n\nimport collections\nimport lo"
  },
  {
    "path": "certbot/_internal/storage.py",
    "chars": 46237,
    "preview": "\"\"\"Renewable certificates storage.\"\"\"\nimport datetime\nimport glob\nimport logging\nimport re\nimport shutil\nimport stat\n\nim"
  },
  {
    "path": "certbot/_internal/updater.py",
    "chars": 3963,
    "preview": "\"\"\"Updaters run at renewal\"\"\"\nimport logging\n\nfrom certbot import errors\nfrom certbot import interfaces\nfrom certbot._in"
  },
  {
    "path": "certbot/achallenges.py",
    "chars": 1582,
    "preview": "\"\"\"Client annotated ACME challenges.\n\nPlease use names such as ``achall`` to distinguish from variables \"of type\"\n:class"
  },
  {
    "path": "certbot/compat/__init__.py",
    "chars": 249,
    "preview": "\"\"\"\nCompatibility layer to run certbot both on Linux and Windows.\n\nThis package contains all logic that needs to be impl"
  },
  {
    "path": "certbot/compat/_path.py",
    "chars": 1615,
    "preview": "\"\"\"\nThis compat module wraps os.path to forbid some functions.\n\nisort:skip_file\n\"\"\"\n# pylint: disable=function-redefined"
  },
  {
    "path": "certbot/compat/filesystem.py",
    "chars": 25351,
    "preview": "\"\"\"Compat module to handle files security on Windows and Linux\"\"\"\nfrom __future__ import absolute_import\n\nimport errno\ni"
  },
  {
    "path": "certbot/compat/misc.py",
    "chars": 3155,
    "preview": "\"\"\"\nThis compat module handles various platform specific calls that do not fall into one\nparticular category.\n\"\"\"\nfrom _"
  },
  {
    "path": "certbot/compat/os.py",
    "chars": 7537,
    "preview": "\"\"\"\nThis compat modules is a wrapper of the core os module that forbids usage of specific operations\n(e.g. chown, chmod,"
  },
  {
    "path": "certbot/crypto_util.py",
    "chars": 16313,
    "preview": "\"\"\"Certbot client crypto utility functions.\n\n.. todo:: Make the transition to use PSS rather than PKCS1_v1_5 when the se"
  },
  {
    "path": "certbot/display/__init__.py",
    "chars": 33,
    "preview": "\"\"\"Certbot display utilities.\"\"\"\n"
  },
  {
    "path": "certbot/display/ops.py",
    "chars": 12547,
    "preview": "\"\"\"Contains UI methods for LE user operations.\"\"\"\nimport logging\n\nimport zope.component\n\nfrom certbot import errors\nfrom"
  },
  {
    "path": "certbot/display/util.py",
    "chars": 21647,
    "preview": "\"\"\"Certbot display.\"\"\"\nimport logging\nimport sys\nimport textwrap\n\nimport zope.interface\n\nfrom certbot import errors\nfrom"
  },
  {
    "path": "certbot/errors.py",
    "chars": 2655,
    "preview": "\"\"\"Certbot client errors.\"\"\"\n\n\nclass Error(Exception):\n    \"\"\"Generic Certbot client error.\"\"\"\n\n\nclass AccountStorageErr"
  },
  {
    "path": "certbot/interfaces.py",
    "chars": 23054,
    "preview": "\"\"\"Certbot client interfaces.\"\"\"\nimport abc\n\nimport six\nimport zope.interface\n\n# pylint: disable=no-self-argument,no-met"
  },
  {
    "path": "certbot/main.py",
    "chars": 405,
    "preview": "\"\"\"Certbot main public entry point.\"\"\"\nfrom certbot._internal import main as internal_main\n\n\ndef main(cli_args=None):\n  "
  },
  {
    "path": "certbot/ocsp.py",
    "chars": 13669,
    "preview": "\"\"\"Tools for checking certificate revocation.\"\"\"\nfrom datetime import datetime\nfrom datetime import timedelta\nimport log"
  },
  {
    "path": "certbot/plugins/__init__.py",
    "chars": 23,
    "preview": "\"\"\"Certbot plugins.\"\"\"\n"
  },
  {
    "path": "certbot/plugins/common.py",
    "chars": 15900,
    "preview": "\"\"\"Plugin common functions.\"\"\"\nimport logging\nimport re\nimport shutil\nimport sys\nimport tempfile\nimport warnings\n\nfrom j"
  },
  {
    "path": "certbot/plugins/dns_common.py",
    "chars": 11956,
    "preview": "\"\"\"Common code for DNS Authenticator Plugins.\"\"\"\n\nimport abc\nimport logging\nfrom time import sleep\n\nimport configobj\nimp"
  },
  {
    "path": "certbot/plugins/dns_common_lexicon.py",
    "chars": 5612,
    "preview": "\"\"\"Common code for DNS Authenticator Plugins built on Lexicon.\"\"\"\nimport logging\n\nfrom requests.exceptions import HTTPEr"
  },
  {
    "path": "certbot/plugins/dns_test_common.py",
    "chars": 1662,
    "preview": "\"\"\"Base test class for DNS authenticators.\"\"\"\n\nimport configobj\nimport josepy as jose\nimport mock\nimport six\n\nfrom acme "
  },
  {
    "path": "certbot/plugins/dns_test_common_lexicon.py",
    "chars": 5646,
    "preview": "\"\"\"Base test class for DNS authenticators built on Lexicon.\"\"\"\n\nimport josepy as jose\nimport mock\nfrom requests.exceptio"
  },
  {
    "path": "certbot/plugins/enhancements.py",
    "chars": 6094,
    "preview": "\"\"\"New interface style Certbot enhancements\"\"\"\nimport abc\n\nimport six\n\nfrom acme.magic_typing import Any\nfrom acme.magic"
  },
  {
    "path": "certbot/plugins/storage.py",
    "chars": 4218,
    "preview": "\"\"\"Plugin storage class.\"\"\"\nimport json\nimport logging\n\nfrom acme.magic_typing import Any\nfrom acme.magic_typing import "
  },
  {
    "path": "certbot/plugins/util.py",
    "chars": 1735,
    "preview": "\"\"\"Plugin utilities.\"\"\"\nimport logging\n\nfrom certbot import util\nfrom certbot.compat import os\nfrom certbot.compat.misc "
  },
  {
    "path": "certbot/reverter.py",
    "chars": 21956,
    "preview": "\"\"\"Reverter class saves configuration checkpoints and allows for recovery.\"\"\"\nimport csv\nimport glob\nimport logging\nimpo"
  },
  {
    "path": "certbot/ssl-dhparams.pem",
    "chars": 424,
    "preview": "-----BEGIN DH PARAMETERS-----\nMIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n+8yTnc4kmz75fS/jY2MMddj2g"
  },
  {
    "path": "certbot/tests/__init__.py",
    "chars": 42,
    "preview": "\"\"\"Utilities for running Certbot tests\"\"\"\n"
  },
  {
    "path": "certbot/tests/acme_util.py",
    "chars": 2842,
    "preview": "\"\"\"ACME utilities for testing.\"\"\"\nimport datetime\n\nimport josepy as jose\nimport six\n\nfrom acme import challenges\nfrom ac"
  },
  {
    "path": "certbot/tests/testdata/README",
    "chars": 462,
    "preview": "The following command has been used to generate test keys:\n\n\tfor x in 256 512 2048; do openssl genrsa -out rsa${k}_key.p"
  },
  {
    "path": "certbot/tests/testdata/cert-5sans_512.pem",
    "chars": 952,
    "preview": "-----BEGIN CERTIFICATE-----\nMIICkTCCAjugAwIBAgIJAJNbfABWQ8bbMA0GCSqGSIb3DQEBCwUAMHkxCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIDApDYWx"
  },
  {
    "path": "certbot/tests/testdata/cert-nosans_nistp256.pem",
    "chars": 623,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIBoDCCAUYCCQDCnzfUZ7TQdDAKBggqhkjOPQQDAjBYMQswCQYDVQQGEwJVUzER\nMA8GA1UECAwITWljaGlnYW4xEjA"
  },
  {
    "path": "certbot/tests/testdata/cert-san_512.pem",
    "chars": 786,
    "preview": "-----BEGIN CERTIFICATE-----\nMIICFjCCAcCgAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhMCVVMx\nETAPBgNVBAgMCE1pY2hpZ2FuMRI"
  },
  {
    "path": "certbot/tests/testdata/cert_2048.pem",
    "chars": 1200,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIDSjCCAjKgAwIBAgIJAIYLtIQHBBG0MA0GCSqGSIb3DQEBCwUAMDoxCzAJBgNV\nBAYTAkNBMQswCQYDVQQIDAJPTjE"
  },
  {
    "path": "certbot/tests/testdata/cert_512.pem",
    "chars": 709,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIB3jCCAYigAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhMCVVMx\nETAPBgNVBAgMCE1pY2hpZ2FuMRI"
  },
  {
    "path": "certbot/tests/testdata/cert_512_bad.pem",
    "chars": 887,
    "preview": "-----BEGIN CERTIFICATE-----\nMIICYzCCAg2gAwIBAgIJAPvqv4TcAtuFMA0GCSqGSIb3DQEBCwUAMIGMMQswCQYD\nVQQGEwJDQTEQMA4GA1UECAwHT25"
  },
  {
    "path": "certbot/tests/testdata/cert_fullchain_2048.pem",
    "chars": 2400,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIDSjCCAjKgAwIBAgIJAIYLtIQHBBG0MA0GCSqGSIb3DQEBCwUAMDoxCzAJBgNV\nBAYTAkNBMQswCQYDVQQIDAJPTjE"
  },
  {
    "path": "certbot/tests/testdata/cli.ini",
    "chars": 25,
    "preview": "agree-dev-preview = True\n"
  },
  {
    "path": "certbot/tests/testdata/csr-6sans_512.conf",
    "chars": 502,
    "preview": "[req]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n\n[req_distinguished_name]\nC=US\nC_default = US\n"
  },
  {
    "path": "certbot/tests/testdata/csr-6sans_512.pem",
    "chars": 676,
    "preview": "-----BEGIN CERTIFICATE REQUEST-----\nMIIBuzCCAWUCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIw\nEAYDVQQHDAlBbm4gQXJ"
  },
  {
    "path": "certbot/tests/testdata/csr-nonames_512.pem",
    "chars": 420,
    "preview": "-----BEGIN CERTIFICATE REQUEST-----\nMIH/MIGqAgEAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw\nHwYDVQQKDBhJbnRlcm5"
  },
  {
    "path": "certbot/tests/testdata/csr-nosans_512.conf",
    "chars": 277,
    "preview": "[req]\ndistinguished_name = req_distinguished_name\n\n[req_distinguished_name]\nC=US\nC_default = US\nST=Michigan\nST_default=M"
  },
  {
    "path": "certbot/tests/testdata/csr-nosans_512.pem",
    "chars": 493,
    "preview": "-----BEGIN CERTIFICATE REQUEST-----\nMIIBMzCB3gIBADB5MQswCQYDVQQGEwJVUzERMA8GA1UECAwITWljaGlnYW4xEjAQ\nBgNVBAcMCUFubiBBcmJ"
  },
  {
    "path": "certbot/tests/testdata/csr-nosans_nistp256.pem",
    "chars": 452,
    "preview": "-----BEGIN CERTIFICATE REQUEST-----\nMIIBFDCBugIBADBYMQswCQYDVQQGEwJVUzERMA8GA1UECAwITWljaGlnYW4xEjAQ\nBgNVBAcMCUFubiBBcmJ"
  },
  {
    "path": "certbot/tests/testdata/csr-san_512.pem",
    "chars": 574,
    "preview": "-----BEGIN CERTIFICATE REQUEST-----\nMIIBbjCCARgCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIw\nEAYDVQQHDAlBbm4gQXJ"
  },
  {
    "path": "certbot/tests/testdata/csr_512.pem",
    "chars": 452,
    "preview": "-----BEGIN CERTIFICATE REQUEST-----\nMIIBFTCBwAIBADBbMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh\nMB8GA1UECgwYSW50ZXJ"
  },
  {
    "path": "certbot/tests/testdata/nistp256_key.pem",
    "chars": 227,
    "preview": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIOvXH384CyNNv2lfxvjc7hg2f7ScYoLvlk/VpINLJlGBoAoGCCqGSM49\nAwEHoUQDQgAEPPl0JauSZukv"
  },
  {
    "path": "certbot/tests/testdata/ocsp_certificate.pem",
    "chars": 2273,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIGYDCCBEigAwIBAgIKcjrC4hZcebbtODANBgkqhkiG9w0BAQsFADBRMQswCQYD\nVQQGEwJOTzEdMBsGA1UECgwUQnV"
  },
  {
    "path": "certbot/tests/testdata/ocsp_issuer_certificate.pem",
    "chars": 2247,
    "preview": "22spng==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIGMzCCBBugAwIBAgIJMvsa+ZFQCj8nMA0GCSqGSIb3DQEBCwUAMFQxC"
  },
  {
    "path": "certbot/tests/testdata/ocsp_responder_certificate.pem",
    "chars": 1671,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIEpjCCAo6gAwIBAgINARMIGYlEsD1LTt6D7zANBgkqhkiG9w0BAQsFADBRMQsw\nCQYDVQQGEwJOTzEdMBsGA1UECgw"
  },
  {
    "path": "certbot/tests/testdata/os-release",
    "chars": 190,
    "preview": "NAME=\"SystemdOS\"\nVERSION=\"42.42.42 LTS, Unreal\"\nID=systemdos\nID_LIKE=\"something nonexistent debian\"\nVERSION_ID=\"42\"\nHOME"
  },
  {
    "path": "certbot/tests/testdata/rsa2048_key.pem",
    "chars": 1708,
    "preview": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDm1WIecnHjL4Fs\nJvxDP27GyeqnXKc41HsRP9cv4z+"
  },
  {
    "path": "certbot/tests/testdata/rsa256_key.pem",
    "chars": 298,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIGrAgEAAiEAm2Fylv+Uz7trgTW8EBHP3FQSMeZs2GNQ6VRo1sIVJEkCAwEAAQIh\nAJT0BA/xD01dFCAXzSNyj9n"
  },
  {
    "path": "certbot/tests/testdata/rsa512_key.pem",
    "chars": 493,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIBOgIBAAJBAKx1c7RR7R/drnBSQ/zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79\nvukFhN9HFoHZiUvOjm0c+pV"
  },
  {
    "path": "certbot/tests/testdata/sample-archive/cert1.pem",
    "chars": 1736,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIE1DCCA7ygAwIBAgITAPoz/CBluNQV/Eh9F+CS6dSxEDANBgkqhkiG9w0BAQsF\nADAfMR0wGwYDVQQDDBRoYXBweSB"
  },
  {
    "path": "certbot/tests/testdata/sample-archive/chain1.pem",
    "chars": 1123,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIDETCCAfmgAwIBAgIJAJzxkS6o1QkIMA0GCSqGSIb3DQEBCwUAMB8xHTAbBgNV\nBAMMFGhhcHB5IGhhY2tlciBmYWt"
  },
  {
    "path": "certbot/tests/testdata/sample-archive/fullchain1.pem",
    "chars": 2859,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIE1DCCA7ygAwIBAgITAPoz/CBluNQV/Eh9F+CS6dSxEDANBgkqhkiG9w0BAQsF\nADAfMR0wGwYDVQQDDBRoYXBweSB"
  },
  {
    "path": "certbot/tests/testdata/sample-archive/privkey1.pem",
    "chars": 1704,
    "preview": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8rnaiynCHVmeV\nWitX7oZRA22bb7NhPrJZuHZkktZ"
  },
  {
    "path": "certbot/tests/testdata/sample-renewal-ancient.conf",
    "chars": 1877,
    "preview": "cert = MAGICDIR/live/sample-renewal-ancient/cert.pem\nprivkey = MAGICDIR/live/sample-renewal-ancient/privkey.pem\nchain = "
  },
  {
    "path": "certbot/tests/testdata/sample-renewal.conf",
    "chars": 1884,
    "preview": "cert = MAGICDIR/live/sample-renewal/cert.pem\nprivkey = MAGICDIR/live/sample-renewal/privkey.pem\nchain = MAGICDIR/live/sa"
  },
  {
    "path": "certbot/tests/testdata/webrootconftest.ini",
    "chars": 54,
    "preview": "webroot\nwebroot-path = /tmp\ndomains = eg.com, eg2.com\n"
  },
  {
    "path": "certbot/tests/util.py",
    "chars": 14005,
    "preview": "\"\"\"Test utilities.\"\"\"\nimport logging\nfrom multiprocessing import Event\nfrom multiprocessing import Process\nimport shutil"
  },
  {
    "path": "certbot/util.py",
    "chars": 18988,
    "preview": "\"\"\"Utilities for all Certbot.\"\"\"\n# distutils.version under virtualenv confuses pylint\n# For more info, see: https://gith"
  },
  {
    "path": "certbot.egg-info/PKG-INFO",
    "chars": 8313,
    "preview": "Metadata-Version: 2.1\nName: certbot\nVersion: 1.3.0\nSummary: ACME client\nHome-page: https://github.com/letsencrypt/letsen"
  },
  {
    "path": "certbot.egg-info/SOURCES.txt",
    "chars": 6295,
    "preview": "CHANGELOG.md\nLICENSE.txt\nMANIFEST.in\nREADME.rst\nsetup.cfg\nsetup.py\ncertbot/__init__.py\ncertbot/achallenges.py\ncertbot/cr"
  },
  {
    "path": "certbot.egg-info/dependency_links.txt",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "certbot.egg-info/entry_points.txt",
    "chars": 292,
    "preview": "[certbot.plugins]\nmanual = certbot._internal.plugins.manual:Authenticator\nnull = certbot._internal.plugins.null:Installe"
  },
  {
    "path": "certbot.egg-info/requires.txt",
    "chars": 375,
    "preview": "acme>=0.40.0\nConfigArgParse>=0.9.3\nconfigobj\ncryptography>=1.2.3\ndistro>=1.0.1\njosepy>=1.1.0\nmock\nparsedatetime>=1.3\npyr"
  },
  {
    "path": "certbot.egg-info/top_level.txt",
    "chars": 8,
    "preview": "certbot\n"
  },
  {
    "path": "debian/README.source",
    "chars": 258,
    "preview": "Because of version dependencies, the debian/control file must be\ngenerated dynamically with each upstream version update"
  },
  {
    "path": "debian/certbot.cron.d",
    "chars": 775,
    "preview": "# /etc/cron.d/certbot: crontab entries for the certbot package\n#\n# Upstream recommends attempting renewal twice a day\n#\n"
  },
  {
    "path": "debian/certbot.docs",
    "chars": 11,
    "preview": "README.rst\n"
  },
  {
    "path": "debian/certbot.links",
    "chars": 104,
    "preview": "usr/bin/certbot usr/bin/letsencrypt\nusr/share/man/man1/certbot.1.gz usr/share/man/man1/letsencrypt.1.gz\n"
  },
  {
    "path": "debian/certbot.logrotate",
    "chars": 82,
    "preview": "/var/log/letsencrypt/*.log {\n    rotate 12\n    weekly\n    compress\n    missingok\n}"
  },
  {
    "path": "debian/certbot.manpages",
    "chars": 14,
    "preview": "build/man/*.1\n"
  },
  {
    "path": "debian/certbot.postrm",
    "chars": 1001,
    "preview": "#!/bin/sh\n# postrm script for letsencrypt\n#\n# see: dh_installdeb(1)\n\nset -e\n\n# summary of how this script can be called:"
  },
  {
    "path": "debian/certbot.service",
    "chars": 233,
    "preview": "[Unit]\nDescription=Certbot\nDocumentation=file:///usr/share/doc/python-certbot-doc/html/index.html\nDocumentation=https://"
  },
  {
    "path": "debian/certbot.timer",
    "chars": 156,
    "preview": "[Unit]\nDescription=Run certbot twice daily\n\n[Timer]\nOnCalendar=*-*-* 00,12:00:00\nRandomizedDelaySec=43200\nPersistent=tru"
  },
  {
    "path": "debian/changelog",
    "chars": 13968,
    "preview": "python-certbot (1.3.0-1) unstable; urgency=medium\n\n  * New upstream version 1.3.0\n  * Enable end-to-end testing 🎉\n\n -- H"
  },
  {
    "path": "debian/cli.ini",
    "chars": 121,
    "preview": "# Because we are using logrotate for greater flexibility, disable the\n# internal certbot logrotation.\nmax-log-backups = "
  },
  {
    "path": "debian/control",
    "chars": 4286,
    "preview": "Source: python-certbot\nMaintainer: Debian Let's Encrypt <team+letsencrypt@tracker.debian.org>\nUploaders: Harlan Lieberma"
  },
  {
    "path": "debian/copyright",
    "chars": 2506,
    "preview": "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\nSource: https://pypi.python.org/pypi/certbot\n"
  },
  {
    "path": "debian/patches/0001-remove-external-images.patch",
    "chars": 938,
    "preview": "Description:  Remove external image links in documentation\nAuthor: Harlan Lieberman-Berg <hlieberman@setec.io>\nForwarded"
  },
  {
    "path": "debian/patches/series",
    "chars": 34,
    "preview": "0001-remove-external-images.patch\n"
  },
  {
    "path": "debian/pydist-overrides",
    "chars": 195,
    "preview": "ConfigArgParse python-configargparse; PEP386\ncryptography python-cryptography; PEP386\nparsedatetime python-parsedatetime"
  },
  {
    "path": "debian/python-certbot-doc.doc-base",
    "chars": 338,
    "preview": "Document: python-certbot-doc\nTitle: Documentation for Certbot\nAuthor: Let's Encrypt Team\nAbstract: These HTML documentat"
  },
  {
    "path": "debian/python-certbot-doc.docs",
    "chars": 11,
    "preview": "build/html\n"
  },
  {
    "path": "debian/python-certbot-doc.examples",
    "chars": 11,
    "preview": "examples/*\n"
  },
  {
    "path": "debian/python3-certbot.lintian-overrides",
    "chars": 238,
    "preview": "# The README file detected in testdata/ is an explanation of how the\n# testdata keys were generated.\npython3-certbot bin"
  },
  {
    "path": "debian/rules",
    "chars": 1072,
    "preview": "#!/usr/bin/make -ef\n\nexport PYBUILD_NAME = certbot\n\n%:\n\tdh $@ --with python3,sphinxdoc --buildsystem=pybuild\n\noverride_d"
  },
  {
    "path": "debian/source/format",
    "chars": 12,
    "preview": "3.0 (quilt)\n"
  },
  {
    "path": "debian/tests/certs/README.md",
    "chars": 233,
    "preview": "# certs/localhost\n\nThis directory contains an end-entity (leaf) certificate (`cert.pem`) and\na private key (`key.pem`) f"
  },
  {
    "path": "debian/tests/certs/cert.pem",
    "chars": 1139,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIDGzCCAgOgAwIBAgIIbEfayDFsBtwwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE\nAxMVbWluaWNhIHJvb3QgY2EgMjR"
  },
  {
    "path": "debian/tests/certs/key.pem",
    "chars": 1675,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAmxTFtw113RK70H9pQmdKs9AxhFmnQ6BdDtp3jOZlWlUO0Blt\nMXOUML5905etgtCbcC6RdKR"
  },
  {
    "path": "debian/tests/control",
    "chars": 191,
    "preview": "# Smoke test\nTest-Command: certbot --help\nRestrictions: superficial\nFeatures: test-name=smoke\n\n# End to End HTTP\nTests: "
  },
  {
    "path": "debian/tests/http-01",
    "chars": 911,
    "preview": "#!/bin/bash\n\n# First, define a safe place for us to puke files\nif [ -d $AUTOPKGTEST_TMP ]\nthen\n    TMP_DIR=$AUTOPKGTEST_"
  },
  {
    "path": "debian/tests/pebble-config.json",
    "chars": 321,
    "preview": "{\n  \"pebble\": {\n    \"listenAddress\": \"0.0.0.0:14000\",\n    \"managementListenAddress\": \"0.0.0.0:15000\",\n    \"certificate\":"
  },
  {
    "path": "debian/upstream/signing-key.asc",
    "chars": 2497,
    "preview": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQENBFZVq4kBCADJvp9fLg1WqQ3KJl9ayOk23i5PNGSF6loT2muvoUcbQFUKC6ie\nxC3chvIIIrXPG1lJh"
  },
  {
    "path": "debian/watch",
    "chars": 165,
    "preview": "version=3\nopts=uversionmangle=s/(rc|a|b|c)/~$1/,pgpsigurlmangle=s/$/.asc/ \\\nhttps://pypi.debian.net/certbot/certbot-(.+)"
  },
  {
    "path": "docs/.gitignore",
    "chars": 9,
    "preview": "/_build/\n"
  },
  {
    "path": "docs/Makefile",
    "chars": 7068,
    "preview": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD "
  },
  {
    "path": "docs/_static/.gitignore",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docs/_templates/footer.html",
    "chars": 1999,
    "preview": "<footer>\n  {% if (theme_prev_next_buttons_location == 'bottom' or theme_prev_next_buttons_location == 'both') and (next "
  },
  {
    "path": "docs/api/certbot.achallenges.rst",
    "chars": 148,
    "preview": "certbot.achallenges module\n==========================\n\n.. automodule:: certbot.achallenges\n    :members:\n    :undoc-memb"
  },
  {
    "path": "docs/api/certbot.compat.filesystem.rst",
    "chars": 166,
    "preview": "certbot.compat.filesystem module\n================================\n\n.. automodule:: certbot.compat.filesystem\n    :member"
  },
  {
    "path": "docs/api/certbot.compat.misc.rst",
    "chars": 148,
    "preview": "certbot.compat.misc module\n==========================\n\n.. automodule:: certbot.compat.misc\n    :members:\n    :undoc-memb"
  },
  {
    "path": "docs/api/certbot.compat.os.rst",
    "chars": 142,
    "preview": "certbot.compat.os module\n========================\n\n.. automodule:: certbot.compat.os\n    :members:\n    :undoc-members:\n "
  },
  {
    "path": "docs/api/certbot.compat.rst",
    "chars": 247,
    "preview": "certbot.compat package\n======================\n\n.. automodule:: certbot.compat\n    :members:\n    :undoc-members:\n    :sho"
  },
  {
    "path": "docs/api/certbot.crypto_util.rst",
    "chars": 150,
    "preview": "certbot.crypto\\_util module\n===========================\n\n.. automodule:: certbot.crypto_util\n    :members:\n    :undoc-me"
  },
  {
    "path": "docs/api/certbot.display.ops.rst",
    "chars": 148,
    "preview": "certbot.display.ops module\n==========================\n\n.. automodule:: certbot.display.ops\n    :members:\n    :undoc-memb"
  },
  {
    "path": "docs/api/certbot.display.rst",
    "chars": 224,
    "preview": "certbot.display package\n=======================\n\n.. automodule:: certbot.display\n    :members:\n    :undoc-members:\n    :"
  },
  {
    "path": "docs/api/certbot.display.util.rst",
    "chars": 151,
    "preview": "certbot.display.util module\n===========================\n\n.. automodule:: certbot.display.util\n    :members:\n    :undoc-m"
  },
  {
    "path": "docs/api/certbot.errors.rst",
    "chars": 133,
    "preview": "certbot.errors module\n=====================\n\n.. automodule:: certbot.errors\n    :members:\n    :undoc-members:\n    :show-"
  },
  {
    "path": "docs/api/certbot.interfaces.rst",
    "chars": 145,
    "preview": "certbot.interfaces module\n=========================\n\n.. automodule:: certbot.interfaces\n    :members:\n    :undoc-members"
  },
  {
    "path": "docs/api/certbot.main.rst",
    "chars": 127,
    "preview": "certbot.main module\n===================\n\n.. automodule:: certbot.main\n    :members:\n    :undoc-members:\n    :show-inheri"
  },
  {
    "path": "docs/api/certbot.ocsp.rst",
    "chars": 131,
    "preview": "certbot.ocsp package\n======================\n\n.. automodule:: certbot.ocsp\n    :members:\n    :undoc-members:\n    :show-in"
  },
  {
    "path": "docs/api/certbot.plugins.common.rst",
    "chars": 157,
    "preview": "certbot.plugins.common module\n=============================\n\n.. automodule:: certbot.plugins.common\n    :members:\n    :u"
  },
  {
    "path": "docs/api/certbot.plugins.dns_common.rst",
    "chars": 171,
    "preview": "certbot.plugins.dns\\_common module\n==================================\n\n.. automodule:: certbot.plugins.dns_common\n    :m"
  },
  {
    "path": "docs/api/certbot.plugins.dns_common_lexicon.rst",
    "chars": 197,
    "preview": "certbot.plugins.dns\\_common\\_lexicon module\n===========================================\n\n.. automodule:: certbot.plugins"
  },
  {
    "path": "docs/api/certbot.plugins.dns_test_common.rst",
    "chars": 188,
    "preview": "certbot.plugins.dns\\_test\\_common module\n========================================\n\n.. automodule:: certbot.plugins.dns_t"
  },
  {
    "path": "docs/api/certbot.plugins.dns_test_common_lexicon.rst",
    "chars": 214,
    "preview": "certbot.plugins.dns\\_test\\_common\\_lexicon module\n=================================================\n\n.. automodule:: cer"
  },
  {
    "path": "docs/api/certbot.plugins.enhancements.rst",
    "chars": 175,
    "preview": "certbot.plugins.enhancements module\n===================================\n\n.. automodule:: certbot.plugins.enhancements\n  "
  },
  {
    "path": "docs/api/certbot.plugins.rst",
    "chars": 432,
    "preview": "certbot.plugins package\n=======================\n\n.. automodule:: certbot.plugins\n    :members:\n    :undoc-members:\n    :"
  },
  {
    "path": "docs/api/certbot.plugins.storage.rst",
    "chars": 160,
    "preview": "certbot.plugins.storage module\n==============================\n\n.. automodule:: certbot.plugins.storage\n    :members:\n   "
  },
  {
    "path": "docs/api/certbot.plugins.util.rst",
    "chars": 151,
    "preview": "certbot.plugins.util module\n===========================\n\n.. automodule:: certbot.plugins.util\n    :members:\n    :undoc-m"
  },
  {
    "path": "docs/api/certbot.reverter.rst",
    "chars": 139,
    "preview": "certbot.reverter module\n=======================\n\n.. automodule:: certbot.reverter\n    :members:\n    :undoc-members:\n    "
  },
  {
    "path": "docs/api/certbot.rst",
    "chars": 424,
    "preview": "certbot package\n===============\n\n.. automodule:: certbot\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nSubpa"
  },
  {
    "path": "docs/api/certbot.tests.acme_util.rst",
    "chars": 162,
    "preview": "certbot.tests.acme\\_util module\n===============================\n\n.. automodule:: certbot.tests.acme_util\n    :members:\n "
  },
  {
    "path": "docs/api/certbot.tests.rst",
    "chars": 220,
    "preview": "certbot.tests package\n=====================\n\n.. automodule:: certbot.tests\n    :members:\n    :undoc-members:\n    :show-i"
  },
  {
    "path": "docs/api/certbot.tests.util.rst",
    "chars": 145,
    "preview": "certbot.tests.util module\n=========================\n\n.. automodule:: certbot.tests.util\n    :members:\n    :undoc-members"
  },
  {
    "path": "docs/api/certbot.util.rst",
    "chars": 127,
    "preview": "certbot.util module\n===================\n\n.. automodule:: certbot.util\n    :members:\n    :undoc-members:\n    :show-inheri"
  },
  {
    "path": "docs/api.rst",
    "chars": 100,
    "preview": "=================\nAPI Documentation\n=================\n\n.. toctree::\n   :maxdepth: 4\n\n   api/certbot\n"
  },
  {
    "path": "docs/challenges.rst",
    "chars": 4713,
    "preview": "Challenges\n==========\n\nTo receive a certificate from Let's Encrypt certificate authority (CA), you must pass a *challeng"
  },
  {
    "path": "docs/ciphers.rst",
    "chars": 16214,
    "preview": "============\nCiphersuites\n============\n\n.. contents:: Table of Contents\n   :local:\n\n\n.. _ciphersuites:\n\nIntroduction\n==="
  },
  {
    "path": "docs/cli-help.txt",
    "chars": 38321,
    "preview": "usage: \n  certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...\n\nCertbot can obtain and install HTTPS/TLS/SSL certi"
  },
  {
    "path": "docs/compatibility.rst",
    "chars": 2067,
    "preview": "=======================\nBackwards Compatibility\n=======================\n\nAll Certbot components including `acme <https:/"
  },
  {
    "path": "docs/conf.py",
    "chars": 10725,
    "preview": "# -*- coding: utf-8 -*-\n#\n# Certbot documentation build configuration file, created by\n# sphinx-quickstart on Sun Nov 23"
  },
  {
    "path": "docs/contributing.rst",
    "chars": 23955,
    "preview": "===============\nDeveloper Guide\n===============\n\n.. contents:: Table of Contents\n   :local:\n\n\n.. _getting_started:\n\nGett"
  },
  {
    "path": "docs/index.rst",
    "chars": 347,
    "preview": "Welcome to the Certbot documentation!\n==================================================\n\n.. toctree::\n   :maxdepth: 2\n\n"
  },
  {
    "path": "docs/install.rst",
    "chars": 12926,
    "preview": "=====================\nGet Certbot\n=====================\n\n.. contents:: Table of Contents\n   :local:\n\n\nAbout Certbot\n===="
  },
  {
    "path": "docs/intro.rst",
    "chars": 258,
    "preview": "=====================\nIntroduction\n=====================\n\n.. note::\n    To get started quickly, use the `interactive ins"
  },
  {
    "path": "docs/make.bat",
    "chars": 7254,
    "preview": "@ECHO OFF\r\n\r\nREM Command file for Sphinx documentation\r\n\r\nif \"%SPHINXBUILD%\" == \"\" (\r\n\tset SPHINXBUILD=sphinx-build\r\n)\r\n"
  },
  {
    "path": "docs/man/certbot.rst",
    "chars": 36,
    "preview": ".. literalinclude:: ../cli-help.txt\n"
  },
  {
    "path": "docs/packaging.rst",
    "chars": 2454,
    "preview": "===============\nPackaging Guide\n===============\n\nReleases\n========\n\nWe release packages and upload them to PyPI (wheels "
  },
  {
    "path": "docs/resources.rst",
    "chars": 147,
    "preview": "=====================\nResources\n=====================\n\n.. include:: ../README.rst\n    :start-after: tag:links-begin\n    "
  },
  {
    "path": "docs/using.rst",
    "chars": 44071,
    "preview": "==========\nUser Guide\n==========\n\n.. contents:: Table of Contents\n   :local:\n\nCertbot Commands\n================\n\nCertbot"
  },
  {
    "path": "docs/what.rst",
    "chars": 1718,
    "preview": "======================\nWhat is a Certificate?\n======================\n\nA public key or digital *certificate* (formerly ca"
  },
  {
    "path": "examples/.gitignore",
    "chars": 36,
    "preview": "# generate-csr.sh:\n/key.pem\n/csr.der"
  },
  {
    "path": "examples/cli.ini",
    "chars": 896,
    "preview": "# This is an example of the kind of things you can do in a configuration file.\n# All flags used by the client can be con"
  },
  {
    "path": "examples/dev-cli.ini",
    "chars": 538,
    "preview": "# Always use the staging/testing server - avoids rate limiting\nserver = https://acme-staging-v02.api.letsencrypt.org/dir"
  },
  {
    "path": "examples/generate-csr.sh",
    "chars": 721,
    "preview": "#!/bin/sh\n# This script generates a simple SAN CSR to be used with Let's Encrypt\n# CA. Mostly intended for \"auth --csr\" "
  },
  {
    "path": "examples/openssl.cnf",
    "chars": 114,
    "preview": "[ req ]\ndistinguished_name = req_distinguished_name\n[ req_distinguished_name ]\n[ san ]\nsubjectAltName=${ENV::SAN}\n"
  },
  {
    "path": "examples/plugins/certbot_example_plugins.py",
    "chars": 861,
    "preview": "\"\"\"Example Certbot plugins.\n\nFor full examples, see `certbot.plugins`.\n\n\"\"\"\nimport zope.interface\n\nfrom certbot import i"
  },
  {
    "path": "examples/plugins/setup.py",
    "chars": 404,
    "preview": "from setuptools import setup\n\nsetup(\n    name='certbot-example-plugins',\n    package='certbot_example_plugins.py',\n    i"
  },
  {
    "path": "setup.cfg",
    "chars": 98,
    "preview": "[bdist_wheel]\nuniversal = 1\n\n[easy_install]\nzip_ok = false\n\n[egg_info]\ntag_build = \ntag_date = 0\n\n"
  },
  {
    "path": "setup.py",
    "chars": 5963,
    "preview": "import codecs\nfrom distutils.version import StrictVersion\nimport os\nimport re\nimport sys\n\nfrom setuptools import __versi"
  },
  {
    "path": "tests/account_test.py",
    "chars": 14242,
    "preview": "\"\"\"Tests for certbot._internal.account.\"\"\"\nimport datetime\nimport json\nimport unittest\n\nimport josepy as jose\nimport moc"
  }
]

// ... and 43 more files (download for full content)

About this extraction

This page contains the full source code of the norbusan/certbot-debian GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 243 files (1.5 MB), approximately 368.7k tokens, and a symbol index with 2271 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!