Compare commits
2 Commits
a2bddefb47
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| ed192d79c2 | |||
| 7c49898b29 |
@@ -3,5 +3,8 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
*.log
|
||||
.offline-server.log
|
||||
.offline-server.pid
|
||||
administration/.offline-server.log
|
||||
administration/.offline-server.pid
|
||||
website/content/.editor-credentials.json
|
||||
website/content/.editor-reset.json
|
||||
website/content/.editor-rate-limit.json
|
||||
|
||||
12
.gitignore
vendored
@@ -2,17 +2,17 @@
|
||||
.DS_Store
|
||||
|
||||
# Local runtime files
|
||||
.offline-server.log
|
||||
.offline-server.pid
|
||||
administration/.offline-server.log
|
||||
administration/.offline-server.pid
|
||||
|
||||
# Editor auth + reset + rate limit state (never commit)
|
||||
content/.editor-credentials.json
|
||||
content/.editor-reset.json
|
||||
content/.editor-rate-limit.json
|
||||
website/content/.editor-credentials.json
|
||||
website/content/.editor-reset.json
|
||||
website/content/.editor-rate-limit.json
|
||||
|
||||
# Generated backups
|
||||
*.bak
|
||||
content/*.bak
|
||||
website/content/*.bak
|
||||
|
||||
# Optional local tooling
|
||||
node_modules/
|
||||
|
||||
91
README.md
@@ -1,87 +1,14 @@
|
||||
# ikfreunde WYSIWYG Multi-Route Deploy
|
||||
# interkollektives micro website
|
||||
|
||||
This project runs a local-content WYSIWYG editor behind Traefik and supports multiple route instances on one domain.
|
||||
Diese Repository-Struktur ist in zwei Zielgruppen getrennt:
|
||||
|
||||
Examples:
|
||||
- `https://mydomain.de/webpage1/`
|
||||
- `https://mydomain.de/webpage2/`
|
||||
- `https://mydomain.de/webpage3/`
|
||||
- `administration/`
|
||||
Für Deployment, Docker, Traefik, Server-Skripte und technische Wartung.
|
||||
|
||||
## 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
|
||||
- `website/`
|
||||
Für Website-Inhalte (HTML, JSON, Bilder, Editor-Frontend) und redaktionelle Arbeit.
|
||||
|
||||
## Requirements
|
||||
- Docker + Docker Compose
|
||||
- Traefik with external network named `proxy`
|
||||
## Einstieg
|
||||
|
||||
## 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
|
||||
```
|
||||
- Technik/DevOps: siehe `administration/README.md`
|
||||
- Redaktion/Content: siehe `website/README.md`
|
||||
|
||||
@@ -6,4 +6,4 @@ COPY . /app
|
||||
|
||||
EXPOSE 4173
|
||||
|
||||
CMD ["php", "-d", "opcache.enable_cli=0", "-S", "0.0.0.0:4173", "scripts/editor_server.php"]
|
||||
CMD ["php", "-d", "opcache.enable_cli=0", "-S", "0.0.0.0:4173", "administration/scripts/editor_server.php"]
|
||||
60
administration/README.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Administration (Technik)
|
||||
|
||||
Dieser Bereich ist für Deployment, Betrieb und technische Wartung.
|
||||
|
||||
## Struktur
|
||||
|
||||
- `Dockerfile`
|
||||
- `docker-compose.yml`
|
||||
- `docker-compose.traefik-routes.yml`
|
||||
- `scripts/` (Server, Extraktion, Route-Generator)
|
||||
- `docs/` (Planungs-/Brainstorm-Dokumente)
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- Docker + Docker Compose
|
||||
- Traefik mit externem Netzwerk `proxy`
|
||||
|
||||
## Lokaler Editor-Server
|
||||
|
||||
```bash
|
||||
./administration/scripts/run_editor_server.sh
|
||||
```
|
||||
|
||||
Aufruf: `http://127.0.0.1:4173/`
|
||||
|
||||
## Traefik Deploy
|
||||
|
||||
```bash
|
||||
docker compose -f administration/docker-compose.traefik-routes.yml up -d --build
|
||||
```
|
||||
|
||||
## Neue Route erzeugen
|
||||
|
||||
```bash
|
||||
./administration/scripts/add-webpage.sh webpage4 mydomain.de
|
||||
```
|
||||
|
||||
Danach:
|
||||
|
||||
```bash
|
||||
docker compose -f administration/docker-compose.traefik-routes.yml up -d --build
|
||||
```
|
||||
|
||||
## Security / Editor Auth
|
||||
|
||||
- Unclaimed by default (Viewer-Rolle)
|
||||
- Claim/Login/Reset über API im `editor_server.php`
|
||||
- Sensible Dateien liegen unter `website/content/` und sind via HTTP blockiert:
|
||||
- `.editor-credentials.json`
|
||||
- `.editor-reset.json`
|
||||
- `.editor-rate-limit.json`
|
||||
|
||||
## Brute-Force Schutz
|
||||
|
||||
Buckets:
|
||||
- `login_account`, `login_global`
|
||||
- `reset_request_account`, `reset_request_global`
|
||||
- `reset_confirm_account`, `reset_confirm_global`
|
||||
|
||||
Implementierung: `administration/scripts/editor_server.php`
|
||||
@@ -1,12 +1,12 @@
|
||||
services:
|
||||
webpage1:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
context: ..
|
||||
dockerfile: administration/Dockerfile
|
||||
container_name: ikfreunde-webpage1
|
||||
volumes:
|
||||
- /srv/ikfreunde/webpage1/ikfreunde.com.html:/app/ikfreunde.com.html
|
||||
- /srv/ikfreunde/webpage1/site-content.de.json:/app/content/site-content.de.json
|
||||
- /srv/ikfreunde/webpage1/ikfreunde.com.html:/app/website/ikfreunde.com.html
|
||||
- /srv/ikfreunde/webpage1/site-content.de.json:/app/website/content/site-content.de.json
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
@@ -24,12 +24,12 @@ services:
|
||||
|
||||
webpage2:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
context: ..
|
||||
dockerfile: administration/Dockerfile
|
||||
container_name: ikfreunde-webpage2
|
||||
volumes:
|
||||
- /srv/ikfreunde/webpage2/ikfreunde.com.html:/app/ikfreunde.com.html
|
||||
- /srv/ikfreunde/webpage2/site-content.de.json:/app/content/site-content.de.json
|
||||
- /srv/ikfreunde/webpage2/ikfreunde.com.html:/app/website/ikfreunde.com.html
|
||||
- /srv/ikfreunde/webpage2/site-content.de.json:/app/website/content/site-content.de.json
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
@@ -47,12 +47,12 @@ services:
|
||||
|
||||
webpage3:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
context: ..
|
||||
dockerfile: administration/Dockerfile
|
||||
container_name: ikfreunde-webpage3
|
||||
volumes:
|
||||
- /srv/ikfreunde/webpage3/ikfreunde.com.html:/app/ikfreunde.com.html
|
||||
- /srv/ikfreunde/webpage3/site-content.de.json:/app/content/site-content.de.json
|
||||
- /srv/ikfreunde/webpage3/ikfreunde.com.html:/app/website/ikfreunde.com.html
|
||||
- /srv/ikfreunde/webpage3/site-content.de.json:/app/website/content/site-content.de.json
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
@@ -1,13 +1,13 @@
|
||||
services:
|
||||
editor:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
context: ..
|
||||
dockerfile: administration/Dockerfile
|
||||
container_name: ikfreunde-editor
|
||||
ports:
|
||||
- "4173:4173"
|
||||
volumes:
|
||||
- .:/app
|
||||
- ..:/app
|
||||
working_dir: /app
|
||||
command: ["php", "-d", "opcache.enable_cli=0", "-S", "0.0.0.0:4173", "scripts/editor_server.php"]
|
||||
command: ["php", "-d", "opcache.enable_cli=0", "-S", "0.0.0.0:4173", "administration/scripts/editor_server.php"]
|
||||
restart: unless-stopped
|
||||
@@ -16,8 +16,9 @@ if [[ ! "$NAME" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
ROOT_BASE="${ROOT_BASE:-/srv/ikfreunde}"
|
||||
COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.traefik-routes.yml}"
|
||||
COMPOSE_FILE="${COMPOSE_FILE:-$ROOT_DIR/administration/docker-compose.traefik-routes.yml}"
|
||||
ROOT="${ROOT_BASE}/${NAME}"
|
||||
|
||||
if [[ ! -f "$COMPOSE_FILE" ]]; then
|
||||
@@ -28,12 +29,12 @@ fi
|
||||
mkdir -p "$ROOT"
|
||||
|
||||
if [[ ! -f "$ROOT/ikfreunde.com.html" ]]; then
|
||||
cp ikfreunde.com.html "$ROOT/ikfreunde.com.html"
|
||||
cp "$ROOT_DIR/website/ikfreunde.com.html" "$ROOT/ikfreunde.com.html"
|
||||
echo "Created: $ROOT/ikfreunde.com.html"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$ROOT/site-content.de.json" ]]; then
|
||||
cp content/site-content.de.json "$ROOT/site-content.de.json"
|
||||
cp "$ROOT_DIR/website/content/site-content.de.json" "$ROOT/site-content.de.json"
|
||||
echo "Created: $ROOT/site-content.de.json"
|
||||
fi
|
||||
|
||||
@@ -47,12 +48,12 @@ else
|
||||
|
||||
${NAME}:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
context: ..
|
||||
dockerfile: administration/Dockerfile
|
||||
container_name: ikfreunde-${NAME}
|
||||
volumes:
|
||||
- ${ROOT}/ikfreunde.com.html:/app/ikfreunde.com.html
|
||||
- ${ROOT}/site-content.de.json:/app/content/site-content.de.json
|
||||
- ${ROOT}/ikfreunde.com.html:/app/website/ikfreunde.com.html
|
||||
- ${ROOT}/site-content.de.json:/app/website/content/site-content.de.json
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
@@ -1,12 +1,13 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
const PROJECT_ROOT = __DIR__ . '/..';
|
||||
const HTML_PATH = PROJECT_ROOT . '/ikfreunde.com.html';
|
||||
const JSON_PATH = PROJECT_ROOT . '/content/site-content.de.json';
|
||||
const CREDENTIALS_PATH = PROJECT_ROOT . '/content/.editor-credentials.json';
|
||||
const RESET_PATH = PROJECT_ROOT . '/content/.editor-reset.json';
|
||||
const RATE_LIMIT_PATH = PROJECT_ROOT . '/content/.editor-rate-limit.json';
|
||||
const PROJECT_ROOT = __DIR__ . '/../..';
|
||||
const WEBSITE_ROOT = PROJECT_ROOT . '/website';
|
||||
const HTML_PATH = WEBSITE_ROOT . '/ikfreunde.com.html';
|
||||
const JSON_PATH = WEBSITE_ROOT . '/content/site-content.de.json';
|
||||
const CREDENTIALS_PATH = WEBSITE_ROOT . '/content/.editor-credentials.json';
|
||||
const RESET_PATH = WEBSITE_ROOT . '/content/.editor-reset.json';
|
||||
const RATE_LIMIT_PATH = WEBSITE_ROOT . '/content/.editor-rate-limit.json';
|
||||
const SESSION_TTL_SECONDS = 60 * 60 * 12; // 12h
|
||||
const RESET_TTL_SECONDS = 60 * 30; // 30m
|
||||
const LOGIN_ACCOUNT_MAX_ATTEMPTS = 6;
|
||||
@@ -970,8 +971,8 @@ function serveStatic(string $uri): void
|
||||
exit;
|
||||
}
|
||||
|
||||
$resolved = realpath(PROJECT_ROOT . '/' . $cleanPath);
|
||||
$root = realpath(PROJECT_ROOT);
|
||||
$resolved = realpath(WEBSITE_ROOT . '/' . $cleanPath);
|
||||
$root = realpath(WEBSITE_ROOT);
|
||||
|
||||
if ($resolved === false || $root === false || !str_starts_with($resolved, $root) || !is_file($resolved)) {
|
||||
http_response_code(404);
|
||||
8
administration/scripts/extract_content.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
INPUT_HTML="${1:-website/ikfreunde.com.html}"
|
||||
OUTPUT_JSON="${2:-website/content/site-content.de.json}"
|
||||
|
||||
mkdir -p "$(dirname "$OUTPUT_JSON")"
|
||||
php -d opcache.enable_cli=0 administration/scripts/extract_dom_content.php "$INPUT_HTML" "$OUTPUT_JSON"
|
||||
@@ -3,7 +3,7 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
if ($argc < 3) {
|
||||
fwrite(STDERR, "Usage: php scripts/extract_dom_content.php <input_html> <output_json>\n");
|
||||
fwrite(STDERR, "Usage: php administration/scripts/extract_dom_content.php <input_html> <output_json>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
10
administration/scripts/run_editor_server.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
PORT="${1:-4173}"
|
||||
|
||||
ln -sf ikfreunde.com.html website/index.html
|
||||
php -d opcache.enable_cli=0 -S 127.0.0.1:"$PORT" administration/scripts/editor_server.php
|
||||
@@ -1,12 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
WEB_DIR="$ROOT_DIR/website"
|
||||
PORT="${1:-4173}"
|
||||
PID_FILE=".offline-server.pid"
|
||||
LOG_FILE=".offline-server.log"
|
||||
PID_FILE="$ROOT_DIR/administration/.offline-server.pid"
|
||||
LOG_FILE="$ROOT_DIR/administration/.offline-server.log"
|
||||
|
||||
if [[ -f "$PID_FILE" ]] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
|
||||
echo "Offline server already running on PID $(cat "$PID_FILE")."
|
||||
@@ -16,19 +15,19 @@ fi
|
||||
|
||||
rm -f "$PID_FILE"
|
||||
|
||||
ln -sf ikfreunde.com.html index.html
|
||||
nohup python3 -m http.server "$PORT" --bind 127.0.0.1 >"$LOG_FILE" 2>&1 &
|
||||
ln -sf ikfreunde.com.html "$WEB_DIR/index.html"
|
||||
nohup python3 -m http.server "$PORT" --bind 127.0.0.1 --directory "$WEB_DIR" >"$LOG_FILE" 2>&1 &
|
||||
SERVER_PID=$!
|
||||
echo "$SERVER_PID" > "$PID_FILE"
|
||||
|
||||
sleep 0.3
|
||||
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
|
||||
echo "Failed to start offline server on port $PORT."
|
||||
echo "Check log: $ROOT_DIR/$LOG_FILE"
|
||||
echo "Check log: $LOG_FILE"
|
||||
rm -f "$PID_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Offline server started (PID $SERVER_PID)."
|
||||
echo "Open: http://127.0.0.1:${PORT}/"
|
||||
echo "Log: $ROOT_DIR/$LOG_FILE"
|
||||
echo "Log: $LOG_FILE"
|
||||
@@ -1,10 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
PID_FILE=".offline-server.pid"
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
PID_FILE="$ROOT_DIR/administration/.offline-server.pid"
|
||||
|
||||
if [[ ! -f "$PID_FILE" ]]; then
|
||||
echo "No PID file found. Server may already be stopped."
|
||||
@@ -1 +0,0 @@
|
||||
ikfreunde.com.html
|
||||
@@ -1 +0,0 @@
|
||||
ikfreunde.com_files
|
||||
@@ -1 +1 @@
|
||||
ikfreunde.com.html
|
||||
website/ikfreunde.com.html
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
INPUT_HTML="${1:-ikfreunde.com.html}"
|
||||
OUTPUT_JSON="${2:-content/site-content.de.json}"
|
||||
|
||||
mkdir -p "$(dirname "$OUTPUT_JSON")"
|
||||
php -d opcache.enable_cli=0 scripts/extract_dom_content.php "$INPUT_HTML" "$OUTPUT_JSON"
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
PORT="${1:-4173}"
|
||||
|
||||
ln -sf ikfreunde.com.html index.html
|
||||
php -d opcache.enable_cli=0 -S 127.0.0.1:"$PORT" scripts/editor_server.php
|
||||
@@ -1 +0,0 @@
|
||||
ikfreunde.com.html
|
||||
@@ -1 +0,0 @@
|
||||
ikfreunde.com_files
|
||||
33
website/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Website (Content)
|
||||
|
||||
Dieser Bereich ist für Menschen gedacht, die Inhalte bearbeiten möchten.
|
||||
|
||||
## Was liegt hier?
|
||||
|
||||
- `ikfreunde.com.html` (die Seite)
|
||||
- `content/site-content.de.json` (Text- und Bilddaten)
|
||||
- `ikfreunde.com_files/` (Assets)
|
||||
- `editor/` (WYSIWYG im Browser)
|
||||
|
||||
## Editor nutzen
|
||||
|
||||
1. Seite öffnen: `https://<domain>/<route>/?edit=1`
|
||||
2. Beim ersten Mal: Claim mit `E-Mail + Passwort`
|
||||
3. Danach: Login erforderlich, sonst Viewer-Modus
|
||||
|
||||
## Bearbeiten
|
||||
|
||||
- Text: Doppelklick auf Text
|
||||
- Bilder: Klick aufs Bild, dann URL/Alt im Overlay ändern
|
||||
- Speichern: über Editor-Steuerung
|
||||
|
||||
## Passwort-Reset
|
||||
|
||||
- Bei Login-Fehlern kann ein Reset angefordert werden
|
||||
- Reset-Link wird in `content/.editor-reset.json` abgelegt
|
||||
- Mit dem `reset_url` Link neues Passwort setzen
|
||||
|
||||
## Wichtiger Hinweis
|
||||
|
||||
Nicht direkt in versteckten `.editor-*` Dateien arbeiten.
|
||||
Diese Dateien gehören zum Auth-System.
|
||||
@@ -197,7 +197,7 @@
|
||||
|
||||
if (!response.ok) {
|
||||
const wantsReset = window.confirm(
|
||||
"Login fehlgeschlagen. Passwort-Reset anfordern (Token wird in content/.editor-reset.json erzeugt)?"
|
||||
"Login fehlgeschlagen. Passwort-Reset anfordern (Token wird in website/content/.editor-reset.json erzeugt)?"
|
||||
);
|
||||
if (wantsReset) {
|
||||
await triggerResetRequest(email);
|
||||
@@ -229,7 +229,7 @@
|
||||
}
|
||||
|
||||
alert(
|
||||
"Reset angefordert. Prüfe im Container die Datei content/.editor-reset.json und nutze den reset_url Link."
|
||||
"Reset angefordert. Prüfe im Container die Datei website/content/.editor-reset.json und nutze den reset_url Link."
|
||||
);
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 208 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 340 KiB After Width: | Height: | Size: 340 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 251 KiB After Width: | Height: | Size: 251 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |