Example #1
0
 def test_linux_directories(self):
     if 'fcntl' in sys.modules:
         self.assertEqual(cli.flag_default('config_dir'),
                          '/etc/letsencrypt')
         self.assertEqual(cli.flag_default('work_dir'),
                          '/var/lib/letsencrypt')
         self.assertEqual(cli.flag_default('logs_dir'),
                          '/var/log/letsencrypt')
Example #2
0
    def test_option_was_set(self):
        key_size_option = "rsa_key_size"
        key_size_value = cli.flag_default(key_size_option)
        self.parse("--rsa-key-size {0}".format(key_size_value).split())

        self.assertTrue(cli.option_was_set(key_size_option, key_size_value))
        self.assertTrue(cli.option_was_set("no_verify_ssl", True))

        config_dir_option = "config_dir"
        self.assertFalse(cli.option_was_set(config_dir_option, cli.flag_default(config_dir_option)))
Example #3
0
    def test_option_was_set(self):
        key_size_option = 'rsa_key_size'
        key_size_value = cli.flag_default(key_size_option)
        self.parse('--rsa-key-size {0}'.format(key_size_value).split())

        self.assertTrue(cli.option_was_set(key_size_option, key_size_value))
        self.assertTrue(cli.option_was_set('no_verify_ssl', True))

        config_dir_option = 'config_dir'
        self.assertFalse(cli.option_was_set(
            config_dir_option, cli.flag_default(config_dir_option)))
Example #4
0
    def test_option_was_set(self):
        key_size_option = 'rsa_key_size'
        key_size_value = cli.flag_default(key_size_option)
        self.parse('--rsa-key-size {0}'.format(key_size_value).split())

        self.assertTrue(cli.option_was_set(key_size_option, key_size_value))
        self.assertTrue(cli.option_was_set('no_verify_ssl', True))

        config_dir_option = 'config_dir'
        self.assertFalse(cli.option_was_set(
            config_dir_option, cli.flag_default(config_dir_option)))
Example #5
0
def _restore_required_config_elements(config, renewalparams):
    """Sets non-plugin specific values in config from renewalparams

    :param configuration.NamespaceConfig config: configuration for the
        current lineage
    :param configobj.Section renewalparams: parameters from the renewal
        configuration file that defines this lineage

    """
    # string-valued items to add if they're present
    for config_item in STR_CONFIG_ITEMS:
        if config_item in renewalparams and not cli.set_by_cli(config_item):
            value = renewalparams[config_item]
            # Unfortunately, we've lost type information from ConfigObj,
            # so we don't know if the original was NoneType or str!
            if value == "None":
                value = None
            setattr(config.namespace, config_item, value)
    # int-valued items to add if they're present
    for config_item in INT_CONFIG_ITEMS:
        if config_item in renewalparams and not cli.set_by_cli(config_item):
            config_value = renewalparams[config_item]
            # the default value for http01_port was None during private beta
            if config_item == "http01_port" and config_value == "None":
                logger.info("updating legacy http01_port value")
                int_value = cli.flag_default("http01_port")
            else:
                try:
                    int_value = int(config_value)
                except ValueError:
                    raise errors.Error(
                        "Expected a numeric value for {0}".format(config_item))
            setattr(config.namespace, config_item, int_value)
Example #6
0
    def _test_relevant_values_common(self, values):
        option = "rsa_key_size"
        mock_parser = mock.Mock(args=["--standalone"], verb="certonly",
                                defaults={option: cli.flag_default(option)})

        from certbot.storage import relevant_values
        with mock.patch("certbot.cli.helpful_parser", mock_parser):
            return relevant_values(values)
Example #7
0
    def _test_relevant_values_common(self, values):
        option = "rsa_key_size"
        mock_parser = mock.Mock(args=["--standalone"], verb="certonly",
                                defaults={option: cli.flag_default(option)})

        from certbot.storage import relevant_values
        with mock.patch("certbot.cli.helpful_parser", mock_parser):
            return relevant_values(values)
