From 192cd256d87d9a3b81150ca02bf65c109b2b15e5 Mon Sep 17 00:00:00 2001 From: Stan Wohlwend Date: Sat, 20 Apr 2024 15:49:16 +0200 Subject: [PATCH] Don't crash when trying to access a deleted user --- .../src/app/api/v1/current-user/route.tsx | 12 ++++- .../stack-server/src/lib/route-handlers.tsx | 1 - packages/stack-server/src/lib/users.tsx | 48 +++++++++++-------- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/packages/stack-server/src/app/api/v1/current-user/route.tsx b/packages/stack-server/src/app/api/v1/current-user/route.tsx index 325a0deea..d1b82ab65 100644 --- a/packages/stack-server/src/app/api/v1/current-user/route.tsx +++ b/packages/stack-server/src/app/api/v1/current-user/route.tsx @@ -8,6 +8,7 @@ import { updateClientUser, updateServerUser } from "@/lib/users"; import { decodeAccessToken, authorizationHeaderSchema } from "@/lib/tokens"; const putOrGetSchema = yup.object({ + method: yup.string().oneOf(["GET", "PUT"]).required(), query: yup.object({ server: yup.string().oneOf(["true", "false"]).default("false"), }).required(), @@ -29,6 +30,7 @@ const putOrGetSchema = yup.object({ const handler = deprecatedSmartRouteHandler(async (req: NextRequest) => { const { + method, query: { server, }, @@ -73,7 +75,11 @@ const handler = deprecatedSmartRouteHandler(async (req: NextRequest) => { const { userId, projectId: accessTokenProjectId } = decodedAccessToken; if (accessTokenProjectId !== projectId) { - return NextResponse.json(null); + if (method === "GET") { + return NextResponse.json(null); + } else { + throw new StatusError(StatusError.NotFound); + } } let user; @@ -107,6 +113,10 @@ const handler = deprecatedSmartRouteHandler(async (req: NextRequest) => { ); } + if (method === "PUT" && !user) { + throw new StatusError(StatusError.NotFound); + } + return NextResponse.json(user); }); export const GET = handler; diff --git a/packages/stack-server/src/lib/route-handlers.tsx b/packages/stack-server/src/lib/route-handlers.tsx index 643c7856a..140084dd8 100644 --- a/packages/stack-server/src/lib/route-handlers.tsx +++ b/packages/stack-server/src/lib/route-handlers.tsx @@ -349,7 +349,6 @@ export function redirectHandler(redirectPath: string, statusCode: 301 | 302 | 30 urlWithTrailingSlash.pathname += "/"; } const newUrl = new URL(redirectPath, urlWithTrailingSlash); - console.log({ req, newUrl }); return { statusCode, headers: { diff --git a/packages/stack-server/src/lib/users.tsx b/packages/stack-server/src/lib/users.tsx index c06c7652a..40b543396 100644 --- a/packages/stack-server/src/lib/users.tsx +++ b/packages/stack-server/src/lib/users.tsx @@ -2,6 +2,7 @@ import { UserCustomizableJson, UserJson, ServerUserCustomizableJson, ServerUserJ import { ProjectUser } from "@prisma/client"; import { prismaClient } from "@/prisma-client"; import { ProjectDB, fullProjectInclude, projectJsonFromDbType } from "@/lib/projects"; +import { filterUndefined } from "@stackframe/stack-shared/dist/utils/objects"; export async function getClientUser(projectId: string, userId: string): Promise { return await updateClientUser(projectId, userId, {}); @@ -51,26 +52,35 @@ export async function updateServerUser( userId: string, update: Partial, ): Promise { - const user = await prismaClient.projectUser.update({ - where: { - projectId_projectUserId: { - projectId, - projectUserId: userId, + let user; + try { + user = await prismaClient.projectUser.update({ + where: { + projectId_projectUserId: { + projectId, + projectUserId: userId, + }, }, - }, - include: { - project: { - include: fullProjectInclude, - } - }, - data: Object.fromEntries(Object.entries({ - displayName: update.displayName, - primaryEmail: update.primaryEmail, - primaryEmailVerified: update.primaryEmailVerified, - clientMetadata: update.clientMetadata as any, - serverMetadata: update.serverMetadata as any, - }).filter(([_, v]) => v !== undefined)), - }); + include: { + project: { + include: fullProjectInclude, + } + }, + data: filterUndefined({ + displayName: update.displayName, + primaryEmail: update.primaryEmail, + primaryEmailVerified: update.primaryEmailVerified, + clientMetadata: update.clientMetadata as any, + serverMetadata: update.serverMetadata as any, + }), + }); + } catch (e) { + // TODO this is kinda hacky, instead we should have the entire method throw an error instead of returning null and have a separate getServerUser function that may return null + if ((e as any)?.code === 'P2025') { + return null; + } + throw e; + } return getServerUserFromDbType(user, user.project); }