import { readProfiles } from "../../stores/userinfo.ts"; import { useNavigate } from "@solidjs/router"; import { createSignal, For, Match, Show, Switch } from "solid-js"; import Cookie from "universal-cookie"; export default function Login() { const [title, setTitle] = createSignal("Sign in"); const [subtitle, setSubtitle] = createSignal("Via your Goatpass account"); const [error, setError] = createSignal(null); const [loading, setLoading] = createSignal(false); const [factor, setFactor] = createSignal(); const [factors, setFactors] = createSignal([]); const [challenge, setChallenge] = createSignal(); const [stage, setStage] = createSignal("starting"); const navigate = useNavigate(); const handlers: { [id: string]: any } = { "starting": async (evt: SubmitEvent) => { evt.preventDefault(); const data = Object.fromEntries(new FormData(evt.target as HTMLFormElement)); if (!data.id) return; setLoading(true); const res = await fetch("/api/auth", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); if (res.status !== 200) { setError(await res.text()); } else { const data = await res.json(); setTitle(`Welcome, ${data["display_name"]}`); setSubtitle("Before continue, we need verify that's you"); setFactors(data["factors"]); setChallenge(data["challenge"]); setError(null); setStage("choosing"); } setLoading(false); }, "choosing": async (evt: SubmitEvent) => { evt.preventDefault(); const data = Object.fromEntries(new FormData(evt.target as HTMLFormElement)); if (!data.factor) return; setLoading(true); const res = await fetch(`/api/auth/factors/${data.id}`, { method: "POST" }); if (res.status !== 200 && res.status !== 204) { setError(await res.text()); } else { setTitle(`Enter the code`); setSubtitle(res.status === 204 ? "Enter your credentials" : "Code has been sent to your inbox"); setError(null); setFactor(parseInt(data.factor as string)); setStage("verifying"); } setLoading(false); }, "verifying": async (evt: SubmitEvent) => { evt.preventDefault(); const data = Object.fromEntries(new FormData(evt.target as HTMLFormElement)); if (!data.credentials) return; setLoading(true); const res = await fetch(`/api/auth`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ challenge_id: challenge().id, factor_id: factor(), secret: data.credentials }) }); if (res.status !== 200) { setError(await res.text()); } else { const data = await res.json(); if (data["is_finished"]) { await grantToken(data["session"]["grant_token"]); await readProfiles(); navigate("/"); } else { setError(null); setStage("choosing"); setTitle("Continue verifying"); setSubtitle("You passed one check, but that's not enough."); } } setLoading(false); } }; async function grantToken(tk: string) { const res = await fetch("/api/auth/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ code: tk, grant_type: "authorization_code" }) }); if (res.status !== 200) { const err = await res.text(); setError(err); throw new Error(err); } else { const data = await res.json(); new Cookie().set("access_token", data["access_token"], { path: "/" }); new Cookie().set("refresh_token", data["refresh_token"], { path: "/" }); setError(null); } } function getFactorName(factor: any) { switch (factor.type) { case 0: return "Password Verification"; default: return "Unknown"; } } return (
handlers[stage()](e)}>
{item => }

Choose a way to verify that's you

); }