f8ead215d8
build-windows / build-hello-agent-x64 (push) Successful in 5m41s
A single-binary, Flutter-free remote-support agent that speaks the stock
RustDesk wire protocol. Designed for one-line MDM deployment against a
self-hosted rustdesk-server: a supporter using the unmodified rustdesk.exe
client connects, the controlled-side user gets a native Win32 approval
prompt, click Yes / No.
CLI surface
hello-agent.exe --install # register + start service
hello-agent.exe --uninstall # stop, delete, clean up
hello-agent.exe --config <BLOB> # admin-UI deploy string
hello-agent.exe --install --config <BLOB> # MDM one-liner
--config accepts both forms emitted by the rustdesk-server admin UI: the
reversed-base64 deploy string and the host=,key=,api=,relay= filename
form. Decoded via the upstream custom_server module, persisted via
hbb_common::config::Config::set_option.
Architecture
--service runs as a Session 0 LocalSystem service. It polls
WTSGetActiveConsoleSessionId and (re)spawns hello-agent.exe --server
into the active console session via librustdesk::platform::run_as_user,
handling the Session 0 → user-session token impersonation.
--server is the worker. It boots three concurrent components:
1. cm_popup: an IPC listener on the rustdesk `_cm` named pipe
2. librustdesk::start_server(true, false): the upstream protocol
stack — rendezvous mediator, NAT punch, IPC server, screen
capture, login validation, hbbs_http heartbeat / sysinfo sync
3. (implicit) ApproveMode::Click is pinned in config, so every
incoming connection routes through cm_popup
The popup mechanism reuses an existing upstream contract without any
patches to the protocol code: when a peer connects with no password,
Connection::start in the upstream code calls try_start_cm_ipc, which
ipc::connect-s the `_cm` pipe before falling back to spawning a Flutter
CM child. Since cm_popup is up first, step 1 succeeds; we read the
Data::Login{authorized:false} frame, show MessageBoxTimeoutW (Yes/No,
60s, top-most, system-modal), and reply Data::Authorize or Data::Close.
Source tree
src/main.rs CLI dispatcher + run_server() composition
src/cli.rs hand-rolled argv parser + unit tests
src/service.rs windows-service install/uninstall/dispatcher
src/config_import.rs --config blob decoding + persistence
src/cm_popup.rs _cm IPC listener + Win32 approval dialog
Vendoring
The upstream RustDesk crate is vendored under vendor/rustdesk/ — full
workspace including libs/{hbb_common, scrap, enigo, clipboard,
virtual_display, remote_printer}. This makes the build self-contained
(no submodules, no sibling-repo checkout in CI) and gives us freedom to
fork in a different direction later. Excluded from the vendor: .git,
target/, flutter/, appimage/, flatpak/, fastlane/, docs/, examples/,
ci/, build.py, Dockerfile, upstream README/CLAUDE/AGENTS/GEMINI.
One local divergence vs. upstream: vendor/rustdesk/src/lib.rs flips
`mod custom_server` → `pub mod custom_server` so config_import.rs can
call get_custom_server_from_string without going through the
ui_interface shim. Documented in README.md → "Re-syncing the vendored
copy".
CI
.gitea/workflows/build-windows.yml builds on a self-hosted Windows
runner with Rust 1.75, LLVM 15.0.6 (libclang for bindgen via libvpx-sys),
and a vcpkg cache. The vendored vcpkg.json drives x64-windows-static
deps. The workflow stages the resulting hello-agent.exe into
SignOutput\, reports authenticode signing status (warns on unsigned),
and uploads as artifact. ~15 min full build, faster on incremental.
Out of scope for this commit: Linux/macOS builds, code signing, MSI
packaging, coexistence with stock rustdesk on the same box (currently
shares the RustDesk APP_NAME and config dir).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
89 lines
4.2 KiB
XML
89 lines
4.2 KiB
XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
<svg
|
|
style="isolation:isolate"
|
|
viewBox="66.993 897.484 32 32.000001"
|
|
version="1.1"
|
|
id="svg11"
|
|
sodipodi:docname="design.svg"
|
|
xml:space="preserve"
|
|
inkscape:export-filename="216333102-4d10c195-be66-4fa0-97ca-70a71756b25e.png"
|
|
inkscape:export-xdpi="3733.2917"
|
|
inkscape:export-ydpi="3733.2917"
|
|
inkscape:version="1.2.2 (b0a84865, 2022-12-01)"
|
|
width="32"
|
|
height="32"
|
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
|
id="defs15"><linearGradient
|
|
inkscape:collect="always"
|
|
xlink:href="#a"
|
|
id="linearGradient765"
|
|
gradientUnits="userSpaceOnUse"
|
|
gradientTransform="matrix(26.000475,0,0,25.999358,17.984526,891.74869)"
|
|
x1="0.14773831"
|
|
y1="0.85134232"
|
|
x2="0.84543866"
|
|
y2="0.15443686" /></defs><sodipodi:namedview
|
|
id="namedview13"
|
|
pagecolor="#ffffff"
|
|
bordercolor="#000000"
|
|
borderopacity="0.25"
|
|
inkscape:showpageshadow="2"
|
|
inkscape:pageopacity="0.0"
|
|
inkscape:pagecheckerboard="0"
|
|
inkscape:deskcolor="#d1d1d1"
|
|
showgrid="false"
|
|
inkscape:zoom="1.8436908"
|
|
inkscape:cx="11.119001"
|
|
inkscape:cy="90.307984"
|
|
inkscape:window-width="1440"
|
|
inkscape:window-height="847"
|
|
inkscape:window-x="0"
|
|
inkscape:window-y="25"
|
|
inkscape:window-maximized="1"
|
|
inkscape:current-layer="svg11"
|
|
showguides="true" /><linearGradient
|
|
id="a"
|
|
x1="0.14773831"
|
|
x2="0.84543866"
|
|
y1="0.85134232"
|
|
y2="0.15443686"
|
|
gradientTransform="matrix(26.301,0,0,26.331,90.673535,911.7572)"
|
|
gradientUnits="userSpaceOnUse"><stop
|
|
offset="0"
|
|
stop-color="#004ba6"
|
|
id="stop4"
|
|
style="stop-color:#0071ff;stop-opacity:1;" /><stop
|
|
offset="1"
|
|
stop-color="#00bfe1"
|
|
id="stop6"
|
|
style="stop-color:#00bfe1;stop-opacity:1;" /></linearGradient><g
|
|
id="g763"
|
|
inkscape:export-filename="../../Desktop/path9.png"
|
|
inkscape:export-xdpi="768"
|
|
inkscape:export-ydpi="768"
|
|
transform="translate(52.008497,8.73577)"><g
|
|
id="g761"
|
|
inkscape:export-filename="./g369.png"
|
|
inkscape:export-xdpi="3733.2917"
|
|
inkscape:export-ydpi="3733.2917"><rect
|
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
|
id="rect757"
|
|
width="32"
|
|
height="32"
|
|
x="14.984506"
|
|
y="888.74823"
|
|
rx="5"
|
|
ry="5" /><path
|
|
fill="url(#a)"
|
|
d="m 40.309479,897.8163 -2.13532,2.12189 c -0.37566,0.3367 -0.557321,0.87878 -0.34675,1.33694 1.422559,2.97602 0.882559,6.52382 -1.45146,8.85602 -2.33502,2.33131 -5.88696,2.8707 -8.866524,1.44881 -0.43892,-0.1965 -0.953964,-0.03 -1.292057,0.31269 l -2.169919,2.16641 c -0.255052,0.2498 -0.3806,0.6023 -0.34007,0.95579 0.04054,0.3545 0.243189,0.6695 0.54767,0.8541 5.1129,3.09451 11.678999,2.30561 15.911089,-1.9116 4.232081,-4.2162 5.03876,-10.77258 1.9554,-15.88729 -0.17696,-0.31103 -0.48935,-0.52234 -0.84425,-0.5717 -0.35489,-0.0503 -0.71276,0.0681 -0.967809,0.31794 z M 21.84293,895.5107 c -4.252844,4.20042 -5.086212,10.75775 -2.019657,15.88535 0.176955,0.312 0.488356,0.5233 0.843254,0.5727 0.354897,0.05 0.712761,-0.0679 0.968802,-0.319 l 2.123457,-2.1091 c 0.384554,-0.3367 0.572151,-0.8847 0.358619,-1.3488 -1.422557,-2.976 -0.883552,-6.52373 1.451458,-8.85593 2.334022,-2.33127 5.886947,-2.87085 8.865525,-1.44997 0.433981,0.19451 0.94211,0.033 1.281191,-0.29971 l 2.181779,-2.1792 c 0.255051,-0.24884 0.380601,-0.60134 0.340071,-0.95581 -0.04149,-0.35349 -0.24319,-0.66847 -0.54767,-0.85411 -5.121801,-3.06787 -11.678015,-2.25523 -15.893292,1.97185 z"
|
|
id="path759"
|
|
inkscape:export-filename="../../Desktop/path9.png"
|
|
inkscape:export-xdpi="2599.3848"
|
|
inkscape:export-ydpi="2599.3848"
|
|
style="fill:url(#linearGradient765);stroke-width:0.987991"
|
|
sodipodi:nodetypes="ccccccccccccccccccccccccccc" /></g></g></svg>
|