Initial import: keyrelay, a WiFi-controlled USB HID keyboard
Browser or terminal controller drives an ESP32-S3 that acts as a Logitech G815 into a target machine running no software. Disarmed by default; arming requires the passphrase, the board button, or the serial console, and every fail-safe path cancels in-flight work. - src/: firmware with pure, host-testable modules (keystate, proto, text, ws_codec, sha1), the WebSocket control server, and the served page - tests/: host suites for the pure modules, relayctl parity, and page JS - tools/: relayctl terminal controller, serial console, bootloader helper, and an evdev target watcher - platformio.ini: bridge (USB HID) and console (no-HID) environments - README.md: single source of truth for behaviour, protocol and safety LLM-Generated: true
This commit is contained in:
+102
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* keyrelay -- build-time defaults.
|
||||
*
|
||||
* Everything here is a DEFAULT. The values stored in NVS win at runtime, so the
|
||||
* network and the control passphrase can be changed from the serial console
|
||||
* without reflashing (`wifi`, `ap`, `token` -- see README "First bring-up").
|
||||
*
|
||||
* Nothing secret belongs in this file. The default passphrase is deliberately
|
||||
* weak and loudly announced as such on the serial console and in the web page,
|
||||
* because a keyboard that anyone on the LAN can arm is an open door.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace kr {
|
||||
|
||||
constexpr const char kFirmwareName[] = "keyrelay";
|
||||
constexpr const char kFirmwareVersion[] = "1.0.0";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Network
|
||||
// ---------------------------------------------------------------------------
|
||||
// Control plane only: the keystrokes travel WiFi -> board -> USB. The target
|
||||
// machine provides nothing but 5 V and a USB port, and never sees a network.
|
||||
constexpr uint16_t kHttpPort = 80;
|
||||
constexpr char kHostname[] = "keyrelay"; // http://keyrelay.local
|
||||
|
||||
// Fallback access point, started whenever the station interface is not up, so
|
||||
// the board is reachable with no infrastructure at all (air-gapped target).
|
||||
constexpr char kApSsid[] = "keyrelay-ctl";
|
||||
constexpr char kApPass[] = "keyrelay-ctl-pass"; // >= 8 chars, WPA2. CHANGE IT.
|
||||
constexpr char kApGw[] = "192.168.4.1";
|
||||
|
||||
// Build-time station credentials (optional, still only a default). Override with
|
||||
// pio run -e bridge -D KR_STA_SSID='"MyNet"' -D KR_STA_PASS='"hunter2"'
|
||||
// without ever committing them.
|
||||
#ifndef KR_STA_SSID
|
||||
#define KR_STA_SSID ""
|
||||
#endif
|
||||
#ifndef KR_STA_PASS
|
||||
#define KR_STA_PASS ""
|
||||
#endif
|
||||
|
||||
constexpr uint32_t kStaTimeoutMs = 8000; // give the association attempt this long at boot
|
||||
constexpr uint32_t kStaRetryMs = 20000; // ... then retry in the background at this rate
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Control passphrase
|
||||
// ---------------------------------------------------------------------------
|
||||
// Checked on every WebSocket connection and on /status. The page cannot arm the
|
||||
// bridge without it, and nothing reaches the target until the bridge is armed.
|
||||
constexpr char kDefaultToken[] = "changeme";
|
||||
constexpr size_t kTokenMax = 32;
|
||||
constexpr uint8_t kTokenMaxFails = 5; // then stop evaluating the token ...
|
||||
constexpr uint32_t kTokenLockMs = 30000; // ... for this long
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Keystroke path
|
||||
// ---------------------------------------------------------------------------
|
||||
constexpr size_t kMaxKeysPerMessage = 8; // protocol cap (HID carries 6)
|
||||
constexpr uint32_t kCadHoldMs = 60; // how long Ctrl+Alt+Del is held down
|
||||
constexpr uint32_t kChordHoldMs = 40; // ditto for the other special chords
|
||||
constexpr uint32_t kMinReportGapUs = 1000; // 1 kHz floor: the host polls at 1 kHz
|
||||
constexpr size_t kReportQueueDepth = 48; // bursts from a fast typist
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Pasted text
|
||||
// ---------------------------------------------------------------------------
|
||||
// `P=<ms>:<hex>` (src/text.h) types a run of characters that a human pasted and
|
||||
// then deliberately sent. The board owns the character map and the pacing: a
|
||||
// controller's clock, arriving over WiFi in whatever order the network delivers
|
||||
// it, is not a keyboard timing source. The controller asks for a pace; the board
|
||||
// keeps it.
|
||||
//
|
||||
// One controller frame is still one command, so a frame carries at most
|
||||
// kTextFrameMax characters and a long paste arrives as several frames. The board
|
||||
// holds whatever it has been given and says so in `typing` in the status frame,
|
||||
// which is how a controller knows it may send the next piece.
|
||||
constexpr size_t kTextFrameMax = 120; // characters per P= frame
|
||||
constexpr size_t kTextJobCap = 2048; // characters held for one paste job
|
||||
constexpr uint16_t kTextPeriodMsDefault = 12; // ms per character when asked for 0
|
||||
constexpr uint16_t kTextPeriodMaxMs = 250; // slowest pace a controller may ask for
|
||||
constexpr uint16_t kTextHoldMaxMs = 6; // how long one character is held down
|
||||
|
||||
// Safety: a bridge that has heard nothing from its controller for this long is
|
||||
// a bridge that should not be typing. Arming never survives it (laptop slept,
|
||||
// cable unplugged, browser killed).
|
||||
constexpr uint32_t kNoClientTimeoutMs = 8000;
|
||||
|
||||
// Status heartbeat to the controller, and the interval of the held-key watchdog.
|
||||
constexpr uint32_t kStatusIntervalMs = 1000;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Control-server buffers
|
||||
// ---------------------------------------------------------------------------
|
||||
constexpr size_t kHttpHeaderCap = 1536; // reject a request line bigger than this
|
||||
constexpr size_t kWsMessageCap = 256; // one controller frame is a command, not a payload
|
||||
constexpr uint32_t kAuthTimeoutMs = 5000; // a new socket must authenticate this fast
|
||||
|
||||
} // namespace kr
|
||||
Reference in New Issue
Block a user