Dingtian harden(): rotate the admin/admin web login (cosmetic)
harden() now rotates the device's default admin/admin web-UI login via GET /userset.cgi?<old>&<old>&<new>&<new>& (best-effort: a failure logs and doesn't fail the assign). The new password is stored back in config (webUser/webPassword) so a re-run can rotate again, and is stripped from the assign response like the push secret. Documented the load-bearing caveat: this device's CGI API is fully UNAUTHENTICATED — config read/write, relay fire, and userset.cgi itself all return 200 with no credentials (verified on hardware). admin/admin gates only the browser UI, and there's no inbound-auth setting (only session_en, which bricks the read API). So the rotation is defence-in- depth for the UI, NOT a boundary; the signed event log remains the real anti-fraud guarantee. Verified rotation end-to-end on 10.0.10.5 (success &0&, wrong-old-pw &2&); device left at admin/admin.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
type: entity
|
||||
tags: [parking, hardware, access-control, relay]
|
||||
sources: []
|
||||
updated: 2026-06-15
|
||||
updated: 2026-06-14
|
||||
---
|
||||
|
||||
# Dingtian Relay Controller
|
||||
@@ -49,8 +49,8 @@ see [[dingtian-vs-mqtt]].
|
||||
The `dingtian` driver ([[device-registry]]) implements three capabilities:
|
||||
`AccessControlDevice` (relay pulse/latch over UDP), `InputDevice` (read inputs + poll-based
|
||||
press/release events ~50 ms), and `PreconditionDevice` (below). Config fields include a separate
|
||||
**`httpPort`** — the device's web/config API is on a configurable HTTP port (this unit: **8080**,
|
||||
not the default 80), distinct from the UDP control port 60001.
|
||||
**`httpPort`** — the device's web/config API is on a configurable HTTP port (default **80**),
|
||||
distinct from the UDP control port 60001.
|
||||
|
||||
### Precondition: input_link_relay must be OFF
|
||||
|
||||
@@ -79,6 +79,31 @@ the relay via UDP. See [[device-input-flow]] for the full path + trust model.
|
||||
> real path** — lower latency, and it can be authenticated (the device supports Basic/Digest +
|
||||
> HTTPS on the push), unlike the open UDP control direction.
|
||||
|
||||
## Hardening (`harden()`) — and why HTTP auth is not a boundary here
|
||||
|
||||
On assign the driver runs `harden()` (the [[device-registry|HardenableDevice]] capability):
|
||||
1. **`relay_pw`** — set a random relay password so binary relay commands (UDP 60000) need it.
|
||||
2. **Disable unused channels** — set `p:255` on rs485/can/tcp×2/mqtt; keep only UDP1 binary
|
||||
(relay control) + UDP2 string (status read).
|
||||
3. **Rotate the `admin`/`admin` web login** — `GET /userset.cgi?<old_u>&<old_p>&<new_u>&<new_p>&`
|
||||
(response `&0&…&` = success, verified on hardware). The new password is stored back in
|
||||
config (`webUser`/`webPassword`) so a re-run can rotate again (the device checks the *old*
|
||||
creds). This step is **best-effort** — a failure logs and does not fail the assign.
|
||||
|
||||
> ⚠️ **The device CGI API is UNAUTHENTICATED.** Verified on hardware: `GET /api/v2/config.cgi`,
|
||||
> `/`, and even `/userset.cgi` all return **200 with no credentials**. The `admin`/`admin` login
|
||||
> gates only the interactive **browser UI** — the CGI control plane (read/write full config, fire
|
||||
> relays, change the password) bypasses it entirely. The `http` config block has **no** setting to
|
||||
> require Basic/Digest on inbound requests; the only inbound gate is `session_en`, which **bricks
|
||||
> the config-read API on this firmware** (the factory-reset incident — *do not enable it*). So
|
||||
> **rotating the login is cosmetic** (stops a casual browser reaching settings); it is **not** a
|
||||
> boundary. On this flat, no-VLAN network the device control plane is effectively open — the
|
||||
> **signed event log is the real anti-fraud guarantee**. See [[device-input-flow]].
|
||||
|
||||
> ⚠️ **`session_en` must stay OFF.** Enabling the HTTP CGI session check makes the config-read API
|
||||
> drop connections (ECONNRESET), locking out the API the driver depends on — recoverable only by
|
||||
> factory reset. `harden()` deliberately never touches it.
|
||||
|
||||
## Status — VERIFIED on hardware (DT-R004, sw V3.1.5461A, 10.0.10.172)
|
||||
|
||||
- ✅ status read (`0000:1111:4`), relay pulse, input press/release events (active-LOW, idle HIGH).
|
||||
@@ -89,4 +114,7 @@ the relay via UDP. See [[device-input-flow]] for the full path + trust model.
|
||||
button presses (all 4 inputs) **pushed to the backend** (`/input/N/on` + `/off` per press,
|
||||
source = the device IP). No polling. Host-in-the-loop entry (`button → backend → ticket →
|
||||
backend opens relay`) is real.
|
||||
- ✅ **Web-login rotation** — `userset.cgi` rotates `admin`/`admin` (response `&0&/&`; wrong old
|
||||
password → `&2&/&`). Confirmed the device validates the old creds. **Also confirmed the CGI API
|
||||
needs NO auth** (config dump + `userset.cgi` return 200 unauthenticated) → rotation is cosmetic.
|
||||
- ⬜ Next: wire the actual entry flow (input event → signed event + print ticket → `pulseOpen`).
|
||||
|
||||
Reference in New Issue
Block a user