Files
MineGeo/supabase/migrations/20261007055439_legacy_password_claims.sql

51 lines
2.7 KiB
PL/PgSQL

create schema if not exists minegeo_private;
revoke all on schema minegeo_private from public, anon, authenticated;
grant usage on schema minegeo_private to service_role;
create table minegeo_private.legacy_password_claims (
user_id uuid primary key references auth.users(id) on delete cascade,
claimed_at timestamptz not null default now()
);
alter table minegeo_private.legacy_password_claims enable row level security;
revoke all on minegeo_private.legacy_password_claims from public, anon, authenticated;
grant select, insert on minegeo_private.legacy_password_claims to service_role;
create policy "Server reads password claims" on minegeo_private.legacy_password_claims
for select to service_role using (true);
create policy "Server creates password claims" on minegeo_private.legacy_password_claims
for insert to service_role with check (true);
-- This private helper reads only password eligibility, never returns a hash,
-- and never stores a plaintext password. Only the trusted server can call it.
create function minegeo_private.legacy_password(p_user uuid, p_claim boolean)
returns boolean language plpgsql security definer set search_path = '' as $$
declare eligible boolean; claimed uuid;
begin
if auth.uid() is not null and auth.uid() <> p_user then return false; end if;
select coalesce(encrypted_password, '') = '' and email is not null
and email_confirmed_at is not null and not coalesce(is_anonymous, false)
into eligible from auth.users where id = p_user for update;
if not coalesce(eligible, false) then return false; end if;
if not p_claim then
return not exists(select 1 from minegeo_private.legacy_password_claims where user_id = p_user);
end if;
insert into minegeo_private.legacy_password_claims(user_id) values(p_user)
on conflict(user_id) do nothing returning user_id into claimed;
return claimed is not null;
end;
$$;
revoke all on function minegeo_private.legacy_password(uuid,boolean) from public, anon, authenticated;
grant execute on function minegeo_private.legacy_password(uuid,boolean) to service_role;
create function public.legacy_password_needed(p_user uuid)
returns boolean language sql security invoker set search_path = '' as $$
select minegeo_private.legacy_password(p_user, false);
$$;
create function public.claim_legacy_password(p_user uuid)
returns boolean language sql security invoker set search_path = '' as $$
select minegeo_private.legacy_password(p_user, true);
$$;
revoke all on function public.legacy_password_needed(uuid) from public, anon, authenticated;
revoke all on function public.claim_legacy_password(uuid) from public, anon, authenticated;
grant execute on function public.legacy_password_needed(uuid) to service_role;
grant execute on function public.claim_legacy_password(uuid) to service_role;