Commit Graph

181 Commits

Author SHA1 Message Date
UNITRONIX 684bd06c6e feat(backup): full disaster-recovery backup archive
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.
2026-06-01 05:21:07 +02:00
UNITRONIX 4d2ffeefc1 feat(branding): full white-label expansion of branding tab
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.
2026-06-01 05:00:12 +02:00
UNITRONIX f4ecb7bfe5 fix(auth): delegate unknown-user logins to Go LDAP/OIDC (#148)
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.
2026-06-01 04:38:04 +02:00
UNITRONIX 03ca839d76 fix(update): force full Go source resync before build (#158)
The in-app updater computed changed files via the GitHub compare API, whose 'files' array is capped at 300 entries. Large updates were truncated, so changed Go callee files (codec/ws.go, peer/map.go, auth/ldap.go, auth/oidc.go) were never downloaded, leaving inconsistent on-disk source that failed 'go build' with 'undefined' errors. ensureServerSource() also short-circuited whenever go.mod existed, so the full-resync safety net never ran.

Fixes: ensureServerSource() gains a force option that performs a full, consistent source resync (git clone / tree API) regardless of go.mod presence; called with force from applyUpdate's server block and from rebuildServerBinary (the 'Rebuild server binary' button).

Installer parity (same #158 class): betterdesk.sh, betterdesk.ps1 and betterdesk-docker.sh copied the source *directory* into the destination, which nested the new tree inside the stale dir when the pre-update rename/mv failed on a locked file. They now copy *contents* into a guaranteed-existing dir while preserving data/ and node_modules/.

This commit was made possible thanks to Insolve.
2026-06-01 04:07:20 +02:00
UNITRONIX dc6b6c088e feat(centralization): move help/chat to Go server and harden agent TLS
Phases 1-4 of the Go-server centralization plan plus optional-TLS transport.

Go server:
- db: HelpRequest model + SQLite/PostgreSQL stores (help_requests_*.go), GetDeviceOrgID.
- cdap: handleHelpRequest/handleChatMessage handlers, SendChatToDevice delivery.
- api: REST help endpoints (help_handlers.go), publish help_request/chat_message events.

Node.js panel:
- bd-api.routes.js: drop local in-memory Maps, proxy all help/chat/notification
  endpoints to the Go server (read-proxy) with status/id/timestamp normalization.

Agent (native Go + Tauri sidecar):
- config.go/agent.go: optional EnforceTLS, ServerCertPin (SPKI pin), TLSInsecureSkipVerify
  with env overlays and dialOptions() cert pinning via VerifyPeerCertificate.
- HTTP (ws://) stays a fully supported transport: TLS enforcement is an explicit
  operator opt-in (never auto-derived from the URL scheme). The agent logs a warning
  recommending wss:// for untrusted networks instead of blocking the connection.
- config.rs/sidecar.rs: propagate enforce_tls + server_cert_pin from AgentConfig
  through SidecarConfig to the Go agent config; warn on plaintext ws:// to remote hosts.

This commit was made possible thanks to Insolve.
2026-06-01 00:51:29 +02:00
UNITRONIX 497dc2752b feat(rdclient): add monitor switching and virtual display support
Implement RustDesk-desktop-style display switching and virtual display management in the web remote client.

- client.js: rewrite switchMonitor to send SwitchDisplay + CaptureDisplays messages with keyframe refresh; getMonitors marks primary (origin 0,0) and current display; add getCurrentDisplay, _processPeerInfo, _parseVirtualDisplaySupport, getVirtualDisplaySupport, toggleVirtualDisplay; switchDisplay receive handler tracks current display.
- remote.js: add i18n helper, peer_info/display_switched/virtual_display_toggled listeners, refreshMonitorButton; rewrite updateMonitorMenu with monitor list plus rustdesk_idd (4 checkboxes) and amyuni_idd (+/- counter) virtual display controls and plug-out-all.
- remote.css: styles for divider, active monitor/virtual items, counter controls.
- i18n: add virtual_displays, virtual_display, plug_out_all keys to en/pl/zh.

This commit was made possible thanks to Insolve.
2026-05-31 21:29:19 +02:00
UNITRONIX 24afad1a8f fix(rdclient): render toolbar dropdowns above the compact handle
Both the expanded pill and the compact handle use backdrop-filter, which creates separate stacking contexts. With auto z-index, paint order followed DOM order, so the handle (rendered last) covered the dropdown menus that extend down into its region — the dropdown z-index:60 only applied inside the pill's own context. Give the pill z-index:2 and the handle z-index:1 so dropdowns appear in front of the handle and stay clickable.

This commit was made possible thanks to Insolve.
2026-05-31 21:14:17 +02:00
UNITRONIX 1d08ab3fea fix(rdclient): allow toolbar dropdowns to open from floating pill
The expanded toolbar pill used overflow-x:auto, which per the CSS spec forces overflow-y to auto as well. This clipped the absolutely-positioned dropdown menus (Actions, Display, Monitors) that open below the pill (top:100%), making them invisible and unclickable. Switch the pill to overflow:visible and let its buttons wrap (flex-wrap) so the bar stays bounded on small screens without a scroll container that traps the dropdowns.

This commit was made possible thanks to Insolve.
2026-05-31 20:08:35 +02:00
UNITRONIX 53c969fc58 feat(rdclient): collapsible floating toolbar + independent browser tab
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.
2026-05-31 19:40:34 +02:00
UNITRONIX 27c082205f fix(i18n): complete web console translations
Complete the web console locale set so all 26 language files share the EN/PL baseline with no missing keys, extra keys, empty values, or English fallback values.

Keep strict i18n audit behavior and disabled auto-fix flow so incomplete translations are surfaced for manual review instead of being filled with English fallback text.

Validated with the strict web-nodejs i18n audit, JSON parsing for all locale files, placeholder preservation checks, and VS Code diagnostics.

This commit was made possible thanks to Insolve.
2026-05-31 18:46:27 +02:00
UNITRONIX 4c1a9d5e88 fix(security): patch vulnerable deps + add Go server rebuild flow
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.
2026-05-31 06:37:02 +02:00
UNITRONIX 141171990a fix(rdclient): encode protobuf string enums via fromObject (keyboard control keys)
serializeMessage used Message.create() which does NOT convert string enum names to numeric values. A KeyEvent with controlKey:'Backspace' (or Space/Tab/Return/arrows) and mode:'Legacy' was encoded as control_key=0 (Unknown), so every non-character key was silently dropped by the peer while numeric chr letter keys worked. Switched to Message.fromObject() which converts enum name strings to their numeric values and preserves Uint8Array byte fields (clipboard content, file blocks, password, public keys). Verified round-trip: Backspace->2, Space->30, mode Legacy->0, bytes/login/file-block/mouse intact.

This commit was made possible thanks to Insolve.
2026-05-31 06:04:33 +02:00
UNITRONIX 934e305040 fix(rdclient): keyboard AltGr, FPS stats, toolbar auto-hide, clipboard sync
Fixes four reported web remote client defects:
- FPS stats stuck at 0: _handleDecodedFrame (WebCodecs/HTTPS path) now records feed timestamps so getStats() reports real FPS (previously only the JMuxer fallback fed the array).
- Top toolbar never auto-hid: mousemove handler no longer re-shows the bar on every move (removed '|| toolbarVisible'), so it hides 3s after the pointer leaves the top edge.
- Keyboard support: rewritten Legacy-mode key handling with full-Unicode codePointAt, AltGr awareness (strips phantom Ctrl+Alt for printable glyphs so accented/national chars type correctly), and proper down/press/up repeat semantics matching RustDesk.
- Clipboard: local clipboard is now auto-pushed to the remote on window focus and viewer mousedown, so a plain Ctrl+V on the remote pastes local content like native RustDesk.

This commit was made possible thanks to Insolve.
2026-05-31 05:55:31 +02:00
UNITRONIX 373f425340 fix(rdclient): echo TestDelay verbatim to unblock QoS framerate
The controlled RustDesk peer periodically sends TestDelay{from_client:false} as a QoS probe and measures its round-trip to size both target bitrate and framerate. We were replying with a fresh buildTestDelay() (new timestamp), so the peer computed a bogus delay and throttled the stream down to ~1 fps. Now we echo the probe back verbatim (same time, from_client stays false), restoring the full 24-30 fps stream like the native client.

This commit was made possible thanks to Insolve.
2026-05-31 05:37:01 +02:00
UNITRONIX 4764d58587 fix(rdclient): enable software-decodable codecs in codec selector
RDVideo.getSupportedCodecs() probed only with hardwareAcceleration:'prefer-hardware', so on machines without hardware decode for VP9/AV1/VP8/H265 every codec except Auto was reported unsupported. That both grayed out the whole codec menu and made the client advertise only H264 in its SupportedDecoding at login, so the peer never offered another codec. Now probe prefer-hardware, then prefer-software, then no-preference and treat a codec as supported if ANY variant works.

This commit was made possible thanks to Insolve.
2026-05-31 05:30:00 +02:00
UNITRONIX 6883cc6249 refactor(installer): revert privilege separation from betterdesk.sh, fix banner ports
Remove the user-mode / rootless install and privilege-separation scaffolding that was added in the previous commit — the feature needs more testing before shipping. Reverts: USER_MODE, RUN_AS_ROOT, ensure_service_user, set_service_ownership, systemd User=/Group= directives, all --user/--rootless/--run-as-root CLI flags, and related help text. Restores API_PORT default to 21114.

server.js: fix startup banner — show 'Disabled' (not 'Served by Go server') when apiEnabled is false, and correct the Go API fallback URL from port 21121 to 21114.

This commit was made possible thanks to Insolve.
2026-05-31 05:23:21 +02:00
UNITRONIX 87a914432f feat(rdclient): add GPU video codec selector + default Best quality
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.
2026-05-31 05:18:54 +02:00
UNITRONIX 9c83917240 fix(rdclient): recover WebCodecs video from black screen on native RustDesk
WebCodecs VideoDecoder must receive a keyframe as the first chunk after configure(); a leading delta frame throws and the decoder produces no output. Because delta frames kept resetting the last-frame timer, the 3s stall-recovery never fired and the keyframe was never requested, leaving a permanent black screen (and 0x0 remote size, which also broke input mapping).

video.js: drop delta frames until a keyframe arrives (_needKeyframe gate after configure), use a dedicated monotonic input counter for chunk timestamps, drop deltas when the decode queue backs up, and rebuild the decoder with a software-decoding fallback + keyframe request on decoder error. init() now probes codec support without forcing hardware acceleration so software-only environments still pass.

client.js: wire video.onNeedKeyframe to send refresh_video, request an initial keyframe at session start, and extend stall-recovery to also fire when peer frames arrive but the decoder yields no output for 2s.

This commit was made possible thanks to Insolve.
2026-05-31 02:46:44 +02:00
UNITRONIX a39ea71968 merge: feat/agent-client-alpha-build-pipeline into main (GPU multi-codec + agent-client branding)
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.
2026-05-31 02:31:50 +02:00
UNITRONIX 15bca36787 feat(codec): GPU multi-codec video for CDAP rdclient incl. plain HTTP
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.
2026-05-31 02:29:53 +02:00
UNITRONIX 923602d679 feat(enrollment): operator approval queue for stock RustDesk clients
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.
2026-05-31 01:10:38 +02:00
UNITRONIX 74fba37821 merge: feat/agent-client-alpha-build-pipeline into main
Includes: alpha bundle generator, cross-platform build pipeline, RustDesk-client API endpoints on Go server (Phase A), privilege separation across all installers (systemd hardening, NSSM virtual accounts, Docker verified).

This commit was made possible thanks to Insolve.
2026-05-31 00:42:32 +02:00
UNITRONIX 0f161181f1 feat(installers): run services under unprivileged accounts by default
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.
2026-05-31 00:35:28 +02:00
UNITRONIX f81d0d0889 fix(rbac): resolve 404 on Policies/Attestation pages (#156)
The policies/attestation page routes used a local requireAdmin that only accepted the literal role 'admin' and redirected rejected users to /dashboard. Under the new 6-role RBAC (Phase 52b), fresh-install admins have role 'super_admin', so the check failed and users were redirected to /dashboard, which has no route and renders the 404 page.

Replaced the local middleware in policies.routes.js with the shared RBAC-aware requireAuth/requireAdmin from middleware/auth.js (accepts super_admin/admin/global_admin, renders errors/403 for others instead of a 404 redirect). Fixed the same outdated role==='admin' checks in reports.routes.js, tenants.routes.js, and cdap-studio.routes.js using isSuperAdminRole.

This commit was made possible thanks to Insolve.
2026-05-30 07:52:51 +02:00
UNITRONIX 760c0e933d feat(agent-client): alpha bundle generator + cross-platform build pipeline
Generator UI: web-nodejs/views/generator.ejs + public/js/generator.js + public/css/generator.css. Logo upload up to 10 MB, 16 MB body parser, branding form (product name, colors, server URL, etc.), per-branding hash deduplication.

Build pipeline: web-nodejs/services/agentBundleService.js (queue API + branding hash) and agentBuildWorker.js (DB-backed queue, 5s poll, concurrency 1, 30 min timeout). Spawns 'cargo tauri build --bundles <fmt> [--target <triple>] [--runner cargo-xwin]' per platform under systemd User=root. Loads /etc/betterdesk/build.env at module top so BUILD_USER/CARGO_HOME/PATH survive empty service env. Uses absolute CARGO_BIN/NPM_BIN paths to avoid PATH-resolution issues. Artifact path resolution honors profile.target presence (no triple subdir when omitted).

Toolchain installer: scripts/install-build-toolchain.sh (Rust + targets + cargo-tauri + cargo-xwin + mingw + makensis + dpkg-deb + rpmbuild + appimagetool + pnpm + node), writes /etc/betterdesk/build.env, 12-tool verification. Wired into betterdesk.sh menu as option B with post-install rsync of agent source to /opt/BetterDeskConsole/agent-source/.

Agent download page: web-nodejs/views/agent-download.ejs + public/css/agent-download.css for end-user installer downloads per platform/format with live status.

Branding scaffold (Tauri side): betterdesk-agent-client/src-tauri/src/branding.rs (Branding struct + OnceLock cache + BETTERDESK_AGENT_BRANDING env override + BaseDirectory::Resource resolve). resources/branding.json (dev skeleton). lib.rs registers module + get_branding command. commands.rs exposes get_branding IPC. tauri.conf.json declares resources/branding.json. Frontend integration of get_branding is intentionally pending — alpha.

Database: web-nodejs/services/database.js + dbAdapter.js add agent_bundle_builds + agent_bundles tables with full PostgreSQL + SQLite parity.

i18n: en.json + pl.json + zh-TW.json get ~75 new keys covering generator wizard, build status, download page, and toolchain installer messages.

Validated end-to-end on prod (Ubuntu 24.04, 4-core, PostgreSQL): linux/x64/AppImage built successfully (83.7 MB, 283s) for branding hash 25e2f242. linux/deb in progress, rpm + windows/exe queued.

Known follow-ups (NOT in this commit): SolidJS invoke('get_branding') wiring in App.tsx, betterdesk.ps1 toolchain menu mirror, reset-password.js PostgreSQL support, Docker decision.

This commit was made possible thanks to Insolve.
2026-05-29 07:15:45 +02:00
UNITRONIX a9e217c165 fix(api): filter banned devices from client sync and fix tag/AB issues (#138)
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.
2026-05-29 03:26:40 +02:00
UNITRONIX 60bccb489a fix(auth): restore local-first login flow — fixes login lockout after SSO update
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.
2026-05-29 02:49:21 +02:00
UNITRONIX f70123e703 fix(sso): normalize API URL + surface Go errors in test endpoints
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.
2026-05-29 02:40:28 +02:00
UNITRONIX 188991d91d feat(auth): add LDAP and OIDC/OAuth2 SSO authentication
Go server: auth/ldap.go (LDAP bind + group-to-role mapping), auth/oidc.go (OIDC provider with PKCE, discovery, token exchange), api/ldap_handlers.go (config CRUD + test connection), api/oidc_handlers.go (authorize/callback/exchange/status + config CRUD), auth_handlers.go (LDAP auth branch before local password check + PBKDF2 rehash on login), password.go (NeedsRehash helper), server.go (LDAP/OIDC route registration + Init methods), main.go (InitLDAP/InitOIDC calls). Node.js console: auth.routes.js (OIDC proxy routes with open-redirect sanitization), settings.routes.js (LDAP/OIDC config tabs), authService.js (LDAP/OIDC auth flows with emergency mode), betterdeskApi.js (6 new SSO API methods), middleware/auth.js (emergencyMode flag), login.ejs (SSO buttons), settings.ejs (LDAP/OIDC config panels), navbar.ejs (SSO indicator). i18n: ~90 SSO keys added to EN/PL/ZH.

This commit was made possible thanks to Insolve.
2026-05-29 02:29:10 +02:00
UNITRONIX 83f3617f98 fix(update): fix infinite update loop and add GitHub-pull update to ALL-IN-ONE scripts (#154)
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.
2026-05-29 02:28:57 +02:00
Knienartowicz 2490de56e3 fix(sidebar): add missing pages to rail category active arrays
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.
2026-05-28 12:32:19 +02:00
UNITRONIX 4d2a4e0488 fix(api,ui): fix tags/groups, status type, operator permissions (#138)
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.
2026-05-28 01:46:19 +02:00
UNITRONIX 40cde4ebee fix(security): remove non-standard browsing-topics from Permissions-Policy
Removes browsing-topics=() directive which caused console warnings in browsers
that don't support this non-standard feature.

This commit was made possible thanks to Insolve.
2026-05-27 01:02:00 +02:00
UNITRONIX ae7498fdaa fix(api): fix RustDesk client AB, groups & peer list format
- Remove string 'id' from group payload (caused Dart 'String is not subtype of int?' crash)
- Add team.peers array with device IDs, access_perm, sort to group response
- Change device filter from online-only to all non-banned/non-disabled peers
- Fix peer format: nested info object, int status, bool online (matching Go server)
- Enable includeDevices for admin/operator AB sync (60 peers now visible)
- Collect peer_ids from device_group_members and device_folder_assignments

This commit was made possible thanks to Insolve.
2026-05-27 01:01:20 +02:00
UNITRONIX ab2dc5d3ab feat(scripts): add HTTP/HTTPS protocol toggle to installer scripts
- 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.
2026-05-27 00:10:51 +02:00
Knienartowicz 5670bdc8b1 fix(api): resolve RustDesk client tag/group/peer type mismatches (#138)
5 root causes identified and fixed:

- H1: /api/peers returned status as string 'ONLINE' — RustDesk PeerPayload expects int (1=active, 0=disabled). New handleClientPeersList() detects client requests (?accessible/?pageSize) and returns {total,data} envelope with PeerPayload format (nested info map, int status).

- H2: mergeAdminTagsIntoAB() used typed struct → silently dropped tag_colors field. Rewritten with map[string]any to preserve all AB fields.

- H3: /api/device-group/accessible missing (404) — RustDesk GroupModel._getDeviceGroups() calls this endpoint. Added route pointing to handleClientGroupList.

- H4: /api/users returned plain array with wrong field names — RustDesk expects {total,data} with UserPayload (name, display_name, status:int, is_admin:bool). New handleClientUsersList() returns correct format.

- L1: .group-chip.chip-add CSS didn't fully override base 3-column grid. Added explicit grid/centering/dashed-border overrides.

Also updated handleClientGroupPeers (/api/peers/list) to use PeerPayload format with nested info map for consistency.

This commit was made possible thanks to Insolve.
2026-05-26 15:47:27 +02:00
Knienartowicz de53408803 security: apply audit fixes (H-02/H-03/H-04/H-05) — branding, TOTP recovery codes, NodeSource SHA verification
Node.js (web-nodejs):

- H-02 (services/brandingService.js): tighten SVG sanitization (strip <style>/<use>/<image>, DOCTYPE/PI, CSS expression()/@import); export validateBrandingUrl() rejecting protocol-relative // and unknown schemes

- H-03 (routes/settings.routes.js): logo upload — whitelist /^logo-[0-9a-f]{16}.(png|jpg|jpeg|gif|webp|svg)$/i + path.resolve prefix check + fs.lstatSync symlink guard before deleting old logo

Go server (betterdesk-server):

- H-04 (auth/recovery.go NEW): TOTP recovery codes — GenerateRecoveryCodes (10 codes XXXX-XXXX-XX, unambiguous alphabet), HashRecoveryCodes (JSON array of bcrypt hashes, cost 10), ConsumeRecoveryCode (single-use, returns updated store)

- H-04 (db/database.go,sqlite.go,postgres.go): User.TOTPRecoveryCodes field with read/write via COALESCE-tolerant SELECTs (additive, backward-compat: column already existed from Phase 12 migration)

- H-04 (api/auth_handlers.go): handleConfirmTOTP returns plaintext recovery codes ONCE on enable; handleLogin2FA falls back to ConsumeRecoveryCode on invalid TOTP and audits with 2fa=recovery_code; handleDisableTOTP clears stored codes

Scripts:

- H-05 (betterdesk.sh): replace curl|bash piping with download-to-tempfile + validation — HTTPS-only (--proto=https --tlsv1.2), size sanity (1-500KB), shebang sanity check, SHA-256 logged, optional pinning via NODESOURCE_SHA256 env

Verification: go build ./... ✓, go vet ./... ✓ (exit 0), go test ./auth/... ./db/... ✓, jest 102/102 passed

This commit was made possible thanks to Insolve.
2026-05-26 14:57:01 +02:00
Knienartowicz 3888e68811 ui(sidebar): translate user role label via users.role_* i18n keys
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.
2026-05-26 14:01:27 +02:00
Knienartowicz f8fbb88e47 security: apply 12 audit fixes (H-03/H-04/M-03/M-04/M-05/M-06/M-07/L-01/L-02/L-04/I-02/I-04)
Node.js (no recompile required):

- H-04: RUSTDESK_API_DISABLE_TOTP now requires explicit _ACKNOWLEDGED flag

- M-03: drop Referer-based skip from apiLimiter; add dedicated widgetLimiter

- M-06: gate /api/system/info, /logs/recent, /database/stats, /docker/containers, /speed-test behind requirePermission('metrics.view')

- L-01: startup banner now warns when TRUST_PROXY is off in production / errors when TOTP bypass is set without acknowledgement

Scripts / Docker:

- M-04: betterdesk.sh migration tool invocation switched from eval(cmd-string) to bash array exec

- M-05: all admin / PostgreSQL password generators switched from openssl rand -base64+tr+head to openssl rand -hex 16 (full entropy)

- L-02: docker-compose.yml / single.yml / quick.yml services gain security_opt: no-new-privileges and cap_drop: ALL

Documentation:

- I-04: add SECURITY.md (supported versions, reporting channels, SLA, scope, hardening defaults)

Go server (requires rebuild on host: cd betterdesk-server && go build ./...):

- H-03: /metrics now gated by METRICS_IP_ALLOWLIST / METRICS_PUBLIC; per-username login + 2FA rate-limit added on top of per-IP

- M-07: enrollment (/api/devices/register*) and branding (GET /api/branding) endpoints rate-limited per IP

- I-02: bd-mgmt WebSocket gets SetReadLimit(16 MiB) to bound memory

- L-04: auth middleware skips noisy public probes and redacts /peers/{id} segments

This commit was made possible thanks to Insolve.
2026-05-26 13:58:16 +02:00
Knienartowicz 8da6f8c9fd security: fix 3 critical + 3 high findings from production audit
Critical:

- C-01: WebSocket Origin validation (CSWSH protection) via new middleware/wsOrigin.js, applied to wsRelay, chatRelay, remoteRelay, bdRelay, cdapTerminalProxy, cdapMediaProxy

- C-02: Remove Tauri Origin-based CSRF bypass in server.js; only /api/bd/* skipped

- C-03: Update vulnerable deps (express 4.21.2, multer 2.0.0, protobufjs 7.4.0, helmet 7.2.0, axios 1.9.0, cookie-parser 1.4.7, express-session 1.18.1)

High:

- H-01: Disable auto-create-local-user on login by default; opt-in via BETTERDESK_AUTH_AUTOCREATE=true (does not affect ensureDefaultAdmin fresh-install bootstrap)

- H-02: Bearer-only auth for /api/bd/*; session cookie fallback removed; tokens redacted in logs

- H-05: Replace custom PBKDF2 with golang.org/x/crypto/pbkdf2; 600k iterations; new format pbkdf2-sha256\\\ with backward-compat for legacy salt:hash

Backward compatibility: legacy password hashes still verify; CSRF tokens still obtainable via csrfTokenProvider; fresh-install admin bootstrap (.admin_credentials flow) unchanged.

Audit report: docs/security/AUDIT_PRODUCTION_2026-04-10.md

This commit was made possible thanks to Insolve.
2026-05-26 13:35:12 +02:00
Knienartowicz 84252f5c40 feat: add warning and outline button styles to main.css; update action button styles in users.css 2026-05-26 13:16:31 +02:00
Knienartowicz 888cbcf38e feat: conditionally initialize backup and update sections based on server.config permission 2026-05-26 13:07:59 +02:00
Knienartowicz c934f07783 feat: add RustDesk PRO group endpoints and adjust request body limits 2026-05-26 13:03:59 +02:00
Knienartowicz 84987c7c9d feat: update Polish translations for BetterDesk dashboard 2026-05-26 12:49:41 +02:00
UNITRONIX 415b6cf967 feat: add terminal updater and keep Go API HTTP 2026-05-23 00:49:49 +02:00
UNITRONIX 274a52d1cd feat: Enhance update process for BetterDesk console and Go server
- 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.
2026-05-23 00:29:19 +02:00
UNITRONIX 9041fb7227 fix: clarify group management workflows (#140)
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.
2026-05-23 00:16:22 +02:00
UNITRONIX 321e49b7f7 fix: polish folder tiles and Available Devices payload (#138) 2026-05-22 02:29:16 +02:00
UNITRONIX 6134b4235e Show pending enrollments in registrations UI (Refs #149) 2026-05-22 01:56:11 +02:00
UNITRONIX 99add5d434 fix: improve device folder tiles and RustDesk group sync (#138) 2026-05-19 18:56:09 +02:00