From fd907c985112e7f0867e1533b270659fb9d94bc4 Mon Sep 17 00:00:00 2001 From: Chi Cong Tran Date: Tue, 4 Nov 2025 09:22:53 +0100 Subject: [PATCH] move API protection check into hooks, adjusting corresponding tests --- src/hooks.server.ts | 10 +++++ src/routes/api/list/+server.ts | 3 -- src/routes/api/list/[vorgang]/+server.ts | 9 ----- .../api/list/[vorgang]/[tatort]/+server.ts | 6 --- src/routes/api/users/+server.ts | 7 ---- src/routes/api/users/[user]/+server.ts | 4 -- tests/api/API_Protection.test.ts | 37 +++++++++++++++++++ tests/api/List.test.ts | 15 -------- tests/api/ListVorgang.test.ts | 15 -------- tests/api/Users.test.ts | 15 -------- 10 files changed, 47 insertions(+), 74 deletions(-) create mode 100644 tests/api/API_Protection.test.ts diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 1eb3671..a7e170f 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -14,5 +14,15 @@ export const handle: Handle = async ({ event, resolve }) => { event.cookies.delete('session', {path: ROUTE_NAMES.ROOT}); event.locals.user = null; } + + if (event.url.pathname.startsWith('/api')) { + if (!event.locals.user) { + return new Response(JSON.stringify({ error: 'Unauthorized' }), { + status: 401, + headers: { 'Content-Type': 'application/json' } + }); + } + } + return await resolve(event); } diff --git a/src/routes/api/list/+server.ts b/src/routes/api/list/+server.ts index b8fa28a..5ffc53d 100644 --- a/src/routes/api/list/+server.ts +++ b/src/routes/api/list/+server.ts @@ -2,9 +2,6 @@ import { getVorgaenge } from '$lib/server/vorgangService'; import { json } from '@sveltejs/kit'; export async function GET({ locals }) { - if (!locals.user) { - return json({ error: 'Unauthorized' }, { status: 401 }); - } const vorgaenge = getVorgaenge(); return new Response(JSON.stringify(vorgaenge), { diff --git a/src/routes/api/list/[vorgang]/+server.ts b/src/routes/api/list/[vorgang]/+server.ts index 4f4155a..c4d1f2f 100644 --- a/src/routes/api/list/[vorgang]/+server.ts +++ b/src/routes/api/list/[vorgang]/+server.ts @@ -7,9 +7,6 @@ import { } from '$lib/server/vorgangService'; export async function DELETE({ locals, params }) { - if (!locals.user) { - return json({ error: 'Unauthorized' }, { status: 401 }); - } const vorgangToken = params.vorgang; const object_list = await new Promise((resolve, reject) => { @@ -34,9 +31,6 @@ export async function DELETE({ locals, params }) { } export async function HEAD({ locals, params }) { - if (!locals.user) { - return json({ error: 'Unauthorized' }, { status: 401 }); - } try { const vorgangName = params.vorgang; const existing = vorgangNameExists(vorgangName); @@ -51,9 +45,6 @@ export async function HEAD({ locals, params }) { } export async function GET({ params, locals }) { - if (!locals.user) { - return json({ error: 'Unauthorized' }, { status: 401 }); - } try { const vorgangToken = params.vorgang; const crimesList = await getCrimesListByToken(vorgangToken); diff --git a/src/routes/api/list/[vorgang]/[tatort]/+server.ts b/src/routes/api/list/[vorgang]/[tatort]/+server.ts index c6d7036..8e0442f 100644 --- a/src/routes/api/list/[vorgang]/[tatort]/+server.ts +++ b/src/routes/api/list/[vorgang]/[tatort]/+server.ts @@ -2,9 +2,6 @@ import { BUCKET, client } from '$lib/minio'; import { json } from '@sveltejs/kit'; export async function GET({ locals }) { - if (!locals.user) { - return json({ error: 'Unauthorized' }, { status: 401 }); - } const stream = client.listObjectsV2(BUCKET, '', true); const result = new ReadableStream({ start(controller) { @@ -28,9 +25,6 @@ export async function GET({ locals }) { } export async function DELETE({ locals, request }) { - if (!locals.user) { - return json({ error: 'Unauthorized' }, { status: 401 }); - } const url_fragments = request.url.split('/'); const item = url_fragments.at(-1); const vorgang = url_fragments.at(-2); diff --git a/src/routes/api/users/+server.ts b/src/routes/api/users/+server.ts index 7bf820c..8a3cdd5 100644 --- a/src/routes/api/users/+server.ts +++ b/src/routes/api/users/+server.ts @@ -5,9 +5,6 @@ import bcrypt from 'bcrypt'; const saltRounds = 12; export function GET({ locals }) { - if (!locals.user) { - return json({ error: 'Unauthorized' }, { status: 401 }); - } const userList = getUsers(); @@ -15,10 +12,6 @@ export function GET({ locals }) { } export async function POST({ request, locals }) { - if (!locals.user) { - return json({ error: 'Unauthorized' }, { status: 401 }); - } - const data = await request.json(); const userName = data.userName; const userPassword = data.userPassword; diff --git a/src/routes/api/users/[user]/+server.ts b/src/routes/api/users/[user]/+server.ts index 704ae19..1339248 100644 --- a/src/routes/api/users/[user]/+server.ts +++ b/src/routes/api/users/[user]/+server.ts @@ -2,10 +2,6 @@ import { json } from '@sveltejs/kit'; import { deleteUser } from '$lib/server/userService'; export async function DELETE({ params, locals }) { - if (!locals.user) { - return json({ error: 'Unauthorized' }, { status: 401 }); - } - const userId = params.user; const rowCount = deleteUser(userId); diff --git a/tests/api/API_Protection.test.ts b/tests/api/API_Protection.test.ts new file mode 100644 index 0000000..8dfa69b --- /dev/null +++ b/tests/api/API_Protection.test.ts @@ -0,0 +1,37 @@ +import { describe, test, expect, vi } from 'vitest'; +import { handle } from '../../src/hooks.server'; + +const event = { + url: new URL("http://localhost/api/list"), + cookies: { get: vi.fn(() => null) }, + locals: {user: null} +}; + +vi.mock('$lib/auth', () => ({ + decryptToken: vi.fn() +})); + +describe('API-Endpoints: Zugangs-Mechanismus', () => { + test('Unautorisierter Zugriff', async () => { + const resolve = vi.fn(); + + const response = await handle({ event, resolve }); + + expect(response.status).toBe(401); + const body = await response.json(); + expect(body.error).toBe('Unauthorized'); + expect(resolve).not.toHaveBeenCalled(); + }); + + test('Authentifizierter Zugriff', async () => { + event.locals = {user: { id: 'admin', admin: true }} + + const resolve = vi.fn(() => new Response('ok', { status: 200 })); + + const response = await handle({ event, resolve }); + + expect(response.status).toBe(200); + expect(await response.text()).toBe('ok'); + expect(resolve).toHaveBeenCalled(); + }); +}) \ No newline at end of file diff --git a/tests/api/List.test.ts b/tests/api/List.test.ts index d7b5ce4..ae54ad8 100644 --- a/tests/api/List.test.ts +++ b/tests/api/List.test.ts @@ -14,21 +14,6 @@ const event = { }; describe('API-Endpoints: list', () => { - test('Unerlaubter Zugriff', async () => { - const event = { - locals: { - user: null - } - }; - - const response = await GET(event); - expect(response.status).toBe(401); - - const json = await response.json(); - const errorObj = { error: 'Unauthorized' }; - expect(json).toEqual(errorObj); - }); - test('Leere Liste wenn keine Vorgänge existieren', async () => { vi.mocked(getVorgaenge).mockReturnValueOnce([]); diff --git a/tests/api/ListVorgang.test.ts b/tests/api/ListVorgang.test.ts index ae25cfc..4429d53 100644 --- a/tests/api/ListVorgang.test.ts +++ b/tests/api/ListVorgang.test.ts @@ -31,21 +31,6 @@ const MockEvent = { }; describe('API-Endpoints: list/[vorgang]', () => { - test('Unerlaubter Zugriff', async () => { - const event = { - locals: { - user: null - } - }; - - const response = await GET(event); - expect(response.status).toBe(401); - - const json = await response.json(); - const errorObj = { error: 'Unauthorized' }; - expect(json).toEqual(errorObj); - }); - test('Vorgang ohne Tatorte', async () => { const testCrimesList = []; diff --git a/tests/api/Users.test.ts b/tests/api/Users.test.ts index a721b46..07e0b50 100644 --- a/tests/api/Users.test.ts +++ b/tests/api/Users.test.ts @@ -16,21 +16,6 @@ vi.mock('bcrypt', () => ({ })); describe('API-Endpoint: Users', () => { - test('Unerlaubter Zugriff', async () => { - const event = { - locals: { - user: null - } - }; - - const response = await GET(event); - expect(response.status).toBe(401); - - const errorMessage = { error: 'Unauthorized' }; - const json = await response.json(); - expect(json).toEqual(errorMessage); - }); - // [INFO] Test auf keine User nicht notwendig, da immer min. ein User vorhanden // Mock eingelogter User bzw. stelle locals.user zur Verfügung