def _restore_int(name: str, value: str) -> int: """Restores an integer key-value pair from a renewal config file. :param str name: option name :param str value: option value :returns: converted option value to be stored in the runtime config :rtype: int :raises errors.Error: if value can't be converted to an int """ if name == "http01_port" and value == "None": logger.info("updating legacy http01_port value") return cli.flag_default("http01_port") try: return int(value) except ValueError: raise errors.Error(f"Expected a numeric value for {name}")
def renew_cert(config, domains, le_client, lineage): "Renew a certificate lineage." renewal_params = lineage.configuration["renewalparams"] original_server = renewal_params.get("server", cli.flag_default("server")) _avoid_invalidating_lineage(config, lineage, original_server) if not domains: domains = lineage.names() # The private key is the existing lineage private key if reuse_key is set. # Otherwise, generate a fresh private key by passing None. new_key = os.path.normpath(lineage.privkey) if config.reuse_key else None new_cert, new_chain, new_key, _ = le_client.obtain_certificate(domains, new_key) if config.dry_run: logger.debug("Dry run: skipping updating lineage at %s", os.path.dirname(lineage.cert)) else: prior_version = lineage.latest_common_version() # TODO: Check return value of save_successor lineage.save_successor(prior_version, new_cert, new_key.pem, new_chain, config) lineage.update_all_links_to(lineage.latest_common_version()) hooks.renew_hook(config, domains, lineage.live_dir)
def test_dry_run_flag(self): config_dir = tempfile.mkdtemp() short_args = '--dry-run --config-dir {0}'.format(config_dir).split() self.assertRaises(errors.Error, self.parse, short_args) self._assert_dry_run_flag_worked( self.parse(short_args + ['auth']), False) self._assert_dry_run_flag_worked( self.parse(short_args + ['certonly']), False) self._assert_dry_run_flag_worked( self.parse(short_args + ['renew']), False) account_dir = os.path.join(config_dir, constants.ACCOUNTS_DIR) filesystem.mkdir(account_dir) filesystem.mkdir(os.path.join(account_dir, 'fake_account_dir')) self._assert_dry_run_flag_worked(self.parse(short_args + ['auth']), True) self._assert_dry_run_flag_worked(self.parse(short_args + ['renew']), True) self._assert_dry_run_flag_worked(self.parse(short_args + ['certonly']), True) short_args += ['certonly'] # `--dry-run --server example.com` should emit example.com self.assertEqual(self.parse(short_args + ['--server', 'example.com']).server, 'example.com') # `--dry-run --server STAGING_URI` should emit STAGING_URI self.assertEqual(self.parse(short_args + ['--server', constants.STAGING_URI]).server, constants.STAGING_URI) # `--dry-run --server LIVE` should emit STAGING_URI self.assertEqual(self.parse(short_args + ['--server', cli.flag_default("server")]).server, constants.STAGING_URI) # `--dry-run --server example.com --staging` should emit an error conflicts = ['--staging'] self._check_server_conflict_message(short_args + ['--server', 'example.com', '--staging'], conflicts)
def _plugins_parsing(helpful, plugins): # It's nuts, but there are two "plugins" topics. Somehow this works helpful.add_group( "plugins", description="Plugin Selection: Certbot client supports an " "extensible plugins architecture. See '%(prog)s plugins' for a " "list of all installed plugins and their names. You can force " "a particular plugin by setting options provided below. Running " "--help <plugin_name> will list flags specific to that plugin.") helpful.add( "plugins", "--configurator", default=flag_default("configurator"), help="Name of the plugin that is both an authenticator and an installer." " Should not be used together with --authenticator or --installer. " "(default: Ask)") helpful.add("plugins", "-a", "--authenticator", default=flag_default("authenticator"), help="Authenticator plugin name.") helpful.add("plugins", "-i", "--installer", default=flag_default("installer"), help="Installer plugin name (also used to find domains).") helpful.add(["plugins", "certonly", "run", "install"], "--apache", action="store_true", default=flag_default("apache"), help="Obtain and install certificates using Apache") helpful.add(["plugins", "certonly", "run", "install"], "--nginx", action="store_true", default=flag_default("nginx"), help="Obtain and install certificates using Nginx") helpful.add(["plugins", "certonly"], "--standalone", action="store_true", default=flag_default("standalone"), help='Obtain certificates using a "standalone" webserver.') helpful.add( ["plugins", "certonly"], "--manual", action="store_true", default=flag_default("manual"), help="Provide laborious manual instructions for obtaining a certificate" ) helpful.add( ["plugins", "certonly"], "--webroot", action="store_true", default=flag_default("webroot"), help="Obtain certificates by placing files in a webroot directory.") helpful.add(["plugins", "certonly"], "--dns-cloudflare", action="store_true", default=flag_default("dns_cloudflare"), help=("Obtain certificates using a DNS TXT record (if you are " "using Cloudflare for DNS).")) helpful.add(["plugins", "certonly"], "--dns-cloudxns", action="store_true", default=flag_default("dns_cloudxns"), help=("Obtain certificates using a DNS TXT record (if you are " "using CloudXNS for DNS).")) helpful.add(["plugins", "certonly"], "--dns-digitalocean", action="store_true", default=flag_default("dns_digitalocean"), help=("Obtain certificates using a DNS TXT record (if you are " "using DigitalOcean for DNS).")) helpful.add(["plugins", "certonly"], "--dns-dnsimple", action="store_true", default=flag_default("dns_dnsimple"), help=("Obtain certificates using a DNS TXT record (if you are " "using DNSimple for DNS).")) helpful.add(["plugins", "certonly"], "--dns-dnsmadeeasy", action="store_true", default=flag_default("dns_dnsmadeeasy"), help=("Obtain certificates using a DNS TXT record (if you are " "using DNS Made Easy for DNS).")) helpful.add( ["plugins", "certonly"], "--dns-gehirn", action="store_true", default=flag_default("dns_gehirn"), help=("Obtain certificates using a DNS TXT record " "(if you are using Gehirn Infrastructure Service for DNS).")) helpful.add(["plugins", "certonly"], "--dns-google", action="store_true", default=flag_default("dns_google"), help=("Obtain certificates using a DNS TXT record (if you are " "using Google Cloud DNS).")) helpful.add(["plugins", "certonly"], "--dns-linode", action="store_true", default=flag_default("dns_linode"), help=("Obtain certificates using a DNS TXT record (if you are " "using Linode for DNS).")) helpful.add(["plugins", "certonly"], "--dns-luadns", action="store_true", default=flag_default("dns_luadns"), help=("Obtain certificates using a DNS TXT record (if you are " "using LuaDNS for DNS).")) helpful.add(["plugins", "certonly"], "--dns-nsone", action="store_true", default=flag_default("dns_nsone"), help=("Obtain certificates using a DNS TXT record (if you are " "using NS1 for DNS).")) helpful.add(["plugins", "certonly"], "--dns-ovh", action="store_true", default=flag_default("dns_ovh"), help=("Obtain certificates using a DNS TXT record (if you are " "using OVH for DNS).")) helpful.add( ["plugins", "certonly"], "--dns-rfc2136", action="store_true", default=flag_default("dns_rfc2136"), help= "Obtain certificates using a DNS TXT record (if you are using BIND for DNS)." ) helpful.add( ["plugins", "certonly"], "--dns-route53", action="store_true", default=flag_default("dns_route53"), help= ("Obtain certificates using a DNS TXT record (if you are using Route53 for " "DNS).")) helpful.add(["plugins", "certonly"], "--dns-sakuracloud", action="store_true", default=flag_default("dns_sakuracloud"), help=("Obtain certificates using a DNS TXT record " "(if you are using Sakura Cloud for DNS).")) # things should not be reorder past/pre this comment: # plugins_group should be displayed in --help before plugin # specific groups (so that plugins_group.description makes sense) helpful.add_plugin_args(plugins)
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
def test_no_args(self): namespace = self.parse([]) for d in ('config_dir', 'logs_dir', 'work_dir'): self.assertEqual(getattr(namespace, d), cli.flag_default(d))
def test_ecdsa_key_option(self): elliptic_curve_option = 'elliptic_curve' elliptic_curve_option_value = cli.flag_default(elliptic_curve_option) self.parse('--elliptic-curve {0}'.format(elliptic_curve_option_value).split()) self.assertIs(cli.option_was_set(elliptic_curve_option, elliptic_curve_option_value), True)
def _create_subparsers(helpful): from certbot._internal.client import sample_user_agent # avoid import loops helpful.add( None, "--user-agent", default=flag_default("user_agent"), help= 'Set a custom user agent string for the client. User agent strings allow ' 'the CA to collect high level statistics about success rates by OS, ' 'plugin and use case, and to know when to deprecate support for past Python ' "versions and flags. If you wish to hide this information from the Let's " 'Encrypt server, set this to "". ' '(default: {0}). The flags encoded in the user agent are: ' '--duplicate, --force-renew, --allow-subset-of-names, -n, and ' 'whether any hooks are set.'.format(sample_user_agent())) helpful.add( None, "--user-agent-comment", default=flag_default("user_agent_comment"), type=_user_agent_comment_type, help= "Add a comment to the default user agent string. May be used when repackaging Certbot " "or calling it from another tool to allow additional statistical data to be collected." " Ignored if --user-agent is set. (Example: Foo-Wrapper/1.0)") helpful.add( "certonly", "--csr", default=flag_default("csr"), type=read_file, help="Path to a Certificate Signing Request (CSR) in DER or PEM format." " Currently --csr only works with the 'certonly' subcommand.") helpful.add( "revoke", "--reason", dest="reason", choices=CaseInsensitiveList( sorted(constants.REVOCATION_REASONS, key=constants.REVOCATION_REASONS.get)), action=_EncodeReasonAction, default=flag_default("reason"), help="Specify reason for revoking certificate. (default: unspecified)") helpful.add( "revoke", "--delete-after-revoke", action="store_true", default=flag_default("delete_after_revoke"), help= "Delete certificates after revoking them, along with all previous and later " "versions of those certificates.") helpful.add("revoke", "--no-delete-after-revoke", action="store_false", dest="delete_after_revoke", default=flag_default("delete_after_revoke"), help="Do not delete certificates after revoking them. This " "option should be used with caution because the 'renew' " "subcommand will attempt to renew undeleted revoked " "certificates.") helpful.add("rollback", "--checkpoints", type=int, metavar="N", default=flag_default("rollback_checkpoints"), help="Revert configuration N number of checkpoints.") helpful.add("plugins", "--init", action="store_true", default=flag_default("init"), help="Initialize plugins.") helpful.add("plugins", "--prepare", action="store_true", default=flag_default("prepare"), help="Initialize and prepare plugins.") helpful.add("plugins", "--authenticators", action="append_const", dest="ifaces", default=flag_default("ifaces"), const=interfaces.IAuthenticator, help="Limit to authenticator plugins only.") helpful.add("plugins", "--installers", action="append_const", dest="ifaces", default=flag_default("ifaces"), const=interfaces.IInstaller, help="Limit to installer plugins only.")