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(/=+$/, '');
|
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() {
|
async function beginRegistration() {
|
||||||
const statusEl = document.getElementById('webauthn-status');
|
const statusEl = document.getElementById('webauthn-status');
|
||||||
|
|
||||||
|
|
@ -21,7 +26,7 @@ async function beginRegistration() {
|
||||||
// Step 1: Get options from server
|
// Step 1: Get options from server
|
||||||
const beginRes = await fetch('/manage/credentials/webauthn/begin', {
|
const beginRes = await fetch('/manage/credentials/webauthn/begin', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': getCsrfToken() },
|
||||||
});
|
});
|
||||||
if (!beginRes.ok) {
|
if (!beginRes.ok) {
|
||||||
if (statusEl) statusEl.innerHTML = '<div role="alert">Failed to start registration</div>';
|
if (statusEl) statusEl.innerHTML = '<div role="alert">Failed to start registration</div>';
|
||||||
|
|
@ -57,7 +62,7 @@ async function beginRegistration() {
|
||||||
// Step 5: Send to server
|
// Step 5: Send to server
|
||||||
const completeRes = await fetch('/manage/credentials/webauthn/complete', {
|
const completeRes = await fetch('/manage/credentials/webauthn/complete', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': getCsrfToken() },
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -115,7 +120,7 @@ async function beginAuthentication() {
|
||||||
// Step 5: Send to server
|
// Step 5: Send to server
|
||||||
const completeRes = await fetch('/login/webauthn/complete', {
|
const completeRes = await fetch('/login/webauthn/complete', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': getCsrfToken() },
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,12 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<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>
|
<title>{% block title %}Porchlight{% endblock %}</title>
|
||||||
<link rel="icon" type="image/png" href="/static/favicon.png">
|
<link rel="icon" type="image/png" href="/static/favicon.png">
|
||||||
<link rel="stylesheet" href="/static/style.css">
|
<link rel="stylesheet" href="/static/style.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body hx-headers='{"X-CSRF-Token": "{{ csrf_token_processor(request) }}"}'>
|
||||||
<a class="skip-link" href="#main">Skip to content</a>
|
<a class="skip-link" href="#main">Skip to content</a>
|
||||||
<header class="site-header">
|
<header class="site-header">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
<p>This application is requesting access to your account.</p>
|
<p>This application is requesting access to your account.</p>
|
||||||
|
|
||||||
<form method="post" action="/consent">
|
<form method="post" action="/consent">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token_processor(request) }}">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Permissions requested</legend>
|
<legend>Permissions requested</legend>
|
||||||
<ul class="scope-list" role="list">
|
<ul class="scope-list" role="list">
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
<section>
|
<section>
|
||||||
<h2>Password</h2>
|
<h2>Password</h2>
|
||||||
<form hx-post="/login/password" hx-target="#login-error" hx-swap="innerHTML">
|
<form hx-post="/login/password" hx-target="#login-error" hx-swap="innerHTML">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token_processor(request) }}">
|
||||||
<div>
|
<div>
|
||||||
<label for="username">Username</label>
|
<label for="username">Username</label>
|
||||||
<input type="text" id="username" name="username" required autocomplete="username">
|
<input type="text" id="username" name="username" required autocomplete="username">
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
<p>No password set.</p>
|
<p>No password set.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<form hx-post="/manage/credentials/password" hx-target="#password-section" hx-swap="innerHTML">
|
<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>
|
<div>
|
||||||
<label for="password">{{ "New password" if has_password else "Set password" }}</label>
|
<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">
|
<input type="password" id="password" name="password" required minlength="8" autocomplete="new-password">
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
<h2>Personal information</h2>
|
<h2>Personal information</h2>
|
||||||
<div id="profile-section">
|
<div id="profile-section">
|
||||||
<form hx-post="/manage/profile" hx-target="#profile-status" hx-swap="innerHTML">
|
<form hx-post="/manage/profile" hx-target="#profile-status" hx-swap="innerHTML">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token_processor(request) }}">
|
||||||
<div>
|
<div>
|
||||||
<label for="given_name">Given name</label>
|
<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">
|
<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