feat(P3.T1): devices.revoked_at + revoke_device RPC + realtime publication
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
-- 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
|
||||
$$;
|
||||
Reference in New Issue
Block a user