fix(api): improve security and performance in leaderboard and rooms
This commit is contained in:
@@ -1,9 +1,18 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { prisma } from "../../../lib/prisma";
|
import { prisma } from "../../../lib/prisma";
|
||||||
|
|
||||||
|
export const revalidate = 60;
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
|
try {
|
||||||
const users = await prisma.user.findMany({
|
const users = await prisma.user.findMany({
|
||||||
include: { games: true },
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
games: {
|
||||||
|
select: { mode: true, won: true, clicks: true, timeSeconds: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const rows = users
|
const rows = users
|
||||||
@@ -12,7 +21,7 @@ export async function GET() {
|
|||||||
const solo = all.filter((g) => g.mode === "solo");
|
const solo = all.filter((g) => g.mode === "solo");
|
||||||
const multi = all.filter((g) => g.mode === "multi");
|
const multi = all.filter((g) => g.mode === "multi");
|
||||||
const wins = all.filter((g) => g.won);
|
const wins = all.filter((g) => g.won);
|
||||||
const wonGames = all.filter((g) => g.won && g.clicks > 0);
|
const wonGames = wins.filter((g) => g.clicks > 0);
|
||||||
const avgClicks = wonGames.length
|
const avgClicks = wonGames.length
|
||||||
? Math.round(wonGames.reduce((s, g) => s + g.clicks, 0) / wonGames.length)
|
? Math.round(wonGames.reduce((s, g) => s + g.clicks, 0) / wonGames.length)
|
||||||
: null;
|
: null;
|
||||||
@@ -34,7 +43,11 @@ export async function GET() {
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter((r) => r.totalGames > 0)
|
.filter((r) => r.totalGames > 0)
|
||||||
.sort((a, b) => b.wins - a.wins || b.totalGames - a.totalGames);
|
.sort((a, b) => b.wins - a.wins || b.totalGames - a.totalGames)
|
||||||
|
.slice(0, 100);
|
||||||
|
|
||||||
return NextResponse.json(rows);
|
return NextResponse.json(rows);
|
||||||
|
} catch {
|
||||||
|
return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ function getRooms(): Map<string, Room> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generatePlayerId(): string {
|
function generatePlayerId(): string {
|
||||||
return Math.random().toString(36).slice(2, 10);
|
return crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timeout joueur inactif : 15s
|
// Timeout joueur inactif : 15s
|
||||||
@@ -156,7 +156,10 @@ export async function PATCH(
|
|||||||
return Response.json({ error: "Joueur inconnu" }, { status: 404 });
|
return Response.json({ error: "Joueur inconnu" }, { status: 404 });
|
||||||
}
|
}
|
||||||
|
|
||||||
player.currentArticle = article ?? "";
|
if (!article || typeof article !== "string" || article.length > 300) {
|
||||||
|
return Response.json({ error: "Article invalide" }, { status: 400 });
|
||||||
|
}
|
||||||
|
player.currentArticle = article;
|
||||||
player.lastSeen = Date.now();
|
player.lastSeen = Date.now();
|
||||||
|
|
||||||
// Verifier si le joueur a atteint la cible
|
// Verifier si le joueur a atteint la cible
|
||||||
@@ -223,3 +226,4 @@ export async function PATCH(
|
|||||||
return Response.json({ error: "Action inconnue" }, { status: 400 });
|
return Response.json({ error: "Action inconnue" }, { status: 400 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ function generateCode(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generatePlayerId(): string {
|
function generatePlayerId(): string {
|
||||||
return Math.random().toString(36).slice(2, 10);
|
return crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nettoie les rooms inactives depuis plus de 2h
|
// Nettoie les rooms inactives depuis plus de 2h
|
||||||
|
|||||||
Reference in New Issue
Block a user