From 65b29830f06fd00f4a52fbb07aaa8082837a5253 Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Sun, 12 May 2024 22:28:34 -0400 Subject: [PATCH] enable modifying profile settings for SSO users --- .../users/userId/deleteUserById.ts | 22 +- .../users/userId/updateUserById.ts | 237 ++++++++---------- lib/api/verifyUser.ts | 8 +- pages/api/v1/auth/[...nextauth].ts | 2 +- 4 files changed, 117 insertions(+), 152 deletions(-) diff --git a/lib/api/controllers/users/userId/deleteUserById.ts b/lib/api/controllers/users/userId/deleteUserById.ts index 19dce14..87c0934 100644 --- a/lib/api/controllers/users/userId/deleteUserById.ts +++ b/lib/api/controllers/users/userId/deleteUserById.ts @@ -25,16 +25,20 @@ export default async function deleteUserById( }; } - // Then, we check if the provided password matches the one stored in the database (disabled in SSO/OAuth integrations) - if (user.password && !isServerAdmin) { - console.log("isServerAdmin", isServerAdmin); - console.log("isServerAdmin", body.password); - const isPasswordValid = bcrypt.compareSync( - body.password, - user.password as string - ); + if (!isServerAdmin) { + if (user.password) { + const isPasswordValid = bcrypt.compareSync( + body.password, + user.password as string + ); - if (!isPasswordValid && !isServerAdmin) { + if (!isPasswordValid && !isServerAdmin) { + return { + response: "Invalid credentials.", + status: 401, // Unauthorized + }; + } + } else { return { response: "Invalid credentials.", status: 401, // Unauthorized diff --git a/lib/api/controllers/users/userId/updateUserById.ts b/lib/api/controllers/users/userId/updateUserById.ts index f2b5e91..782cc3a 100644 --- a/lib/api/controllers/users/userId/updateUserById.ts +++ b/lib/api/controllers/users/userId/updateUserById.ts @@ -24,144 +24,106 @@ export default async function updateUserById( }, }); - if (ssoUser) { - // deny changes to SSO-defined properties - if (data.email !== user?.email) { + if (emailEnabled && !data.email) + return { + response: "Email invalid.", + status: 400, + }; + else if (!data.username) + return { + response: "Username invalid.", + status: 400, + }; + if (data.newPassword && data.newPassword?.length < 8) + return { + response: "Password must be at least 8 characters.", + status: 400, + }; + // Check email (if enabled) + const checkEmail = + /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; + if (emailEnabled && !checkEmail.test(data.email?.toLowerCase() || "")) + return { + response: "Please enter a valid email.", + status: 400, + }; + + const checkUsername = RegExp("^[a-z0-9_-]{3,31}$"); + + if (!checkUsername.test(data.username.toLowerCase())) + return { + response: + "Username has to be between 3-30 characters, no spaces and special characters are allowed.", + status: 400, + }; + + const userIsTaken = await prisma.user.findFirst({ + where: { + id: { not: userId }, + OR: emailEnabled + ? [ + { + username: data.username.toLowerCase(), + }, + { + email: data.email?.toLowerCase(), + }, + ] + : [ + { + username: data.username.toLowerCase(), + }, + ], + }, + }); + + if (userIsTaken) { + if (data.email?.toLowerCase().trim() === userIsTaken.email?.trim()) return { - response: "SSO users cannot change their email.", + response: "Email is taken.", status: 400, }; + else if ( + data.username?.toLowerCase().trim() === userIsTaken.username?.trim() + ) + return { + response: "Username is taken.", + status: 400, + }; + + return { + response: "Username/Email is taken.", + status: 400, + }; + } + + // Avatar Settings + + if ( + data.image?.startsWith("data:image/jpeg;base64") && + data.image.length < 1572864 + ) { + try { + const base64Data = data.image.replace(/^data:image\/jpeg;base64,/, ""); + + createFolder({ filePath: `uploads/avatar` }); + + await createFile({ + filePath: `uploads/avatar/${userId}.jpg`, + data: base64Data, + isBase64: true, + }); + } catch (err) { + console.log("Error saving image:", err); } - if (data.newPassword) { - return { - response: "SSO Users cannot change their password.", - status: 400, - }; - } - if (data.name !== user?.name) { - return { - response: "SSO Users cannot change their name.", - status: 400, - }; - } - if (data.username !== user?.username) { - return { - response: "SSO Users cannot change their username.", - status: 400, - }; - } - if (data.image?.startsWith("data:image/jpeg;base64")) { - return { - response: "SSO Users cannot change their avatar.", - status: 400, - }; - } - } else { - // verify only for non-SSO users - // SSO users cannot change their email, password, name, username, or avatar - if (emailEnabled && !data.email) - return { - response: "Email invalid.", - status: 400, - }; - else if (!data.username) - return { - response: "Username invalid.", - status: 400, - }; - if (data.newPassword && data.newPassword?.length < 8) - return { - response: "Password must be at least 8 characters.", - status: 400, - }; - // Check email (if enabled) - const checkEmail = - /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; - if (emailEnabled && !checkEmail.test(data.email?.toLowerCase() || "")) - return { - response: "Please enter a valid email.", - status: 400, - }; - - const checkUsername = RegExp("^[a-z0-9_-]{3,31}$"); - - if (!checkUsername.test(data.username.toLowerCase())) - return { - response: - "Username has to be between 3-30 characters, no spaces and special characters are allowed.", - status: 400, - }; - - const userIsTaken = await prisma.user.findFirst({ - where: { - id: { not: userId }, - OR: emailEnabled - ? [ - { - username: data.username.toLowerCase(), - }, - { - email: data.email?.toLowerCase(), - }, - ] - : [ - { - username: data.username.toLowerCase(), - }, - ], - }, - }); - - if (userIsTaken) { - if (data.email?.toLowerCase().trim() === userIsTaken.email?.trim()) - return { - response: "Email is taken.", - status: 400, - }; - else if ( - data.username?.toLowerCase().trim() === userIsTaken.username?.trim() - ) - return { - response: "Username is taken.", - status: 400, - }; - - return { - response: "Username/Email is taken.", - status: 400, - }; - } - - // Avatar Settings - - if (data.image?.startsWith("data:image/jpeg;base64")) { - if (data.image.length < 1572864) { - try { - const base64Data = data.image.replace( - /^data:image\/jpeg;base64,/, - "" - ); - - createFolder({ filePath: `uploads/avatar` }); - - await createFile({ - filePath: `uploads/avatar/${userId}.jpg`, - data: base64Data, - isBase64: true, - }); - } catch (err) { - console.log("Error saving image:", err); - } - } else { - console.log("A file larger than 1.5MB was uploaded."); - return { - response: "A file larger than 1.5MB was uploaded.", - status: 400, - }; - } - } else if (data.image == "") { - removeFile({ filePath: `uploads/avatar/${userId}.jpg` }); - } + } else if (data.image?.length && data.image?.length >= 1572864) { + console.log("A file larger than 1.5MB was uploaded."); + return { + response: "A file larger than 1.5MB was uploaded.", + status: 400, + }; + } else if (data.image == "") { + removeFile({ filePath: `uploads/avatar/${userId}.jpg` }); } const previousEmail = ( @@ -182,7 +144,12 @@ export default async function updateUserById( username: data.username?.toLowerCase().trim(), email: data.email?.toLowerCase().trim(), isPrivate: data.isPrivate, - image: data.image ? `uploads/avatar/${userId}.jpg` : "", + image: + data.image && data.image.startsWith("http") + ? data.image + : data.image + ? `uploads/avatar/${userId}.jpg` + : "", collectionOrder: data.collectionOrder.filter( (value, index, self) => self.indexOf(value) === index ), diff --git a/lib/api/verifyUser.ts b/lib/api/verifyUser.ts index 6e5fdf5..d77a74f 100644 --- a/lib/api/verifyUser.ts +++ b/lib/api/verifyUser.ts @@ -32,19 +32,13 @@ export default async function verifyUser({ subscriptions: true, }, }); - const ssoUser = await prisma.account.findFirst({ - where: { - userId: userId, - }, - }); if (!user) { res.status(404).json({ response: "User not found." }); return null; } - if (!user.username && !ssoUser) { - // SSO users don't need a username + if (!user.username) { res.status(401).json({ response: "Username not found.", }); diff --git a/pages/api/v1/auth/[...nextauth].ts b/pages/api/v1/auth/[...nextauth].ts index c1d4c1d..79b6f08 100644 --- a/pages/api/v1/auth/[...nextauth].ts +++ b/pages/api/v1/auth/[...nextauth].ts @@ -119,7 +119,7 @@ if ( passwordMatches = bcrypt.compareSync(password, user.password); } - if (passwordMatches) { + if (passwordMatches && user?.password) { return { id: user?.id }; } else return null as any; },