Skip to content

Commit 1fd3dc3

Browse files
committed
feat: enable webhooks by default
1 parent 3c208ac commit 1fd3dc3

File tree

2 files changed

+430
-0
lines changed

2 files changed

+430
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
-- migrate:up
2+
3+
-- Create pg_net extension
4+
CREATE EXTENSION IF NOT EXISTS pg_net SCHEMA extensions;
5+
6+
-- Create supabase_functions schema
7+
CREATE SCHEMA supabase_functions AUTHORIZATION supabase_admin;
8+
9+
GRANT USAGE ON SCHEMA supabase_functions TO postgres, anon, authenticated, service_role;
10+
ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON TABLES TO postgres, anon, authenticated, service_role;
11+
ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON FUNCTIONS TO postgres, anon, authenticated, service_role;
12+
ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON SEQUENCES TO postgres, anon, authenticated, service_role;
13+
14+
-- supabase_functions.migrations definition
15+
CREATE TABLE supabase_functions.migrations (
16+
version text PRIMARY KEY,
17+
inserted_at timestamptz NOT NULL DEFAULT NOW()
18+
);
19+
20+
-- Initial supabase_functions migration
21+
INSERT INTO supabase_functions.migrations (version) VALUES ('initial');
22+
23+
-- supabase_functions.hooks definition
24+
CREATE TABLE supabase_functions.hooks (
25+
id bigserial PRIMARY KEY,
26+
hook_table_id integer NOT NULL,
27+
hook_name text NOT NULL,
28+
created_at timestamptz NOT NULL DEFAULT NOW(),
29+
request_id bigint
30+
);
31+
CREATE INDEX supabase_functions_hooks_request_id_idx ON supabase_functions.hooks USING btree (request_id);
32+
CREATE INDEX supabase_functions_hooks_h_table_id_h_name_idx ON supabase_functions.hooks USING btree (hook_table_id, hook_name);
33+
COMMENT ON TABLE supabase_functions.hooks IS 'Supabase Functions Hooks: Audit trail for triggered hooks.';
34+
35+
CREATE FUNCTION supabase_functions.http_request()
36+
RETURNS trigger
37+
LANGUAGE plpgsql
38+
AS $function$
39+
DECLARE
40+
request_id bigint;
41+
payload jsonb;
42+
url text := TG_ARGV[0]::text;
43+
method text := TG_ARGV[1]::text;
44+
headers jsonb DEFAULT '{}'::jsonb;
45+
params jsonb DEFAULT '{}'::jsonb;
46+
timeout_ms integer DEFAULT 1000;
47+
BEGIN
48+
IF url IS NULL OR url = 'null' THEN
49+
RAISE EXCEPTION 'url argument is missing';
50+
END IF;
51+
52+
IF method IS NULL OR method = 'null' THEN
53+
RAISE EXCEPTION 'method argument is missing';
54+
END IF;
55+
56+
IF TG_ARGV[2] IS NULL OR TG_ARGV[2] = 'null' THEN
57+
headers = '{"Content-Type": "application/json"}'::jsonb;
58+
ELSE
59+
headers = TG_ARGV[2]::jsonb;
60+
END IF;
61+
62+
IF TG_ARGV[3] IS NULL OR TG_ARGV[3] = 'null' THEN
63+
params = '{}'::jsonb;
64+
ELSE
65+
params = TG_ARGV[3]::jsonb;
66+
END IF;
67+
68+
IF TG_ARGV[4] IS NULL OR TG_ARGV[4] = 'null' THEN
69+
timeout_ms = 1000;
70+
ELSE
71+
timeout_ms = TG_ARGV[4]::integer;
72+
END IF;
73+
74+
CASE
75+
WHEN method = 'GET' THEN
76+
SELECT http_get INTO request_id FROM net.http_get(
77+
url,
78+
params,
79+
headers,
80+
timeout_ms
81+
);
82+
WHEN method = 'POST' THEN
83+
payload = jsonb_build_object(
84+
'old_record', OLD,
85+
'record', NEW,
86+
'type', TG_OP,
87+
'table', TG_TABLE_NAME,
88+
'schema', TG_TABLE_SCHEMA
89+
);
90+
91+
SELECT http_post INTO request_id FROM net.http_post(
92+
url,
93+
payload,
94+
params,
95+
headers,
96+
timeout_ms
97+
);
98+
ELSE
99+
RAISE EXCEPTION 'method argument % is invalid', method;
100+
END CASE;
101+
102+
INSERT INTO supabase_functions.hooks
103+
(hook_table_id, hook_name, request_id)
104+
VALUES
105+
(TG_RELID, TG_NAME, request_id);
106+
107+
RETURN NEW;
108+
END
109+
$function$;
110+
111+
-- Supabase super admin
112+
DO
113+
$$
114+
BEGIN
115+
IF NOT EXISTS (
116+
SELECT 1
117+
FROM pg_roles
118+
WHERE rolname = 'supabase_functions_admin'
119+
)
120+
THEN
121+
CREATE USER supabase_functions_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION;
122+
END IF;
123+
END
124+
$$;
125+
126+
GRANT ALL PRIVILEGES ON SCHEMA supabase_functions TO supabase_functions_admin;
127+
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA supabase_functions TO supabase_functions_admin;
128+
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA supabase_functions TO supabase_functions_admin;
129+
ALTER USER supabase_functions_admin SET search_path = "supabase_functions";
130+
ALTER table "supabase_functions".migrations OWNER TO supabase_functions_admin;
131+
ALTER table "supabase_functions".hooks OWNER TO supabase_functions_admin;
132+
ALTER function "supabase_functions".http_request() OWNER TO supabase_functions_admin;
133+
GRANT supabase_functions_admin TO postgres;
134+
135+
-- Remove unused supabase_pg_net_admin role
136+
DO
137+
$$
138+
BEGIN
139+
IF EXISTS (
140+
SELECT 1
141+
FROM pg_roles
142+
WHERE rolname = 'supabase_pg_net_admin'
143+
)
144+
THEN
145+
REASSIGN OWNED BY supabase_pg_net_admin TO supabase_admin;
146+
DROP OWNED BY supabase_pg_net_admin;
147+
DROP ROLE supabase_pg_net_admin;
148+
END IF;
149+
END
150+
$$;
151+
152+
-- pg_net grants when extension is already enabled
153+
DO
154+
$$
155+
BEGIN
156+
IF EXISTS (
157+
SELECT 1
158+
FROM pg_extension
159+
WHERE extname = 'pg_net'
160+
)
161+
THEN
162+
GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role;
163+
164+
ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
165+
ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
166+
167+
ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
168+
ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
169+
170+
REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
171+
REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
172+
173+
GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
174+
GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
175+
END IF;
176+
END
177+
$$;
178+
179+
-- Event trigger for pg_net
180+
CREATE OR REPLACE FUNCTION extensions.grant_pg_net_access()
181+
RETURNS event_trigger
182+
LANGUAGE plpgsql
183+
AS $$
184+
BEGIN
185+
IF EXISTS (
186+
SELECT 1
187+
FROM pg_event_trigger_ddl_commands() AS ev
188+
JOIN pg_extension AS ext
189+
ON ev.objid = ext.oid
190+
WHERE ext.extname = 'pg_net'
191+
)
192+
THEN
193+
IF NOT EXISTS (
194+
SELECT 1
195+
FROM pg_roles
196+
WHERE rolname = 'supabase_functions_admin'
197+
)
198+
THEN
199+
CREATE USER supabase_functions_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION;
200+
END IF;
201+
202+
GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role;
203+
204+
ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
205+
ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
206+
207+
ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
208+
ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
209+
210+
REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
211+
REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
212+
213+
GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
214+
GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
215+
END IF;
216+
END;
217+
$$;
218+
COMMENT ON FUNCTION extensions.grant_pg_net_access IS 'Grants access to pg_net';
219+
220+
DO
221+
$$
222+
BEGIN
223+
IF NOT EXISTS (
224+
SELECT 1
225+
FROM pg_event_trigger
226+
WHERE evtname = 'issue_pg_net_access'
227+
) THEN
228+
CREATE EVENT TRIGGER issue_pg_net_access ON ddl_command_end WHEN TAG IN ('CREATE EXTENSION')
229+
EXECUTE PROCEDURE extensions.grant_pg_net_access();
230+
END IF;
231+
END
232+
$$;
233+
234+
INSERT INTO supabase_functions.migrations (version) VALUES ('20210809183423_update_grants');
235+
236+
ALTER function supabase_functions.http_request() SECURITY DEFINER;
237+
ALTER function supabase_functions.http_request() SET search_path = supabase_functions;
238+
REVOKE ALL ON FUNCTION supabase_functions.http_request() FROM PUBLIC;
239+
GRANT EXECUTE ON FUNCTION supabase_functions.http_request() TO postgres, anon, authenticated, service_role;
240+
241+
242+
-- migrate:down

0 commit comments

Comments
 (0)