Skip to content

Commit 0bc4178

Browse files
committed
Merge branch 'pilip/user-group-removal' into 'master'
feat: Allow group members removal See merge request TankerHQ/sdk-python!195
2 parents 55e1dff + 22d83af commit 0bc4178

File tree

3 files changed

+79
-19
lines changed

3 files changed

+79
-19
lines changed

cffi_defs.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,9 @@ tanker_future_t* tanker_update_group_members(
335335
tanker_t* session,
336336
char const* group_id,
337337
char const* const* public_identities_to_add,
338-
uint64_t nb_public_identities_to_add);
338+
uint64_t nb_public_identities_to_add,
339+
char const* const* public_identities_to_remove,
340+
uint64_t nb_public_identities_to_remove);
339341

340342
// ctanker/stream.h
341343

tankersdk/tanker.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -893,13 +893,23 @@ async def create_group(self, member_identities: List[str]) -> str:
893893
return ffihelpers.c_string_to_str(c_str)
894894

895895
async def update_group_members(
896-
self, group_id: str, *, users_to_add: OptionalStrList = None
896+
self,
897+
group_id: str,
898+
*,
899+
users_to_add: OptionalStrList = None,
900+
users_to_remove: OptionalStrList = None,
897901
) -> None:
898-
"""Add some users to an existing group"""
902+
"""Add or remove some users from an existing group"""
899903
add_list = CCharList(users_to_add, ffi, tankerlib)
904+
remove_list = CCharList(users_to_remove, ffi, tankerlib)
900905
c_group_id = ffihelpers.str_to_c_string(group_id)
901906
c_future = tankerlib.tanker_update_group_members(
902-
self.c_tanker, c_group_id, add_list.data, add_list.size
907+
self.c_tanker,
908+
c_group_id,
909+
add_list.data,
910+
add_list.size,
911+
remove_list.data,
912+
remove_list.size,
903913
)
904914

905915
await ffihelpers.handle_tanker_future(c_future)

test/test_tanker.py

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from faker import Faker
1010
import requests
11-
from typing import cast, Any, Dict, Iterator, Tuple
11+
from typing import cast, Any, List, Dict, Iterator, Tuple
1212

1313
import tankersdk
1414
from tankersdk import Tanker
@@ -339,43 +339,60 @@ async def test_postponed_share(tmp_path: Path, app: Dict[str, str]) -> None:
339339

340340

341341
async def check_share_with_group_works(
342-
alice: User, group_id: str, bob: User, charlie: User
342+
alice: User, group_id: str, members: List[User], non_members: List[User] = []
343343
) -> None:
344344
message = b"Hi, guys"
345345
encrypted = await alice.session.encrypt(
346346
message, EncryptionOptions(share_with_groups=[group_id])
347347
)
348-
decrypted = await charlie.session.decrypt(encrypted)
349-
assert decrypted == message
350-
decrypted = await bob.session.decrypt(encrypted)
351-
assert decrypted == message
348+
for m in members:
349+
decrypted = await m.session.decrypt(encrypted)
350+
assert decrypted == message
351+
for n in non_members:
352+
with pytest.raises(error.InvalidArgument):
353+
await n.session.decrypt(encrypted)
352354

353355

354356
@pytest.mark.asyncio
355357
async def test_create_group(tmp_path: Path, app: Dict[str, str]) -> None:
356358
alice = await create_user_session(tmp_path, app)
357359
bob = await create_user_session(tmp_path, app)
358360
charlie = await create_user_session(tmp_path, app)
361+
tom = await create_user_session(tmp_path, app)
359362

360363
group_id = await alice.session.create_group(
361-
[bob.public_identity, charlie.public_identity]
364+
[bob.public_identity, charlie.public_identity, tom.public_identity]
362365
)
363-
await check_share_with_group_works(alice, group_id, bob, charlie)
366+
await check_share_with_group_works(alice, group_id, [bob, charlie, tom])
364367

365368

366369
@pytest.mark.asyncio
367370
async def test_update_group(tmp_path: Path, app: Dict[str, str]) -> None:
368371
alice = await create_user_session(tmp_path, app)
369372
bob = await create_user_session(tmp_path, app)
370373
charlie = await create_user_session(tmp_path, app)
374+
tom = await create_user_session(tmp_path, app)
371375

