async def do_create_new_device(self, author: LocalDevice, device_label: Optional[str]) -> None: device_id = author.user_id.to_device_id(DeviceName.new()) try: now = pendulum_now() device_certificate = DeviceCertificateContent( author=author.device_id, timestamp=now, device_id=device_id, device_label=device_label, verify_key=self._verify_key, ) redacted_device_certificate = device_certificate.evolve( device_label=None) device_certificate = device_certificate.dump_and_sign( author.signing_key) redacted_device_certificate = redacted_device_certificate.dump_and_sign( author.signing_key) except DataError as exc: raise InviteError( f"Cannot generate device certificate: {exc}") from exc rep = await self._cmds.device_create( device_certificate=device_certificate, redacted_device_certificate=redacted_device_certificate, ) _check_rep(rep, step_name="device creation") try: payload = InviteDeviceConfirmation( device_id=device_id, device_label=device_label, human_handle=author.human_handle, profile=author.profile, private_key=author.private_key, user_manifest_id=author.user_manifest_id, user_manifest_key=author.user_manifest_key, root_verify_key=author.root_verify_key, ).dump_and_encrypt(key=self._shared_secret_key) except DataError as exc: raise InviteError( "Cannot generate InviteUserConfirmation payload") from exc rep = await self._cmds.invite_4_greeter_communicate(token=self.token, payload=payload) _check_rep(rep, step_name="step 4 (confirmation exchange)") await self._cmds.invite_delete(token=self.token, reason=InvitationDeletedReason.FINISHED)
async def do_create_new_device( self, author: LocalDevice, device_label: Optional[DeviceLabel]) -> None: device_id = author.user_id.to_device_id(DeviceName.new()) try: timestamp = author.timestamp() device_certificate = DeviceCertificateContent( author=author.device_id, timestamp=timestamp, device_id=device_id, device_label=device_label, verify_key=self._verify_key, ) redacted_device_certificate = device_certificate.evolve( device_label=None) device_certificate = device_certificate.dump_and_sign( author.signing_key) redacted_device_certificate = redacted_device_certificate.dump_and_sign( author.signing_key) except DataError as exc: raise InviteError( f"Cannot generate device certificate: {exc}") from exc rep = await self._cmds.device_create( device_certificate=device_certificate, redacted_device_certificate=redacted_device_certificate, ) _check_rep(rep, step_name="step 4 (device certificates upload)") # From now on the device has been created on the server, but greeter # is not aware of it yet. If something goes wrong, we can end up with # the greeter losing it private keys. # This is considered acceptable given 1) the error window is small and # 2) if this occurs the inviter can revoke the device and retry the # enrollment process to fix this try: payload = InviteDeviceConfirmation( device_id=device_id, device_label=device_label, human_handle=author.human_handle, profile=author.profile, private_key=author.private_key, user_manifest_id=author.user_manifest_id, user_manifest_key=author.user_manifest_key, root_verify_key=author.root_verify_key, ).dump_and_encrypt(key=self._shared_secret_key) except DataError as exc: raise InviteError( "Cannot generate InviteUserConfirmation payload") from exc rep = await self._cmds.invite_4_greeter_communicate(token=self.token, payload=payload) _check_rep(rep, step_name="step 4 (confirmation exchange)") # Invitation deletion is not strictly necessary (enrollment has succeeded # anyway) so it's no big deal if something goes wrong before it can be # done (and it can be manually deleted from invitation list). await self._cmds.invite_delete(token=self.token, reason=InvitationDeletedReason.FINISHED)