feat: implement auth
This commit is contained in:
parent
7901dd3f1f
commit
7f7d77749e
12
components/Button.tsx
Normal file
12
components/Button.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { JSX } from "preact";
|
||||
|
||||
export default function Button(props: JSX.HTMLAttributes<HTMLButtonElement>) {
|
||||
return (
|
||||
<button
|
||||
{...props}
|
||||
class={`px-3 py-2 bg-white rounded border(gray-500 2) hover:bg-gray-200 active:bg-gray-300 disabled:(opacity-50 cursor-not-allowed) ${
|
||||
props.class ?? ""
|
||||
}`}
|
||||
/>
|
||||
);
|
||||
}
|
12
components/Center.tsx
Normal file
12
components/Center.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { JSX } from "preact";
|
||||
|
||||
export default function Center(props: JSX.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
class={`flex items-center justify-center h-full w-full ${
|
||||
props.class ?? ""
|
||||
}`}
|
||||
/>
|
||||
);
|
||||
}
|
12
components/Input.tsx
Normal file
12
components/Input.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { JSX } from "preact";
|
||||
|
||||
export default function Input(props: JSX.HTMLAttributes<HTMLInputElement>) {
|
||||
return (
|
||||
<input
|
||||
{...props}
|
||||
class={`px-3 py-2 bg-white rounded border(gray-500 2) disabled:(opacity-50 cursor-not-allowed) ${
|
||||
props.class ?? ""
|
||||
}`}
|
||||
/>
|
||||
);
|
||||
}
|
@ -76,6 +76,9 @@
|
||||
"https://deno.land/std@0.178.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1",
|
||||
"https://deno.land/std@0.178.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba",
|
||||
"https://deno.land/std@0.178.0/semver/mod.ts": "409a2691f5a411c34e917c1e6d445a6d1d53f3fadf660e44a99dd0bf9b2ef412",
|
||||
"https://deno.land/std@0.182.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462",
|
||||
"https://deno.land/std@0.182.0/datetime/to_imf.ts": "8f9c0af8b167031ffe2e03da01a12a3b0672cc7562f89c61942a0ab0129771b2",
|
||||
"https://deno.land/std@0.182.0/http/cookie.ts": "934f92d871d50852dbd7a836d721df5a9527b14381db16001b40991d30174ee4",
|
||||
"https://deno.land/x/code_block_writer@11.0.3/mod.ts": "2c3448060e47c9d08604c8f40dee34343f553f33edcdfebbf648442be33205e5",
|
||||
"https://deno.land/x/code_block_writer@11.0.3/utils/string_utils.ts": "60cb4ec8bd335bf241ef785ccec51e809d576ff8e8d29da43d2273b69ce2a6ff",
|
||||
"https://deno.land/x/denoflate@1.2.1/mod.ts": "f5628e44b80b3d80ed525afa2ba0f12408e3849db817d47a883b801f9ce69dd6",
|
||||
|
@ -4,10 +4,14 @@
|
||||
|
||||
import config from "./deno.json" assert { type: "json" };
|
||||
import * as $0 from "./routes/index.tsx";
|
||||
import * as $1 from "./routes/library.tsx";
|
||||
import * as $2 from "./routes/login.tsx";
|
||||
|
||||
const manifest = {
|
||||
routes: {
|
||||
"./routes/index.tsx": $0,
|
||||
"./routes/library.tsx": $1,
|
||||
"./routes/login.tsx": $2,
|
||||
},
|
||||
islands: {},
|
||||
baseUrl: import.meta.url,
|
||||
|
@ -7,6 +7,7 @@
|
||||
"@preact/signals": "https://esm.sh/*@preact/signals@1.1.3",
|
||||
"@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.2.3",
|
||||
"twind": "https://esm.sh/twind@0.16.19",
|
||||
"twind/": "https://esm.sh/twind@0.16.19/"
|
||||
"twind/": "https://esm.sh/twind@0.16.19/",
|
||||
"$std/": "https://deno.land/std@0.182.0/"
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,19 @@
|
||||
import { Head } from "$fresh/runtime.ts";
|
||||
import { getCookies } from "$std/http/cookie.ts";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Fresh App</title>
|
||||
</Head>
|
||||
<div class="p-4 mx-auto max-w-screen-md">
|
||||
<img
|
||||
src="/logo.svg"
|
||||
class="w-32 h-32"
|
||||
alt="the fresh logo: a sliced lemon dripping with juice"
|
||||
/>
|
||||
<p class="my-6">
|
||||
Welcome to `fresh`. Try updating this message in the ./routes/index.tsx
|
||||
file, and refresh.
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
export function handler(req: Request): Response {
|
||||
const cookies = getCookies(req.headers);
|
||||
const username = cookies["username"];
|
||||
const password = cookies["password"];
|
||||
|
||||
if (username != null && password != null) {
|
||||
return new Response("", {
|
||||
status: 303,
|
||||
headers: { location: "/library" },
|
||||
});
|
||||
} else {
|
||||
return new Response("", {
|
||||
status: 303,
|
||||
headers: { location: "/login" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
37
routes/library.tsx
Normal file
37
routes/library.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
import { Handlers, PageProps } from "$fresh/server.ts";
|
||||
import { getCookies } from "$std/http/cookie.ts";
|
||||
import { Head } from "$fresh/runtime.ts";
|
||||
|
||||
interface Data {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export const handler: Handlers<Data> = {
|
||||
GET(req, ctx) {
|
||||
const cookies = getCookies(req.headers);
|
||||
const username = cookies["username"];
|
||||
const password = cookies["password"];
|
||||
|
||||
if (username && password) {
|
||||
return ctx.render({ username, password });
|
||||
} else {
|
||||
return new Response("", {
|
||||
status: 303,
|
||||
headers: { location: "/login" },
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default function LibraryPage({ data }: PageProps<Data>) {
|
||||
const { username, password } = data;
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>musikspider</title>
|
||||
</Head>
|
||||
<p>Library {username} {password}</p>
|
||||
</>
|
||||
);
|
||||
}
|
74
routes/login.tsx
Normal file
74
routes/login.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import { setCookie } from "$std/http/cookie.ts";
|
||||
import { Handlers } from "$fresh/server.ts";
|
||||
import { Head } from "$fresh/runtime.ts";
|
||||
|
||||
import Button from "../components/Button.tsx";
|
||||
import Input from "../components/Input.tsx";
|
||||
|
||||
const LOGIN_MAX_AGE = 60 * 60 * 24 * 7;
|
||||
|
||||
export const handler: Handlers = {
|
||||
GET(_, ctx) {
|
||||
return ctx.render();
|
||||
},
|
||||
async POST(req, _) {
|
||||
const form = await req.formData();
|
||||
const username = form.get("username")!.toString();
|
||||
const password = form.get("password")!.toString();
|
||||
|
||||
const response = new Response("", {
|
||||
status: 303,
|
||||
headers: { location: "/library" },
|
||||
});
|
||||
setCookie(response.headers, {
|
||||
name: "username",
|
||||
value: username,
|
||||
maxAge: LOGIN_MAX_AGE,
|
||||
httpOnly: true,
|
||||
});
|
||||
setCookie(response.headers, {
|
||||
name: "password",
|
||||
value: password,
|
||||
maxAge: LOGIN_MAX_AGE,
|
||||
httpOnly: true,
|
||||
});
|
||||
return response;
|
||||
},
|
||||
};
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>musikspider</title>
|
||||
</Head>
|
||||
<div class="flex items-center justify-center p-4 mx-auto max-w-screen-md h-screen">
|
||||
<form method="POST">
|
||||
<div class="flex flex-col gap-2 max-w-xs">
|
||||
<div class="flex gap-4 place-items-center">
|
||||
<label for="username" class="w-1/3">username</label>
|
||||
<Input
|
||||
class="w-2/3"
|
||||
id="username"
|
||||
type="text"
|
||||
name="username"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="flex gap-4 place-items-center">
|
||||
<label for="password" class="w-1/3">password</label>
|
||||
<Input
|
||||
class="w-2/3"
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<Button class="w-min" type="submit">login</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user