Files
ChatApp/supabase/migrations/20260516000005_device_revocation.sql
T
2026-05-16 18:48:22 +02:00

68 lines
2.0 KiB
PL/PgSQL

-- Phase 3: per-device revocation. Adds a revoked_at flag, an RPC that lets
-- the device's owner flip it, and publishes the devices table to realtime
-- so every signed-in install can react to its own row being revoked.
alter table public.devices
add column if not exists revoked_at timestamptz null;
create index if not exists devices_user_revoked_idx
on public.devices(user_id, revoked_at);
-- RLS: existing policy on devices already gates by user_id; an UPDATE done
-- via the RPC runs with SECURITY DEFINER so we don't widen the RLS surface.
create or replace function public.revoke_device(p_device_id uuid)
returns void
language plpgsql
security definer
set search_path = public
as $$
declare
v_owner uuid;
begin
if auth.uid() is null then
raise exception 'not authenticated' using errcode = '28000';
end if;
select user_id into v_owner
from public.devices
where id = p_device_id;
if v_owner is null then
raise exception 'device not found' using errcode = 'P0002';
end if;
if v_owner <> auth.uid() then
raise exception 'not authorized' using errcode = '42501';
end if;
update public.devices
set revoked_at = now()
where id = p_device_id
and revoked_at is null;
end;
$$;
revoke all on function public.revoke_device(uuid) from public;
grant execute on function public.revoke_device(uuid) to authenticated;
-- Replica identity full so UPDATE events deliver the full new row (including
-- revoked_at) to subscribers; default REPLICA IDENTITY DEFAULT only sends
-- the primary key columns, which would force a refetch on every event.
alter table public.devices replica identity full;
-- Add devices to the supabase_realtime publication if not already present.
do $$
begin
if not exists (
select 1
from pg_publication_tables
where pubname = 'supabase_realtime'
and schemaname = 'public'
and tablename = 'devices'
) then
execute 'alter publication supabase_realtime add table public.devices';
end if;
end
$$;