add: login

This commit is contained in:
trisua 2025-08-24 17:04:27 -04:00
parent ce9ce4f635
commit 8c86dd6cda
13 changed files with 407 additions and 25 deletions

View file

@ -0,0 +1,109 @@
(text "{% extends \"root.lisp\" %} {% block head %}")
(title
(text "Login — {{ name }}"))
(text "{% endblock %} {% block body %}")
(div
("class" "card")
(h4 (text "Login with Tetratto"))
(form
("class" "flex flex_col gap_4")
("onsubmit" "login(event)")
(div
("id" "flow_1")
("style" "display: contents")
(div
("class" "flex flex_col gap_1")
(label ("for" "username") (b (text "Username")))
(input
("class" "surface")
("type" "text")
("placeholder" "username")
("required" "")
("name" "username")
("id" "username")))
(div
("class" "flex flex_col gap_1")
(label ("for" "username") (b (text "Password")))
(input
("class" "surface")
("type" "password")
("placeholder" "password")
("required" "")
("name" "password")
("id" "password"))))
(div
("id" "flow_2")
("style" "display: none")
(div
("class" "flex flex_col gap_1")
(label ("for" "totp") (b (text "TOTP code")))
(input
("class" "surface")
("type" "text")
("placeholder" "totp code")
("name" "totp")
("id" "totp"))))
(button
("class" "button surface")
(text "{{ icon \"arrow-right\" }}")
(text "Continue")))
(hr ("class" "margin"))
(a ("href" "{{ config.service_hosts.tetratto }}/auth/register") (text "I don't have a Tetratto account")))
(script
(text "let flow_page = 1;
function next_page() {
document.getElementById(`flow_${flow_page}`).style.display = \"none\";
flow_page += 1;
document.getElementById(`flow_${flow_page}`).style.display = \"contents\";
}
async function login(e) {
e.preventDefault();
if (flow_page === 1) {
// check if we need TOTP
const res = await (
await fetch(
`/api/v1/auth/user/${e.target.username.value}/check_totp`,
)
).json();
if (res.ok && res.payload) {
// user exists AND totp is required
return next_page();
}
}
fetch(\"/api/v1/auth/login\", {
method: \"POST\",
headers: {
\"Content-Type\": \"application/json\",
},
body: JSON.stringify({
username: e.target.username.value,
password: e.target.password.value,
totp: e.target.totp.value,
}),
})
.then((res) => res.json())
.then(async (res) => {
show_message(res.message, res.ok);
if (res.ok) {
// update tokens
LOGIN_ACCOUNT_TOKENS[e.target.username.value] = res.message;
save_login_account_tokens();
// redirect
setTimeout(() => {
window.location.href = \"/app\";
}, 150);
}
});
}"))
(text "{% endblock %}")