brewlog/templates/pages/register.html
Jon Seager 920931ba17
refactor: fix template review findings (security, macros, tokens)
Address findings from the templates code review:

- Fix XSS in admin.html onclick handlers via data attributes
- Fix XSS in 5 edit page signal initializations via JSON serialization
- Fix register.html token exposure by moving to data attribute
- Add entity_icon, quick_notes_toggles, add_form_submit macros
- Replace hardcoded colors with design tokens (warning, error, success)
- Add warning design tokens to CSS theme
- Scope MutationObserver to main element
- Add defer to webauthn.js script tags
- Refactor login/register JS to arrow functions
- Guard lightbox script behind image_url check
- Fix else-if to elif in 5 templates
2026-02-13 16:20:30 +00:00

121 lines
3.9 KiB
HTML

{% extends "base.html" %} {% import "partials/icons.html" as icons %}
{% block title %}Brewlog · Register{% endblock %}
{% block head %}
<script defer src="/static/js/webauthn.js"></script>
{% endblock %}
{% block content %}
<div class="mx-auto max-w-md">
<div class="rounded-lg border bg-surface p-6">
<h1 class="text-2xl font-semibold text-accent">Register</h1>
<p class="mt-2 text-sm text-text-secondary">
Create an account by registering a passkey. This will be used to sign in
going forward.
</p>
<div
id="register-error"
class="mt-4 hidden rounded-md bg-error-bg border border-error-border p-3 text-sm text-error-text"
role="alert"
></div>
<div
id="register-unsupported"
class="mt-4 hidden rounded-md bg-warning-bg border border-warning-border p-3 text-sm text-warning-text"
>
This browser does not support passkeys. Please use a modern browser
(Chrome, Firefox, Safari, or Edge).
</div>
<div
id="register-form"
class="mt-6 flex flex-col gap-4"
data-token="{{ token }}"
>
<label class="flex flex-col gap-1 text-sm">
<span class="text-text">Display Name</span>
<input
type="text"
id="display-name"
required
aria-required="true"
autofocus
class="input-field"
placeholder="Display name"
/>
</label>
<label class="flex flex-col gap-1 text-sm">
<span class="text-text">Passkey Name</span>
<input
type="text"
id="passkey-name"
required
aria-required="true"
class="input-field"
placeholder="e.g. MacBook Touch ID, iPhone"
/>
</label>
<button
id="register-button"
type="button"
onclick="handleRegister()"
class="mt-2 inline-flex w-full items-center justify-center gap-2 rounded-md bg-accent px-4 py-3 text-sm font-semibold text-accent-text transition hover:bg-accent-hover disabled:opacity-50 disabled:cursor-not-allowed"
>
{{ icons::key("h-4 w-4") }} Register Passkey
</button>
<div
id="register-loading"
class="mt-2 hidden text-center text-sm text-text-muted"
>
<p>Follow the prompts from the browser or device...</p>
</div>
</div>
</div>
</div>
<script>
const handleRegister = async () => {
const token = document.getElementById("register-form").dataset.token;
const button = document.getElementById("register-button");
const errorDiv = document.getElementById("register-error");
const loadingDiv = document.getElementById("register-loading");
const displayName = document.getElementById("display-name").value.trim();
if (!displayName) {
errorDiv.textContent = "Please enter a display name.";
errorDiv.classList.remove("hidden");
return;
}
const passkeyName = document.getElementById("passkey-name").value.trim();
if (!passkeyName) {
errorDiv.textContent = "Please enter a name for this passkey.";
errorDiv.classList.remove("hidden");
return;
}
errorDiv.classList.add("hidden");
loadingDiv.classList.remove("hidden");
button.disabled = true;
try {
await startPasskeyRegistration(token, displayName, passkeyName);
window.location.href = "/";
} catch (err) {
errorDiv.textContent = err.message;
errorDiv.classList.remove("hidden");
loadingDiv.classList.add("hidden");
button.disabled = false;
}
};
if (!window.PublicKeyCredential) {
document.getElementById("register-button").disabled = true;
document
.getElementById("register-unsupported")
.classList.remove("hidden");
}
</script>
{% endblock %}