Skip to content

Commit f77c88a

Browse files
committed
force chat insert timestamps
1 parent 297fd73 commit f77c88a

1 file changed

Lines changed: 128 additions & 0 deletions

File tree

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
-- Rate limits use created_at windows, so authenticated clients must not be
2+
-- able to backdate chat rows. Force server timestamps for client inserts.
3+
4+
create or replace function private.enforce_chat_message_insert()
5+
returns trigger
6+
language plpgsql
7+
security definer
8+
set search_path = ''
9+
as $$
10+
declare
11+
thread_record public.chat_threads%rowtype;
12+
jwt_role text;
13+
begin
14+
jwt_role := nullif(current_setting('request.jwt.claim.role', true), '');
15+
16+
if jwt_role = 'service_role'
17+
or ((select auth.uid()) is null and jwt_role is null)
18+
then
19+
return new;
20+
end if;
21+
22+
new.created_at := timezone('utc'::text, now());
23+
24+
if (select auth.uid()) is null or new.sender_id is distinct from (select auth.uid()) then
25+
raise exception 'Users can only send messages as themselves.'
26+
using errcode = '42501';
27+
end if;
28+
29+
select *
30+
into thread_record
31+
from public.chat_threads
32+
where id = new.thread_id;
33+
34+
if thread_record.id is null or (
35+
thread_record.initiator_id is distinct from new.sender_id
36+
and thread_record.owner_id is distinct from new.sender_id
37+
) then
38+
raise exception 'Users can only send messages in their own threads.'
39+
using errcode = '42501';
40+
end if;
41+
42+
if new.content is null or trim(both from new.content) = '' then
43+
raise exception 'Message content cannot be empty.'
44+
using errcode = '23514';
45+
end if;
46+
47+
if (
48+
select count(*)
49+
from public.chat_messages
50+
where sender_id = new.sender_id
51+
and created_at >= now() - interval '1 hour'
52+
) >= 10 then
53+
raise exception 'Too many messages sent recently.'
54+
using errcode = '42501';
55+
end if;
56+
57+
return new;
58+
end;
59+
$$;
60+
61+
alter function private.enforce_chat_message_insert() owner to postgres;
62+
63+
revoke all privileges on function private.enforce_chat_message_insert()
64+
from anon, authenticated, public;
65+
66+
create or replace function private.enforce_chat_thread_insert()
67+
returns trigger
68+
language plpgsql
69+
security definer
70+
set search_path = ''
71+
as $$
72+
declare
73+
jwt_role text;
74+
begin
75+
jwt_role := nullif(current_setting('request.jwt.claim.role', true), '');
76+
77+
if jwt_role = 'service_role'
78+
or ((select auth.uid()) is null and jwt_role is null)
79+
then
80+
return new;
81+
end if;
82+
83+
new.created_at := timezone('utc'::text, now());
84+
85+
if (select auth.uid()) is null or new.initiator_id is distinct from (select auth.uid()) then
86+
raise exception 'Users can only start chat threads as themselves.'
87+
using errcode = '42501';
88+
end if;
89+
90+
if not exists (
91+
select 1
92+
from public.listings
93+
where listings.id = new.listing_id
94+
and listings.owner_id = new.owner_id
95+
and listings.visibility = true
96+
) then
97+
raise exception 'Users can only start chat threads for visible listings with the correct owner.'
98+
using errcode = '42501';
99+
end if;
100+
101+
if (
102+
select count(*)
103+
from public.chat_messages
104+
where sender_id = new.initiator_id
105+
and created_at >= now() - interval '1 hour'
106+
) >= 10 then
107+
raise exception 'Too many messages sent recently to start a new chat thread.'
108+
using errcode = '42501';
109+
end if;
110+
111+
if (
112+
select count(*)
113+
from public.chat_threads
114+
where initiator_id = new.initiator_id
115+
and created_at >= now() - interval '1 hour'
116+
) >= 6 then
117+
raise exception 'Too many chat threads started recently.'
118+
using errcode = '42501';
119+
end if;
120+
121+
return new;
122+
end;
123+
$$;
124+
125+
alter function private.enforce_chat_thread_insert() owner to postgres;
126+
127+
revoke all privileges on function private.enforce_chat_thread_insert()
128+
from anon, authenticated, public;

0 commit comments

Comments
 (0)