adding middleware

This commit is contained in:
qpismont 2024-07-01 21:58:06 +02:00
parent abad2cec96
commit 65cccb9620
15 changed files with 115 additions and 28 deletions

View file

@ -3,6 +3,7 @@ import { defineConfig } from "astro/config";
import react from "@astrojs/react";
import node from "@astrojs/node";
// https://astro.build/config
export default defineConfig({
integrations: [react()],
output: "server",

View file

@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/1.5.3/schema.json",
"$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
"organizeImports": {
"enabled": true
},

BIN
bun.lockb

Binary file not shown.

View file

@ -4,24 +4,24 @@
"version": "0.0.1",
"scripts": {
"dev": "bunx --bun astro dev",
"start": "bunx --bun astro dev",
"build": "rm -rf dist && bunx --bun astro check && bunx --bun astro build",
"preview": "bunx --bun astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/check": "^0.7.0",
"@astrojs/node": "^8.2.5",
"@astrojs/react": "^3.4.0",
"@types/react": "^18.3.2",
"@astrojs/node": "^8.3.2",
"@astrojs/react": "^3.6.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"astro": "^4.9.1",
"astro": "^4.11.3",
"bootstrap": "^5.3.3",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"typescript": "^5.3.3"
"react-icons": "^5.2.1",
"typescript": "^5.5.2"
},
"devDependencies": {
"@biomejs/biome": "1.7.3"
"@biomejs/biome": "1.8.3"
}
}

View file

@ -0,0 +1,3 @@
<div class="col-auto"><a href="/home">Movies</a></div>
<div class="col-auto"><a href="/home/settings">Settings</a></div>
<div class="col-auto"><a href="/logout">Logout</a></div>

View file

@ -2,7 +2,9 @@ import LoginForm, { type LoginFormValue } from "./LoginForm";
export default function LoginFormData() {
function handleOnFormSubmit(data: LoginFormValue) {
fetch(`${import.meta.env.PUBLIC_API_URL}/accounts/login`, {
const searchParams = new URLSearchParams(window.location.search);
fetch("/api/accounts/login", {
method: "POST",
body: JSON.stringify(data),
credentials: "include",
@ -13,7 +15,7 @@ export default function LoginFormData() {
})
.then((res) => res.json())
.then((json) => {
window.location.href = "/home";
window.location.href = searchParams.get("redirect") || "/home";
})
.catch((err) => console.log(err));
}

View file

@ -1,4 +1,5 @@
---
import Header from "../components/Header.astro";
import RootLayout from "./RootLayout.astro";
interface Props {
@ -8,13 +9,11 @@ interface Props {
const { title } = Astro.props;
---
<RootLayout title={title}>
<RootLayout title={`Trepa - ${title}`}>
<div class="row justify-content-center">
<div class="col-auto">Films</div>
<div class="col-auto">Compte</div>
<div class="col-auto">Deconnexion</div>
<Header />
</div>
<hr />
<div class="row">
<div class="col">
<slot />
@ -22,4 +21,17 @@ const { title } = Astro.props;
</div>
</RootLayout>
<script></script>
<script>
const logoutElt = document.getElementById("logout-btn");
logoutElt?.addEventListener("click", () => {
fetch(`${import.meta.env.PUBLIC_API_URL}/accounts/logout`, {
method: "POST",
credentials: "include",
})
.then(() => {
window.location.href = "/";
})
.catch((err) => console.error(err));
});
</script>

View file

@ -2,22 +2,25 @@ import { defineMiddleware, sequence } from "astro:middleware";
const protectedRoutes = defineMiddleware(async (ctx, next) => {
const pathname = ctx.url.pathname;
if (!["/", "/register"].includes(pathname)) {
const jwt = ctx.cookies.get("token");
if (
!["/", "/register", "/logout"].includes(pathname) &&
!pathname.startsWith("/api")
) {
const jwt = ctx.cookies.get("jwt");
if (!jwt) {
return ctx.redirect("/");
return ctx.redirect(`/?redirect=${pathname}`);
}
const res = await fetch(
`${import.meta.env.PUBLIC_API_URL}/accounts/recovery`,
{
credentials: "include",
headers: ctx.request.headers,
const jwtValue = jwt.value;
const res = await fetch(`${import.meta.env.API_URL}/accounts/recovery`, {
credentials: "include",
headers: {
Authorization: `Bearer ${jwtValue}`,
},
);
});
if (res.status !== 201) {
return ctx.redirect("/");
if (res.status !== 200) {
return ctx.redirect(`/?redirect=${pathname}`);
}
ctx.locals.account = JSON.parse(await res.text()).account;

View file

@ -0,0 +1,28 @@
import type { APIRoute } from "astro";
export const POST: APIRoute = async ({ request, cookies }) => {
const reqBody = await request.text();
if (!reqBody) throw new Error("body not found");
const res = await fetch(`${import.meta.env.API_URL}/accounts/login`, {
method: "POST",
body: reqBody,
headers: {
"Content-Type": "application/json",
},
});
const resBody = await res.text();
const resBodyJson = JSON.parse(resBody);
if (res.status === 201 && resBodyJson?.jwt) {
cookies.set("jwt", resBodyJson.jwt, {
secure: true,
httpOnly: true,
path: "/",
sameSite: "strict",
});
}
return new Response(resBody, { status: res.status });
};

View file

@ -4,6 +4,6 @@ import HomeLayout from "../../layouts/HomeLayout.astro";
const account = Astro.locals.account;
---
<HomeLayout title="Trepa">
<HomeLayout title="Movies">
Hello {account?.username}
</HomeLayout>

View file

View file

View file

@ -0,0 +1,34 @@
---
import {
MdAccountBox,
MdAdminPanelSettings,
MdOutlineLocalMovies,
} from "react-icons/md";
import HomeLayout from "../../../layouts/HomeLayout.astro";
---
<HomeLayout title="Settings">
<div class="row justify-content-center">
<div class="col-4">
<div class="list-group">
<a
href="/home/settings/account"
class="list-group-item list-group-item-action"
>
<MdAccountBox /> My account
</a>
<a
href="/home/settings/accounts"
class="list-group-item list-group-item-action"
><MdAdminPanelSettings /> Accounts</a
>
<a
href="/home/settings/movies"
class="list-group-item list-group-item-action"
><MdOutlineLocalMovies /> Movies</a
>
</div>
</div>
</div>
</HomeLayout>

View file

4
src/pages/logout.astro Normal file
View file

@ -0,0 +1,4 @@
---
Astro.cookies.delete("jwt");
return Astro.redirect("/");
---