mirror of
https://github.com/jcreek/LivingDexTracker.git
synced 2026-07-13 02:53:45 +00:00
fix(#55): implement user data isolation to prevent cross-user data access
- Add server-side authentication validation for all protected API endpoints - Create auth utility with requireAuth() function for session validation - Update CombinedDataRepository to filter data by authenticated user ID - Add findByUserId() method to CatchRecordRepository for user-specific queries - Replace client-side userId parameters with server-side session extraction - Use MongoDB aggregation with $lookup and $expr for secure user filtering - Return 401 errors for unauthenticated requests - Fix critical security vulnerability where users could see others' catch records Fixes: User data isolation bug where one user's catch records were used for everyone Security: Prevents unauthorized access to other users' Pokemon tracking data
This commit is contained in:
@@ -1,19 +1,27 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { json, error } from '@sveltejs/kit';
|
||||
import { dbConnect, dbDisconnect } from '$lib/utils/db';
|
||||
import { type CatchRecord } from '$lib/models/CatchRecord';
|
||||
import CatchRecordRepository from '$lib/repositories/CatchRecordRepository';
|
||||
import { requireAuth } from '$lib/utils/auth';
|
||||
import type { RequestEvent } from '@sveltejs/kit';
|
||||
|
||||
export const GET = async () => {
|
||||
export const GET = async (event: RequestEvent) => {
|
||||
let catchData = null as CatchRecord[] | null;
|
||||
|
||||
try {
|
||||
const userId = await requireAuth(event);
|
||||
await dbConnect();
|
||||
const repo = new CatchRecordRepository();
|
||||
catchData = await repo.findAll();
|
||||
catchData = await repo.findByUserId(userId);
|
||||
// order by pokedexEntryId property, ascending
|
||||
catchData = catchData.sort((a, b) => a.pokedexEntryId - b.pokedexEntryId);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
if (error.status) {
|
||||
// Re-throw SvelteKit errors (like 401)
|
||||
throw error;
|
||||
}
|
||||
return json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
} finally {
|
||||
dbDisconnect();
|
||||
}
|
||||
@@ -21,29 +29,40 @@ export const GET = async () => {
|
||||
return json(catchData);
|
||||
};
|
||||
|
||||
export const PUT = async ({ request }) => {
|
||||
export const PUT = async (event: RequestEvent) => {
|
||||
try {
|
||||
const data: Partial<CatchRecord> = await request.json();
|
||||
const userId = await requireAuth(event);
|
||||
const data: Partial<CatchRecord> = await event.request.json();
|
||||
|
||||
// Ensure the userId is set to the authenticated user
|
||||
data.userId = userId;
|
||||
|
||||
await dbConnect();
|
||||
const repo = new CatchRecordRepository();
|
||||
const upsertedRecord = await repo.upsert(data);
|
||||
return json(upsertedRecord);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw error(500, 'Internal Server Error');
|
||||
if (err.status) {
|
||||
throw err;
|
||||
}
|
||||
return json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
} finally {
|
||||
await dbDisconnect();
|
||||
}
|
||||
};
|
||||
|
||||
export const POST = async ({ request }) => {
|
||||
export const POST = async (event: RequestEvent) => {
|
||||
try {
|
||||
const records: Partial<CatchRecord>[] = await request.json();
|
||||
const userId = await requireAuth(event);
|
||||
const records: Partial<CatchRecord>[] = await event.request.json();
|
||||
await dbConnect();
|
||||
const repo = new CatchRecordRepository();
|
||||
|
||||
const insertedRecords = [];
|
||||
for (const record of records) {
|
||||
// Ensure the userId is set to the authenticated user
|
||||
record.userId = userId;
|
||||
const upsertedRecord = await repo.upsert(record);
|
||||
insertedRecords.push(upsertedRecord);
|
||||
}
|
||||
@@ -51,7 +70,10 @@ export const POST = async ({ request }) => {
|
||||
return json(insertedRecords);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw error(500, 'Internal Server Error');
|
||||
if (err.status) {
|
||||
throw err;
|
||||
}
|
||||
return json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
} finally {
|
||||
await dbDisconnect();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user