diff --git a/README.md b/README.md index d6346e5..72ea8f2 100644 --- a/README.md +++ b/README.md @@ -187,240 +187,20 @@ Amounts use atomic units: 1 WOW = 10^11 atomic units. ## Production Deployment -### Checklist +See [docs/DEPLOY.md](docs/DEPLOY.md) for detailed production deployment instructions including: +- systemd service configuration +- Nginx/reverse proxy setup with WebSocket support +- Database permissions and security hardening +- Multi-instance deployment (running Wownero and Monero on the same server) -- [ ] Set `NODE_ENV=production` -- [ ] Configure TLS via reverse proxy (Nginx/Caddy) -- [ ] Set secure database credentials -- [ ] Configure wallet-rpc with authentication -- [ ] Set `ADMIN_API_KEY` for admin endpoints -- [ ] Firewall: expose only 80/443 -- [ ] Protect `/admin.html` with basic auth -- [ ] Set up database backups -- [ ] Configure log rotation +--- -### Create Dedicated User +## Operations -Create an isolated system user for security: - -```bash -# Create system user with no login shell and dedicated home -sudo useradd --system --shell /usr/sbin/nologin --home-dir /var/www/wownerogue --create-home wownerogue - -# Create .ssh directory for deploy key -sudo mkdir -p /var/www/wownerogue/.ssh -sudo chmod 700 /var/www/wownerogue/.ssh -sudo chown wownerogue:wownerogue /var/www/wownerogue/.ssh - -# Create log directory -sudo mkdir -p /var/log/wownerogue -sudo chown wownerogue:wownerogue /var/log/wownerogue -``` - -### Setup Deploy Key and Clone Repository - -Generate an SSH deploy key for the wownerogue user: - -```bash -# Generate deploy key (as root, since user has no shell) -sudo ssh-keygen -t ed25519 -C "wownerogue-deploy" -f /var/www/wownerogue/.ssh/id_ed25519 -N "" - -# Set correct ownership and permissions -sudo chown wownerogue:wownerogue /var/www/wownerogue/.ssh/id_ed25519* -sudo chmod 600 /var/www/wownerogue/.ssh/id_ed25519 -sudo chmod 644 /var/www/wownerogue/.ssh/id_ed25519.pub - -# Display the public key -sudo cat /var/www/wownerogue/.ssh/id_ed25519.pub -``` - -Add the deploy key to GitHub: -1. Go to your repository → **Settings** → **Deploy keys** -2. Click **Add deploy key** -3. Paste the public key from the command above -4. Leave "Allow write access" unchecked (read-only is sufficient) -5. Click **Add key** - -Configure SSH for GitHub: - -```bash -# Create SSH config for the wownerogue user -sudo tee /var/www/wownerogue/.ssh/config << 'EOF' -Host github.com - HostName github.com - User git - IdentityFile ~/.ssh/id_ed25519 - IdentitiesOnly yes - StrictHostKeyChecking accept-new -EOF - -sudo chown wownerogue:wownerogue /var/www/wownerogue/.ssh/config -sudo chmod 600 /var/www/wownerogue/.ssh/config -``` - -Clone the repository: - -```bash -# Clone as the wownerogue user (replace YOUR_USERNAME with your GitHub username) -sudo -u wownerogue git clone git@github.com:YOUR_USERNAME/wownerogue.git /var/www/wownerogue/app -``` - -### Install Node.js - -Install Node.js LTS using NodeSource (run as root): - -```bash -# Install Node.js 22.x LTS (or check https://nodejs.org for current LTS) -curl -fsSL https://deb.nodesource.com/setup_22.x | bash - -apt-get install -y nodejs - -# Verify installation -node --version -npm --version -``` - -Install dependencies and audit for vulnerabilities: - -```bash -cd /var/www/wownerogue/app/src -sudo -u wownerogue npm install - -# Check for known vulnerabilities -sudo -u wownerogue npm audit - -# Auto-fix vulnerabilities where possible -sudo -u wownerogue npm audit fix -``` - -To update the deployment later: - -```bash -cd /var/www/wownerogue/app -sudo -u wownerogue git pull -cd src && sudo -u wownerogue npm install -sudo -u wownerogue npm audit fix -sudo systemctl restart wownerogue -``` - -### Set File Permissions - -```bash -# Set ownership of application files -sudo chown -R wownerogue:wownerogue /var/www/wownerogue - -# Restrict permissions (owner only, no world access) -sudo chmod 750 /var/www/wownerogue -sudo chmod 640 /var/www/wownerogue/app/src/.env -``` - -**Database permissions** - create a restricted PostgreSQL role: - -```sql --- Create role with minimal privileges -CREATE USER wownerogue WITH PASSWORD 'secure-password-here'; -CREATE DATABASE wownerogue OWNER wownerogue; - --- Revoke dangerous permissions -REVOKE CREATE ON SCHEMA public FROM wownerogue; - --- Grant only what's needed -GRANT CONNECT ON DATABASE wownerogue TO wownerogue; -GRANT USAGE ON SCHEMA public TO wownerogue; -GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO wownerogue; -GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO wownerogue; -``` - -**Filesystem isolation** (optional, for extra hardening): - -```bash -# Prevent the user from accessing other users' home directories -sudo chmod 700 /home/* - -# Mount application directory with noexec for uploads (if applicable) -# Add to /etc/fstab if using separate partition -``` - -### systemd Service - -Save to `/etc/systemd/system/wownerogue.service`: - -```ini -[Unit] -Description=Wownerogue Game Server -After=network.target postgresql.service - -[Service] -Type=simple -User=wownerogue -Group=wownerogue -# Adjust paths if you cloned to a different location -WorkingDirectory=/var/www/wownerogue/app/src -EnvironmentFile=/var/www/wownerogue/app/src/.env -ExecStart=/usr/bin/node index.js -Restart=on-failure -RestartSec=10 - -# Security hardening -NoNewPrivileges=yes -ProtectSystem=strict -ProtectHome=yes -PrivateTmp=yes -ReadWritePaths=/var/www/wownerogue /var/log/wownerogue - -[Install] -WantedBy=multi-user.target -``` - -Then enable and start: - -```bash -# Create .env from example first! -sudo -u wownerogue cp /var/www/wownerogue/app/src/.env.example /var/www/wownerogue/app/src/.env -sudo vim /var/www/wownerogue/app/src/.env # Edit with your settings - -# Enable and start service -sudo systemctl daemon-reload -sudo systemctl enable wownerogue -sudo systemctl start wownerogue -sudo systemctl status wownerogue -``` - -The systemd hardening options: -- `NoNewPrivileges` - prevents privilege escalation -- `ProtectSystem=strict` - mounts filesystem read-only except allowed paths -- `ProtectHome=yes` - hides /home, /root, /run/user -- `PrivateTmp=yes` - isolates /tmp -- `ReadWritePaths` - whitelists writable directories - -### Reverse Proxy (Nginx Proxy Manager) - -If using Nginx Proxy Manager: - -1. **Add Proxy Host** - - Domain Names: `yourdomain.com` - - Scheme: `http` - - Forward Hostname/IP: Your server's LAN IP (e.g., `192.168.1.100`) - - Forward Port: `3000` - - Enable "Websockets Support" toggle - -2. **SSL Tab** - - Request a new SSL certificate - - Enable "Force SSL" - -3. **Advanced Tab** - Paste this config for WebSocket support: - -```nginx -location /socket.io/ { - proxy_pass http://192.168.1.100:3000; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_read_timeout 86400s; - proxy_send_timeout 86400s; -} -``` +See [docs/LOGS_AND_BACKUP.md](docs/LOGS_AND_BACKUP.md) for: +- Log management with systemd/journald +- PostgreSQL automated backups +- Backup verification procedures --- diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md new file mode 100644 index 0000000..3c17797 --- /dev/null +++ b/docs/DEPLOY.md @@ -0,0 +1,402 @@ +# Production Deployment Guide + +This guide covers deploying Wownerogue to a production environment. + +--- + +## Prerequisites + +- Node.js 22.x LTS or later +- PostgreSQL 12+ +- Wownero or Monero wallet-rpc running and synced +- A domain with SSL certificate (via reverse proxy) + +--- + +## Deployment Checklist + +- [ ] Set `NODE_ENV=production` +- [ ] Configure TLS via reverse proxy (Nginx/Caddy) +- [ ] Set secure database credentials +- [ ] Configure wallet-rpc with authentication +- [ ] Set `ADMIN_API_KEY` for admin endpoints +- [ ] Firewall: expose only 80/443 +- [ ] Protect `/admin.html` with basic auth +- [ ] Set up database backups (see [LOGS_AND_BACKUP.md](./LOGS_AND_BACKUP.md)) +- [ ] Configure log rotation +- [ ] Run database migrations + +--- + +## Create Dedicated User + +Create an isolated system user for security: + +```bash +# Create system user with no login shell and dedicated home +sudo useradd --system --shell /usr/sbin/nologin --home-dir /var/www/wownerogue --create-home wownerogue + +# Create .ssh directory for deploy key +sudo mkdir -p /var/www/wownerogue/.ssh +sudo chmod 700 /var/www/wownerogue/.ssh +sudo chown wownerogue:wownerogue /var/www/wownerogue/.ssh + +# Create log directory +sudo mkdir -p /var/log/wownerogue +sudo chown wownerogue:wownerogue /var/log/wownerogue +``` + +--- + +## Setup Deploy Key and Clone Repository + +Generate an SSH deploy key for the wownerogue user: + +```bash +# Generate deploy key (as root, since user has no shell) +sudo ssh-keygen -t ed25519 -C "wownerogue-deploy" -f /var/www/wownerogue/.ssh/id_ed25519 -N "" + +# Set correct ownership and permissions +sudo chown wownerogue:wownerogue /var/www/wownerogue/.ssh/id_ed25519* +sudo chmod 600 /var/www/wownerogue/.ssh/id_ed25519 +sudo chmod 644 /var/www/wownerogue/.ssh/id_ed25519.pub + +# Display the public key +sudo cat /var/www/wownerogue/.ssh/id_ed25519.pub +``` + +Add the deploy key to GitHub: +1. Go to your repository → **Settings** → **Deploy keys** +2. Click **Add deploy key** +3. Paste the public key from the command above +4. Leave "Allow write access" unchecked (read-only is sufficient) +5. Click **Add key** + +Configure SSH for GitHub: + +```bash +# Create SSH config for the wownerogue user +sudo tee /var/www/wownerogue/.ssh/config << 'EOF' +Host github.com + HostName github.com + User git + IdentityFile ~/.ssh/id_ed25519 + IdentitiesOnly yes + StrictHostKeyChecking accept-new +EOF + +sudo chown wownerogue:wownerogue /var/www/wownerogue/.ssh/config +sudo chmod 600 /var/www/wownerogue/.ssh/config +``` + +Clone the repository: + +```bash +# Clone as the wownerogue user (replace YOUR_USERNAME with your GitHub username) +sudo -u wownerogue git clone git@github.com:YOUR_USERNAME/wownerogue.git /var/www/wownerogue/app +``` + +--- + +## Install Node.js + +Install Node.js LTS using NodeSource (run as root): + +```bash +# Install Node.js 22.x LTS (or check https://nodejs.org for current LTS) +curl -fsSL https://deb.nodesource.com/setup_22.x | bash - +apt-get install -y nodejs + +# Verify installation +node --version +npm --version +``` + +Install dependencies and audit for vulnerabilities: + +```bash +cd /var/www/wownerogue/app/src +sudo -u wownerogue npm install + +# Check for known vulnerabilities +sudo -u wownerogue npm audit + +# Auto-fix vulnerabilities where possible +sudo -u wownerogue npm audit fix +``` + +--- + +## Set File Permissions + +```bash +# Set ownership of application files +sudo chown -R wownerogue:wownerogue /var/www/wownerogue + +# Restrict permissions (owner only, no world access) +sudo chmod 750 /var/www/wownerogue +sudo chmod 640 /var/www/wownerogue/app/src/.env +``` + +**Database permissions** - create a restricted PostgreSQL role: + +```sql +-- Create role with minimal privileges +CREATE USER wownerogue WITH PASSWORD 'secure-password-here'; +CREATE DATABASE wownerogue OWNER wownerogue; + +-- Revoke dangerous permissions +REVOKE CREATE ON SCHEMA public FROM wownerogue; + +-- Grant only what's needed +GRANT CONNECT ON DATABASE wownerogue TO wownerogue; +GRANT USAGE ON SCHEMA public TO wownerogue; +GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO wownerogue; +GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO wownerogue; +``` + +**Filesystem isolation** (optional, for extra hardening): + +```bash +# Prevent the user from accessing other users' home directories +sudo chmod 700 /home/* + +# Mount application directory with noexec for uploads (if applicable) +# Add to /etc/fstab if using separate partition +``` + +--- + +## Database Setup + +### Run Migrations + +Database migrations run automatically on server start (via `databaseManager.runMigrations()`), but you can also run them manually: + +```bash +cd /var/www/wownerogue/app/src + +# Source environment variables +source .env + +# Run migrations manually if needed +psql -h $DB_HOST -U $DB_USER -d $DB_NAME -f migrations/001_initial_schema.sql +# ... repeat for each migration file in order +``` + +### Database Reset (Development Only) + +```bash +npm run db:drop # Drop all tables +npm run db:create # Recreate schema +``` + +--- + +## systemd Service + +Save to `/etc/systemd/system/wownerogue.service`: + +```ini +[Unit] +Description=Wownerogue Game Server +After=network.target postgresql.service + +[Service] +Type=simple +User=wownerogue +Group=wownerogue +# Adjust paths if you cloned to a different location +WorkingDirectory=/var/www/wownerogue/app/src +EnvironmentFile=/var/www/wownerogue/app/src/.env +ExecStart=/usr/bin/node index.js +Restart=on-failure +RestartSec=10 + +# Security hardening +NoNewPrivileges=yes +ProtectSystem=strict +ProtectHome=yes +PrivateTmp=yes +ReadWritePaths=/var/www/wownerogue /var/log/wownerogue + +[Install] +WantedBy=multi-user.target +``` + +Enable and start: + +```bash +# Create .env from example first! +sudo -u wownerogue cp /var/www/wownerogue/app/src/.env.example /var/www/wownerogue/app/src/.env +sudo vim /var/www/wownerogue/app/src/.env # Edit with your settings + +# Enable and start service +sudo systemctl daemon-reload +sudo systemctl enable wownerogue +sudo systemctl start wownerogue +sudo systemctl status wownerogue +``` + +The systemd hardening options: +- `NoNewPrivileges` - prevents privilege escalation +- `ProtectSystem=strict` - mounts filesystem read-only except allowed paths +- `ProtectHome=yes` - hides /home, /root, /run/user +- `PrivateTmp=yes` - isolates /tmp +- `ReadWritePaths` - whitelists writable directories + +--- + +## Reverse Proxy (Nginx Proxy Manager) + +If using Nginx Proxy Manager: + +1. **Add Proxy Host** + - Domain Names: `yourdomain.com` + - Scheme: `http` + - Forward Hostname/IP: Your server's LAN IP (e.g., `192.168.1.100`) + - Forward Port: `3000` + - Enable "Websockets Support" toggle + +2. **SSL Tab** + - Request a new SSL certificate + - Enable "Force SSL" + +3. **Advanced Tab** - Paste this config for WebSocket support: + +```nginx +location /socket.io/ { + proxy_pass http://192.168.1.100:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_read_timeout 86400s; + proxy_send_timeout 86400s; +} +``` + +--- + +## Updating the Deployment + +```bash +cd /var/www/wownerogue/app +sudo -u wownerogue git pull +cd src && sudo -u wownerogue npm install +sudo -u wownerogue npm audit fix +sudo systemctl restart wownerogue +``` + +--- + +## Multi-Instance Deployment + +To run multiple instances (e.g., Wownero on port 3000 and Monero stagenet on port 3001): + +### Directory Structure + +``` +/var/www/ +├── wownerogue/ # Wownero instance (port 3000) +│ └── app/src/.env +└── monerogue/ # Monero instance (port 3001) + └── app/src/.env +``` + +### Configuration Differences + +| Setting | Wownero Instance | Monero Instance | +|---------|------------------|-----------------| +| `PORT` | 3000 | 3001 | +| `CRYPTO_TYPE` | WOW | XMR | +| `MONERO_NETWORK` | mainnet | stagenet | +| `DB_NAME` | wownerogue | monerogue_stagenet | +| `PRIMARY_WALLET_ENDPOINT` | http://127.0.0.1:34570 | http://127.0.0.1:38070 | +| `PRIMARY_RPC_ENDPOINT` | http://127.0.0.1:34568 | http://127.0.0.1:38081 | + +### Separate systemd Service + +Create `/etc/systemd/system/monerogue.service`: + +```ini +[Unit] +Description=Monerogue Game Server (Stagenet) +After=network.target postgresql.service + +[Service] +Type=simple +User=monerogue +WorkingDirectory=/var/www/monerogue/app/src +EnvironmentFile=/var/www/monerogue/app/src/.env +ExecStart=/usr/bin/node index.js +Restart=on-failure +RestartSec=10 + +[Install] +WantedBy=multi-user.target +``` + +--- + +## Monitoring + +### Check Service Status + +```bash +systemctl status wownerogue +journalctl -u wownerogue -f # Follow logs +``` + +### Health Endpoint + +```bash +curl http://localhost:3000/health +``` + +Returns server uptime, memory usage, wallet status, and balance. + +### Admin Dashboard + +Access `/admin.html` with your `ADMIN_API_KEY` for: +- Wallet balance and connection status +- Pending/failed payouts +- Game statistics +- User search + +--- + +## Troubleshooting + +### Server Won't Start + +```bash +# Check logs for errors +journalctl -u wownerogue -n 50 + +# Verify environment file +sudo -u wownerogue cat /var/www/wownerogue/app/src/.env + +# Test database connection +psql -h localhost -U wownerogue -d wownerogue -c "SELECT 1;" +``` + +### Wallet RPC Issues + +```bash +# Test wallet RPC directly +curl -u user:password -X POST http://127.0.0.1:34570/json_rpc \ + -d '{"jsonrpc":"2.0","id":"0","method":"get_balance"}' \ + -H 'Content-Type: application/json' +``` + +### Database Migrations + +If migrations fail, check the `migrations` table: + +```sql +SELECT * FROM migrations ORDER BY id; +``` + +Migrations are tracked by name to prevent duplicate execution. diff --git a/LOGS_AND_BACKUP.md b/docs/LOGS_AND_BACKUP.md similarity index 100% rename from LOGS_AND_BACKUP.md rename to docs/LOGS_AND_BACKUP.md diff --git a/TODO.md b/docs/TODO.md similarity index 71% rename from TODO.md rename to docs/TODO.md index 677b6c6..c6bee6e 100644 --- a/TODO.md +++ b/docs/TODO.md @@ -66,13 +66,59 @@ - [x] **Rate Limit Tuning**: Current defaults (60 games/hour, 100 payouts/day) suitable for launch ✅ - [x] **Log Rotation**: Using systemd journald with configurable retention (see `LOGS_AND_BACKUP.md`) ✅ +## Security Audit Fixes (Jan 2026) +- [x] **XSS Vulnerability**: Complete HTML entity escaping in chat handler (`&`, `<`, `>`, `"`, `'`) +- [x] **tx_hash Idempotency**: UNIQUE partial indexes on payments/payouts tables (migration 008) +- [x] **Timing-Safe Auth**: Admin API uses `crypto.timingSafeEqual()` for key comparison +- [x] **Transactional Payouts**: Payout flow creates pending record first, updates atomically +- [x] **Payout Retry Service**: Auto-retries failed payouts (max 3 attempts, 5-min interval) +- [x] **Address Validation**: `validateAddress()` called before every payout attempt +- [x] **Transaction Status Check**: `checkTransactionStatus()` verifies blockchain before retry + +## Smirk Wallet Integration (Jan 2026) +- [x] **Database Schema**: `smirk_public_key` column, `smirk_challenges` table (migration 009) +- [x] **Auth Endpoints**: `/api/auth/smirk/challenge`, `/verify`, `/status` +- [x] **Frontend Module**: `smirkAuth.js` with extension detection and login flow +- [x] **Address Modal**: Shows Smirk connect button or install link + +## Admin Dashboard (Jan 2026) +- [x] **Alert Service**: Email alerts via Resend for low balance, disconnects, failed payouts +- [x] **Stats Endpoints**: `/api/admin/stats/overview`, `/payouts`, `/games`, `/users` +- [x] **Admin UI**: Full dashboard at `/admin.html` with charts and tables +- [x] **Payout Retry**: Manual retry button in admin dashboard + +## Pre-Production Testing Checklist + +### Security Verification +- [ ] Chat XSS: `
-