Skip to content

Commit edd4e5f

Browse files
authored
Revert "fix(realtime): re-validate socket role and evict revoked collaborator…"
This reverts commit 4ab8760.
1 parent 4ab8760 commit edd4e5f

18 files changed

Lines changed: 16 additions & 964 deletions

File tree

apps/realtime/src/handlers/eviction.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

apps/realtime/src/handlers/operations.ts

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ import { generateId } from '@sim/utils/id'
1414
import { assertWorkflowMutable, WorkflowLockedError } from '@sim/workflow-authz'
1515
import { ZodError } from 'zod'
1616
import { persistWorkflowOperation } from '@/database/operations'
17-
import { evictRevokedSocket } from '@/handlers/eviction'
1817
import type { AuthenticatedSocket } from '@/middleware/auth'
19-
import { authorizeSocketOperation } from '@/middleware/permissions'
18+
import { checkRolePermission } from '@/middleware/permissions'
2019
import type { IRoomManager, UserSession } from '@/rooms'
2120

2221
const logger = createLogger('OperationsHandlers')
@@ -126,42 +125,15 @@ export function setupOperationsHandlers(socket: AuthenticatedSocket, roomManager
126125

127126
await roomManager.updateUserActivity(workflowId, socket.id, { lastActivity: Date.now() })
128127

129-
// Re-validate the cached role against the live permissions table (bounded
130-
// by a short TTL) so a revoked or downgraded collaborator cannot keep
131-
// mutating the workflow on an already-connected socket.
132-
const authorization = await authorizeSocketOperation({
133-
roomManager,
134-
workflowId,
135-
socketId: socket.id,
136-
userId: session.userId,
137-
presence: userPresence,
138-
operation,
139-
})
140-
141-
if (authorization.accessRevoked) {
142-
logger.warn(
143-
`User ${session.userId} lost access to workflow ${workflowId}; evicting socket ${socket.id}`
144-
)
145-
emitOperationError(
146-
{
147-
type: 'ACCESS_REVOKED',
148-
message: authorization.reason || 'Access to this workflow has been revoked',
149-
operation,
150-
target,
151-
},
152-
{ error: authorization.reason || 'Access revoked', retryable: false }
153-
)
154-
await evictRevokedSocket(roomManager, socket, workflowId)
155-
return
156-
}
157-
158-
if (!authorization.allowed) {
128+
// Check permissions using cached role (no DB query)
129+
const permissionCheck = checkRolePermission(userPresence.role, operation)
130+
if (!permissionCheck.allowed) {
159131
logger.warn(
160-
`User ${session.userId} (role: ${authorization.role}) forbidden from ${operation} on ${target}`
132+
`User ${session.userId} (role: ${userPresence.role}) forbidden from ${operation} on ${target}`
161133
)
162134
emitOperationError({
163135
type: 'INSUFFICIENT_PERMISSIONS',
164-
message: `${authorization.reason} on '${target}'`,
136+
message: `${permissionCheck.reason} on '${target}'`,
165137
operation,
166138
target,
167139
})

apps/realtime/src/handlers/subblocks.ts

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import { getErrorMessage } from '@sim/utils/errors'
66
import { assertWorkflowMutable, WorkflowLockedError } from '@sim/workflow-authz'
77
import { isWorkflowBlockProtected } from '@sim/workflow-types/workflow'
88
import { and, eq } from 'drizzle-orm'
9-
import { evictRevokedSocket } from '@/handlers/eviction'
109
import type { AuthenticatedSocket } from '@/middleware/auth'
11-
import { authorizeSocketOperation } from '@/middleware/permissions'
10+
import { checkRolePermission } from '@/middleware/permissions'
1211
import type { IRoomManager } from '@/rooms'
1312

1413
const logger = createLogger('SubblocksHandlers')
@@ -137,44 +136,18 @@ export function setupSubblocksHandlers(socket: AuthenticatedSocket, roomManager:
137136
return
138137
}
139138

140-
const authorization = await authorizeSocketOperation({
141-
roomManager,
142-
workflowId,
143-
socketId: socket.id,
144-
userId: session.userId,
145-
presence: userPresence,
146-
operation: SUBBLOCK_OPERATIONS.UPDATE,
147-
})
148-
149-
if (authorization.accessRevoked) {
150-
socket.emit('operation-forbidden', {
151-
type: 'ACCESS_REVOKED',
152-
message: authorization.reason || 'Access to this workflow has been revoked',
153-
operation: SUBBLOCK_OPERATIONS.UPDATE,
154-
target: 'subblock',
155-
})
156-
if (operationId) {
157-
socket.emit('operation-failed', {
158-
operationId,
159-
error: authorization.reason || 'Access revoked',
160-
retryable: false,
161-
})
162-
}
163-
await evictRevokedSocket(roomManager, socket, workflowId)
164-
return
165-
}
166-
167-
if (!authorization.allowed) {
139+
const permissionCheck = checkRolePermission(userPresence.role, SUBBLOCK_OPERATIONS.UPDATE)
140+
if (!permissionCheck.allowed) {
168141
socket.emit('operation-forbidden', {
169142
type: 'INSUFFICIENT_PERMISSIONS',
170-
message: authorization.reason || 'Insufficient permissions',
143+
message: permissionCheck.reason || 'Insufficient permissions',
171144
operation: SUBBLOCK_OPERATIONS.UPDATE,
172145
target: 'subblock',
173146
})
174147
if (operationId) {
175148
socket.emit('operation-failed', {
176149
operationId,
177-
error: authorization.reason || 'Insufficient permissions',
150+
error: permissionCheck.reason || 'Insufficient permissions',
178151
retryable: false,
179152
})
180153
}

apps/realtime/src/handlers/variables.ts

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ import { VARIABLE_OPERATIONS } from '@sim/realtime-protocol/constants'
55
import { getErrorMessage } from '@sim/utils/errors'
66
import { assertWorkflowMutable, WorkflowLockedError } from '@sim/workflow-authz'
77
import { eq } from 'drizzle-orm'
8-
import { evictRevokedSocket } from '@/handlers/eviction'
98
import type { AuthenticatedSocket } from '@/middleware/auth'
10-
import { authorizeSocketOperation } from '@/middleware/permissions'
9+
import { checkRolePermission } from '@/middleware/permissions'
1110
import type { IRoomManager } from '@/rooms'
1211

1312
const logger = createLogger('VariablesHandlers')
@@ -125,44 +124,18 @@ export function setupVariablesHandlers(socket: AuthenticatedSocket, roomManager:
125124
return
126125
}
127126

128-
const authorization = await authorizeSocketOperation({
129-
roomManager,
130-
workflowId,
131-
socketId: socket.id,
132-
userId: session.userId,
133-
presence: userPresence,
134-
operation: VARIABLE_OPERATIONS.UPDATE,
135-
})
136-
137-
if (authorization.accessRevoked) {
138-
socket.emit('operation-forbidden', {
139-
type: 'ACCESS_REVOKED',
140-
message: authorization.reason || 'Access to this workflow has been revoked',
141-
operation: VARIABLE_OPERATIONS.UPDATE,
142-
target: 'variable',
143-
})
144-
if (operationId) {
145-
socket.emit('operation-failed', {
146-
operationId,
147-
error: authorization.reason || 'Access revoked',
148-
retryable: false,
149-
})
150-
}
151-
await evictRevokedSocket(roomManager, socket, workflowId)
152-
return
153-
}
154-
155-
if (!authorization.allowed) {
127+
const permissionCheck = checkRolePermission(userPresence.role, VARIABLE_OPERATIONS.UPDATE)
128+
if (!permissionCheck.allowed) {
156129
socket.emit('operation-forbidden', {
157130
type: 'INSUFFICIENT_PERMISSIONS',
158-
message: authorization.reason || 'Insufficient permissions',
131+
message: permissionCheck.reason || 'Insufficient permissions',
159132
operation: VARIABLE_OPERATIONS.UPDATE,
160133
target: 'variable',
161134
})
162135
if (operationId) {
163136
socket.emit('operation-failed', {
164137
operationId,
165-
error: authorization.reason || 'Insufficient permissions',
138+
error: permissionCheck.reason || 'Insufficient permissions',
166139
retryable: false,
167140
})
168141
}

apps/realtime/src/handlers/workflow.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ export function setupWorkflowHandlers(socket: AuthenticatedSocket, roomManager:
160160
joinedAt: Date.now(),
161161
lastActivity: Date.now(),
162162
role: userRole,
163-
roleCheckedAt: Date.now(),
164163
avatarUrl,
165164
}
166165

apps/realtime/src/index.test.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,6 @@ vi.mock('@/middleware/permissions', () => ({
7373
checkRolePermission: vi.fn().mockReturnValue({
7474
allowed: true,
7575
}),
76-
authorizeSocketOperation: vi.fn().mockResolvedValue({
77-
allowed: true,
78-
role: 'admin',
79-
accessRevoked: false,
80-
}),
8176
}))
8277

8378
vi.mock('@/database/operations', () => ({

0 commit comments

Comments
 (0)