From 13ff49903f00f66ad42e7521dbcf430187f83254 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 22 Aug 2026 23:10:55 +0000 Subject: [PATCH] Terminal --- .../20260726160000_mail_accounts.sql | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 supabase/migrations/20260726160000_mail_accounts.sql diff --git a/supabase/migrations/20260726160000_mail_accounts.sql b/supabase/migrations/20260726160000_mail_accounts.sql deleted file mode 100644 index b990c1a..0000000 --- a/supabase/migrations/20260726160000_mail_accounts.sql +++ /dev/null @@ -1,63 +0,0 @@ --- Embedded mail: one shared IMAP/SMTP server configured by admins, with a --- per-user mailbox login. --- --- Threat model drives the shape here. A mailbox password grants full read and --- send access to someone's email, so: --- --- * user_mailboxes has RLS enabled and NO policies at all. Nothing reachable --- from a browser can read it — not even the mailbox owner, and not admins. --- Every access goes through server functions using the service role, the --- same pattern intake_tokens uses. --- * The password is never stored as plaintext. It is sealed with AES-256-GCM --- using MAIL_CRED_KEY from .env.secret, so a database dump alone is not --- enough to open anyone's mail. --- * The IMAP/SMTP *host* settings are not secret, so admins may read those --- directly to populate the setup form. - -CREATE TABLE IF NOT EXISTS public.mail_server_settings ( - -- Single-row table: the school has one mail server. - id BOOLEAN PRIMARY KEY DEFAULT TRUE CHECK (id = TRUE), - imap_host TEXT NOT NULL, - imap_port INT NOT NULL DEFAULT 993, - imap_secure BOOLEAN NOT NULL DEFAULT TRUE, -- implicit TLS on connect - smtp_host TEXT NOT NULL, - smtp_port INT NOT NULL DEFAULT 587, - smtp_secure BOOLEAN NOT NULL DEFAULT FALSE, -- false = STARTTLS upgrade - updated_by UUID REFERENCES auth.users(id), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now() -); -GRANT SELECT ON public.mail_server_settings TO authenticated; -GRANT ALL ON public.mail_server_settings TO service_role; -ALTER TABLE public.mail_server_settings ENABLE ROW LEVEL SECURITY; - --- Host/port are operational config, not secrets. Admins read them to fill in --- the setup form; writes go through a server function so they can be validated --- against a live login first. -CREATE POLICY "mail settings admin read" ON public.mail_server_settings FOR SELECT TO authenticated - USING (public.current_user_has_role('admin')); - -CREATE TABLE IF NOT EXISTS public.user_mailboxes ( - user_id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE, - email TEXT NOT NULL, - -- AES-256-GCM sealed mailbox password. Never returned to any client. - secret_ciphertext TEXT NOT NULL, - secret_iv TEXT NOT NULL, - secret_tag TEXT NOT NULL, - last_verified_at TIMESTAMPTZ, - created_by UUID REFERENCES auth.users(id), - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now() -); -CREATE INDEX IF NOT EXISTS idx_user_mailboxes_email ON public.user_mailboxes(email); -GRANT ALL ON public.user_mailboxes TO service_role; -ALTER TABLE public.user_mailboxes ENABLE ROW LEVEL SECURITY; --- Deliberately no policies and no grant to `authenticated`: credentials must --- never be reachable from the browser under any role. - -DROP TRIGGER IF EXISTS trg_mail_settings_upd ON public.mail_server_settings; -CREATE TRIGGER trg_mail_settings_upd BEFORE UPDATE ON public.mail_server_settings - FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); - -DROP TRIGGER IF EXISTS trg_user_mailboxes_upd ON public.user_mailboxes; -CREATE TRIGGER trg_user_mailboxes_upd BEFORE UPDATE ON public.user_mailboxes - FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();