mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-24 17:48:34 +02:00
462 lines
13 KiB
Markdown
462 lines
13 KiB
Markdown
# Wownerogue
|
||
|
||
A browser-based roguelike synchronized with Monero (XMR) and Wownero (WOW) block timing. Built with Node.js/Express and Socket.IO for real-time play, optional crypto payments, and automated payouts.
|
||
|
||
## Features
|
||
|
||
- **Provably fair** gaming with pre-game hash commitments
|
||
- **Live spectator mode** - watch active games in real-time
|
||
- **Persistent chat** with 30-day history
|
||
- **Transaction history** - view payment and payout records
|
||
- **Multiple game modes**: Free play, per-game payments, or credit bundles
|
||
- Configurable difficulty with house edge tuning
|
||
- Automatic wallet RPC integration for payments and payouts
|
||
|
||
## Quick Start
|
||
|
||
```bash
|
||
git clone <repository-url>
|
||
cd wownerogue/src
|
||
npm install
|
||
cp .env.example .env # Edit with your database/wallet settings
|
||
npm run db:create # Initialize PostgreSQL
|
||
npm run dev # Start development server
|
||
```
|
||
|
||
Open http://localhost:3000 to play.
|
||
|
||
---
|
||
|
||
## Game Modes
|
||
|
||
| Mode | Cost | Payout | Description |
|
||
|------|------|--------|-------------|
|
||
| **FREE** | None | None | No payments required |
|
||
| **PAID_SINGLE** | 1 WOW/game | 2× escape, 3× with treasure | Per-run payment |
|
||
| **PAID_CREDITS** | 10 credits/5 WOW | Optional | Buy credit bundles |
|
||
|
||
When both modes are enabled (`ALLOW_MIXED_MODE=true`), players with credits can start games instantly without the payment modal.
|
||
|
||
## Difficulty Presets
|
||
|
||
| Preset | Dungeon Size | Monster Aggression | House Win Rate |
|
||
|--------|--------------|--------------------|----|
|
||
| `easy` | 30×15 | Low | ~30% |
|
||
| `normal` | 45×22 | Medium | ~55% |
|
||
| `hard` | 55×28 | High | ~65% |
|
||
| `casino` | 60×30 | Very High | ~70% |
|
||
|
||
Set via `DIFFICULTY_PRESET` in `.env`. Defaults to `casino` for paid modes.
|
||
|
||
---
|
||
|
||
## Key Features
|
||
|
||
### Provably Fair Gaming
|
||
|
||
1. Server generates a random seed and shows its SHA-256 hash before the game
|
||
2. The seed deterministically generates the dungeon layout and positions
|
||
3. After the game, the seed is revealed for verification
|
||
4. Players can verify `hash(seed) = commitment` to prove no manipulation
|
||
|
||
### Spectator Mode
|
||
|
||
Click **"👁️ Watch Games"** to see active games. Spectators receive real-time updates via Socket.IO rooms. Press ESC to exit.
|
||
|
||
### Transaction History
|
||
|
||
Click **"📜 History"** to view your payment and payout records. Shows:
|
||
- Total received from payouts
|
||
- Payment history with status and credits received
|
||
- Payout history with multipliers and transaction hashes
|
||
|
||
### Session Persistence
|
||
|
||
Sessions use an anonymous token stored in localStorage:
|
||
- ✅ Persists across refreshes, browser closes, server restarts
|
||
- ⚠️ Lost when clearing cookies/localStorage, using incognito mode, or switching browsers/devices
|
||
|
||
A warning appears if localStorage is unavailable.
|
||
|
||
---
|
||
|
||
## API Reference
|
||
|
||
### Public Endpoints
|
||
|
||
| Endpoint | Description |
|
||
|----------|-------------|
|
||
| `GET /health` | Server health, uptime, memory, wallet status |
|
||
| `GET /api/game-modes` | Current modes and pricing |
|
||
| `GET /api/user/:socketId/credits` | User credit balance |
|
||
| `GET /api/user/:socketId/payments` | Payment history (paginated) |
|
||
| `GET /api/user/:socketId/payouts` | Payout history (paginated) |
|
||
| `POST /api/user/:socketId/address` | Set payout address |
|
||
| `GET /verify/:gameId` | Provably fair verification page |
|
||
|
||
### Admin Endpoints
|
||
|
||
Require `X-Admin-Key` header matching `ADMIN_API_KEY` env variable.
|
||
|
||
| Endpoint | Description |
|
||
|----------|-------------|
|
||
| `POST /api/admin/refund/payment` | Refund a payment, deduct credits if applicable |
|
||
| `POST /api/admin/credits/adjust` | Add or remove credits from a user |
|
||
| `GET /api/admin/users/search` | Search users by socket ID or address |
|
||
|
||
**Example: Refund a payment**
|
||
```bash
|
||
curl -X POST http://localhost:3000/api/admin/refund/payment \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-Admin-Key: your-admin-key" \
|
||
-d '{"paymentId": 123, "reason": "Customer request", "sendFunds": true}'
|
||
```
|
||
|
||
**Example: Adjust credits**
|
||
```bash
|
||
curl -X POST http://localhost:3000/api/admin/credits/adjust \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-Admin-Key: your-admin-key" \
|
||
-d '{"socketId": "abc123", "amount": 5, "reason": "Compensation"}'
|
||
```
|
||
|
||
### Socket.IO Events
|
||
|
||
**Client → Server**
|
||
| Event | Description |
|
||
|-------|-------------|
|
||
| `auto_start` | Start game (uses credits if available) |
|
||
| `player_move` | Move player (direction: 0-3) |
|
||
| `request_payment` | Request payment address |
|
||
| `get_active_games` | List games for spectating |
|
||
| `spectate_game` | Start spectating a game |
|
||
|
||
**Server → Client**
|
||
| Event | Description |
|
||
|-------|-------------|
|
||
| `game_start` | Game initialized with dungeon state |
|
||
| `game_update` | State after movement |
|
||
| `game_over` | Game ended |
|
||
| `payment_created` | Payment address ready |
|
||
| `credits_update` | Credit balance changed |
|
||
| `spectator_update` | Spectated game state |
|
||
|
||
---
|
||
|
||
## Configuration
|
||
|
||
Key environment variables (see `.env.example` for full list):
|
||
|
||
```bash
|
||
# Core
|
||
NODE_ENV=production
|
||
PORT=3000
|
||
DIFFICULTY_PRESET=casino
|
||
|
||
# Payments
|
||
PAYMENTS_ENABLED=true
|
||
PAYMENT_MODES=direct,credits
|
||
DIRECT_GAME_PRICE=100000000000 # 1 WOW in atomic units
|
||
CREDITS_PACKAGES='[{"id":"small","credits":10,"price":"500000000000","bonus":0}]'
|
||
|
||
# Payouts
|
||
DIRECT_PAYOUT_ESCAPE=2.0
|
||
DIRECT_PAYOUT_TREASURE=3.0
|
||
|
||
# Wallet RPC (required for paid modes)
|
||
PRIMARY_WALLET_ENDPOINT=http://127.0.0.1:34570
|
||
WALLET_RPC_USER=user
|
||
WALLET_RPC_PASSWORD=password
|
||
|
||
# Database
|
||
DB_HOST=localhost
|
||
DB_NAME=wownerogue
|
||
DB_USER=your_user
|
||
DB_PASSWORD=your_password
|
||
|
||
# Admin API (generate with: openssl rand -hex 32)
|
||
ADMIN_API_KEY=your-secure-key
|
||
|
||
# Network (Monero only - Wownero only has mainnet)
|
||
MONERO_NETWORK=mainnet
|
||
```
|
||
|
||
Amounts use atomic units: 1 WOW = 10^11 atomic units.
|
||
|
||
---
|
||
|
||
## Production 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
|
||
- [ ] Configure log rotation
|
||
|
||
### 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
|
||
```
|
||
|
||
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;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Testing
|
||
|
||
```bash
|
||
cd src
|
||
npm test
|
||
```
|
||
|
||
Tests cover payment handlers, wallet RPC, security rules, movement logic, and integration flows.
|
||
|
||
---
|
||
|
||
## Project Structure
|
||
|
||
```
|
||
src/
|
||
├── index.js # Entry point
|
||
├── config/ # Payment config, validation
|
||
├── db/ # PostgreSQL layer
|
||
├── game/ # Dungeon, player, monster logic
|
||
├── network/ # Socket handlers, chat, queue, spectator
|
||
├── payments/ # Wallet RPC, QR codes
|
||
└── utils/ # Errors, memory management
|
||
html/
|
||
├── index.html # Game client
|
||
├── admin.html # Admin dashboard
|
||
└── js/ # Frontend modules
|
||
test/
|
||
└── *.test.js # Jest tests
|
||
```
|
||
|
||
---
|
||
|
||
## License
|
||
|
||
See LICENSE file for details.
|