From 625d9994900f2357361bc06d81bc3bec12c2a55f Mon Sep 17 00:00:00 2001 From: Vincent Michel Date: Wed, 6 Nov 2024 18:56:20 +0100 Subject: [PATCH] Add shamir recovery invitation to invite_list tests --- .../authenticated_cmds/v4/invite_list.rs | 71 ++++++++++++++++ .../api_v4/authenticated/test_invite_list.py | 80 ++++++++++++++++++- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/libparsec/crates/protocol/tests/authenticated_cmds/v4/invite_list.rs b/libparsec/crates/protocol/tests/authenticated_cmds/v4/invite_list.rs index 3170ae86d17..a400cbcf8b4 100644 --- a/libparsec/crates/protocol/tests/authenticated_cmds/v4/invite_list.rs +++ b/libparsec/crates/protocol/tests/authenticated_cmds/v4/invite_list.rs @@ -92,4 +92,75 @@ pub fn rep_ok() { let data2 = authenticated_cmds::invite_list::Rep::load(&raw2).unwrap(); p_assert_eq!(data2, expected); + + // Generated from Parsec 3.1.1-a.0+dev + // Content: + // status: 'ok' + // invitations: [ + // { + // type: 'USER', + // claimer_email: 'alice@example.com', + // created_on: ext(1, 946774800000000) i.e. 2000-01-02T02:00:00Z, + // status: 'IDLE', + // token: 0xd864b93ded264aae9ae583fd3d40c45a, + // }, + // { + // type: 'DEVICE', + // created_on: ext(1, 946774800000000) i.e. 2000-01-02T02:00:00Z, + // status: 'IDLE', + // token: 0xd864b93ded264aae9ae583fd3d40c45a, + // }, + // { + // type: 'SHAMIR_RECOVERY', + // claimer_user_id: ext(2, 0xa11cec00100000000000000000000000), + // created_on: ext(1, 946774800000000) i.e. 2000-01-02T02:00:00Z, + // status: 'IDLE', + // token: 0xd864b93ded264aae9ae583fd3d40c45a, + // }, + // ] + let raw: &[u8] = hex!( + "82a6737461747573a26f6bab696e7669746174696f6e739385a474797065a455534552" + "ad636c61696d65725f656d61696cb1616c696365406578616d706c652e636f6daa6372" + "65617465645f6f6ed70100035d162fa2e400a6737461747573a449444c45a5746f6b65" + "6ec410d864b93ded264aae9ae583fd3d40c45a84a474797065a6444556494345aa6372" + "65617465645f6f6ed70100035d162fa2e400a6737461747573a449444c45a5746f6b65" + "6ec410d864b93ded264aae9ae583fd3d40c45a85a474797065af5348414d49525f5245" + "434f56455259af636c61696d65725f757365725f6964d802a11cec0010000000000000" + "0000000000aa637265617465645f6f6ed70100035d162fa2e400a6737461747573a449" + "444c45a5746f6b656ec410d864b93ded264aae9ae583fd3d40c45a" + ) + .as_ref(); + + let expected = authenticated_cmds::invite_list::Rep::Ok { + invitations: vec![ + authenticated_cmds::invite_list::InviteListItem::User { + token: InvitationToken::from_hex("d864b93ded264aae9ae583fd3d40c45a").unwrap(), + created_on: "2000-1-2T01:00:00Z".parse().unwrap(), + claimer_email: "alice@example.com".to_owned(), + status: InvitationStatus::Idle, + }, + authenticated_cmds::invite_list::InviteListItem::Device { + token: InvitationToken::from_hex("d864b93ded264aae9ae583fd3d40c45a").unwrap(), + created_on: "2000-1-2T01:00:00Z".parse().unwrap(), + status: InvitationStatus::Idle, + }, + authenticated_cmds::invite_list::InviteListItem::ShamirRecovery { + token: InvitationToken::from_hex("d864b93ded264aae9ae583fd3d40c45a").unwrap(), + created_on: "2000-1-2T01:00:00Z".parse().unwrap(), + claimer_user_id: "alice".parse().unwrap(), + status: InvitationStatus::Idle, + }, + ], + }; + + let data = authenticated_cmds::invite_list::Rep::load(raw).unwrap(); + println!("***expected: {:?}", expected.dump().unwrap()); + p_assert_eq!(data, expected); + + // Also test serialization round trip + let raw2 = data.dump().unwrap(); + + let data2 = authenticated_cmds::invite_list::Rep::load(&raw2).unwrap(); + + p_assert_eq!(data2, expected); } diff --git a/server/tests/api_v4/authenticated/test_invite_list.py b/server/tests/api_v4/authenticated/test_invite_list.py index 25a97c0882d..be5552000cb 100644 --- a/server/tests/api_v4/authenticated/test_invite_list.py +++ b/server/tests/api_v4/authenticated/test_invite_list.py @@ -1,9 +1,87 @@ # Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -from parsec._parsec import DateTime, InvitationStatus, authenticated_cmds +import pytest + +from parsec._parsec import ( + DateTime, + InvitationStatus, + InvitationToken, + ShamirRecoveryBriefCertificate, + ShamirRecoveryShareCertificate, + authenticated_cmds, +) from tests.common import Backend, CoolorgRpcClients, HttpCommonErrorsTester, MinimalorgRpcClients +@pytest.fixture +async def alice_shamir(backend: Backend, coolorg: CoolorgRpcClients, with_postgresql: bool) -> None: + if with_postgresql: + pytest.xfail("TODO: postgre not implemented yet") + dt = DateTime.now() + bob_share = ShamirRecoveryShareCertificate( + author=coolorg.alice.device_id, + user_id=coolorg.alice.user_id, + timestamp=dt, + recipient=coolorg.bob.user_id, + ciphered_share=b"abc", + ) + mallory_share = ShamirRecoveryShareCertificate( + author=coolorg.alice.device_id, + user_id=coolorg.alice.user_id, + timestamp=dt, + recipient=coolorg.mallory.user_id, + ciphered_share=b"abc", + ) + brief = ShamirRecoveryBriefCertificate( + author=coolorg.alice.device_id, + user_id=coolorg.alice.user_id, + timestamp=dt, + threshold=2, + per_recipient_shares={coolorg.bob.user_id: 1, coolorg.mallory.user_id: 1}, + ) + + setup = authenticated_cmds.v4.shamir_recovery_setup.ShamirRecoverySetup( + b"abc", + InvitationToken.new(), + brief.dump_and_sign(coolorg.alice.signing_key), + [ + bob_share.dump_and_sign(coolorg.alice.signing_key), + mallory_share.dump_and_sign(coolorg.alice.signing_key), + ], + ) + rep = await coolorg.alice.shamir_recovery_setup(setup) + assert rep == authenticated_cmds.v4.shamir_recovery_setup.RepOk() + + +async def test_authenticated_invite_list_ok_with_shamir_recovery( + coolorg: CoolorgRpcClients, backend: Backend, alice_shamir: None +) -> None: + expected_invitations = [] + + # Shamir recovery invitation + t6 = DateTime(2020, 1, 6) + outcome = await backend.invite.new_for_shamir_recovery( + now=t6, + organization_id=coolorg.organization_id, + author=coolorg.bob.device_id, + claimer_user_id=coolorg.alice.user_id, + send_email=False, + ) + assert isinstance(outcome, tuple) + expected_invitations.append( + authenticated_cmds.v4.invite_list.InviteListItemShamirRecovery( + created_on=t6, + status=InvitationStatus.IDLE, + claimer_user_id=coolorg.alice.user_id, + token=outcome[0], + ) + ) + + rep = await coolorg.bob.invite_list() + assert isinstance(rep, authenticated_cmds.v4.invite_list.RepOk) + assert rep.invitations == expected_invitations + + async def test_authenticated_invite_list_ok( minimalorg: MinimalorgRpcClients, backend: Backend ) -> None: