diff --git a/playbeat/package-lock.json b/playbeat/package-lock.json index 6f8cf31..bc92a84 100644 --- a/playbeat/package-lock.json +++ b/playbeat/package-lock.json @@ -23,6 +23,7 @@ "axios": "^1.6.8", "clsx": "^2.1.0", "framer-motion": "^11.0.5", + "jose": "^5.2.3", "react": "^18.2.0", "react-dom": "^18.2.0", "svelte": "^4.2.12", @@ -6921,6 +6922,14 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jose": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.3.tgz", + "integrity": "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/playbeat/package.json b/playbeat/package.json index c8b04cd..3736b1c 100644 --- a/playbeat/package.json +++ b/playbeat/package.json @@ -25,6 +25,7 @@ "axios": "^1.6.8", "clsx": "^2.1.0", "framer-motion": "^11.0.5", + "jose": "^5.2.3", "react": "^18.2.0", "react-dom": "^18.2.0", "svelte": "^4.2.12", diff --git a/playbeat/src/constants.ts b/playbeat/src/constants.ts new file mode 100644 index 0000000..e18e25d --- /dev/null +++ b/playbeat/src/constants.ts @@ -0,0 +1,2 @@ +export const PUBLIC_ROUTES = ["/", "/login", "/register"]; +export const TOKEN = "token"; \ No newline at end of file diff --git a/playbeat/src/middleware.ts b/playbeat/src/middleware.ts new file mode 100644 index 0000000..11281d5 --- /dev/null +++ b/playbeat/src/middleware.ts @@ -0,0 +1,73 @@ +import { errors, jwtVerify } from "jose"; +import { defineMiddleware } from "astro/middleware"; +import { TOKEN, PUBLIC_ROUTES } from "./constants"; + +// The JWT secret +const secret = new TextEncoder().encode(import.meta.env.JWT_SECRET_KEY); + +/** +* Verify if the client token is valid. +*/ +const verifyAuth = async (token?: string) => { + if (!token) { + return { + status: "unauthorized", + msg: "Please pass a request token", + } as const; + } + + try { + const jwtVerifyResult = await jwtVerify(token, secret); + + return { + status: "authorized", + payload: jwtVerifyResult.payload, + msg: "successfully verified auth token", + } as const; + } catch (err) { + if (err instanceof errors.JOSEError) { + return { status: "error", msg: err.message } as const; + } + + console.debug(err); + return { status: "error", msg: "could not validate auth token" } as const; + } +}; + +export const onRequest = defineMiddleware(async (context, next) => { + // Ignore auth validation for public routes + if (PUBLIC_ROUTES.includes(context.url.pathname)) { + // Respond as usual + return next(); + } + + // Get the token from cookies + const token = context.cookies.get(TOKEN)?.value; + // Verify the token + const validationResult = await verifyAuth(token); + + console.log(validationResult); + + // Handle the validation result + switch (validationResult.status) { + case "authorized": + // Respond as usual if the user is authorised + return next(); + + case "error": + case "unauthorized": + // If an API endpoint, return a JSON response + if (context.url.pathname.startsWith("/api/")) { + return new Response(JSON.stringify({ message: validationResult.msg }), { + status: 401, + }); + } + // Otherwise, this is a standard page. Redirect to the root page for the user to login + else { + return Response.redirect(new URL("/", context.url)); + } + + default: + return Response.redirect(new URL("/", context.url)); + } +}); \ No newline at end of file diff --git a/playbeat/src/pages/login.astro b/playbeat/src/pages/login.astro index 3717031..aee8b07 100644 --- a/playbeat/src/pages/login.astro +++ b/playbeat/src/pages/login.astro @@ -2,6 +2,7 @@ import Logo from '@/icons/Logo.astro' import NormalLayout from '../layouts/NormalLayout.astro' import LogoBlanco from '@/icons/LogoBlanco.astro' +import {TOKEN} from '@/constants.ts' import { loginUser } from '@/utils/login.ts' @@ -41,7 +42,7 @@ if (Astro.request.method ==="POST" ) { const response = await loginUser({email: values.email, contrasegna: values.contrasegna}); if (response && response.status === 200) { - Astro.cookies.set("token", response.data); + Astro.cookies.set(TOKEN, response.data); return Astro.redirect("/"); } else { errors.peticion = "Error al registrar, intentelo de nuevo"; diff --git a/playbeat/src/pages/logout.astro b/playbeat/src/pages/logout.astro index d59d07c..3ca81af 100644 --- a/playbeat/src/pages/logout.astro +++ b/playbeat/src/pages/logout.astro @@ -1,6 +1,6 @@ --- - +import {TOKEN} from '@/constants.ts' //Para usar astro.cookies.delete no pude usarse en una funcion, por lo tanto se puede solucionar con el siguiente codigo -Astro.cookies.delete('token'); +Astro.cookies.delete(TOKEN); return Astro.redirect('/login'); --- \ No newline at end of file diff --git a/playbeat/src/pages/register.astro b/playbeat/src/pages/register.astro index 57f16ac..7d0436e 100644 --- a/playbeat/src/pages/register.astro +++ b/playbeat/src/pages/register.astro @@ -1,6 +1,7 @@ --- import NormalLayout from '../layouts/NormalLayout.astro' import {registerUser} from '@/utils/register.ts' +import {TOKEN} from '@/constants.ts' const errors = { username: "", email: "", password: "", peticion:"" }; const values = { username: "", email: "", password: "", password2:"" }; @@ -47,7 +48,7 @@ if (Astro.request.method === "POST") { if (!hasErrors) { const response = await registerUser({nombreUsuario: name, email, contrasegna: password}); if (response && response.status === 201) { - Astro.cookies.set("token", response.data); + Astro.cookies.set(TOKEN, response.data); return Astro.redirect("/"); } else { errors.peticion = "Error al registrar, intentelo de nuevo";