diff --git a/CHANGELOG.md b/CHANGELOG.md index 10fcc0b..f437804 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ Format mengikuti [Keep a Changelog](https://keepachangelog.com/) dan [Semantic Versioning](https://semver.org/). +## [0.6.3] — 2026-11-06 — "webhook-secret-auto" + +### Diperbaiki +- **Secret Token webhook pembayaran** dibuat otomatis (64 hex) bila kosong/default, ditampilkan di Pengaturan dan langsung dipakai pada URL webhook. +- URL webhook memakai **Public Base URL**; bila kosong memakai host saat ini (tidak lagi menghasilkan URL relatif). +- Default lama `billing-rtrw-secret-key` tidak lagi diterima — forwarder harus memakai secret dari Pengaturan. + ## [0.6.2] — 2026-11-06 — "webhook-diag" ### Diperbaiki diff --git a/README.md b/README.md index a912430..a403e07 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@
-
+
diff --git a/app-customer.js b/app-customer.js
index 706d0a9..c0cccac 100644
--- a/app-customer.js
+++ b/app-customer.js
@@ -61,6 +61,7 @@ const { SUPPORTED_LANGS, FALLBACK_LANG, normalizeLang, t } = require('./config/i
if (typeof ensureDefaultSettings === 'function') {
ensureDefaultSettings();
try { require('./config/settingsManager').ensureGowaWebhookSecret(); } catch (e) {}
+ try { require('./config/settingsManager').ensureWebhookSecret(); } catch (e) {}
// Proses baru = kode terbaru sudah dimuat; hapus penanda restart.
try { fs.rmSync(path.join(__dirname, '.restart-required'), { force: true }); } catch (e) {}
}
@@ -901,7 +902,7 @@ app.post('/api/webhook/v1/payment-notif', multer().any(), async (req, res) => {
gotTrim = gotTrim.replace(/^[\"'\s]+|[\"'\s]+$/g, '');
if (/^bearer\s+/i.test(gotTrim)) gotTrim = gotTrim.replace(/^bearer\s+/i, '').trim();
- const isSecretValid = (gotTrim === expectedTrim) || (gotTrim === 'billing-rtrw-secret-key');
+ const isSecretValid = gotTrim === expectedTrim;
if (!isSecretValid) {
logger.warn(`[WEBHOOK][payment-notif] Forbidden: secret_key mismatch. service=${String(service || '-')} (gotLen=${gotTrim.length}${gotTrim ? ', ***' + gotTrim.slice(-3) : ', empty'}, expectedLen=${expectedTrim.length}, ***${expectedTrim.slice(-3)})`);
diff --git a/config/settingsManager.js b/config/settingsManager.js
index 6fbab28..17c15e6 100644
--- a/config/settingsManager.js
+++ b/config/settingsManager.js
@@ -282,6 +282,14 @@ function formatTimeLocal(date) {
* Pastikan gowa_webhook_secret tidak memakai default 'secret'.
* Dibuat otomatis (32 byte hex) bila kosong/default/terlalu pendek.
*/
+function ensureWebhookSecret(force) {
+ const current = String(getSetting('webhook_secret', '') || '').trim();
+ if (!force && current && current !== 'billing-rtrw-secret-key' && current.length >= 24) return current;
+ const secret = crypto.randomBytes(32).toString('hex');
+ saveSettings({ webhook_secret: secret });
+ return secret;
+}
+
function ensureGowaWebhookSecret(force) {
const current = String(getSetting('gowa_webhook_secret', '') || '').trim();
if (!force && current && current !== 'secret' && current.length >= 24) return current;
@@ -374,5 +382,6 @@ module.exports = {
parseDateInTimezone,
startSettingsWatcher,
ensureDefaultSettings,
- ensureGowaWebhookSecret
+ ensureGowaWebhookSecret,
+ ensureWebhookSecret
};
diff --git a/package.json b/package.json
index b883d37..ba583fe 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "open-isp",
- "version": "0.6.2",
+ "version": "0.6.3",
"description": "OPEN-ISP \u2014 sistem billing & manajemen ISP open-source (PWA pelanggan, multi-OLT, RADIUS, WhatsApp, QRIS)",
"main": "app-customer.js",
"scripts": {
diff --git a/routes/adminPortal.js b/routes/adminPortal.js
index e382112..0c66da0 100644
--- a/routes/adminPortal.js
+++ b/routes/adminPortal.js
@@ -4490,15 +4490,17 @@ router.post('/automation/send-now', requireAdminSession, express.urlencoded({ ex
});
router.get('/settings', requireAdminSession, requireSidebarMenuAccess('settings'), (req, res) => {
- const settings = getSettings();
+ let settings = getSettings();
+ try { require('../config/settingsManager').ensureWebhookSecret(); settings = getSettings(); } catch (e) {}
const protocol = req.headers['x-forwarded-proto'] || req.protocol;
const host = req.get('host');
- const baseUrl = (settings && settings.app_url ? String(settings.app_url) : `${protocol}://${host}`).replace(/\/+$/, '');
+ const baseUrl = (settings.public_base_url || (settings && settings.app_url) || `${protocol}://${host}`).toString().replace(/\/+$/, '');
const paymentWebhookUrl = `${baseUrl}/customer/payment/callback`;
res.render('admin/settings', {
title: 'Pengaturan Sistem', company: company(), activePage: 'settings',
settings, msg: flashMsg(req),
- paymentWebhookUrl
+ paymentWebhookUrl,
+ webhookBaseUrl: baseUrl
});
});
diff --git a/version.txt b/version.txt
index b1d7abc..a0a1517 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-0.6.2
\ No newline at end of file
+0.6.3
\ No newline at end of file
diff --git a/views/admin/settings.ejs b/views/admin/settings.ejs
index ab563e5..88fee71 100644
--- a/views/admin/settings.ejs
+++ b/views/admin/settings.ejs
@@ -815,7 +815,7 @@