import { ValTownAdapter } from "https://esm.town/v/yawnxyz/lucia_adapter_valtown";
import { createUser, getUser, verifyPassword } from "https://esm.town/v/yawnxyz/lucia_sqlite";
import { Lucia, Session, User } from "npm:lucia@3.0.1";
import { renderToString } from "npm:react-dom/server";
import { CookieJar } from "https://deno.land/x/cookies/mod.ts";
const userTable = "user";
const sessionTable = "session";
const adapter = new ValTownAdapter({ userTable, sessionTable });
export const lucia = new Lucia(adapter, {
getUserAttributes: (attributes) => {
return {
username: attributes.username,
};
},
});
declare module "npm:lucia" {
interface Register {
Lucia: typeof lucia;
DatabaseUserAttributes: DatabaseUserAttributes;
}
}
interface DatabaseUserAttributes {
username: string;
}
function redirect(url: string, status = 302): Response {
return new Response(null, {
status,
headers: { Location: url }
});
}
export const luciaMiddleware = (handler: (req: Request) => Response | Promise<Response>) => {
return async (req: Request) => {
const url = new URL(req.url);
const cookies = new CookieJar(req);
const sessionId = cookies.get(lucia.sessionCookieName) ?? null;
let user: User | null = null;
let session: Session | null = null;
if (sessionId) {
const result = await lucia.validateSession(sessionId);
user = result.user;
session = result.session;
}
let response: Response;
if (url.pathname === "/auth/signup" && req.method === "GET") {
response = new Response(
renderToString(
<div>
<h1 style={{ textAlign: "center" }}>Sign up</h1>
<form
method="post"
action="/auth/signup"
style={{ display: "flex", flexDirection: "column", gap: "0.5rem", alignItems: "center" }}
>
<div>
<input id="username" name="username" autoComplete="off" placeholder="Username" />
</div>
<div>
<input id="password" name="password" type="password" autoComplete="off" placeholder="Password" />
</div>
<input type="submit" value="Sign up" />
</form>
</div>,
),
{ headers: { "Content-Type": "text/html" } },
);
} else if (url.pathname === "/auth/signup" && req.method === "POST") {
const formData = await req.formData();
const username = formData.get("username") as string;
const password = formData.get("password") as string;
if (
username.length < 3
|| username.length > 31
|| !/^[a-z0-9_-]+$/.test(username)
) {
return new Response("Invalid username: needs to be > 3 and < 31 characters and match regex: ^[a-z0-9_-]+$", {
status: 400,
});
}
if (password.length < 6 || password.length > 255) {
return new Response("Invalid password: needs to be > 6 and < 255 characters", {
status: 400,
});