def _save_device_with_password(key_file: Path, device: LocalDevice, password: str, force: bool) -> None: if key_file.exists() and not force: raise LocalDeviceAlreadyExistsError( f"Device key file `{key_file}` already exists") try: key, salt = derivate_secret_key_from_password(password) ciphertext = key.encrypt(device.dump()) except (CryptoError, DataError) as exc: raise LocalDeviceValidationError( f"Cannot dump local device: {exc}") from exc key_file_content = key_file_serializer.dumps({ "salt": salt, "ciphertext": ciphertext, "human_handle": device.human_handle, "device_label": device.device_label, "organization_id": device.organization_id, "device_id": device.device_id, "slug": device.slug, }) try: key_file.parent.mkdir(mode=0o700, exist_ok=True, parents=True) key_file.write_bytes(key_file_content) except OSError as exc: raise LocalDeviceError(f"Cannot save {key_file}: {exc}") from exc
def _save_device( key_file: Path, device: LocalDevice, force: bool, encrypt_dump: Callable[[bytes], Tuple[DeviceFileType, bytes, dict]], ) -> None: assert key_file.suffix == DEVICE_FILE_SUFFIX if key_file.exists() and not force: raise LocalDeviceAlreadyExistsError( f"Device key file `{key_file}` already exists") cleartext = device.dump() type, ciphertext, extra_args = encrypt_dump(cleartext) key_file_content = key_file_serializer.dumps({ "type": type, **extra_args, "ciphertext": ciphertext, "human_handle": device.human_handle, "device_label": device.device_label, "organization_id": device.organization_id, "device_id": device.device_id, "slug": device.slug, }) try: key_file.parent.mkdir(mode=0o700, exist_ok=True, parents=True) key_file.write_bytes(key_file_content) except OSError as exc: raise LocalDeviceError(f"Cannot save {key_file}: {exc}") from exc
def _save_device(key_file: Path, device: LocalDevice, encryptor: BaseLocalDeviceEncryptor, force: bool = False) -> None: """ Raises: LocalDeviceError LocalDeviceAlreadyExistsError LocalDeviceCryptoError LocalDeviceValidationError LocalDevicePackingError """ if key_file.exists() and not force: raise LocalDeviceAlreadyExistsError( f"Device `{device.organization_id}:{device.device_id}` already exists" ) try: raw = device.dump() except DataError as exc: raise LocalDeviceValidationError( f"Cannot dump local device: {exc}") from exc ciphertext = encryptor.encrypt(raw) try: key_file.parent.mkdir(exist_ok=True, parents=True) key_file.write_bytes(ciphertext) except OSError as exc: raise LocalDeviceError(f"Cannot save {key_file}: {exc}") from exc
async def save_recovery_device(key_file: PurePath, device: LocalDevice, force: bool = False) -> str: """ Return the recovery passphrase """ assert key_file.suffix == RECOVERY_DEVICE_FILE_SUFFIX key_file = trio.Path(key_file) if await key_file.exists() and not force: raise LocalDeviceAlreadyExistsError( f"Device key file `{key_file}` already exists") passphrase, key = generate_recovery_passphrase() try: ciphertext = key.encrypt(device.dump()) except (CryptoError, DataError) as exc: raise LocalDeviceValidationError( f"Cannot dump local device: {exc}") from exc key_file_content = key_file_serializer.dumps({ "type": DeviceFileType.RECOVERY, "ciphertext": ciphertext, "human_handle": device.human_handle, "device_label": device.device_label, "organization_id": device.organization_id, "device_id": device.device_id, "slug": device.slug, }) try: await key_file.parent.mkdir(mode=0o700, exist_ok=True, parents=True) await key_file.write_bytes(key_file_content) except OSError as exc: raise LocalDeviceError(f"Cannot save {key_file}: {exc}") from exc return passphrase