--- module: agent.remote title: Remote Control Module — on-demand screen capture & file access on ATMs tab: Internal order: 20 audience: dev --- > **Internal · ops/support view.** Confirmed against `hiveops-module-remote` source (`RemoteModule`, agent parent v4.4.3) on 2026-07-01. ## What it does (and doesn't) `hiveops-module-remote` (module name `hiveops-remote`, class `com.hiveops.remote.module.RemoteModule`) is **not** a monitor and does **not** emit incident/journal events. It is an **on-demand remote-control executor**. It sits idle, registers with the **HiveIQ Remote server** (`hiveops-remote`, internal port 8090), long-polls it for a single queued command, executes it, and uploads the binary result back. There is no continuous monitoring, no baseline, and no `IAT_*` / `EventType` reporting from this module. Supported commands (the module's advertised `capabilities`): | Capability | What the agent does | |---|---| | `SCREENSHOT` | Captures the ATM's display via AWT `Robot`, encodes JPEG, uploads bytes in chunks | | `FILE_LIST` | Lists a directory (name, size, mtime, type, POSIX perms) and returns JSON | | `FILE_DOWNLOAD` | Streams a single file's bytes back in chunks | `SYSTEM_INFO` exists in the `CommandType` enum but is **not** advertised as a capability and is **not** handled — if the server ever sends it the agent replies `FAILED: Unknown command type`. Flow at a glance: 1. On `start()`, the module `POST`s to `/api/v1/agents/register` on the remote server and stores the returned Bearer token. 2. It polls `GET /api/v1/agents/poll` every **5s** (`remote.poll.interval.ms`). 3. When `hasCommand=true`, it sets the command `IN_PROGRESS`, runs it, then reports `COMPLETED` (with result/binary) or `FAILED`. 4. Binary results (screenshot JPEG, file bytes) are uploaded in **1 MiB** chunks with a per-chunk SHA-256 checksum to `POST /api/v1/agents/commands/{id}/upload`. > This module talks to the **hiveops-remote** service (`/api/remote/`, port 8090) — **not** to agent-proxy or hiveops-incident. It is a separate path from the standard journal/event pipeline. ## Config properties it registers Registered in `getDefaultConfiguration()` (namespace `remote.*`): | Key | Default | Meaning | |---|---|---| | `remote.enabled` | `false` | Master on/off. Module only loads when `true`. | | `remote.server.url` | `http://localhost:8090` | Remote-server base URL. **Required** — init throws if blank. | | `remote.poll.interval.ms` | `5000` | Delay between polls for a queued command. | | `remote.poll.timeout.ms` | `15000` | Registered default, but **not referenced anywhere in code** (no effect — unverified whether wired in a newer build). | | `remote.chunk.size.bytes` | `1048576` | Upload chunk size (1 MiB) for binary results. | | `remote.max.file.size.bytes` | `104857600` | Max file size (100 MiB) for `FILE_DOWNLOAD`; larger files fail. | Also read at init but **not** in the defaults set (must be added explicitly to take effect): | Key | Default if unset | Meaning | |---|---|---| | `remote.machine.id` | derived from hostname (then random UUID) | Stable machine identity sent at registration. | | `remote.allowed.paths` | *(empty = all paths allowed)* | Comma/semicolon list; if set, file ops are restricted to these base dirs. | | `remote.blocked.paths` | OS default block list | Comma/semicolon list of blocked path patterns (`*` wildcard). Defaults block `/etc/shadow`, `/etc/passwd`, `/etc/sudoers`, `/root/.ssh`, `/home/*/.ssh` (Linux) and `C:\Windows\System32\config`, `...\drivers`, credential stores (Windows). | ## Enabled / deployed to ATMs - **Enable condition:** module self-enables only when `remote.enabled=true`. It is **off by default**. Turn it on for a device/institution with a `CONFIG_UPDATE` fleet task setting `remote.enabled=true` (and, on locked-down ATMs, `remote.allowed.paths`). - **Shipped how:** it's a drop-in JAR (`modules/hiveops-module-remote.jar`), not baked into the fat JAR. Jackson is shaded into the JAR (hiveops-core is `provided`). - **Retrofitting an ATM that doesn't have the JAR:** deliver via a fleet `INSTALL_MODULE` task — it drops the JAR into `modules/` and restarts the agent (`ProcessInstallModule`). The filename must end in `.jar`. ## Common failure modes / what to check | Symptom | Likely cause | What to check | |---|---|---| | Module never registers / no commands run | `remote.enabled` not `true`, or module JAR absent | Confirm `remote.enabled=true` and that `modules/hiveops-module-remote.jar` is present; check agent log for `Initializing remote module for server: ...` | | Init fails: `remote.server.url is required` | Property blank/missing | Set `remote.server.url` to the remote server (prod path is via `/api/remote/`, internal `:8090`). | | Registration logs `Failed to register with remote server` | Server unreachable / auth rejected | Registration errors are swallowed (no retry loop) — the module keeps polling with a null token, so polls 401. Verify network path to the remote server and that it accepts the registration payload. | | `SCREENSHOT` fails: `Screen capture not available in headless mode` | ATM/JVM is headless (no X display / service session) | Screen capture needs a real graphics environment + AWT `Robot`. Headless Linux boxes and some Windows service sessions can't capture. | | `FILE_DOWNLOAD` fails: `File exceeds maximum size limit` | File > `remote.max.file.size.bytes` (100 MiB default) | Raise the limit via config, or collect large files with a fleet `FILECOLLECT`/`LOG_COLLECT` task instead. | | File op fails: `Access to path is blocked` / `Path is not within allowed directories` | Hit a `remote.blocked.paths` pattern, or path is outside `remote.allowed.paths` | Expected security behavior — adjust the allow/block lists if the target should be reachable. | | File op fails: `Path contains directory traversal sequences` / `null bytes` | Path contained `..` or `\0` | Path-traversal guard (`PathSecurityUtils`) — send a normalized absolute path. | | Upload fails mid-transfer | Network drop, or server rejected a chunk (checksum/size) | Uploads are **not** retried by this module — the command goes `FAILED`. Re-issue the command. |