From 9e72050658a4330879b680da88e7257ab2575bda Mon Sep 17 00:00:00 2001 From: Jordi Enric <37541088+jordienr@users.noreply.github.com> Date: Thu, 15 May 2025 10:57:06 +0200 Subject: [PATCH] Add regex guard for edge functions test endpoint (#35688) * Add regex guard for edge functions test endpoint * Remove conosle log * add tests * empty --------- Co-authored-by: Joshen Lim --- apps/studio/lib/api/edgeFunctions.test.ts | 31 ++++++++++++++++++++ apps/studio/lib/api/edgeFunctions.ts | 7 +++++ apps/studio/pages/api/edge-functions/test.ts | 10 +++++++ 3 files changed, 48 insertions(+) create mode 100644 apps/studio/lib/api/edgeFunctions.test.ts create mode 100644 apps/studio/lib/api/edgeFunctions.ts diff --git a/apps/studio/lib/api/edgeFunctions.test.ts b/apps/studio/lib/api/edgeFunctions.test.ts new file mode 100644 index 00000000000..06887983411 --- /dev/null +++ b/apps/studio/lib/api/edgeFunctions.test.ts @@ -0,0 +1,31 @@ +import { expect, describe, it } from 'vitest' +import { isValidEdgeFunctionURL } from './edgeFunctions' + +describe('isValidEdgeFunctionURL', () => { + const validEdgeFunctionUrls = [ + 'https://projectref.supabase.co/functions/v1/hello-world', + 'https://projectref.supabase.red/functions/v1/hello-world', + 'https://projectref.supabase.red/functions/v3/hello-world', + 'https://projectref.supabase.red/functions/v3/hello-world', + ] + + const invalidEdgeFunctionUrls = [ + 'https://notsupabase.com/functions/v1/test', + 'https://projectref.notsupabase.com/functions/v1/test', + 'https://localhost?https://aaaa.supabase.co/functions/v1/xxx', + 'https://localhost:3000/?https://aaaa.supabase.co/functions/v1/xxx', + 'http://localhost:3000/?https://aaaa.supabase.co/functions/v1/xxx', + ] + + it('should match valid edge function URLs', () => { + for (const url of validEdgeFunctionUrls) { + expect(isValidEdgeFunctionURL(url), `Expected ${url} to be valid`).toBe(true) + } + }) + + it('should not match invalid edge function URLs', () => { + for (const url of invalidEdgeFunctionUrls) { + expect(isValidEdgeFunctionURL(url), `Expected ${url} to be invalid`).toBe(false) + } + }) +}) diff --git a/apps/studio/lib/api/edgeFunctions.ts b/apps/studio/lib/api/edgeFunctions.ts new file mode 100644 index 00000000000..47fc1175054 --- /dev/null +++ b/apps/studio/lib/api/edgeFunctions.ts @@ -0,0 +1,7 @@ +export const isValidEdgeFunctionURL = (url: string) => { + const regexValidEdgeFunctionURL = new RegExp( + '^https://[a-z]*.supabase.(red|co)/functions/v[0-9]{1}/.*$' + ) + + return regexValidEdgeFunctionURL.test(url) +} diff --git a/apps/studio/pages/api/edge-functions/test.ts b/apps/studio/pages/api/edge-functions/test.ts index 2d194366de4..cd53337cbc5 100644 --- a/apps/studio/pages/api/edge-functions/test.ts +++ b/apps/studio/pages/api/edge-functions/test.ts @@ -1,3 +1,4 @@ +import { isValidEdgeFunctionURL } from 'lib/api/edgeFunctions' import { NextApiRequest, NextApiResponse } from 'next' export default async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -21,6 +22,15 @@ async function handlePost(req: NextApiRequest, res: NextApiResponse) { try { const { url, method, body: requestBody, headers: customHeaders } = req.body + const validEdgeFnUrl = isValidEdgeFunctionURL(url) + + if (!validEdgeFnUrl) { + return res.status(400).json({ + status: 400, + error: { message: 'Provided URL is not a valid Supabase edge function URL' }, + }) + } + // Remove any undefined or null values from custom headers const sanitizedCustomHeaders = Object.entries(customHeaders || {}).reduce( (acc, [key, value]) => {