feat: logout + better token generation

This commit is contained in:
TheClashFruit 2024-08-29 16:06:07 +02:00
parent 7991ce7ee0
commit 77234531c5
Signed by: TheClashFruit
GPG key ID: 09BB24C34C2F3204
5 changed files with 90 additions and 9 deletions

View file

@ -2,9 +2,9 @@ import styles from '@/styles/Dropdown.module.scss';
import Link from 'next/link';
import { useRef } from 'react';
import { MouseEventHandler, useRef } from 'react';
export default function Dropdown({ children, items, className }: { children: React.ReactNode, items: { divider?: boolean, icon?: any, label?: string, href?: string }[], className: string }) {
export default function Dropdown({ children, items, className }: { children: React.ReactNode, items: { divider?: boolean, icon?: any, label?: string, href?: string, onClick?: MouseEventHandler<HTMLAnchorElement> }[], className: string }) {
const dropDownRef = useRef<HTMLDivElement>(null);
const handleClick = () => {
@ -26,11 +26,19 @@ export default function Dropdown({ children, items, className }: { children: Rea
</li>
) || (
<li key={i}>
<Link href={item.href!}>
{item.icon && <item.icon />}
{item.href ? (
<Link href={item.href!}>
{item.icon && <item.icon />}
{item.label}
</Link>
{item.label}
</Link>
) : (
<a onClick={item.onClick}>
{item.icon && <item.icon />}
{item.label}
</a>
)}
</li>
)
))}

View file

@ -40,6 +40,8 @@ export default function NavBar({ currentPage }: { currentPage: string }) {
const { publicRuntimeConfig } = getConfig();
const router = useRouter();
const server = {
version: '1.12.2'
};
@ -154,7 +156,15 @@ export default function NavBar({ currentPage }: { currentPage: string }) {
{
icon: LogOut,
label: 'Logout',
href: '/logout'
onClick: async (e) => {
e.preventDefault();
await fetch('/api/v1/session', {
method: 'DELETE'
});
router.reload();
}
}
]} className={styles.dropDown}>
<User />
@ -179,7 +189,15 @@ export default function NavBar({ currentPage }: { currentPage: string }) {
{
icon: LogOut,
label: 'Logout',
href: '/logout'
onClick: async (e) => {
e.preventDefault();
await fetch('/api/v1/session', {
method: 'DELETE'
});
router.reload();
}
}
]} className={styles.dropDown}>
<User />

View file

@ -107,10 +107,11 @@ class Database {
const sum = crypto.createHmac('sha256', process.env.AUTH_SECRET!);
const base = Buffer.from(user.id).toString('base64');
const date = Buffer.from((Date.now() - 1688940000000).toString()).toString('base64').replaceAll('=', '');
sum.update(userData.access_token);
const sid = base + '.' + sum.digest('hex');
const sid = base + '.' + date + '.' + sum.digest('hex');
const [ result ] = await this.mysqlPool!.execute('INSERT INTO sessions (sid, uid, access_token, refresh_token, id_token, user_agent, expires) VALUES (?, ?, ?, ?, ?, ?, ?)', [
sid,
@ -128,6 +129,10 @@ class Database {
}
}
async deleteSession(sid: string): Promise<void> {
await this.mysqlPool!.execute('DELETE FROM sessions WHERE sid = ?', [ sid ]);
}
async getSession(sid: string): Promise<any> {
const [ rows ] = await this.mysqlPool!.execute('SELECT * FROM sessions WHERE sid = ?', [ sid ]);

48
pages/api/v1/session.ts Normal file
View file

@ -0,0 +1,48 @@
import Database from '@/lib/Database';
import type { NextApiRequest, NextApiResponse } from 'next';
import { serialize } from 'cookie';
type Data = {
success: string;
};
interface Error {
error: string;
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data | Error>,
) {
const db = new Database();
const sid = req.cookies.session;
if (!sid)
return res.status(401).json({ error: 'Unauthorized' });
const session = await db.getSession(sid!);
if (!session)
return res.status(401).json({ error: 'Unauthorized' });
const user = await db.getUser(session.uid);
if (!user)
return res.status(404).json({ error: 'Not Found' });
if (req.method === 'DELETE') {
db.deleteSession(sid!);
res.setHeader('Set-Cookie', serialize('session', '', {
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
path: '/',
expires: new Date(0),
}));
return res.status(200).json({ success: 'Delete Session for ' + user.username });
}
res.status(405).json({ error: 'Method Not Allowed' });
}

View file

@ -53,6 +53,8 @@ a {
text-decoration: none;
cursor: pointer;
&:hover {
text-decoration: underline;
}