2022-10-05 17:02:21 -05:00
|
|
|
import { HandlerContext, Handlers, PageProps } from "$fresh/server.ts";
|
|
|
|
import { compare } from "https://deno.land/x/bcrypt@v0.4.1/mod.ts";
|
2022-10-08 02:01:48 -05:00
|
|
|
import { createToken, getUser } from "@/db/mod.ts";
|
|
|
|
import * as base64 from "$std/encoding/base64.ts";
|
|
|
|
import { setCookie } from "$std/http/cookie.ts";
|
2022-09-30 15:14:57 -05:00
|
|
|
|
2022-10-05 17:02:21 -05:00
|
|
|
type UserID = string;
|
|
|
|
|
|
|
|
interface LoginError {
|
|
|
|
message: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function invalidLogin<LoginError>(context: HandlerContext<LoginError>) {
|
|
|
|
return await context.render({ message: "Invalid login" } as LoginError);
|
|
|
|
}
|
|
|
|
|
|
|
|
export const handler: Handlers<UserID | LoginError | null> = {
|
|
|
|
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" });
|
|
|
|
}
|
|
|
|
|
2022-10-08 02:01:48 -05:00
|
|
|
const user = await getUser({ username: username.toString() });
|
|
|
|
if (!user) {
|
2022-10-05 17:02:21 -05:00
|
|
|
return await invalidLogin(context);
|
|
|
|
}
|
2022-10-08 02:01:48 -05:00
|
|
|
if (!await compare(password.toString(), user.passwordDigest)) {
|
2022-10-05 17:02:21 -05:00
|
|
|
return await invalidLogin(context);
|
|
|
|
}
|
2022-10-08 02:01:48 -05:00
|
|
|
|
|
|
|
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;
|
2022-10-05 17:02:21 -05:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
export default function Login({ data }: PageProps) {
|
|
|
|
if (typeof data == "string") {
|
|
|
|
return LoginSuccessful(data);
|
|
|
|
} else {
|
|
|
|
return LoginForm(data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function LoginSuccessful(_userId: UserID) {
|
|
|
|
return (
|
2022-10-11 17:12:32 -05:00
|
|
|
<p>
|
|
|
|
You are now logged in. Let's go to your{" "}
|
|
|
|
<a href="/dashboard">dashboard</a>!
|
|
|
|
</p>
|
2022-10-05 17:02:21 -05:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function LoginForm(props?: LoginError | null) {
|
2022-09-30 15:14:57 -05:00
|
|
|
return (
|
2022-10-11 17:12:32 -05:00
|
|
|
<form class="flex flex-col max-w-lg" method="post">
|
2022-10-05 17:02:21 -05:00
|
|
|
{props != null &&
|
|
|
|
(
|
|
|
|
<p class="text-red-500">
|
|
|
|
<strong>Error</strong>: {props.message}
|
|
|
|
</p>
|
|
|
|
)}
|
2022-10-01 14:34:07 -05:00
|
|
|
<h1 class="text-4xl mb-4 outline-white">
|
|
|
|
Log in to your account
|
|
|
|
</h1>
|
2022-10-11 17:12:32 -05:00
|
|
|
<label for="username">Username</label>
|
|
|
|
<input type="text" name="username" />
|
|
|
|
<label for="password">Password</label>
|
|
|
|
<input type="password" name="password" />
|
|
|
|
<input class="mt-2" type="submit" value="Login" />
|
|
|
|
</form>
|
2022-09-30 15:14:57 -05:00
|
|
|
);
|
|
|
|
}
|