def test_load_bad_data(config_dir, alice): alice_key = get_default_key_file(config_dir, alice) alice_key.parent.mkdir(parents=True) alice_key.write_bytes(b"dummy") with pytest.raises(LocalDevicePackingError): load_device_with_password(alice_key, "S3Cr37")
def test_change_password(config_dir, alice): old_password = "******" new_password = "******" save_device_with_password_in_config(config_dir, alice, old_password) key_file = get_key_file(config_dir, alice) change_device_password(key_file, old_password, new_password) alice_reloaded = load_device_with_password(key_file, new_password) assert alice == alice_reloaded with pytest.raises(LocalDeviceCryptoError): load_device_with_password(key_file, old_password)
def login_with_password(self, key_file, password): message = None exception = None try: device = load_device_with_password(key_file, password) if ParsecApp.is_device_connected( device.organization_addr.organization_id, device.device_id ): message = _("TEXT_LOGIN_ERROR_ALREADY_CONNECTED") else: self.start_core(device) except LocalDeviceError as exc: message = _("TEXT_LOGIN_ERROR_AUTHENTICATION_FAILED") exception = exc except (RuntimeError, MountpointConfigurationError, MountpointDriverCrash) as exc: message = _("TEXT_LOGIN_MOUNTPOINT_ERROR") exception = exc except Exception as exc: message = _("TEXT_LOGIN_UNKNOWN_ERROR") exception = exc logger.exception("Unhandled error during login") finally: if message: show_error(self, message, exception=exception) self.login_failed.emit()
def test_password_save_and_load(path_exists, config_dir, alice): config_dir = config_dir if path_exists else config_dir / "dummy" save_device_with_password_in_config(config_dir, alice, "S3Cr37") key_file = get_key_file(config_dir, alice) alice_reloaded = load_device_with_password(key_file, "S3Cr37") assert alice == alice_reloaded
def wrapper(**kwargs): config = kwargs["config"] password = kwargs["password"] organization_id, device_id, slugname = kwargs["device"] devices = [ (o, d, t, kf) for o, d, t, kf in list_available_devices(config.config_dir) if (not organization_id or o == organization_id) and d == device_id ] if not devices: raise SystemExit(f"Device `{slugname}` not found") elif len(devices) > 1: found = "\n".join([str(kf.parent) for *_, kf in devices]) raise SystemExit( f"Multiple devices found for `{slugname}`:\n{found}") else: _, _, cipher, key_file = devices[0] try: if cipher != "password": raise SystemExit( f"Device {slugname} is ciphered with {cipher}.") if password is None: password = click.prompt("password", hide_input=True) device = load_device_with_password(key_file, password) except LocalDeviceError as exc: raise SystemExit(f"Cannot load device {slugname}: {exc}") kwargs["device"] = device return fn(**kwargs)
def wrapper(**kwargs): config = kwargs["config"] password = kwargs["password"] device_slughash = kwargs.pop("device") all_available_devices = list_available_devices(config.config_dir) devices = [] for device in all_available_devices: if device.slughash.startswith(device_slughash): devices.append(device) if not devices: raise SystemExit( f"Device `{device_slughash}` not found, available devices:\n" f"{format_available_devices(all_available_devices)}") elif len(devices) > 1: raise SystemExit( f"Multiple devices found for `{device_slughash}`:\n" f"{format_available_devices(devices)}") try: if password is None: password = click.prompt("password", hide_input=True) device = load_device_with_password(devices[0].key_file_path, password) except LocalDeviceError as exc: raise SystemExit(f"Cannot load device {device_slughash}: {exc}") kwargs["device"] = device return fn(**kwargs)
def test_available_devices_slughash_uniqueness(organization_factory, local_device_factory, config_dir): def _to_available(device): return AvailableDevice( key_file_path=get_default_key_file(config_dir, device), organization_id=device.organization_id, device_id=device.device_id, human_handle=device.human_handle, device_label=device.device_label, slug=device.slug, type=DeviceFileType.PASSWORD, ) def _assert_different_as_available(d1, d2): available_device_d1 = _to_available(d1) available_device_d2 = _to_available(d2) assert available_device_d1.slughash != available_device_d2.slughash # Make sure slughash is consistent between LocalDevice and AvailableDevice assert available_device_d1.slughash == d1.slughash assert available_device_d2.slughash == d2.slughash o1 = organization_factory("org1") o2 = organization_factory("org2") # Different user id o1u1d1 = local_device_factory("u1@d1", o1) o1u2d1 = local_device_factory("u2@d1", o1) _assert_different_as_available(o1u1d1, o1u2d1) # Different device name o1u1d2 = local_device_factory("u1@d2", o1) _assert_different_as_available(o1u1d1, o1u1d2) # Different organization id o2u1d1 = local_device_factory("u1@d1", o2) _assert_different_as_available(o1u1d1, o2u1d1) # Same organization_id, but different root verify key ! dummy_key = SigningKey.generate().verify_key o1u1d1_bad_rvk = o1u1d1.evolve( organization_addr=o1u1d1.organization_addr.build( backend_addr=o1u1d1.organization_addr.get_backend_addr(), organization_id=o1u1d1.organization_addr.organization_id, root_verify_key=dummy_key, )) _assert_different_as_available(o1u1d1, o1u1d1_bad_rvk) # Finally make sure slughash is stable through save/load save_device_with_password_in_config(config_dir, o1u1d1, "S3Cr37") key_file = get_key_file(config_dir, o1u1d1) o1u1d1_reloaded = load_device_with_password(key_file, "S3Cr37") available_device = _to_available(o1u1d1) available_device_reloaded = _to_available(o1u1d1_reloaded) assert available_device.slughash == available_device_reloaded.slughash
def test_same_device_id_different_orginazations(config_dir, alice, otheralice): devices = (alice, otheralice) for device in devices: save_device_with_password_in_config( config_dir, device, f"S3Cr37-{device.organization_id}") for device in devices: key_file = get_key_file(config_dir, device) device_reloaded = load_device_with_password( key_file, f"S3Cr37-{device.organization_id}") assert device == device_reloaded
async def main(): # Config config_dir = get_default_config_dir(os.environ) config = load_config(config_dir) devices = list_available_devices(config_dir) key_file = next(key_file for _, device_id, _, key_file in devices if device_id == DEVICE_ID) device = load_device_with_password(key_file, PASSWORD) # Log in async with logged_core_factory(config, device) as core: # Get workspace user_manifest = core.user_fs.get_user_manifest() workspace_entry = user_manifest.workspaces[0] workspace = core.user_fs.get_workspace(workspace_entry.id) # await make_workspace_dir_inconsistent(device, workspace, "/bar") await make_workspace_dir_simple_versions(device, workspace, "/foo")
async def show_modal(cls, core, jobs_ctx, parent, on_finished=None): available_device = get_available_device(core.config.config_dir, core.device) loaded_device = None try: if available_device.type == DeviceFileType.PASSWORD: password = get_text_input( parent, _("TEXT_DEVICE_UNLOCK_TITLE"), _("TEXT_DEVICE_UNLOCK_FOR_AUTH_CHANGE_LABEL"), placeholder="", default_text="", completion=None, button_text=None, validator=None, hidden=True, ) if not password: return loaded_device = load_device_with_password( available_device.key_file_path, password) else: loaded_device = await load_device_with_smartcard( available_device.key_file_path) except LocalDeviceError: show_error(parent, _("TEXT_LOGIN_ERROR_AUTHENTICATION_FAILED")) return w = cls(core=core, jobs_ctx=jobs_ctx, loaded_device=loaded_device) d = GreyedDialog(w, title=_("TEXT_CHANGE_AUTHENTICATION_TITLE"), parent=parent) w.dialog = d if on_finished: d.finished.connect(on_finished) # Unlike exec_, show is asynchronous and works within the main Qt loop d.show() return w
async def _on_validate_clicked(self): if isinstance(self.current_page, DeviceRecoveryExportPage1Widget): self.button_validate.setEnabled(False) selected_device = self.current_page.get_selected_device() save_path = self.current_page.get_save_path() device = None if isinstance(selected_device, LocalDevice): selected_device = get_available_device(self.config.config_dir, selected_device) if selected_device.type == DeviceFileType.PASSWORD: password = get_text_input( self, translate("TEXT_DEVICE_UNLOCK_TITLE"), translate("TEXT_DEVICE_UNLOCK_FOR_RECOVERY_LABEL"), placeholder="", default_text="", completion=None, button_text=None, validator=None, hidden=True, ) if password is None: self.button_validate.setEnabled(True) return try: device = load_device_with_password( selected_device.key_file_path, password) except LocalDeviceError: show_error( self, translate("TEXT_LOGIN_ERROR_AUTHENTICATION_FAILED")) self.button_validate.setEnabled(True) return elif selected_device.type == DeviceFileType.SMARTCARD: try: device = await load_device_with_smartcard( selected_device.key_file_path) except LocalDeviceError as exc: show_error( self, translate("TEXT_LOGIN_ERROR_AUTHENTICATION_FAILED"), exception=exc) self.button_validate.setEnabled(True) return except ModuleNotFoundError as exc: show_error( self, translate("TEXT_UNLOCK_ERROR_SMARTCARD_NOT_AVAILABLE"), exception=exc) self.button_validate.setEnabled(True) return self.jobs_ctx.submit_job( self.export_success, self.export_failure, self._export_recovery_device, config_dir=self.config.config_dir, device=device, export_path=save_path, ) else: self.dialog.accept()
def test_password_load_not_found(config_dir, alice): with pytest.raises(LocalDeviceNotFoundError): key_file = get_default_key_file(config_dir, alice) load_device_with_password(key_file, "S3Cr37")
def test_load_bad_password(config_dir, alice): save_device_with_password_in_config(config_dir, alice, "S3Cr37") with pytest.raises(LocalDeviceCryptoError): key_file = get_key_file(config_dir, alice) load_device_with_password(key_file, "dummy")