116 lines
3.7 KiB
PL/PgSQL
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;
|