# ikfreunde WYSIWYG Multi-Route Deploy

This project runs a local-content WYSIWYG editor behind Traefik and supports multiple route instances on one domain.

Examples:
- `https://mydomain.de/webpage1/`
- `https://mydomain.de/webpage2/`
- `https://mydomain.de/webpage3/`

## Files
- `docker-compose.traefik-routes.yml`: Traefik-ready multi-service compose file
- `scripts/add-webpage.sh`: auto-generate new `webpageN` route + compose service
- `scripts/editor_server.php`: local API + static server (`/api/content`, `/api/save`)
- See [Brute-Force Protection](#brute-force-protection) for auth hardening details

## Requirements
- Docker + Docker Compose
- Traefik with external network named `proxy`

## First deploy
```bash
docker compose -f docker-compose.traefik-routes.yml up -d --build
```

## Add a new route (autogenerator)
```bash
./scripts/add-webpage.sh webpage4 mydomain.de
```

What it does:
1. Creates route data folder: `/srv/ikfreunde/webpage4/`
2. Seeds files if missing:
- `/srv/ikfreunde/webpage4/ikfreunde.com.html`
- `/srv/ikfreunde/webpage4/site-content.de.json`
3. Injects `webpage4` service into `docker-compose.traefik-routes.yml`

Then redeploy:
```bash
docker compose -f docker-compose.traefik-routes.yml up -d --build
```

Open:
- `https://mydomain.de/webpage4/`

## Notes
- Edit mode is only active with `?edit=1`.
- Saves write both HTML and JSON and create `.bak` backups.
- Route names can include letters, numbers, `_`, `-`.

## Editor claim, login, reset (v1)
- New deployment starts as **unclaimed** (viewer-only by default).
- Open `https://mydomain.de/webpageN/?edit=1` to run first-time onboarding.
- First onboarding claim uses `email + password` and creates:
  - `content/.editor-credentials.json`
- Afterwards, editing requires login. Without auth, users remain viewer.

### Password reset (without SMTP)
- On failed login, trigger reset request.
- Server writes reset data to:
  - `content/.editor-reset.json`
- The file contains `reset_url` with token.
- Open that URL, set new password, then login again.

Security note:
- `content/.editor-credentials.json` and `content/.editor-reset.json` are blocked from HTTP access by the server router.
- Access to these files requires container/filesystem access.
- Simple brute-force protection is enabled in-app for login/reset (`content/.editor-rate-limit.json`) with account-based + global per-site thresholds (IP-independent).
- L3/L4 DDoS and global rate limiting should be handled at Traefik/network level.

## Brute-Force Protection
- Login/Reset limits are enforced in `scripts/editor_server.php`.
- Limiting is account-based + global per site (not IP-bound), so IP hopping is less effective.
- Buckets currently used:
  - `login_account`, `login_global`
  - `reset_request_account`, `reset_request_global`
  - `reset_confirm_account`, `reset_confirm_global`
- Rate-limit state is stored in:
  - `content/.editor-rate-limit.json`

## Optional env overrides
- `ROOT_BASE` (default: `/srv/ikfreunde`)
- `COMPOSE_FILE` (default: `docker-compose.traefik-routes.yml`)

Example:
```bash
ROOT_BASE=/data/pages COMPOSE_FILE=docker-compose.traefik-routes.yml ./scripts/add-webpage.sh webpage5 mydomain.de
```
