Commit Graph

434 Commits

Author SHA1 Message Date
mike 3e89d61566 feat: add Pro-equivalent management API on top of OSS hbbs
Brings the rustdesk-server up to feature parity with RustDesk Server Pro for
the API surface the desktop client expects (CONSOLE_API.md). Implemented as
an in-process axum router mounted by hbbs alongside its existing
rendezvous + relay TCP/UDP/WS listeners; everything persists in the existing
SQLx + SQLite database via additional CREATE TABLE IF NOT EXISTS migrations.

================================================================================
M1 — Auth foundation + heartbeat + sysinfo
================================================================================
- New tables: users, tokens, device_sysinfo.
- Endpoints: HEAD+GET /api/login-options, POST /api/login, POST /api/logout,
  POST /api/currentUser, POST /api/heartbeat, POST /api/sysinfo_ver,
  POST /api/sysinfo.
- Bearer-token auth: tokens are 32 random bytes (base64url); only the
  sha256 of the token is stored. `tokens.last_used_at`/`expires_at` slide
  forward on every authenticated request (30-day TTL by default).
- Bcrypt-cost-10 password hashing, always wrapped in
  tokio::task::spawn_blocking to keep the runtime responsive.
- New CLI flags --http-port, --bootstrap-admin-username,
  --bootstrap-admin-password.
- Heartbeat returns the `sysinfo: true` flag on first contact and after
  cfg.sysinfo_ver bumps; sysinfo upload returns the bare-string body
  ("SYSINFO_UPDATED" / "ID_NOT_FOUND") the client expects.

================================================================================
M2 — Address book, device groups, accessible peers
================================================================================
- New tables: address_books, address_book_shares, address_book_peers,
  address_book_tags, address_book_peer_tags, device_groups,
  device_group_members. Soft-ALTER adds device_sysinfo.user_id (the
  binding from a device to its enrolled user, set by /api/login).
- Endpoints: POST /api/ab/settings, POST /api/ab/personal,
  POST /api/ab/shared/profiles, POST /api/ab/peers, POST /api/ab/tags/{guid},
  POST /api/ab/peer/add/{guid}, PUT /api/ab/peer/update/{guid},
  DELETE /api/ab/peer/{guid}, POST /api/ab/tag/add/{guid},
  PUT /api/ab/tag/rename/{guid}, PUT /api/ab/tag/update/{guid},
  DELETE /api/ab/tag/{guid}, GET+POST /api/ab (legacy single-blob fallback),
  GET /api/device-group/accessible, GET /api/users, GET /api/peers.
- Share-rule enforcement (1=read, 2=read/write, 3=full) at the top of every
  AB mutation. Owners are full; other rules come from
  address_book_shares (direct or via device_group). Rejection is HTTP 200 +
  {"error":"read-only"} so the client doesn't yank the session.
- New CLI flags --ab-legacy-mode, --ab-max-peers-per-book.
- Action endpoints (peer add/update/delete, tag CRUD) return HTTP 200 with
  EMPTY body on success — matches the Flutter _jsonDecodeActionResp at
  ab_model.dart:2002 which treats {} as the literal error string "null".

================================================================================
M3 — Audit, recording, strategy push
================================================================================
- New tables: audit_conn (PK guid echoed back to client),
  audit_file, audit_alarm, recordings, strategies, strategy_assignments,
  heartbeat_commands.
- Endpoints: POST /api/audit/conn (returns {"guid":"..."}),
  POST /api/audit/file, POST /api/audit/alarm, PUT /api/audit (note update),
  POST /api/record?type={new|part|tail|remove}.
- Recording uploader: filesystem state machine under --recording-dir;
  filenames sanitized to a single Normal path component to block traversal;
  `tail` writes the first ≤1024 bytes at offset 0 after all `part` chunks.
- Heartbeat extended to:
  * resolve a per-peer strategy (peer > device-group > user, highest
    priority wins) and emit `strategy.config_options` + `extra` +
    `modified_at`.
  * read-and-delete heartbeat_commands rows so an admin can queue
    `disconnect: [conn_id]` or force `sysinfo: true` via SQL and have it
    delivered on the next 15-second tick.
- New CLI flags --recording-dir (default ./recordings),
  --recording-max-size-mb, --audit-retention-days.

