supersam/docs/sql/order-groups-anon-n8n-inser...

116 lines
3.7 KiB
PL/PgSQL

-- Allow n8n to insert order_groups with the anon key, but only with a private
-- integration secret passed in the x-n8n-secret HTTP header.
--
-- n8n REST headers:
-- apikey: <SUPABASE_ANON_KEY>
-- Authorization: Bearer <SUPABASE_ANON_KEY>
-- x-n8n-secret: <LONG_RANDOM_SECRET>
-- Content-Type: application/json
-- Prefer: resolution=merge-duplicates,return=representation
--
-- Endpoint:
-- POST https://supa.supersamsev.ru/rest/v1/order_groups
--
-- Important:
-- - Keep this secret only in n8n credentials/environment.
-- - Do not put it in the frontend.
-- - Replace CHANGE_ME_LONG_RANDOM_SECRET before running this SQL.
create extension if not exists pgcrypto;
create table if not exists public.integration_api_secrets (
name text primary key,
secret_hash text not null,
created_at timestamptz not null default now()
);
alter table public.integration_api_secrets enable row level security;
drop policy if exists "integration api secrets admin only" on public.integration_api_secrets;
create policy "integration api secrets admin only"
on public.integration_api_secrets
for all
using (public.current_role_name() = 'admin')
with check (public.current_role_name() = 'admin');
insert into public.integration_api_secrets (name, secret_hash)
values (
'n8n_order_groups_insert',
crypt('CHANGE_ME_LONG_RANDOM_SECRET', gen_salt('bf'))
)
on conflict (name) do update
set secret_hash = excluded.secret_hash;
create or replace function public.is_valid_n8n_order_groups_secret()
returns boolean
language sql
stable
security definer
set search_path = public
as $$
select coalesce(
exists (
select 1
from public.integration_api_secrets s
where s.name = 'n8n_order_groups_insert'
and crypt(
nullif(current_setting('request.headers', true)::jsonb ->> 'x-n8n-secret', ''),
s.secret_hash
) = s.secret_hash
),
false
);
$$;
revoke all on function public.is_valid_n8n_order_groups_secret() from public;
grant execute on function public.is_valid_n8n_order_groups_secret() to anon, authenticated;
alter table public.order_groups enable row level security;
drop policy if exists "order groups insert service roles" on public.order_groups;
drop policy if exists "order groups insert coordination and integration roles" on public.order_groups;
drop policy if exists "order groups insert n8n anon secret" on public.order_groups;
create policy "order groups insert n8n anon secret"
on public.order_groups
for insert
to anon
with check (public.is_valid_n8n_order_groups_secret());
create policy "order groups insert coordination and integration roles"
on public.order_groups
for insert
to authenticated
with check (
public.current_role_name() in ('manager', 'logistician', 'admin', 'integration')
);
-- If n8n uses upsert, update must also be allowed for the same anon secret.
drop policy if exists "order groups update n8n anon secret" on public.order_groups;
drop policy if exists "order groups update coordination roles" on public.order_groups;
drop policy if exists "order groups update coordination and integration roles" on public.order_groups;
create policy "order groups update n8n anon secret"
on public.order_groups
for update
to anon
using (public.is_valid_n8n_order_groups_secret())
with check (public.is_valid_n8n_order_groups_secret());
create policy "order groups update coordination and integration roles"
on public.order_groups
for update
to authenticated
using (
public.current_role_name() in ('manager', 'logistician', 'admin', 'integration')
)
with check (
public.current_role_name() in ('manager', 'logistician', 'admin', 'integration')
);
-- Diagnostics:
-- select policyname, cmd, roles, qual, with_check
-- from pg_policies
-- where schemaname = 'public' and tablename = 'order_groups'
-- order by policyname;