Files
karim 1d3818e725 docker-mailserver LXC für Proxmox: Stack + Admin-UI + Webmail + Hardening
- dms-lxc.sh: Proxmox-Host-Installer (unprivilegierter LXC, Debian 13, Docker),
  curl-Self-Download, Multi-Domain-DKIM, SnappyMail-Provisionierung, PVE-Firewall
- Stack: docker-mailserver, Node-Admin-API (Supabase-Auth), React-Admin-UI
  (OPENBUREAU-Look), SnappyMail (Shibui-Theme), Rspamd-Web-UI, docker-socket-proxy
- Admin: Postfächer/Aliase/Catch-all/Quota, editierbare Domains+Settings,
  Server (Quota/Queue über abgesicherte Bridge), Status & DNS
- Hardening: no-new-privileges, Whitelisted exec-Bridge, Rspamd-Passwort,
  .env chmod 600, PVE-CT-Firewall, generisch/teilbar (keine festen Domains)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 02:26:28 +02:00

61 lines
2.5 KiB
JavaScript

// ---------------------------------------------------------------------------
// auth.js — Supabase-Token-Prüfung (wie in OPENBUREAU)
//
// Die React-Admin-UI loggt sich per Supabase ein und schickt das Access-Token
// als Authorization: Bearer <token>. Hier validieren wir es gegen Supabase
// und prüfen, ob die E-Mail in ADMIN_ALLOWED_EMAILS steht.
// ---------------------------------------------------------------------------
import { createClient } from '@supabase/supabase-js';
const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_ANON_KEY = process.env.SUPABASE_ANON_KEY;
const ALLOWED = (process.env.ADMIN_ALLOWED_EMAILS || '')
.split(',')
.map((s) => s.trim().toLowerCase())
.filter(Boolean);
// Nur für lokale Tests: hebt die Auth komplett auf. Standardmäßig AUS.
// Wird ausschließlich im docker-compose.local.yml gesetzt, niemals im Deploy.
const AUTH_DISABLED = process.env.AUTH_DISABLED === 'true';
if (AUTH_DISABLED) {
console.warn('[auth] ⚠ AUTH_DISABLED=true — KEINE Authentifizierung! Nur für lokale Tests verwenden.');
}
// Supabase-Client nur erstellen, wenn Auth aktiv und konfiguriert ist
// (createClient wirft bei leerer URL — würde sonst den Start verhindern).
let supabase = null;
if (!AUTH_DISABLED) {
if (!SUPABASE_URL || !SUPABASE_ANON_KEY) {
console.warn('[auth] SUPABASE_URL / SUPABASE_ANON_KEY nicht gesetzt — Auth wird fehlschlagen.');
} else {
supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
auth: { persistSession: false, autoRefreshToken: false },
});
}
}
export async function requireAdmin(req, res, next) {
try {
if (AUTH_DISABLED) {
req.user = { email: 'dev@local.test' };
return next();
}
if (!supabase) return res.status(500).json({ error: 'Auth nicht konfiguriert (SUPABASE_URL/ANON_KEY fehlen).' });
const header = req.headers.authorization || '';
const token = header.startsWith('Bearer ') ? header.slice(7) : null;
if (!token) return res.status(401).json({ error: 'Kein Token.' });
const { data, error } = await supabase.auth.getUser(token);
if (error || !data?.user) return res.status(401).json({ error: 'Token ungültig.' });
const email = (data.user.email || '').toLowerCase();
if (ALLOWED.length && !ALLOWED.includes(email)) {
return res.status(403).json({ error: 'Kein Admin-Zugriff für diese E-Mail.' });
}
req.user = { email };
next();
} catch (e) {
res.status(500).json({ error: 'Auth-Fehler: ' + e.message });
}
}