mirror of
https://github.com/UNITRONIX/BetterDesk.git
synced 2026-10-26 14:30:19 +00:00
d514ffc18b
Operators can switch a BetterDesk Desktop client between normal and incoming-only. The command is stored per device and delivered only inside the signed telemetry envelope. Thanks: INSOLVE (Honorary); Marco Jakobs (@jacotec); MyNameisStitch (@MyNameisStitch); Redspin (@playerumpknow)
149 lines
5.5 KiB
Markdown
149 lines
5.5 KiB
Markdown
# BetterDesk device telemetry contract
|
|
|
|
Version: `1`
|
|
|
|
This contract is shared by BetterDesk desktop clients, the Go server, and the
|
|
web console. It is additive to the RustDesk-compatible `/api/heartbeat` and
|
|
`/api/sysinfo` endpoints.
|
|
|
|
## Device modes
|
|
|
|
`product_sku` is authoritative for product behavior:
|
|
|
|
- `betterdesk-desktop`: managed desktop agent. The UI may show all capabilities
|
|
that the operating system and policy permit.
|
|
- `betterdesk-support`: Support Agent. It is incoming-only and must not be
|
|
promoted to a managed agent by a server strategy.
|
|
|
|
`conn_mode` is `normal` or `incoming-only`. The server must enforce both the
|
|
SKU and the operator permission; client-reported capabilities are never an
|
|
authorization decision by themselves.
|
|
|
|
## Collection status
|
|
|
|
Every optional collector may return one of these short codes:
|
|
|
|
`ok`, `unsupported`, `permission_denied`, `unavailable`, `error`.
|
|
|
|
The payload may include a short, localized-by-the-panel `message_key`, but
|
|
must not include stack traces, command output, usernames, paths, or secrets.
|
|
|
|
## Heartbeat envelope
|
|
|
|
The existing heartbeat remains small and frequent. New clients may include:
|
|
|
|
```json
|
|
{
|
|
"telemetry_schema": 1,
|
|
"id": "DEVICE_ID",
|
|
"uuid": "DEVICE_UUID",
|
|
"product_sku": "betterdesk-desktop",
|
|
"conn_mode": "normal",
|
|
"capabilities": ["telemetry.metrics", "inventory.hardware"],
|
|
"telemetry": {
|
|
"sample_id": "uuid",
|
|
"collected_at": "2026-09-12T17:00:00Z",
|
|
"metrics": {
|
|
"cpu_percent": 12.5,
|
|
"memory_percent": 44.1,
|
|
"disk_percent": 61.0
|
|
},
|
|
"status": {"metrics": "ok", "hardware": "unavailable"}
|
|
}
|
|
}
|
|
```
|
|
|
|
Legacy `cpu`, `memory`, and `disk` fields remain accepted and are mapped to the
|
|
same metric sample. Samples are idempotent by `(device_id, sample_id)`.
|
|
|
|
Recommended defaults:
|
|
|
|
- heartbeat/status: existing client interval;
|
|
- resource sample: 60 seconds, configurable by server policy;
|
|
- hardware inventory: once per 24 hours, plus an authenticated refresh command;
|
|
- services/processes/events: cached snapshots, normally no more often than every
|
|
5 minutes;
|
|
- activity: opt-in, aggregated application/window metadata only, no URLs,
|
|
document contents, keystrokes, screenshots, or clipboard data.
|
|
|
|
## Inventory and cached snapshots
|
|
|
|
Inventory and snapshots are sent as bounded records:
|
|
|
|
```json
|
|
{
|
|
"telemetry_schema": 1,
|
|
"device_id": "DEVICE_ID",
|
|
"kind": "hardware",
|
|
"sample_id": "uuid",
|
|
"collected_at": "2026-09-12T17:00:00Z",
|
|
"status": "ok",
|
|
"data": {}
|
|
}
|
|
```
|
|
|
|
Supported `kind` values are `hardware`, `services`, `processes`, `events`, and
|
|
`activity`. The server stores only the latest inventory plus bounded history.
|
|
Events and activity have independent retention policies.
|
|
|
|
## Commands
|
|
|
|
Commands are addressed to one device and contain a unique `command_id`,
|
|
`command`, bounded `args`, an expiry, and the operator audit identity. The
|
|
agent returns `queued`, `ok`, `rejected`, `unsupported`, `permission_denied`,
|
|
or `error`. Service changes, process termination, file writes/deletes, and
|
|
downloads require an explicit capability and operator permission.
|
|
|
|
Commands must be allowlisted. An arbitrary shell command is not part of this
|
|
contract.
|
|
|
|
## Desktop connection mode
|
|
|
|
Operators with `device.connection_mode` may switch a BetterDesk Desktop client
|
|
between `normal` and `incoming-only`:
|
|
|
|
`POST /api/peers/{id}/connection-mode` with `{ "mode", "reason" }`.
|
|
|
|
The panel exposes the same action as `POST /api/devices/{id}/connection-mode`.
|
|
The server stores the requested mode per device and delivers
|
|
`connection_mode_command` only inside a sealed `betterdesk_envelope` on
|
|
heartbeat. Plaintext heartbeats, `strategy`, and `config_options` never carry
|
|
the command. Retries keep the same `command_id` and revision. A command that
|
|
expires is not replaced by an automatic return to `normal`.
|
|
|
|
Control requires a signed identity of `product_sku=betterdesk-desktop` and
|
|
capability `connection-mode.remote-control`. `betterdesk-support` stays
|
|
incoming-only. A desktop client that reports `incoming-only` remains a desktop
|
|
client; only a missing SKU plus `incoming-only` is still treated as a legacy
|
|
Support Agent.
|
|
|
|
The next signed heartbeat may report `effective_conn_mode`, `policy_revision`,
|
|
`policy_status`, `last_command_id`, and `policy_error`.
|
|
|
|
## Application-level protection
|
|
|
|
HTTPS/WSS remains the required production transport. For deployments that
|
|
still expose HTTP, telemetry may additionally use an envelope containing:
|
|
|
|
- a server deployment public key for authenticated encryption;
|
|
- a signed X25519 key fetched from `/api/telemetry/key`, verified against the
|
|
BetterDesk server public key configured in the client's existing `key`
|
|
connection setting;
|
|
- a device key for signing;
|
|
- a unique nonce and monotonic sequence;
|
|
- the schema version and device ID as authenticated additional data.
|
|
|
|
The server rejects invalid signatures, stale sequences, mismatched device IDs,
|
|
and payloads above the endpoint limit. BetterDesk heartbeats and command
|
|
responses use the same envelope when the signed key is available. Private
|
|
keys never leave their owner. Ordinary RustDesk heartbeats remain
|
|
plaintext-compatible and are classified as `RustDesk` when no BetterDesk
|
|
identity fields are present.
|
|
|
|
After the first authenticated device heartbeat, BetterDesk JSON API requests
|
|
may use `X-BetterDesk-Envelope: 1` and `X-BetterDesk-Device`. The server
|
|
decrypts the request before invoking the normal handler and encrypts the
|
|
response. Bootstrap endpoints such as login, enrollment, branding, health,
|
|
and `/api/telemetry/key` remain compatible so a device can establish identity.
|
|
Production deployments should still use HTTPS/WSS.
|