security: fix private storage buckets, api access, and admin RLS bypasses
All checks were successful
Staging Build / build (push) Successful in 3m41s

This commit is contained in:
DanielS
2026-07-04 17:36:51 +02:00
parent 205acb803f
commit 28f2285a0e
2 changed files with 64 additions and 1 deletions

View File

@@ -67,7 +67,7 @@ export async function updateSession(request: NextRequest) {
} }
// Admin protection // Admin protection
if (request.nextUrl.pathname.startsWith("/admin")) { if (request.nextUrl.pathname.startsWith("/admin") || request.nextUrl.pathname.startsWith("/api/admin")) {
if (!user || !user.sub) { if (!user || !user.sub) {
const url = request.nextUrl.clone(); const url = request.nextUrl.clone();
url.pathname = "/auth/login"; url.pathname = "/auth/login";

View File

@@ -0,0 +1,63 @@
-- Migration: Secure invoices bucket and allow admin access in RLS policies
-- 1. Secure storage bucket and set public to false
UPDATE storage.buckets SET public = false WHERE id = 'invoices';
-- 2. Update storage policy for invoice access to check authenticated company assignment or admin
DROP POLICY IF EXISTS "Public Access" ON storage.objects;
CREATE POLICY "Secure Invoice Access" ON storage.objects FOR SELECT USING (
bucket_id = 'invoices'
AND (
-- Admins can read all invoices
(SELECT role FROM public.users WHERE id = auth.uid()) = 'admin'
OR
-- Partner users can only read invoices belonging to their company
-- Filename format: ab_[order_id].pdf
(SELECT company_id FROM public.users WHERE id = auth.uid()) = (
SELECT company_id FROM public.orders
WHERE id = CAST(substring(name from 'ab_(.+)\.pdf') AS UUID)
)
)
);
-- 3. Recreate end_customers RLS policies to allow admin bypass
DROP POLICY IF EXISTS "Partner sehen nur eigene Endkunden" ON public.end_customers;
CREATE POLICY "Partner sehen nur eigene Endkunden" ON public.end_customers
FOR ALL
USING (
(SELECT role FROM public.users WHERE id = auth.uid()) = 'admin'
OR partner_id = (SELECT company_id FROM public.users WHERE id = auth.uid())
)
WITH CHECK (
(SELECT role FROM public.users WHERE id = auth.uid()) = 'admin'
OR partner_id = (SELECT company_id FROM public.users WHERE id = auth.uid())
);
-- 4. Recreate licenses SELECT RLS policy to allow admin bypass
DROP POLICY IF EXISTS "Partner sehen Lizenzen eigener Kunden" ON public.licenses;
CREATE POLICY "Partner sehen Lizenzen eigener Kunden" ON public.licenses
FOR SELECT
USING (
(SELECT role FROM public.users WHERE id = auth.uid()) = 'admin'
OR EXISTS (
SELECT 1 FROM public.end_customers c
WHERE c.id = licenses.end_customer_id
AND c.partner_id = (SELECT company_id FROM public.users WHERE id = auth.uid())
)
);
-- 5. Recreate licenses INSERT RLS policy to allow admin bypass
DROP POLICY IF EXISTS "Partner erstellen Lizenzen eigener Kunden" ON public.licenses;
CREATE POLICY "Partner erstellen Lizenzen eigener Kunden" ON public.licenses
FOR INSERT
WITH CHECK (
(SELECT role FROM public.users WHERE id = auth.uid()) = 'admin'
OR EXISTS (
SELECT 1 FROM public.end_customers c
WHERE c.id = licenses.end_customer_id
AND c.partner_id = (SELECT company_id FROM public.users WHERE id = auth.uid())
)
);
-- Reload Schema Cache
NOTIFY pgrst, 'reload schema';