From 9f7b903901acb0cd6ec9cb2146406a92ebf79cab Mon Sep 17 00:00:00 2001 From: Vika Date: Fri, 7 Oct 2022 19:53:04 +0300 Subject: templates: move static assets to the templates crate It makes more sense to keep CSS near the templates, and the client-side JavaScript code too, since it depends on the DOM structure to work. Additionally, the overhead of `include_dir!()` is almost completely mitigated by the fact that this is a separate crate that isn't recompiled often. The linking stage, however, is still expected to take a little bit long. But I doubt it'd be longer than what it was before, since it's the same exact files that get linked into the app. --- kittybox-rs/templates/javascript/dist/indieauth.js | 118 +++++++++++++++++++++ .../templates/javascript/dist/webauthn/register.js | 1 + 2 files changed, 119 insertions(+) create mode 100644 kittybox-rs/templates/javascript/dist/indieauth.js create mode 100644 kittybox-rs/templates/javascript/dist/webauthn/register.js (limited to 'kittybox-rs/templates/javascript/dist') diff --git a/kittybox-rs/templates/javascript/dist/indieauth.js b/kittybox-rs/templates/javascript/dist/indieauth.js new file mode 100644 index 0000000..297b4b5 --- /dev/null +++ b/kittybox-rs/templates/javascript/dist/indieauth.js @@ -0,0 +1,118 @@ +"use strict"; +const WEBAUTHN_TIMEOUT = 60 * 1000; +async function webauthn_create_credential() { + const response = await fetch("/.kittybox/webauthn/pre_register"); + const { challenge, rp, user } = await response.json(); + return await navigator.credentials.create({ + publicKey: { + challenge: Uint8Array.from(challenge, (c) => c.charCodeAt(0)), + rp: rp, + user: { + id: Uint8Array.from(user.cred_id, (c) => c.charCodeAt(0)), + name: user.name, + displayName: user.displayName + }, + pubKeyCredParams: [{ alg: -7, type: "public-key" }], + authenticatorSelection: {}, + timeout: WEBAUTHN_TIMEOUT, + attestation: "none" + } + }); +} +async function webauthn_authenticate() { + const response = await fetch("/.kittybox/webauthn/pre_auth"); + const { challenge, credentials } = await response.json(); + try { + return await navigator.credentials.get({ + publicKey: { + challenge: Uint8Array.from(challenge, (c) => c.charCodeAt(0)), + allowCredentials: credentials.map(cred => ({ + id: Uint8Array.from(cred.id, c => c.charCodeAt(0)), + type: cred.type + })), + timeout: WEBAUTHN_TIMEOUT + } + }); + } + catch (e) { + console.error("WebAuthn authentication failed:", e); + alert("Using your authenticator failed. (Check the DevTools for details)"); + throw e; + } +} +async function submit_handler(e) { + e.preventDefault(); + if (e.target != null && e.target instanceof HTMLFormElement) { + const form = e.target; + let scopes; + if (form.elements.namedItem("scope") === undefined) { + scopes = []; + } + else if (form.elements.namedItem("scope") instanceof Node) { + scopes = [form.elements.namedItem("scope")] + .filter((e) => e.checked) + .map((e) => e.value); + } + else { + scopes = Array.from(form.elements.namedItem("scope")) + .filter((e) => e.checked) + .map((e) => e.value); + } + const authorization_request = { + response_type: form.elements.namedItem("response_type").value, + client_id: form.elements.namedItem("client_id").value, + redirect_uri: form.elements.namedItem("redirect_uri").value, + state: form.elements.namedItem("state").value, + code_challenge: form.elements.namedItem("code_challenge").value, + code_challenge_method: form.elements.namedItem("code_challenge_method").value, + // I would love to leave that as a list, but such is the form of + // IndieAuth. application/x-www-form-urlencoded doesn't have + // lists, so scopes are space-separated instead. It is annoying. + scope: scopes.length > 0 ? scopes.join(" ") : undefined, + }; + let credential = null; + switch (form.elements.namedItem("auth_method").value) { + case "password": + credential = form.elements.namedItem("user_password").value; + if (credential.length == 0) { + alert("Please enter a password."); + return; + } + break; + case "webauthn": + // credential = await webauthn_authenticate(); + alert("WebAuthn isn't implemented yet!"); + return; + break; + default: + alert("Please choose an authentication method."); + return; + } + console.log("Authorization request:", authorization_request); + console.log("Authentication method:", credential); + const body = JSON.stringify({ + request: authorization_request, + authorization_method: credential + }); + console.log(body); + const response = await fetch(form.action, { + method: form.method, + body: body, + headers: { + "Content-Type": "application/json" + } + }); + if (response.ok) { + let location = response.headers.get("Location"); + if (location != null) { + window.location.href = location; + } + else { + throw "Error: didn't return a location"; + } + } + } + else { + return; + } +} diff --git a/kittybox-rs/templates/javascript/dist/webauthn/register.js b/kittybox-rs/templates/javascript/dist/webauthn/register.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/kittybox-rs/templates/javascript/dist/webauthn/register.js @@ -0,0 +1 @@ +"use strict"; -- cgit 1.4.1