research/gopay-merchant-qris-gateway/repos.md

10 KiB
Raw Blame History

title description status category tags draft created updated
Repo audits & comparison Audit cards for gopay-api-gateaway, gobiz-payment, and QrisMerchantID at pinned commits — what each actually executes, key implementation facts, strengths, and the surrounding ecosystem map. concluded technical
gopay
gobiz
repos
source-audit
comparison
true 2026-10-15 2026-10-15

Repo audits & comparison

Part of gopay-merchant-qris-gateway/index

All three repos read at pinned commits (2026-10-15); star counts captured via GitHub API the same day. Entry-point claims were checked against source, not READMEs alone.

1. ahmadzakiyox/gopay-api-gateaway — the turnkey service

Pinned: c753b8c23daf5ced58febe650bcd229b6b2b7dec (2026-07-26) · Node.js · MIT · 233 ★ / 84 forks · created 2026-07-21 · deploy guides for VPS/cPanel/Pterodactyl/Docker [S3][S5]

What it is: a self-hosted Express API that exposes a merchant's GoPay account as a mini payment gateway: create a dynamic QRIS for an amount, host a checkout page, verify whether that exact payment arrived, read transaction history. [S3]

Audit findings (from source):

  • [verified] Entry server.js is fully readable (736 lines) and contains the real logic: EMVCo TLV parser + CRC16 (calculateCRC16 L72–L85), generateDynamicQRIS() L88–L147 (also flips tag 01 11→12), REST endpoints L176–L732, hosted HTML checkout with 5-min countdown + manual check + optional 8-s auto-poll L255–L481, claim-scoped verifyPayment() L566–L653, in-RAM claim map with 24-h expiry L16–L53.
  • [verified] login.js (425 KB) and sessionManager.js (464 KB) are obfuscated (javascript-obfuscator-style hex string arrays; the javascript-obfuscator package is a devDependency; no readable endpoint strings leak). The OTP login and token refresh — the credential-handling code — cannot be source-audited. The 6-hourly refresh scheduling is visible in server.js L56–L69; the refresh mechanics are not.
  • [verified] Amount-unit question: verifyPayment() compares raw gross_amount against a rupiah input with no /100 normalisation — inconsistent with the other two repos' handling of the same feed (see gopay-merchant-qris-gateway/analysis §4). Unresolved.
  • [verified] QR rendering is outsourced: checkout page builds QR images via https://api.qrserver.com (L267, L272) — the merchant's QR payload (merchant ID + amount) is sent to a third-party image service. Avoidable.
  • [verified] Claim state is in-process RAM (Map) — restarts lose claims; no multi-instance story.
  • [verified] README claims beyond code: "auto-refresh token every 6 hours" [reported — schedule visible, mechanics obfuscated]; "session 100 % safe on your server" [reported — true by design only if the obfuscated code is honest].
  • [verified] Anti-poll design at the UI level: the checkout page defaults to a manual button; auto-polling is opt-in at 8 s, an explicit nod to ban-avoidance.

Take: the clearest end-to-end reference for the service shape (REST contract, claim scoping, checkout UX). Don't take: obfuscated credential handling, the RAM claim store, or the third-party QR renderer. The obfuscation makes this a poor base for anything security-sensitive despite being the most popular.

2. kavionn/gobiz-payment — the readable library

Pinned: 0bac129fefa09a3b723b68dd8f09e4b0e3899527 (2026-09-07) · Node.js ≥18 · MIT · 73 ★ / 29 forks · created 2026-06-15 [S2][S5]

What it is: an ES-module library — GoPayMerchant (login, merchant-ID discovery, history) + GoPayWatcher (EventEmitter polling watcher, singleton). The code reference the rest of the ecosystem (including QrisMerchantID) builds on. [S2]

