Update README.md
build-windows / build-hello-agent-x64 (push) Successful in 6m5s
build-windows / sign-hello-agent-x64 (push) Successful in 5s
build-windows / validate-hello-agent-x64 (push) Successful in 7s

This commit is contained in:
2026-05-09 14:25:27 +02:00
parent 8025f8558a
commit d10e547b70
+76 -15
View File
@@ -45,6 +45,10 @@ hello-agent.exe --install
└──> creates Windows service "HelloAgent", binPath ends in --service └──> creates Windows service "HelloAgent", binPath ends in --service
hello-agent.exe --service # Session 0, LocalSystem hello-agent.exe --service # Session 0, LocalSystem
├── unattended_password::rotate_and_report (background thread)
│ └─ POSTs per-boot password to <api-server>/api/unattended-password
│ with retry until ack — races rendezvous registration
└──> spawns into the active console session as SYSTEM token: └──> spawns into the active console session as SYSTEM token:
@@ -53,6 +57,12 @@ hello-agent.exe --server # user session, SYSTEM token
├── default ipc listener (rustdesk core) ├── default ipc listener (rustdesk core)
├── RendezvousMediator ──> rustdesk-server registration + NAT ├── RendezvousMediator ──> rustdesk-server registration + NAT
├── hbbs_http::sync ──> /api/heartbeat + /api/sysinfo ├── hbbs_http::sync ──> /api/heartbeat + /api/sysinfo
│ └─ stamps `agent_name` / `agent_version` / `inventory`
│ into each /api/sysinfo payload (re-uploads when the
│ inventory collector below transitions empty → ready)
├── inventory::collect_inventory (background thread)
│ └─ PowerShell + WMI + wlanapi + ipify → `INVENTORY` global
│ consumed by hbbs_http::sync above; one-shot, no retry
│ at startup, --server proactively spawns (via WTSQueryUserToken │ at startup, --server proactively spawns (via WTSQueryUserToken
│ + CreateProcessAsUserW with lpDesktop = winsta0\default — │ + CreateProcessAsUserW with lpDesktop = winsta0\default —
@@ -78,35 +88,66 @@ Flutter Connection Manager.
``` ```
hello-agent/ hello-agent/
├── src/ hello-agent sources (~600 lines) ├── src/ hello-agent sources (~2400 lines)
├── vendor/rustdesk/ vendored RustDesk crate + workspace libs ├── vendor/rustdesk/ vendored RustDesk crate + workspace libs
│ ├── Cargo.toml rustdesk's own workspace + package manifest │ ├── Cargo.toml rustdesk's own workspace + package manifest
│ ├── src/ librustdesk source │ ├── src/ librustdesk source
│ └── libs/ hbb_common, scrap, enigo, clipboard, … │ └── libs/ hbb_common, scrap, enigo, clipboard, …
├── Cargo.toml hello-agent package manifest, path-deps on vendor ├── Cargo.toml hello-agent package manifest, path-deps on vendor
├── ci/ provision scripts for the Gitea Windows-build /
│ Linux-signing self-hosted runners
├── .gitea/workflows/ Gitea CI ├── .gitea/workflows/ Gitea CI
└── README.md └── README.md
``` ```
The vendored source has a few local divergences from upstream — all The vendored source has a handful of local divergences from upstream.
documented inline at the patch site so they're easy to spot when Most patch sites carry an inline `hello-agent` breadcrumb (search for
re-syncing: `grep -rn "hello-agent" vendor/rustdesk/` in a tree where the patches
have been applied) but a couple of one-token edits like
`pub mod custom_server` don't, so the list below is the authoritative
inventory — keep it in sync when adding new patches.
1. [`vendor/rustdesk/src/lib.rs`](vendor/rustdesk/src/lib.rs): 1. **Module visibility**
`mod custom_server``pub mod custom_server` so hello-agent can call [`vendor/rustdesk/src/lib.rs`](vendor/rustdesk/src/lib.rs):
the deploy-blob decoder. * `mod custom_server``pub mod custom_server` so hello-agent's
2. [`vendor/rustdesk/Cargo.toml`](vendor/rustdesk/Cargo.toml): `config_import` can call the deploy-blob decoder.
* `mod ui_cm_interface``pub mod ui_cm_interface` so the headless
`--cm` process can plug a `MessageBoxW`-based `InvokeUiCM` into
upstream's connection-manager IPC loop and inherit file-transfer,
chat, and clipboard handling rather than re-implementing them.
2. **Build shape** — [`vendor/rustdesk/Cargo.toml`](vendor/rustdesk/Cargo.toml):
`[lib] crate-type` reduced from `["cdylib", "staticlib", "rlib"]` to `[lib] crate-type` reduced from `["cdylib", "staticlib", "rlib"]` to
`["rlib"]`. We statically link the rlib into hello-agent.exe; the `["rlib"]`. We statically link the rlib into hello-agent.exe; the
cdylib link step (used by upstream for Flutter FFI) trips cdylib link step (used by upstream for Flutter FFI) trips
`LNK1169 multiply-defined symbols` from overlapping `LNK1169 multiply-defined symbols` from overlapping
windows-targets/windows_x86_64_msvc versions and we don't need it. windows-targets/windows_x86_64_msvc versions and we don't need it.
3. Heartbeat intervals lowered 15s → 1s so device-online status in the 3. **Heartbeat cadence** lowered 15s → 1s so device-online status in
admin UI reacts faster: the admin UI reacts faster:
[`vendor/rustdesk/libs/hbb_common/src/config.rs`](vendor/rustdesk/libs/hbb_common/src/config.rs) [`libs/hbb_common/src/config.rs`](vendor/rustdesk/libs/hbb_common/src/config.rs)
(`REG_INTERVAL`, UDP rendezvous re-register) and (`REG_INTERVAL`, UDP rendezvous re-register) and
[`vendor/rustdesk/src/hbbs_http/sync.rs`](vendor/rustdesk/src/hbbs_http/sync.rs) [`src/hbbs_http/sync.rs`](vendor/rustdesk/src/hbbs_http/sync.rs)
(`TIME_HEARTBEAT`, HTTP `/api/heartbeat`). (`TIME_HEARTBEAT`, HTTP `/api/heartbeat`).
4. **Sysinfo upload extensions**
[`libs/hbb_common/src/config.rs`](vendor/rustdesk/libs/hbb_common/src/config.rs)
adds three opt-in `RwLock<String>` globals — `AGENT_NAME`,
`AGENT_VERSION`, `INVENTORY` — that hello-agent populates at startup
(rebrand identity) and asynchronously (CMDB inventory).
[`src/hbbs_http/sync.rs`](vendor/rustdesk/src/hbbs_http/sync.rs)
reads them when each `/api/sysinfo` payload is constructed and
tracks `had_inventory` on the `InfoUploaded` state so the loop
re-uploads when `INVENTORY` transitions empty → populated (the
collector is async and routinely loses the race against the first
sysinfo tick).
5. **Documentation / branding URLs** retargeted from `rustdesk.com` to
`cstudio.ch/hello-agent/`:
[`libs/hbb_common/src/config.rs`](vendor/rustdesk/libs/hbb_common/src/config.rs)
(`LINK_DOCS_HOME`, `LINK_DOCS_X11_REQUIRED`),
[`src/client.rs`](vendor/rustdesk/src/client.rs) (`SCRAP_X11_REF_URL`,
login-screen help link). Plus author / copyright strings in
[`Cargo.toml`](vendor/rustdesk/Cargo.toml) (`LegalCopyright`) and
[`src/main.rs`](vendor/rustdesk/src/main.rs) (`.author(...)`).
Cosmetic, but they show through in the Windows EXE metadata and
in-app error dialogs.
## Build ## Build
@@ -138,8 +179,13 @@ To pull updates from upstream RustDesk:
1. Sync the upstream rustdesk repo locally and `git submodule update --init` for `libs/hbb_common`. 1. Sync the upstream rustdesk repo locally and `git submodule update --init` for `libs/hbb_common`.
2. `rsync -a --delete --exclude=.git --exclude=target --exclude=flutter --exclude=appimage … upstream-rustdesk/ vendor/rustdesk/` 2. `rsync -a --delete --exclude=.git --exclude=target --exclude=flutter --exclude=appimage … upstream-rustdesk/ vendor/rustdesk/`
3. Re-apply the one-line `pub mod custom_server` patch in 3. Re-apply the local divergences enumerated in the
[`vendor/rustdesk/src/lib.rs`](vendor/rustdesk/src/lib.rs). [Repo layout](#repo-layout) section above (that list is the source
of truth — most patches carry a `hello-agent` breadcrumb in a
nearby comment, but a couple of one-token edits like
`pub mod custom_server` do not). The reliable recipe is to diff
against the upstream rev you rsync'd from before you do the rsync,
stash the patch hunks, then re-apply them on top of the new tree.
4. `cargo build --release --bin hello-agent` — fix any breakage from 4. `cargo build --release --bin hello-agent` — fix any breakage from
upstream API drift in our [src/](src/) modules. upstream API drift in our [src/](src/) modules.
@@ -243,7 +289,22 @@ it duplicates info that's already in the main log).
The only residual contention is the optional direct-server port The only residual contention is the optional direct-server port
(TCP 21118) and LAN-discovery port (UDP 21119); both default to off, (TCP 21118) and LAN-discovery port (UDP 21119); both default to off,
so a vanilla install of each side can run simultaneously. so a vanilla install of each side can run simultaneously.
- ✅ CMDB asset inventory — BIOS serial, manufacturer, model, AD domain,
OS edition + release, CPU, RAM, disks, BitLocker recovery key,
network interfaces, public IP, current + nearby Wi-Fi networks.
Collected once at startup ([`src/inventory.rs`](src/inventory.rs),
[`src/wifi_native.rs`](src/wifi_native.rs)) and merged into the
`/api/sysinfo` payload under the `inventory` key, where the
rustdesk-server admin UI's per-device detail page reads it.
- ✅ Unattended-access password — rotated once per service start
([`src/unattended_password.rs`](src/unattended_password.rs)) and
reported to rustdesk-server's `/api/unattended-password` so the admin
UI can show the current per-boot password for headless /
no-user-logged-in support sessions.
- ✅ Authenticode code signing in CI — separate Linux signing job runs
`osslsigncode` against the cStudio CA, with pre-/post-sign SHA-256
audit hashes that catch a tampered transit between build and sign
runners ([`.gitea/workflows/build-windows.yml`](.gitea/workflows/build-windows.yml)).
- ⏳ Linux / macOS (out of scope for v0) - ⏳ Linux / macOS (out of scope for v0)
- ⏳ Code signing (CI warns, doesn't sign)
- ⏳ Multiple simultaneous interactive users (only one can receive the - ⏳ Multiple simultaneous interactive users (only one can receive the
approval popup at a time — the one in the `WTSActive` session) approval popup at a time — the one in the `WTSActive` session)