def perform_registration(acme, config): """ Actually register new account, trying repeatedly if there are email problems :param .IConfig config: Client configuration. :param acme.client.Client client: ACME client object. :returns: Registration Resource. :rtype: `acme.messages.RegistrationResource` """ try: return acme.register(messages.NewRegistration.from_data(email=config.email)) except messages.Error as e: if e.code == "invalidEmail" or e.code == "invalidContact": if config.noninteractive_mode: msg = ("The ACME server believes %s is an invalid email address. " "Please ensure it is a valid email and attempt " "registration again." % config.email) raise errors.Error(msg) else: config.email = display_ops.get_email(invalid=True) return perform_registration(acme, config) else: raise
def _determine_account(config): """Determine which account to use. If ``config.account`` is ``None``, it will be updated based on the user input. Same for ``config.email``. :param config: Configuration object :type config: interfaces.IConfig :returns: Account and optionally ACME client API (biproduct of new registration). :rtype: tuple of :class:`certbot._internal.account.Account` and :class:`acme.client.Client` :raises errors.Error: If unable to register an account with ACME server """ def _tos_cb(terms_of_service): 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(terms_of_service, config.server)) obj = zope.component.getUtility(interfaces.IDisplay) result = obj.yesno(msg, "Agree", "Cancel", cli_flag="--agree-tos", force_interactive=True) if not result: raise errors.Error("Registration cannot proceed without accepting " "Terms of Service.") return None 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.email = display_ops.get_email() try: acc, acme = client.register(config, account_storage, tos_cb=_tos_cb) except errors.MissingCommandlineFlag: raise except errors.Error: logger.debug("", exc_info=True) raise errors.Error( "Unable to register an account with ACME server") config.account = acc.id return acc, acme
def perform_registration(acme, config, tos_cb): """ Actually register new account, trying repeatedly if there are email problems :param .IConfig config: Client configuration. :param acme.client.Client client: ACME client object. :returns: Registration Resource. :rtype: `acme.messages.RegistrationResource` """ try: return acme.new_account_and_tos( messages.NewRegistration.from_data(email=config.email), tos_cb) except messages.Error as e: if e.code == "invalidEmail" or e.code == "invalidContact": if config.noninteractive_mode: msg = ( "The ACME server believes %s is an invalid email address. " "Please ensure it is a valid email and attempt " "registration again." % config.email) raise errors.Error(msg) else: config.email = display_ops.get_email(invalid=True) return perform_registration(acme, config, tos_cb) else: raise
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 certbot.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 `certbot.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.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", force_interactive=True) 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.account = acc.id return acc, acme
def register(config, unused_plugins): """Create or modify accounts on the server. :param config: Configuration object :type config: interfaces.IConfig :param unused_plugins: List of plugins (deprecated) :type unused_plugins: `list` of `str` :returns: `None` or a string indicating and error :rtype: None or str """ # Portion of _determine_account logic to see whether accounts already # exist or not. account_storage = account.AccountFileStorage(config) accounts = account_storage.find_all() reporter_util = zope.component.getUtility(interfaces.IReporter) add_msg = lambda m: reporter_util.add_message( m, reporter_util.MEDIUM_PRIORITY) # registering a new account if not config.update_registration: if len(accounts) > 0: # TODO: add a flag to register a duplicate account (this will # also require extending _determine_account's behavior # or else extracting the registration code from there) return ("There is an existing account; registration of a " "duplicate account with this command is currently " "unsupported.") # _determine_account will register an account _determine_account(config) return # --update-registration if len(accounts) == 0: return "Could not find an existing account to update." if config.email is None: if config.register_unsafely_without_email: return ("--register-unsafely-without-email provided, however, a " "new e-mail address must\ncurrently be provided when " "updating a registration.") config.email = display_ops.get_email(optional=False) acc, acme = _determine_account(config) cb_client = client.Client(config, acc, None, None, acme=acme) # We rely on an exception to interrupt this process if it didn't work. acc_contacts = ['mailto:' + email for email in config.email.split(',')] prev_regr_uri = acc.regr.uri acc.regr = cb_client.acme.update_registration( acc.regr.update(body=acc.regr.body.update(contact=acc_contacts))) # A v1 account being used as a v2 account will result in changing the uri to # the v2 uri. Since it's the same object on disk, put it back to the v1 uri # so that we can also continue to use the account object with acmev1. acc.regr = acc.regr.update(uri=prev_regr_uri) account_storage.save_regr(acc, cb_client.acme) eff.handle_subscription(config) add_msg("Your e-mail address was updated to {0}.".format(config.email))
def _determine_account(config): """Determine which account to use. If ``config.account`` is ``None``, it will be updated based on the user input. Same for ``config.email``. :param config: Configuration object :type config: interfaces.IConfig :returns: Account and optionally ACME client API (biproduct of new registration). :rtype: tuple of :class:`certbot.account.Account` and :class:`acme.client.Client` :raises errors.Error: If unable to register an account with ACME server """ def _tos_cb(terms_of_service): 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( terms_of_service, config.server)) obj = zope.component.getUtility(interfaces.IDisplay) result = obj.yesno(msg, "Agree", "Cancel", cli_flag="--agree-tos", force_interactive=True) if not result: raise errors.Error( "Registration cannot proceed without accepting " "Terms of Service.") 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.email = display_ops.get_email() try: acc, acme = client.register( config, account_storage, tos_cb=_tos_cb) except errors.MissingCommandlineFlag: raise except errors.Error: logger.debug("", exc_info=True) raise errors.Error( "Unable to register an account with ACME server") config.account = acc.id return acc, acme
def register(config, unused_plugins): """Create or modify accounts on the server. :param config: Configuration object :type config: interfaces.IConfig :param unused_plugins: List of plugins (deprecated) :type unused_plugins: `list` of `str` :returns: `None` or a string indicating and error :rtype: None or str """ # Portion of _determine_account logic to see whether accounts already # exist or not. account_storage = account.AccountFileStorage(config) accounts = account_storage.find_all() reporter_util = zope.component.getUtility(interfaces.IReporter) add_msg = lambda m: reporter_util.add_message(m, reporter_util.MEDIUM_PRIORITY) # registering a new account if not config.update_registration: if len(accounts) > 0: # TODO: add a flag to register a duplicate account (this will # also require extending _determine_account's behavior # or else extracting the registration code from there) return ("There is an existing account; registration of a " "duplicate account with this command is currently " "unsupported.") # _determine_account will register an account _determine_account(config) return # --update-registration if len(accounts) == 0: return "Could not find an existing account to update." if config.email is None: if config.register_unsafely_without_email: return ("--register-unsafely-without-email provided, however, a " "new e-mail address must\ncurrently be provided when " "updating a registration.") config.email = display_ops.get_email(optional=False) acc, acme = _determine_account(config) cb_client = client.Client(config, acc, None, None, acme=acme) # We rely on an exception to interrupt this process if it didn't work. acc_contacts = ['mailto:' + email for email in config.email.split(',')] prev_regr_uri = acc.regr.uri acc.regr = cb_client.acme.update_registration(acc.regr.update( body=acc.regr.body.update(contact=acc_contacts))) # A v1 account being used as a v2 account will result in changing the uri to # the v2 uri. Since it's the same object on disk, put it back to the v1 uri # so that we can also continue to use the account object with acmev1. acc.regr = acc.regr.update(uri=prev_regr_uri) account_storage.save_regr(acc, cb_client.acme) eff.handle_subscription(config) add_msg("Your e-mail address was updated to {0}.".format(config.email))
def perform_registration( acme: acme_client.ClientV2, config: configuration.NamespaceConfig, tos_cb: Optional[Callable[[str], None]]) -> messages.RegistrationResource: """ Actually register new account, trying repeatedly if there are email problems :param acme.client.Client acme: ACME client object. :param certbot.configuration.NamespaceConfig config: Client configuration. :param Callable tos_cb: a callback to handle Term of Service agreement. :returns: Registration Resource. :rtype: `acme.messages.RegistrationResource` """ eab_credentials_supplied = config.eab_kid and config.eab_hmac_key eab: Optional[Dict[str, Any]] if eab_credentials_supplied: account_public_key = acme.net.key.public_key() eab = messages.ExternalAccountBinding.from_data( account_public_key=account_public_key, kid=config.eab_kid, hmac_key=config.eab_hmac_key, directory=acme.directory) else: eab = None if acme.external_account_required(): if not eab_credentials_supplied: msg = ("Server requires external account binding." " Please use --eab-kid and --eab-hmac-key.") raise errors.Error(msg) try: newreg = messages.NewRegistration.from_data( email=config.email, external_account_binding=eab) # Until ACME v1 support is removed from Certbot, we actually need the provided # ACME client to be a wrapper of type BackwardsCompatibleClientV2. # TODO: Remove this cast and rewrite the logic when the client is actually a ClientV2 try: return cast(acme_client.BackwardsCompatibleClientV2, acme).new_account_and_tos(newreg, tos_cb) except AttributeError: raise errors.Error("The ACME client must be an instance of " "acme.client.BackwardsCompatibleClientV2") except messages.Error as e: if e.code in ("invalidEmail", "invalidContact"): if config.noninteractive_mode: msg = ( "The ACME server believes %s is an invalid email address. " "Please ensure it is a valid email and attempt " "registration again." % config.email) raise errors.Error(msg) config.email = display_ops.get_email(invalid=True) return perform_registration(acme, config, tos_cb) raise
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 certbot.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 `certbot.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", force_interactive=True) 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
def update_account(config, unused_plugins): """Modify accounts on the server. :param config: Configuration object :type config: interfaces.IConfig :param unused_plugins: List of plugins (deprecated) :type unused_plugins: `list` of `str` :returns: `None` or a string indicating and error :rtype: None or str """ # Portion of _determine_account logic to see whether accounts already # exist or not. account_storage = account.AccountFileStorage(config) accounts = account_storage.find_all() reporter_util = zope.component.getUtility(interfaces.IReporter) add_msg = lambda m: reporter_util.add_message( m, reporter_util.MEDIUM_PRIORITY) if not accounts: return "Could not find an existing account to update." if config.email is None and not config.register_unsafely_without_email: config.email = display_ops.get_email(optional=False) acc, acme = _determine_account(config) cb_client = client.Client(config, acc, None, None, acme=acme) # Empty list of contacts in case the user is removing all emails acc_contacts = () # type: Iterable[str] if config.email: acc_contacts = ['mailto:' + email for email in config.email.split(',')] # We rely on an exception to interrupt this process if it didn't work. prev_regr_uri = acc.regr.uri acc.regr = cb_client.acme.update_registration( acc.regr.update(body=acc.regr.body.update(contact=acc_contacts))) # A v1 account being used as a v2 account will result in changing the uri to # the v2 uri. Since it's the same object on disk, put it back to the v1 uri # so that we can also continue to use the account object with acmev1. acc.regr = acc.regr.update(uri=prev_regr_uri) account_storage.update_regr(acc, cb_client.acme) if config.email is None: add_msg( "Any contact information associated with this account has been removed." ) else: eff.prepare_subscription(config, acc) add_msg("Your e-mail address was updated to {0}.".format(config.email)) return None
def perform_registration(acme, config, tos_cb): """ Actually register new account, trying repeatedly if there are email problems :param acme.client.Client client: ACME client object. :param certbot.configuration.NamespaceConfig config: Client configuration. :param Callable tos_cb: a callback to handle Term of Service agreement. :returns: Registration Resource. :rtype: `acme.messages.RegistrationResource` """ eab_credentials_supplied = config.eab_kid and config.eab_hmac_key eab: Optional[Dict[str, Any]] if eab_credentials_supplied: account_public_key = acme.client.net.key.public_key() eab = messages.ExternalAccountBinding.from_data( account_public_key=account_public_key, kid=config.eab_kid, hmac_key=config.eab_hmac_key, directory=acme.client.directory) else: eab = None if acme.external_account_required(): if not eab_credentials_supplied: msg = ("Server requires external account binding." " Please use --eab-kid and --eab-hmac-key.") raise errors.Error(msg) try: # TODO: Remove the cast once certbot package is fully typed newreg = messages.NewRegistration.from_data( email=config.email, external_account_binding=cast( Optional[messages.ExternalAccountBinding], eab)) return acme.new_account_and_tos(newreg, tos_cb) except messages.Error as e: if e.code in ('invalidEmail', 'invalidContact'): if config.noninteractive_mode: msg = ( "The ACME server believes %s is an invalid email address. " "Please ensure it is a valid email and attempt " "registration again." % config.email) raise errors.Error(msg) config.email = display_ops.get_email(invalid=True) return perform_registration(acme, config, tos_cb) raise
def perform_registration(acme, config, tos_cb): """ Actually register new account, trying repeatedly if there are email problems :param acme.client.Client client: ACME client object. :param .IConfig config: Client configuration. :param Callable tos_cb: a callback to handle Term of Service agreement. :returns: Registration Resource. :rtype: `acme.messages.RegistrationResource` """ eab_credentials_supplied = config.eab_kid and config.eab_hmac_key if eab_credentials_supplied: account_public_key = acme.client.net.key.public_key() eab = messages.ExternalAccountBinding.from_data(account_public_key=account_public_key, kid=config.eab_kid, hmac_key=config.eab_hmac_key, directory=acme.client.directory) else: eab = None if acme.external_account_required(): if not eab_credentials_supplied: msg = ("Server requires external account binding." " Please use --eab-kid and --eab-hmac-key.") raise errors.Error(msg) try: newreg = messages.NewRegistration.from_data(email=config.email, external_account_binding=eab) return acme.new_account_and_tos(newreg, tos_cb) except messages.Error as e: if e.code == "invalidEmail" or e.code == "invalidContact": if config.noninteractive_mode: msg = ("The ACME server believes %s is an invalid email address. " "Please ensure it is a valid email and attempt " "registration again." % config.email) raise errors.Error(msg) else: config.email = display_ops.get_email(invalid=True) return perform_registration(acme, config, tos_cb) else: raise
def register(config, unused_plugins): """Create or modify accounts on the server.""" # Portion of _determine_account logic to see whether accounts already # exist or not. account_storage = account.AccountFileStorage(config) accounts = account_storage.find_all() reporter_util = zope.component.getUtility(interfaces.IReporter) add_msg = lambda m: reporter_util.add_message( m, reporter_util.MEDIUM_PRIORITY) # registering a new account if not config.update_registration: if len(accounts) > 0: # TODO: add a flag to register a duplicate account (this will # also require extending _determine_account's behavior # or else extracting the registration code from there) return ("There is an existing account; registration of a " "duplicate account with this command is currently " "unsupported.") # _determine_account will register an account _determine_account(config) return # --update-registration if len(accounts) == 0: return "Could not find an existing account to update." if config.email is None: if config.register_unsafely_without_email: return ("--register-unsafely-without-email provided, however, a " "new e-mail address must\ncurrently be provided when " "updating a registration.") config.email = display_ops.get_email(optional=False) acc, acme = _determine_account(config) cb_client = client.Client(config, acc, None, None, acme=acme) # We rely on an exception to interrupt this process if it didn't work. acc.regr = cb_client.acme.update_registration( acc.regr.update(body=acc.regr.body.update(contact=('mailto:' + config.email, )))) account_storage.save_regr(acc, cb_client.acme) eff.handle_subscription(config) add_msg("Your e-mail address was updated to {0}.".format(config.email))
def register(config, unused_plugins): """Create or modify accounts on the server.""" # Portion of _determine_account logic to see whether accounts already # exist or not. account_storage = account.AccountFileStorage(config) accounts = account_storage.find_all() reporter_util = zope.component.getUtility(interfaces.IReporter) add_msg = lambda m: reporter_util.add_message(m, reporter_util.MEDIUM_PRIORITY) # registering a new account if not config.update_registration: if len(accounts) > 0: # TODO: add a flag to register a duplicate account (this will # also require extending _determine_account's behavior # or else extracting the registration code from there) return ("There is an existing account; registration of a " "duplicate account with this command is currently " "unsupported.") # _determine_account will register an account _determine_account(config) return # --update-registration if len(accounts) == 0: return "Could not find an existing account to update." if config.email is None: if config.register_unsafely_without_email: return ("--register-unsafely-without-email provided, however, a " "new e-mail address must\ncurrently be provided when " "updating a registration.") config.namespace.email = display_ops.get_email(optional=False) acc, acme = _determine_account(config) acme_client = client.Client(config, acc, None, None, acme=acme) # We rely on an exception to interrupt this process if it didn't work. acc.regr = acme_client.acme.update_registration(acc.regr.update( body=acc.regr.body.update(contact=('mailto:' + config.email,)))) account_storage.save_regr(acc) eff.handle_subscription(config) add_msg("Your e-mail address was updated to {0}.".format(config.email))
def perform_registration(acme, config): """ Actually register new account, trying repeatedly if there are email problems :param .IConfig config: Client configuration. :param acme.client.Client client: ACME client object. :returns: Registration Resource. :rtype: `acme.messages.RegistrationResource` :raises .UnexpectedUpdate: """ try: return acme.register(messages.NewRegistration.from_data(email=config.email)) except messages.Error as e: if e.typ == "urn:acme:error:invalidEmail": config.namespace.email = display_ops.get_email(more=True, invalid=True) return perform_registration(acme, config) else: raise
def _call(cls, **kwargs): from certbot.display.ops import get_email return get_email(**kwargs)