-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3272683
commit bee2c50
Showing
8 changed files
with
234 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,40 @@ | ||
from parsec.components.shamir import BaseShamirComponent | ||
# Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS | ||
|
||
from parsec._parsec import DeviceID, OrganizationID, UserID, VerifyKey, authenticated_cmds | ||
from parsec.components.events import EventBus | ||
from parsec.components.memory.datamodel import ( | ||
MemoryDatamodel, | ||
MemoryShamirSetup, | ||
) | ||
from parsec.components.shamir import BaseShamirComponent, verify_certificates | ||
|
||
|
||
class MemoryShamirComponent(BaseShamirComponent): | ||
pass | ||
def __init__(self, data: MemoryDatamodel, event_bus: EventBus) -> None: | ||
super().__init__() | ||
self._data = data | ||
self._event_bus = event_bus | ||
|
||
async def remove_recovery_setup( | ||
self, | ||
organization_id: OrganizationID, | ||
author: UserID, | ||
) -> None: | ||
self._data.organizations[organization_id].shamir_setup.pop(author) | ||
|
||
async def add_recovery_setup( | ||
self, | ||
organization_id: OrganizationID, | ||
author: UserID, | ||
device: DeviceID, | ||
author_verify_key: VerifyKey, | ||
setup: authenticated_cmds.latest.shamir_recovery_setup.ShamirRecoverySetup, | ||
) -> None | authenticated_cmds.latest.shamir_recovery_setup.Rep: | ||
match verify_certificates(setup, device, author_verify_key): | ||
case (brief, shares): | ||
self._data.organizations[organization_id].shamir_setup[author] = MemoryShamirSetup( | ||
setup.ciphered_data, setup.reveal_token, brief, shares | ||
) | ||
|
||
case authenticated_cmds.latest.shamir_recovery_setup.RepInvalidData() as error: | ||
return error |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,102 @@ | ||
# Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS | ||
|
||
from __future__ import annotations | ||
|
||
from parsec._parsec import ( | ||
DeviceID, | ||
OrganizationID, | ||
ShamirRecoveryBriefCertificate, | ||
ShamirRecoveryShareCertificate, | ||
UserID, | ||
VerifyKey, | ||
authenticated_cmds, | ||
) | ||
from parsec.api import api | ||
from parsec._parsec import authenticated_cmds | ||
from parsec.client_context import AuthenticatedClientContext | ||
|
||
|
||
class BaseShamirComponent: | ||
@api | ||
async def create_shared_recovery_device(self, client_ctx: AuthenticatedClientContext, req: authenticated_cmds.latest.shamir_recovery_setup.Req) -> authenticated_cmds.latest.shamir_recovery_setup.Rep: | ||
pass | ||
async def create_shared_recovery_device( | ||
self, | ||
client_ctx: AuthenticatedClientContext, | ||
req: authenticated_cmds.latest.shamir_recovery_setup.Req, | ||
) -> authenticated_cmds.latest.shamir_recovery_setup.Rep: | ||
if req.setup is None: | ||
await self.remove_recovery_setup(client_ctx.organization_id, client_ctx.user_id) | ||
return authenticated_cmds.latest.shamir_recovery_setup.RepOk() | ||
else: | ||
match await self.add_recovery_setup( | ||
client_ctx.organization_id, | ||
client_ctx.user_id, | ||
client_ctx.device_id, | ||
client_ctx.device_verify_key, | ||
req.setup, | ||
): | ||
case None: | ||
return authenticated_cmds.latest.shamir_recovery_setup.RepOk() | ||
case authenticated_cmds.latest.shamir_recovery_setup.Rep() as error: | ||
return error | ||
|
||
# async def test_dump_current_shamir( | ||
# self, organization_id: OrganizationID | ||
# ) -> dict[UserID, ShamirDump]: | ||
# raise NotImplementedError | ||
|
||
async def remove_recovery_setup( | ||
self, | ||
organization_id: OrganizationID, | ||
author: UserID, | ||
) -> None: | ||
raise NotImplementedError | ||
|
||
async def add_recovery_setup( | ||
self, | ||
organization_id: OrganizationID, | ||
author: UserID, | ||
device: DeviceID, | ||
author_verify_key: VerifyKey, | ||
setup: authenticated_cmds.latest.shamir_recovery_setup.ShamirRecoverySetup, | ||
) -> None | authenticated_cmds.latest.shamir_recovery_setup.Rep: | ||
raise NotImplementedError | ||
|
||
|
||
def verify_certificates( | ||
setup: authenticated_cmds.latest.shamir_recovery_setup.ShamirRecoverySetup, | ||
author: DeviceID, | ||
author_verify_key: VerifyKey, | ||
) -> ( | ||
tuple[ShamirRecoveryBriefCertificate, dict[UserID, bytes]] | ||
| authenticated_cmds.latest.shamir_recovery_setup.RepInvalidData | ||
): | ||
share_certificates: dict[UserID, bytes] = {} | ||
try: | ||
brief_certificate = ShamirRecoveryBriefCertificate.verify_and_load( | ||
setup.brief, author_verify_key, expected_author=author | ||
) | ||
except ValueError: | ||
return authenticated_cmds.latest.shamir_recovery_setup.RepInvalidData() | ||
|
||
for raw_share in setup.shares: | ||
try: | ||
share_certificate = ShamirRecoveryShareCertificate.verify_and_load( | ||
raw_share, author_verify_key, expected_author=author, expected_recipient=None | ||
) | ||
except ValueError: | ||
return authenticated_cmds.latest.shamir_recovery_setup.RepInvalidData() | ||
|
||
# share recipient not in brief | ||
if share_certificate.recipient not in brief_certificate.per_recipient_shares: | ||
return authenticated_cmds.latest.shamir_recovery_setup.RepInvalidData() | ||
# this recipient already has a share | ||
if share_certificate.recipient in share_certificates: | ||
return authenticated_cmds.latest.shamir_recovery_setup.RepInvalidData() | ||
# user included themselves as a share recipient | ||
if share_certificate.recipient == author.user_id: | ||
return authenticated_cmds.latest.shamir_recovery_setup.RepInvalidData() | ||
share_certificates[share_certificate.recipient] = raw_share | ||
delta = set(brief_certificate.per_recipient_shares) - set(share_certificates) | ||
# some recipient specified in brief has no share | ||
if delta: | ||
return authenticated_cmds.latest.shamir_recovery_setup.RepInvalidData() | ||
return brief_certificate, share_certificates |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
server/tests/api_v4/authenticated/test_shamir_recovery_setup.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS | ||
|
||
from parsec._parsec import ( | ||
DateTime, | ||
ShamirRecoveryBriefCertificate, | ||
ShamirRecoveryShareCertificate, | ||
authenticated_cmds, | ||
) | ||
from tests.common import Backend, CoolorgRpcClients, TestbedBackend | ||
|
||
|
||
async def test_authenticated_shamir_recovery_setup_ok( | ||
coolorg: CoolorgRpcClients, | ||
backend: Backend, | ||
testbed: TestbedBackend, | ||
) -> None: | ||
share = ShamirRecoveryShareCertificate( | ||
coolorg.alice.device_id, DateTime.now(), coolorg.mallory.user_id, b"abc" | ||
) | ||
brief = ShamirRecoveryBriefCertificate( | ||
author=coolorg.alice.device_id, | ||
timestamp=DateTime.now(), | ||
threshold=1, | ||
per_recipient_shares={coolorg.mallory.user_id: 2}, | ||
) | ||
|
||
setup = authenticated_cmds.v4.shamir_recovery_setup.ShamirRecoverySetup( | ||
b"abc", | ||
b"def", | ||
brief.dump_and_sign(coolorg.alice.signing_key), | ||
[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() | ||
|
||
# TODO dump | ||
|
||
|
||
async def test_authenticated_shamir_recovery_setup_already_set( | ||
coolorg: CoolorgRpcClients, | ||
backend: Backend, | ||
testbed: TestbedBackend, | ||
) -> None: | ||
pass | ||
|
||
|
||
async def test_authenticated_shamir_recovery_setup_invalid_certification( | ||
coolorg: CoolorgRpcClients, | ||
backend: Backend, | ||
testbed: TestbedBackend, | ||
) -> None: | ||
pass | ||
|
||
|
||
async def test_authenticated_shamir_recovery_setup_invalid_data( | ||
coolorg: CoolorgRpcClients, | ||
backend: Backend, | ||
testbed: TestbedBackend, | ||
) -> None: | ||
setup = authenticated_cmds.v4.shamir_recovery_setup.ShamirRecoverySetup( | ||
bytes("abc", "utf-8"), bytes("def", "utf-8"), bytes("ijk", "utf-8"), [bytes("lmn", "utf-8")] | ||
) | ||
rep = await coolorg.alice.shamir_recovery_setup(setup) | ||
assert rep == authenticated_cmds.v4.shamir_recovery_setup.RepInvalidData() |