Example #8
0
def _handle_exception(exc_type, exc_value, trace, config):
    """Logs exceptions and reports them to the user.

    Config is used to determine how to display exceptions to the user. In
    general, if config.debug is True, then the full exception and traceback is
    shown to the user, otherwise it is suppressed. If config itself is None,
    then the traceback and exception is attempted to be written to a logfile.
    If this is successful, the traceback is suppressed, otherwise it is shown
    to the user. sys.exit is always called with a nonzero status.

    """
    logger.debug(
        "Exiting abnormally:%s%s", os.linesep,
        "".join(traceback.format_exception(exc_type, exc_value, trace)))

    if issubclass(exc_type, Exception) and (config is None
                                            or not config.debug):
        if config is None:
            logfile = "certbot.log"
            try:
                with open(logfile, "w") as logfd:
                    traceback.print_exception(exc_type,
                                              exc_value,
                                              trace,
                                              file=logfd)
            except:  # pylint: disable=bare-except
                sys.exit("".join(
                    traceback.format_exception(exc_type, exc_value, trace)))

        if issubclass(exc_type, errors.Error):
            sys.exit(exc_value)
        else:
            # Here we're passing a client or ACME error out to the client at the shell
            # Tell the user a bit about what happened, without overwhelming
            # them with a full traceback
            if issubclass(exc_type, dialog.error):
                err = exc_value.complete_message()
            else:
                err = traceback.format_exception_only(exc_type, exc_value)[0]
            # Typical error from the ACME module:
            # acme.messages.Error: urn:acme:error:malformed :: The request message was
            # malformed :: Error creating new registration :: Validation of contact
            # mailto:[email protected] failed: Server failure at resolver
            if (("urn:acme" in err and ":: " in err and
                 config.verbose_count <= cli.flag_default("verbose_count"))):
                # prune ACME error code, we have a human description
                _code, _sep, err = err.partition(":: ")
            msg = "An unexpected error occurred:\n" + err + "Please see the "
            if config is None:
                msg += "logfile '{0}' for more details.".format(logfile)
            else:
                msg += "logfiles in {0} for more details.".format(
                    config.logs_dir)
            sys.exit(msg)
    else:
        sys.exit("".join(traceback.format_exception(exc_type, exc_value,
                                                    trace)))
Example #9
0
def _handle_exception(exc_type, exc_value, trace, config):
    """Logs exceptions and reports them to the user.

    Config is used to determine how to display exceptions to the user. In
    general, if config.debug is True, then the full exception and traceback is
    shown to the user, otherwise it is suppressed. If config itself is None,
    then the traceback and exception is attempted to be written to a logfile.
    If this is successful, the traceback is suppressed, otherwise it is shown
    to the user. sys.exit is always called with a nonzero status.

    """
    logger.debug(
        "Exiting abnormally:%s%s",
        os.linesep,
        "".join(traceback.format_exception(exc_type, exc_value, trace)))

    if issubclass(exc_type, Exception) and (config is None or not config.debug):
        if config is None:
            logfile = "certbot.log"
            try:
                with open(logfile, "w") as logfd:
                    traceback.print_exception(
                        exc_type, exc_value, trace, file=logfd)
            except:  # pylint: disable=bare-except
                sys.exit("".join(
                    traceback.format_exception(exc_type, exc_value, trace)))

        if issubclass(exc_type, errors.Error):
            sys.exit(exc_value)
        else:
            # Here we're passing a client or ACME error out to the client at the shell
            # Tell the user a bit about what happened, without overwhelming
            # them with a full traceback
            if issubclass(exc_type, dialog.error):
                err = exc_value.complete_message()
            else:
                err = traceback.format_exception_only(exc_type, exc_value)[0]
            # Typical error from the ACME module:
            # acme.messages.Error: urn:ietf:params:acme:error:malformed :: The
            # request message was malformed :: Error creating new registration
            # :: Validation of contact mailto:[email protected] failed:
            # Server failure at resolver
            if (messages.is_acme_error(err) and ":: " in err and
                 config.verbose_count <= cli.flag_default("verbose_count")):
                # prune ACME error code, we have a human description
                _code, _sep, err = err.partition(":: ")
            msg = "An unexpected error occurred:\n" + err + "Please see the "
            if config is None:
                msg += "logfile '{0}' for more details.".format(logfile)
            else:
                msg += "logfiles in {0} for more details.".format(config.logs_dir)
            sys.exit(msg)
    else:
        sys.exit("".join(
            traceback.format_exception(exc_type, exc_value, trace)))
