Skip to content

Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

⚡ VirtualPOS — Production-Ready Virtual Point of Sale

A secure, full-stack Virtual POS system built with React, Node.js/Express, and PostgreSQL, featuring Dynamic Currency Conversion (DCC), Idempotency protection, Stripe integration, Webhook support, and enterprise-grade network architecture including SOCKS5 tunneling, transparent proxy, and mobile VPOS reverse proxy authentication.


🏗 Tech Stack

LayerTechnology
FrontendReact 18, React Router v6
BackendNode.js 20, Express 4
DatabasePostgreSQL 16
PaymentsStripe
BIN Lookupbinlist.net (free) / bintable.com (paid)
FX Ratesfrankfurter.app (free) / exchangeratesapi.io (paid)
ProxyHTTP / HTTPS / SOCKS5
Reverse ProxyNginx
ContainerizationDocker + Docker Compose

🚀 Quick Start (Development)

1. Prerequisites

  • Node.js 20+
  • PostgreSQL 16+
  • npm

2. Clone and Configure

cd vpos
# Backend
cp backend/.env.example backend/.env
# Edit backend/.env with your values# Frontend
cp frontend/.env.example frontend/.env

3. Install Dependencies

# Backendcd backend
npm install
# Frontendcd ../frontend
npm install

4. Database Setup

cd backend
# Run migrations (creates all tables)
npm run migrate
# Seed default admin user
npm run seed
# Or do both at once
npm run setup

5. Start Backend

cd backend
npm run dev
# Runs on http://localhost:5000

6. Start Frontend

cd frontend
npm start
# Runs on http://localhost:3000

7. Verify Everything Works

# Check backend health (includes proxy and tunnel status)
curl http://localhost:5000/api/health

🌐 Network Architecture

Overview

The VPOS supports four enterprise network modes that can be combined:

┌─────────────────────────────────────────────────────┐
│ VPOS Terminals │
│ (Desktops / Tablets / Mobile) │
└──────────────────────┬──────────────────────────────┘
│
┌──────────▼──────────┐
│ VPOS Backend │
│ (Node.js/Express) │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Proxy Layer │
│ HTTP/HTTPS/SOCKS5 │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Payment Gateway │
│ (Stripe API) │
└─────────────────────┘

Mode 1: Standard HTTP/HTTPS Proxy (Gateway Bridge)

Used when VPOS is on an air-gapped network with no direct internet access. The proxy acts as the bridge between the internal network and Stripe.

Setup in backend/.env:

OUTBOUND_PROXY_URL=http://your-proxy-server:8080# Or with authentication:OUTBOUND_PROXY_URL=http://username:password@your-proxy-server:8080

What it does:

  • All Stripe API calls route through your proxy
  • Your proxy's static IP is what Stripe sees (use for IP whitelisting)
  • Full packet inspection by your security stack
  • Centralized logging of all payment traffic

Mode 2: SOCKS5 Proxy (Protocol-Agnostic VPN-Like Tunnel)

Best for organizations needing a VPN-like tunnel without a full VPN. SOCKS5 handles any protocol (TCP/UDP) on any port — not just HTTP.

Setup in backend/.env:

# Without authenticationOUTBOUND_PROXY_URL=socks5://your-proxy-server:1080# With authenticationOUTBOUND_PROXY_URL=socks5://username:password@your-proxy-server:1080

What it does:

  • All payment traffic tunneled through SOCKS5
  • Protocol agnostic — works with any payment processor
  • All terminals appear as one static IP to Stripe
  • Identity masking for multi-terminal deployments

Setting up a SOCKS5 server (Linux):

# Install Dante SOCKS5 server
apt-get install dante-server
# Edit /etc/danted.conf
logoutput: /var/log/danted.log
internal: eth0 port = 1080
external: eth0
method: username none
user.privileged: root
user.unprivileged: nobody
# Start service
systemctl start danted
systemctl enable danted

Mode 3: Transparent Proxy

The most VPN-like setup. VPOS terminals require zero configuration. Your router intercepts all traffic on port 443 and redirects to the proxy.

Setup in backend/.env:

TRANSPARENT_PROXY_MODE=true

Router configuration (iptables on Linux gateway):

# Redirect all HTTPS traffic to proxy (port 3128)
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 3128
# Save rules
iptables-save > /etc/iptables/rules.v4

Squid proxy config (/etc/squid/squid.conf): http_port 3128 intercept https_port 3129 intercept ssl-bump cert=/etc/squid/ssl_cert/myCA.pem ssl_bump server-first all acl payment_gateways dstdomain .stripe.com http_access allow payment_gateways http_access deny all

What it does:

  • Zero config on VPOS terminals
  • Router handles all interception
  • Employees cannot bypass or tamper with settings
  • All traffic logged at network level

Mode 4: Mobile VPOS Reverse Proxy (Tablet/Handheld Units)

For mobile units like delivery agents or field sales reps. Each device must authenticate with a unique token before processing payments.

Step 1 — Enable mobile mode in backend/.env:

MOBILE_VPOS_MODE=true

Step 2 — Register each device in backend/.env:

# Format: DEVICE_TOKEN_<DEVICEID>=<secret-token># Device IDs must be uppercase, no spacesDEVICE_TOKEN_TABLET001=aB3xK9mP2qR7sT1uV4wY6zDEVICE_TOKEN_TABLET002=cD5eF8gH0iJ2kL4mN6oP8qDEVICE_TOKEN_MOBILE001=rS1tU3vW5xY7zA9bC2dE4f

Step 3 — Configure each mobile device to send these headers with every request: X-Device-Id: TABLET001 X-Device-Token: aB3xK9mP2qR7sT1uV4wY6z

