fix: corregir acceso automático al Hub por dominio
This commit is contained in:
@@ -25,3 +25,9 @@ No es necesario modificar los workflows de n8n.
|
|||||||
| `role = member`, `is_active = false` | Usuario bloqueado |
|
| `role = member`, `is_active = false` | Usuario bloqueado |
|
||||||
|
|
||||||
Los registros `member` activos se eliminan durante la migración porque ya no son necesarios.
|
Los registros `member` activos se eliminan durante la migración porque ya no son necesarios.
|
||||||
|
|
||||||
|
## Corrección de compatibilidad con Supabase self-hosted
|
||||||
|
|
||||||
|
La validación del perfil consulta `glm_hub_authorized_users` como una lista limitada a una fila. Cuando no existe una fila, el resultado vacío se interpreta como **Usuario normal**, evitando que algunas versiones self-hosted de PostgREST rechacen el inicio de sesión al solicitar un objeto único sin coincidencias.
|
||||||
|
|
||||||
|
Para instalaciones que todavía conserven la función anterior de autorización, ejecuta `SUPABASE-GLM-HUB-HOTFIX-ACCESO-POR-DOMINIO.sql` una sola vez.
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- GLM HUB — HOTFIX DE ACCESO AUTOMÁTICO POR DOMINIO
|
||||||
|
-- ============================================================================
|
||||||
|
-- Ejecutar una sola vez en Supabase Studio > SQL Editor.
|
||||||
|
--
|
||||||
|
-- Resultado esperado:
|
||||||
|
-- * Todo usuario autenticado con @gomezleemarketing.com entra como Usuario.
|
||||||
|
-- * La ausencia de una fila en glm_hub_authorized_users NO bloquea el acceso.
|
||||||
|
-- * La tabla queda reservada para administradores y bloqueos excepcionales.
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
comment on table public.glm_hub_authorized_users is
|
||||||
|
'Excepciones del GLM Hub: administradores activos y usuarios bloqueados. Los usuarios corporativos normales no requieren registro.';
|
||||||
|
|
||||||
|
-- Cada usuario puede consultar únicamente su propia excepción. Una respuesta
|
||||||
|
-- vacía significa que es un Usuario normal del dominio corporativo.
|
||||||
|
drop policy if exists "GLM Hub users can read only their active access"
|
||||||
|
on public.glm_hub_authorized_users;
|
||||||
|
drop policy if exists "GLM Hub users can read their own control record"
|
||||||
|
on public.glm_hub_authorized_users;
|
||||||
|
|
||||||
|
create policy "GLM Hub users can read their own control record"
|
||||||
|
on public.glm_hub_authorized_users
|
||||||
|
for select
|
||||||
|
to authenticated
|
||||||
|
using (
|
||||||
|
email = lower(coalesce((select auth.jwt() ->> 'email'), ''))
|
||||||
|
);
|
||||||
|
|
||||||
|
-- La ausencia de registro significa acceso normal como Usuario.
|
||||||
|
create or replace function public.glm_hub_is_active_user()
|
||||||
|
returns boolean
|
||||||
|
language plpgsql
|
||||||
|
stable
|
||||||
|
security definer
|
||||||
|
set search_path = ''
|
||||||
|
as $$
|
||||||
|
declare
|
||||||
|
v_email text;
|
||||||
|
begin
|
||||||
|
v_email := lower(coalesce(auth.jwt() ->> 'email', ''));
|
||||||
|
|
||||||
|
return
|
||||||
|
auth.uid() is not null
|
||||||
|
and v_email ~ '^[a-z0-9.!#$%&''*+/=?^_`{|}~-]+@gomezleemarketing\.com$'
|
||||||
|
and not exists (
|
||||||
|
select 1
|
||||||
|
from public.glm_hub_authorized_users as access
|
||||||
|
where access.email = v_email
|
||||||
|
and access.is_active = false
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- Solo una fila activa con role = admin concede funciones administrativas.
|
||||||
|
create or replace function public.glm_hub_is_admin()
|
||||||
|
returns boolean
|
||||||
|
language plpgsql
|
||||||
|
stable
|
||||||
|
security definer
|
||||||
|
set search_path = ''
|
||||||
|
as $$
|
||||||
|
declare
|
||||||
|
v_email text;
|
||||||
|
begin
|
||||||
|
v_email := lower(coalesce(auth.jwt() ->> 'email', ''));
|
||||||
|
|
||||||
|
return
|
||||||
|
auth.uid() is not null
|
||||||
|
and exists (
|
||||||
|
select 1
|
||||||
|
from public.glm_hub_authorized_users as access
|
||||||
|
where access.email = v_email
|
||||||
|
and access.role = 'admin'
|
||||||
|
and access.is_active = true
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
alter function public.glm_hub_is_active_user() owner to postgres;
|
||||||
|
alter function public.glm_hub_is_admin() owner to postgres;
|
||||||
|
|
||||||
|
revoke all on function public.glm_hub_is_active_user() from public, anon;
|
||||||
|
revoke all on function public.glm_hub_is_admin() from public, anon;
|
||||||
|
grant execute on function public.glm_hub_is_active_user() to authenticated;
|
||||||
|
grant execute on function public.glm_hub_is_admin() to authenticated;
|
||||||
|
grant execute on function public.glm_hub_is_active_user() to service_role;
|
||||||
|
grant execute on function public.glm_hub_is_admin() to service_role;
|
||||||
|
|
||||||
|
-- Limpia registros normales antiguos. Se conservan administradores y bloqueos.
|
||||||
|
delete from public.glm_hub_authorized_users
|
||||||
|
where role = 'member'
|
||||||
|
and is_active = true;
|
||||||
|
|
||||||
|
notify pgrst, 'reload schema';
|
||||||
|
|
||||||
|
commit;
|
||||||
|
|
||||||
|
-- VERIFICACIÓN OPCIONAL:
|
||||||
|
-- select public.glm_hub_is_active_user() as puede_entrar,
|
||||||
|
-- public.glm_hub_is_admin() as es_administrador;
|
||||||
+11
-11
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -9,7 +9,7 @@
|
|||||||
<link rel="shortcut icon" type="image/png" href="https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png?v=glm-hub-20260722-v3" />
|
<link rel="shortcut icon" type="image/png" href="https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png?v=glm-hub-20260722-v3" />
|
||||||
<link rel="apple-touch-icon" href="https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png?v=glm-hub-20260722-v3" />
|
<link rel="apple-touch-icon" href="https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png?v=glm-hub-20260722-v3" />
|
||||||
<title>GLM Hub — GomezLee Marketing</title>
|
<title>GLM Hub — GomezLee Marketing</title>
|
||||||
<script type="module" crossorigin src="/assets/index-_vT1KbDN.js"></script>
|
<script type="module" crossorigin src="/assets/index-Kd6NFVcJ.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-9ByAKvcq.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-9ByAKvcq.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
+8
-2
@@ -139,12 +139,18 @@ async function authorizeSupabaseSession(authSession: SupabaseAuthSession): Promi
|
|||||||
|
|
||||||
// Todos los correos corporativos entran como Usuario por defecto.
|
// Todos los correos corporativos entran como Usuario por defecto.
|
||||||
// La tabla solo conserva administradores y bloqueos excepcionales.
|
// La tabla solo conserva administradores y bloqueos excepcionales.
|
||||||
|
// Se consulta como una lista limitada a una fila en lugar de usar
|
||||||
|
// `maybeSingle()`. En algunas instalaciones self-hosted de PostgREST, una
|
||||||
|
// consulta sin coincidencias puede responder como error al solicitar un
|
||||||
|
// objeto único. Una lista vacía, en cambio, representa correctamente a un
|
||||||
|
// usuario corporativo normal que no necesita registro en la tabla.
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from("glm_hub_authorized_users")
|
.from("glm_hub_authorized_users")
|
||||||
.select("email, full_name, role, is_active")
|
.select("email, full_name, role, is_active")
|
||||||
.eq("email", email)
|
.eq("email", email)
|
||||||
.maybeSingle();
|
.limit(1);
|
||||||
const access = data as AuthorizedUserRow | null;
|
const accessRows = (data ?? []) as AuthorizedUserRow[];
|
||||||
|
const access = accessRows[0] ?? null;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("No se pudo validar el perfil de acceso:", error);
|
console.error("No se pudo validar el perfil de acceso:", error);
|
||||||
|
|||||||
Reference in New Issue
Block a user