================================================================================
secure_tcp on the rendezvous TCP listener (M3 polish)
================================================================================
A logged-in client conditionally calls secure_tcp() on its TCP rendezvous
connection (src/client.rs:427-431, gated on `key && token` both non-empty).
OSS hbbs had no KeyExchange handler at all on TCP rendezvous, so the
client's secure_tcp_impl read timed out with "Failed to secure tcp:
deadline has elapsed". Added:
- A try_secure_tcp_handshake helper that, on every accepted TCP connection,
  generates an ephemeral box keypair, signs the box public key with the
  server's Ed25519 sk (already loaded for relay-response signing), sends
  KeyExchange, then waits 5s for the client's reply.
  - Reply is KeyExchange[client_box_pk, sealed_sym_key] -> decrypt the
    sealed key, install Encrypt on both halves of the stream.
  - Reply is any other RendezvousMessage -> buffer it and replay through
    the normal handle_tcp dispatcher (plain-mode clients filter unsolicited
    KeyExchange via get_next_nonkeyexchange_msg, so our preceding KX is
    harmless).
  - Reply never comes (timeout) -> fall through to plain mode.
- Sink::TcpStream now carries an Option<Encrypt>; outgoing writes are
  sealed when keyed. Symmetric Encrypt is cloned for inbound (`dec`) and
  outbound (`enc`) so the two directions track independent counters.

================================================================================
M4 — Advanced auth (TOTP, email-code, OIDC), CLI assign, plugin signing
================================================================================
- New tables: user_totp_secrets, pending_tfa_challenges,
  pending_email_codes, oidc_providers, oidc_sessions. Soft-ALTER adds
  users.oidc_subject.
- /api/login extended:
  * type:"account" (existing) — issues an `tfa_check` challenge (5-min
    nonce in `secret`) when the user has TOTP enrolled.
  * type:"tfa_code" — verifies the nonce + the 6-digit TOTP code against
    user_totp_secrets.secret_b32.
  * type:"email_code" — passwordless. First leg mints a 6-digit code and
    sends it via SMTP (or logs to stdout when --smtp-host is empty);
    second leg verifies. Brute-force capped at 5 attempts per code, then
    the row is purged.
- /api/oidc/auth + GET /oidc/callback + GET /api/oidc/auth-query implement
  the standard OAuth2 authorization-code flow with userinfo. Discovery via
  <issuer>/.well-known/openid-configuration with an in-memory cache.
  --oidc-config TOML upserts providers at startup; --public-base-url builds
  the redirect_uri.
- New endpoints: POST /api/2fa/enroll (admin-only, returns secret_b32 +
  otpauth_url), POST /api/2fa/unenroll, POST /api/devices/cli (used by
  `rustdesk --assign`; binds device to user, ensures device-group, adds
  AB entry, attaches peer-scoped strategy), POST /lic/web/api/plugin-sign
  (Ed25519 over the request body using the same id_ed25519 secret).
- /api/login-options is now dynamic: returns ["account"], plus "email_code"
  when SMTP or ALLOW_DEV_EMAIL_CODE is set, plus an "oidc/<name>" entry
  per enabled provider in oidc_providers.
- New CLI flags --smtp-host, --smtp-port, --smtp-user, --smtp-pass,
  --smtp-from, --smtp-tls, --public-base-url, --oidc-config.
- New crate deps: tokio (fs/io-util features), totp-rs, lettre (rustls +
  builder + smtp-transport, no defaults), toml.

================================================================================
Code organization
================================================================================
- src/api/                 axum router + shared state + error envelope
  ├── ab/                  address book endpoints (settings/profiles/peers/
  │                        tags/legacy/rules)
  ├── audit/               conn/file/alarm/note
  ├── oidc/                providers/discovery/auth/callback/poll
  ├── record/              storage state machine + handler
  ├── strategy/            resolver wrapper around DB
  ├── auth.rs              login/logout/currentUser
  ├── devices_cli.rs       /api/devices/cli
  ├── email.rs             SMTP transport (lettre) + dev-mode stdout fallback
  ├── error.rs             ApiError enum -> HTTP 200/401/403/404 + JSON envelope
  ├── groups.rs            /api/device-group/accessible
  ├── heartbeat.rs         /api/heartbeat
  ├── middleware.rs        AuthedUser extractor (Bearer -> sha256 -> token row)
  ├── pagination.rs        Page<T> + PageQuery
  ├── peers.rs             /api/peers
  ├── plugin_sign.rs       /lic/web/api/plugin-sign
  ├── state.rs             AppState + ApiConfig (incl. EmailConfig)
  ├── sysinfo.rs           /api/sysinfo, /api/sysinfo_ver
  ├── twofa.rs             /api/2fa/enroll, /unenroll
  └── users.rs             UserPayload + /api/users + bcrypt helpers

================================================================================
Conventions enforced throughout
================================================================================
- All new SQL uses the runtime sqlx::query("...") form (NOT the query!
  macro) so first-time builds don't require DATABASE_URL to point at a DB
  containing the new tables.