372376
group_id = await alice.session.create_group(
373-
[alice.public_identity, bob.public_identity]
377+
[alice.public_identity, tom.public_identity, bob.public_identity]
374378
)
375379
await alice.session.update_group_members(
376-
group_id, users_to_add=[charlie.public_identity]
380+
group_id,
381+
users_to_add=[charlie.public_identity],
382+
users_to_remove=[tom.public_identity],
377383
)
378-
await check_share_with_group_works(alice, group_id, bob, charlie)
384+
await check_share_with_group_works(alice, group_id, [bob, charlie], [tom])
385+
386+
387+
@pytest.mark.asyncio
388+
async def test_update_group_empty(tmp_path: Path, app: Dict[str, str]) -> None:
389+
alice = await create_user_session(tmp_path, app)
390+
391+
group_id = await alice.session.create_group([alice.public_identity])
392+
with pytest.raises(error.InvalidArgument):
393+
await alice.session.update_group_members(
394+
group_id, users_to_add=[], users_to_remove=[],
395+
)
379396

380397

381398
@pytest.mark.asyncio
@@ -721,7 +738,7 @@ async def test_bad_verification_code(tmp_path: Path, app: Dict[str, str]) -> Non
721738
)
722739

723740

724-
async def set_up_preshare(tmp_path: Path, app: Dict[str, str]) -> Tuple[User, PreUser]:
741+
async def create_pre_user(tmp_path: Path, app: Dict[str, str]) -> PreUser:
725742
fake = Faker()
726743
bob_email = fake.email(domain="tanker.io")
727744
bob_provisional_identity = tankersdk_identity.create_provisional_identity(
@@ -730,7 +747,6 @@ async def set_up_preshare(tmp_path: Path, app: Dict[str, str]) -> Tuple[User, Pr
730747
bob_public_provisional_identity = tankersdk_identity.get_public_identity(
731748
bob_provisional_identity
732749
)
733-
alice = await create_user_session(tmp_path, app)
734750
bob = await create_user_session(tmp_path, app)
735751
pre_bob = PreUser(
736752
session=bob.session,
@@ -741,7 +757,12 @@ async def set_up_preshare(tmp_path: Path, app: Dict[str, str]) -> Tuple[User, Pr
741757
email=bob_email,
742758
verification_code=get_verification_code_email(app, bob_email),
743759
)
744-
return alice, pre_bob
760+
return pre_bob
761+
762+
763+
async def set_up_preshare(tmp_path: Path, app: Dict[str, str]) -> Tuple[User, PreUser]:
764+
alice = await create_user_session(tmp_path, app)
765+
return alice, await create_pre_user(tmp_path, app)
745766

746767

747768
@pytest.mark.asyncio
@@ -899,7 +920,9 @@ async def test_create_group_with_prov_id(tmp_path: Path, app: Dict[str, str]) ->
899920

900921

901922
@pytest.mark.asyncio
902-
async def test_add_to_group_with_prov_id(tmp_path: Path, app: Dict[str, str]) -> None:
923+
async def test_add_group_members_with_prov_id(
924+
tmp_path: Path, app: Dict[str, str]
925+
) -> None:
903926
alice, bob = await set_up_preshare(tmp_path, app)
904927
message = b"Hi, this is for a group"
905928
group_id = await alice.session.create_group([alice.public_identity])
@@ -917,6 +940,31 @@ async def test_add_to_group_with_prov_id(tmp_path: Path, app: Dict[str, str]) ->
917940
assert decrypted == message
918941

919942

943+
@pytest.mark.asyncio
944+
async def test_remove_group_members_with_prov_id(
945+
tmp_path: Path, app: Dict[str, str]
946+
) -> None:
947+
alice, bob = await set_up_preshare(tmp_path, app)
948+
message = b"Hi, this is for a group"
949+
group_id = await alice.session.create_group(
950+
[alice.public_identity, bob.public_provisional_identity]
951+
)
952+
953+
await bob.session.attach_provisional_identity(bob.private_provisional_identity)
954+
await bob.session.verify_provisional_identity(
955+
EmailVerification(bob.email, bob.verification_code)
956+
)
957+
958+
encrypted = await alice.session.encrypt(
959+
message, EncryptionOptions(share_with_groups=[group_id])
960+
)
961+
await alice.session.update_group_members(
962+
group_id, users_to_remove=[bob.public_identity]
963+
)
964+
with pytest.raises(error.InvalidArgument):
965+
await bob.session.decrypt(encrypted)
966+
967+
920968
@pytest.mark.asyncio
921969
async def test_user_not_found(tmp_path: Path, app: Dict[str, str]) -> None:
922970
user_id = encode("*" * 32)

0 commit comments

Comments
 (0)