Example #1
0
def test_backend_addr_bad_value(url, exc_msg):
    with pytest.raises(ValueError) as exc:
        BackendAddr.from_url(url)
    if isinstance(exc_msg, str):
        assert str(exc.value) == exc_msg
    else:
        assert str(exc.value) in exc_msg
Example #2
0
 def validate(self, string, pos):
     try:
         if len(string) == 0:
             return QValidator.Intermediate, string, pos
         BackendAddr.from_url(string)
         return QValidator.Acceptable, string, pos
     except ValueError:
         return QValidator.Invalid, string, pos
Example #3
0
def core_config(tmpdir, backend_addr, unused_tcp_port, fixtures_customization):
    if fixtures_customization.get("fake_preferred_org_creation_backend_addr", False):
        backend_addr = BackendAddr.from_url(f"parsec://127.0.0.1:{unused_tcp_port}")

    tmpdir = Path(tmpdir)
    return CoreConfig(
        config_dir=tmpdir / "config",
        data_base_dir=tmpdir / "data",
        mountpoint_base_dir=tmpdir / "mnt",
        preferred_org_creation_backend_addr=backend_addr,
        gui_language=fixtures_customization.get("gui_language"),
    )
Example #4
0
def test_backend_organization_addr_good(base_url, expected, verify_key):
    org = OrganizationID("org")
    backend_addr = BackendAddr.from_url(base_url)
    addr = BackendOrganizationAddr.build(backend_addr,
                                         organization_id=org,
                                         root_verify_key=verify_key)
    assert addr.hostname == "foo"
    assert addr.port == expected["port"]
    assert addr.use_ssl == expected["ssl"]
    assert addr.organization_id == org
    assert addr.root_verify_key == verify_key

    addr2 = BackendOrganizationAddr.from_url(addr.to_url())
    assert addr == addr2
def test_build_addrs():
    backend_addr = BackendAddr.from_url(BackendAddrTestbed.url)
    assert backend_addr.hostname == "parsec.cloud.com"
    assert backend_addr.port == 443
    assert backend_addr.use_ssl is True

    organization_id = OrganizationID("MyOrg")
    root_verify_key = SigningKey.generate().verify_key

    organization_addr = BackendOrganizationAddr.build(
        backend_addr=backend_addr, organization_id=organization_id, root_verify_key=root_verify_key
    )
    assert organization_addr.organization_id == organization_id
    assert organization_addr.root_verify_key == root_verify_key

    organization_bootstrap_addr = BackendOrganizationBootstrapAddr.build(
        backend_addr=backend_addr,
        organization_id=organization_id,
        token="a0000000000000000000000000000001",
    )
    assert organization_bootstrap_addr.token == "a0000000000000000000000000000001"
    assert organization_bootstrap_addr.organization_id == organization_id

    organization_bootstrap_addr2 = BackendOrganizationBootstrapAddr.build(
        backend_addr=backend_addr, organization_id=organization_id, token=None
    )
    assert organization_bootstrap_addr2.organization_id == organization_id
    assert organization_bootstrap_addr2.token == ""

    organization_file_link_addr = BackendOrganizationFileLinkAddr.build(
        organization_addr=organization_addr,
        workspace_id=EntryID.from_hex("2d4ded12-7406-4608-833b-7f57f01156e2"),
        encrypted_path=b"<encrypted_payload>",
    )
    assert organization_file_link_addr.workspace_id == EntryID.from_hex(
        "2d4ded12-7406-4608-833b-7f57f01156e2"
    )
    assert organization_file_link_addr.encrypted_path == b"<encrypted_payload>"

    invitation_addr = BackendInvitationAddr.build(
        backend_addr=backend_addr,
        organization_id=organization_id,
        invitation_type=InvitationType.USER,
        token=InvitationToken.from_hex("a0000000000000000000000000000001"),
    )
    assert invitation_addr.organization_id == organization_id
    assert invitation_addr.token == InvitationToken.from_hex("a0000000000000000000000000000001")
    assert invitation_addr.invitation_type == InvitationType.USER
Example #6
0
async def restart_local_backend(administration_token, backend_port, email_host,
                                db, blockstore):
    pattern = f"parsec.* backend.* run.* -P {backend_port}"
    command = (
        f"{sys.executable} -Wignore -m parsec.cli backend run --log-level=WARNING "
        f"-b {blockstore} --db {db} "
        f"--email-host={email_host} -P {backend_port} "
        f"--spontaneous-organization-bootstrap "
        f"--administration-token {administration_token} --backend-addr parsec://localhost:{backend_port}?no_ssl=true"
    )

    # Trio does not support subprocess in windows yet

    def _windows_target():
        for proc in psutil.process_iter():
            if "python" in proc.name():
                arguments = " ".join(proc.cmdline())
                if re.search(pattern, arguments):
                    proc.kill()
        backend_process = subprocess.Popen(command.split(),
                                           stdout=subprocess.PIPE)
        for data in backend_process.stdout:
            print(data.decode(), end="")
            break
        backend_process.stdout.close()

    # Windows restart
    if sys.platform == "win32":
        await trio.to_thread.run_sync(_windows_target)

    # Linux restart
    else:

        await trio.run_process(["pkill", "-f", pattern], check=False)
        backend_process = await trio.open_process(command.split(),
                                                  stdout=subprocess.PIPE)
        async with backend_process.stdout:
            async for data in backend_process.stdout:
                print(data.decode(), end="")
                break

    # Make sure the backend is actually started
    await trio.sleep(0.2)
    url = f"parsec://localhost:{backend_port}?no_ssl=true"
    return BackendAddr.from_url(url)
