feat(db): add user_keys table with RLS and public-key view
Note: not applied locally — push via pnpm prod:migrate when ready.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
-- Per-user X25519 identity replacing the per-device key model.
|
||||
-- The private key is sealed with a PIN-derived Argon2id KEK; the server
|
||||
-- never sees plaintext. Lockout counters protect the 6-digit PIN against
|
||||
-- online brute force by gating ciphertext delivery (see try_unlock_user_key).
|
||||
|
||||
create table if not exists public.user_keys (
|
||||
user_id uuid primary key references auth.users(id) on delete cascade,
|
||||
public_key bytea not null,
|
||||
sealed_private_key bytea not null,
|
||||
salt bytea not null,
|
||||
kdf_params jsonb not null,
|
||||
recovery_sealed_private_key bytea null,
|
||||
recovery_salt bytea null,
|
||||
failed_attempts int not null default 0,
|
||||
locked_until timestamptz null,
|
||||
failed_recovery_attempts int not null default 0,
|
||||
recovery_locked_until timestamptz null,
|
||||
key_version int not null default 1,
|
||||
created_at timestamptz not null default now(),
|
||||
updated_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
alter table public.user_keys enable row level security;
|
||||
|
||||
drop policy if exists user_keys_self_rw on public.user_keys;
|
||||
create policy user_keys_self_rw
|
||||
on public.user_keys
|
||||
for all
|
||||
to authenticated
|
||||
using (user_id = auth.uid())
|
||||
with check (user_id = auth.uid());
|
||||
|
||||
-- Public-key view: any authenticated user may read peer public keys to wrap
|
||||
-- conv-keys for them. Only the columns granted below are exposed.
|
||||
create or replace view public.user_public_keys
|
||||
with (security_invoker = true) as
|
||||
select user_id, public_key, key_version
|
||||
from public.user_keys;
|
||||
|
||||
grant select on public.user_public_keys to authenticated;
|
||||
|
||||
-- Column-level grant lets the view see those columns without RLS rejecting
|
||||
-- non-owners. The self_rw policy still grants full row access to the owner.
|
||||
grant select (user_id, public_key, key_version) on public.user_keys to authenticated;
|
||||
|
||||
drop policy if exists user_keys_select_public_columns on public.user_keys;
|
||||
create policy user_keys_select_public_columns
|
||||
on public.user_keys
|
||||
for select
|
||||
to authenticated
|
||||
using (true);
|
||||
|
||||
alter publication supabase_realtime add table public.user_keys;
|
||||
Reference in New Issue
Block a user