Bump golang.org/x/crypto to v0.52.0 and x/sys to v0.45.0 in betterdesk-server, x/sys to v0.45.0 in betterdesk-agent, and aiohttp to >=3.10.11 in the rest-webhook bridge. Validated clean via govulncheck.
Add an explicit Go server rebuild path to the in-app updater so security/library updates actually reach the running binary: updateService now marks the server binary stale when the source changed but a non-critical rebuild/deploy step failed, exposes getServerBinaryStatus() and rebuildServerBinary(), and surfaces a warning banner plus a Rebuild button in the settings update panel. New REST endpoints GET/POST /api/settings/updates/server-binary/{status,rebuild} guarded by server.config permission. i18n keys added across all locales.
This commit was made possible thanks to Insolve.
Add a device verification/enrollment workflow so new registrations are
held for operator review instead of connecting silently.
Go server (signal + api):
- Signal-mode pending: in 'managed' mode, unknown stock RustDesk clients
are queued (pending_device_<id>) instead of being silently rejected.
- Rich approve: handleApproveDevice accepts display_name, sync_mode and
normalized tags; handleRejectDevice supports an optional ban.
Node.js console:
- registrations.ejs approve modal (name, sync mode, tags, folder) and
reject modal with ban option; betterdeskApi + routes wire display_name,
sync_mode, tags and folder assignment through to the Go server.
- EN/PL/ZH i18n for all new strings.
Installers (managed default for FRESH installs only; existing installs
stay on the Go default 'open' or their DB-persisted mode):
- betterdesk.sh / betterdesk.ps1 write ENROLLMENT_MODE=managed to the
server env only when no existing database is detected (FRESH_INSTALL).
- Docker single + multi container entrypoints detect fresh volumes via a
sentinel plus id_ed25519/db_v2.sqlite3 presence and default to managed;
ENROLLMENT_MODE is now passed through supervisord and all compose files.
This commit was made possible thanks to Insolve.
Privilege separation across all installers so the long-running services no longer run with full administrative rights:
betterdesk.sh: installer keeps root but systemd units now run as a dedicated unprivileged 'betterdesk' system account by default (auto-created via ensure_service_user). Added full systemd hardening for the Go server (NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp, ReadWritePaths) and light hardening for the Node.js console. chown migrates existing root-owned data to the service account on update. Opt-out via --run-as-root / BETTERDESK_RUN_AS_ROOT=1; custom account via BETTERDESK_SERVICE_USER. Minimal mode covered too.
betterdesk.ps1: NSSM services now run under their per-service low-privilege virtual accounts (NT SERVICE\<service>) instead of LocalSystem, with scoped icacls grants on the install/data dirs (Set-ServiceLeastPrivilege helper). Applied to the Go server, Node.js console and minimal-mode service. Opt-out via -RunAsRoot / BETTERDESK_RUN_AS_ROOT=1.
Docker: verified already privilege-separated (supervisord drops both programs to user=betterdesk; multi-container images drop via su-exec).
Also bundles in-progress changes to the Go server API, Node.js console services and Docker compose/Dockerfiles.
This commit was made possible thanks to Insolve.
Go server:
- mergeAdminTagsIntoAB: strip banned/deleted peers from AB data
- handleClientGroupList: exclude banned peers from tag groups
- handleClientPeersList: add device_name fallback to peer ID, add online field
- handleGetPeer/handleListPeers: return status as int (1/0) with status_text
- handleUsersWithClientFallback: only return users with assigned devices
Node.js console:
- mergeAddressBookData: filter banned devices from AB merge
- buildSyncedAddressBook: set includeDevices=false to prevent ghost AB entries
- normalisePeer: use status_text fallback for status_tier
This commit was made possible thanks to Insolve.
The SSO commit (188991d) changed authenticate() to delegate auth to the Go server first, falling back to local-only for admin roles in 'emergency mode'. This broke login for all users whose accounts exist only in auth.db (Node.js) but not in Go server's database — which is the default for ALL-IN-ONE installs. Go server returned 401 for unknown users, and the new code treated that as a hard rejection with no local fallback. Restored the original local-first flow: check auth.db first, verify password locally, use Go server only as a fallback when local password fails (LDAP/password change sync) or when user doesn't exist locally (opt-in auto-create).
This commit was made possible thanks to Insolve.
auth.routes.js: strip trailing /api segment from BETTERDESK_API_URL when building the absolute OIDC authorize redirect, otherwise the env value (which intentionally ends with /api for axios baseURL) caused doubled /api/api/auth/oidc/authorize URLs.
betterdeskApi.js: testLDAPConnection and testOIDCDiscovery now extract e.response.data.error from axios failures, so the Settings -> SSO test buttons show real Go-side messages (e.g. 'LDAP host is required', DNS errors) instead of the generic 'Request failed with status code 400'.
This commit was made possible thanks to Insolve.
updateService.js: distinguish critical vs non-critical failures in SHA tracking. Server binary compile/download failures are non-critical — SHA is saved so the same update is not shown again on restart. update-cli.js: match same logic, non-critical failures don't set exit code 1. betterdesk.sh: new update_from_github() with git clone + tarball fallback, 3-method menu. betterdesk.ps1: new Update-FromGitHub with git clone + ZIP fallback, 3-method menu. betterdesk-docker.sh: new update_docker_from_github() with 2-method menu.
This commit was made possible thanks to Insolve.
UI: group chip buttons changed to icon-only (matching folder chips), Create Group tile styling unified with Create Folder, old .group-chip-action CSS replaced with unified .chip-action class.
Go server: peerResponse and singlePeerResponse now return status as int (1=active, 0=disabled) instead of string, added status_text for admin panel backward compat. Fixes RustDesk client crash 'type String is not a subtype of type int?'.
Go server: new handleUsersWithClientFallback — detects RustDesk client requests to /api/users and returns current user without requiring user.view permission. Fixes disappearing folders/groups caused by _getUsers() 403 short-circuiting _pull().
Node.js: normalisePeer updated to use status_text fallback for status_tier.
Branding: RustDesk Server Management -> BetterDesk Server Management across themes, i18n, settings. Console version bumped to 3.0.0.
This commit was made possible thanks to Insolve.
- Add menu option T (Toggle HTTP/HTTPS) to betterdesk.sh and betterdesk.ps1
- Add --protocol http|https CLI flag (bash) and -Protocol param (PS1)
- Toggle updates .env, systemd/NSSM services, and Go server TLS flags
- Auto-generate self-signed cert when switching to HTTPS if none exists
- Go API (:21114) always stays HTTP (internal Node.js<->Go communication)
- Fix betterdeskApi.js: conditional httpsAgent/httpAgent based on URL scheme
- Fix deviceStatusPush.js: TLS options only applied for wss:// connections
This commit was made possible thanks to Insolve.
- Updated Polish and Chinese language files to reflect changes in update descriptions and confirmations.
- Modified settings.js to automatically include server updates in the update process.
- Simplified the update installation API to automatically handle server updates without user intervention.
- Improved updateService.js to ensure all supported components are updated together, enhancing reliability.
- Added logic to check and install the Go toolchain as needed during updates, ensuring compatibility.
- Enhanced error handling and logging during the update process for better visibility of issues.
- Added user group membership functionality, allowing users to be assigned to groups.
- Introduced validation for group GUIDs and enhanced error handling in user routes.
- Updated device group routes to support allowed user groups, enabling better access control for devices.
- Enhanced database schema to include user group memberships and device group user group access.
- Updated services and database adapters to handle user group data and relationships.
- Modified front-end views to display and manage user groups effectively.
- Added tests to ensure proper functionality of user group assignments and device access control.
- Implemented server management service providing resource snapshots, file browser, service control, and audit logging.
- Added terminal proxy for WebSocket-backed PTY, allowing browser-based shell access with user authentication and role-based access control.
- Created server management view with tabs for overview, terminal, file management, and services, including UI elements for displaying system metrics and managing files/services.
Co-authored-by: Copilot <copilot@github.com>
Render language choices dynamically from loaded locale files instead of hardcoding EN/PL. Add selectors on the navbar, login screen, and desktop login screen so users can choose a language before or after authentication.
Persist the selected language in the browser via cookie/localStorage and on authenticated accounts via users.preferred_language. Merge client translations with the default locale fallback so incomplete language files do not surface raw keys in the UI.
Panel accounts were created only in the Node auth.db while the
Organization 'Add User -> Add Existing' dropdown queries the Go
server's users table via db.ListUsersNotInOrg(). This produced a
mismatch where only the seeded admin appeared as linkable.
Add a userSync service that mirrors create / update / delete /
password-reset operations from the Node panel to the Go server's
/api/users endpoints, plus a one-shot backfill at startup that
creates Go-side records for any pre-existing panel users (random
throwaway password; Node bcrypt remains authoritative for panel
login).
Reported-by: SterlynKong <SterlynKong@users.noreply.github.com>
Three independent bug fixes bundled together; none of the issues are
auto-closed by this commit so the reporters can confirm on a tagged build.
#121 — NAT hairpin: same-public-IP detection forces relay path
The signal handler now distinguishes 'same /24 private subnet' (genuine
LAN, keep direct path) from 'same public IP' (NAT hairpin scenario).
When both peers register from the same public IP, both the UDP and
TCP/WS punch-hole handlers skip the LAN-address exchange and steer the
client straight to the relay — matching upstream RustDesk behavior.
Most consumer routers and cellular gateways drop hairpinned UDP, which
was causing same-Wi-Fi connections to silently time out.
- new helper isSamePublicIP() in signal/handler.go
- new config flag SameNATRelay (default: enabled)
- env: SAME_NAT_RELAY=N to opt out
- cli: --same-nat-relay=false to opt out
Reported-by: @eternalliving (#121)
#122 — Rate limit configurable, 0 disables
The 20 registrations/min/IP cap was unworkable for any deployment with
real NAT/CGNAT in front of it. Made it tunable without recompiling and
hardened the limiter to short-circuit when disabled.
- new config field SignalRateLimitPerIP (default: 20, unchanged)
- env: SIGNAL_RATE_LIMIT_PER_IP=<n> (0 = unlimited)
- cli: --signal-rate-limit-per-ip=<n>
- ratelimit.IPLimiter.Allow() now returns true early when limit<=0
Reported-by: @Henry-739 (#122)
#123 — Updater corrupting live SQLite WAL files
A previous gitleaks-fix commit accidentally tracked live SQLite sidecar
files (auth.db-shm/wal, betterdesk.db-shm/wal, .session_secret,
.update_sha). The in-app updater's diff-against-GitHub logic then
'restored' those tracked-by-mistake files on user installs, which is
exactly how SQLite database corruption gets manufactured.
Layered defense:
- .gitignore now covers *.db-shm, *.db-wal, *.sqlite3-{shm,wal,journal},
web-nodejs/data/, .session_secret, .update_sha, .api_key,
.admin_credentials, .force_password_update, .env*
- removed the offending files from the index (data/.gitkeep retained)
- updateService.js EXCLUDE_PATTERNS extended to match the new gitignore
- new write-time guard isProtectedRuntimePath() wired into all four
write sites in updateService.js so even a stale GitHub diff cannot
overwrite a runtime state file on disk
Reported-by: @SterlynKong (#123)
- deployServerBinary: use rename(2) for atomic replace, fixes ETXTBSY
when target Go binary is busy (Linux kernel handles inode swap).
Falls back to copyFileSync on cross-device rename or non-Linux.
Windows: rename target out of the way first, then move new in.
- settings.js: mark 'server' phase as error when build succeeded but
deploy failed (was incorrectly marking 'done' from build alone).
- settings.js: completion modal now shows error title, error message
and pre-formatted stderr when serverDeploy.success === false.
- i18n: added complete_with_errors, modal_done_with_errors_title in
en/pl.
- updateService: enhanced checkGoAvailable() to scan well-known paths
(/usr/local/go, /snap, vendored data/go-toolchain, /usr/lib/go-1.x)
and return absolute binary path so spawned exec works without PATH.
- New installGoToolchain(): dynamically fetches go.dev/dl/?mode=json,
picks newest stable >= 1.23.0 for current OS/arch, downloads archive,
verifies SHA-256 from manifest, extracts to data/go-toolchain/.
- buildGoServer() now uses absolute go path, 600s timeout.
- New 'install-go' update strategy + auto-fallback in 'auto' mode:
when host has neither Go nor a prebuilt release, the toolchain is
installed automatically and compilation proceeds.
- New POST /api/settings/updates/install-go endpoint for explicit
install (audit-logged, server.config permission gated).
- Settings UI: third 'Auto-install Go and compile' radio. Update
checkbox is no longer disabled when Go is missing — auto-install
is always offered as a fallback.
- installUpdate() rewritten as Modal-based phased dialog:
Confirmation -> Backup -> Console -> Server -> Restart -> Done.
Live phase icons (pending/active/done/error/skipped), progress bar,
log pane, completion modal with reload CTA, auto-reload after
successful console restart.
- New i18n keys (EN+PL): strategy_install_go, auto_strategy,
toolchain_*, modal_*, phase_*, confirm_*, etc.
- New CSS (.update-progress-modal, .update-phase, .update-progress-log).
Expose an update strategy UI and support downloading pre-built server binaries as an alternative to compiling from source.
- Add new translation keys (en/pl/zh) for strategy labels, badges, download/build messages and install Go hint.
- Update settings UI: show strategy selection (download / compile), badges with availability/release/size, auto-select best strategy, and adjust status/info messages and progress text.
- settings.routes: make server-info handler async and include prebuilt info; accept serverStrategy in updates/install request and forward to updateService.
- updateService: add helpers getReleaseBinaryName, checkPrebuiltAvailable, downloadPrebuiltBinary and getPrebuiltInfo; extend getServerUpdateInfo to include expected binary/platform/arch. Implement server update flow to support compile or download strategies (auto fallback), download/prep binary, validate size, deploy binary, and record method/size in results.
This enables faster updates on platforms with prebuilt releases while preserving the compile-from-source path and providing clear UI feedback and fallbacks.
Add OS-level admin detection and use it to gate sensitive agent UI and tray actions. Introduce privileges.rs (Windows TokenElevation / Unix geteuid) and expose is_os_admin as a Tauri command; wire it into tray setup to hide admin-only menu items (Settings, Quit) and re-check privileges before executing those actions. Add show_window helper and emit navigate events from the tray; frontend listens for navigate and conditionally renders /settings (shows AdminRequired component for non-admins). Update App.tsx to query is_os_admin on startup and include navigation listener; add AdminRequired component, styles, and i18n keys. Update Cargo.toml with platform deps (windows features + libc for unix). Also add UI/locale assets and CSS for agent lazy-loaded device tabs and a notifications dropdown, plus several web-nodejs route/view/style updates and new task docs describing phase work.
Multiple security and maintenance fixes across components:
- betterdesk-mgmt: validate peer_id format to prevent injection in connect_to_peer (reject empty/oversized/invalid chars).
- betterdesk-mgmt (tauri.conf.json): tighten CSP by removing 'unsafe-eval' from script-src.
- betterdesk-agent-client: increase device ID entropy from 4 to 8 bytes (BD- prefix) to reduce collision/brute-force risk.
- betterdesk-server: enforce RBAC (operator+) before upgrading CDAP video WebSocket to block unauthorized access.
- betterdesk-server DBs: exclude soft_deleted peers in GetPeer queries for Postgres and SQLite.
- web-nodejs: add audit log housekeeping (hourly cleanup), add indices for audit_log, and implement cleanupOldAuditLogs(days) in sqlite adapter.
- web-nodejs brandingService: validate logo/favicon URLs to allow only http(s) or relative paths, preventing javascript:/data: XSS/SSRF vectors.
- docs: add AUDIT_BETTERDESK_2026-04-17.md (security audit summary).
These changes tighten client CSP, improve input validation, increase device identifier entropy, ensure RBAC is enforced before websocket upgrades, hide soft-deleted peers from normal queries, and add audit log maintenance and DB indexes for better performance and retention management.
Enable optional compilation and deployment of the Go server as part of the self-update flow. UI: add checkbox/status/info area in settings.js, check /api/settings/updates/server-info, include server component when selected, adjust progress/messages and longer timeouts. API/Server: add server-info endpoint and extend install request timeouts. Service: updateService now sets server localRoot and implements functions to detect Go, fetch server source (git or GitHub API), build the binary, and deploy it. i18n: add related translation keys across many locale files. Misc: improve input validation and error logging in desktop.routes, and return graceful defaults for missing policy routes in policies.routes.
Add warnings for TLS API misconfiguration and enrollment restrictions. The Go server now logs a clear warning when TLS on the API port is enabled (explaining it breaks HTTP consumers and how to fix) and logs active enrollment restriction when restored from DB. The Node.js API client (betterdeskApi.js) and event bus handler (deviceStatusPush.js) now detect TLS/HTTP mismatches and surface actionable console/error messages to help operators debug the issue (references issue #104). Files changed: betterdesk-server/main.go, web-nodejs/services/betterdeskApi.js, web-nodejs/services/deviceStatusPush.js.
Several cross-cutting fixes and refactors:
- API routing: Consolidated multiple org policy PUT endpoints into a single parameterized route (/api/org/{id}/policy/{category}) to simplify handlers (api/server.go).
- Relay/LAN handling: Prefer server LAN IP for LAN relay addresses (with proper port detection from configured relay), added strconv import and fallback to configured relay when LAN IP unknown; improves reliability with NAT hairpin issues (signal/handler.go).
- Web security: Allow inline event handlers (scriptSrcAttr: 'unsafe-inline') while still requiring nonced <script> tags for scripts used by admin pages (web-nodejs/middleware/security.js).
- CSRF: Include x-csrf-token header when POSTing language fix requests from the UI (web-nodejs/public/js/languages.js).
- Admin roles: Broaden admin checks to accept multiple admin role names via ADMIN_ROLES and update requireAdmin and RustDesk payload is_admin logic (web-nodejs/routes/rustdesk-api.routes.js).
- Admin credentials & startup resilience: authService now searches additional candidate dirs (config.dataDir, extra Windows/RustDesk paths, /app/data in Docker), skips empty candidates, and increases retries/delays when waiting for .admin_credentials (web-nodejs/services/authService.js).
- Chat API paths: Updated chat-related API calls to use /chat/* (instead of /api/chat/*) across persistence, history, contacts, groups, read and other operations (web-nodejs/services/chatRelay.js).
These changes improve compatibility (LAN relay, admin detection), robustness (longer retries, Docker/Windows path checks), and frontend behavior (CSRF token, inline handlers, updated chat endpoints).
DB: Use current_schema() when checking columns for deferred index creation and add exception handling to skip index creation if column is absent (avoids cross-schema false positives and race errors).
Signal: Harden isSameNetwork by normalizing IPv4, handling mapped addresses, adding detailed debug logs for loopback/private/subnet checks, and logging LAN detection failures in the RequestRelay handler.
Auth/API: Add tighter debug logging and trimming for /api/login (redacting passwords), and reject empty/invalid usernames early in authenticate() to address Issue #104.
UI: Add save button feedback (spinner, disable/restore), extra logging and error handling when saving org settings, and make logo image URL input editable by removing readonly.
Add typography support and a text-based logo option plus several TLS/connectivity improvements. Introduces a new font service (web-nodejs/services/fontService.js) to search, download and serve Google Fonts for self-hosting, new API routes for font management, and client-side font picker UI/logic (settings.js) with CSS (pages.css, main.css) and i18n entries (en/pl/zh). BrandingService now supports logo text/accent and font heading/body and includes generated font CSS. Views (login/sidebar) updated to render text logos and a new theme (themes/insolve.json) added. Server and TLS updates: API server now prefers TLS on the API port when valid certs exist, and dual-mode listener in tls.go adds a short peek timeout to avoid deadlocks with RustDesk clients.
Implement RBAC Phase 52: add server-side role & permission handlers and wire API routes, plus frontend UI, styles and translations.
Server: new role_handlers.go exposing endpoints to list roles, get effective role permissions, list/set/delete role permission overrides; routes registered in server.go with permission checks (PermUserView / PermServerConfig). Protects super-admin defaults and validates inputs.
Frontend (management & web UI): add permissions page assets (CSS, JS, view), add i18n strings for en/pl/zh, update sidebar to filter items by canView, show user role badge in topbar and empty access-denied state when no permission. Add role badges styling in users.css and small UX/i18n improvements in organizationDetail.js.
Also several route and service adjustments to support the new permissions UI. This change introduces RBAC UI/API plumbing for managing role-based permissions and overrides.
Adds a full Phase-52 RBAC implementation and multiple server/frontend fixes. Key changes: new auth/permissions.go with 28 granular permissions and DefaultRolePermissions, expanded 7-role hierarchy and helpers in auth/roles.go, JWT org context and GenerateOrgToken, requirePermission/requireOrgMembership middlewares (Go + Node.js), DB schema & adapter changes for role_permissions and is_server_admin, org role boundary checks and peer org scoping, and guards for last-admin demotion and self-demotion. Also: TCP EOF/connection-reset log filtering in signal/relay servers, improved startup banner port display, KEYS_PATH auto-detect warning, CSS hover/transition layout fixes, admin password race mitigation, ID-change ghost peer cleanup, added Tauri ACL schema files, and a new RBAC_PHASE52.md doc. Misc: numerous web-nodejs i18n, CSS, JS and route updates and an updated .github/copilot-instructions.md timestamp/summary.
- Fix critical SQLite migration bug: auth.db column migrations (last_login,
totp_*, settings.updated_at) were in ensureInventoryTables() which receives
main DB handle — PRAGMA table_info(users) returned empty on main DB, so
ALTER TABLE never executed. Moved to ensureAuthTables() (auth DB handle).
- Add migration logging (console.log for each added column)
- Add branding_config.updated_at migration
- Fix bd-api.routes.js: session cookie fallback auth for desktop client
- Fix auth.routes.js: rate limiter improvements
- MGMT client: add logging module, improve auth store with TOTP + token
acquisition, enhance RemoteView with session logging, improve relay
connection handling in bd_relay.rs
- ensureDefaultAdmin() now reads Go server's .admin_credentials file as
fallback when DEFAULT_ADMIN_PASSWORD env var is not set
- Searches multiple candidate dirs: keysPath, keysPath/data, /opt/betterdesk,
/opt/betterdesk/data, /opt/rustdesk, /opt/rustdesk/data
- Parses 'Admin Password: <value>' line from the file
- Fixes password mismatch on manual installs without ALL-IN-ONE scripts
- Existing installs with .env DEFAULT_ADMIN_PASSWORD are unaffected (env wins)
- Replace release-based check (always 404) with commit-SHA tracking
- Track deployed state via data/.update_sha file
- Detect changes across all components (console, server, agent, scripts)
- Show recent commits, component breakdown, and file counts
- Auto-update console + script files, manual badge for Go server
- Pre-update backup with SHA-tracked restore
- Support npm install when package.json changes
- Service restart for console (auto) and Go server (on demand)
- 15 new i18n keys in EN/PL/ZH for update UI
- CSS for commit list, component rows, rebuild warning
- Change default GITHUB_REPO from 'Rustdesk-FreeConsole' to 'BetterDesk'
(repo was renamed, causing 404 on releases/latest API call)
- Handle 404 gracefully when no GitHub releases exist yet: return
'up to date' response instead of throwing error
- Add 'updateAvailable' and 'releaseNotes' fields to response object
(frontend settings.js expects these field names)
- users.js: Change parseInt(userId, 10) to Number() on both sides of
comparison to handle BigInt/string/number ID types correctly
- dbAdapter.js: Wrap all lastInsertRowid with Number() to prevent
BigInt leak from better-sqlite3 v9+ (BigInt === Number is always false)
Root cause: better-sqlite3 v9+ returns lastInsertRowid as BigInt.
If user objects with BigInt IDs ended up in the users array, strict
equality (===) with parseInt result (Number) always fails silently,
making edit/reset-password/delete buttons appear unresponsive.
- Add zh-TW translations for web console, agent client, and MGMT client
- Update VALID_LANG_CODE regex to support BCP 47 tags (e.g. zh-TW)
- Add zh-TW to LANGUAGE_META in i18nService
Introduce a SessionManager for relay-based remote sessions in the Tauri MGMT client: new SessionCommand API, start/stop/session input routing, clipboard/recording/quality controls, and notification read/dismiss state. Wire AppState with new mutexes and show main window on startup. CI: add SBOM generation (anchore) and Trivy vulnerability scan steps. Misc: change console Docker DB path, large README/CHANGELOG updates (chat E2E, unattended access/WOL, i18n expansion, CDAP/SDK docs), and many web-nodejs assets/locales/routes/views/services and server-side changes.
Add multiple security hardenings across the server and web console: enforce proof-of-possession for /ws/bd-mgmt using Ed25519-signed headers with timestamp/nonce and replay protection (public key binding, canonicalization, storage, verification, and tests); remove legacy API key query param and config-table fallback in favor of scoped api_keys (migrate bootstrap key into api_keys); tighten WebSocket origin handling for relay and signal servers to allow only localhost origins by default unless an explicit allowlist is set; update auth middleware public paths and test helpers to use X-API-Key header; add ensureScopedAPIKey migration and related helpers; add a GitHub Secret Scan workflow and an audit report. Misc: propagate audit logging on bd-mgmt connect/disconnect and validate enrollment public keys during device register.
Add unit tests and test helpers (5 suites, 41 tests) and test npm scripts; introduce deviceStatusPush service and WS real-time device status push integration. Fix chatRelay to acknowledge connections (send `welcome`), and apply multiple web remote/rdclient fixes (video ack/timing, keyframe refresh, SourceBuffer trimming, input focus handling) to improve FPS and control. Add new server route file (system.routes.js), new device-status service, update server.js and package.json, and modify various frontend CSS/JS/views. Update English and Polish locale files with many new widget/i18n keys and remove the Russian locale file (ru.json). Also include assorted UI/desktop-widget dashboard tweaks and documentation status updates in .github/copilot-instructions.md.