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/(token-based)/list/[vorgang]/+page.server.ts b/src/routes/(token-based)/list/[vorgang]/+page.server.ts new file mode 100644 index 0000000..72c55fe --- /dev/null +++ b/src/routes/(token-based)/list/[vorgang]/+page.server.ts @@ -0,0 +1,23 @@ +import { getCrimesListByToken, getVorgaenge } from '$lib/server/vorgangService.js'; +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async ({ params, url }) => { + const vorgangList = getVorgaenge(); + const vorgangToken = params.vorgang; + const crimesList = await getCrimesListByToken(vorgangToken); + const vorgang = vorgangList.find((v) => v.vorgangToken === vorgangToken); //vorgang sollte ein eigener Typ werden, und dann kann man es hier vernünftig typisieren + if (!vorgang || !crimesList) { + throw new Error(`Fehlgeschlagen, es wurden keine Daten zum token gefunden`); + } + + //Variabeln für NameItemEditor + const crimeNames: string[] = crimesList.map((l) => l.name); + + return { + vorgang, + vorgangList, + crimesList, + url, + crimeNames + }; +} diff --git a/src/routes/(token-based)/list/[vorgang]/+page.ts b/src/routes/(token-based)/list/[vorgang]/+page.ts deleted file mode 100644 index fdc38b8..0000000 --- a/src/routes/(token-based)/list/[vorgang]/+page.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { API_ROUTES } from '../../../index.js'; - -export async function load({fetch, params, url}){ - const vorgangResponse = await fetch(API_ROUTES.LIST); - const vorgangList = await vorgangResponse.json() - const vorgangToken = params.vorgang; - const crimesListResponse = await fetch(API_ROUTES.VORGANG(vorgangToken)) - const crimesList = await crimesListResponse.json(); - const vorgang = vorgangList.find(v => v.vorgangToken === vorgangToken); //vorgang sollte ein eigener Typ werden, und dann kann man es hier vernünftig typisieren - if(!vorgang || !crimesList){ - throw new Error(`Fehlgeschlagen, es wurden keine Daten zum token gefunden`); - } - - //Variabeln für NameItemEditor - const crimeNames: string[] = crimesList.map((l) => l.name); - - - return { - vorgang, - vorgangList, - crimesList, - url, - crimeNames - } -} diff --git a/src/routes/api/list/+server.ts b/src/routes/api/list/+server.ts index b2c542d..21a483a 100644 --- a/src/routes/api/list/+server.ts +++ b/src/routes/api/list/+server.ts @@ -1,7 +1,7 @@ import { getVorgaenge } from '$lib/server/vorgangService'; +import { json } from '@sveltejs/kit'; -export async function GET({ locals }) { - +export async function GET() { 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 d3c0534..69fc6a6 100644 --- a/src/routes/api/list/[vorgang]/+server.ts +++ b/src/routes/api/list/[vorgang]/+server.ts @@ -1,4 +1,5 @@ import { BUCKET, client } from '$lib/minio'; +import { json } from '@sveltejs/kit'; import { deleteVorgangByToken, getCrimesListByToken, @@ -43,8 +44,7 @@ export async function HEAD({ params }) { } } -export async function GET({ params, locals }) { - +export async function GET({ params }) { 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 eb9473f..2af6f3a 100644 --- a/src/routes/api/list/[vorgang]/[tatort]/+server.ts +++ b/src/routes/api/list/[vorgang]/[tatort]/+server.ts @@ -24,7 +24,7 @@ export async function GET() { }); } -export async function DELETE({ request }: { request: Request }) { +export async function DELETE({ request }) { 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..9bf12d8 100644 --- a/src/routes/api/users/+server.ts +++ b/src/routes/api/users/+server.ts @@ -4,21 +4,14 @@ import bcrypt from 'bcrypt'; const saltRounds = 12; -export function GET({ locals }) { - if (!locals.user) { - return json({ error: 'Unauthorized' }, { status: 401 }); - } +export function GET() { const userList = getUsers(); return new Response(JSON.stringify(userList)); } -export async function POST({ request, locals }) { - if (!locals.user) { - return json({ error: 'Unauthorized' }, { status: 401 }); - } - +export async function POST({ request }) { 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..19109e7 100644 --- a/src/routes/api/users/[user]/+server.ts +++ b/src/routes/api/users/[user]/+server.ts @@ -1,11 +1,7 @@ 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 }); - } - +export async function DELETE({ params }) { 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 39c868c..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.skip('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 812ee36..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.skip('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/ListVorgangTatort.test.ts b/tests/api/ListVorgangTatort.test.ts index a870aa2..b49b0e1 100644 --- a/tests/api/ListVorgangTatort.test.ts +++ b/tests/api/ListVorgangTatort.test.ts @@ -1,6 +1,7 @@ import { describe, test, expect, vi } from 'vitest'; import { DELETE, PUT } from '$root/routes/api/list/[vorgang]/[tatort]/+server'; import { BUCKET, client } from '$lib/minio'; +import { baseData } from '../fixtures'; // Mock data and methods const fakeVorgangToken = `c399423a-ba37-4fe1-bbdf-80e5881168ff`; @@ -22,7 +23,8 @@ vi.mock('$lib/minio', () => ({ describe('API-Endpoints: list/[vorgang]/[tatort]', () => { test('Löschen von Tatorten', async () => { const request = new Request(fakeCrimeAPIURL); - const response = await DELETE({ request }); + const locals = { user: baseData.user } + const response = await DELETE({ locals, request }); expect(client.removeObject).toHaveBeenCalledWith(BUCKET, fakeCrimePath); @@ -40,11 +42,12 @@ describe('API-Endpoints: list/[vorgang]/[tatort]', () => { }) }); const params = { vorgang: fakeVorgangToken }; + const locals = { user: baseData.user } // Mock Datei nicht gefunden client.statObject.mockRejectedValueOnce(new Error('NotFound')); - const response = await PUT({ params, request }); + const response = await PUT({ locals, params, request }); const fakeCrimeNewPath = `${fakeVorgangToken}/${fakeCrimeNewName}`; expect(client.statObject).toHaveBeenCalledWith(BUCKET, fakeCrimeNewPath); @@ -62,9 +65,10 @@ describe('API-Endpoints: list/[vorgang]/[tatort]', () => { newName: '' }) }); + const locals = { user: baseData.user } const params = { vorgang: fakeVorgangToken }; - const response = await PUT({ params, request }); + const response = await PUT({ locals, params, request }); expect(response.status).toBe(400); }); @@ -77,11 +81,12 @@ describe('API-Endpoints: list/[vorgang]/[tatort]', () => { }) }); const params = { vorgang: fakeVorgangToken }; + const locals = { user: baseData.user } // Datei existiert bereits client.statObject.mockResolvedValueOnce({}); - const response = await PUT({ params, request }); + const response = await PUT({ locals, params, request }); expect(response.status).toBe(400); 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 diff --git a/tests/api/VorgangVorgangPIN.test.ts b/tests/api/VorgangVorgangPIN.test.ts index 8d39143..4c11d3a 100644 --- a/tests/api/VorgangVorgangPIN.test.ts +++ b/tests/api/VorgangVorgangPIN.test.ts @@ -1,9 +1,11 @@ import { describe, test, expect, vi } from 'vitest'; import { GET } from '$root/routes/api/vorgang/[vorgang]/vorgangPIN/+server'; import { db } from '$lib/server/dbService'; +import { baseData } from '../fixtures'; const mockEvent = { - params: { vorgang: '123' } + params: { vorgang: '123' }, + locals: { user: baseData.user } }; vi.mock('$lib/server/dbService', () => ({