def _on_claim_clicked(self): # No try/except given `self.line_edit_device` has already been validated against `DeviceLabel` device_label = DeviceLabel( validators.trim_user_name(self.line_edit_device.text())) try: user_name = validators.trim_user_name( self.line_edit_user_full_name.text()) human_handle = HumanHandle(email=self.line_edit_user_email.text(), label=user_name) device_label = DeviceLabel(self.line_edit_device.text()) except ValueError as exc: show_error(self, _("TEXT_CLAIM_USER_INVALID_HUMAN_HANDLE"), exception=exc) return self.button_ok.setDisabled(True) self.widget_info.setDisabled(True) self.label_wait.show() self.claim_job = self.jobs_ctx.submit_job( self.claim_success, self.claim_error, self.claimer.claim_user, device_label=device_label, human_handle=human_handle, )
async def _bootstrap_organization( config: CoreConfig, addr: BackendOrganizationBootstrapAddr, device_label: Optional[DeviceLabel], human_label: Optional[str], human_email: Optional[str], save_device_with_selected_auth: Callable, ) -> None: if not human_label: human_label = await aprompt("User fullname") if not human_email: human_email = await aprompt("User email") human_handle = HumanHandle(email=human_email, label=human_label) if not device_label: device_label_raw = await aprompt("Device label", default=platform.node()) device_label = DeviceLabel(device_label_raw) async with spinner("Bootstrapping organization in the backend"): new_device = await do_bootstrap_organization(addr, human_handle=human_handle, device_label=device_label) # We don't have to worry about overwritting an existing keyfile # given their names are base on the device's slughash which is intended # to be globally unique. # The organization is brand new, of course there is no existing # remote user manifest, hence our placeholder is non-speculative. await user_storage_non_speculative_init(data_base_dir=config.data_base_dir, device=new_device) await save_device_with_selected_auth(config_dir=config.config_dir, device=new_device)
async def ask_info_new_user( default_device_label: str, default_user_label: str, default_user_email: str ) -> Tuple[DeviceLabel, HumanHandle, UserProfile]: while True: granted_label = await aprompt("New user label", default=default_user_label) granted_email = await aprompt("New user email", default=default_user_email) try: granted_human_handle = HumanHandle(email=granted_email, label=granted_label) break except ValueError: click.echo("Invalid user label and/or email") continue while True: try: granted_device_label = DeviceLabel( await aprompt("New user device label", default=default_device_label) ) break except ValueError: click.echo("Invalid value") continue choices = list(UserProfile) for i, choice in enumerate(UserProfile): display_choice = click.style(choice.value, fg="yellow") click.echo(f" {i} - {display_choice}") choice_index = await aprompt( "New user profile", default="1", type=click.Choice([str(i) for i, _ in enumerate(choices)]) ) granted_profile = choices[int(choice_index)] return granted_device_label, granted_human_handle, granted_profile
def _on_create_user_clicked(self): assert not self.create_user_job handle = None # No try/except given `self.line_edit_device` has already been validated against `DeviceLabel` device_label = DeviceLabel( validators.trim_user_name(self.line_edit_device.text())) try: user_name = validators.trim_user_name( self.line_edit_user_full_name.text()) handle = HumanHandle(label=user_name, email=self.line_edit_user_email.text()) except ValueError as exc: show_error(self, _("TEXT_GREET_USER_INVALID_HUMAN_HANDLE"), exception=exc) return self.button_create_user.setDisabled(True) self.button_create_user.setText(_("TEXT_GREET_USER_WAITING")) self.create_user_job = self.jobs_ctx.submit_job( self.create_user_success, self.create_user_error, self.greeter.create_new_user, human_handle=handle, device_label=device_label, profile=self.combo_profile.currentData(), )
def generate_ALICE_local_device(): return LocalDevice( organization_addr=BackendOrganizationAddr.from_url( "parsec://alice_dev1.example.com:9999/CoolOrg?no_ssl=true&rvk=XYUXM4ZM5SGKSTXNZ4FK7VATZUKZGY7A7LOJ42CXFR32DYL5TO6Qssss" ), device_id=DeviceID("alice@dev1"), device_label=DeviceLabel("My dev1 machine"), human_handle=HumanHandle("*****@*****.**", "Alicey McAliceFace"), signing_key=SigningKey( unhexlify( "d544f66ece9c85d5b80275db9124b5f04bb038081622bed139c1e789c5217400" )), private_key=PrivateKey( unhexlify( "74e860967fd90d063ebd64fb1ba6824c4c010099dd37508b7f2875a5db2ef8c9" )), profile=UserProfile.ADMIN, user_manifest_id=EntryID.from_hex("a4031e8bcdd84df8ae12bd3d05e6e20f"), user_manifest_key=SecretKey( unhexlify( "26bf35a98c1e54e90215e154af92a1af2d1142cdd0dba25b990426b0b30b0f9a" )), local_symkey=SecretKey( unhexlify( "125a78618995e2e0f9a19bc8617083c809c03deb5457d5b82df5bcaec9966cd4" )), )
def generate_BOB_local_device(): return LocalDevice( organization_addr=BackendOrganizationAddr.from_url( "parsec://bob_dev1.example.com:9999/CoolOrg?no_ssl=true&rvk=XYUXM4ZM5SGKSTXNZ4FK7VATZUKZGY7A7LOJ42CXFR32DYL5TO6Qssss" ), device_id=DeviceID("bob@dev1"), device_label=DeviceLabel("My dev1 machine"), human_handle=HumanHandle("*****@*****.**", "Boby McBobFace"), signing_key=SigningKey( unhexlify( "85f47472a2c0f30f01b769617db248f3ec8d96a490602a9262f95e9e43432b30" )), private_key=PrivateKey( unhexlify( "16767ec446f2611f971c36f19c2dc11614d853475ac395d6c1d70ba46d07dd49" )), profile=UserProfile.STANDARD, user_manifest_id=EntryID.from_hex("71568d41afcb4e2380b3d164ace4fb85"), user_manifest_key=SecretKey( unhexlify( "65de53d2c6cd965aa53a1ba5cc7e54b331419e6103466121996fa99a97197a48" )), local_symkey=SecretKey( unhexlify( "93f25b18491016f20b10dcf4eb7986716d914653d6ab4e778701c13435e6bdf0" )), )
async def _do_greet_device(device: LocalDevice, initial_ctx: DeviceGreetInitialCtx) -> bool: async with spinner("Waiting for claimer"): in_progress_ctx = await initial_ctx.do_wait_peer() display_greeter_sas = click.style(str(in_progress_ctx.greeter_sas), fg="yellow") click.echo(f"Code to provide to claimer: {display_greeter_sas}") async with spinner("Waiting for claimer"): in_progress_ctx = await in_progress_ctx.do_wait_peer_trust() choices = in_progress_ctx.generate_claimer_sas_choices(size=3) for i, choice in enumerate(choices): display_choice = click.style(choice, fg="yellow") click.echo(f" {i} - {display_choice}") code = await aprompt( f"Select code provided by claimer", type=click.Choice([str(x) for x in range(len(choices))]) ) if choices[int(code)] != in_progress_ctx.claimer_sas: click.secho("Wrong code provided", fg="red") return False async with spinner("Waiting for claimer"): in_progress_ctx = await in_progress_ctx.do_signify_trust() in_progress_ctx = await in_progress_ctx.do_get_claim_requests() granted_device_label = await aprompt( "New device label", default=in_progress_ctx.requested_device_label ) async with spinner("Creating the device in the backend"): await in_progress_ctx.do_create_new_device( author=device, device_label=DeviceLabel(granted_device_label) ) return True
async def _do_claim_device(initial_ctx: DeviceClaimInitialCtx) -> LocalDevice: async with spinner("Initializing connection with greeter for claiming device"): in_progress_ctx = await initial_ctx.do_wait_peer() choices = in_progress_ctx.generate_greeter_sas_choices(size=3) for i, choice in enumerate(choices): display_choice = click.style(choice, fg="yellow") click.echo(f" {i} - {display_choice}") code = await aprompt( f"Select code provided by greeter", type=click.Choice([str(x) for x in range(len(choices))]) ) if choices[int(code)] != in_progress_ctx.greeter_sas: click.secho("Wrong code provided", fg="red") return None in_progress_ctx = await in_progress_ctx.do_signify_trust() display_claimer_sas = click.style(str(in_progress_ctx.claimer_sas), fg="yellow") click.echo(f"Code to provide to greeter: {display_claimer_sas}") async with spinner("Waiting for greeter"): in_progress_ctx = await in_progress_ctx.do_wait_peer_trust() requested_device_label = await aprompt("Device label", default=platform.node()) async with spinner("Waiting for greeter (finalizing)"): new_device = await in_progress_ctx.do_claim_device( requested_device_label=DeviceLabel(requested_device_label) ) return new_device
def validate(self, string, pos): try: if len(string) == 0: return QValidator.Intermediate, string, pos DeviceLabel(string) return QValidator.Acceptable, string, pos except ValueError: return QValidator.Invalid, string, pos
async def _do_claimer_claim_device(): with pytest.raises( BackendInvitationAlreadyUsed) as exc_info: await claimer_in_progress_ctx.do_claim_device( requested_device_label=DeviceLabel( "TheSecretDevice")) assert str( exc_info.value ) == "Invalid handshake: Invitation already deleted"
def test_list_devices_support_key_file(config_dir, type): if type == "password": data_extra = {"type": "password", "salt": b"12345"} available_device_extra = {"type": DeviceFileType.PASSWORD} elif type == "smartcard": data_extra = { "type": "smartcard", "encrypted_key": b"12345", "certificate_id": "42", "certificate_sha1": b"12345", } available_device_extra = {"type": DeviceFileType.SMARTCARD} # Device information user_id = uuid4().hex device_name = uuid4().hex organization_id = "Org" rvk_hash = (uuid4().hex)[:10] device_id = f"{user_id}@{device_name}" slug = f"{rvk_hash}#{organization_id}#{device_id}" human_label = "Billy Mc BillFace" human_email = "*****@*****.**" device_label = "My device" # Craft file data key_file_data = packb({ "ciphertext": b"whatever", "human_handle": (human_email.encode(), human_label.encode()), "device_label": device_label, "device_id": device_id, "organization_id": organization_id, "slug": slug, **data_extra, }) key_file_path = get_devices_dir(config_dir) / "device.keys" key_file_path.parent.mkdir(parents=True) key_file_path.write_bytes(key_file_data) devices = list_available_devices(config_dir) expected_device = AvailableDevice( key_file_path=key_file_path, organization_id=OrganizationID(organization_id), device_id=DeviceID(device_id), human_handle=HumanHandle(human_email, human_label), device_label=DeviceLabel(device_label), slug=slug, **available_device_extra, ) assert devices == [expected_device] assert get_key_file(config_dir, expected_device) == key_file_path
def test_device_certificate(): from parsec.api.data.certif import ( _RsDeviceCertificateContent, DeviceCertificateContent, _PyDeviceCertificateContent, ) assert DeviceCertificateContent is _RsDeviceCertificateContent def _assert_device_certificate_eq(py, rs): assert py.author == rs.author assert py.timestamp == rs.timestamp assert py.device_id == rs.device_id assert py.device_label == rs.device_label assert py.verify_key == rs.verify_key kwargs = { "author": DeviceID.new(), "timestamp": pendulum.now(), "device_id": DeviceID("bob@dev1"), "device_label": DeviceLabel("dev machine"), "verify_key": SigningKey.generate().verify_key, } py_dc = _PyDeviceCertificateContent(**kwargs) rs_dc = DeviceCertificateContent(**kwargs) _assert_device_certificate_eq(py_dc, rs_dc) kwargs = { "author": DeviceID.new(), "timestamp": pendulum.now(), "device_id": DeviceID("alice@dev1"), "device_label": None, "verify_key": SigningKey.generate().verify_key, } py_dc = py_dc.evolve(**kwargs) rs_dc = rs_dc.evolve(**kwargs) _assert_device_certificate_eq(py_dc, rs_dc) sign_key = SigningKey.generate() py_data = py_dc.dump_and_sign(sign_key) rs_data = rs_dc.dump_and_sign(sign_key) py_dc = _PyDeviceCertificateContent.verify_and_load( rs_data, sign_key.verify_key, expected_author=py_dc.author, expected_device=py_dc.device_id ) rs_dc = DeviceCertificateContent.verify_and_load( py_data, sign_key.verify_key, expected_author=rs_dc.author, expected_device=rs_dc.device_id ) _assert_device_certificate_eq(py_dc, rs_dc) py_dc = _PyDeviceCertificateContent.unsecure_load(rs_data) rs_dc = DeviceCertificateContent.unsecure_load(py_data) _assert_device_certificate_eq(py_dc, rs_dc)
async def generate_recovery_device( original_device: LocalDevice, ) -> LocalDevice: """ Raises: BackendConnectionError """ now = pendulum.now() # Unique enough label is expected, but unicity is not strongly enforced new_device_label = DeviceLabel( f"recovery-{now.year}-{now.month}-{now.day}-{secrets.token_hex(2)}") return await _create_new_device_for_self(original_device, new_device_label)
async def test_create_organization_same_name( gui, aqtbot, running_backend, catch_create_org_widget, autoclose_dialog, organization_bootstrap_addr, ): # Create an org human_handle = HumanHandle(email="*****@*****.**", label="Zack") await bootstrap_organization(organization_bootstrap_addr, human_handle=human_handle, device_label=DeviceLabel("PC1")) # Now create an org with the same name aqtbot.key_click(gui, "n", QtCore.Qt.ControlModifier, 200) co_w = await catch_create_org_widget() assert co_w def _user_widget_ready(): assert isinstance(co_w.current_widget, CreateOrgUserInfoWidget) await aqtbot.wait_until(_user_widget_ready) # Adding a few spaces to the name await aqtbot.key_clicks(co_w.current_widget.line_edit_user_full_name, "Gordon Freeman") await aqtbot.key_clicks(co_w.current_widget.line_edit_user_email, "*****@*****.**") await aqtbot.key_clicks(co_w.current_widget.line_edit_org_name, "AnomalousMaterials") await aqtbot.key_clicks(co_w.current_widget.line_edit_device, "HEV") assert not co_w.button_validate.isEnabled() aqtbot.mouse_click(co_w.current_widget.check_accept_contract, QtCore.Qt.LeftButton) def _user_widget_button_validate_ready(): assert co_w.button_validate.isEnabled() await aqtbot.wait_until(_user_widget_button_validate_ready) async with aqtbot.wait_signal(co_w.req_error): aqtbot.mouse_click(co_w.button_validate, QtCore.Qt.LeftButton) def _modal_shown(): assert autoclose_dialog.dialogs == [ ("Error", "This organization name is already used.") ] await aqtbot.wait_until(_modal_shown)
async def _get_device(conn, organization_id: OrganizationID, device_id: DeviceID) -> Device: row = await conn.fetchrow(*_q_get_device( organization_id=organization_id.str, device_id=device_id.str)) if not row: raise UserNotFoundError(device_id) return Device( device_id=device_id, device_label=DeviceLabel(row["device_label"]), device_certificate=row["device_certificate"], redacted_device_certificate=row["redacted_device_certificate"], device_certifier=DeviceID(row["device_certifier"]), created_on=row["created_on"], )
async def _get_user_devices(conn, organization_id: OrganizationID, user_id: UserID) -> Tuple[Device, ...]: results = await conn.fetch(*_q_get_user_devices( organization_id=organization_id.str, user_id=user_id.str)) return tuple( Device( device_id=DeviceID(row["device_id"]), device_label=DeviceLabel(row["device_label"] ) if row["device_label"] else None, device_certificate=row["device_certificate"], redacted_device_certificate=row["redacted_device_certificate"], device_certifier=DeviceID(row["device_certifier"] ) if row["device_certifier"] else None, created_on=row["created_on"], ) for row in results)
async def _on_validate_clicked(self): if isinstance(self.current_page, DeviceRecoveryImportPage1Widget): # No try/except given `self.line_edit_device` has already been validated against `DeviceLabel` device_label = DeviceLabel( validators.trim_user_name( self.current_page.line_edit_device.text())) self.jobs_ctx.submit_job( self.create_new_device_success, self.create_new_device_failure, self._create_new_device, device_label=device_label, file_path=PurePath(self.current_page.get_recovery_key_file()), passphrase=self.current_page.get_passphrase(), ) else: try: self.button_validate.setEnabled(False) auth_method = self.current_page.get_auth_method() if auth_method == DeviceFileType.PASSWORD: save_device_with_password_in_config( config_dir=self.config.config_dir, device=self.new_device, password=self.current_page.get_auth(), ) else: await save_device_with_smartcard_in_config( config_dir=self.config.config_dir, device=self.new_device) show_info(self, translate("TEXT_RECOVERY_IMPORT_SUCCESS")) self.dialog.accept() except LocalDeviceCryptoError as exc: self.button_validate.setEnabled(True) if auth_method == DeviceFileType.SMARTCARD: show_error(self, translate("TEXT_INVALID_SMARTCARD"), exception=exc) except LocalDeviceNotFoundError as exc: if auth_method == DeviceFileType.PASSWORD: show_error(self, translate("TEXT_CANNOT_SAVE_DEVICE"), exception=exc) self.button_validate.setEnabled(True) except LocalDeviceError as exc: show_error(self, translate("TEXT_CANNOT_SAVE_DEVICE"), exception=exc) self.button_validate.setEnabled(True)
def test_list_devices_support_legacy_file_with_meaningful_name(config_dir): # Legacy path might exceed the 256 characters limit in some cases (see issue #1356) # So we use the `\\?\` workaround: https://stackoverflow.com/a/57502760/2846140 if sys.platform == "win32": config_dir = Path("\\\\?\\" + str(config_dir.resolve())) # Device information user_id = uuid4().hex device_name = uuid4().hex organization_id = "Org" rvk_hash = (uuid4().hex)[:10] device_id = f"{user_id}@{device_name}" slug = f"{rvk_hash}#{organization_id}#{device_id}" human_label = "Billy Mc BillFace" human_email = "*****@*****.**" device_label = "My device" # Craft file data without the user_id, organization_id and slug fields key_file_data = packb({ "type": "password", "salt": b"12345", "ciphertext": b"whatever", "human_handle": (human_email.encode(), human_label.encode()), "device_label": device_label, }) key_file_path = get_devices_dir(config_dir) / slug / f"{slug}.keys" key_file_path.parent.mkdir(parents=True) key_file_path.write_bytes(key_file_data) devices = list_available_devices(config_dir) expected_device = AvailableDevice( key_file_path=key_file_path, organization_id=OrganizationID(organization_id), device_id=DeviceID(device_id), human_handle=HumanHandle(human_email, human_label), device_label=DeviceLabel(device_label), slug=slug, type=DeviceFileType.PASSWORD, ) assert devices == [expected_device] assert get_key_file(config_dir, expected_device) == key_file_path
def _on_claim_clicked(self): if not self.new_device: # No try/except given `self.line_edit_device` has already been validated against `DeviceLabel` device_label = DeviceLabel( validators.trim_user_name(self.line_edit_device.text())) self.button_ok.setDisabled(True) self.widget_info.setDisabled(True) self.label_wait.show() self.claim_job = self.jobs_ctx.submit_job( self.claim_success, self.claim_error, self.claimer.claim_device, device_label=device_label, ) else: self.succeeded.emit(self.new_device, self.widget_auth.get_auth_method(), self.widget_auth.get_auth())
def __init__(self): self.requested_device_label = DeviceLabel("PC1") self.password = "******" self.steps_done = [] self.author = alice self.cmds = alice_backend_cmds # Set during bootstrap self.invitation_addr = None self.claim_device_widget = None self.claim_device_instructions_widget = None # Set by step 2 self.claim_device_code_exchange_widget = None # Set by step 4 self.claim_device_provide_info_widget = None
def __init__(self): self.requested_human_handle = HumanHandle( email="*****@*****.**", label="Bender B. Rodriguez") self.requested_device_label = DeviceLabel("PC1") self.steps_done = [] # Set during bootstrap self.author = None self.devices_widget = None self.invitation_addr = None self.greet_device_widget = None self.greet_device_information_widget = None self.cmds = None # Set by step 2 self.greet_device_code_exchange_widget = None # Set by step 5 self.claimer_claim_task = None
def __init__(self): self.requested_human_handle = HumanHandle(email="*****@*****.**", label="Philip J. Fry") self.requested_device_label = DeviceLabel("PC1") self.password = "******" self.steps_done = [] self.author = alice self.cmds = alice_backend_cmds # Set during bootstrap self.invitation_addr = None self.claim_user_widget = None self.claim_user_instructions_widget = None # Set by step 2 self.claim_user_code_exchange_widget = None # Set by step 4 self.claim_user_provide_info_widget = None
async def test_greet_user_modified_claim_info(GreetUserTestBed, backend, coolorg): granted_email = "*****@*****.**" granted_label = "Don Diego De La Vega" granted_device_label = DeviceLabel("Tornado") class ModifiedClaimInfoTestBed(GreetUserTestBed): async def step_5_provide_claim_info(self): await super().step_5_provide_claim_info() self.granted_email = granted_email self.granted_label = granted_label self.granted_device_label = granted_device_label guci_w = self.greet_user_check_informations_widget guci_w.line_edit_user_full_name.setText(self.granted_label) guci_w.line_edit_user_email.setText(self.granted_email) guci_w.line_edit_device.setText(self.granted_device_label.str) for index in range(guci_w.combo_profile.model().rowCount()): item = guci_w.combo_profile.model().item(index) if item.text() == translate("TEXT_USER_PROFILE_ADMIN"): item = guci_w.combo_profile.setCurrentIndex(index) break else: assert False return "step_6_validate_claim_info" await ModifiedClaimInfoTestBed().run() # Now check in the backend if everything went as expected results, _ = await backend.user.find_humans( organization_id=coolorg.organization_id, query="zorro") assert len(results) == 1 assert results[0].human_handle.label == granted_label assert results[0].human_handle.email == granted_email user = await backend.user.get_user(organization_id=coolorg.organization_id, user_id=results[0].user_id) assert user.profile == UserProfile.ADMIN
async def query_get_user_with_device( conn, organization_id: OrganizationID, device_id: DeviceID) -> Tuple[User, Device]: d_row = await conn.fetchrow(*_q_get_device( organization_id=organization_id.str, device_id=device_id.str)) u_row = await conn.fetchrow(*_q_get_user( organization_id=organization_id.str, user_id=device_id.user_id.str)) if not u_row or not d_row: raise UserNotFoundError(device_id) human_handle = None if u_row["human_email"]: human_handle = HumanHandle(email=u_row["human_email"], label=u_row["human_label"]) device = Device( device_id=device_id, device_label=DeviceLabel(d_row["device_label"]) if d_row["device_label"] else None, device_certificate=d_row["device_certificate"], redacted_device_certificate=d_row["redacted_device_certificate"], device_certifier=DeviceID(d_row["device_certifier"]) if d_row["device_certifier"] else None, created_on=d_row["created_on"], ) user = User( user_id=device_id.user_id, human_handle=human_handle, profile=UserProfile(u_row["profile"]), user_certificate=u_row["user_certificate"], redacted_user_certificate=u_row["redacted_user_certificate"], user_certifier=DeviceID(u_row["user_certifier"]) if u_row["user_certifier"] else None, created_on=u_row["created_on"], revoked_on=u_row["revoked_on"], revoked_user_certificate=u_row["revoked_user_certificate"], revoked_user_certifier=DeviceID(u_row["revoked_user_certifier"]) if u_row["revoked_user_certifier"] else None, ) return user, device
async def _add_random_users( cmds: BackendAuthenticatedCmds, author: LocalDevice, alice_core: LoggedCore, bob_core: LoggedCore, alice_ws_id: EntryID, bob_ws_id: EntryID, additional_users_number: int, ): """ Add random number of users with random role, and share workspaces with them. 1 out of 5 users will be revoked from organization. """ for _ in range(additional_users_number): name = "test_" + str(uuid4())[:9] user_profile = random.choice(list(UserProfile)) if user_profile == UserProfile.OUTSIDER: realm_role = random.choice([WorkspaceRole.READER, WorkspaceRole.CONTRIBUTOR]) else: realm_role = random.choice(list(WorkspaceRole)) # Workspace_choice : 0 = add user to first_ws, 1 = add to second_ws, 2 = add in both workspace, other = nothing workspace_choice = random.randint(0, 3) # invite user to organization user_device = await _register_new_user( cmds=cmds, author=author, device_label=DeviceLabel("desktop"), human_handle=HumanHandle(email=f"{name}@gmail.com", label=name), profile=user_profile, ) # Share workspace with new user if workspace_choice == 0 or workspace_choice == 2: await alice_core.user_fs.workspace_share(alice_ws_id, user_device.user_id, realm_role) if workspace_choice == 1 or workspace_choice == 2: await bob_core.user_fs.workspace_share(bob_ws_id, user_device.user_id, realm_role) # One chance out of 5 to be revoked from organization if not random.randint(0, 4): await alice_core.revoke_user(user_device.user_id)
async def test_user_create_human_handle_already_exists(alice_backend_sock, alice, bob): now = pendulum.now() bob2_device_id = DeviceID("bob2@dev1") user_certificate = UserCertificateContent( author=alice.device_id, timestamp=now, user_id=bob2_device_id.user_id, human_handle=bob.human_handle, public_key=bob.public_key, profile=UserProfile.STANDARD, ) redacted_user_certificate = user_certificate.evolve(human_handle=None) device_certificate = DeviceCertificateContent( author=alice.device_id, timestamp=now, device_id=bob2_device_id, device_label=DeviceLabel("dev2"), verify_key=bob.verify_key, ) redacted_device_certificate = device_certificate.evolve(device_label=None) user_certificate = user_certificate.dump_and_sign(alice.signing_key) redacted_user_certificate = redacted_user_certificate.dump_and_sign(alice.signing_key) device_certificate = device_certificate.dump_and_sign(alice.signing_key) redacted_device_certificate = redacted_device_certificate.dump_and_sign(alice.signing_key) rep = await user_create( alice_backend_sock, user_certificate=user_certificate, device_certificate=device_certificate, redacted_user_certificate=redacted_user_certificate, redacted_device_certificate=redacted_device_certificate, ) assert rep == { "status": "already_exists", "reason": f"Human handle `{bob.human_handle}` already corresponds to a non-revoked user", }
def test_invite_device_data(): from parsec.api.data.invite import _RsInviteDeviceData, InviteDeviceData, _PyInviteDeviceData assert InviteDeviceData is _RsInviteDeviceData dl = DeviceLabel("label") sk = SigningKey.generate() vk = sk.verify_key sek = SecretKey.generate() py_idd = _PyInviteDeviceData(requested_device_label=dl, verify_key=vk) rs_idd = InviteDeviceData(requested_device_label=dl, verify_key=vk) assert rs_idd.requested_device_label.str == py_idd.requested_device_label.str rs_encrypted = rs_idd.dump_and_encrypt(key=sek) py_encrypted = py_idd.dump_and_encrypt(key=sek) # Decrypt Rust-encrypted with Rust rs_idd2 = InviteDeviceData.decrypt_and_load(rs_encrypted, sek) assert rs_idd.requested_device_label.str == rs_idd2.requested_device_label.str # Decrypt Python-encrypted with Python rs_idd3 = InviteDeviceData.decrypt_and_load(py_encrypted, sek) assert rs_idd.requested_device_label.str == rs_idd3.requested_device_label.str # Decrypt Rust-encrypted with Python py_idd2 = _PyInviteDeviceData.decrypt_and_load(rs_encrypted, sek) assert rs_idd.requested_device_label.str == py_idd2.requested_device_label.str # With requested_human_handle and requested_device_label as None py_idd = _PyInviteDeviceData(requested_device_label=None, verify_key=vk) rs_idd = InviteDeviceData(requested_device_label=None, verify_key=vk) assert py_idd.requested_device_label is None assert rs_idd.requested_device_label is None
def __init__(self): self.requested_email = "*****@*****.**" self.requested_label = "Philip J. Fry" self.requested_device_label = DeviceLabel("PC1") self.granted_email = self.requested_email self.granted_label = self.requested_label self.granted_device_label = self.requested_device_label self.steps_done = [] # Set during bootstrap self.author = None self.users_widget = None self.invitation_widget = None self.invitation_addr = None self.greet_user_widget = None self.greet_user_information_widget = None self.cmds = None # Set by step 2 self.greet_user_code_exchange_widget = None # Set by step 5 self.claimer_claim_task = None self.greet_user_check_informations_widget = None
def test_invite_user_data(): from parsec.api.data.invite import _RsInviteUserData, InviteUserData, _PyInviteUserData assert InviteUserData is _RsInviteUserData dl = DeviceLabel("label") hh = HumanHandle("*****@*****.**", "Hubert Farnsworth") pk = PrivateKey.generate() sik = SigningKey.generate() sek = SecretKey.generate() py_iud = _PyInviteUserData( requested_device_label=dl, requested_human_handle=hh, public_key=pk.public_key, verify_key=sik.verify_key, ) rs_iud = InviteUserData( requested_device_label=dl, requested_human_handle=hh, public_key=pk.public_key, verify_key=sik.verify_key, ) assert rs_iud.requested_device_label.str == py_iud.requested_device_label.str assert str(rs_iud.requested_human_handle) == str( py_iud.requested_human_handle) rs_encrypted = rs_iud.dump_and_encrypt(key=sek) py_encrypted = py_iud.dump_and_encrypt(key=sek) # Decrypt Rust-encrypted with Rust rs_iud2 = InviteUserData.decrypt_and_load(rs_encrypted, sek) assert rs_iud.requested_device_label.str == rs_iud2.requested_device_label.str assert str(rs_iud.requested_human_handle) == str( rs_iud2.requested_human_handle) # Decrypt Python-encrypted with Python rs_iud3 = InviteUserData.decrypt_and_load(py_encrypted, sek) assert rs_iud.requested_device_label.str == rs_iud3.requested_device_label.str assert str(rs_iud.requested_human_handle) == str( rs_iud3.requested_human_handle) # Decrypt Rust-encrypted with Python py_iud2 = _PyInviteUserData.decrypt_and_load(rs_encrypted, sek) assert rs_iud.requested_device_label.str == py_iud2.requested_device_label.str assert str(rs_iud.requested_human_handle) == str( py_iud2.requested_human_handle) # With requested_human_handle and requested_device_label as None py_iud = _PyInviteUserData( requested_device_label=None, requested_human_handle=None, public_key=pk.public_key, verify_key=sik.verify_key, ) rs_iud = InviteUserData( requested_device_label=None, requested_human_handle=None, public_key=pk.public_key, verify_key=sik.verify_key, ) assert py_iud.requested_device_label is None assert rs_iud.requested_device_label is None assert py_iud.requested_human_handle is None assert rs_iud.requested_human_handle is None
async def test_good( running_backend, backend, user_fs_factory, with_labels, data_base_dir, backend_version, monkeypatch, ): org_id = OrganizationID("NewOrg") org_token = "123456" await backend.organization.create(org_id, org_token) organization_addr = BackendOrganizationBootstrapAddr.build( running_backend.addr, org_id, org_token) if with_labels: human_handle = HumanHandle(email="*****@*****.**", label="Zack") device_label = DeviceLabel("PC1") else: human_handle = None device_label = None if backend_version == "2.5": _handle_request = AsyncMock( return_value=HTTPResponse.build_msgpack(404, {})) monkeypatch.setattr("parsec.backend.http.HTTPComponent.handle_request", _handle_request) if backend_version == "2.6": _handle_request = AsyncMock(return_value=HTTPResponse.build_msgpack( 200, {"status": "unknown_command"})) monkeypatch.setattr("parsec.backend.http.HTTPComponent.handle_request", _handle_request) if backend_version == "latest": _handle_request = None new_device = await bootstrap_organization(organization_addr, human_handle=human_handle, device_label=device_label) if _handle_request is not None: _handle_request.assert_awaited_once() assert new_device is not None assert new_device.organization_id == org_id assert new_device.device_label == device_label assert new_device.human_handle == human_handle assert new_device.profile == UserProfile.ADMIN # This function should always be called as part of bootstrap organization # (yeah, we should improve the ergonomics...) await user_storage_non_speculative_init(data_base_dir=data_base_dir, device=new_device) # Test the behavior of this new device async with user_fs_factory(new_device, data_base_dir=data_base_dir) as newfs: # New user should start with a non-speculative user manifest um = newfs.get_user_manifest() assert um.is_placeholder assert not um.speculative await newfs.workspace_create(EntryName("wa")) await newfs.sync() um = newfs.get_user_manifest() assert not um.is_placeholder assert not um.speculative # Test the device in correct in the backend backend_user, backend_device = await backend.user.get_user_with_device( org_id, new_device.device_id) assert backend_user.user_id == new_device.user_id assert backend_user.human_handle == new_device.human_handle assert backend_user.profile == new_device.profile assert backend_user.user_certifier is None if with_labels: assert backend_user.user_certificate != backend_user.redacted_user_certificate else: assert backend_user.user_certificate == backend_user.redacted_user_certificate assert backend_device.device_id == new_device.device_id assert backend_device.device_label == new_device.device_label assert backend_device.device_certifier is None if with_labels: assert backend_device.device_certificate != backend_device.redacted_device_certificate else: assert backend_device.device_certificate == backend_device.redacted_device_certificate