Skip to content

Commit c987f2f

Browse files
committed
Add advisory_device_file_protection support to server_config API command on server
1 parent c7c5dea commit c987f2f

4 files changed

Lines changed: 61 additions & 3 deletions

File tree

server/parsec/cli/run.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@
99

1010
import click
1111

12-
from parsec._parsec import ActiveUsersLimit, EmailAddress, ParsecAddr, SecretKey, TrustAnchor
12+
from parsec._parsec import (
13+
ActiveUsersLimit,
14+
AdvisoryDeviceFileProtection,
15+
EmailAddress,
16+
ParsecAddr,
17+
SecretKey,
18+
TrustAnchor,
19+
)
1320
from parsec._version import __version__ as server_version
1421
from parsec.asgi import app_factory, serve_parsec_asgi_app
1522
from parsec.backend import backend_factory
@@ -193,6 +200,24 @@ def handle_parse_result(
193200
type=click.Choice(AccountConfig),
194201
default=AccountConfig.DISABLED,
195202
)
203+
@click.option(
204+
"--advisory-device-file-protection",
205+
"advisory_device_file_protection",
206+
envvar="PARSEC_ADVISORY_DEVICE_FILE_PROTECTION",
207+
show_envvar=True,
208+
multiple=True,
209+
type=AdvisoryDeviceFileProtection.from_str,
210+
metavar="STRATEGY",
211+
help="""Advisory device file protection to recommend to clients.
212+
213+
Can be specified multiple times to recommend multiple strategies.
214+
215+
Allowed values: PASSWORD, PASSWORD+TOTP, KEYRING, KEYRING+TOTP, PKI,
216+
PKI+TOTP, OPENBAO, OPENBAO+TOTP, ACCOUNT_VAULT, ACCOUNT_VAULT+TOTP.
217+
218+
When not specified, no recommendation is made (all strategies accepted).
219+
""",
220+
)
196221
@click.option(
197222
"--cryptpad-server-url",
198223
envvar="PARSEC_CRYPTPAD_SERVER_URL",
@@ -554,6 +579,7 @@ async def run_cmd(
554579
blockstore: BaseBlockStoreConfig,
555580
administration_token: str,
556581
account_config: AccountConfig,
582+
advisory_device_file_protection: tuple[AdvisoryDeviceFileProtection, ...],
557583
cryptpad_server_url: str | None,
558584
openbao_server_url: str | None,
559585
openbao_secret_mount_path: str,
@@ -674,6 +700,7 @@ async def run_cmd(
674700
server_addr=server_addr,
675701
debug=debug,
676702
account_config=account_config,
703+
advisory_device_file_protection=advisory_device_file_protection,
677704
cryptpad_config=cryptpad_config,
678705
openbao_config=openbao_config,
679706
organization_bootstrap_webhook_url=organization_bootstrap_webhook,

server/parsec/components/events.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,4 +547,7 @@ async def api_server_config(
547547
organization_bootstrap=organization_bootstrap,
548548
cryptpad=cryptpad,
549549
openbao=openbao,
550+
advisory_device_file_protection=[
551+
p.str for p in self._config.advisory_device_file_protection
552+
],
550553
)

server/parsec/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
from parsec._parsec import (
1313
ActiveUsersLimit,
14+
AdvisoryDeviceFileProtection,
1415
DateTime,
1516
EmailAddress,
1617
OpenBaoAuthType,
@@ -306,6 +307,8 @@ class BackendConfig:
306307

307308
openbao_config: OpenBaoConfig | None = None
308309

310+
advisory_device_file_protection: tuple[AdvisoryDeviceFileProtection, ...] = ()
311+
309312
organization_bootstrap_webhook_url: str | None = None
310313
organization_spontaneous_bootstrap: bool = False
311314
organization_initial_active_users_limit: ActiveUsersLimit = field(

server/tests/api_v5/anonymous_server/test_server_config.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22

33
import pytest
44

5-
from parsec._parsec import OpenBaoAuthType, anonymous_server_cmds
5+
from parsec._parsec import (
6+
AdvisoryDeviceFilePrimaryProtection,
7+
AdvisoryDeviceFileProtection,
8+
OpenBaoAuthType,
9+
anonymous_server_cmds,
10+
)
611
from parsec.config import AccountConfig, CryptPadConfig, OpenBaoAuthConfig, OpenBaoConfig
712
from tests.common import AnonymousServerRpcClient, Backend, HttpCommonErrorsTester
813

914

10-
@pytest.mark.parametrize("kind", ("default", "custom"))
15+
@pytest.mark.parametrize("kind", ("default", "custom", "with_advisory_device_file_protection"))
1116
async def test_anonymous_server_server_config_ok(
1217
backend: Backend,
1318
anonymous_server: AnonymousServerRpcClient,
@@ -20,6 +25,7 @@ async def test_anonymous_server_server_config_ok(
2025
organization_bootstrap=anonymous_server_cmds.latest.server_config.OrganizationBootstrapConfig.WITH_BOOTSTRAP_TOKEN,
2126
cryptpad=anonymous_server_cmds.latest.server_config.CryptPadConfigDisabled(),
2227
openbao=anonymous_server_cmds.latest.server_config.OpenBaoConfigDisabled(),
28+
advisory_device_file_protection=[],
2329
)
2430

2531
case "custom":
@@ -66,6 +72,25 @@ async def test_anonymous_server_server_config_ok(
6672
),
6773
],
6874
),
75+
advisory_device_file_protection=[],
76+
)
77+
78+
case "with_advisory_device_file_protection":
79+
backend.config.advisory_device_file_protection = (
80+
AdvisoryDeviceFileProtection(
81+
primary=AdvisoryDeviceFilePrimaryProtection.PASSWORD, with_totp=True
82+
),
83+
AdvisoryDeviceFileProtection(
84+
primary=AdvisoryDeviceFilePrimaryProtection.PKI, with_totp=False
85+
),
86+
)
87+
88+
expected_rep = anonymous_server_cmds.latest.server_config.RepOk(
89+
account=anonymous_server_cmds.latest.server_config.AccountConfig.DISABLED,
90+
organization_bootstrap=anonymous_server_cmds.latest.server_config.OrganizationBootstrapConfig.WITH_BOOTSTRAP_TOKEN,
91+
cryptpad=anonymous_server_cmds.latest.server_config.CryptPadConfigDisabled(),
92+
openbao=anonymous_server_cmds.latest.server_config.OpenBaoConfigDisabled(),
93+
advisory_device_file_protection=["PASSWORD+TOTP", "PKI"],
6994
)
7095

7196
case unknown:

0 commit comments

Comments
 (0)