feat: add CSRF tokens to templates and JS fetch calls
This commit is contained in:
parent
d1f2b39cb6
commit
9e5773f52f
6 changed files with 14 additions and 4 deletions
|
|
@ -14,6 +14,11 @@ function bytesToBase64url(bytes) {
|
|||
return btoa(raw).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
||||
}
|
||||
|
||||
function getCsrfToken() {
|
||||
const meta = document.querySelector('meta[name="csrf-token"]');
|
||||
return meta ? meta.getAttribute('content') : '';
|
||||
}
|
||||
|
||||
async function beginRegistration() {
|
||||
const statusEl = document.getElementById('webauthn-status');
|
||||
|
||||
|
|
@ -21,7 +26,7 @@ async function beginRegistration() {
|
|||
// Step 1: Get options from server
|
||||
const beginRes = await fetch('/manage/credentials/webauthn/begin', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': getCsrfToken() },
|
||||
});
|
||||
if (!beginRes.ok) {
|
||||
if (statusEl) statusEl.innerHTML = '<div role="alert">Failed to start registration</div>';
|
||||
|
|
@ -57,7 +62,7 @@ async function beginRegistration() {
|
|||
// Step 5: Send to server
|
||||
const completeRes = await fetch('/manage/credentials/webauthn/complete', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': getCsrfToken() },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
|
|
@ -115,7 +120,7 @@ async function beginAuthentication() {
|
|||
// Step 5: Send to server
|
||||
const completeRes = await fetch('/login/webauthn/complete', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': getCsrfToken() },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token_processor(request) }}">
|
||||
<title>{% block title %}Porchlight{% endblock %}</title>
|
||||
<link rel="icon" type="image/png" href="/static/favicon.png">
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<body hx-headers='{"X-CSRF-Token": "{{ csrf_token_processor(request) }}"}'>
|
||||
<a class="skip-link" href="#main">Skip to content</a>
|
||||
<header class="site-header">
|
||||
<a href="/">
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
<p>This application is requesting access to your account.</p>
|
||||
|
||||
<form method="post" action="/consent">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token_processor(request) }}">
|
||||
<fieldset>
|
||||
<legend>Permissions requested</legend>
|
||||
<ul class="scope-list" role="list">
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<section>
|
||||
<h2>Password</h2>
|
||||
<form hx-post="/login/password" hx-target="#login-error" hx-swap="innerHTML">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token_processor(request) }}">
|
||||
<div>
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="username" required autocomplete="username">
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
<p>No password set.</p>
|
||||
{% endif %}
|
||||
<form hx-post="/manage/credentials/password" hx-target="#password-section" hx-swap="innerHTML">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token_processor(request) }}">
|
||||
<div>
|
||||
<label for="password">{{ "New password" if has_password else "Set password" }}</label>
|
||||
<input type="password" id="password" name="password" required minlength="8" autocomplete="new-password">
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
<h2>Personal information</h2>
|
||||
<div id="profile-section">
|
||||
<form hx-post="/manage/profile" hx-target="#profile-status" hx-swap="innerHTML">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token_processor(request) }}">
|
||||
<div>
|
||||
<label for="given_name">Given name</label>
|
||||
<input type="text" id="given_name" name="given_name" value="{{ user.given_name or '' }}" maxlength="255" autocomplete="given-name">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue