- Added audio stream handling to the agent, including support for audio start and stop messages.
- Introduced lifecycle callbacks for consent and session management in the agent configuration.
- Updated desktop handling to utilize new consent handler and session start/end callbacks.
- Improved UI to reflect enrollment status and consent requests, enhancing user experience.
- Refactored branding structure to include additional color properties for better theming.
Restore POST /api/peers/{id}/restore removed in a9e217c, add signal tests
that managed mode queues pending_device_* while locked does not, and move
RustDesk enrollment controls to Settings with full approval (folder, groups,
tag picker) wired through the registrations flow.
Expose global connection strategy in the web panel with systemd/Docker persistence, extend server health diagnostics, enforce org network policy in the signal handler, and document when relay fallback is expected vs misconfiguration.
Let server.config admins edit .env, blocklist, and systemd units from the
panel with backups on save and service restart via the existing updater.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add auth_provider attribute (local/ldap/oidc) to User model across SQLite and PostgreSQL with automatic migration (existing accounts default to local). Rewrite login to be provider-bound: LDAP-backed accounts never fall through to local password verification, OIDC accounts reject password login, and LDAP/OIDC provisioning stores an unusable random local password instead of the provider password. LDAP/OIDC accounts always re-apply provider role mapping on every login so a matching local account can no longer override AD-mapped permissions. Guard handleUpdateUser against setting a local password on non-local accounts. Propagate auth_provider through the Node.js sync layer and panel API, add a Provider column with badges in the users table, hide local password reset for provider-managed accounts, and add EN/PL i18n keys.
This commit was made possible thanks to Insolve.
Redesign the console backup into a complete .tar.gz disaster-recovery bundle that can be restored on a fresh machine to bring the entire server back online. Adds zero-dependency tar.gz writer/reader (backupArchive.js), logical dumpAllTables/importAllTables for SQLite and PostgreSQL, and packs the console database, auth.db, .env, .session_secret, branding uploads, and Go server identity (Ed25519 keys, .api_key, db_v2.sqlite3) plus a recovery README. Restore auto-detects archive vs legacy JSON snapshot, supports per-component selection (database/uploads/secrets/.env/Go DB) with restart-required signaling, and warns that the archive contains secrets. EN/PL/ZH i18n added.
This commit was made possible thanks to Insolve.
Add console wallpaper, login page branding (title/subtitle/background/footer), global agent download page branding, footer/copyright with 'Powered by BetterDesk' toggle, and custom CSS injection. Includes background image upload route (8MB), sanitization for colors/gradients/CSS, dynamic theme CSS for app and login pages, sidebar attribution, and EN/PL/ZH i18n keys.
This commit was made possible thanks to Insolve.
Redesign the web remote toolbar into a RustDesk-style floating pill. The compact handle (move / fullscreen / expand) is always visible and the action pill no longer auto-opens on hover - it expands only on an explicit click of the expand button. The left handle drags the toolbar horizontally along one axis. The 'back to devices' control is now a button that closes the script-opened rdclient tab (re-focusing the opener) instead of navigating this tab to /devices, which previously spawned duplicate web-panel tabs. closeSession uses the same returnToDevices() helper. Adds move_toolbar/toggle_menu i18n keys (EN/PL/ZH) and an updated cross-platform feature matrix.
This commit was made possible thanks to Insolve.
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 codec selector (Auto/VP9/AV1/H264/VP8/H265) to the remote viewer display menu so users can request a GPU-friendly codec from the peer. setCodec() re-advertises SupportedDecoding abilities with the chosen prefer codec via OptionMessage and forces a fresh keyframe. Browser decode abilities are probed (VideoDecoder.isConfigSupported) and unsupported codecs are disabled in the menu and advertised honestly at login. Raise default image quality from Balanced to Best at both client-creation sites and pause adaptive auto-quality once the user makes a manual quality/codec choice so it no longer overrides them.
This commit was made possible thanks to Insolve.
Brings in GPU multi-codec video for the CDAP rdclient (HTTP H.264 via MSE, HTTPS AV1/VP9/H264 via WebCodecs), agent-client runtime branding, and the prebuilt Windows sidecar binary.
This commit was made possible thanks to Insolve.
Enables hardware-accelerated video for the CDAP/OS-agent rdclient path instead of being stuck on 1-2fps MJPEG, including over plain HTTP (no HTTPS/domain/cert required).
Browser viewers (web-nodejs): cdap-adapter.js and cdap-desktop.js now decode video via the shared RDVideo pipeline. WebCodecs (AV1/VP9/H264, hardware-accelerated) is used in secure contexts (HTTPS/localhost); over plain HTTP, H.264 is decoded through JMuxer/MSE using the browser's native (usually GPU) decoder. Viewers advertise decodableCodecs() in the desktop_start init payload so the agent sends a real GPU stream; MJPEG/WebP remain safe fallbacks. cdap-device.ejs preloads jmuxer + RDVideo.
Go agent (betterdesk-agent): codec.go + codec_framing.go add multi-codec engine with GPU encoder probing and selection order AV1 -> VP9 -> H264 -> WebP; desktop.go intersects the operator-advertised codec list with local encoder ability and emits honest desktop_meta (format + codec_string); config.go adds codec config fields.
Go server (betterdesk-server): cdap_handlers.go + cdap/desktop.go thread the codecs[] / video_codec fields through desktop_start so operator codec advertisement reaches the agent.
Tauri agent-client: config.rs/sidecar.rs/commands.rs codec plumbing, SettingsPanel codec dropdown + en/pl/zh i18n, refreshed agent sidecar binary.
Note: AV1/VP9 still require WebCodecs (HTTPS/localhost); H.264-over-MSE covers the plain-HTTP case. Self-signed HTTPS (installer SSL menu option C) unlocks all codecs. Fully backward compatible.
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.
Fleet, scaling, cross-platform were missing from management category. Toolkit was missing from tools category. This caused the sidebar flyout to not open and the user card to jump to the top when visiting these pages.
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.
Sidebar footer previously rendered the raw DB role string (e.g. 'global_admin'). Now resolves user.role to users.role_<role> translation key with snake_case->Title Case fallback when key is missing.
Make device group edit/delete actions visible, add direct user-group management entry points from the device group ACL modal, and allow device group editors to load user groups for ACL assignment.
Refs #140.
- Implemented user groups creation, editing, and deletion features.
- Added API endpoints for managing user groups: create, update, and delete.
- Enhanced user interface with a dedicated user groups manager section.
- Updated translations for user groups related strings in multiple languages.
- Improved CSS styles for user groups display and actions.
- Added tests for user groups API functionality.
- 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.
Address the follow-up feedback on #136 about the user-management UX
feeling disjointed and using non-standard role labels:
- Rename the base organization role from "Viewer"/"User" to
"Member" across all 26 locales. This removes the vocabulary
collision with the server-wide "Viewer" role and makes the
two-axis role model (server role vs per-org role) clearer.
- Add an Organizations column to the System > Users table so
admins can see each user's org memberships at a glance without
opening a modal. Badges are clickable and reopen the existing
Organizations modal for that user.
- Clarify the Add/Edit User form: the role dropdown is now
labelled "Server Role" with a hint that per-organization roles
are configured separately under each user's Organizations.
- The Organizations modal now has an explicit section heading and
a short hint, and uses i18n labels for the role dropdown with
an aria-label so the org role is visually distinct from the
server role.
Backend role values are unchanged ("user"/"operator"/"admin"/
"owner" for orgs, existing 7 server roles), so this is a pure
UX/i18n change with no schema or API impact.
Refs: #136
Suggested-by: Sterlyn Kong <68391309+SterlynKong@users.noreply.github.com>
- 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.
Three independent bugs combined to make 'Add Relay' silently do nothing:
1. saveRelay() in public/js/scaling.js used raw fetch() without the panel's
CSRF token, so every POST/PUT/DELETE was rejected by the CSRF middleware.
2. The catch block swallowed every error and the modal closed regardless of
the response code, so the user never saw the rejection.
3. The relay/rules routes proxied to /scaling/relays on the Go server, but
the Go server doesn't (yet) implement those endpoints — every request
ended up as a 404 and the panel's relay table stayed empty forever.
Changes:
- routes/scaling.routes.js: drop the dead Go proxy, persist relay-node
metadata and assignment rules in the existing 'settings' table
(auth.db / DATABASE_URL). Strict input validation (host:port,
Unicode-safe name, ranges for sessions/bandwidth/priority), 409 on
duplicate addresses, capped at 100 relays / 200 rules. Health and
metrics endpoints now return explicit 'live telemetry not yet
available' placeholders instead of 500s.
- public/js/scaling.js: every mutating fetch() now sends x-csrf-token,
validates inputs with a toast, parses JSON error bodies, only closes
the modal and reloads on success. Falls back to alert() if the toast
service is missing so users are never left guessing.
- views/scaling.ejs: info banner above the Relay Nodes table making
clear that the list is operator-side metadata and that actual relay
routing is configured via RELAY_SERVERS on the BetterDesk server.
- public/css/scaling.css: styles for the new info banner.
- lang/en.json, lang/pl.json: i18n keys for the banner, validation
messages and success/failure toasts.
Note: the reporter also tried RELAY=... — only RELAY_SERVERS is read
by the Go server (see config/config.go:160). Worth surfacing in docs
in a follow-up.
Reported-by: @Elektrik1
- 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.
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.
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 broad request logging in auth middleware and more granular debug logs for login handling (JSON decode errors and non-password login fields) to aid troubleshooting. Trim and sanitize username/password on the web login route and log whitespace/empty username cases and missing credentials. Extend isSameNetwork logic to treat loopback ↔ private-IP pairs as same network (covers local server → LAN target cases). Fix remote viewer templates to avoid inline string interpolation by injecting device data via JSON and setting DOM textContent (prevents XSS and EJS injection); also minor formatting/alignment tweaks in role handler comments/structs.
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.
Remove theme selection UI, CSS and logic and enforce dark theme across the app. Deleted sidebar and settings theme toggle markup and related CSS (.sidebar-theme-toggle, .theme-selector) and removed theme handling (storage keys, applyTheme/cycleTheme, event handlers and public theme API) from desktop-mode.js. Instead the app now forces the dark theme via document attributes/classes (comment: conflicts with branding). Files changed: public CSS (main.css, ui-polish.css), desktop-mode.js, main layout and sidebar templates. Local theme storage/controls are no longer used.
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.
- 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
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.