198 lines
6.7 KiB
Markdown
198 lines
6.7 KiB
Markdown
# Hermes Pair (`hermes-pair`)
|
|
|
|
[](https://github.com/ochenstarik-ui/hermes-pair/actions/workflows/build.yml)
|
|
[](https://opensource.org/licenses/MIT)
|
|
|
|
Fast, lightweight, cross-platform pairing helper for **Hermes Agent** and the **Hermes Android App**.
|
|
|
|
`hermes-pair` bridges your host computer (running Hermes) with the mobile companion app by generating high-contrast QR codes and standard pairing URIs (`hermes://pair?data=...`) containing host network information, authentication state, and cryptographically secure random nonces.
|
|
|
|
---
|
|
|
|
## Features
|
|
|
|
- 🖥️ **Native GUI & Terminal UI Modes**: Runs as a lightweight native GUI window (`eframe`/`egui`) on desktop or an interactive/single-shot ANSI terminal interface on headless servers.
|
|
- 🔍 **Smart Network Interface Discovery**: Automatically discovers and prioritizes physical LAN interfaces (`192.168.x.x`, `10.x.x.x`, `172.16-31.x.x`) and Tailscale overlays (`100.x.x.x`), while filtering out loopback and link-local adapters.
|
|
- ⚡ **Real-Time Hermes Status Probing**: Connects to `http://127.0.0.1:<port>/api/status` and `http://<lan_ip>:<port>/api/status` to detect whether Hermes is active, verify version and auth requirements, and warn if Hermes is mistakenly bound only to loopback (`127.0.0.1`).
|
|
- 🛡️ **Built-in Security Safeguards**:
|
|
- Automatically warns if Hermes is exposed over LAN without authentication.
|
|
- Generates single-use, 16-byte cryptographically secure random nonces.
|
|
- Enforces configurable TTL expiry (default: 120 seconds).
|
|
- Validates payload structure, versioning, and UUID integrity.
|
|
- 💾 **Persistent Host Identity**: Manages a persistent UUIDv4 `host_id` saved atomically to `%APPDATA%\HermesPair\config.json` (Windows) or `~/.config/hermes-pair/config.json` (Linux).
|
|
|
|
---
|
|
|
|
## Pairing Protocol Specification (`v1`)
|
|
|
|
The generated QR code encodes a custom URI:
|
|
```text
|
|
hermes://pair?data=<BASE64URL_ENCODED_JSON>
|
|
```
|
|
|
|
### Decoded JSON Payload (`PairingPayloadV1`)
|
|
|
|
```json
|
|
{
|
|
"v": 1,
|
|
"type": "hermes-pair",
|
|
"host_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
|
|
"name": "Gaming-PC",
|
|
"host": "192.168.1.34",
|
|
"port": 9119,
|
|
"scheme": "http",
|
|
"expires_at": 1756012800,
|
|
"nonce": "k7a_QW9jRz1M..."
|
|
}
|
|
```
|
|
|
|
| Field | Type | Description |
|
|
|---|---|---|
|
|
| `v` | `u32` | Protocol schema version (`1`). |
|
|
| `type` | `string` | Payload identifier (`hermes-pair`). |
|
|
| `host_id` | `string` | Persistent UUIDv4 identifying the host machine. |
|
|
| `name` | `string` | Human-readable computer or host display name. |
|
|
| `host` | `string` | Reachable IPv4 address or hostname for the mobile client. |
|
|
| `port` | `u16` | HTTP port on which Hermes Agent is listening (e.g. `9119`). |
|
|
| `scheme` | `string` | Connection scheme (`http` or `https`). |
|
|
| `expires_at` | `u64` | Unix epoch timestamp (seconds) after which this payload is rejected. |
|
|
| `nonce` | `string` | 16 cryptographically random bytes, Base64URL-encoded. |
|
|
|
|
---
|
|
|
|
## Installation & Build
|
|
|
|
### Prerequisites
|
|
- [Rust](https://rustup.rs/) 1.80+ (tested on Rust 1.98.0)
|
|
|
|
### Building from Source
|
|
|
|
```bash
|
|
# Clone the repository
|
|
git clone https://github.com/ochenstarik-ui/hermes-pair.git
|
|
cd hermes-pair
|
|
|
|
# Run tests
|
|
cargo test
|
|
|
|
# Build release binary
|
|
cargo build --release
|
|
```
|
|
|
|
Release binaries are produced at:
|
|
- **Windows**: `target/release/hermes-pair.exe`
|
|
- **Linux**: `target/release/hermes-pair`
|
|
|
|
---
|
|
|
|
## Usage
|
|
|
|
### 1. Native GUI Mode (Default)
|
|
|
|
Simply execute `hermes-pair` without flags to open the native desktop window:
|
|
|
|
```bash
|
|
hermes-pair
|
|
```
|
|
|
|
#### GUI Controls:
|
|
- **Status Badge**: Shows Hermes connectivity (Running, Offline, Loopback Only) and auth status.
|
|
- **Network Interface Dropdown**: Switch between Wi-Fi, Ethernet, Tailscale, or virtual adapters.
|
|
- **[ 🔄 Regenerate QR ]**: Generates a new payload with a fresh nonce and resets the countdown.
|
|
- **[ 📋 Copy Link ]**: Copies `hermes://pair?data=...` directly to the system clipboard.
|
|
- **[ 🔄 Check ]**: Retries probing the Hermes status endpoint immediately.
|
|
|
|
### 2. Interactive Terminal UI Mode
|
|
|
|
For remote SSH sessions or terminals without a display server:
|
|
|
|
```bash
|
|
hermes-pair --terminal
|
|
# or short flag:
|
|
hermes-pair -t
|
|
```
|
|
|
|
Output:
|
|
```text
|
|
Hermes: Running (v1.2.0, Auth: Required)
|
|
Host: Gaming-PC
|
|
Address: http://192.168.1.34:9119
|
|
Host ID: 7b31d044...
|
|
Expires in: 01:58
|
|
|
|
██████████████████████████████
|
|
██ ██ ██ ██
|
|
██ ██████ ██ ██ ██████ ██
|
|
██ ██████ ██ ██ ██████ ██
|
|
██ ██ ██ ██
|
|
██████████████████████████████
|
|
...
|
|
Pairing Link: hermes://pair?data=eyJ2Ijox...
|
|
```
|
|
|
|
### 3. Headless / Single-Shot Script Mode
|
|
|
|
To print the QR code once to stdout (useful for automation, provisioning scripts, or terminal output piping):
|
|
|
|
```bash
|
|
hermes-pair qr
|
|
# or
|
|
hermes-pair --no-gui
|
|
```
|
|
|
|
### 4. Command Line Options
|
|
|
|
```text
|
|
Usage: hermes-pair [OPTIONS] [COMMAND]
|
|
|
|
Commands:
|
|
qr Output QR code once to stdout and exit
|
|
help Print this message or the help of the given subcommand(s)
|
|
|
|
Options:
|
|
-t, --terminal Run interactive terminal mode with periodic refresh
|
|
--no-gui Print QR once to stdout and exit (headless/script mode)
|
|
--port <PORT> Port of Hermes Agent [default: 9119]
|
|
--hermes-url <URL> Hermes status API URL (e.g. http://127.0.0.1:9119)
|
|
-i, --interface <INTERFACE> Specific network interface name or IPv4 address to advertise
|
|
--ttl <TTL> Pairing QR validity TTL in seconds [default: 120]
|
|
-h, --help Print help
|
|
-V, --version Print version
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration & Storage
|
|
|
|
`hermes-pair` generates a persistent `host_id` on first launch and stores it in JSON format:
|
|
|
|
- **Windows**: `%APPDATA%\HermesPair\config.json`
|
|
- **Linux / macOS**: `~/.config/hermes-pair/config.json`
|
|
|
|
Example configuration:
|
|
```json
|
|
{
|
|
"host_id": "7b31d044-cf64-4e78-9df2-bb58a8f5e1a1",
|
|
"display_name": "Studio-Workstation"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting & Warnings
|
|
|
|
### Warning: Loopback Only
|
|
If Hermes is started with default `127.0.0.1` binding, other devices on the LAN cannot connect.
|
|
Start Hermes binding to all interfaces:
|
|
```bash
|
|
hermes serve --host 0.0.0.0 --port 9119
|
|
```
|
|
|
|
### Warning: Unauthenticated Network Access
|
|
If Hermes has no authentication configured, any device on your local network could access the API. Consider enabling token or password authentication for production usage.
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
Licensed under the [MIT License](LICENSE).
|