- Soft-ALTER helper (try_alter) swallows "duplicate column name" errors so
  schema migrations are idempotent across re-runs and existing-DB upgrades.
- Bcrypt compares always via spawn_blocking.
- Tokens (Bearer access_token, TFA challenge nonce, OIDC poll handle) are
  always 24-32 random bytes from sodiumoxide::randombytes; the Bearer is
  stored only as its sha256.
- Constant-time hash comparison for email codes.
- Action endpoints return HTTP 200 with empty body on success; HTTP 200 +
  {"error": "..."} for business errors so the client doesn't get logged
  out; 401 only from the auth middleware.

Tested end-to-end via curl + a stock RustDesk client (M1-M2 verified
against two laptops; M3 verified against the strategy-push and
force-disconnect paths; M4 verified via direct flow tests + a mock IdP for
OIDC). Stock client connect now works whether the user is signed in or
not (the secure_tcp regression that blocked logged-in connect is fixed).

The remaining piece on the M4 plan — HttpProxyRequest, the TCP-over-
rendezvous fallback for clients with OPTION_USE_RAW_TCP_FOR_API=Y — is
gated on bumping the OSS server's vendored hbb_common to a commit that
includes proto tags 27 and 28. That work lives on a separate branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 19:07:01 +02:00
WC3D 815c728837 fix(security): update mio from 0.8.5 to 0.8.11 (#633)
Co-authored-by: aikido-autofix[bot] <119856028+aikido-autofix[bot]@users.noreply.github.com>
2026-02-17 14:28:35 +08:00
RustDesk bd7bc52c43 Update build.yaml 2026-01-13 10:26:46 +08:00
rustdesk 34cbd57e71 bump version 2026-01-13 10:20:40 +08:00
rustdesk 46e9ecd47d fix pr 2026-01-12 17:28:25 +08:00
rustdesk d0770e6c06 high rustc 2026-01-12 15:08:01 +08:00
rustdesk f87372ead0 GHCR manifest 2026-01-12 14:59:45 +08:00
RustDesk 04efb7033c Update README.md 2026-01-12 14:54:50 +08:00
RustDesk 9bae9f2f39 Update build.yaml 2026-01-12 13:28:04 +08:00
rustdesk 7c2057c360 remove annoying fmt check 2026-01-10 16:33:46 +08:00
rustdesk f61b31f04e 1.1.15 debain log 2026-01-10 16:07:16 +08:00
rustdesk bb455a3eb7 merge ghcr to build.yml 2026-01-10 15:51:06 +08:00
RustDesk 631618a6be Update build.yaml 2026-01-10 14:47:34 +08:00
rustdesk 34946219c3 update workflow 2026-01-09 19:12:49 +08:00
rustdesk 5d1b4ba78a connection log query 2026-01-06 23:59:47 +08:00
Nawer 7e921be539 chore: Added kubernetes example file (#623) 2026-01-06 17:58:33 +08:00
lrin 716041bac1 libs: Fix hbb_common Submodule (#553)
The hbb_common Submodule was accidentally deleted in https://github.com/rustdesk/rustdesk-server/commit/c650217919ce6b67bf62a3d0c092e41f0d37b18b
2025-11-22 15:24:50 +08:00
Guiorgy 6b72cefbc5 define the HOME env to allow running rootless (#612) 2025-11-22 15:20:15 +08:00
Geert Stappers 386c83874c debian/changelog more like the first two (#573)
* debian/changelog more like the first two

Added "Who and When" lines, added empty lines as separator.
The time stamps where retrieved from the git commit log.

All entries look now like:

rustdesk-server (1.1.7) UNRELEASED; urgency=medium

  * ipv6 support

 -- rustdesk <info@rustdesk.com>  Wed, 11 Jan 2023 11:27:00 +0800

rustdesk-server (1.1.6) UNRELEASED; urgency=medium

  * Initial release

 -- open-trade <info@rustdesk.com>  Fri, 15 Jul 2022 12:27:27 +0200

* debian/changelog: reformat a date stamp

The "wrong format" was discovered by Lintian.
2025-11-03 13:57:06 +08:00
Geert Stappers 5cc309dc9f new file: debian/README.source (#592)
Describes how to build
2025-11-03 13:56:00 +08:00
rustdesk 4e8d6d08e2 fix https://github.com/rustdesk/rustdesk-server/issues/435 2025-11-03 13:03:19 +08:00
c8a5d41906 chore: Update to Windows 2022 runner image (#568) 2025-07-13 07:33:30 +08:00
rustdesk 2c57e51ec5 higher default bandwidth 2025-06-22 15:03:13 +09:00
RustDesk 796a75af5c Update README.md 2025-06-16 14:46:51 +08:00
rustdesk f09b79c6da README-ZH.md 2025-06-16 00:23:50 +08:00
rustdesk 1e84478837 simplify doc 2025-06-16 00:23:33 +08:00
RustDesk 2417c7ddd0 Update build.yaml 2025-05-11 20:54:24 +08:00
bato3 235a3c326c In cargo it is named "rustdesk-utils" (#551) 2025-04-29 20:40:55 +08:00
Guoiaoang e4c85764f9 fix translation errors (#545) 2025-04-19 09:48:05 +08:00
dependabot[bot] c650217919 Git submodule: Bump libs/hbb_common from 7cf11f7 to 83419b6 (#524)
Bumps [libs/hbb_common](https://github.com/rustdesk/hbb_common) from `7cf11f7` to `83419b6`.
- [Commits](https://github.com/rustdesk/hbb_common/compare/7cf11f7b771e27ecbd14fd1dd0ced55a64f40eb5...83419b6549636ee39dacef7776c473f5802e08d6)

---
updated-dependencies:
- dependency-name: libs/hbb_common
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 09:06:09 +08:00
dependabot[bot] 262a1d49f8 Git submodule: Bump libs/hbb_common from 49c6b24 to 7cf11f7 (#523)
Bumps [libs/hbb_common](https://github.com/rustdesk/hbb_common) from `49c6b24` to `7cf11f7`.
- [Commits](https://github.com/rustdesk/hbb_common/compare/49c6b24a7a8c39d4448e07b743007ef1a3febd43...7cf11f7b771e27ecbd14fd1dd0ced55a64f40eb5)

---
updated-dependencies:
- dependency-name: libs/hbb_common
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 22:45:13 +08:00
XLion f0a6c3de0b Create dependabot.yml (#522) 2025-02-24 22:42:23 +08:00
621da3c8fe fix: 127.0.0.1 is not loopback (#515) 2025-02-06 20:25:10 +08:00
RustDesk 801826f36d Update build.yaml 2025-01-31 15:11:28 +08:00
rustdesk 8557c4ab82 freebsd still not work 2025-01-25 20:47:19 +08:00
rustdesk 1fd1a2a3b6 1.1.14 2025-01-25 20:37:16 +08:00
21pages bcdfda43af update dep (#507)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-01-22 20:27:25 +08:00
XLion 11a1f99169 Fix test error (#505) 2025-01-21 23:53:23 +08:00
21pages 464a687043 fix windows crash (#504)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-01-21 17:03:45 +08:00
RustDesk 66c78c23fe Update build.yaml 2025-01-21 01:33:42 +08:00
rustdesk e251161c5d rust 1.81 2025-01-21 01:21:13 +08:00
rustdesk b9e5968299 1.1.13 2025-01-21 01:09:21 +08:00
21pages 7a509f6975 replace libs/hbb_common with submodule (#502)
cargo update -p schannel to fix crash on higher rust toolchain, https://github.com/seanmonstar/reqwest/issues/2311

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-01-20 17:34:22 +08:00
Integral 772db7422f refactor: replace static with const for global constants (#494) 2024-12-07 17:54:53 +08:00
XLion 2f246537df README: Restructure Container expression; add ghcr; multiple tidy up (#479)
* Update README.md

* make hbbs first everywhere

* Update README.md

* Fix link

* dockerhub to Docker Hub; Suggest user use ghcr if can't access Docker Hub

* Add `

* Add Debian 12
2024-12-02 21:14:56 +08:00
XLion 4c74586ce0 Borrow Cargo.toml's profile.release from RustDesk for better binary (#481) 2024-10-14 11:00:38 +08:00
XLion 2ac3169d77 Don't test with editing README (#480) 2024-10-12 18:14:37 +08:00
rustdesk 6f18a97644 v1.1.12 2024-10-07 16:21:36 +08:00
XLion 3b386b6b54 feat: Publish container images to GitHub ghcr.io (#473)
* ghcr

* fix name

* ghcr

* ghcr

* ghcr

* ghcr

* ghcr

* ghcr update action

* ghcr update action

* ghcr update action

* ghcr update action

* ghcr update action

* ghcr update action

* ghcr classic

* ghcr classic

* ghcr: better naming and tidy up

* ghcr classic fix chmod

* tidy up

* tidy up

* if-no-files-found: error
2024-09-30 08:46:35 +08:00
Fionera b37033d92c docs: the servers are by comma instead of colon (#462) 2024-09-28 23:34:47 +08:00