100 lines
3.7 KiB
PL/PgSQL
100 lines
3.7 KiB
PL/PgSQL
-- Migration to fix infinite recursion in RLS policies
|
|
-- Date: 2024-12-06
|
|
-- Description: Introduces security definer function to fetch user organizations safely and updates policies.
|
|
|
|
-- 1. Create helper function to get user's organizations (Bypasses RLS)
|
|
CREATE OR REPLACE FUNCTION public.get_my_org_ids()
|
|
RETURNS UUID[] AS $$
|
|
BEGIN
|
|
RETURN ARRAY(
|
|
SELECT organizacao_id
|
|
FROM public.organizacao_usuarios
|
|
WHERE usuario_id = auth.uid()
|
|
AND ativo = true
|
|
);
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
COMMENT ON FUNCTION public.get_my_org_ids() IS 'Retorna lista de IDs das organizações do usuário (Security Definer para evitar recursão)';
|
|
|
|
-- 2. Drop recursive policies
|
|
|
|
-- Organizacao Usuarios
|
|
DROP POLICY IF EXISTS "Ver membros da organização" ON public.organizacao_usuarios;
|
|
DROP POLICY IF EXISTS "Admins gerenciam membros" ON public.organizacao_usuarios;
|
|
|
|
-- Usuarios
|
|
DROP POLICY IF EXISTS "Usuários veem membros da organização" ON public.usuarios;
|
|
DROP POLICY IF EXISTS "Admins podem criar usuários" ON public.usuarios;
|
|
|
|
|
|
-- 3. Re-create policies using the safe function
|
|
|
|
-- ========================================
|
|
-- ORGANIZACAO_USUARIOS
|
|
-- ========================================
|
|
|
|
-- Usuários veem membros das organizações que participam
|
|
CREATE POLICY "Ver membros da organização" ON public.organizacao_usuarios
|
|
FOR SELECT USING (
|
|
organizacao_id = ANY(public.get_my_org_ids())
|
|
);
|
|
|
|
-- Admins gerenciam membros (precisamos verificar role também)
|
|
CREATE POLICY "Admins gerenciam membros" ON public.organizacao_usuarios
|
|
FOR ALL USING (
|
|
organizacao_id = ANY(public.get_my_org_ids())
|
|
AND (
|
|
SELECT role FROM public.organizacao_usuarios
|
|
WHERE usuario_id = auth.uid()
|
|
AND organizacao_id = public.organizacao_usuarios.organizacao_id
|
|
) IN ('owner', 'admin')
|
|
);
|
|
-- Note: The subquery above might still be recursive if not careful.
|
|
-- But since we are checking the row being accessed 'public.organizacao_usuarios.organizacao_id',
|
|
-- and matching it against 'auth.uid()', we are looking up OUR OWN role in that specific org.
|
|
-- To be absolutely safe and avoid recursion in 'role' lookup, we should use get_user_role() function which is SECURITY DEFINER.
|
|
|
|
DROP POLICY IF EXISTS "Admins gerenciam membros" ON public.organizacao_usuarios;
|
|
CREATE POLICY "Admins gerenciam membros" ON public.organizacao_usuarios
|
|
FOR ALL USING (
|
|
organizacao_id = ANY(public.get_my_org_ids())
|
|
AND public.get_user_role(auth.uid(), organizacao_id) IN ('owner', 'admin')
|
|
);
|
|
|
|
|
|
-- ========================================
|
|
-- USUARIOS
|
|
-- ========================================
|
|
|
|
-- Usuários veem outros usuários da mesma organização
|
|
CREATE POLICY "Usuários veem membros da organização" ON public.usuarios
|
|
FOR SELECT USING (
|
|
organizacao_id = ANY(public.get_my_org_ids())
|
|
);
|
|
|
|
-- Admins podem criar usuários
|
|
CREATE POLICY "Admins podem criar usuários" ON public.usuarios
|
|
FOR INSERT WITH CHECK (
|
|
organizacao_id = ANY(public.get_my_org_ids())
|
|
AND public.get_user_role(auth.uid(), organizacao_id) IN ('owner', 'admin')
|
|
);
|
|
|
|
-- ========================================
|
|
-- OUTRAS TABELAS (Otimização opcional, mas recomendada para consistência)
|
|
-- ========================================
|
|
|
|
-- Atualizar convites
|
|
DROP POLICY IF EXISTS "Ver convites da organização" ON public.convites;
|
|
CREATE POLICY "Ver convites da organização" ON public.convites
|
|
FOR SELECT USING (
|
|
organizacao_id = ANY(public.get_my_org_ids())
|
|
);
|
|
|
|
-- Atualizar tarefas
|
|
DROP POLICY IF EXISTS "Ver tarefas da organização" ON public.tarefas;
|
|
CREATE POLICY "Ver tarefas da organização" ON public.tarefas
|
|
FOR SELECT USING (
|
|
organizacao_id = ANY(public.get_my_org_ids())
|
|
);
|