2023-05-23 01:15:29 +00:00
|
|
|
import type { Membership } from "@prisma/client";
|
|
|
|
|
2023-04-25 22:39:47 +00:00
|
|
|
import { prisma } from "@calcom/prisma";
|
2023-05-23 01:15:29 +00:00
|
|
|
import { MembershipRole } from "@calcom/prisma/enums";
|
2023-04-25 22:39:47 +00:00
|
|
|
|
|
|
|
import { TRPCError } from "@trpc/server";
|
|
|
|
|
2023-05-09 19:27:05 +00:00
|
|
|
import authedProcedure from "../../../procedures/authedProcedure";
|
2023-04-25 22:39:47 +00:00
|
|
|
import { webhookIdAndEventTypeIdSchema } from "./types";
|
|
|
|
|
|
|
|
export const webhookProcedure = authedProcedure
|
|
|
|
.input(webhookIdAndEventTypeIdSchema.optional())
|
|
|
|
.use(async ({ ctx, input, next }) => {
|
|
|
|
// Endpoints that just read the logged in user's data - like 'list' don't necessary have any input
|
|
|
|
if (!input) return next();
|
2023-05-23 01:15:29 +00:00
|
|
|
const { id, teamId, eventTypeId } = input;
|
|
|
|
|
|
|
|
const assertPartOfTeamWithRequiredAccessLevel = (memberships?: Membership[], teamId?: number) => {
|
|
|
|
if (!memberships) return false;
|
|
|
|
if (teamId) {
|
|
|
|
return memberships.some(
|
|
|
|
(membership) =>
|
|
|
|
membership.teamId === teamId &&
|
|
|
|
(membership.role === MembershipRole.ADMIN || membership.role === MembershipRole.OWNER)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return memberships.some(
|
|
|
|
(membership) =>
|
|
|
|
membership.userId === ctx.user.id &&
|
|
|
|
(membership.role === MembershipRole.ADMIN || membership.role === MembershipRole.OWNER)
|
|
|
|
);
|
|
|
|
};
|
2023-04-25 22:39:47 +00:00
|
|
|
|
2023-05-23 01:15:29 +00:00
|
|
|
if (id) {
|
|
|
|
//check if user is authorized to edit webhook
|
|
|
|
const webhook = await prisma.webhook.findFirst({
|
2023-04-25 22:39:47 +00:00
|
|
|
where: {
|
2023-05-23 01:15:29 +00:00
|
|
|
id: id,
|
2023-04-25 22:39:47 +00:00
|
|
|
},
|
|
|
|
include: {
|
2023-05-23 01:15:29 +00:00
|
|
|
user: true,
|
|
|
|
team: true,
|
|
|
|
eventType: true,
|
2023-04-25 22:39:47 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2023-05-23 01:15:29 +00:00
|
|
|
if (webhook) {
|
2023-06-09 11:18:59 +00:00
|
|
|
if (teamId && teamId !== webhook.teamId) {
|
|
|
|
throw new TRPCError({
|
|
|
|
code: "UNAUTHORIZED",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (eventTypeId && eventTypeId !== webhook.eventTypeId) {
|
|
|
|
throw new TRPCError({
|
|
|
|
code: "UNAUTHORIZED",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-05-23 01:15:29 +00:00
|
|
|
if (webhook.teamId) {
|
|
|
|
const user = await prisma.user.findFirst({
|
|
|
|
where: {
|
|
|
|
id: ctx.user.id,
|
|
|
|
},
|
|
|
|
include: {
|
|
|
|
teams: true,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
const userHasAdminOwnerPermissionInTeam =
|
|
|
|
user &&
|
|
|
|
user.teams.some(
|
|
|
|
(membership) =>
|
|
|
|
membership.teamId === webhook.teamId &&
|
|
|
|
(membership.role === MembershipRole.ADMIN || membership.role === MembershipRole.OWNER)
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!userHasAdminOwnerPermissionInTeam) {
|
|
|
|
throw new TRPCError({
|
|
|
|
code: "UNAUTHORIZED",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else if (webhook.eventTypeId) {
|
|
|
|
const eventType = await prisma.eventType.findFirst({
|
|
|
|
where: {
|
|
|
|
id: webhook.eventTypeId,
|
|
|
|
},
|
|
|
|
include: {
|
|
|
|
team: {
|
|
|
|
include: {
|
|
|
|
members: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
if (eventType && eventType.userId !== ctx.user.id) {
|
|
|
|
if (!assertPartOfTeamWithRequiredAccessLevel(eventType.team?.members)) {
|
|
|
|
throw new TRPCError({
|
|
|
|
code: "UNAUTHORIZED",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (webhook.userId && webhook.userId !== ctx.user.id) {
|
|
|
|
throw new TRPCError({
|
|
|
|
code: "UNAUTHORIZED",
|
|
|
|
});
|
|
|
|
}
|
2023-04-25 22:39:47 +00:00
|
|
|
}
|
2023-05-23 01:15:29 +00:00
|
|
|
} else {
|
|
|
|
//check if user is authorized to create webhook on event type or team
|
|
|
|
if (teamId) {
|
|
|
|
const user = await prisma.user.findFirst({
|
|
|
|
where: {
|
|
|
|
id: ctx.user.id,
|
|
|
|
},
|
|
|
|
include: {
|
|
|
|
teams: true,
|
|
|
|
},
|
2023-04-25 22:39:47 +00:00
|
|
|
});
|
2023-05-23 01:15:29 +00:00
|
|
|
|
|
|
|
if (!assertPartOfTeamWithRequiredAccessLevel(user?.teams, teamId)) {
|
|
|
|
throw new TRPCError({
|
|
|
|
code: "UNAUTHORIZED",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else if (eventTypeId) {
|
|
|
|
const eventType = await prisma.eventType.findFirst({
|
|
|
|
where: {
|
|
|
|
id: eventTypeId,
|
|
|
|
},
|
|
|
|
include: {
|
|
|
|
team: {
|
|
|
|
include: {
|
|
|
|
members: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
if (eventType && eventType.userId !== ctx.user.id) {
|
|
|
|
if (!assertPartOfTeamWithRequiredAccessLevel(eventType.team?.members)) {
|
|
|
|
throw new TRPCError({
|
|
|
|
code: "UNAUTHORIZED",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2023-04-25 22:39:47 +00:00
|
|
|
}
|
|
|
|
}
|
2023-05-23 01:15:29 +00:00
|
|
|
|
2023-04-25 22:39:47 +00:00
|
|
|
return next();
|
|
|
|
});
|