Disable ADMIN role when password requirements aren't met (#5445)
This commit is contained in:
@@ -13,6 +13,7 @@ import path from "path";
|
||||
import checkLicense from "@calcom/features/ee/common/server/checkLicense";
|
||||
import ImpersonationProvider from "@calcom/features/ee/impersonation/lib/ImpersonationProvider";
|
||||
import { hostedCal, isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
|
||||
import { ErrorCode, verifyPassword, isPasswordValid } from "@calcom/lib/auth";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { symmetricDecrypt } from "@calcom/lib/crypto";
|
||||
import { defaultCookies } from "@calcom/lib/default-cookies";
|
||||
@@ -20,7 +21,6 @@ import rateLimit from "@calcom/lib/rateLimit";
|
||||
import { serverConfig } from "@calcom/lib/serverConfig";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import { ErrorCode, verifyPassword } from "@lib/auth";
|
||||
import CalComAdapter from "@lib/auth/next-auth-custom-adapter";
|
||||
import { randomString } from "@lib/random";
|
||||
import slugify from "@lib/slugify";
|
||||
@@ -53,6 +53,17 @@ const providers: Provider[] = [
|
||||
where: {
|
||||
email: credentials.email.toLowerCase(),
|
||||
},
|
||||
select: {
|
||||
role: true,
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
email: true,
|
||||
identityProvider: true,
|
||||
password: true,
|
||||
twoFactorEnabled: true,
|
||||
twoFactorSecret: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
@@ -106,6 +117,17 @@ const providers: Provider[] = [
|
||||
});
|
||||
await limiter.check(10, user.email); // 10 requests per minute
|
||||
|
||||
// authentication success- but does it meet the minimum password requirements?
|
||||
if (user.role === "ADMIN" && !isPasswordValid(credentials.password, false, true)) {
|
||||
return {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
role: "USER",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
@@ -218,6 +240,13 @@ export default NextAuth({
|
||||
const existingUser = await prisma.user.findFirst({
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
where: { email: token.email! },
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
email: true,
|
||||
role: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!existingUser) {
|
||||
@@ -225,20 +254,18 @@ export default NextAuth({
|
||||
}
|
||||
|
||||
return {
|
||||
id: existingUser.id,
|
||||
username: existingUser.username,
|
||||
name: existingUser.name,
|
||||
email: existingUser.email,
|
||||
role: existingUser.role,
|
||||
impersonatedByUID: token?.impersonatedByUID as number,
|
||||
...existingUser,
|
||||
...token,
|
||||
};
|
||||
};
|
||||
|
||||
if (!user) {
|
||||
return await autoMergeIdentities();
|
||||
}
|
||||
|
||||
if (account && account.type === "credentials") {
|
||||
return {
|
||||
...token,
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
@@ -273,6 +300,7 @@ export default NextAuth({
|
||||
}
|
||||
|
||||
return {
|
||||
...token,
|
||||
id: existingUser.id,
|
||||
name: existingUser.name,
|
||||
username: existingUser.username,
|
||||
|
||||
@@ -15,13 +15,13 @@ const querySchema = z.object({
|
||||
.refine((val) => val.trim().length >= 1, { message: "Please enter at least one character" }),
|
||||
full_name: z.string().min(3, "Please enter at least 3 characters"),
|
||||
email_address: z.string().email({ message: "Please enter a valid email" }),
|
||||
password: z.string().refine((val) => isPasswordValid(val.trim()), {
|
||||
password: z.string().refine((val) => isPasswordValid(val.trim(), false, true), {
|
||||
message:
|
||||
"The password must be a minimum of 7 characters long containing at least one number and have a mixture of uppercase and lowercase letters",
|
||||
"The password must be a minimum of 15 characters long containing at least one number and have a mixture of uppercase and lowercase letters",
|
||||
}),
|
||||
});
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
async function handler(req: NextApiRequest) {
|
||||
const userCount = await prisma.user.count();
|
||||
if (userCount !== 0) {
|
||||
throw new HttpError({ statusCode: 400, message: "No setup needed." });
|
||||
|
||||
@@ -36,14 +36,15 @@ export async function getSession(options: GetSessionParams): Promise<Session | n
|
||||
export function isPasswordValid(password: string): boolean;
|
||||
export function isPasswordValid(
|
||||
password: string,
|
||||
breakdown: boolean
|
||||
breakdown: boolean,
|
||||
strict?: boolean
|
||||
): { caplow: boolean; num: boolean; min: boolean };
|
||||
export function isPasswordValid(password: string, breakdown?: boolean) {
|
||||
export function isPasswordValid(password: string, breakdown?: boolean, strict?: boolean) {
|
||||
let cap = false, // Has uppercase characters
|
||||
low = false, // Has lowercase characters
|
||||
num = false, // At least one number
|
||||
min = false; // Eight characters
|
||||
if (password.length > 7) min = true;
|
||||
min = false; // Eight characters, or fifteen in strict mode.
|
||||
if (password.length > 7 && (!strict || password.length > 14)) min = true;
|
||||
for (let i = 0; i < password.length; i++) {
|
||||
if (!isNaN(parseInt(password[i]))) num = true;
|
||||
else {
|
||||
|
||||
Reference in New Issue
Block a user