1- import { and , eq } from 'drizzle-orm'
1+ import { eq } from 'drizzle-orm'
22import { type NextRequest , NextResponse } from 'next/server'
33import { getSession } from '@/lib/auth'
44import { createLogger } from '@/lib/logs/console/logger'
5+ import { getUserEntityPermissions } from '@/lib/permissions/utils'
56import { db } from '@/db'
67import { webhook , workflow } from '@/db/schema'
78
@@ -29,18 +30,47 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
2930 workflow : {
3031 id : workflow . id ,
3132 name : workflow . name ,
33+ userId : workflow . userId ,
34+ workspaceId : workflow . workspaceId ,
3235 } ,
3336 } )
3437 . from ( webhook )
3538 . innerJoin ( workflow , eq ( webhook . workflowId , workflow . id ) )
36- . where ( and ( eq ( webhook . id , id ) , eq ( workflow . userId , session . user . id ) ) )
39+ . where ( eq ( webhook . id , id ) )
3740 . limit ( 1 )
3841
3942 if ( webhooks . length === 0 ) {
4043 logger . warn ( `[${ requestId } ] Webhook not found: ${ id } ` )
4144 return NextResponse . json ( { error : 'Webhook not found' } , { status : 404 } )
4245 }
4346
47+ const webhookData = webhooks [ 0 ]
48+
49+ // Check if user has permission to access this webhook
50+ let hasAccess = false
51+
52+ // Case 1: User owns the workflow
53+ if ( webhookData . workflow . userId === session . user . id ) {
54+ hasAccess = true
55+ }
56+
57+ // Case 2: Workflow belongs to a workspace and user has any permission
58+ if ( ! hasAccess && webhookData . workflow . workspaceId ) {
59+ const userPermission = await getUserEntityPermissions (
60+ session . user . id ,
61+ 'workspace' ,
62+ webhookData . workflow . workspaceId
63+ )
64+ if ( userPermission !== null ) {
65+ hasAccess = true
66+ }
67+ }
68+
69+ if ( ! hasAccess ) {
70+ logger . warn ( `[${ requestId } ] User ${ session . user . id } denied access to webhook: ${ id } ` )
71+ return NextResponse . json ( { error : 'Access denied' } , { status : 403 } )
72+ }
73+
4474 logger . info ( `[${ requestId } ] Successfully retrieved webhook: ${ id } ` )
4575 return NextResponse . json ( { webhook : webhooks [ 0 ] } , { status : 200 } )
4676 } catch ( error ) {
@@ -66,13 +96,14 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
6696 const body = await request . json ( )
6797 const { path, provider, providerConfig, isActive } = body
6898
69- // Find the webhook and check ownership
99+ // Find the webhook and check permissions
70100 const webhooks = await db
71101 . select ( {
72102 webhook : webhook ,
73103 workflow : {
74104 id : workflow . id ,
75105 userId : workflow . userId ,
106+ workspaceId : workflow . workspaceId ,
76107 } ,
77108 } )
78109 . from ( webhook )
@@ -85,9 +116,33 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
85116 return NextResponse . json ( { error : 'Webhook not found' } , { status : 404 } )
86117 }
87118
88- if ( webhooks [ 0 ] . workflow . userId !== session . user . id ) {
89- logger . warn ( `[${ requestId } ] Unauthorized webhook update attempt for webhook: ${ id } ` )
90- return NextResponse . json ( { error : 'Unauthorized' } , { status : 403 } )
119+ const webhookData = webhooks [ 0 ]
120+
121+ // Check if user has permission to modify this webhook
122+ let canModify = false
123+
124+ // Case 1: User owns the workflow
125+ if ( webhookData . workflow . userId === session . user . id ) {
126+ canModify = true
127+ }
128+
129+ // Case 2: Workflow belongs to a workspace and user has write or admin permission
130+ if ( ! canModify && webhookData . workflow . workspaceId ) {
131+ const userPermission = await getUserEntityPermissions (
132+ session . user . id ,
133+ 'workspace' ,
134+ webhookData . workflow . workspaceId
135+ )
136+ if ( userPermission === 'write' || userPermission === 'admin' ) {
137+ canModify = true
138+ }
139+ }
140+
141+ if ( ! canModify ) {
142+ logger . warn (
143+ `[${ requestId } ] User ${ session . user . id } denied permission to modify webhook: ${ id } `
144+ )
145+ return NextResponse . json ( { error : 'Access denied' } , { status : 403 } )
91146 }
92147
93148 logger . debug ( `[${ requestId } ] Updating webhook properties` , {
@@ -136,13 +191,14 @@ export async function DELETE(
136191 return NextResponse . json ( { error : 'Unauthorized' } , { status : 401 } )
137192 }
138193
139- // Find the webhook and check ownership
194+ // Find the webhook and check permissions
140195 const webhooks = await db
141196 . select ( {
142197 webhook : webhook ,
143198 workflow : {
144199 id : workflow . id ,
145200 userId : workflow . userId ,
201+ workspaceId : workflow . workspaceId ,
146202 } ,
147203 } )
148204 . from ( webhook )
@@ -155,12 +211,36 @@ export async function DELETE(
155211 return NextResponse . json ( { error : 'Webhook not found' } , { status : 404 } )
156212 }
157213
158- if ( webhooks [ 0 ] . workflow . userId !== session . user . id ) {
159- logger . warn ( `[${ requestId } ] Unauthorized webhook deletion attempt for webhook: ${ id } ` )
160- return NextResponse . json ( { error : 'Unauthorized' } , { status : 403 } )
214+ const webhookData = webhooks [ 0 ]
215+
216+ // Check if user has permission to delete this webhook
217+ let canDelete = false
218+
219+ // Case 1: User owns the workflow
220+ if ( webhookData . workflow . userId === session . user . id ) {
221+ canDelete = true
222+ }
223+
224+ // Case 2: Workflow belongs to a workspace and user has write or admin permission
225+ if ( ! canDelete && webhookData . workflow . workspaceId ) {
226+ const userPermission = await getUserEntityPermissions (
227+ session . user . id ,
228+ 'workspace' ,
229+ webhookData . workflow . workspaceId
230+ )
231+ if ( userPermission === 'write' || userPermission === 'admin' ) {
232+ canDelete = true
233+ }
234+ }
235+
236+ if ( ! canDelete ) {
237+ logger . warn (
238+ `[${ requestId } ] User ${ session . user . id } denied permission to delete webhook: ${ id } `
239+ )
240+ return NextResponse . json ( { error : 'Access denied' } , { status : 403 } )
161241 }
162242
163- const foundWebhook = webhooks [ 0 ] . webhook
243+ const foundWebhook = webhookData . webhook
164244
165245 // If it's a Telegram webhook, delete it from Telegram first
166246 if ( foundWebhook . provider === 'telegram' ) {
0 commit comments