WIP: PayPal-Einstellungen ueber die Verwaltung (Test folgt auf dem Server)

This commit is contained in:
2026-08-23 16:50:18 +02:00
parent 692d702ebf
commit 5043642951
6 changed files with 629 additions and 11 deletions
@@ -51,6 +51,7 @@ import { ausweisPruefen } from "../lib/webdesign-ausweis.js";
import { brauchtKunde } from "./webdesign-portal.js";
import { zustimmungSpeichern } from "./webdesign-widerruf.js";
import * as paypal from "../lib/webdesign-paypal.js";
import * as geheim from "../lib/webdesign-geheimnisse.js";
import {
jetzt, neueId, naechsteNummer, text, verlauf, centZuText,
besucherIp, spracheOderDe,
@@ -454,3 +455,125 @@ export async function zahlungenListe(req, res) {
},
});
}
/* =====================================================================
EINSTELLUNGEN — PayPal-Zugangsdaten über die Verwaltung eintragen
Damit Filipe dafür nicht in die Konsole muss. Die Werte werden
verschlüsselt gespeichert (siehe lib/webdesign-geheimnisse.js) und
wirken sofort — ohne Dienstneustart.
===================================================================== */
/* GET /webdesign/admin/einstellungen
Gibt NIE einen hinterlegten Wert zurück, auch nicht teilweise. Nur:
ist etwas da, woher stammt es, wie lang ist es, wann zuletzt geändert.
Ein Geheimnis, das man wieder auslesen kann, ist über kurz oder lang
auch dort, wo es nicht hingehört. */
export async function einstellungenLesen(req, res) {
const p = await darf(req, "WD_ZAHLUNGEN_VIEW");
if (!p.erlaubt) return json(res, { ok: false, error: "Kein Zugriff." }, p.grund);
return json(res, {
ok: true,
stand: geheim.stand(),
einrichtung: {
einmal: paypal.istEingerichtet("einmal"),
abo: paypal.istEingerichtet("abo"),
fehlt: paypal.fehlendeEinstellungen("abo"),
live: paypal.istLive(),
},
webhookUrl: `${(process.env.API_BASIS_URL || "https://postfach.dogfather-universe.com")}/webdesign/paypal-webhook`,
});
}
/* POST /webdesign/admin/einstellungen
Nimmt beliebig viele der erlaubten Schlüssel entgegen. Ein FEHLENDER
Schlüssel bleibt unverändert — nur ein ausdrücklich leerer Wert
löscht. Sonst würde ein Formular, das nur ein Feld ausfüllt, beim
Speichern alle anderen leeren. */
export async function einstellungenSchreiben(req, res) {
const p = await darf(req, "WD_ZAHLUNGEN_VIEW");
if (!p.erlaubt) return json(res, { ok: false, error: "Kein Zugriff." }, p.grund);
const eingang = req.body?.werte;
if (!eingang || typeof eingang !== "object") {
return json(res, { ok: false, error: "Keine Werte übermittelt." }, 400);
}
const geaendert = [];
const abgelehnt = [];
for (const [schluessel, wert] of Object.entries(eingang)) {
if (!(schluessel in geheim.ERLAUBTE_SCHLUESSEL)) { abgelehnt.push(schluessel); continue; }
/* undefined = "nicht angefasst". Leerer String = "löschen". Das ist
ein echter Unterschied und darf nicht verwischt werden. */
if (wert === undefined || wert === null) continue;
try {
const r = await geheim.einstellungSetzen(schluessel, wert);
geaendert.push(schluessel + (r.entfernt ? " (entfernt)" : ""));
} catch (fehler) {
return json(res, { ok: false, error: fehler.message }, 400);
}
}
/* PayPal merkt sich ein Zugangstoken. Nach einem Wechsel der
Zugangsdaten wäre es das alte — und die nächste Zahlung liefe noch
über das vorherige Konto oder scheiterte mit "invalid client".
Deshalb hier ausdrücklich vergessen. */
paypal.tokenVergessen();
/* Im Protokoll steht, WAS geändert wurde, nie WOMIT. */
verlauf("einstellungen", "paypal", "geaendert",
"team:" + (p.sitzung?.actor || "?"), { felder: geaendert });
return json(res, {
ok: true,
geaendert,
abgelehnt,
stand: geheim.stand(),
einrichtung: {
einmal: paypal.istEingerichtet("einmal"),
abo: paypal.istEingerichtet("abo"),
fehlt: paypal.fehlendeEinstellungen("abo"),
live: paypal.istLive(),
},
});
}
/* POST /webdesign/admin/einstellungen/pruefen
Meldet sich testweise bei PayPal an. Erst das beweist, dass die Werte
stimmen — "gesetzt" heisst nur, dass etwas dasteht, nicht dass es
richtig ist. Es fliesst dabei kein Geld. */
export async function einstellungenPruefen(req, res) {
const p = await darf(req, "WD_ZAHLUNGEN_VIEW");
if (!p.erlaubt) return json(res, { ok: false, error: "Kein Zugriff." }, p.grund);
if (!paypal.istEingerichtet("einmal")) {
return json(res, {
ok: false,
error: "Es fehlen noch Werte: " + paypal.fehlendeEinstellungen("einmal").join(", "),
}, 400);
}
try {
paypal.tokenVergessen();
await paypal.zugangstokenPruefen();
return json(res, {
ok: true,
live: paypal.istLive(),
meldung: paypal.istLive()
? "Anmeldung bei PayPal erfolgreich — Echtbetrieb."
: "Anmeldung erfolgreich — aber im TESTMODUS. Es fliesst kein echtes Geld.",
});
} catch (fehler) {
return json(res, {
ok: false,
error: "PayPal hat die Anmeldung abgelehnt. Meist stimmen Client ID und Secret "
+ "nicht zusammen, oder sie stammen aus verschiedenen Apps bzw. aus dem Testbereich.",
technisch: String(fehler.message || fehler).slice(0, 200),
}, 400);
}
}