Example #7
0
def test_backend_organization_bootstrap_addr_good(base_url, expected, verify_key):
    org = OrganizationID("org")
    backend_addr = BackendAddr.from_url(base_url)
    addr = BackendOrganizationBootstrapAddr.build(backend_addr, org, "token-123")
    assert addr.hostname == "foo"
    assert addr.port == expected["port"]
    assert addr.use_ssl == expected["ssl"]
    assert addr.organization_id == org
    assert addr.token == "token-123"

    addr2 = BackendOrganizationBootstrapAddr.from_url(str(addr))
    assert addr == addr2

    org_addr = addr.generate_organization_addr(verify_key)
    assert isinstance(org_addr, BackendOrganizationAddr)
    assert org_addr.root_verify_key == verify_key
    assert org_addr.hostname == addr.hostname
    assert org_addr.port == addr.port
    assert org_addr.use_ssl == addr.use_ssl
    assert org_addr.organization_id == addr.organization_id
Example #8
0
async def restart_local_backend(administration_token, backend_port):
    pattern = f"parsec.* backend.* run.* -P {backend_port}"
    command = (
        f"python -Wignore -m parsec.cli backend run -b MOCKED --db MOCKED "
        f"-P {backend_port} --administration-token {administration_token}")

    # Trio does not support subprocess in windows yet

    def _windows_target():
        for proc in psutil.process_iter():
            if "python" in proc.name():
                arguments = " ".join(proc.cmdline())
                if re.search(pattern, arguments):
                    proc.kill()
        backend_process = subprocess.Popen(command.split(),
                                           stdout=subprocess.PIPE)
        for data in backend_process.stdout:
            print(data.decode(), end="")
            break
        backend_process.stdout.close()

    # Windows restart
    if os.name == "nt" or True:
        await trio.to_thread.run_sync(_windows_target)

    # Linux restart
    else:

        await trio.run_process(["pkill", "-f", pattern], check=False)
        backend_process = await trio.open_process(command.split(),
                                                  stdout=subprocess.PIPE)
        async with backend_process.stdout:
            async for data in backend_process.stdout:
                print(data.decode(), end="")
                break

    # Make sure the backend is actually started
    await trio.sleep(0.2)
    url = f"parsec://localhost:{backend_port}?no_ssl=true"
    return BackendAddr.from_url(url)
 def backend_addr(self):
     return (BackendAddr.from_url(self.line_edit_backend_addr.text())
             if self.check_use_custom_backend.isChecked() else None)
