import { HandlerContext, Handlers, PageProps } from "$fresh/server.ts"; import { compare } from "https://deno.land/x/bcrypt@v0.4.1/mod.ts"; import { Page } from "@/components/Page.tsx"; import { createToken, getUser } from "@/db/mod.ts"; import * as base64 from "$std/encoding/base64.ts"; import { setCookie } from "$std/http/cookie.ts"; type UserID = string; interface LoginError { message: string; } async function invalidLogin(context: HandlerContext) { return await context.render({ message: "Invalid login" } as LoginError); } export const handler: Handlers = { async POST(request: Request, context) { const formData = (await request.formData()); const username = formData.get("username"); const password = formData.get("password"); if (!username) { return await context.render({ message: "no username provided" }); } if (!password) { return await context.render({ message: "no password provided" }); } const user = await getUser({ username: username.toString() }); if (!user) { return await invalidLogin(context); } if (!await compare(password.toString(), user.passwordDigest)) { return await invalidLogin(context); } const token = await createToken({ userId: user.id, data: { type: "login" }, }); if (!token || !token.bytes) throw "failed to create token"; const cookie = base64.encode(token.bytes); const response = await context.render(user.id); setCookie(response.headers, { name: "lsauth", value: cookie }); return response; }, }; export default function Login({ data }: PageProps) { if (typeof data == "string") { return LoginSuccessful(data); } else { return LoginForm(data); } } function LoginSuccessful(_userId: UserID) { return (

You are now logged in. Let's go to your{" "} dashboard!

); } function LoginForm(props?: LoginError | null) { return ( {props != null && (

Error: {props.message}

)}

Log in to your account

); }