Skip to content

Commit 4c4083b

Browse files
fix: Validate queue names (supabase#40290)
* fix: input validation for queue name * grammar * fix: whitespacing issue * Reuse the validation logic for queue name. * Reuse the query name schema in the create queue sheet. --------- Co-authored-by: Ivan Vasilov <[email protected]>
1 parent 776e44f commit 4c4083b

11 files changed

+92
-20
lines changed

apps/studio/components/interfaces/Integrations/Queues/CreateQueueSheet.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { Admonition } from 'ui-patterns'
3030
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
3131
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
3232
import { QUEUE_TYPES } from './Queues.constants'
33+
import { QueryNameSchema } from './Queues.utils'
3334

3435
export interface CreateQueueSheetProps {
3536
isClosing: boolean
@@ -52,12 +53,7 @@ const unloggedQueueSchema = z.object({
5253
})
5354

5455
const FormSchema = z.object({
55-
name: z
56-
.string()
57-
.trim()
58-
.min(1, 'Please provide a name for your queue')
59-
.max(47, "The name can't be longer than 47 characters")
60-
.regex(/^[a-z_-]+$/, 'Name must contain only lowercase letters, hyphens, and underscores'),
56+
name: QueryNameSchema,
6157
enableRls: z.boolean(),
6258
values: z.discriminatedUnion('type', [
6359
normalQueueSchema,

apps/studio/components/interfaces/Integrations/Queues/Queues.utils.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Column } from 'react-data-grid'
2+
import z from 'zod'
23

34
import { PostgresQueue } from 'data/database-queues/database-queues-query'
45
import { cn } from 'ui'
@@ -107,3 +108,20 @@ export const prepareQueuesForDataGrid = (queues: PostgresQueue[]): QueueWithMetr
107108
id: queue.queue_name, // Use queue_name as unique id
108109
}))
109110
}
111+
112+
export const QueryNameSchema = z
113+
.string()
114+
.trim()
115+
.min(1, 'Please provide a name for your queue')
116+
.max(47, "The name can't be longer than 47 characters")
117+
.regex(
118+
/^[a-zA-Z0-9_-]+$/,
119+
'Name must contain only alphanumeric characters, underscores, and hyphens'
120+
)
121+
122+
/**
123+
* Checks if the queue name is valid. Returns a boolean.
124+
*/
125+
export const isQueueNameValid = (queueName: string) => {
126+
return QueryNameSchema.safeParse(queueName).success
127+
}

apps/studio/components/interfaces/Integrations/Queues/SingleQueue/MessageDetailsPanel.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ export const MessageDetailsPanel = ({
146146
readMessage({
147147
projectRef: project!.ref,
148148
connectionString: project?.connectionString,
149-
queryName: queueName!,
149+
queueName: queueName!,
150150
messageId: selectedMessage.msg_id,
151151
duration: 60,
152152
})
@@ -173,7 +173,7 @@ export const MessageDetailsPanel = ({
173173
archiveMessage({
174174
projectRef: project!.ref,
175175
connectionString: project?.connectionString,
176-
queryName: queueName!,
176+
queueName: queueName!,
177177
messageId: selectedMessage.msg_id,
178178
})
179179
},

apps/studio/data/database-queues/database-queue-messages-archive-mutation.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,33 @@
11
import { useMutation, useQueryClient } from '@tanstack/react-query'
22
import { toast } from 'sonner'
33

4+
import { isQueueNameValid } from 'components/interfaces/Integrations/Queues/Queues.utils'
45
import { executeSql } from 'data/sql/execute-sql-query'
56
import type { ResponseError, UseCustomMutationOptions } from 'types'
67
import { databaseQueuesKeys } from './keys'
78

89
export type DatabaseQueueMessageArchiveVariables = {
910
projectRef: string
1011
connectionString?: string | null
11-
queryName: string
12+
queueName: string
1213
messageId: number
1314
}
1415

1516
export async function archiveDatabaseQueueMessage({
1617
projectRef,
1718
connectionString,
18-
queryName,
19+
queueName,
1920
messageId,
2021
}: DatabaseQueueMessageArchiveVariables) {
22+
if (!isQueueNameValid(queueName)) {
23+
throw new Error(
24+
'Invalid queue name: must contain only alphanumeric characters, underscores, and hyphens'
25+
)
26+
}
2127
const { result } = await executeSql({
2228
projectRef,
2329
connectionString,
24-
sql: `SELECT * FROM pgmq.archive('${queryName}', ${messageId})`,
30+
sql: `SELECT * FROM pgmq.archive('${queueName}', ${messageId})`,
2531
queryKey: databaseQueuesKeys.create(),
2632
})
2733

@@ -51,9 +57,9 @@ export const useDatabaseQueueMessageArchiveMutation = ({
5157
>({
5258
mutationFn: (vars) => archiveDatabaseQueueMessage(vars),
5359
async onSuccess(data, variables, context) {
54-
const { projectRef, queryName } = variables
60+
const { projectRef, queueName } = variables
5561
await queryClient.invalidateQueries({
56-
queryKey: databaseQueuesKeys.getMessagesInfinite(projectRef, queryName),
62+
queryKey: databaseQueuesKeys.getMessagesInfinite(projectRef, queueName),
5763
})
5864
await onSuccess?.(data, variables, context)
5965
},

apps/studio/data/database-queues/database-queue-messages-delete-mutation.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useMutation, useQueryClient } from '@tanstack/react-query'
22
import { toast } from 'sonner'
33

4+
import { isQueueNameValid } from 'components/interfaces/Integrations/Queues/Queues.utils'
45
import { executeSql } from 'data/sql/execute-sql-query'
56
import type { ResponseError, UseCustomMutationOptions } from 'types'
67
import { databaseQueuesKeys } from './keys'
@@ -18,6 +19,12 @@ export async function deleteDatabaseQueueMessage({
1819
queueName,
1920
messageId,
2021
}: DatabaseQueueMessageDeleteVariables) {
22+
if (!isQueueNameValid(queueName)) {
23+
throw new Error(
24+
'Invalid queue name: must contain only alphanumeric characters, underscores, and hyphens'
25+
)
26+
}
27+
2128
const { result } = await executeSql({
2229
projectRef,
2330
connectionString,

apps/studio/data/database-queues/database-queue-messages-infinite-query.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useInfiniteQuery } from '@tanstack/react-query'
22
import dayjs from 'dayjs'
33
import { last } from 'lodash'
44

5+
import { isQueueNameValid } from 'components/interfaces/Integrations/Queues/Queues.utils'
56
import { QUEUE_MESSAGE_TYPE } from 'components/interfaces/Integrations/Queues/SingleQueue/Queue.utils'
67
import { executeSql } from 'data/sql/execute-sql-query'
78
import { DATE_FORMAT } from 'lib/constants'
@@ -34,6 +35,11 @@ export async function getDatabaseQueue({
3435
status,
3536
}: DatabaseQueueVariables & { afterTimestamp: string }) {
3637
if (!projectRef) throw new Error('Project ref is required')
38+
if (!isQueueNameValid(queueName)) {
39+
throw new Error(
40+
'Invalid queue name: must contain only alphanumeric characters, underscores, and hyphens'
41+
)
42+
}
3743

3844
if (status.length === 0) {
3945
return []

apps/studio/data/database-queues/database-queue-messages-read-mutation.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,36 @@
11
import { useMutation, useQueryClient } from '@tanstack/react-query'
22
import { toast } from 'sonner'
33

4+
import { isQueueNameValid } from 'components/interfaces/Integrations/Queues/Queues.utils'
45
import { executeSql } from 'data/sql/execute-sql-query'
56
import type { ResponseError, UseCustomMutationOptions } from 'types'
67
import { databaseQueuesKeys } from './keys'
78

89
export type DatabaseQueueMessageReadVariables = {
910
projectRef: string
1011
connectionString?: string | null
11-
queryName: string
12+
queueName: string
1213
duration: number
1314
messageId: number
1415
}
1516

1617
export async function readDatabaseQueueMessage({
1718
projectRef,
1819
connectionString,
19-
queryName,
20+
queueName,
2021
messageId,
2122
duration,
2223
}: DatabaseQueueMessageReadVariables) {
24+
if (!isQueueNameValid(queueName)) {
25+
throw new Error(
26+
'Invalid queue name: must contain only alphanumeric characters, underscores, and hyphens'
27+
)
28+
}
29+
2330
const { result } = await executeSql({
2431
projectRef,
2532
connectionString,
26-
sql: `select * from pgmq.set_vt('${queryName}', ${messageId}, ${duration})`,
33+
sql: `select * from pgmq.set_vt('${queueName}', ${messageId}, ${duration})`,
2734
queryKey: databaseQueuesKeys.create(),
2835
})
2936

@@ -53,9 +60,9 @@ export const useDatabaseQueueMessageReadMutation = ({
5360
>({
5461
mutationFn: (vars) => readDatabaseQueueMessage(vars),
5562
async onSuccess(data, variables, context) {
56-
const { projectRef, queryName } = variables
63+
const { projectRef, queueName } = variables
5764
await queryClient.invalidateQueries({
58-
queryKey: databaseQueuesKeys.getMessagesInfinite(projectRef, queryName),
65+
queryKey: databaseQueuesKeys.getMessagesInfinite(projectRef, queueName),
5966
})
6067
await onSuccess?.(data, variables, context)
6168
},

apps/studio/data/database-queues/database-queue-messages-send-mutation.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useMutation, useQueryClient } from '@tanstack/react-query'
22
import { toast } from 'sonner'
33

4+
import { isQueueNameValid } from 'components/interfaces/Integrations/Queues/Queues.utils'
45
import { executeSql } from 'data/sql/execute-sql-query'
56
import type { ResponseError, UseCustomMutationOptions } from 'types'
67
import { databaseQueuesKeys } from './keys'
@@ -20,6 +21,12 @@ export async function sendDatabaseQueueMessage({
2021
payload,
2122
delay,
2223
}: DatabaseQueueMessageSendVariables) {
24+
if (!isQueueNameValid(queueName)) {
25+
throw new Error(
26+
'Invalid queue name: must contain only alphanumeric characters, underscores, and hyphens'
27+
)
28+
}
29+
2330
const { result } = await executeSql({
2431
projectRef,
2532
connectionString,

apps/studio/data/database-queues/database-queues-delete-mutation.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { toast } from 'sonner'
44
import { executeSql } from 'data/sql/execute-sql-query'
55
import type { ResponseError, UseCustomMutationOptions } from 'types'
66
import { databaseQueuesKeys } from './keys'
7+
import { isQueueNameValid } from 'components/interfaces/Integrations/Queues/Queues.utils'
78

89
export type DatabaseQueueDeleteVariables = {
910
projectRef: string
@@ -16,6 +17,12 @@ export async function deleteDatabaseQueue({
1617
connectionString,
1718
queueName,
1819
}: DatabaseQueueDeleteVariables) {
20+
if (!isQueueNameValid(queueName)) {
21+
throw new Error(
22+
'Invalid queue name: must contain only alphanumeric characters, underscores, and hyphens'
23+
)
24+
}
25+
1926
const { result } = await executeSql({
2027
projectRef,
2128
connectionString,

apps/studio/data/database-queues/database-queues-metrics-query.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { useQuery } from '@tanstack/react-query'
2+
3+
import { isQueueNameValid } from 'components/interfaces/Integrations/Queues/Queues.utils'
24
import { executeSql } from 'data/sql/execute-sql-query'
35
import type { ResponseError, UseCustomQueryOptions } from 'types'
46
import { databaseQueuesKeys } from './keys'
@@ -15,15 +17,18 @@ export type PostgresQueueMetric = {
1517
method: 'estimated' | 'precise'
1618
}
1719

18-
const preciseMetricsSqlQuery = (queueName: string) => `
20+
const preciseMetricsSqlQuery = (queueName: string) => {
21+
return `
1922
set local statement_timeout = '1s';
2023
SELECT
2124
COUNT(*) AS row_count
2225
FROM
2326
"pgmq"."q_${queueName}";
2427
`
28+
}
2529

26-
const estimateMetricsSqlQuery = (queueName: string) => `
30+
const estimateMetricsSqlQuery = (queueName: string) => {
31+
return `
2732
select
2833
reltuples::bigint as estimated_rows
2934
from
@@ -32,13 +37,19 @@ const estimateMetricsSqlQuery = (queueName: string) => `
3237
relname = 'q_${queueName}'
3338
and relnamespace = 'pgmq'::regnamespace;
3439
`
40+
}
3541

3642
export async function getDatabaseQueuesMetrics({
3743
projectRef,
3844
connectionString,
3945
queueName,
4046
}: DatabaseQueuesMetricsVariables) {
4147
if (!projectRef) throw new Error('Project ref is required')
48+
if (!isQueueNameValid(queueName)) {
49+
throw new Error(
50+
'Invalid queue name: must contain only alphanumeric characters, underscores, and hyphens'
51+
)
52+
}
4253

4354
try {
4455
const { result } = await executeSql({

0 commit comments

Comments
 (0)