Merge commit 'f518eb7a1394ee29b825e551e6557dd71cd95a28'
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
import { Hono } from 'hono';
|
||||
import { rateLimit } from '../ratelimit.js';
|
||||
import { login } from '../auth-local.js';
|
||||
|
||||
// Lokaler Login (auth: 'local') — ersetzt GoTrue. Liefert ein GoTrue-förmiges
|
||||
// Token, das requireAuth genauso prüft wie ein Supabase-Token. Nur gemountet,
|
||||
// wenn config.auth === 'local' (siehe index.js); Brute-Force gedrosselt.
|
||||
const auth = new Hono();
|
||||
|
||||
auth.post('/login', rateLimit({ max: 10, windowMs: 5 * 60_000 }), async (c) => {
|
||||
let body = {};
|
||||
try { body = await c.req.json(); } catch { /* leerer/kaputter Body → 400 unten */ }
|
||||
const { email, password } = body;
|
||||
if (!email || !password) return c.json({ error: 'E-Mail und Passwort nötig' }, 400);
|
||||
const res = await login(email, password);
|
||||
if (!res) return c.json({ error: 'Login fehlgeschlagen' }, 401);
|
||||
return c.json(res);
|
||||
});
|
||||
|
||||
export default auth;
|
||||
@@ -5,6 +5,10 @@ import { requireAdmin, roleOf } from '../auth.js';
|
||||
import { config } from '../config.js';
|
||||
import { contentStats } from '../collections.js';
|
||||
import { manager } from '../plugins.js';
|
||||
import { countByRole } from '../auth-local.js';
|
||||
|
||||
const ADMIN_EMAILS = (process.env.ADMIN_EMAILS || '')
|
||||
.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
|
||||
|
||||
// Kennzahlen für die Admin-Übersicht. Nur Admins; rein lesend.
|
||||
const stats = new Hono();
|
||||
@@ -16,12 +20,16 @@ stats.get('/', async (c) => {
|
||||
try { content = contentStats(await listEntries(), config.collections); }
|
||||
catch { /* Filesystem nicht lesbar → leer */ }
|
||||
|
||||
// Nutzer nach Rolle (GoTrue).
|
||||
const users = { total: 0, admin: 0, editor: 0, user: 0 };
|
||||
try {
|
||||
const { data } = await supabase.auth.admin.listUsers();
|
||||
for (const u of data?.users || []) { users.total++; users[roleOf(u)] = (users[roleOf(u)] || 0) + 1; }
|
||||
} catch { /* GoTrue nicht erreichbar */ }
|
||||
// Nutzer nach Rolle: lokal aus der User-Datei, sonst aus GoTrue.
|
||||
let users = { total: 0, admin: 0, editor: 0, user: 0 };
|
||||
if (config.auth === 'local') {
|
||||
try { users = await countByRole(ADMIN_EMAILS); } catch { /* User-Datei fehlt → 0 */ }
|
||||
} else if (supabase) {
|
||||
try {
|
||||
const { data } = await supabase.auth.admin.listUsers();
|
||||
for (const u of data?.users || []) { users.total++; users[roleOf(u)] = (users[roleOf(u)] || 0) + 1; }
|
||||
} catch { /* GoTrue nicht erreichbar */ }
|
||||
}
|
||||
|
||||
// Plugin-Kennzahlen einsammeln (jedes Plugin unter seinem Namen). Nur geladene
|
||||
// Plugins lesen die DB — eine pluginlose Site macht hier null DB-Zugriffe.
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import { Hono } from 'hono';
|
||||
import { supabase } from '../supabase.js';
|
||||
import { requireAdmin, roleOf } from '../auth.js';
|
||||
import { config } from '../config.js';
|
||||
import * as local from '../auth-local.js';
|
||||
|
||||
// Autoren-/Nutzerverwaltung über die GoTrue-Admin-API (Service-Key). Nur Admins.
|
||||
// Autoren-/Nutzerverwaltung. Mit auth:'local' gegen die User-Datei (DB-los),
|
||||
// sonst über die GoTrue-Admin-API (Service-Key). Nur Admins.
|
||||
const ADMINS = (process.env.ADMIN_EMAILS || '')
|
||||
.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
|
||||
const isLocal = () => config.auth === 'local';
|
||||
|
||||
const users = new Hono();
|
||||
users.use('*', requireAdmin);
|
||||
|
||||
users.get('/', async (c) => {
|
||||
if (isLocal()) {
|
||||
try { return c.json(await local.listUsers(ADMINS)); }
|
||||
catch (e) { return c.json({ error: String(e.message || e) }, 500); }
|
||||
}
|
||||
const { data, error } = await supabase.auth.admin.listUsers();
|
||||
if (error) return c.json({ error: error.message }, 500);
|
||||
const list = (data?.users || []).map((u) => {
|
||||
@@ -32,6 +40,10 @@ users.post('/', async (c) => {
|
||||
const { email, password, role } = await c.req.json();
|
||||
if (!email || !password) return c.json({ error: 'E-Mail und Passwort nötig' }, 400);
|
||||
if (role && !['user', 'editor', 'admin'].includes(role)) return c.json({ error: 'Unbekannte Rolle' }, 400);
|
||||
if (isLocal()) {
|
||||
try { return c.json({ ok: true, id: await local.createUser({ email, password, role }) }); }
|
||||
catch (e) { return c.json({ error: String(e.message || e) }, 400); }
|
||||
}
|
||||
const payload = { email, password, email_confirm: true };
|
||||
if (role && role !== 'user') payload.app_metadata = { role };
|
||||
const { data, error } = await supabase.auth.admin.createUser(payload);
|
||||
@@ -41,19 +53,25 @@ users.post('/', async (c) => {
|
||||
|
||||
users.put('/:id', async (c) => {
|
||||
const { password, role } = await c.req.json();
|
||||
if (role && !['user', 'editor', 'admin'].includes(role)) return c.json({ error: 'Unbekannte Rolle' }, 400);
|
||||
if (!password && !role) return c.json({ error: 'Nichts zu ändern' }, 400);
|
||||
if (isLocal()) {
|
||||
try { await local.updateUser(c.req.param('id'), { password, role }); return c.json({ ok: true }); }
|
||||
catch (e) { return c.json({ error: String(e.message || e) }, 400); }
|
||||
}
|
||||
const patch = {};
|
||||
if (password) patch.password = password;
|
||||
if (role) {
|
||||
if (!['user', 'editor', 'admin'].includes(role)) return c.json({ error: 'Unbekannte Rolle' }, 400);
|
||||
patch.app_metadata = { role };
|
||||
}
|
||||
if (!Object.keys(patch).length) return c.json({ error: 'Nichts zu ändern' }, 400);
|
||||
if (role) patch.app_metadata = { role };
|
||||
const { error } = await supabase.auth.admin.updateUserById(c.req.param('id'), patch);
|
||||
if (error) return c.json({ error: error.message }, 400);
|
||||
return c.json({ ok: true });
|
||||
});
|
||||
|
||||
users.delete('/:id', async (c) => {
|
||||
if (isLocal()) {
|
||||
try { await local.deleteUser(c.req.param('id')); return c.json({ ok: true }); }
|
||||
catch (e) { return c.json({ error: String(e.message || e) }, 400); }
|
||||
}
|
||||
const { error } = await supabase.auth.admin.deleteUser(c.req.param('id'));
|
||||
if (error) return c.json({ error: error.message }, 400);
|
||||
return c.json({ ok: true });
|
||||
|
||||
Reference in New Issue
Block a user