With the MCP plugin enabled, payload.auth() can return a payload-mcp-api-keys doc instead of a User. Add an isPayloadUser type guard and use it in every server action, page, and route that treats the auth result as a real user, so API-key sessions can no longer pass user auth checks. hasRoles now explicitly requires a users-collection doc.
39 lines
1.6 KiB
TypeScript
39 lines
1.6 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import config from "@payload-config";
|
|
import { isPayloadUser } from "@/utils/access-control/isPayloadUser";
|
|
import { getPayload } from "payload";
|
|
import { removePresence, touchPresence } from "@/lib/realtime/presence";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
export const runtime = "nodejs";
|
|
|
|
async function authenticate(req: NextRequest) {
|
|
const payload = await getPayload({ config: await config });
|
|
return payload.auth({ headers: req.headers, canSetHeaders: false });
|
|
}
|
|
|
|
function channelFrom(req: NextRequest): string | null {
|
|
const channel = req.nextUrl.searchParams.get("channel")?.trim();
|
|
return channel && /^[a-z0-9:_-]{1,80}$/i.test(channel) ? channel : null;
|
|
}
|
|
|
|
export async function POST(req: NextRequest) {
|
|
const channel = channelFrom(req);
|
|
if (!channel) return NextResponse.json({ ok: false, error: "Invalid channel." }, { status: 400 });
|
|
const { user } = await authenticate(req);
|
|
if (!isPayloadUser(user)) return NextResponse.json({ ok: false }, { status: 401 });
|
|
touchPresence(channel, {
|
|
id: user.id as number,
|
|
name: user.payloadDisplayName || user.username || `Pilot #${user.id}`,
|
|
});
|
|
return NextResponse.json({ ok: true });
|
|
}
|
|
|
|
export async function DELETE(req: NextRequest) {
|
|
const channel = channelFrom(req);
|
|
if (!channel) return NextResponse.json({ ok: false, error: "Invalid channel." }, { status: 400 });
|
|
const { user } = await authenticate(req);
|
|
if (!isPayloadUser(user)) return NextResponse.json({ ok: false }, { status: 401 });
|
|
removePresence(channel, user.id as number);
|
|
return NextResponse.json({ ok: true });
|
|
}
|