-
Notifications
You must be signed in to change notification settings - Fork 2.5k
fix: add client-side user ID validation for task data isolation (partial fix for #7932) #7933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,8 +26,9 @@ type TaskEventMapping = { | |
| createPayload: (task: TaskLike, ...args: any[]) => any // eslint-disable-line @typescript-eslint/no-explicit-any | ||
| } | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/no-empty-object-type | ||
| interface TaskChannelOptions extends BaseChannelOptions {} | ||
| interface TaskChannelOptions extends BaseChannelOptions { | ||
| userId?: string | ||
| } | ||
|
|
||
| /** | ||
| * Manages task-level communication channels. | ||
|
|
@@ -41,6 +42,7 @@ export class TaskChannel extends BaseChannel< | |
| private subscribedTasks: Map<string, TaskLike> = new Map() | ||
| private pendingTasks: Map<string, TaskLike> = new Map() | ||
| private taskListeners: Map<string, Map<TaskBridgeEventName, TaskEventListener>> = new Map() | ||
| private readonly userId?: string | ||
|
|
||
| private readonly eventMapping: readonly TaskEventMapping[] = [ | ||
| { | ||
|
|
@@ -74,6 +76,7 @@ export class TaskChannel extends BaseChannel< | |
|
|
||
| constructor(options: TaskChannelOptions) { | ||
| super(options) | ||
| this.userId = options.userId | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we validate that userId is a non-empty string when provided? An empty string could cause issues downstream. |
||
| } | ||
|
|
||
| protected async handleCommandImplementation(command: TaskBridgeCommand): Promise<void> { | ||
|
|
@@ -160,7 +163,10 @@ export class TaskChannel extends BaseChannel< | |
| public async subscribeToTask(task: TaskLike, _socket: Socket): Promise<void> { | ||
| const taskId = task.taskId | ||
|
|
||
| await this.publish(TaskSocketEvents.JOIN, { taskId }, (response: JoinResponse) => { | ||
| // Include userId in the join request for server-side validation | ||
| const joinPayload = this.userId ? { taskId, userId: this.userId } : { taskId } | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: This client-side validation is like putting a 'Please Don't Enter' sign on an unlocked door. Without server-side validation, this provides only a false sense of security. The PR description correctly notes this limitation. |
||
|
|
||
| await this.publish(TaskSocketEvents.JOIN, joinPayload, (response: JoinResponse) => { | ||
| if (response.success) { | ||
| console.log(`[TaskChannel#subscribeToTask] subscribed to ${taskId}`) | ||
| this.subscribedTasks.set(taskId, task) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this comment be more specific? For example: 'The server MUST validate that the authenticated user (from session token) matches the task's owner_id field'