1. 31 Aug, 2026 3 commits
  2. 30 Aug, 2026 4 commits
    • Configure trust proxy and enable Secure session cookies in production · de551724
      Trust the single nginx reverse-proxy hop (confirmed in deploy.md) so
      express-rate-limit's per-client bucketing on POST /admin/login sees the
      real client IP instead of nginx's. Also fix a dead cookieSecure check
      (NODE_ENV === 'secure' never matched) so the session cookie actually
      gets Secure in production, verified live with X-Forwarded-Proto: https.
      Co-Authored-By: 's avatarClaude Sonnet 5 <noreply@anthropic.com>
      tdgiang authored
    • Merge branch 'feature/admin-account-management' into dev · ddd32d38
      # Conflicts:
      #	app/views/admin/transactions-list.server.view.html
      #	app/views/admin/transactions-new.server.view.html
      tdgiang authored
    • Redesign admin transaction management UI · 40388425
      Applies a cohesive visual system to the admin panel: a navy/blue
      dashboard style (Inter font) for the internal staff pages, and a
      navy/gold fintech-trust style (IBM Plex Sans) for the customer-facing
      payment pages. Preserves all existing form fields, MegaPay integration
      markup, and Swig template bindings unchanged.
      tdgiang authored
    • Rate-limit POST /admin/login to bound bcrypt-induced event-loop stalls · 4bb319e9
      Async bcryptjs measured to still not yield the event loop for realistic
      hash costs (~70ms compares finish before its 100ms yield threshold), so
      a login flood could still stall the same process's live MegaPay payment
      webhooks. Caps each client (or shared-proxy-bucket, see known limitation
      below) to 5 POST /admin/login attempts per rolling 60s window via
      express-rate-limit; requests over the limit get a 429 with a Vietnamese
      error and never reach adminAuth.login, so the bcrypt compare never runs.
      
      Known limitation: this app has no app.set('trust proxy', ...) configured
      and runs behind a reverse proxy in production, so express-rate-limit's
      default req.ip-based bucketing will key off the proxy's address, not the
      real client IP. In production this enforces "5 attempts/minute in
      aggregate behind the proxy" rather than "5 per real client IP" — an
      accepted trade-off for this low-traffic internal tool, but not the same
      guarantee trust proxy + per-IP limiting would give. Configuring trust
      proxy is an infrastructure change, left out of scope here.
      tdgiang authored
  3. 29 Aug, 2026 13 commits
  4. 28 Aug, 2026 20 commits