feat: implement auth

This commit is contained in:
dusk 2023-04-12 14:12:20 +03:00
parent 7901dd3f1f
commit 7f7d77749e
Signed by: dusk
GPG Key ID: 1D8F8FAF2294D6EA
9 changed files with 173 additions and 21 deletions

12
components/Button.tsx Normal file
View 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
View 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
View 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 ?? ""
}`}
/>
);
}

View File

@ -76,6 +76,9 @@
"https://deno.land/std@0.178.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1", "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/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba",
"https://deno.land/std@0.178.0/semver/mod.ts": "409a2691f5a411c34e917c1e6d445a6d1d53f3fadf660e44a99dd0bf9b2ef412", "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/mod.ts": "2c3448060e47c9d08604c8f40dee34343f553f33edcdfebbf648442be33205e5",
"https://deno.land/x/code_block_writer@11.0.3/utils/string_utils.ts": "60cb4ec8bd335bf241ef785ccec51e809d576ff8e8d29da43d2273b69ce2a6ff", "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", "https://deno.land/x/denoflate@1.2.1/mod.ts": "f5628e44b80b3d80ed525afa2ba0f12408e3849db817d47a883b801f9ce69dd6",

View File

@ -4,10 +4,14 @@
import config from "./deno.json" assert { type: "json" }; import config from "./deno.json" assert { type: "json" };
import * as $0 from "./routes/index.tsx"; import * as $0 from "./routes/index.tsx";
import * as $1 from "./routes/library.tsx";
import * as $2 from "./routes/login.tsx";
const manifest = { const manifest = {
routes: { routes: {
"./routes/index.tsx": $0, "./routes/index.tsx": $0,
"./routes/library.tsx": $1,
"./routes/login.tsx": $2,
}, },
islands: {}, islands: {},
baseUrl: import.meta.url, baseUrl: import.meta.url,

View File

@ -7,6 +7,7 @@
"@preact/signals": "https://esm.sh/*@preact/signals@1.1.3", "@preact/signals": "https://esm.sh/*@preact/signals@1.1.3",
"@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.2.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/" "twind/": "https://esm.sh/twind@0.16.19/",
"$std/": "https://deno.land/std@0.182.0/"
} }
} }

View File

@ -1,22 +1,19 @@
import { Head } from "$fresh/runtime.ts"; import { getCookies } from "$std/http/cookie.ts";
export default function Home() { export function handler(req: Request): Response {
return ( const cookies = getCookies(req.headers);
<> const username = cookies["username"];
<Head> const password = cookies["password"];
<title>Fresh App</title>
</Head> if (username != null && password != null) {
<div class="p-4 mx-auto max-w-screen-md"> return new Response("", {
<img status: 303,
src="/logo.svg" headers: { location: "/library" },
class="w-32 h-32" });
alt="the fresh logo: a sliced lemon dripping with juice" } else {
/> return new Response("", {
<p class="my-6"> status: 303,
Welcome to `fresh`. Try updating this message in the ./routes/index.tsx headers: { location: "/login" },
file, and refresh. });
</p> }
</div>
</>
);
} }

37
routes/library.tsx Normal file
View 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
View 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>
</>
);
}