Example #1
0
def _determine_account(config):
    """Determine which account to use.

    In order to make the renewer (configuration de/serialization) happy,
    if ``config.account`` is ``None``, it will be updated based on the
    user input. Same for ``config.email``.

    :param argparse.Namespace config: CLI arguments
    :param letsencrypt.interface.IConfig config: Configuration object
    :param .AccountStorage account_storage: Account storage.

    :returns: Account and optionally ACME client API (biproduct of new
        registration).
    :rtype: `tuple` of `letsencrypt.account.Account` and
        `acme.client.Client`

    """
    account_storage = account.AccountFileStorage(config)
    acme = None

    if config.account is not None:
        acc = account_storage.load(config.account)
    else:
        accounts = account_storage.find_all()
        if len(accounts) > 1:
            acc = display_ops.choose_account(accounts)
        elif len(accounts) == 1:
            acc = accounts[0]
        else:  # no account registered yet
            if config.email is None and not config.register_unsafely_without_email:
                config.namespace.email = display_ops.get_email()

            def _tos_cb(regr):
                if config.tos:
                    return True
                msg = ("Please read the Terms of Service at {0}. You "
                       "must agree in order to register with the ACME "
                       "server at {1}".format(regr.terms_of_service,
                                              config.server))
                obj = zope.component.getUtility(interfaces.IDisplay)
                return obj.yesno(msg,
                                 "Agree",
                                 "Cancel",
                                 cli_flag="--agree-tos")

            try:
                acc, acme = client.register(config,
                                            account_storage,
                                            tos_cb=_tos_cb)
            except errors.MissingCommandlineFlag:
                raise
            except errors.Error as error:
                logger.debug(error, exc_info=True)
                raise errors.Error(
                    "Unable to register an account with ACME server")

    config.namespace.account = acc.id
    return acc, acme
Example #2
0
def renew(cert, old_version):
    """Perform automated renewal of the referenced cert, if possible.

    :param letsencrypt.storage.RenewableCert cert: The certificate
        lineage to attempt to renew.
    :param int old_version: The version of the certificate lineage
        relative to which the renewal should be attempted.

    :returns: A number referring to newly created version of this cert
        lineage, or ``False`` if renewal was not successful.
    :rtype: `int` or `bool`

    """
    # TODO: handle partial success (some names can be renewed but not
    #       others)
    # TODO: handle obligatory key rotation vs. optional key rotation vs.
    #       requested key rotation
    if "renewalparams" not in cert.configfile:
        # TODO: notify user?
        return False
    renewalparams = cert.configfile["renewalparams"]
    if "authenticator" not in renewalparams:
        # TODO: notify user?
        return False
    # Instantiate the appropriate authenticator
    plugins = plugins_disco.PluginsRegistry.find_all()
    config = configuration.NamespaceConfig(_AttrDict(renewalparams))
    # XXX: this loses type data (for example, the fact that key_size
    #      was an int, not a str)
    config.rsa_key_size = int(config.rsa_key_size)
    config.dvsni_port = int(config.dvsni_port)
    config.namespace.http01_port = int(config.namespace.http01_port)
    zope.component.provideUtility(config)
    try:
        authenticator = plugins[renewalparams["authenticator"]]
    except KeyError:
        # TODO: Notify user? (authenticator could not be found)
        return False
    authenticator = authenticator.init(config)

    authenticator.prepare()
    acc = account.AccountFileStorage(config).load(
        account_id=renewalparams["account"])

    le_client = client.Client(config, acc, authenticator, None)
    with open(cert.version("cert", old_version)) as f:
        sans = crypto_util.get_sans_from_cert(f.read())
    new_certr, new_chain, new_key, _ = le_client.obtain_certificate(sans)
    if new_chain:
        # XXX: Assumes that there was a key change.  We need logic
        #      for figuring out whether there was or not.  Probably
        #      best is to have obtain_certificate return None for
        #      new_key if the old key is to be used (since save_successor
        #      already understands this distinction!)
        return cert.save_successor(
            old_version, OpenSSL.crypto.dump_certificate(
                OpenSSL.crypto.FILETYPE_PEM, new_certr.body),
            new_key.pem, crypto_util.dump_pyopenssl_chain(new_chain))
        # TODO: Notify results
    else:
        # TODO: Notify negative results
        return False