diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-14 22:20:15 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-14 22:20:15 +0200 |
| commit | 422647e7898b8df67cd11f8fb060aec23dec84aa (patch) | |
| tree | 7ecca0e8df1bc8a7d26cf4b471bd44906dd9cfd1 /packages/meshbay-cli/src/meshbay_cli/selftest.py | |
| parent | 28c88908b88c58cba4de08710f6bb268ede02d57 (diff) | |
| download | meshbay-422647e7898b8df67cd11f8fb060aec23dec84aa.tar.gz | |
feat(cli): meshbay-cli, a command-line client for members
Signs in to the hub, lists the account's groups and their folders, and
downloads and uploads files directly with each group's node, end-to-end
encrypted. With no argument it opens a two-pane interactive mode (Textual).
Session and device keys are kept encrypted under the system's key storage,
or a 0600 key file where there is none; node keys are pinned at first
contact; a new machine links as a device.
Packaged on its own on Linux (deb and rpm, on meshbay-common's venv, with a
man page generated from the parser) and frozen next to meshbay-node in the
full Windows installer, not the light one, with a self-test the build runs.
client/keys.py ports keyderive.js and is LGPL like it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-cli/src/meshbay_cli/selftest.py')
| -rw-r--r-- | packages/meshbay-cli/src/meshbay_cli/selftest.py | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/packages/meshbay-cli/src/meshbay_cli/selftest.py b/packages/meshbay-cli/src/meshbay_cli/selftest.py new file mode 100644 index 0000000..81453c4 --- /dev/null +++ b/packages/meshbay-cli/src/meshbay_cli/selftest.py @@ -0,0 +1,61 @@ +""" +What a frozen build must be able to load, checked with no hub and no node. + +A PyInstaller build carries only the modules its analysis found, and a module +it missed fails at run time only — in the interactive mode, or the first time +the store asks for the system's key storage. The Windows build runs this +(`MESHBAY_CLI_SELFTEST=1 meshbay-cli`, see packaging/win/build-node-runtime.ps1) +on the frozen executable; nothing here is reachable through the command line. +""" + +import asyncio +import os +import sys +import tempfile + + +async def _interactive() -> None: + """The sign-in screen, drawn off-screen: Textual's widgets, CSS and Rich.""" + from .__main__ import build_parser + from .commands.context import Context + from .tui.app import MeshBayApp + from .tui.screens import SignInScreen + + app = MeshBayApp(Context(build_parser().parse_args(["--hub", "http://127.0.0.1:1"]))) + async with app.run_test(size=(100, 30)) as pilot: + for _ in range(100): + if isinstance(app.screen, SignInScreen): + break + await pilot.pause(0.05) + else: + raise RuntimeError("the sign-in screen never showed") + app.screen.query_one("#user") + + +async def _webrtc() -> None: + from aiortc import RTCPeerConnection + pc = RTCPeerConnection() + pc.createDataChannel("selftest") + await pc.setLocalDescription(await pc.createOffer()) + await pc.close() + + +def run() -> int: + with tempfile.TemporaryDirectory() as home: + os.environ["MESHBAY_CLI_HOME"] = home # nothing stored: the sign-in screen + # keyring finds its backends through its own entry points: without its + # metadata in the build, Windows Credential Manager is simply not + # there and the store falls back to a key file on every machine. + import keyring.backend + backends = [type(b).__module__ for b in keyring.backend.get_all_keyring()] + if sys.platform == "win32" and "keyring.backends.Windows" not in backends: + raise RuntimeError(f"no Windows Credential Manager backend in {backends}") + + from argon2.low_level import Type, hash_secret_raw + hash_secret_raw(b"x", b"saltsalt", 1, 8, 1, 16, Type.ID) + + from .__main__ import loop_factory + asyncio.run(_webrtc(), loop_factory=loop_factory()) + asyncio.run(_interactive(), loop_factory=loop_factory()) + print(f"self-test ok (keyring: {', '.join(backends)})") + return 0 |