Example #10
0
 def test_default_directories(self):
     if os.name != 'nt':
         self.assertEqual(cli.flag_default('config_dir'), '/etc/letsencrypt')
         self.assertEqual(cli.flag_default('work_dir'), '/var/lib/letsencrypt')
         self.assertEqual(cli.flag_default('logs_dir'), '/var/log/letsencrypt')
     else:
         self.assertEqual(cli.flag_default('config_dir'), 'C:\\Certbot')
         self.assertEqual(cli.flag_default('work_dir'), 'C:\\Certbot\\lib')
         self.assertEqual(cli.flag_default('logs_dir'), 'C:\\Certbot\\log')
Example #11
0
    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)
Example #12
0
    def _test_relevant_values_common(self, values):
        defaults = dict((option, cli.flag_default(option))
                        for option in ("authenticator", "installer",
                                       "rsa_key_size", "server",))
        mock_parser = mock.Mock(args=[], verb="plugins",
                                defaults=defaults)

        # make a copy to ensure values isn't modified
        values = values.copy()
        values.setdefault("server", defaults["server"])
        expected_server = values["server"]

        from certbot.storage import relevant_values
        with mock.patch("certbot.cli.helpful_parser", mock_parser):
            rv = relevant_values(values)
        self.assertIn("server", rv)
        self.assertEqual(rv.pop("server"), expected_server)
        return rv
Example #13
0
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()
    new_cert, new_chain, new_key, _ = le_client.obtain_certificate(domains)
    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_relevant_values_common(self, values):
        defaults = dict((option, cli.flag_default(option))
                        for option in ("authenticator", "installer",
                                       "rsa_key_size", "server",))
        mock_parser = mock.Mock(args=[], verb="plugins",
                                defaults=defaults)

        # make a copy to ensure values isn't modified
        values = values.copy()
        values.setdefault("server", defaults["server"])
        expected_server = values["server"]

        from certbot.storage import relevant_values
        with mock.patch("certbot.cli.helpful_parser", mock_parser):
            rv = relevant_values(values)
        self.assertIn("server", rv)
        self.assertEqual(rv.pop("server"), expected_server)
        return rv
Example #15
0
def renew_cert(config, 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)
    new_certr, new_chain, new_key, _ = le_client.obtain_certificate(lineage.names())
    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()
        new_cert = OpenSSL.crypto.dump_certificate(
            OpenSSL.crypto.FILETYPE_PEM, new_certr.body.wrapped)
        new_chain = crypto_util.dump_pyopenssl_chain(new_chain)
        # 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, lineage.names(), lineage.live_dir)
Example #16
0
def _restore_int(name, value):
    """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("Expected a numeric value for {0}".format(name))
Example #17
0
def _restore_int(name, value):
    """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("Expected a numeric value for {0}".format(name))
Example #18
0
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 = 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)
Example #19
0
 def test_relevant_values_default(self):
     """Test that relevant_values() can reject a default value."""
     option = "rsa_key_size"
     values = {option: cli.flag_default(option)}
     self.assertEqual(self._test_relevant_values_common(values), {})
Example #20
0
 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))
Example #21
0
 def test_relevant_values_default(self):
     """Test that relevant_values() can reject a default value."""
     option = "rsa_key_size"
     values = {option: cli.flag_default(option)}
     self.assertEqual(self._test_relevant_values_common(values), {})
Example #22
0
 def test_linux_directories(self):
     if 'fcntl' in sys.modules:
         self.assertEqual(cli.flag_default('config_dir'), '/etc/letsencrypt')
         self.assertEqual(cli.flag_default('work_dir'), '/var/lib/letsencrypt')
         self.assertEqual(cli.flag_default('logs_dir'), '/var/log/letsencrypt')
Example #23
0
 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))