harden admin api authorization and add authz regression tests
This commit is contained in:
1 parent
272c9b36dd
commit
10b58245f5
28 files changed
+1336
-240
No files matched your search
@@ -3,6 +3,7 @@ import { auth } from "@clerk/nextjs/server";
|
||||
import { eq, sql } from "@fitai/database";
|
||||
import { db, users as usersTable, gyms as gymsTable } from "@fitai/database";
|
||||
import { ensureUserSynced } from "@/lib/sync-user";
|
||||
import { getDatabase } from "@/lib/database";
|
||||
import log from "@/lib/logger";
|
||||
|
||||
async function ensureGymsTable() {
|
||||
@@ -23,14 +24,37 @@ async function ensureGymsTable() {
|
||||
// Lists active gyms for selection (grid)
|
||||
export async function GET() {
|
||||
try {
|
||||
const { userId } = await auth();
|
||||
if (!userId) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
const appDb = await getDatabase();
|
||||
const currentUser = await ensureUserSynced(userId, appDb);
|
||||
|
||||
if (!currentUser) {
|
||||
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
}
|
||||
|
||||
if (currentUser.role !== "admin" && currentUser.role !== "superAdmin") {
|
||||
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
}
|
||||
|
||||
await ensureGymsTable();
|
||||
const rows = await db
|
||||
let rows = await db
|
||||
.select()
|
||||
.from(gymsTable)
|
||||
.where(eq(gymsTable.status, "active"))
|
||||
.orderBy(sql`created_at DESC`)
|
||||
.all();
|
||||
|
||||
if (currentUser.role !== "superAdmin") {
|
||||
if (!currentUser.gymId) {
|
||||
return NextResponse.json({ error: "No gym assigned" }, { status: 403 });
|
||||
}
|
||||
rows = rows.filter((row) => row.id === currentUser.gymId);
|
||||
}
|
||||
|
||||
return NextResponse.json(rows);
|
||||
} catch (error) {
|
||||
log.error("Failed to get gyms", error);
|
||||
@@ -48,60 +72,8 @@ export async function POST(req: Request) {
|
||||
const { userId } = await auth();
|
||||
if (!userId) return new NextResponse("Unauthorized", { status: 401 });
|
||||
|
||||
// Ensure our local DB has the user synced (role, etc.)
|
||||
const currentUser = await ensureUserSynced(userId, {
|
||||
// minimal facade for ensureUserSynced to work: it expects an object implementing part of IDatabase
|
||||
getUserById: async (id: string) => {
|
||||
const row = await db
|
||||
.select()
|
||||
.from(usersTable)
|
||||
.where(eq(usersTable.id, id))
|
||||
.get();
|
||||
return row
|
||||
? {
|
||||
id: row.id,
|
||||
email: row.email,
|
||||
firstName: row.firstName,
|
||||
lastName: row.lastName,
|
||||
password: row.password ?? "",
|
||||
phone: row.phone ?? undefined,
|
||||
role: row.role,
|
||||
imageUrl: undefined,
|
||||
createdAt: new Date(row.createdAt),
|
||||
updatedAt: new Date(row.updatedAt),
|
||||
}
|
||||
: null;
|
||||
},
|
||||
updateUser: async (id: string, updates: any) => {
|
||||
await db
|
||||
.update(usersTable)
|
||||
.set({
|
||||
...updates,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.where(eq(usersTable.id, id))
|
||||
.run();
|
||||
const row = await db
|
||||
.select()
|
||||
.from(usersTable)
|
||||
.where(eq(usersTable.id, id))
|
||||
.get();
|
||||
return row
|
||||
? {
|
||||
id: row.id,
|
||||
email: row.email,
|
||||
firstName: row.firstName,
|
||||
lastName: row.lastName,
|
||||
password: row.password ?? "",
|
||||
phone: row.phone ?? undefined,
|
||||
role: row.role,
|
||||
imageUrl: undefined,
|
||||
createdAt: new Date(row.createdAt),
|
||||
updatedAt: new Date(row.updatedAt),
|
||||
}
|
||||
: null;
|
||||
},
|
||||
} as any);
|
||||
const appDb = await getDatabase();
|
||||
const currentUser = await ensureUserSynced(userId, appDb);
|
||||
|
||||
if (
|
||||
!currentUser ||
|
||||
|
||||
Reference in new issue
Block a user