import type { APIRoute } from 'astro'; import { randomBytes } from 'node:crypto'; import { one, query } from '../../../lib/db'; import { encrypt, maskSecret, decrypt } from '../../../lib/crypto'; export const prerender = false; const randomToken = () => 'klb_' + randomBytes(24).toString('hex'); const json = (b: unknown, s = 200) => new Response(JSON.stringify(b), { status: s, headers: { 'Content-Type': 'application/json' } }); export const GET: APIRoute = async () => { const s = await one('SELECT * FROM settings WHERE id=1'); if (!s) return json({ settings: null }); let orMask = ''; if (s.openrouter_key_enc) { try { orMask = maskSecret(decrypt(s.openrouter_key_enc)); } catch { orMask = 'gesetzt'; } } return json({ settings: { openrouter_key_masked: orMask, openrouter_key_set: !!s.openrouter_key_enc, picdrop_host: s.picdrop_host, picdrop_protocol: s.picdrop_protocol, picdrop_port: s.picdrop_port, picdrop_user: s.picdrop_user, picdrop_base_path: s.picdrop_base_path, picdrop_default_gallery: s.picdrop_default_gallery, picdrop_password_set: !!s.picdrop_password_enc, default_dpi: s.default_dpi, default_crop_mode: s.default_crop_mode, concurrency: s.concurrency, cricut_sheet_cm: s.cricut_sheet_cm, monthly_budget: s.monthly_budget, n8n_webhook_url: s.n8n_webhook_url, // Speicherverwaltung keep_sources: s.keep_sources, make_thumbnails: s.make_thumbnails, retention_days: s.retention_days, metadata_sidecar: s.metadata_sidecar, api_token: s.api_token, picdrop_metadata_sidecar: s.picdrop_metadata_sidecar, nas_metadata_sidecar: s.nas_metadata_sidecar, output_ext: s.output_ext, // Rechte / Datenschutz / NSFW library_visibility: s.library_visibility, anonymous_generations: s.anonymous_generations, private_allowed: s.private_allowed, allow_nsfw: s.allow_nsfw, // NAS-Sicherung nas_enabled: s.nas_enabled, nas_host: s.nas_host, nas_protocol: s.nas_protocol, nas_port: s.nas_port, nas_user: s.nas_user, nas_base_path: s.nas_base_path, nas_password_set: !!s.nas_password_enc, // E-Mail-Versand (Passwort wird nie zurückgegeben, nur ob es gesetzt ist) smtp_host: s.smtp_host, smtp_port: s.smtp_port, smtp_secure: s.smtp_secure, smtp_user: s.smtp_user, smtp_from: s.smtp_from, smtp_password_set: !!s.smtp_password, // Teilen share_default_days: s.share_default_days, } }); }; export const PATCH: APIRoute = async ({ request }) => { const b = await request.json(); const sets: string[] = []; const args: any[] = []; const set = (col: string, val: any) => { args.push(val); sets.push(`${col}=$${args.length}`); }; if (b.openrouter_key) set('openrouter_key_enc', encrypt(String(b.openrouter_key))); if (b.picdrop_password) set('picdrop_password_enc', encrypt(String(b.picdrop_password))); if (b.nas_password) set('nas_password_enc', encrypt(String(b.nas_password))); if (b.smtp_password) set('smtp_password', encrypt(String(b.smtp_password))); if (b.generate_api_token) set('api_token', randomToken()); const boolCols = ['keep_sources', 'make_thumbnails', 'nas_enabled', 'metadata_sidecar', 'picdrop_metadata_sidecar', 'nas_metadata_sidecar', 'anonymous_generations', 'private_allowed', 'allow_nsfw', 'smtp_secure']; for (const col of ['picdrop_host', 'picdrop_protocol', 'picdrop_port', 'picdrop_user', 'picdrop_base_path', 'picdrop_default_gallery', 'default_dpi', 'default_crop_mode', 'concurrency', 'cricut_sheet_cm', 'monthly_budget', 'n8n_webhook_url', 'keep_sources', 'make_thumbnails', 'retention_days', 'metadata_sidecar', 'api_token', 'picdrop_metadata_sidecar', 'nas_metadata_sidecar', 'output_ext', 'library_visibility', 'anonymous_generations', 'private_allowed', 'allow_nsfw', 'nas_enabled', 'nas_host', 'nas_protocol', 'nas_port', 'nas_user', 'nas_base_path', 'smtp_host', 'smtp_port', 'smtp_secure', 'smtp_user', 'smtp_from', 'share_default_days']) { if (col in b) { const raw = b[col]; const val = boolCols.includes(col) ? !!raw : (raw === '' ? null : raw); set(col, val); } } if (!sets.length) return json({ ok: true }); await query(`UPDATE settings SET ${sets.join(',')} WHERE id=1`, args); return json({ ok: true }); };