mirror of
https://github.com/supabase/supabase.git
synced 2026-10-16 14:49:10 +03:00
## What Escapes user-controlled string values before interpolating them into SQL in `apps/studio/data/database-queues/`. ## Why Several queue message queries were constructing SQL via direct string interpolation without sanitization: | File | Value | Risk | |------|-------|------| | `database-queue-messages-send-mutation.ts` | `payload` | **High** — arbitrary user-provided JSON; a single quote breaks the query and a crafted payload could execute arbitrary SQL | | `database-queue-messages-infinite-query.ts` | `afterTimestamp` | Medium — sourced from a previous DB result, but still unsafe to interpolate | | `database-queue-messages-delete-mutation.ts` | `messageId` | Low — typed `number`, but truncated for safety | | `database-queue-messages-archive-mutation.ts` | `messageId` | Low — same as above | ## Fix - Escape string literals with the standard PostgreSQL approach (doubling single quotes `'` → `''`) before interpolation - Wrap numeric `messageId` values with `Math.trunc()` to prevent floating-point edge cases - `queueName` was already validated via `isQueueNameValid` regex (alphanumeric/underscore/hyphen only) — no change needed Fixes #44375 ## Test plan - [x] Open Queue Messages panel in Studio - [x] Send a message with a payload containing single quotes (e.g. `{"key": "it's a value"}`) — verify it sends without error - [x] Verify pagination still works correctly after fix <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved safety of queue operations by ensuring message IDs, payloads, timestamps, and queue names are handled securely to prevent injection and formatting issues. * Normalized numeric message fields (IDs/delays) for consistent processing. * Increased stability and correctness of archive, delete, query, and send operations; no public APIs were changed. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
78 lines
2.2 KiB
TypeScript
78 lines
2.2 KiB
TypeScript
import { literal } from '@supabase/pg-meta/src/pg-format'
|
|
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
import { isQueueNameValid } from 'components/interfaces/Integrations/Queues/Queues.utils'
|
|
import { executeSql } from 'data/sql/execute-sql-query'
|
|
import { toast } from 'sonner'
|
|
import type { ResponseError, UseCustomMutationOptions } from 'types'
|
|
|
|
import { databaseQueuesKeys } from './keys'
|
|
|
|
export type DatabaseQueueMessageDeleteVariables = {
|
|
projectRef: string
|
|
connectionString?: string | null
|
|
queueName: string
|
|
messageId: number
|
|
}
|
|
|
|
export async function deleteDatabaseQueueMessage({
|
|
projectRef,
|
|
connectionString,
|
|
queueName,
|
|
messageId,
|
|
}: DatabaseQueueMessageDeleteVariables) {
|
|
if (!isQueueNameValid(queueName)) {
|
|
throw new Error(
|
|
'Invalid queue name: must contain only alphanumeric characters, underscores, and hyphens'
|
|
)
|
|
}
|
|
|
|
const { result } = await executeSql({
|
|
projectRef,
|
|
connectionString,
|
|
sql: `SELECT * FROM pgmq.delete(${literal(queueName)}, ${literal(messageId)})`,
|
|
queryKey: databaseQueuesKeys.create(),
|
|
})
|
|
|
|
return result
|
|
}
|
|
|
|
type DatabaseQueueMessageDeleteData = Awaited<ReturnType<typeof deleteDatabaseQueueMessage>>
|
|
|
|
export const useDatabaseQueueMessageDeleteMutation = ({
|
|
onSuccess,
|
|
onError,
|
|
...options
|
|
}: Omit<
|
|
UseCustomMutationOptions<
|
|
DatabaseQueueMessageDeleteData,
|
|
ResponseError,
|
|
DatabaseQueueMessageDeleteVariables
|
|
>,
|
|
'mutationFn'
|
|
> = {}) => {
|
|
const queryClient = useQueryClient()
|
|
|
|
return useMutation<
|
|
DatabaseQueueMessageDeleteData,
|
|
ResponseError,
|
|
DatabaseQueueMessageDeleteVariables
|
|
>({
|
|
mutationFn: (vars) => deleteDatabaseQueueMessage(vars),
|
|
async onSuccess(data, variables, context) {
|
|
const { projectRef, queueName } = variables
|
|
await queryClient.invalidateQueries({
|
|
queryKey: databaseQueuesKeys.getMessagesInfinite(projectRef, queueName),
|
|
})
|
|
await onSuccess?.(data, variables, context)
|
|
},
|
|
async onError(data, variables, context) {
|
|
if (onError === undefined) {
|
|
toast.error(`Failed to delete database queue message: ${data.message}`)
|
|
} else {
|
|
onError(data, variables, context)
|
|
}
|
|
},
|
|
...options,
|
|
})
|
|
}
|