fix: idor checks on all exposed endpoints
This commit is contained in:
@@ -2,11 +2,12 @@ import { json, error } from '@sveltejs/kit';
|
|||||||
import { db } from '$lib/server/db';
|
import { db } from '$lib/server/db';
|
||||||
import { mappool, mappoolSlot } from '$lib/server/db/schema';
|
import { mappool, mappoolSlot } from '$lib/server/db/schema';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
|
import { requireAuth, requireOwnerOrAdmin } from '$lib/server/permissions';
|
||||||
import type { RequestHandler } from './$types';
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
// Get a mappool with its slots
|
// Get a mappool with its slots
|
||||||
export const GET: RequestHandler = async ({ params, locals }) => {
|
export const GET: RequestHandler = async ({ params, locals }) => {
|
||||||
if (!locals.user) error(401, 'Not logged in');
|
requireAuth(locals);
|
||||||
|
|
||||||
const pool = await db.query.mappool.findFirst({
|
const pool = await db.query.mappool.findFirst({
|
||||||
where: eq(mappool.id, params.id)
|
where: eq(mappool.id, params.id)
|
||||||
@@ -24,7 +25,17 @@ export const GET: RequestHandler = async ({ params, locals }) => {
|
|||||||
|
|
||||||
// Delete a mappool
|
// Delete a mappool
|
||||||
export const DELETE: RequestHandler = async ({ params, locals }) => {
|
export const DELETE: RequestHandler = async ({ params, locals }) => {
|
||||||
if (!locals.user) error(401, 'Not logged in');
|
const pool = await db.query.mappool.findFirst({
|
||||||
|
where: eq(mappool.id, params.id)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!pool) error(404, 'Mappool not found');
|
||||||
|
|
||||||
|
requireOwnerOrAdmin(
|
||||||
|
locals,
|
||||||
|
pool.createdBy,
|
||||||
|
'Only the mappool creator or an admin can delete this'
|
||||||
|
);
|
||||||
|
|
||||||
await db.delete(mappool).where(eq(mappool.id, params.id));
|
await db.delete(mappool).where(eq(mappool.id, params.id));
|
||||||
return json({ ok: true });
|
return json({ ok: true });
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
import { json, error } from '@sveltejs/kit';
|
import { json, error } from '@sveltejs/kit';
|
||||||
import { db } from '$lib/server/db';
|
import { db } from '$lib/server/db';
|
||||||
import { mappoolSlot } from '$lib/server/db/schema';
|
import { mappool, mappoolSlot } from '$lib/server/db/schema';
|
||||||
import { eq, and } from 'drizzle-orm';
|
import { eq, and } from 'drizzle-orm';
|
||||||
import { getBeatmap } from '$lib/server/osu/api';
|
import { requireOwnerOrAdmin } from '$lib/server/permissions';
|
||||||
import type { RequestHandler } from './$types';
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
// Add a slot to a mappool
|
// Add a slot to a mappool
|
||||||
export const POST: RequestHandler = async ({ params, request, locals }) => {
|
export const POST: RequestHandler = async ({ params, request, locals }) => {
|
||||||
if (!locals.user) error(401, 'Not logged in');
|
const pool = await db.query.mappool.findFirst({
|
||||||
|
where: eq(mappool.id, params.id)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!pool) error(404, 'Mappool not found');
|
||||||
|
|
||||||
|
requireOwnerOrAdmin(locals, pool.createdBy, 'Only the mappool creator or an admin can add slots');
|
||||||
|
|
||||||
const { beatmapId, category, mods } = await request.json();
|
const { beatmapId, category, mods } = await request.json();
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,22 @@
|
|||||||
import { json, error } from '@sveltejs/kit';
|
import { json, error } from '@sveltejs/kit';
|
||||||
import { db } from '$lib/server/db';
|
import { db } from '$lib/server/db';
|
||||||
import { mappoolSlot } from '$lib/server/db/schema';
|
import { mappool, mappoolSlot } from '$lib/server/db/schema';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
|
import { requireOwnerOrAdmin } from '$lib/server/permissions';
|
||||||
import type { RequestHandler } from './$types';
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
export const DELETE: RequestHandler = async ({ params, locals }) => {
|
export const DELETE: RequestHandler = async ({ params, locals }) => {
|
||||||
if (!locals.user) error(401, 'Not logged in');
|
const pool = await db.query.mappool.findFirst({
|
||||||
|
where: eq(mappool.id, params.id)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!pool) error(404, 'Mappool not found');
|
||||||
|
|
||||||
|
requireOwnerOrAdmin(
|
||||||
|
locals,
|
||||||
|
pool.createdBy,
|
||||||
|
'Only the mappool creator or an admin can delete slots'
|
||||||
|
);
|
||||||
|
|
||||||
await db.delete(mappoolSlot).where(eq(mappoolSlot.id, params.slotId));
|
await db.delete(mappoolSlot).where(eq(mappoolSlot.id, params.slotId));
|
||||||
return json({ ok: true });
|
return json({ ok: true });
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
// src/routes/api/matches/[id]/lobby/+server.ts
|
// src/routes/api/matches/[id]/lobby/+server.ts
|
||||||
import { json, error } from '@sveltejs/kit';
|
import { json, error } from '@sveltejs/kit';
|
||||||
import { moveToLobby } from '$lib/server/match/engine';
|
import { moveToLobby } from '$lib/server/match/engine';
|
||||||
|
import { requireRole } from '$lib/server/permissions';
|
||||||
import type { RequestHandler } from './$types';
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
export const POST: RequestHandler = async ({ params, request, locals }) => {
|
export const POST: RequestHandler = async ({ params, request, locals }) => {
|
||||||
if (!locals.user) error(401, 'Not logged in');
|
requireRole(locals, 'referee', 'Only referees or admins can move matches to lobby');
|
||||||
|
|
||||||
const body = await request.json().catch(() => ({}));
|
const body = await request.json().catch(() => ({}));
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,30 @@
|
|||||||
// src/routes/api/matches/[id]/pick/+server.ts
|
// src/routes/api/matches/[id]/pick/+server.ts
|
||||||
import { json, error } from '@sveltejs/kit';
|
import { json, error } from '@sveltejs/kit';
|
||||||
import { pickMap } from '$lib/server/match/engine';
|
import { pickMap } from '$lib/server/match/engine';
|
||||||
|
import { requireAuth, hasRole } from '$lib/server/permissions';
|
||||||
|
import { getMatchFull } from '$lib/server/match/helpers';
|
||||||
import type { RequestHandler } from './$types';
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
export const POST: RequestHandler = async ({ params, request, locals }) => {
|
export const POST: RequestHandler = async ({ params, request, locals }) => {
|
||||||
if (!locals.user) error(401, 'Not logged in');
|
const user = requireAuth(locals);
|
||||||
|
|
||||||
const { participantId, mappoolSlotId } = await request.json();
|
const { mappoolSlotId } = await request.json();
|
||||||
if (!participantId || !mappoolSlotId) {
|
if (!mappoolSlotId) {
|
||||||
error(400, 'participantId and mappoolSlotId required');
|
error(400, 'mappoolSlotId required');
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = await getMatchFull(params.id);
|
||||||
|
|
||||||
|
// Find the participant linked to the authenticated user
|
||||||
|
const participant = match.participants.find((p) => p.players.some((pl) => pl.userId === user.id));
|
||||||
|
|
||||||
|
if (!participant && !hasRole(user.role, 'referee')) {
|
||||||
|
error(403, 'You are not a participant in this match');
|
||||||
|
}
|
||||||
|
|
||||||
|
const participantId = participant?.id;
|
||||||
|
if (!participantId) {
|
||||||
|
error(400, 'Could not resolve participant');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,14 +1,30 @@
|
|||||||
// src/routes/api/matches/[id]/roll/+server.ts
|
// src/routes/api/matches/[id]/roll/+server.ts
|
||||||
import { json, error } from '@sveltejs/kit';
|
import { json, error } from '@sveltejs/kit';
|
||||||
import { submitRoll } from '$lib/server/match/engine';
|
import { submitRoll } from '$lib/server/match/engine';
|
||||||
|
import { requireAuth, hasRole } from '$lib/server/permissions';
|
||||||
|
import { getMatchFull } from '$lib/server/match/helpers';
|
||||||
import type { RequestHandler } from './$types';
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
export const POST: RequestHandler = async ({ params, request, locals }) => {
|
export const POST: RequestHandler = async ({ params, request, locals }) => {
|
||||||
if (!locals.user) error(401, 'Not logged in');
|
const user = requireAuth(locals);
|
||||||
|
|
||||||
const { participantId, value } = await request.json();
|
const { value } = await request.json();
|
||||||
if (!participantId || value == null) {
|
if (value == null) {
|
||||||
error(400, 'participantId and value required');
|
error(400, 'value required');
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = await getMatchFull(params.id);
|
||||||
|
|
||||||
|
// Find the participant linked to the authenticated user
|
||||||
|
const participant = match.participants.find((p) => p.players.some((pl) => pl.userId === user.id));
|
||||||
|
|
||||||
|
if (!participant && !hasRole(user.role, 'referee')) {
|
||||||
|
error(403, 'You are not a participant in this match');
|
||||||
|
}
|
||||||
|
|
||||||
|
const participantId = participant?.id;
|
||||||
|
if (!participantId) {
|
||||||
|
error(400, 'Could not resolve participant');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
// src/routes/api/matches/[id]/rolling/+server.ts
|
// src/routes/api/matches/[id]/rolling/+server.ts
|
||||||
import { json, error } from '@sveltejs/kit';
|
import { json, error } from '@sveltejs/kit';
|
||||||
import { moveToRolling } from '$lib/server/match/engine';
|
import { moveToRolling } from '$lib/server/match/engine';
|
||||||
|
import { requireRole } from '$lib/server/permissions';
|
||||||
import type { RequestHandler } from './$types';
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
export const POST: RequestHandler = async ({ params, locals }) => {
|
export const POST: RequestHandler = async ({ params, locals }) => {
|
||||||
if (!locals.user) error(401, 'Not logged in');
|
requireRole(locals, 'referee', 'Only referees or admins can move matches to rolling');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const m = await moveToRolling(params.id);
|
const m = await moveToRolling(params.id);
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
// src/routes/api/matches/[id]/score/+server.ts
|
// src/routes/api/matches/[id]/score/+server.ts
|
||||||
import { json, error } from '@sveltejs/kit';
|
import { json, error } from '@sveltejs/kit';
|
||||||
import { submitGameScores } from '$lib/server/match/engine';
|
import { submitGameScores } from '$lib/server/match/engine';
|
||||||
|
import { requireRole } from '$lib/server/permissions';
|
||||||
import type { RequestHandler } from './$types';
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
export const POST: RequestHandler = async ({ request, locals }) => {
|
export const POST: RequestHandler = async ({ request, locals }) => {
|
||||||
if (!locals.user) error(401, 'Not logged in');
|
requireRole(locals, 'referee', 'Only referees or admins can submit scores');
|
||||||
|
|
||||||
const { matchGameId, scores } = await request.json();
|
const { matchGameId, scores } = await request.json();
|
||||||
if (!matchGameId || !scores?.length) {
|
if (!matchGameId || !scores?.length) {
|
||||||
|
|||||||
Reference in New Issue
Block a user