summaryrefslogtreecommitdiffstats
path: root/templates
diff options
context:
space:
mode:
Diffstat (limited to 'templates')
-rw-r--r--templates/login.html.template46
-rw-r--r--templates/otp.html.template25
-rw-r--r--templates/register/register-success.html.template28
-rw-r--r--templates/register/register.html.template65
4 files changed, 143 insertions, 21 deletions
diff --git a/templates/login.html.template b/templates/login.html.template
index 279927b..2a498a5 100644
--- a/templates/login.html.template
+++ b/templates/login.html.template
@@ -17,25 +17,29 @@
-- <https://www.gnu.org/licenses/>.
-->
-<title>Login</title>
+<!doctype html>
-<section>
-{{- if .Error}}
- <p class="login-error"><img class="inline" width="150" height="163" src="/static/angry.webp">Incorrect password
-{{- end}}
- <form class="password-form" method="post">
- <table>
- {{- if not .Quick}}
- <tr class="password-form-row">
- <td><label class="password-label" for="password">Enter password</label>
- <td><input id="password" class="password" type="password" name="password" autofocus>
- {{- end}}
- <tr class="password-form-row">
- <td><label class="password-label" for="auth">Google authenticator code</label>
- <td><input id="auth" class="password" name="auth">
- <tr>
- <td>
- <td><input type="image" width="100" height="71" class="submit" src="/static/point.webp" alt="Submit">
- </table>
- </form>
-</section>
+<form id="form" method="post">
+ <input id="user" type="hidden" name="user">
+ <input id="auth-data" type="hidden" name="auth-data">
+ <input id="client-data" type="hidden" name="client-data">
+ <input id="sig" type="hidden" name="sig">
+</form>
+
+<script>
+ async function main() {
+ const publicKeyCredential = await navigator.credentials.get({publicKey: {
+ challenge: Uint8Array.fromBase64("{{.Challenge}}").buffer,
+ }});
+ const rsp = publicKeyCredential.response;
+ document.getElementById("user").value = new Uint8Array(rsp.userHandle).toBase64();
+ document.getElementById("auth-data").value = new Uint8Array(rsp.authenticatorData).toBase64();
+ document.getElementById("client-data").value = new Uint8Array(rsp.clientDataJSON).toBase64();
+ document.getElementById("sig").value = new Uint8Array(rsp.signature).toBase64();
+ document.getElementById("form").submit();
+ }
+
+ main();
+</script>
+
+This page requires JavaScriptâ„¢ to be enabled
diff --git a/templates/otp.html.template b/templates/otp.html.template
new file mode 100644
index 0000000..b20d71c
--- /dev/null
+++ b/templates/otp.html.template
@@ -0,0 +1,25 @@
+<!-- Copyright 2026 Rose Hogenson <r@roseh.moe>
+ --
+ -- This file is part of roseh.moe.
+ --
+ -- roseh.moe is free software: you can redistribute it and/or modify
+ -- it under the terms of the GNU Affero General Public License
+ -- as published by the Free Software Foundation, either version 3 of
+ -- the License, or (at your option) any later version.
+ --
+ -- roseh.moe is distributed in the hope that it will be useful,
+ -- but WITHOUT ANY WARRANTY; without even the implied warranty
+ -- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ -- GNU Affero General Public License for more details.
+ --
+ -- You should have received a copy of the GNU Affero General Public
+ -- License along with roseh.moe. If not, see
+ -- <https://www.gnu.org/licenses/>.
+ -->
+
+<title>OTP</title>
+
+<div style="display:flex;flex-direction:column;align-items:center;font-size:50px">
+ <p>Your OTP link: <a href="{{.URL}}">{{.URL}}</a></p>
+ <img src="{{.QR}}" alt="QR code for {{.URL}}" width="500px">
+</div>
diff --git a/templates/register/register-success.html.template b/templates/register/register-success.html.template
new file mode 100644
index 0000000..d9c64e1
--- /dev/null
+++ b/templates/register/register-success.html.template
@@ -0,0 +1,28 @@
+<!-- Copyright 2026 Rose Hogenson <r@roseh.moe>
+ --
+ -- This file is part of roseh.moe.
+ --
+ -- roseh.moe is free software: you can redistribute it and/or modify
+ -- it under the terms of the GNU Affero General Public License
+ -- as published by the Free Software Foundation, either version 3 of
+ -- the License, or (at your option) any later version.
+ --
+ -- roseh.moe is distributed in the hope that it will be useful,
+ -- but WITHOUT ANY WARRANTY; without even the implied warranty
+ -- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ -- GNU Affero General Public License for more details.
+ --
+ -- You should have received a copy of the GNU Affero General Public
+ -- License along with roseh.moe. If not, see
+ -- <https://www.gnu.org/licenses/>.
+ -->
+
+<title>Registered</title>
+
+<section>
+ <h1>Registered!</h1>
+ <p>A device key has been generated, but it must be authorized on
+ the server:</p>
+ <pre> &lt;Passkey ID="{{.ID | xmlEscape}}"
+ Key="{{.Key}}"/&gt;</pre>
+</section>
diff --git a/templates/register/register.html.template b/templates/register/register.html.template
new file mode 100644
index 0000000..d97b585
--- /dev/null
+++ b/templates/register/register.html.template
@@ -0,0 +1,65 @@
+<!-- Copyright 2026 Rose Hogenson <r@roseh.moe>
+ --
+ -- This file is part of roseh.moe.
+ --
+ -- roseh.moe is free software: you can redistribute it and/or modify
+ -- it under the terms of the GNU Affero General Public License
+ -- as published by the Free Software Foundation, either version 3 of
+ -- the License, or (at your option) any later version.
+ --
+ -- roseh.moe is distributed in the hope that it will be useful,
+ -- but WITHOUT ANY WARRANTY; without even the implied warranty
+ -- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ -- GNU Affero General Public License for more details.
+ --
+ -- You should have received a copy of the GNU Affero General Public
+ -- License along with roseh.moe. If not, see
+ -- <https://www.gnu.org/licenses/>.
+ -->
+
+<title>Register</title>
+
+<section>
+ <form id="form" class="password-form" method="post">
+ <input id="id" type="hidden" name="id" value="{{.ID}}">
+ <input id="key" type="hidden" name="key">
+ <table>
+ <tr class="password-form-row">
+ <td><label class="password-label" for="name">Enter a name for this passkey</label>
+ <td><input id="name" class="password" name="name">
+ <tr>
+ <td>
+ <td>
+ <img width="100" height="71" class="submit" src="/static/point.webp" alt="Submit"
+ onClick="generateKey()">
+ </table>
+ </form>
+</section>
+
+<script>
+ async function generateKey() {
+ const name = document.getElementById("name").value;
+ const publicKeyCredential = await navigator.credentials.create({publicKey: {
+ authenticatorSelection: {
+ residentKey: "required",
+ userVerification: "required",
+ },
+ challenge: Uint8Array.fromBase64("{{.Challenge}}").buffer,
+ pubKeyCredParams: [
+ {alg: -9, type: "public-key"},
+ {alg: -257, type: "public-key"},
+ {alg: -7, type: "public-key"},
+ ],
+ rp: {
+ name: "roseh.moe",
+ },
+ user: {
+ displayName: name,
+ id: Uint8Array.fromBase64(document.getElementById("id").value).buffer,
+ name: name,
+ },
+ }});
+ document.getElementById("key").value = new Uint8Array(publicKeyCredential.response.getPublicKey()).toBase64();
+ document.getElementById("form").submit();
+ }
+</script>