fix: payload cleanup (#13552)

* fix: payload cleanup

* Update eventType.ts

* Send whitelisted fields everywhere

* Removed a user select

* Removed extra usage of users

* Put back user field with fewer selects

* Added user pick

* Removed more users selects

* Another select removal

---------

Co-authored-by: Hariom <hariombalhara@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
This commit is contained in:
Omar López
2024-02-06 11:20:08 -03:00
committed by GitHub
co-authored by Hariom Keith Williams
parent bba68e09a9
commit 66b5dfd796
19 changed files with 230 additions and 48 deletions
@@ -51,7 +51,6 @@ export async function getHandler(req: NextApiRequest) {
include: {
customInputs: true,
team: { select: { slug: true } },
users: true,
hosts: { select: { userId: true, isFixed: true } },
owner: { select: { username: true, id: true } },
children: { select: { id: true, userId: true } },
-1
View File
@@ -56,7 +56,6 @@ async function getHandler(req: NextApiRequest) {
include: {
customInputs: true,
team: { select: { slug: true } },
users: true,
hosts: { select: { userId: true, isFixed: true } },
owner: { select: { username: true, id: true } },
children: { select: { id: true, userId: true } },
@@ -59,7 +59,6 @@ async function getHandler(req: NextApiRequest) {
include: {
customInputs: true,
team: { select: { slug: true } },
users: true,
hosts: { select: { userId: true, isFixed: true } },
owner: { select: { username: true, id: true } },
children: { select: { id: true, userId: true } },
@@ -24,7 +24,12 @@ export const responseHandler = async ({ ctx, input }: ResponseHandlerOptions) =>
id: formId,
},
include: {
user: true,
user: {
select: {
id: true,
email: true,
},
},
},
});
if (!form) {
@@ -10,7 +10,7 @@ import type { OrderedResponses } from "../types/types";
import type { Response, SerializableForm } from "../types/types";
export async function onFormSubmission(
form: Ensure<SerializableForm<App_RoutingForms_Form> & { user: User }, "fields">,
form: Ensure<SerializableForm<App_RoutingForms_Form> & { user: Pick<User, "id" | "email"> }, "fields">,
response: Response
) {
const fieldResponsesByName: Record<
@@ -57,8 +57,6 @@ const Reschedule = async (bookingUid: string, cancellationReason: string) => {
const event = await prisma.eventType.findFirstOrThrow({
select: {
title: true,
users: true,
schedulingType: true,
},
where: {
id: bookingToReschedule.eventTypeId,
@@ -57,7 +57,6 @@ const Reschedule = async (bookingUid: string, cancellationReason: string) => {
const event = await prisma.eventType.findFirstOrThrow({
select: {
title: true,
users: true,
schedulingType: true,
},
where: {
@@ -47,7 +47,7 @@ const loginWithTotp = async (user: { email: string }) =>
type UserTeams = {
teams: (Membership & {
team: Team;
team: Pick<Team, "metadata">;
})[];
};
@@ -106,7 +106,9 @@ const providers: Provider[] = [
throw new Error(ErrorCode.InternalServerError);
}
const user = await UserRepository.findByEmailAndIncludeProfiles({ email: credentials.email });
const user = await UserRepository.findByEmailAndIncludeProfilesAndPassword({
email: credentials.email,
});
// Don't leak information about it being username or password that is invalid
if (!user) {
throw new Error(ErrorCode.IncorrectEmailPassword);
@@ -273,7 +275,9 @@ if (isSAMLLoginEnabled) {
email?: string;
locale?: string;
}) => {
const user = await UserRepository.findByEmailAndIncludeProfiles({ email: profile.email || "" });
const user = await UserRepository.findByEmailAndIncludeProfilesAndPassword({
email: profile.email || "",
});
if (!user) {
throw new Error(ErrorCode.UserNotFound);
}
@@ -339,7 +343,7 @@ if (isSAMLLoginEnabled) {
}
const { id, firstName, lastName, email } = userInfo;
const user = await UserRepository.findByEmailAndIncludeProfiles({ email });
const user = await UserRepository.findByEmailAndIncludeProfilesAndPassword({ email });
if (!user) {
throw new Error(ErrorCode.UserNotFound);
}
+20 -5
View File
@@ -1,4 +1,5 @@
import type { Prisma, EventType as PrismaEventType } from "@prisma/client";
import type { EventType as PrismaEventType } from "@prisma/client";
import { Prisma } from "@prisma/client";
import logger from "@calcom/lib/logger";
import { prisma } from "@calcom/prisma";
@@ -22,6 +23,16 @@ type IEventType = Ensure<
"title" | "slug" | "length"
>;
const userSelect = Prisma.validator<Prisma.UserSelect>()({
name: true,
avatarUrl: true,
username: true,
id: true,
email: true,
locale: true,
defaultScheduleId: true,
});
export class EventTypeRepository {
static async create(data: IEventType) {
const {
@@ -92,19 +103,23 @@ export class EventTypeRepository {
// TODO: As required by getByViewHandler - Make it configurable
team: {
include: {
eventTypes: true,
eventTypes: {
include: {
users: { select: userSelect },
},
},
},
},
hashedLink: true,
users: true,
users: { select: userSelect },
children: {
include: {
users: true,
users: { select: userSelect },
},
},
hosts: {
include: {
user: true,
user: { select: userSelect },
},
},
};
+47 -11
View File
@@ -1,5 +1,6 @@
import { prisma } from "@calcom/prisma";
import type { Prisma, MembershipRole } from "@calcom/prisma/client";
import type { MembershipRole } from "@calcom/prisma/client";
import { Prisma } from "@calcom/prisma/client";
import logger from "../../logger";
import { safeStringify } from "../../safeStringify";
@@ -14,6 +15,33 @@ type IMembership = {
role: MembershipRole;
};
const membershipSelect = Prisma.validator<Prisma.MembershipSelect>()({
id: true,
teamId: true,
userId: true,
accepted: true,
role: true,
disableImpersonation: true,
});
const teamParentSelect = Prisma.validator<Prisma.TeamSelect>()({
id: true,
name: true,
slug: true,
logoUrl: true,
parentId: true,
});
const userSelect = Prisma.validator<Prisma.UserSelect>()({
name: true,
avatarUrl: true,
username: true,
id: true,
email: true,
locale: true,
defaultScheduleId: true,
});
export class MembershipRepository {
static async create(data: IMembership) {
return await prisma.membership.create({
@@ -68,25 +96,33 @@ export class MembershipRepository {
include: {
team: {
include: {
members: true,
parent: true,
members: {
select: membershipSelect,
},
parent: {
select: teamParentSelect,
},
eventTypes: {
include: {
team: {
include: {
eventTypes: true,
eventTypes: {
include: {
users: { select: userSelect },
},
},
},
},
hashedLink: true,
users: true,
hosts: {
include: {
user: true,
},
},
users: { select: userSelect },
children: {
include: {
users: true,
users: { select: userSelect },
},
},
hosts: {
include: {
user: { select: userSelect },
},
},
},
+49 -9
View File
@@ -4,6 +4,7 @@ import { v4 as uuidv4 } from "uuid";
import { whereClauseForOrgWithSlugOrRequestedSlug } from "@calcom/ee/organizations/lib/orgDomains";
import { safeStringify } from "@calcom/lib/safeStringify";
import prisma from "@calcom/prisma";
import { Prisma } from "@calcom/prisma/client";
import type { Team } from "@calcom/prisma/client";
import type { UpId, UserAsPersonalProfile, UserProfile } from "@calcom/types/UserProfile";
@@ -11,6 +12,28 @@ import logger from "../../logger";
import { getParsedTeam } from "./teamUtils";
import { UserRepository } from "./user";
const userSelect = Prisma.validator<Prisma.UserSelect>()({
name: true,
avatarUrl: true,
username: true,
id: true,
email: true,
locale: true,
defaultScheduleId: true,
startTime: true,
endTime: true,
bufferTime: true,
});
const membershipSelect = Prisma.validator<Prisma.MembershipSelect>()({
id: true,
teamId: true,
userId: true,
accepted: true,
role: true,
disableImpersonation: true,
});
const log = logger.getSubLogger({ prefix: ["repository/profile"] });
const organizationSelect = {
id: true,
@@ -30,14 +53,17 @@ export class ProfileRepository {
return uuidv4();
}
private static getInheritedDataFromUser({ user }: { user: PrismaUser }) {
private static getInheritedDataFromUser({
user,
}: {
user: Pick<PrismaUser, "name" | "avatarUrl" | "startTime" | "endTime" | "bufferTime">;
}) {
return {
name: user.name,
avatarUrl: user.avatarUrl,
startTime: user.startTime,
endTime: user.endTime,
bufferTime: user.bufferTime,
avatar: user.avatar,
};
}
@@ -233,7 +259,9 @@ export class ProfileRepository {
organization: {
select: organizationSelect,
},
user: true,
user: {
select: userSelect,
},
},
});
@@ -268,7 +296,9 @@ export class ProfileRepository {
organization: {
select: organizationSelect,
},
user: true,
user: {
select: userSelect,
},
},
});
return profile;
@@ -313,11 +343,15 @@ export class ProfileRepository {
id,
},
include: {
user: true,
user: {
select: userSelect,
},
movedFromUser: true,
organization: {
include: {
members: true,
members: {
select: membershipSelect,
},
},
},
},
@@ -346,7 +380,9 @@ export class ProfileRepository {
organization: whereClauseForOrgWithSlugOrRequestedSlug(orgSlug),
},
include: {
user: true,
user: {
select: userSelect,
},
organization: {
select: organizationSelect,
},
@@ -416,7 +452,9 @@ export class ProfileRepository {
organizationId,
},
include: {
user: true,
user: {
select: userSelect,
},
organization: {
select: organizationSelect,
},
@@ -434,7 +472,9 @@ export class ProfileRepository {
organization: {
select: organizationSelect,
},
user: true,
user: {
select: userSelect,
},
},
});
if (!profile) {
+12 -1
View File
@@ -1,4 +1,4 @@
import type { Prisma } from "@prisma/client";
import { Prisma } from "@prisma/client";
import type { z } from "zod";
import { whereClauseForOrgWithSlugOrRequestedSlug } from "@calcom/ee/organizations/lib/orgDomains";
@@ -148,12 +148,23 @@ export async function getOrg<TeamSelect extends Prisma.TeamSelect>({
teamSelect,
});
}
const teamSelect = Prisma.validator<Prisma.TeamSelect>()({
id: true,
name: true,
slug: true,
logoUrl: true,
parentId: true,
metadata: true,
});
export class TeamRepository {
static async findById({ id }: { id: number }) {
const team = await prisma.team.findUnique({
where: {
id,
},
select: teamSelect,
});
if (!team) {
return null;
+59 -4
View File
@@ -1,6 +1,7 @@
import { whereClauseForOrgWithSlugOrRequestedSlug } from "@calcom/ee/organizations/lib/orgDomains";
import prisma from "@calcom/prisma";
import type { User as UserType, Prisma } from "@calcom/prisma/client";
import { Prisma } from "@calcom/prisma/client";
import type { User as UserType } from "@calcom/prisma/client";
import type { UpId, UserProfile } from "@calcom/types/UserProfile";
import { isOrganization } from "../../entityPermissionUtils";
@@ -12,6 +13,54 @@ import { getParsedTeam } from "./teamUtils";
const log = logger.getSubLogger({ prefix: ["[repository/user]"] });
export const ORGANIZATION_ID_UNKNOWN = "ORGANIZATION_ID_UNKNOWN";
const teamSelect = Prisma.validator<Prisma.TeamSelect>()({
id: true,
name: true,
slug: true,
metadata: true,
logoUrl: true,
});
const userSelect = Prisma.validator<Prisma.UserSelect>()({
id: true,
username: true,
name: true,
email: true,
emailVerified: true,
bio: true,
avatar: true,
avatarUrl: true,
timeZone: true,
startTime: true,
endTime: true,
weekStart: true,
bufferTime: true,
hideBranding: true,
theme: true,
createdDate: true,
trialEndsAt: true,
completedOnboarding: true,
locale: true,
timeFormat: true,
twoFactorSecret: true,
twoFactorEnabled: true,
backupCodes: true,
identityProviderId: true,
invitedTo: true,
brandColor: true,
darkBrandColor: true,
away: true,
allowDynamicBooking: true,
allowSEOIndexing: true,
receiveMonthlyDigestEmail: true,
verified: true,
disableImpersonation: true,
locked: true,
movedToProfileId: true,
metadata: true,
});
export class UserRepository {
static async findTeamsByUserId({ userId }: { userId: UserType["id"] }) {
const teamMemberships = await prisma.membership.findMany({
@@ -19,7 +68,9 @@ export class UserRepository {
userId: userId,
},
include: {
team: true,
team: {
select: teamSelect,
},
},
});
@@ -69,6 +120,7 @@ export class UserRepository {
return (
await prisma.user.findMany({
select: userSelect,
where,
})
).map((user) => {
@@ -136,7 +188,7 @@ export class UserRepository {
return { where, profiles };
}
static async findByEmailAndIncludeProfiles({ email }: { email: string }) {
static async findByEmailAndIncludeProfilesAndPassword({ email }: { email: string }) {
const user = await prisma.user.findUnique({
where: {
email: email.toLowerCase(),
@@ -157,7 +209,9 @@ export class UserRepository {
locale: true,
teams: {
include: {
team: true,
team: {
select: teamSelect,
},
},
},
},
@@ -179,6 +233,7 @@ export class UserRepository {
where: {
id,
},
select: userSelect,
});
if (!user) {
@@ -100,7 +100,11 @@ export const confirmHandler = async ({ ctx, input }: ConfirmOptions) => {
schedulingType: SchedulingType.COLLECTIVE,
},
select: {
users: true,
users: {
select: {
id: true,
},
},
},
});
@@ -127,7 +127,6 @@ export const requestRescheduleHandler = async ({ ctx, input }: RequestReschedule
event = await prisma.eventType.findFirstOrThrow({
select: {
title: true,
users: true,
schedulingType: true,
recurringEvent: true,
},
@@ -32,7 +32,11 @@ export const duplicateHandler = async ({ ctx, input }: DuplicateOptions) => {
include: {
customInputs: true,
schedule: true,
users: true,
users: {
select: {
id: true,
},
},
team: true,
workflows: true,
webhooks: true,
@@ -20,7 +20,11 @@ export const eventOwnerProcedure = authedProcedure
const event = await ctx.prisma.eventType.findUnique({
where: { id: input.id },
include: {
users: true,
users: {
select: {
id: true,
},
},
team: {
select: {
members: {
@@ -29,7 +29,14 @@ export const paymentsRouter = router({
},
include: {
payment: true,
user: true,
user: {
select: {
email: true,
locale: true,
name: true,
timeZone: true,
},
},
attendees: true,
eventType: true,
},
@@ -147,7 +147,11 @@ export const updateHandler = async ({ ctx, input }: UpdateOptions) => {
id: newEventTypeId,
},
include: {
users: true,
users: {
select: {
id: true,
},
},
team: {
include: {
members: true,