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

Layer Technology
Frontend React 18, React Router v6
Backend Node.js 20, Express 4
Database PostgreSQL 16
Payments Stripe
BIN Lookup binlist.net (free) / bintable.com (paid)
FX Rates frankfurter.app (free) / exchangeratesapi.io (paid)
Proxy HTTP / HTTPS / SOCKS5
Reverse Proxy Nginx
Containerization Docker + 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

# Backend
cd backend
npm install

# Frontend
cd ../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 authentication
OUTBOUND_PROXY_URL=socks5://your-proxy-server:1080

# With authentication
OUTBOUND_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 spaces
DEVICE_TOKEN_TABLET001=aB3xK9mP2qR7sT1uV4wY6z
DEVICE_TOKEN_TABLET002=cD5eF8gH0iJ2kL4mN6oP8q
DEVICE_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

Method Endpoint Description
POST /api/auth/login Login
GET /api/auth/profile Get profile
PUT /api/auth/change-password Change password

Payments

Method Endpoint Headers Description
POST /api/payments/dcc-quote Bearer DCC quote
POST /api/payments/charge Bearer + Idempotency-Key Process charge
GET /api/payments/transactions Bearer List transactions
GET /api/payments/transactions/:id Bearer Single transaction

System

Method Endpoint Description
GET /api/health Health + proxy + tunnel status
POST /api/webhooks/stripe Stripe 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