fix(ui): delete prompts use data-confirm, so a quote in a name no longer runs script (#5099)
#5099 "A name containing a quote runs script when an admin clicks Delete". Inline handlers like onclick="return confirm('Delete {{ rule.name }}?')" are HTML-decoded before the JavaScript is parsed, so autoescaping did not stop a name such as x');fetch(…);// from running. - Every prompt (22 handlers, plus the docker prune and token revoke ones) is now data-confirm="…", read through dataset by one submit listener in base.html; nothing rendered is parsed as JavaScript. - The remaining inline handlers take integers only (|int), and the time range buttons pass this.dataset.range. - tests/test_inline_handlers.py fails on any {{ }} in an inline handler that is not |int, with a self-test; tests/_templates.py is the one template walker the template guards now share. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -46,7 +46,7 @@
|
||||
{% endif %}
|
||||
|
||||
<button class="btn btn-ghost btn-sm" style="font-size:0.78rem;"
|
||||
onclick="toggleAnsibleEdit({{ idx }})">Edit</button>
|
||||
onclick="toggleAnsibleEdit({{ idx|int }})">Edit</button>
|
||||
|
||||
<button class="btn btn-danger btn-sm" style="font-size:0.78rem;"
|
||||
hx-post="/settings/ansible/sources/{{ idx }}/remove"
|
||||
@@ -72,7 +72,7 @@
|
||||
<div class="form-group" style="margin:0;">
|
||||
<label style="font-size:0.8rem;">Type</label>
|
||||
<select name="type" id="ansible-edit-type-{{ idx }}"
|
||||
onchange="updateAnsibleEditFields({{ idx }})">
|
||||
onchange="updateAnsibleEditFields({{ idx|int }})">
|
||||
<option value="local" {% if src.type == 'local' %}selected{% endif %}>local</option>
|
||||
<option value="git" {% if src.type == 'git' %}selected{% endif %}>git</option>
|
||||
</select>
|
||||
@@ -118,7 +118,7 @@
|
||||
<div style="display:flex;gap:0.5rem;margin-top:0.75rem;">
|
||||
<button type="submit" class="btn btn-sm">Save</button>
|
||||
<button type="button" class="btn btn-ghost btn-sm"
|
||||
onclick="toggleAnsibleEdit({{ idx }})">Cancel</button>
|
||||
onclick="toggleAnsibleEdit({{ idx|int }})">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</div>
|
||||
<div style="display:flex;gap:0.4rem;flex-shrink:0;">
|
||||
<button class="btn btn-ghost btn-sm" style="font-size:0.78rem;"
|
||||
onclick="toggleRepoEdit({{ idx }})">Edit</button>
|
||||
onclick="toggleRepoEdit({{ idx|int }})">Edit</button>
|
||||
<button class="btn btn-danger btn-sm" style="font-size:0.78rem;"
|
||||
hx-post="/settings/plugins/repos/{{ idx }}/remove"
|
||||
hx-target="#plugin-repos"
|
||||
@@ -47,7 +47,7 @@
|
||||
<div style="display:flex;gap:0.5rem;margin-top:0.75rem;">
|
||||
<button type="submit" class="btn btn-sm">Save</button>
|
||||
<button type="button" class="btn btn-ghost btn-sm"
|
||||
onclick="toggleRepoEdit({{ idx }})">Cancel</button>
|
||||
onclick="toggleRepoEdit({{ idx|int }})">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<span style="color:var(--text-muted);font-size:0.78rem;">Click to select — add to a host's <code>authorized_keys</code> to authorize Steward manually.</span>
|
||||
</div>
|
||||
<form method="post" action="/settings/ansible/generate-key"
|
||||
onsubmit="return confirm('Regenerate the managed key? Already-provisioned hosts will reject Steward until you re-provision them.');">{{ csrf_field() }}
|
||||
data-confirm="Regenerate the managed key? Already-provisioned hosts will reject Steward until you re-provision them.">{{ csrf_field() }}
|
||||
<button type="submit" class="btn btn-ghost btn-sm">Regenerate key</button>
|
||||
</form>
|
||||
{% else %}
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<div class="section-title">Monitoring capabilities</div>
|
||||
<form method="post" action="/settings/plugins/restart/"
|
||||
hx-post="/settings/plugins/restart/" hx-target="#restart-banner" hx-swap="outerHTML"
|
||||
onsubmit="return confirm('Restart the app now? This will briefly interrupt all monitoring.')"
|
||||
data-confirm="Restart the app now? This will briefly interrupt all monitoring."
|
||||
style="margin:0;">{{ csrf_field() }}
|
||||
<button type="submit" class="btn btn-ghost btn-sm" style="font-size:0.78rem;">Restart App</button>
|
||||
</form>
|
||||
@@ -134,7 +134,7 @@
|
||||
</div>
|
||||
{% if orphan.removable %}
|
||||
<form method="post" action="/settings/plugins/orphans/{{ orphan.name }}/remove/"
|
||||
onsubmit="return confirm('Remove stored settings for "{{ orphan.name }}"? Its saved configuration, including any credentials, will be discarded. This cannot be undone.');"
|
||||
data-confirm="Remove stored settings for "{{ orphan.name }}"? Its saved configuration, including any credentials, will be discarded. This cannot be undone."
|
||||
style="margin:0;flex-shrink:0;">{{ csrf_field() }}
|
||||
<button type="submit" class="btn btn-danger btn-sm" style="font-size:0.78rem;">Remove</button>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user