diff --git a/CHANGELOG.md b/CHANGELOG.md index 235662d..f00482f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Format mengikuti [Keep a Changelog](https://keepachangelog.com/) dan [Semantic Versioning](https://semver.org/). +## [0.5.8] — 2026-11-05 — "gowa-qr-error" + +### Diperbaiki +- QR GOWA: pesan gagal kini menampilkan status HTTP dan respons GOWA (mis. `HTTP 401 — Unauthorized`) sehingga penyebabnya langsung terlihat, bukan lagi "pastikan GOWA berjalan". + ## [0.5.7] — 2026-11-05 — "gowa-podman" ### Ditambahkan diff --git a/README.md b/README.md index 3362a92..f515538 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@

Lisensi: ISC - Versi 0.5.7 (gowa-podman) + Versi 0.5.8 (gowa-qr-error) Node.js >= 20 Docker Demo diff --git a/package.json b/package.json index 09d0b77..da3a9ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-isp", - "version": "0.5.7", + "version": "0.5.8", "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 4f1bb07..182e567 100644 --- a/routes/adminPortal.js +++ b/routes/adminPortal.js @@ -6650,7 +6650,10 @@ router.get('/whatsapp/gowa/qr', requireAdminSession, async (req, res) => { const dev = await gowa.ensureDevice(); if (dev && dev !== getSetting('gowa_device_id', '')) saveSettings({ gowa_device_id: dev }); const r = await gowa.getLoginQr(dev); - if (!r.ok) return res.json({ ok: false, message: 'Gagal membuat QR (' + (r.code || 'pastikan GOWA berjalan') + ').' }); + if (!r.ok) { + const detail = r.message || r.code || 'pastikan GOWA berjalan & username/password Basic Auth benar'; + return res.json({ ok: false, status: r.status || 0, message: 'Gagal membuat QR: ' + (r.status ? 'HTTP ' + r.status + ' — ' : '') + detail + '.' }); + } return res.json({ ok: true, image: '/admin/whatsapp/gowa/qr.png?v=' + Date.now(), device_id: r.device_id, duration: r.duration }); } catch (e) { return res.json({ ok: false, message: e.message }); } }); diff --git a/services/gowaWhatsappService.js b/services/gowaWhatsappService.js index 0a33a72..78a2925 100644 --- a/services/gowaWhatsappService.js +++ b/services/gowaWhatsappService.js @@ -168,12 +168,29 @@ async function ensureDevice() { async function getLoginQr(deviceId) { const dev = deviceId || deviceHeader(); const url = baseUrl() + '/app/login' + (dev ? ('?device_id=' + encodeURIComponent(dev)) : ''); - const res = await fetch(url, { headers: commonHeaders() }); - const json = await res.json().catch(function () { return null; }); - const r = (json && json.results) || {}; - const link = r.qr_link || r.image_path || null; - if (link) _lastQr = { link: link, at: Date.now() }; - return { ok: !!link, qr_link: link, duration: r.qr_duration || null, device_id: r.device_id || dev || null, code: (json && json.code) || null }; + try { + const res = await fetch(url, { headers: commonHeaders() }); + const text = await res.text(); + let json = null; + try { json = JSON.parse(text); } catch (e) {} + if (!res.ok) { + const detail = String( + (json && (json.message || json.error || json.code)) || text || '' + ).replace(/\s+/g, ' ').trim().slice(0, 160); + return { + ok: false, + status: res.status, + code: (json && json.code) || null, + message: detail || ('HTTP ' + res.status) + }; + } + const r = (json && json.results) || {}; + const link = r.qr_link || r.image_path || null; + if (link) _lastQr = { link: link, at: Date.now() }; + return { ok: !!link, qr_link: link, duration: r.qr_duration || null, device_id: r.device_id || dev || null, code: (json && json.code) || null }; + } catch (e) { + return { ok: false, status: 0, code: null, message: e.message }; + } } async function getLastQrImage() { if (!_lastQr.link) return null; diff --git a/version.txt b/version.txt index dc2b74e..b35b9dd 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.5.7 \ No newline at end of file +0.5.8 \ No newline at end of file