Tests / Test failed: 4, passed: 744
Replace hand-written f-string + html.escape() rendering in the Host Agent
local console with a module-level Jinja2 Environment configured with
select_autoescape(["html","xml"]). XSS safety now holds by mechanism
rather than per-call discipline — every operator-controlled field
(device name, connection_info, task summary, etc.) is escaped by the
engine uniformly.
Eight templates under host_agent/web/templates/ replace the former
_chrome(), _CSS, escape(), and per-page _xxx_body() helpers: base.html
(header/nav/CSS + {% block body %}), login, dashboard (with the polling
<script> preserved byte-identically inside {% raw %}), devices, account,
history, tasks_list, and task_detail. The task-list and task-detail
templates — added by the just-landed task-execution-progress-visibility
change — were also migrated here rather than left in f-string form,
since this change removes the shared helpers they depended on.
URLs, auth/session/CSRF semantics, redirects, and /api/status JSON are
unchanged. 15 new template tests cover render-smoke, XSS probing, script
byte-identity, and no-autoescape-bypass guards. Tasks 8.1-8.6 (manual
browser verification) remain.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
38 lines
1.7 KiB
HTML
38 lines
1.7 KiB
HTML
{% extends "base.html" %}
|
|
{% block body %}
|
|
<h1>Devices</h1>
|
|
{% if error %}
|
|
<p class="error">{{ error }}</p>
|
|
{% endif %}
|
|
<table>
|
|
<thead><tr><th>ID</th><th>Name</th><th>Driver</th><th>Cloud ID</th><th></th></tr></thead>
|
|
<tbody>{% for device in devices %}
|
|
<tr>
|
|
<td>{{ device["device_id"] }}</td>
|
|
<td>{{ device["name"] or "" }}</td>
|
|
<td>{{ device["driver_type"] }}</td>
|
|
<td>{{ device["cloud_device_id"] or "" }}</td>
|
|
<td>
|
|
<a href="/devices?edit={{ device["device_id"] }}">Edit</a>
|
|
<form class="inline" method="post" action="/devices/remove">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<input type="hidden" name="device_id" value="{{ device["device_id"] }}">
|
|
<button type="submit">Remove</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}</tbody>
|
|
</table>
|
|
<h2>{{ "Edit device" if edit_record else "Add device" }}</h2>
|
|
<form method="post" action="/devices/save">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<label>Device ID <input type="text" name="device_id" value="{{ edit_record["device_id"] if edit_record else "" }}" required></label><br>
|
|
<label>Name <input type="text" name="name" value="{{ edit_record["name"] if edit_record else "" }}"></label><br>
|
|
<label>Driver type <input type="text" name="driver_type" value="{{ edit_record["driver_type"] if edit_record else "wda" }}" required></label><br>
|
|
<label>Connection info (JSON)<br>
|
|
<textarea name="connection_info" rows="3" cols="50">{{ connection_info_json }}</textarea>
|
|
</label><br>
|
|
<button type="submit">Save</button>
|
|
</form>
|
|
{% endblock %}
|