Skip to content

Commit 374f65e

Browse files
committed
force chat messages unread on insert
1 parent ed54461 commit 374f65e

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
-- Chat unread state is server-owned. Authenticated senders can create a
2+
-- message, but they cannot mark it read during insert.
3+
4+
revoke insert on table public.chat_messages from authenticated;
5+
6+
grant insert (
7+
thread_id,
8+
sender_id,
9+
content
10+
) on table public.chat_messages to authenticated;
11+
12+
revoke insert on table public.chat_threads from authenticated;
13+
14+
grant insert (
15+
listing_id,
16+
initiator_id,
17+
owner_id
18+
) on table public.chat_threads to authenticated;
19+
20+
create or replace function private.enforce_chat_message_insert()
21+
returns trigger
22+
language plpgsql
23+
security definer
24+
set search_path = ''
25+
as $$
26+
declare
27+
thread_record public.chat_threads%rowtype;
28+
jwt_role text;
29+
begin
30+
jwt_role := nullif(current_setting('request.jwt.claim.role', true), '');
31+
32+
if jwt_role = 'service_role'
33+
or ((select auth.uid()) is null and jwt_role is null)
34+
then
35+
return new;
36+
end if;
37+
38+
new.created_at := timezone('utc'::text, now());
39+
new.read_at := null;
40+
41+
if (select auth.uid()) is null or new.sender_id is distinct from (select auth.uid()) then
42+
raise exception 'Users can only send messages as themselves.'
43+
using errcode = '42501';
44+
end if;
45+
46+
select *
47+
into thread_record
48+
from public.chat_threads
49+
where id = new.thread_id;
50+
51+
if thread_record.id is null or (
52+
thread_record.initiator_id is distinct from new.sender_id
53+
and thread_record.owner_id is distinct from new.sender_id
54+
) then
55+
raise exception 'Users can only send messages in their own threads.'
56+
using errcode = '42501';
57+
end if;
58+
59+
if new.content is null or trim(both from new.content) = '' then
60+
raise exception 'Message content cannot be empty.'
61+
using errcode = '23514';
62+
end if;
63+
64+
if (
65+
select count(*)
66+
from public.chat_messages
67+
where sender_id = new.sender_id
68+
and created_at >= now() - interval '1 hour'
69+
) >= 10 then
70+
raise exception 'Too many messages sent recently.'
71+
using errcode = '42501';
72+
end if;
73+
74+
return new;
75+
end;
76+
$$;
77+
78+
alter function private.enforce_chat_message_insert() owner to postgres;
79+
80+
revoke all privileges on function private.enforce_chat_message_insert()
81+
from anon, authenticated, public;

0 commit comments

Comments
 (0)