chg: pkg: add JWT generation script to make Mercure safe #4
This commit is contained in:
5
Makefile
5
Makefile
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: help start start-build stop build down ps logs prune-everything db-reset
|
.PHONY: help start start-build stop build down ps logs prune-everything db-reset mercure-jwt
|
||||||
|
|
||||||
.DEFAULT_GOAL := help
|
.DEFAULT_GOAL := help
|
||||||
|
|
||||||
@@ -38,6 +38,9 @@ prune-everything:
|
|||||||
fi
|
fi
|
||||||
docker compose down -v --rmi all --remove-orphans
|
docker compose down -v --rmi all --remove-orphans
|
||||||
|
|
||||||
|
mercure-jwt:
|
||||||
|
@php bin/generate-mercure-jwt.php
|
||||||
|
|
||||||
db-reset:
|
db-reset:
|
||||||
@echo "WARNING: This will DROP and RECREATE the database!"
|
@echo "WARNING: This will DROP and RECREATE the database!"
|
||||||
@read -p "Type 'yes' to confirm: " confirm; \
|
@read -p "Type 'yes' to confirm: " confirm; \
|
||||||
|
|||||||
149
README.md
149
README.md
@@ -1,40 +1,143 @@
|
|||||||
mineseeker
|
# MineSeeker
|
||||||
=========
|
|
||||||
|
|
||||||
A Symfony project created on September 22, 2016, 13:56 pm.
|
A real-time **1v1 multiplayer minesweeper** game played in the browser.
|
||||||
|
Two players race on the same hidden minefield — uncover safe cells to score points, but hit a mine and you hand the advantage to your opponent.
|
||||||
|
Games are live and synchronised instantly via a Mercure hub; no page reloads, no polling.
|
||||||
|
|
||||||
PROJECT VERSION 1.1.0-20191026
|
Created by [SplendidBear](https://www.splendidbear.org).
|
||||||
|
|
||||||
This is a Symfony 3 project w/ React JS in standalone mode and w/ WebSocket.
|
---
|
||||||
|
|
||||||
#### Must installed modules w/ npm are in package.json + to global:
|
## Features
|
||||||
|
|
||||||
$ npm install webpack -g
|
- **Real-time 1v1 gameplay** — moves broadcast instantly over Mercure (server-sent events)
|
||||||
|
- **Guest & registered play** — jump in anonymously or create an account for stats and history
|
||||||
|
- **Full authentication stack** — email/password, passkeys (WebAuthn), TOTP 2FA with backup codes
|
||||||
|
- **Player profiles** — win/loss/draw stats, per-month charts, recent battle history with shareable replay links
|
||||||
|
- **Profile pictures** — uploaded to MinIO object storage, thumbnails generated on-the-fly by LiipImagine
|
||||||
|
- **Battle replay sharing** — share a direct link to any finished game
|
||||||
|
- **Docker-ready** — single `make start-build` brings up the full production-like stack
|
||||||
|
|
||||||
You will need a
|
---
|
||||||
.babelrc file w/ the presets
|
|
||||||
webpack.config.js - https://webpack.github.io/docs/webpack-for-browserify-users.html
|
|
||||||
same as dir where the package.json!!
|
|
||||||
|
|
||||||
__(!) Tutorial: https://egghead.io/lessons/react-introduction-to-properties__
|
## Tech stack
|
||||||
|
|
||||||
#### Backend WebSocket server start as daemon - GeniusesOfSymfony/WebSocketBundle
|
| Layer | Technology |
|
||||||
|
|---|---|
|
||||||
|
| Backend | PHP 8.5, Symfony 7.4, Doctrine ORM |
|
||||||
|
| Frontend | React 19, Vite, MUI, SCSS |
|
||||||
|
| Database | PostgreSQL 18 |
|
||||||
|
| Real-time | Mercure (built into FrankenPHP / Caddy) |
|
||||||
|
| File storage | MinIO (S3-compatible) |
|
||||||
|
| Image processing | LiipImagine + Flysystem |
|
||||||
|
| Server | FrankenPHP (Caddy + PHP in one binary) |
|
||||||
|
| Auth | Symfony Security, Scheb 2FA, web-auth/webauthn-framework |
|
||||||
|
|
||||||
$ nohup bin/console gos:websocket:server &
|
---
|
||||||
|
|
||||||
#### React JS WebPack watch generator w/ babel presets: es2015, react
|
## Requirements
|
||||||
|
|
||||||
$ webpack -p --config=webpack-prod.config.js
|
### Bare-metal development
|
||||||
|
- PHP >= 8.5 with extensions: `pdo_pgsql`, `gd`, `intl`, `zip`, `sodium`
|
||||||
|
- Composer 2
|
||||||
|
- Node.js 22 + Bun
|
||||||
|
- PostgreSQL 18
|
||||||
|
- Caddy with FrankenPHP and the Mercure module
|
||||||
|
- MailHog (or any SMTP server on port 1025)
|
||||||
|
- MinIO (listening on port 9000)
|
||||||
|
|
||||||
PROD
|
### Docker
|
||||||
|
- Docker Engine 24+
|
||||||
|
- Docker Compose v2
|
||||||
|
- Bun (for building frontend assets before `make start-build`)
|
||||||
|
- Composer (for `make start-build`)
|
||||||
|
|
||||||
$ webpack --progress --colors --watch -d
|
---
|
||||||
|
|
||||||
DEV
|
## Installation
|
||||||
|
|
||||||
-d --> Debugger; If you write this line somewhere: debugger;
|
### 1. Clone the repository
|
||||||
The browser will stop the code here!!!
|
|
||||||
|
|
||||||
#### Connect to Prod
|
```bash
|
||||||
|
git clone https://github.com/splendidbear/mineseeker.git
|
||||||
|
cd mineseeker
|
||||||
|
```
|
||||||
|
|
||||||
ssh xxsvci@laszlolang.com -i ~/.ssh/id_rsa_laszlolang
|
### 2. Configure environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.dist .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit `.env` and fill in every value. Key ones:
|
||||||
|
|
||||||
|
| Variable | What to set |
|
||||||
|
|---|---|
|
||||||
|
| `APP_SECRET` | Random 32-byte hex: `openssl rand -hex 32` |
|
||||||
|
| `POSTGRES_USER/PASSWORD/DB` | Your PostgreSQL credentials |
|
||||||
|
| `MINIO_ROOT_USER/PASSWORD` | MinIO admin credentials |
|
||||||
|
| `MINIO_ENDPOINT` | `http://localhost:9000` (bare-metal) |
|
||||||
|
| `MINIO_PUBLIC_URL` | Public URL browsers use to reach MinIO |
|
||||||
|
| `RECAPTCHA_SITE_KEY/SECRET_KEY` | Google reCAPTCHA v3 keys for your domain |
|
||||||
|
| `MERCURE_JWT_SECRET` | Random secret (generated in step 3) |
|
||||||
|
| `MERCURE_JWT_TOKEN` | Signed publisher JWT (generated in step 3) |
|
||||||
|
| `MERCURE_SUBSCRIBER_JWT` | Signed subscriber JWT (generated in step 3) |
|
||||||
|
| `MAILER_DSN` | `smtp://localhost:1025` for MailHog in dev |
|
||||||
|
|
||||||
|
### 3. Generate Mercure JWT tokens
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer install
|
||||||
|
make mercure-jwt
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy the printed values into `.env` and into the `publisher_jwt` / `subscriber_jwt` lines of your Caddy Mercure block, then reload Caddy:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl reload caddy
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4a. Run with Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make start-build
|
||||||
|
```
|
||||||
|
|
||||||
|
This installs PHP dependencies, builds the frontend assets with Bun, builds the Docker image, and starts all services (`app`, `db`, `mail`, `minio`, `minio_init`).
|
||||||
|
|
||||||
|
The app is available at `http://localhost:10080` (or the domain set in `APP_PUBLIC_HOSTNAME`).
|
||||||
|
|
||||||
|
To apply any code changes later, run the same command again.
|
||||||
|
|
||||||
|
### 4b. Run bare-metal (development)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer install
|
||||||
|
bun install
|
||||||
|
bun run dev # Vite dev server with hot-reload
|
||||||
|
php bin/console doctrine:migrations:migrate --no-interaction
|
||||||
|
```
|
||||||
|
|
||||||
|
Start MinIO and MailHog, then open the URL configured in your Caddy vhost.
|
||||||
|
|
||||||
|
### 5. MinIO bucket setup
|
||||||
|
|
||||||
|
**Docker** — handled automatically on first start by the `minio_init` service. No action needed.
|
||||||
|
|
||||||
|
**Bare-metal** — run once after MinIO is up:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mc alias set local http://localhost:9000 $MINIO_ROOT_USER $MINIO_ROOT_PASSWORD
|
||||||
|
mc mb local/mineseeker
|
||||||
|
echo '' | mc pipe local/mineseeker/media/.keep
|
||||||
|
echo '' | mc pipe local/mineseeker/cache/.keep
|
||||||
|
# Apply public-read policy for media/ and cache/ — see docker/minio-init.sh for the JSON
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
LGPL-3.0 — see [LICENSE](LICENSE) for details.
|
||||||
|
|
||||||
|
© 2026 [SplendidBear](https://www.splendidbear.org)
|
||||||
|
|||||||
31
bin/generate-mercure-jwt.php
Executable file
31
bin/generate-mercure-jwt.php
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
use Firebase\JWT\JWT;
|
||||||
|
|
||||||
|
$secret = bin2hex(random_bytes(32));
|
||||||
|
|
||||||
|
$publisherToken = JWT::encode(
|
||||||
|
['mercure' => ['publish' => ['*']]],
|
||||||
|
$secret,
|
||||||
|
'HS256'
|
||||||
|
);
|
||||||
|
|
||||||
|
$subscriberToken = JWT::encode(
|
||||||
|
['mercure' => ['subscribe' => ['*']]],
|
||||||
|
$secret,
|
||||||
|
'HS256'
|
||||||
|
);
|
||||||
|
|
||||||
|
echo PHP_EOL;
|
||||||
|
echo "# ── .env ──────────────────────────────────────────────────────────────" . PHP_EOL;
|
||||||
|
echo "MERCURE_JWT_SECRET=\"{$secret}\"" . PHP_EOL;
|
||||||
|
echo "MERCURE_JWT_TOKEN={$publisherToken}" . PHP_EOL;
|
||||||
|
echo "MERCURE_SUBSCRIBER_JWT={$subscriberToken}" . PHP_EOL;
|
||||||
|
echo PHP_EOL;
|
||||||
|
echo "# ── /etc/caddy/conf.d/mine.caddy (inside the mercure {} block) ───────" . PHP_EOL;
|
||||||
|
echo "publisher_jwt {$secret} HS256" . PHP_EOL;
|
||||||
|
echo "subscriber_jwt {$secret} HS256" . PHP_EOL;
|
||||||
|
echo PHP_EOL;
|
||||||
Reference in New Issue
Block a user