2
0

🐛 (editor) Fix typebot update permissions

This commit is contained in:
Baptiste Arnaud
2023-02-13 15:27:49 +01:00
parent 8a02c701da
commit bac97a8ee4

View File

@ -1,13 +1,12 @@
import { CollaborationType, Prisma } from 'db' import { CollaborationType, CollaboratorsOnTypebots, Prisma, User } from 'db'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { canReadTypebots, canWriteTypebots } from '@/utils/api/dbRules'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
import { getAuthenticatedUser } from '@/features/auth/api' import { getAuthenticatedUser } from '@/features/auth/api'
import { archiveResults } from '@/features/results/api' import { archiveResults } from '@/features/results/api'
import { typebotSchema } from 'models' import { Typebot, typebotSchema } from 'models'
import { captureEvent } from '@sentry/nextjs' import { captureEvent } from '@sentry/nextjs'
import { omit } from 'utils' import { isDefined, omit } from 'utils'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req) const user = await getAuthenticatedUser(req)
@ -26,15 +25,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
webhooks: true, webhooks: true,
}, },
}) })
if (!typebot) return res.send({ typebot: null }) if (!typebot || !(await canReadTypebots(typebot, user)))
const memberInWorkspace = await prisma.memberInWorkspace.findFirst({ return res.status(404).send({ typebot: null })
where: {
workspaceId: typebot.workspaceId,
userId: user.id,
},
})
if (process.env.ADMIN_EMAIL !== user.email && !memberInWorkspace)
return res.send({ typebot: null })
const { publishedTypebot, collaborators, webhooks, ...restOfTypebot } = const { publishedTypebot, collaborators, webhooks, ...restOfTypebot } =
typebot typebot
@ -50,6 +42,15 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
} }
if (req.method === 'DELETE') { if (req.method === 'DELETE') {
const typebot = await prisma.typebot.findFirst({
where: { id: typebotId },
select: {
workspaceId: true,
collaborators: { select: { userId: true, type: true } },
},
})
if (!typebot || !(await canWriteTypebots(typebot, user)))
return res.status(404).send({ typebot: null })
const { success } = await archiveResults({ const { success } = await archiveResults({
typebotId, typebotId,
user, user,
@ -57,14 +58,15 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
}) })
if (!success) return res.status(500).send({ success: false }) if (!success) return res.status(500).send({ success: false })
await prisma.publicTypebot.deleteMany({ await prisma.publicTypebot.deleteMany({
where: { typebot: canWriteTypebots(typebotId, user) }, where: { typebotId },
}) })
const typebots = await prisma.typebot.updateMany({ const typebots = await prisma.typebot.updateMany({
where: canWriteTypebots(typebotId, user), where: { id: typebotId },
data: { isArchived: true, publicId: null }, data: { isArchived: true, publicId: null },
}) })
return res.send({ typebots }) return res.send({ typebots })
} }
if (req.method === 'PUT') { if (req.method === 'PUT') {
const data = typeof req.body === 'string' ? JSON.parse(req.body) : req.body const data = typeof req.body === 'string' ? JSON.parse(req.body) : req.body
const parser = typebotSchema.safeParse({ const parser = typebotSchema.safeParse({
@ -81,17 +83,22 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
}, },
}) })
} }
const existingTypebot = await prisma.typebot.findFirst({
where: canReadTypebots(typebotId, user), const typebot = await prisma.typebot.findFirst({
select: { updatedAt: true }, where: { id: typebotId },
select: {
updatedAt: true,
workspaceId: true,
collaborators: { select: { userId: true, type: true } },
},
}) })
if ( if (!typebot || !(await canWriteTypebots(typebot, user)))
existingTypebot && return res.status(404).send({ message: 'Typebot not found' })
existingTypebot?.updatedAt > new Date(data.updatedAt)
) if (typebot.updatedAt > new Date(data.updatedAt))
return res.send({ message: 'Found newer version of typebot in database' }) return res.send({ message: 'Found newer version of typebot in database' })
const typebots = await prisma.typebot.updateMany({ const typebots = await prisma.typebot.updateMany({
where: canWriteTypebots(typebotId, user), where: { id: typebotId },
data: removeOldProperties({ data: removeOldProperties({
...data, ...data,
theme: data.theme ?? undefined, theme: data.theme ?? undefined,
@ -101,10 +108,21 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
}) })
return res.send({ typebots }) return res.send({ typebots })
} }
if (req.method === 'PATCH') { if (req.method === 'PATCH') {
const typebot = await prisma.typebot.findFirst({
where: { id: typebotId },
select: {
updatedAt: true,
workspaceId: true,
collaborators: { select: { userId: true, type: true } },
},
})
if (!typebot || !(await canWriteTypebots(typebot, user)))
return res.status(404).send({ message: 'Typebot not found' })
const data = typeof req.body === 'string' ? JSON.parse(req.body) : req.body const data = typeof req.body === 'string' ? JSON.parse(req.body) : req.body
const typebots = await prisma.typebot.updateMany({ const typebots = await prisma.typebot.updateMany({
where: canWriteTypebots(typebotId, user), where: { id: typebotId },
data, data,
}) })
return res.send({ typebots }) return res.send({ typebots })
@ -112,6 +130,50 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res) return methodNotAllowed(res)
} }
const canReadTypebots = async (
typebot: Pick<Typebot, 'workspaceId'> & {
collaborators: Pick<CollaboratorsOnTypebots, 'userId' | 'type'>[]
},
user: Pick<User, 'email' | 'id'>
) => {
if (
process.env.ADMIN_EMAIL === user.email ||
typebot.collaborators.find(
(collaborator) => collaborator.userId === user.id
)
)
return true
const memberInWorkspace = await prisma.memberInWorkspace.findFirst({
where: {
workspaceId: typebot.workspaceId,
userId: user.id,
},
})
return isDefined(memberInWorkspace)
}
const canWriteTypebots = async (
typebot: Pick<Typebot, 'workspaceId'> & {
collaborators: Pick<CollaboratorsOnTypebots, 'userId' | 'type'>[]
},
user: Pick<User, 'email' | 'id'>
) => {
if (
process.env.ADMIN_EMAIL === user.email ||
typebot.collaborators.find(
(collaborator) => collaborator.userId === user.id
)?.type === CollaborationType.WRITE
)
return true
const memberInWorkspace = await prisma.memberInWorkspace.findFirst({
where: {
workspaceId: typebot.workspaceId,
userId: user.id,
},
})
return memberInWorkspace && memberInWorkspace?.role !== 'GUEST'
}
// TODO: Remove in a month // TODO: Remove in a month
const removeOldProperties = (data: unknown) => { const removeOldProperties = (data: unknown) => {
if (data && typeof data === 'object' && 'publishedTypebotId' in data) { if (data && typeof data === 'object' && 'publishedTypebotId' in data) {