mbproxy: fix dashboard review findings, add named BCD tags + fleet config
Reviewed the new SignalR dashboard and fixed its two top findings: a stored XSS on the connection-detail page (unescaped tag name / direction / timestamp rendered into innerHTML) and FC03/FC04 cache hits bypassing the debug-view capture, which left cached tags frozen while their age climbed. Also adds an optional human-friendly Name to BCD tags surfaced on the debug view, and loads the real fleet config from tags.txt (12 named BCD tags, PLC Z28061) so the published appsettings.json is deploy-ready. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -158,6 +158,7 @@ The fleet-wide BCD tag list. Every PLC starts with this set, then applies its pe
|
||||
| `Address` | ushort | `0` | `[0, 65535]` | Modbus PDU address (decimal). Address `0` is valid on DL205/DL260 — do not skip it. Octal V-memory addresses must be converted: `V2000` octal = decimal `1024`. |
|
||||
| `Width` | byte | `0` | `{ 16, 32 }` | Bit width. `16` is one register holding 4 BCD digits (`0–9999`). `32` is a CDAB-ordered register pair at `Address` (low word) and `Address+1` (high word). |
|
||||
| `CacheTtlMs` | int? | `null` | `>= 0`, `<= 60000` unless `Cache.AllowLongTtl = true` | Optional per-tag opt-in to the response cache. `null` falls back to the PLC's `DefaultCacheTtlMs`. `0` explicitly disables caching for this tag even when the PLC default is non-zero. |
|
||||
| `Name` | string? | `null` | free-form | Optional human-friendly label (e.g. `"Left AirSP"`). Shown on the connection-detail debug view as the row heading. No effect on Modbus rewriting — purely a display aid. |
|
||||
|
||||
`MbproxyOptionsValidator` rejects any entry whose `Width` is not `16` or `32`. See [`../Features/BcdRewriting.md`](../Features/BcdRewriting.md) for the wire encoding rules and the multi-tag-overlap validation that runs in `BcdTagMapBuilder`.
|
||||
|
||||
|
||||
@@ -314,12 +314,15 @@ The UI is a Bootstrap 5 single-page app served from embedded assets under `src/M
|
||||
|
||||
The detail page's debug view is fed by an **on-demand per-tag value capture** (`Proxy/TagValueCapture.cs`, one per PLC, held in `Proxy/TagCaptureRegistry.cs`). The `BcdPduPipeline` records the last raw/decoded value for each configured BCD tag — but only while the capture is *armed*. `StatusHub` arms a PLC's capture when the first detail page subscribes and disarms it (clearing all slots) when the last viewer leaves, so the hot path carries zero cost when nobody is watching. The per-PLC payload is `PlcDetailResponse` (`src/Mbproxy/Admin/DebugDto.cs`):
|
||||
|
||||
> When the response cache is enabled, an FC03/FC04 **cache hit** bypasses the pipeline. To keep the debug view live for cached tags, each cache entry carries the tag observations captured when it was stored (only when a viewer was armed at that time); a hit replays them into the capture, re-stamped to the hit time. The debug view therefore reflects the value the client actually receives — cache-served reads included — not only backend round-trips.
|
||||
|
||||
| JSON path | Type | Meaning |
|
||||
|---|---|---|
|
||||
| `plc` | `PlcStatus?` | The standard per-PLC status row, or `null` if the PLC was removed by a hot-reload. |
|
||||
| `debug.captureArmed` | `bool` | Whether a detail page currently has the capture armed. |
|
||||
| `debug.tags[].address` | `int` | BCD tag PDU address. |
|
||||
| `debug.tags[].width` | `int` | 16 or 32. |
|
||||
| `debug.tags[].name` | `string?` | Optional human-friendly tag label from config (`BcdTags[].Name`); `null` when unset. Shown as the debug-row heading, with the PDU address as sub-text. |
|
||||
| `debug.tags[].hasValue` | `bool` | `false` until the first observation since the capture was armed. |
|
||||
| `debug.tags[].direction` | `string` | `"read"` (FC03/FC04) or `"write"` (FC06/FC16). |
|
||||
| `debug.tags[].rawHex` | `string` | Raw PLC-side value as BCD nibbles — `0xLLLL` (16-bit) or `0xHHHHLLLL` (32-bit). |
|
||||
|
||||
Reference in New Issue
Block a user