Audit findings (from source, 886 lines, fully readable):

  • [verified] Auth: OTP (added Sep 2026 via PR #6) and email+password; both replayed against /goid/*. Quirk: login calls are executed via execFileSync('curl', ['-4', …]) instead of fetch — IPv4 forced, external binary dependency; rationale never explained in-code [unverified why — likely TLS/IPv6 quirks, unconfirmed].
  • [verified] Token model is minimal: access token only, cached in .gopay_cache.json; validity probed via merchants/search; on 401 it redoes a full login (no refresh-token exchange). Contrast with QMID's single-refresh flow.
  • [verified] History: analytics primary (L469–L518), journals fallback (L520–L629, with the lifted ES query DSL and special journal headers); amounts ÷100 for display.
  • [verified] Watcher (L632–L748): seed-then-diff, seen-set cap 500, waitForPayment(amount, {timeout, tolerance}), singleton via getGoPayWatcher() so the whole process shares one poller; poll interval default 6 s.
  • [verified] Merchant-ID auto-discovery from merchants/search hits (first hit), cached.
  • [reported] Community known-issues: issue #4 (empty history — maintainer: still works), #7 (OTP not arriving — open). Both consistent with drift/account-state, not code death.

Take: the cleanest implementation reference for the pattern; good naming, JSDoc, honest constraints. Don't take: no refresh-token path (full re-login on 401 = avoidable OTP traffic), curl subprocess for auth.

3. AlfinAI/QrisMerchantID — the research SDK & knowledge base

Pinned: ac1f2ba3c1d82910bc8a81e9f0b98d10c0ead36b (2026-10-10) · Python ≥3.10 (one dep: httpx) · MIT (LICENSE file; GitHub classifier says "NOASSERTION") · 12 ★ / 2 forks · created 2026-09-10 [S1][S5]

What it is: a typed Python SDK for the same merchant APIs plus the best public documentation of the reverse-engineering process itself: APK analyses of both merchant apps, HAR-verification reports, a reproduction guide, endpoint/host inventories, conflict register, responsible-disclosure doc. Also ships a ShopeePay provider (out of scope here). [S1]

Audit findings:

  • [verified] Structure: src/qrismerchantid/{core,gopay,shopee} — gopay = auth, client, constants, merchants, money, payouts, qris, transactions, users, watcher; core = transport, token_cache, exceptions. Facade GoPayMerchant with per-service namespaces.
  • [verified] Capture-grade fidelity: constant defaults mirror the portal exactly (headers, platform-v3.125.0-e1923971, status/payment-type lists, journal headers); auth shapes annotated to specific capture sections (§9.1/§9.4/§9.5); phone normalisation to bare national; login_type omitted to match browser.
  • [verified] Money handling: raw minor units + to_rupiah(); watcher matches on minor units; docs call out the two providers' unit mismatch explicitly.
  • [verified] QRIS helper is pure/offline and conservative — injects tag 54, recomputes CRC16, deliberately leaves tag 01 alone, and warns a valid CRC ≠ guaranteed acceptance. [S10 docs/gopay/qris.md]
  • [verified] Robustness engineering: typed ApiException (http_status/code/payload), transport-only retries with backoff, single refresh attempt then fail-fast, 500-entry seen cache, offline test suite + ruff + mypy strict gates (as documented).
  • [verified] Process discipline visible in-repo: version-drift fixes documented as reports (OTP regression, email flow verification), TODO register with priorities/owners, conflict register, masking rules, disclosure doc, full credits to prior repos. Honest throughout about what is NOT verified (live login from SDK, request signing, app flows).
  • [reported] "100 % offline test suite" / "190 passed" — stated in reports; we didn't run it (out of audit scope).

Take: the model for how to document this class of work (and a genuinely usable Python client). Don't take: nothing critical — main caveats are the young project age and that live-verification TODOs remain open.

4. Side by side

gopay-api-gateaway gobiz-payment QrisMerchantID
Shape Express service (REST + checkout page) Library (embed in bot/backend) SDK + research KB (+ ShopeePay)
Language Node.js Node.js ≥18 Python ≥3.10
Auth OTP (CLI); obfuscated internals OTP + email/password (readable) OTP + email/password (readable, capture-verified)
Token model 6-h refresh cycle + 401 refresh [reported/partly verified] re-login on 401 (no refresh) single refresh attempt, then re-login
Payment feed analytics (no journal fallback) analytics → journal fallback analytics + journals + aggregations + payouts
QRIS approach tag 54 + tag 01 flip + CRC16 (QRIS gen via demo/portal string) tag 54 + CRC16, tag 01 untouched
Dedupe/claims trx_id claim map (RAM, 24 h) seen-set (500) seen-set (500) + docs recommend Rp1–99 amount codes
Amount units raw (discrepancy — see §1) ÷100 raw minor + to_rupiah()
Readability partial (auth obfuscated) full full
Tests none visible none visible offline suite + lint/type gates [reported]
Docs deploy-heavy README README + mermaid flows full docs/ tree + research/ + reference/ CSVs
License MIT MIT MIT

5. Ecosystem map (context — not audited here)

The QMID research doc maps the wider field [S6 §1]; treat those entries as [reported], not verified by this audit: warungerik/API-GOPAY-MERCHANT (Vue/Nuxt, "user-tested", HMAC webhook), namtxs/gopay-api (PHP, customer-side wallet flow — different scope), alhifnywahid/merchantid (TS, ShopeePay full programmatic login + GoPay provider), IbraDecode/gopaymerchant, ardianryan/qbiz-qrisdinamis, xirf/gobiz-merchant-sdk, azmi2409/gopay-merchant-qris-gateway, plus ahmadzakiyox/shoppepay-api-gateway (same author; server fully obfuscated). The pattern reproduced across ≥8 independent repos within ~4 months — the clearest signal this is a real market need, not one person's project. [S6]

6. One cross-cutting observation

[inference] The three repos agree on mechanics (auth replay, TLV+CRC16, seed-poll-match) but each differs in an important engineering choice (refresh handling, unit conversion, tag-01 handling, claim store). None of them is a canonical reference for all of it — the audit found at least one substantive inconsistency per repo (gateway: units + RAM claims; kavionn: no refresh path; QMID: young project, live-login TODOs open). Anyone touching this space should treat all three as complementary evidence, and the capture reports [S6][S7] as the closest thing to ground truth.