Files
linux-cloud-router/debian-package/src/usr/share/vpn-router/templates/oidc-page.html.j2
T

109 lines
4.5 KiB
Django/Jinja

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex">
<title>{{ title }}</title>
<style>
body { font-family: system-ui, sans-serif; background: #f4f5f7; color: #1f2937; margin: 0; }
main { max-width: 22rem; margin: 4rem auto; background: #fff; padding: 2rem; border-radius: 0.5rem; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15); }
h1 { font-size: 1.25rem; margin: 0 0 0.25rem; }
p { margin: 0 0 1rem; color: #4b5563; }
label { display: block; font-size: 0.875rem; margin: 0.75rem 0 0.25rem; }
input { box-sizing: border-box; width: 100%; padding: 0.5rem; border: 1px solid #d1d5db; border-radius: 0.25rem; font-size: 1rem; }
button { width: 100%; margin-top: 1.25rem; padding: 0.6rem; border: 0; border-radius: 0.25rem; font-size: 1rem; cursor: pointer; background: #1d4ed8; color: #fff; }
button.secondary { background: #fff; color: #1d4ed8; border: 1px solid #1d4ed8; margin-top: 0.75rem; }
.error { background: #fee2e2; color: #991b1b; padding: 0.5rem 0.75rem; border-radius: 0.25rem; margin-bottom: 1rem; }
ul { margin: 0 0 1rem; padding-left: 1.25rem; color: #4b5563; }
#user_code { text-transform: uppercase; letter-spacing: 0.15em; font-family: ui-monospace, monospace; }
.issuer { font-size: 0.75rem; color: #6b7280; margin: 1.5rem 0 0; }
</style>
</head>
<body>
<main>
<h1>{{ title }}</h1>
{%- if message %}
<p>{{ message }}</p>
{%- endif %}
{%- if error %}
<div class="error" role="alert">{{ error }}</div>
{%- endif %}
{%- if items %}
<ul>
{%- for item in items %}
<li>{{ item }}</li>
{%- endfor %}
</ul>
{%- endif %}
{%- if decide %}
<form method="post" action="/oidc/device/decide">
<input type="hidden" name="user_code" value="{{ user_code }}">
<button type="submit" name="decision" value="allow">Allow</button>
<button class="secondary" type="submit" name="decision" value="deny">Deny</button>
</form>
{%- endif %}
{%- if form or device %}
<form id="sign-in" method="post" action="{{ action }}">
{%- if device %}
<label for="user_code">Code shown on the device</label>
<input id="user_code" name="user_code" value="{{ user_code }}" autocapitalize="characters" autocomplete="off" spellcheck="false" required{% if not form %} autofocus{% endif %}>
{%- else %}
<input type="hidden" name="request" value="{{ request }}">
{%- endif %}
{%- if form %}
<label for="name">Name</label>
<input id="name" name="name" value="{{ name }}" autocomplete="username webauthn" autocapitalize="none" spellcheck="false" required{% if not device %} autofocus{% endif %}>
<label for="password">Password</label>
<input id="password" name="password" type="password" autocomplete="current-password" required>
<label for="code">Code from the authenticator, when you have one</label>
<input id="code" name="code" inputmode="numeric" pattern="[0-9]{6}" maxlength="6" autocomplete="one-time-code">
<button type="submit">Sign in</button>
{%- else %}
<button type="submit">Continue</button>
{%- endif %}
</form>
{%- endif %}
{%- if form %}
<form id="passkey-form" method="post" action="{{ action }}" hidden>
<input type="hidden" name="request" value="{{ request }}">
<input type="hidden" name="user_code">
<input type="hidden" name="passkey_id">
<input type="hidden" name="credential">
</form>
<button id="passkey" class="secondary" type="button" hidden>Sign in with a passkey</button>
<script>
// A passkey sign-in begins at /oidc/passkey and posts the browser's answer to the form's action with the authorization
// request, or with the user code the sign-in form holds.
(function () {
var button = document.getElementById('passkey');
if (!window.PublicKeyCredential || !PublicKeyCredential.parseRequestOptionsFromJSON) {
return;
}
button.hidden = false;
button.addEventListener('click', async function () {
var code = document.getElementById('user_code');
if (code && !code.reportValidity()) {
return;
}
button.disabled = true;
try {
var begun = await (await fetch('/oidc/passkey', { method: 'POST' })).json();
var credential = await navigator.credentials.get({ publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(begun.options.publicKey) });
var form = document.getElementById('passkey-form');
form.elements.user_code.value = code ? code.value : '';
form.elements.passkey_id.value = begun.id;
form.elements.credential.value = JSON.stringify(credential.toJSON());
form.submit();
} catch (error) {
button.disabled = false;
}
});
})();
</script>
{%- endif %}
<p class="issuer">{{ issuer }}</p>
</main>
</body>
</html>