Skip to content

Commit

Permalink
Fixes security issue when updating workflows (#3661)
Browse files Browse the repository at this point in the history
* check if workflow is deleted before deleting reminders

* disable continue button when mutation is loading

* check if new active event types belong to user

* fix issue with onCascade deletion

* Simplified ANDs

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
4 people committed Aug 9, 2022
1 parent e8d6d50 commit d363f6e
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ export function NewWorkflowButton() {
</div>
)}
</>
<div className="mt-8 flex flex-row-reverse gap-x-2">
<div className=" mt-8 flex flex-row-reverse gap-x-2">
<Button type="submit" disabled={createMutation.isLoading}>
{t("continue")}
</Button>
Expand Down
124 changes: 74 additions & 50 deletions packages/trpc/server/routers/viewer/workflows.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,8 @@ export const workflowsRouter = createProtectedRouter()
async resolve({ ctx, input }) {
const workflow = await ctx.prisma.workflow.findFirst({
where: {
AND: [
{
userId: ctx.user.id,
},
{
id: input.id,
},
],
userId: ctx.user.id,
id: input.id,
},
select: {
id: true,
Expand Down Expand Up @@ -136,41 +130,43 @@ export const workflowsRouter = createProtectedRouter()
async resolve({ ctx, input }) {
const { id } = input;

//delete all scheduled reminders of this workflow
const scheduledReminders = await ctx.prisma.workflowReminder.findMany({
const workflowToDelete = await ctx.prisma.workflow.findFirst({
where: {
workflowStep: {
workflowId: id,
},
scheduled: true,
NOT: {
referenceId: null,
},
id,
userId: ctx.user.id,
},
});

scheduledReminders.forEach((reminder) => {
if (reminder.referenceId) {
if (reminder.method === WorkflowMethods.EMAIL) {
deleteScheduledEmailReminder(reminder.referenceId);
} else if (reminder.method === WorkflowMethods.SMS) {
deleteScheduledSMSReminder(reminder.referenceId);
}
}
});

await ctx.prisma.workflow.deleteMany({
where: {
AND: [
{
userId: ctx.user.id,
if (workflowToDelete) {
const scheduledReminders = await ctx.prisma.workflowReminder.findMany({
where: {
workflowStep: {
workflowId: id,
},
{
id,
scheduled: true,
NOT: {
referenceId: null,
},
],
},
});
},
});

scheduledReminders.forEach((reminder) => {
if (reminder.referenceId) {
if (reminder.method === WorkflowMethods.EMAIL) {
deleteScheduledEmailReminder(reminder.referenceId);
} else if (reminder.method === WorkflowMethods.SMS) {
deleteScheduledSMSReminder(reminder.referenceId);
}
}
});

await ctx.prisma.workflow.deleteMany({
where: {
userId: ctx.user.id,
id,
},
});
}

return {
id,
Expand Down Expand Up @@ -214,7 +210,6 @@ export const workflowsRouter = createProtectedRouter()

if (!userWorkflow || userWorkflow.userId !== user.id) throw new TRPCError({ code: "UNAUTHORIZED" });

//remove all scheduled Email and SMS reminders for eventTypes that are not active any more
const oldActiveOnEventTypes = await ctx.prisma.workflowsOnEventTypes.findMany({
where: {
workflowId: id,
Expand All @@ -224,6 +219,46 @@ export const workflowsRouter = createProtectedRouter()
},
});

const newActiveEventTypes = activeOn.filter((eventType) => {
if (
!oldActiveOnEventTypes ||
!oldActiveOnEventTypes
.map((oldEventType) => {
return oldEventType.eventTypeId;
})
.includes(eventType)
) {
return eventType;
}
});

//check if new event types belong to user
for (const newEventTypeId of newActiveEventTypes) {
const newEventType = await ctx.prisma.eventType.findFirst({
where: {
id: newEventTypeId,
},
include: {
team: {
include: {
members: true,
},
},
},
});

if (
newEventType &&
newEventType.userId !== user.id &&
newEventType?.team?.members.filter((membership) => {
membership.userId === user.id;
}).length
) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
}

//remove all scheduled Email and SMS reminders for eventTypes that are not active any more
const removedEventTypes = oldActiveOnEventTypes
.map((eventType) => {
return eventType.eventTypeId;
Expand Down Expand Up @@ -300,18 +335,7 @@ export const workflowsRouter = createProtectedRouter()
let newEventTypes: number[] = [];
if (activeOn.length) {
if (trigger === WorkflowTriggerEvents.BEFORE_EVENT) {
newEventTypes = activeOn.filter((eventType) => {
if (
!oldActiveOnEventTypes ||
!oldActiveOnEventTypes
.map((oldEventType) => {
return oldEventType.eventTypeId;
})
.includes(eventType)
) {
return eventType;
}
});
newEventTypes = newActiveEventTypes;
}
if (newEventTypes.length > 0) {
//create reminders for all bookings with newEventTypes
Expand Down

0 comments on commit d363f6e

Please sign in to comment.