Fresh Docker installs without ADMIN_PASSWORD generated two different random
passwords: Go wrote /opt/rustdesk/.admin_credentials while the panel
authenticated against auth.db seeded by Node.js. Pre-bootstrap a shared
password in entrypoints before supervisord / server start.
Refs #385
Thanks: INSOLVE (Honorary); Marco Jakobs (@jacotec); MyNameisStitch (@MyNameisStitch); Redspin (@playerumpknow)
Match rustdesk://config/ path to Copy deploy string so ServerConfig.decode accepts the QR (#368). Also align MFA otpauth URI with Go (issuer BetterDesk, 20-byte secret) and document Android 1.4.9 deep-link fallback in UI hints.
Refs #368
Thanks: INSOLVE (Honorary); Marco Jakobs (@jacotec); MyNameisStitch (@MyNameisStitch); Redspin (@playerumpknow)
Populate CHANGELOG [Unreleased] with curated operator highlights since main 3.3.39, and remove illegal const password reassignment in ensureDefaultAdmin.
Commit web-nodejs lockfile with tar override; CI uses npm ci and moderate npm audit.
Add LOG_LEVEL filtering and log redaction in Node console and Go server.
Validate WS tokens on bd-signal; require single-use token for remote-agent relay.
Limit active relay sessions per IP and block open enrollment without TLS.
Fixes#242. Replace 24h JWT-only client tokens with configurable DB sessions (default 7 days, sliding renewal up to 30 days) and panel settings under Authentication -> RustDesk clients.
Centralize path-segment validation in goApiProxy for fleet/commercialization/cross-platform routes while preserving RustDesk peer ID compatibility; sanitize panel JS output and cap audit Recent queries.
Stop logging generated admin passwords, redact API login usernames,
confine font and file-transfer temp paths with safePath, and scope
GitHub Actions permissions in build.yml.
Add Go LDAP verify endpoint and probe it from the console when a local
user's password fails, so valid domain credentials return HTTP 409 with a
clear collision message instead of a misleading password mismatch. Includes
i18n for auth.username_collision across all console locales.
Do not auto-convert an existing local account if Go authenticates the same
username via LDAP/OIDC. Treat it as a collision and require admin action,
preventing potential privilege confusion when names overlap.
Repair the Node.js panel auth path so LDAP/OIDC users get the correct
provider and role from Go: forward authProvider in the database facade,
export syncUserFromGo, enforce provider-bound login, use unusable hashes
for external accounts, block panel edits of IdP-managed users, and
reconcile provider/role via Go API on PostgreSQL.
Merge .env keys instead of replacing files, patch systemd/NSSM in place,
block panel updates when the server cannot be rebuilt, and stop routine
updates from syncing admin passwords from .env into auth.db/PostgreSQL.
Node now persists auth_provider on SSO provisioning and re-syncs role/provider after Go login success, including SQLite auth.db backfill. Go login returns auth_provider; LDAP group mapping accepts CN keys and newlines. Default agent build cache under dataDir to avoid EACCES.
Co-authored-by: Cursor <cursoragent@cursor.com>
Issue #148 reporter @Kreol13 confirmed LDAP test connection works but
actual login fails with 'user not found in database'. Root cause: the
Node.js console only delegates unknown-user logins to the Go server when
BETTERDESK_AUTH_AUTOCREATE=true is set explicitly (security audit fix
H-01). When LDAP/OIDC is configured via the UI, that env var is not set,
so LDAP/OIDC users who don't have a local account are rejected before
Go gets a chance to authenticate them.
Go server:
- New public endpoint GET /api/auth/sso/status returning
{ldap_enabled, oidc_enabled, any_enabled}.
- Restored missing POST /api/auth/oidc/exchange route registration and
authMiddleware whitelist (regression from earlier OIDC hardening).
Node.js console:
- authService.getGoSSOStatus() — cached 60s lookup of Go SSO state.
- authenticate() now auto-provisions LDAP/OIDC-authenticated users when
any SSO provider is enabled on Go, in addition to the existing
BETTERDESK_AUTH_AUTOCREATE opt-in. Default role drops from 'admin' to
'viewer' for safer first-login provisioning when Go does not return
an explicit role mapping. Logs name which provider triggered
provisioning for audit clarity.
The H-01 concern (compromised Go server auto-provisioning admins) is
mitigated because enabling LDAP/OIDC requires an admin with the
server.config permission to explicitly opt in via the Authentication
settings tab.
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.
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.
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.
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.
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.
- 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)
Ensure freshly generated admin passwords are actually applied on reinstall and make CSRF handling more robust. Install scripts (Docker, POSH, sh) now remove stale auth.db from the console_data/data volume or data dir and create a .force_password_update sentinel (Docker also sets FORCE_PASSWORD_UPDATE=true) so the Node.js console will force-update the admin password. web-nodejs/services/authService.js adds checkForcePasswordUpdate() (env var or sentinel) and will forcibly update the admin bcrypt hash when requested; sentinel files are removed after detection. CSRF middleware now only generates tokens for safe methods (GET/HEAD/OPTIONS), avoids interfering with state-changing requests, and clears corrupt cookies using consistent options (httpOnly, sameSite: 'lax', secure based on config) to prevent spurious 403s. server.js mounts rustdeskApiRoutes before CSRF so bearer-token desktop clients are not blocked by cookie-based CSRF. Also unified the health check path from /api/health to /health in diagnostics checks and added required fs/path imports.
Co-Authored-By: MrBrodacz - Design <215021251+MrBrodacz2025@users.noreply.github.com>
Co-Authored-By: boruto79 <176351662+boruto79@users.noreply.github.com>
Rework password reset flow and diagnostics: change reset-password.js argument order (password first, optional username) and update Docker/CLI scripts to call it accordingly; persist DEFAULT_ADMIN_PASSWORD to .env and restart betterdesk-console after resets to avoid overwrites. Add translations for an "invalid_credentials" message across supported locales. Harden reset-password.js with a bcrypt self-test, log hash info, and add additional data directory candidates. Enhance authService with detailed auth/logging (hash type, failures/success), safer admin-hash migration logic (avoid overwriting if admin has logged in), and self-tests when creating/updating admin password hashes to detect/retry corrupted hashes.
Co-Authored-By: MrBrodacz - Design <215021251+MrBrodacz2025@users.noreply.github.com>
Co-Authored-By: boruto79 <176351662+boruto79@users.noreply.github.com>
Add PostgreSQL support for the web console password reset and install scripts, and improve cross-language auth handling.
Key changes:
- Introduce a unified reset-password.js that supports SQLite and PostgreSQL (reads DB_TYPE / DATABASE_URL) and make shell/PowerShell/Docker helpers prefer it with fallbacks.
- Update betterdesk-server to load an API key from API_KEY or .api_key (key/db dirs) and sync it into the database so Go server and Node console share the same key.
- Adjust docker-compose default command to run the all-in-one mode and point at the bundled DB/key paths.
- Improve dashboard health checks to avoid raw TCP probes in single-binary BetterDesk mode and derive signal/relay status from the API health; allow /api/currentUser to accept POST as well as GET.
- Enhance authService to recognize Go-style PBKDF2 hashes, verify them, auto-migrate verified PBKDF2 hashes to bcrypt, and migrate default admin if needed.
These changes improve interoperability between the Go server and Node console (shared API key and DB modes), add Postgres support for admin tooling, and provide a smooth auth migration path from the Go server's hashing scheme to bcrypt.
Co-Authored-By: MrBrodacz - Design <215021251+MrBrodacz2025@users.noreply.github.com>
Convert many Express route handlers and helper functions to async and await database calls (e.g. getAccessToken, touchAccessToken, getPeerById, getDevice, getPeerSysinfo, upsertPeerSysinfo, logAction, insertAudit*, getAll*/count* etc.). Also made identifyDevice and several route callbacks async, adjusted session.regenerate callback to use async logging, and replaced db.getDatabase() usage with db.getDb() where applicable. These changes ensure DB operations complete before responding and reduce race conditions/unhandled-promise behavior across numerous route files (activity, auth, automation, bd-api, devices, folders, i18n, inventory, registration, remote, rustdesk-api, and related route handlers).
Co-Authored-By: Charles Olivier Savignac <1275666+sircharlo@users.noreply.github.com>
Add a new betterdesk-server Go codebase (server, api, auth, db, relay, signal, metrics, audit, ratelimit, proto, tools, tests) and related deployment/migration scripts. Add a comprehensive SECURITY_AUDIT_2026-03-01 report and .gitattributes; update copilot-instructions (ALL-IN-ONE v2.4.0), README, VERSION, Dockerfiles, scripts, docker-compose and entrypoint. Large updates to web-nodejs (translations, routes, services, frontend assets and middleware) and numerous new utilities; remove legacy Flask web files and archive hbbs-patch-v2 artifacts. Prepares repository for PostgreSQL support, DB migration tooling and the new Go server as the production backend.
Bump to v2.3.0 and switch to Node.js web console as the primary console (Flask deprecated). Add comprehensive security and feature updates: CSRF protection, session-fixation prevention, timing-safe auth, WebSocket auth, TOTP 2FA, operator/admin roles, address-book sync, desktop connect (URI handler), and SSL certificate configuration in installers. Introduce a dedicated RustDesk Client API (WAN port 21121) and related web-nodejs middleware, routes, views, protos, and client JS (rdclient) plus vendor libs. Add developer tooling and scripts (dev_modules), update hbbs-patch-v2 Rust sources, README and changelog/docs, and ignore Node.js artifacts in .gitignore.
Introduce a new Node.js-based web console (Express + EJS + better-sqlite3) under web-nodejs/ and add installer support to choose between Node.js and the legacy Flask console. Update interactive ALL-IN-ONE installers (betterdesk.sh, betterdesk.ps1) with flags/options for --nodejs/--flask, automatic Node.js installation, migration logic, enhanced service handling and diagnostics. Bump VERSION to 2.2.0 and update README and project docs (.github/copilot-instructions.md) to reflect the new console, usage examples, and Docker/docs changes. Many new web-nodejs files and supporting middleware/services/routes/views/static assets were added to support the new console.