| [1b4d5dd] | 1 | /**
|
|---|
| [834bcc3] | 2 | * Admin: Link Patreon for the premium layer (god-only).
|
|---|
| [1b4d5dd] | 3 | *
|
|---|
| [834bcc3] | 4 | * GET /admin/patreon/connect -> redirect the admin to the license server
|
|---|
| 5 | * (oauth/start) with our callback as return URL.
|
|---|
| 6 | * GET /admin/patreon/callback -> license server returns with ?klonkt_token
|
|---|
| 7 | * (or ?klonkt_error). Verify + store.
|
|---|
| 8 | * GET /admin/patreon/disconnect -> clear entitlement.
|
|---|
| [1b4d5dd] | 9 | *
|
|---|
| [834bcc3] | 10 | * The real monetisation lock is in the signed token (only the
|
|---|
| 11 | * license server can sign). See PatreonService.js.
|
|---|
| [1b4d5dd] | 12 | */
|
|---|
| 13 |
|
|---|
| 14 | import express from 'express';
|
|---|
| 15 | import { requireGod } from '../middleware/auth.js';
|
|---|
| 16 | import {
|
|---|
| 17 | licenseBase, premiumEnabled, verifyEntitlementToken, storeEntitlement, clearEntitlement,
|
|---|
| 18 | } from '../services/PatreonService.js';
|
|---|
| 19 |
|
|---|
| 20 | const router = express.Router();
|
|---|
| 21 | router.use(requireGod);
|
|---|
| 22 |
|
|---|
| 23 | function baseUrl(req) {
|
|---|
| 24 | return (process.env.PUBLIC_BASE_URL || `${req.protocol}://${req.get('host')}`).replace(/\/$/, '');
|
|---|
| 25 | }
|
|---|
| 26 |
|
|---|
| 27 | router.get('/connect', (req, res) => {
|
|---|
| 28 | if (!premiumEnabled()) return res.redirect('/admin/settings');
|
|---|
| 29 | const ret = baseUrl(req) + '/admin/patreon/callback';
|
|---|
| 30 | res.redirect(`${licenseBase()}/oauth/start?return=${encodeURIComponent(ret)}`);
|
|---|
| 31 | });
|
|---|
| 32 |
|
|---|
| 33 | router.get('/callback', async (req, res) => {
|
|---|
| 34 | if (!premiumEnabled()) return res.redirect('/admin/settings');
|
|---|
| 35 | const { klonkt_token, klonkt_error, klonkt_support_cents } = req.query;
|
|---|
| 36 | if (klonkt_error) {
|
|---|
| 37 | const cents = Number(klonkt_support_cents || 0);
|
|---|
| 38 | const msg = klonkt_error === 'not_entitled'
|
|---|
| 39 | ? `Patreon gekoppeld, maar nog geen $10 lifetime (nu $${(cents / 100).toFixed(2)}). Steun de campagne en koppel opnieuw.`
|
|---|
| 40 | : 'Patreon-koppeling mislukt.';
|
|---|
| 41 | return res.redirect('/admin/settings?error=' + encodeURIComponent(msg));
|
|---|
| 42 | }
|
|---|
| 43 | try {
|
|---|
| 44 | const payload = await verifyEntitlementToken(String(klonkt_token || ''));
|
|---|
| 45 | if (!payload.entitled) throw new Error('not entitled');
|
|---|
| 46 | storeEntitlement(payload, String(klonkt_token));
|
|---|
| 47 | res.redirect('/admin/settings?success=' + encodeURIComponent('Patreon gekoppeld — premium is actief.'));
|
|---|
| 48 | } catch (e) {
|
|---|
| 49 | console.error('[patreon/callback]', e.message);
|
|---|
| 50 | res.redirect('/admin/settings?error=' + encodeURIComponent('Patreon-token kon niet geverifieerd worden.'));
|
|---|
| 51 | }
|
|---|
| 52 | });
|
|---|
| 53 |
|
|---|
| 54 | router.get('/disconnect', (req, res) => {
|
|---|
| 55 | clearEntitlement();
|
|---|
| 56 | res.redirect('/admin/settings?success=' + encodeURIComponent('Patreon ontkoppeld.'));
|
|---|
| 57 | });
|
|---|
| 58 |
|
|---|
| 59 | export default router;
|
|---|