def update_registration(self, regr): """Update registration. :pram regr: Registration Resource. :type regr: `.RegistrationResource` :returns: Updated Registration Resource. :rtype: `.RegistrationResource` """ response = self.net.post( regr.uri, messages.UpdateRegistration(**dict(regr.body))) # TODO: Boulder returns httplib.ACCEPTED #assert response.status_code == httplib.OK # TODO: Boulder does not set Location or Link on update # (c.f. acme-spec #94) updated_regr = self._regr_from_response( response, uri=regr.uri, new_authzr_uri=regr.new_authzr_uri, terms_of_service=regr.terms_of_service) if updated_regr != regr: raise errors.UnexpectedUpdate(regr) return updated_regr
def register(ctx, email, phone, auto_accept_tos, quiet=False): regr = ctx.obj['acme'].register( messages.NewRegistration.from_data(email=email, phone=phone)) if regr.body.agreement != regr.terms_of_service: if not auto_accept_tos and not click.confirm( 'Accept Terms of Service? (%s)' % regr.terms_of_service, default=None): ctx.fail('Must accept ToS to continue') elif auto_accept_tos: logger.info('automatically accepting ToS') ctx.obj['acme'].agree_to_tos(regr) if (email and (email, ) != regr.body.emails) or (phone and (phone, ) != regr.body.phones): logger.info('updating contact information') upd_reg = messages.UpdateRegistration().from_data(email=email, phone=phone) try: regr = ctx.obj['acme'].update_registration(regr, upd_reg) except errors.UnexpectedUpdate: pass # no idea why it complains, but updates anyway regr = ctx.obj['acme'].query_registration(regr) if not quiet: click.echo('Registration:') click.echo('Email: %s' % (regr.body.emails, )) click.echo('Phone: %s' % (regr.body.phones, )) else: return regr
def update_registration(self, regr, uri=None): """ Submit a registration to the server to update it. :param ~acme.messages.RegistrationResource regr: The registration to update. Can be a :class:`~acme.messages.NewRegistration` instead, in order to create a new registration. :param str uri: The url to submit to. Must be specified if a :class:`~acme.messages.NewRegistration` is provided. :return: The updated registration resource. :rtype: Deferred[`~acme.messages.RegistrationResource`] """ if uri is None: uri = regr.uri if isinstance(regr, messages.RegistrationResource): message = messages.UpdateRegistration(**dict(regr.body)) else: message = regr action = LOG_ACME_UPDATE_REGISTRATION(uri=uri, registration=message) with action.context(): return ( DeferredContext(self._client.post(uri, message)) .addCallback(self._parse_regr_response, uri=uri) .addCallback(self._check_regr, regr) .addCallback( tap(lambda r: action.add_success_fields(registration=r))) .addActionFinish())
def query_registration(self, regr): """Query server about registration. :param messages.RegistrationResource: Existing Registration Resource. """ return self._send_recv_regr(regr, messages.UpdateRegistration())
def register(ctx, email, phone, auto_accept_tos, quiet=False): ''' Register a new account key or update an existing registration. ''' logger.info('starting registration for email:"%s", phone:"%s"', email, phone) try: regr = ctx.obj.acme.register( messages.NewRegistration.from_data(email=email, phone=phone)) except errors.ConflictError as e: logger.info('found existing registration for key; fetching') response = ctx.obj.acme.net.post(e.location, messages.UpdateRegistration()) regr = client.Client._regr_from_response(response, uri=e.location) if regr.body.agreement != regr.terms_of_service: if not auto_accept_tos and not click.confirm( 'Accept Terms of Service? (%s)' % regr.terms_of_service, default=None): ctx.fail('Must accept ToS to continue') elif auto_accept_tos: logger.info('automatically accepting ToS') ctx.obj.acme.agree_to_tos(regr) if (email and (email, ) != regr.body.emails) or (phone and (phone, ) != regr.body.phones): logger.info('updating contact information') upd_reg = messages.UpdateRegistration().from_data(email=email, phone=phone) try: regr = ctx.obj.acme.update_registration(regr, upd_reg) except errors.UnexpectedUpdate: pass # no idea why it complains, but updates anyway regr = ctx.obj.acme.query_registration(regr) if not quiet: click.echo('Registration:') click.echo('Email: %s' % (regr.body.emails or '')) click.echo('Phone: %s' % (regr.body.phones or '')) else: return regr
def _maybe_registered(self, failure): """ If the registration already exists, we should just load it. """ failure.trap(ServerError) response = failure.value.response if response.code == http.CONFLICT: uri = self._maybe_location(response) return self.update_registration( messages.UpdateRegistration(), uri=uri) return failure
def _monkeypatch_register(self, new_reg=None): new_reg = new_reg or messages.NewRegistration() response = self.net.post(self.directory[new_reg], new_reg, check_response=False) loc = None if response.status_code == client.http_client.CONFLICT and response.headers.get( 'Location'): reg = messages.UpdateRegistration() loc = response.headers.get('Location') response = self.net.post(loc, reg) return self._regr_from_response(response, uri=loc)
def update_registration(self, regr, update=None): """Update registration. :param messages.RegistrationResource regr: Registration Resource. :param messages.Registration update: Updated body of the resource. If not provided, body will be taken from `regr`. :returns: Updated Registration Resource. :rtype: `.RegistrationResource` """ update = regr.body if update is None else update body = messages.UpdateRegistration(**dict(update)) updated_regr = self._send_recv_regr(regr, body=body) return updated_regr
async def connect(cls, directory: str, key: crypto.PrivateKey, *, loop: _T_AIO_LOOP = None) -> 'AsyncmeClient': """ Connect to an ACME server. :param directory: The URI of the ACME server's directory. :param key: Private key used for interacting with the ACME server. :param loop: Event loop. :return: A new instance of ``AsyncmeClient`` which has been registered against the given ACME server, if the key has not already been registered. """ # Determine the JWS 'alg' Type for the Given Key # RSA if key.algorithm is crypto.KeyAlgorithmType.RSA: if key.size / 8 == 256: alg = jose.jwa.RS256 elif key.size / 8 == 384: alg = jose.jwa.RS384 elif key.size / 8 == 512: alg = jose.jwa.RS512 else: raise ValueError("RSA key size of {} " "is unsupported".format(key.size)) # ECDSA elif key.algorithm is crypto.KeyAlgorithmType.ECDSA: if key.size == 256: alg = jose.jwa.ES256 elif key.size == 384: alg = jose.jwa.ES384 elif key.size == 521: alg = jose.jwa.ES512 else: raise ValueError("ECDSA key size of {} " "is unsupported".format(key.size)) # Other else: raise ValueError("Unsupported private key type, must " "be RSA or ECDSA") # Convert Key password = os.urandom(255) acme_key = jose.JWKRSA(key=serialization.load_der_private_key( key.to_bytes(encoding=crypto.EncodingType.DER, password=password), password, default_backend())) # Get Async. Loop loop = loop or asyncio.get_event_loop() # Instantiate Underlying Client # (and make the initial connection to the ACME server) try: client = await ExecutorClient.connect( directory=directory, key=acme_key, alg=alg, net=ExtendedNetwork( key=acme_key, alg=alg, user_agent='asyncme-python-{}'.format(ASYNCME_VERSION)), loop=loop) except TypeError: raise ValueError("Invalid ACME directory given") # Client Registration try: regr = await client.register() except errors.Error as e: # The upstream client currently has no way to "recover" a lost # registration resource, thus we must resort to the tactics below. if "key is already in use" in str(e): LOG.debug("Key already in use: attempting to recover " "registration resource.") # (1) Send a Post in Attempt to Register the Client # and Get a 409 Back in Response with Location # Header set. post = functools.partial(client.net.post, client.directory['new-reg'], messages.NewRegistration(), checked=False) response = await loop.run_in_executor(None, post) assert response.status_code == 409 # (2) Manually create a new Registration Resource and # send an empty registration update. # (per draft-ietf-acme-acme-03#section-6.2) regr = messages.RegistrationResource( uri=response.headers.get("location")) # Empty Update regr = await client._send_recv_regr( regr, body=messages.UpdateRegistration()) else: raise RuntimeError(e) return cls(client, regr)