DataApiEnableSwitch.utils.ts68 lines · main
1import { getUnsafeEntitiesInApiSql } from '@supabase/pg-meta'
2
3import type { EnableCheckAction, EnableCheckState } from './DataApiEnableSwitch.types'
4import { executeSql } from '@/data/sql/execute-sql-query'
5
6export type ExposedEntity = {
7 schema: string
8 name: string
9 type: 'table' | 'foreign table' | 'materialized view' | 'view'
10}
11
12/**
13 * Queries for entities that would be exposed through the Data API with
14 * potential security issues: tables without RLS, foreign tables, materialized
15 * views, and views without SECURITY INVOKER.
16 *
17 * This checks against the _target_ schemas rather than the currently active
18 * PostgREST config, so it works correctly when enabling the Data API.
19 */
20export async function queryUnsafeEntitiesInApi({
21 projectRef,
22 connectionString,
23 schemas,
24}: {
25 projectRef: string
26 connectionString?: string | null
27 schemas: Array<string>
28}): Promise<Array<ExposedEntity>> {
29 if (schemas.length === 0) return []
30
31 const { result } = await executeSql<Array<ExposedEntity>>({
32 projectRef,
33 connectionString,
34 sql: getUnsafeEntitiesInApiSql({ schemas }),
35 queryKey: ['unsafe-entities-in-api'],
36 })
37
38 return result ?? []
39}
40
41export const getDefaultSchemas = (dbSchema: string | null | undefined) => {
42 const schemas =
43 dbSchema
44 ?.split(',')
45 .map((schema) => schema.trim())
46 .filter((schema) => schema.length > 0) ?? []
47
48 return schemas.length > 0 ? schemas : ['public']
49}
50
51export function enableCheckReducer(
52 state: EnableCheckState,
53 action: EnableCheckAction
54): EnableCheckState {
55 switch (state.status) {
56 case 'idle':
57 if (action.type === 'START_CHECK') return { status: 'checking' }
58 return state
59 case 'checking':
60 if (action.type === 'ENTITIES_FOUND')
61 return { status: 'confirming', unsafeEntities: action.unsafeEntities }
62 if (action.type === 'DISMISS') return { status: 'idle' }
63 return state
64 case 'confirming':
65 if (action.type === 'DISMISS') return { status: 'idle' }
66 return state
67 }
68}