Example #10
0
def config_factory(
    config_dir: Path = None,
    data_base_dir: Path = None,
    cache_base_dir: Path = None,
    mountpoint_base_dir: Path = None,
    prevent_sync_pattern_path: Optional[Path] = None,
    mountpoint_enabled: bool = False,
    disabled_workspaces: FrozenSet[EntryID] = frozenset(),
    backend_max_cooldown: int = 30,
    backend_connection_keepalive: Optional[int] = 29,
    backend_max_connections: int = 4,
    telemetry_enabled: bool = True,
    debug: bool = False,
    gui_last_device: str = None,
    gui_tray_enabled: bool = True,
    gui_language: str = None,
    gui_first_launch: bool = True,
    gui_last_version: str = None,
    gui_check_version_at_startup: bool = True,
    gui_check_version_allow_pre_release: bool = False,
    gui_workspace_color: bool = False,
    gui_allow_multiple_instances: bool = False,
    preferred_org_creation_backend_addr: Optional[BackendAddr] = None,
    gui_show_confined: bool = False,
    gui_geometry: bytes = None,
    environ: dict = {},
    **_,
) -> CoreConfig:

    # The environment variable we always be used first, and if it is not present,
    # we'll use the value from the configuration file.
    backend_addr_env = environ.get("PREFERRED_ORG_CREATION_BACKEND_ADDR")
    if backend_addr_env:
        preferred_org_creation_backend_addr = BackendAddr.from_url(
            backend_addr_env)
    if not preferred_org_creation_backend_addr:
        preferred_org_creation_backend_addr = BackendAddr.from_url(
            "parsec://localhost:6777?no_ssl=true")

    data_base_dir = data_base_dir or get_default_data_base_dir(environ)
    core_config = CoreConfig(
        config_dir=config_dir or get_default_config_dir(environ),
        data_base_dir=data_base_dir,
        cache_base_dir=cache_base_dir or get_default_cache_base_dir(environ),
        mountpoint_base_dir=get_default_mountpoint_base_dir(environ),
        prevent_sync_pattern_path=prevent_sync_pattern_path,
        mountpoint_enabled=mountpoint_enabled,
        disabled_workspaces=disabled_workspaces,
        backend_max_cooldown=backend_max_cooldown,
        backend_connection_keepalive=backend_connection_keepalive,
        backend_max_connections=backend_max_connections,
        telemetry_enabled=telemetry_enabled,
        debug=debug,
        sentry_url=environ.get("SENTRY_URL") or None,
        gui_last_device=gui_last_device,
        gui_tray_enabled=gui_tray_enabled,
        gui_language=gui_language,
        gui_first_launch=gui_first_launch,
        gui_last_version=gui_last_version,
        gui_check_version_at_startup=gui_check_version_at_startup,
        gui_check_version_allow_pre_release=gui_check_version_allow_pre_release,
        gui_workspace_color=gui_workspace_color,
        gui_allow_multiple_instances=gui_allow_multiple_instances,
        preferred_org_creation_backend_addr=preferred_org_creation_backend_addr,
        gui_show_confined=gui_show_confined,
        gui_geometry=gui_geometry,
        ipc_socket_file=data_base_dir / "parsec-cloud.lock",
        ipc_win32_mutex_name="parsec-cloud",
    )

    # Make sure the directories exist on the system
    core_config.config_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
    core_config.data_base_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
    core_config.cache_base_dir.mkdir(mode=0o700, parents=True, exist_ok=True)

    # Mountpoint base directory is not used on windows
    if os.name != "nt":
        core_config.mountpoint_base_dir.mkdir(mode=0o700,
                                              parents=True,
                                              exist_ok=True)

    return core_config
Example #11
0
def load_config(config_dir: Path, **extra_config) -> CoreConfig:

    config_file = config_dir / "config.json"
    try:
        raw_conf = config_file.read_text()
        data_conf = json.loads(raw_conf)

    except OSError:
        # Config file not created yet, fallback to default
        data_conf = {}

    except (ValueError, json.JSONDecodeError) as exc:
        # Config file broken, fallback to default
        logger.warning(f"Ignoring invalid config in {config_file} ({exc})")
        data_conf = {}

    try:
        data_conf["data_base_dir"] = Path(data_conf["data_base_dir"])
    except (KeyError, ValueError):
        pass

    try:
        data_conf["cache_base_dir"] = Path(data_conf["cache_base_dir"])
    except (KeyError, ValueError):
        pass

    try:
        data_conf["prevent_sync_pattern_path"] = Path(
            data_conf["prevent_sync_pattern_path"])
    except (KeyError, ValueError):
        pass

    try:
        data_conf["disabled_workspaces"] = frozenset(
            map(EntryID, data_conf["disabled_workspaces"]))
    except (KeyError, ValueError):
        pass

    try:
        data_conf[
            "preferred_org_creation_backend_addr"] = BackendAddr.from_url(
                data_conf["preferred_org_creation_backend_addr"])
    except KeyError:
        pass
    except ValueError as exc:
        logger.warning(
            f"Invalid value for `preferred_org_creation_backend_addr` ({exc})")
        data_conf["preferred_org_creation_backend_addr"] = None

    try:
        data_conf["gui_geometry"] = base64.b64decode(
            data_conf["gui_geometry"].encode("ascii"))
    except (AttributeError, KeyError, UnicodeEncodeError, binascii.Error):
        data_conf["gui_geometry"] = None

    # Work around versionning issue with parsec releases:
    # - v1.12.0, v1.11.4, v1.11.3, v1.11.2, v1.11.1, v1.11.0 and v1.10.0
    # A `v` has been incorrectly added to `parsec.__version__`, potentially
    # affecting the `gui_last_version` entry in the configuration file.
    if data_conf.get("gui_last_version"):
        data_conf["gui_last_version"] = data_conf["gui_last_version"].lstrip(
            "v")

    return config_factory(config_dir=config_dir,
                          **data_conf,
                          **extra_config,
                          environ=os.environ)
Example #12
0
def test_backend_addr_good(url, expected):
    addr = BackendAddr.from_url(url)
    assert addr.hostname == "foo"
    assert addr.port == expected["port"]
    assert addr.use_ssl == expected["ssl"]
Example #13
0
def test_backend_addr_bad_value(url, exc_msg):
    with pytest.raises(ValueError) as exc:
        BackendAddr.from_url(url)
    assert str(exc.value) == exc_msg
Example #14
0
 def backend_addr(self):
     return (BackendAddr.from_url(self.line_edit_backend_addr.text(),
                                  allow_http_redirection=True)
             if self.radio_use_custom.isChecked() else None)