custom JS removed in favor of proper CSRF implementation
This commit is contained in:
@@ -43,38 +43,9 @@
|
||||
{% block head %}{% endblock head %}
|
||||
<script src="/static/vendor/htmx/htmx-1.9.12.min.js"></script>
|
||||
<script defer src="/static/vendor/alpine/alpinejs-3.14.9.min.js"></script>
|
||||
<!-- CSRF: echo the signed `csrf_token` cookie back on every unsafe request.
|
||||
htmx requests get it as an X-CSRF-Token header; native <form> submits
|
||||
can't set a header, so a hidden _csrf field is injected instead.
|
||||
Server side: shared::csrf::protect. -->
|
||||
<script>
|
||||
(function () {
|
||||
function csrfToken() {
|
||||
var m = document.cookie.split('; ').find(function (c) { return c.indexOf('csrf_token=') === 0; });
|
||||
return m ? decodeURIComponent(m.split('=').slice(1).join('=')) : '';
|
||||
}
|
||||
document.addEventListener('htmx:configRequest', function (e) {
|
||||
var t = csrfToken();
|
||||
if (t) e.detail.headers['X-CSRF-Token'] = t;
|
||||
});
|
||||
document.addEventListener('submit', function (e) {
|
||||
var form = e.target;
|
||||
if (!form || (form.method || '').toLowerCase() !== 'post') return;
|
||||
var t = csrfToken();
|
||||
if (!t) return;
|
||||
var input = form.querySelector('input[name="_csrf"]');
|
||||
if (!input) {
|
||||
input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = '_csrf';
|
||||
form.appendChild(input);
|
||||
}
|
||||
input.value = t;
|
||||
}, true);
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body
|
||||
hx-headers='{"X-CSRF-Token": "{{ csrf_token() }}"}'
|
||||
x-data="{ showSidebar: false }"
|
||||
class="min-h-screen bg-surface text-on-surface antialiased dark:bg-surface-dark dark:text-on-surface-dark">
|
||||
|
||||
@@ -126,6 +97,7 @@
|
||||
{{ t(key="admin-exit", lang=lang | default(value='sk')) }}
|
||||
</a>
|
||||
<form method="post" action="/logout">
|
||||
{{ ui::csrf_field() }}
|
||||
<button type="submit" class="flex w-full items-center gap-2 rounded-radius px-2 py-1.5 text-left text-sm font-medium text-danger underline-offset-2 transition hover:bg-danger/5 focus:outline-hidden focus-visible:underline">
|
||||
{{ t(key="logout", lang=lang | default(value='sk')) }}
|
||||
</button>
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
{{ ui::button(variant="outline-secondary", label=t(key="edit", lang=lang | default(value='sk')), href="/admin/catalog/categories/" ~ row.category.id ~ "/edit", size="px-3 py-1.5 text-xs") }}
|
||||
<form method="post" action="/admin/catalog/categories/{{ row.category.id }}/delete"
|
||||
onsubmit="return confirm('{{ t(key="confirm-delete", lang=lang | default(value='sk')) }}')">
|
||||
{{ ui::csrf_field() }}
|
||||
{{ ui::button(variant="outline-danger", label=t(key="delete", lang=lang | default(value='sk')), type="submit", size="px-3 py-1.5 text-xs") }}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<form method="post" enctype="multipart/form-data"
|
||||
action="{% if category %}/admin/catalog/categories/{{ category.id }}{% else %}/admin/catalog/categories{% endif %}"
|
||||
class="mt-6 space-y-5 rounded-radius border border-outline bg-surface p-6 dark:border-outline-dark dark:bg-surface-dark-alt">
|
||||
{{ ui::csrf_field() }}
|
||||
|
||||
{% if category %}
|
||||
{% set v_name = category.name %}{% set v_slug = category.slug %}{% set v_pos = category.position %}{% set v_desc = category.description | default(value="") %}{% set v_pub = category.published %}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<form method="post" enctype="multipart/form-data"
|
||||
action="{% if product %}/admin/catalog/products/{{ product.id }}{% else %}/admin/catalog/products{% endif %}"
|
||||
class="mt-6 space-y-5 rounded-radius border border-outline bg-surface p-6 dark:border-outline-dark dark:bg-surface-dark-alt">
|
||||
{{ ui::csrf_field() }}
|
||||
|
||||
{% if product %}
|
||||
{% set v_name = product.name %}{% set v_price = product.price %}{% set v_currency = product.currency %}{% set v_stock = product.stock %}{% set v_sku = product.sku | default(value="") %}{% set v_slug = product.slug %}{% set v_desc = product.description | default(value="") %}{% set v_pub = product.published %}
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
{{ ui::button(variant="outline-secondary", label=t(key="view", lang=lang | default(value='sk')), href="/shop/" ~ product.slug, size="px-3 py-1.5 text-xs") }}
|
||||
<form method="post" action="/admin/catalog/products/{{ product.id }}/delete"
|
||||
onsubmit="return confirm('{{ t(key="confirm-delete", lang=lang | default(value='sk')) }}')">
|
||||
{{ ui::csrf_field() }}
|
||||
{{ ui::button(variant="outline-danger", label=t(key="delete", lang=lang | default(value='sk')), type="submit", size="px-3 py-1.5 text-xs") }}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
<p class="text-on-surface/70 dark:text-on-surface-dark/70">{{ t(key="order-send-hint", lang=lang | default(value='sk')) }}</p>
|
||||
<form method="post" action="/admin/orders/{{ order.id }}/ship"
|
||||
onsubmit="return confirm('{{ t(key="order-send-confirm", lang=lang | default(value='sk')) }}')">
|
||||
{{ ui::csrf_field() }}
|
||||
{% set carrier_up = carrier | upper %}
|
||||
{% set ship_label = t(key="order-send-to-carrier", lang=lang | default(value='sk')) ~ " " ~ carrier_up %}
|
||||
{{ ui::button(label=ship_label, type="submit", extra="w-full") }}
|
||||
@@ -118,6 +119,7 @@
|
||||
</div>
|
||||
|
||||
<form method="post" action="/admin/orders/{{ order.id }}/status" class="space-y-3 rounded-radius border border-outline bg-surface p-5 dark:border-outline-dark dark:bg-surface-dark-alt">
|
||||
{{ ui::csrf_field() }}
|
||||
<label for="status" class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">{{ t(key="order-status", lang=lang | default(value='sk')) }}</label>
|
||||
<div class="relative">
|
||||
<select id="status" name="status"
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
{% for method in methods %}
|
||||
<form method="post" action="/admin/shipping/{{ method.id }}"
|
||||
class="flex flex-wrap items-end gap-4 rounded-radius border border-outline bg-surface p-5 dark:border-outline-dark dark:bg-surface-dark-alt">
|
||||
{{ ui::csrf_field() }}
|
||||
<div class="min-w-40">
|
||||
<p class="font-semibold text-on-surface-strong dark:text-on-surface-dark-strong">{{ method.name }}</p>
|
||||
<p class="text-xs text-on-surface/60 dark:text-on-surface-dark/60">{{ method.carrier | upper }}{% if method.requires_pickup_point %} · {{ t(key="checkout-pickup-point", lang=lang | default(value='sk')) }}{% endif %}</p>
|
||||
|
||||
Reference in New Issue
Block a user