Step 4 — Revoke a stolen device instantly:

If a tablet is stolen, remove its token from .env and restart the backend. That device can no longer process any payments immediately.

Generating secure device tokens:

# Linux/Mac
openssl rand -hex 32
# PowerShell (Windows)
[System.Web.Security.Membership]::GeneratePassword(32, 8)
# Or simpler:
-join ((65..90) + (97..122) + (48..57) | Get-Random -Count 32|% {[char]$_})

Domain Whitelisting (PCI-DSS Compliance)

Only approved domains can receive outbound connections. All other connections are blocked and logged.

Setup in backend/.env:

ALLOWED_OUTBOUND_DOMAINS=api.stripe.com,lookup.binlist.net,api.frankfurter.app,api.exchangeratesapi.io,api.bintable.com

IP Whitelisting on Stripe

Once your proxy is set up with a static IP:

  1. Go to dashboard.stripe.com
  2. Settings → Security → Allowed IP addresses
  3. Add your proxy server's public IP
  4. All terminals now share one trusted identity

✨ Core Features

🔐 Secure Card Entry

  • Manual entry: Card number, Expiry, CVV
  • Real-time Luhn algorithm validation
  • Card brand detection (Visa, Mastercard, Amex, Discover, JCB)
  • Animated card preview
  • CVV masking with correct length per brand

💱 Dynamic Currency Conversion (DCC)

  • BIN lookup detects card issuing country
  • Offers conversion to customer's home currency
  • Live exchange rates (1-hour DB cache)
  • 2.5% DCC markup (industry standard)
  • Full audit trail per transaction

🔑 Idempotency Keys

  • Auto-generated per charge session
  • Duplicate clicks never double-charge
  • 24-hour TTL with automatic cleanup

📡 Stripe Webhooks

  • Signature verification on every event
  • Handles: succeeded, failed, refunded, disputed
  • Duplicate event protection
  • Full event log in database

🗄 Database (PostgreSQL)

  • users — merchant accounts
  • transactions — full charge history
  • idempotency_keys — deduplication
  • exchange_rate_cache — FX cache
  • audit_log — all actions with IP
  • webhook_events — delivery log

🗺 API Reference

Auth

MethodEndpointDescription
POST/api/auth/loginLogin
GET/api/auth/profileGet profile
PUT/api/auth/change-passwordChange password

Payments

MethodEndpointHeadersDescription
POST/api/payments/dcc-quoteBearerDCC quote
POST/api/payments/chargeBearer + Idempotency-KeyProcess charge
GET/api/payments/transactionsBearerList transactions
GET/api/payments/transactions/:idBearerSingle transaction

System

MethodEndpointDescription
GET/api/healthHealth + proxy + tunnel status
POST/api/webhooks/stripeStripe events

📁 Project Structure

vpos/
├── backend/
│ ├── src/
│ │ ├── controllers/
│ │ │ ├── authController.js
│ │ │ └── paymentController.js
│ │ ├── middleware/
│ │ │ ├── auth.js
│ │ │ ├── domainWhitelist.js
│ │ │ ├── idempotency.js
│ │ │ └── sanitize.js
│ │ ├── migrations/
│ │ │ ├── run.js
│ │ │ └── seed.js
│ │ ├── models/
│ │ │ └── db.js
│ │ ├── routes/
│ │ │ ├── auth.js
│ │ │ └── payment.js
│ │ ├── services/
│ │ │ ├── currencyService.js
│ │ │ ├── proxyConfig.js
│ │ │ └── tunnelService.js
│ │ ├── utils/
│ │ │ └── logger.js
│ │ ├── webhooks/
│ │ │ └── stripeWebhook.js
│ │ └── index.js
│ ├── Dockerfile
│ ├── package.json
│ └── .env.example
│
├── frontend/
│ ├── public/
│ │ └── index.html
│ ├── src/
│ │ ├── components/
│ │ │ └── Layout.js
│ │ ├── pages/
│ │ │ ├── Charge.js
│ │ │ ├── Transactions.js
│ │ │ └── Settings.js
│ │ ├── styles/
│ │ │ └── global.css
│ │ ├── utils/
│ │ │ ├── api.js
│ │ │ └── cardUtils.js
│ │ ├── App.js
│ │ └── index.js
│ ├── Dockerfile
│ ├── package.json
│ └── .env.example
│
├── nginx/
│ └── nginx.conf
├── docker-compose.yml
├── .env.example
└── README.md

⚠️ Production Checklist

  • Set strong JWT_SECRET (openssl rand -hex 64)
  • Set strong DB_PASSWORD
  • Add real Stripe live secret key
  • Configure Stripe webhook endpoint and secret
  • Add SSL certificate to nginx/ssl/
  • Update ALLOWED_ORIGINS with your domain
  • Configure outbound proxy (OUTBOUND_PROXY_URL)
  • Add proxy static IP to Stripe IP whitelist
  • Set ALLOWED_OUTBOUND_DOMAINS for PCI-DSS
  • Register all mobile devices with unique tokens
  • Enable TRANSPARENT_PROXY_MODE if using router interception
  • Set up PostgreSQL backups
  • Configure log rotation for backend/logs/
  • Set NODE_ENV=production

📜 License

Proprietary — for internal organisational use only.

About

A secure, full-stack Virtual POS system built with React, Node.js/Express, and PostgreSQL, featuring Dynamic Currency Conversion (DCC), Idempotency protection, Stripe integration, Webhook support, and enterprise-grade network architecture including SOCKS5 tunneling, transparent proxy, and mobile VPOS reverse proxy authentication.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages