From 90c3c6a01f46c9b29c5d92702d7383f32e8951d7 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Wed, 19 Aug 2026 16:36:29 +0200 Subject: feat(ui): 11-point UI overhaul — tabs, transfers, settings, uploads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hub/UI: - Icon-only group tabs (chat, files, settings) with per-group default tab - Transfer widget: filename becomes a clickable link to open completed downloads - Pulse animation on transfer icon (pale→dark green) while active - Download button feedback in FilePreview (spinner, auto-reset) - Group mute toggle persists across navigation - Login page autofocus, chat refocus after send - Theme toggle closes menu, status badge and duplicate connecting removed - Create-folder restricted to operators, download-path note removed - User preferences API (CRUD) with Alembic migration - Profile: email display/edit via PATCH /v1/users/me - Settings: "Defaults" section for default tab selector - All 10 locale files updated Node: - upload_dir in node.toml: separate filesystem path for uploads - Root.direct flag: uploads land at root path, no subdirectory - CLI --upload-dir flag on `group add` - Admin UI accepts upload_dir Client (Electron): - shell.openPath bridge for opening completed downloads - platform.js passes open callback from native save Co-Authored-By: Claude Opus 4.6 --- .../src/meshbay_node/transport/webrtc_server.py | 29 +++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'packages/meshbay-node/src/meshbay_node/transport') diff --git a/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py b/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py index 22e5e15..f182ab2 100644 --- a/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py +++ b/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py @@ -2087,21 +2087,20 @@ class WebRTCPeerSession: "filename": filename}) return - # One destination, chosen by the operator and not by the client: - # uploads/ inside the group's designated root. C5a is still honoured — - # the name passed the allowlist above, and an existing file is never - # replaced, which was the real defect (overwriting a file also made the - # attacker its recorded uploader, and therefore able to delete it). - rel_dir = f"{upload_root.name}/{UPLOAD_DIR_NAME}" - target_dir = upload_root.path / UPLOAD_DIR_NAME - try: - target_dir.mkdir(parents=True, exist_ok=True) - except OSError as e: - log.warning("Cannot create upload folder in root %r: %s", - upload_root.name, e) - self._send({"type": "error", "detail": "Upload folder unavailable", - "filename": filename}) - return + if upload_root.direct: + rel_dir = upload_root.name + target_dir = upload_root.path + else: + rel_dir = f"{upload_root.name}/{UPLOAD_DIR_NAME}" + target_dir = upload_root.path / UPLOAD_DIR_NAME + try: + target_dir.mkdir(parents=True, exist_ok=True) + except OSError as e: + log.warning("Cannot create upload folder in root %r: %s", + upload_root.name, e) + self._send({"type": "error", "detail": "Upload folder unavailable", + "filename": filename}) + return upload_key = f"{rel_dir}/{filename}" state = self._uploads.get(upload_key) -- cgit v1.2.3