#!/usr/bin/env bash set -euo pipefail usage() { cat <<'EOF' Usage: ./scripts/create_admin_user.sh --username --password [options] Erstellt per HTTP-API entweder den initialen Admin (wenn noch keiner existiert) oder legt – nach Login mit bestehenden Admin-Zugangsdaten – zusätzliche Admins an. Benötigte Tools: curl, jq Optionen: --server Backend-Basis-URL (Standard: http://localhost:5000) --username Neuer Admin-Benutzername (Pflicht) --password Neues Admin-Passwort (Pflicht, min. 10 Zeichen) --role Rolle für den Benutzer (Standard: admin) --require-password-change Markiert den Benutzer für Passwort-Änderung beim Login --admin-user Bestehender Admin (für zusätzliche Benutzer erforderlich) --admin-password Passwort des bestehenden Admins --insecure TLS-Zertifikatsprüfung deaktivieren (z. B. bei Self-Signed) -h, --help Diese Hilfe anzeigen Hinweis: Wenn bereits ein Admin existiert, müssen --admin-user und --admin-password angegeben werden, damit sich das Skript anmelden und den neuen Benutzer anlegen kann. EOF } require_cmd() { if ! command -v "$1" >/dev/null 2>&1; then echo "ERROR: Benötigtes Tool '$1' wurde nicht gefunden." >&2 exit 1 fi } # Standardwerte SERVER_URL="${SERVER_URL:-${SERVER:-http://localhost:5000}}" TARGET_USERNAME="" TARGET_PASSWORD="" TARGET_ROLE="admin" REQUIRE_PASSWORD_CHANGE=false ADMIN_USERNAME="${ADMIN_USERNAME:-}" ADMIN_PASSWORD="${ADMIN_PASSWORD:-}" CURL_INSECURE=0 while [[ $# -gt 0 ]]; do case "$1" in --server) SERVER_URL="$2" shift 2 ;; --username) TARGET_USERNAME="$2" shift 2 ;; --password) TARGET_PASSWORD="$2" shift 2 ;; --role) TARGET_ROLE="$2" shift 2 ;; --require-password-change) REQUIRE_PASSWORD_CHANGE=true shift ;; --admin-user) ADMIN_USERNAME="$2" shift 2 ;; --admin-password) ADMIN_PASSWORD="$2" shift 2 ;; --insecure) CURL_INSECURE=1 shift ;; -h|--help) usage exit 0 ;; *) echo "Unbekannte Option: $1" >&2 usage exit 1 ;; esac done if [[ -z "$TARGET_USERNAME" || -z "$TARGET_PASSWORD" ]]; then echo "ERROR: --username und --password sind erforderlich." >&2 usage exit 1 fi require_cmd curl require_cmd jq BASE_URL="${SERVER_URL%/}" COOKIE_JAR="$(mktemp)" trap 'rm -f "$COOKIE_JAR"' EXIT CURL_EXTRA=() if [[ "$CURL_INSECURE" -eq 1 ]]; then CURL_EXTRA+=(-k) fi HTTP_STATUS=0 HTTP_BODY="" api_request() { local method="$1" local url="$2" local data="$3" shift 3 local tmp tmp="$(mktemp)" local args=(-sS -o "$tmp" -w '%{http_code}' -X "$method" -H 'Accept: application/json' -b "$COOKIE_JAR" -c "$COOKIE_JAR") if [[ -n "$data" ]]; then args+=(-H 'Content-Type: application/json' -d "$data") fi if [[ ${#CURL_EXTRA[@]} -gt 0 ]]; then args+=("${CURL_EXTRA[@]}") fi if [[ $# -gt 0 ]]; then args+=("$@") fi local status if ! status=$(curl "${args[@]}" "$url"); then rm -f "$tmp" echo "ERROR: HTTP-Anfrage fehlgeschlagen (${method} ${url})" >&2 exit 1 fi HTTP_STATUS="$status" HTTP_BODY="$(cat "$tmp")" rm -f "$tmp" } assert_status() { local expected="$1" shift || true local matched=0 IFS=',' read -ra codes <<< "$expected" for code in "${codes[@]}"; do if [[ "$HTTP_STATUS" == "$code" ]]; then matched=1 break fi done if [[ $matched -eq 0 ]]; then local msg msg=$(echo "$HTTP_BODY" | jq -r '.error // .message // empty' 2>/dev/null || true) if [[ -z "$msg" ]]; then msg="$HTTP_BODY" fi echo "ERROR: Anfrage fehlgeschlagen (${HTTP_STATUS}): $msg" >&2 exit 1 fi } json_bool() { if [[ "$1" == "true" ]]; then echo "true" else echo "false" fi } jq_payload() { jq -n "$@" } echo "INFO: Prüfe Setup-Status am ${BASE_URL}..." api_request "GET" "${BASE_URL}/auth/setup/status" "" assert_status "200" needs_setup=$(echo "$HTTP_BODY" | jq -r '.needsSetup // false') if [[ "$needs_setup" == "true" ]]; then echo "INFO: Kein Admin vorhanden – erstelle initialen Benutzer..." payload=$(jq_payload --arg username "$TARGET_USERNAME" --arg password "$TARGET_PASSWORD" '{username:$username,password:$password}') api_request "POST" "${BASE_URL}/auth/setup/initial-admin" "$payload" assert_status "201" user=$(echo "$HTTP_BODY" | jq -r '.user.username') echo "SUCCESS: Initialer Admin '$user' erstellt." exit 0 fi if [[ -z "$ADMIN_USERNAME" || -z "$ADMIN_PASSWORD" ]]; then echo "ERROR: Bestehender Admin benötigt: bitte --admin-user und --admin-password angeben." >&2 exit 1 fi echo "INFO: Melde bestehenden Admin an..." login_payload=$(jq_payload --arg username "$ADMIN_USERNAME" --arg password "$ADMIN_PASSWORD" '{username:$username,password:$password}') api_request "POST" "${BASE_URL}/auth/login" "$login_payload" assert_status "200" api_request "GET" "${BASE_URL}/auth/csrf-token" "" assert_status "200" csrf_token=$(echo "$HTTP_BODY" | jq -r '.csrfToken // empty') if [[ -z "$csrf_token" ]]; then echo "ERROR: Konnte keinen CSRF-Token abrufen." >&2 exit 1 fi require_flag=$(json_bool "$REQUIRE_PASSWORD_CHANGE") create_payload=$(jq_payload --arg username "$TARGET_USERNAME" --arg password "$TARGET_PASSWORD" --arg role "$TARGET_ROLE" --argjson requirePasswordChange "$require_flag" '{username:$username,password:$password,role:($role // "admin"),requirePasswordChange:$requirePasswordChange}') echo "INFO: Lege zusätzlichen Admin an..." api_request "POST" "${BASE_URL}/api/admin/users" "$create_payload" -H "X-CSRF-Token: $csrf_token" assert_status "201" created_user=$(echo "$HTTP_BODY" | jq -r '.user.username') created_role=$(echo "$HTTP_BODY" | jq -r '.user.role') echo "SUCCESS: Neuer Admin '${created_user}' (Rolle: ${created_role}) wurde erstellt." #!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" BACKEND_DIR="${REPO_ROOT}/backend" NODE_SCRIPT="${BACKEND_DIR}/src/scripts/createAdminUser.js" STAMP_FILE="${BACKEND_DIR}/.create_admin_user_deps.stamp" usage() { cat < --password [--role ] [--require-password-change] Beispiele: ./scripts/create_admin_user.sh --username admin2 --password 'SehrSicher123!' ./scripts/create_admin_user.sh --username audit --password 'NochSicherer123!' --role auditor --require-password-change EOF } if [[ $# -eq 0 ]]; then usage exit 1 fi case "${1:-}" in -h|--help) usage exit 0 ;; esac if [[ ! -f "${NODE_SCRIPT}" ]]; then echo "createAdminUser.js nicht gefunden (erwartet unter ${NODE_SCRIPT})." >&2 exit 1 fi if ! command -v node >/dev/null 2>&1; then echo "Node.js wird benötigt, bitte installieren." >&2 exit 1 fi ensure_node_modules() { if [[ ! -d "${BACKEND_DIR}/node_modules" ]]; then echo "📦 Installiere Backend-Abhängigkeiten (npm install)..." (cd "${BACKEND_DIR}" && npm install) touch "${STAMP_FILE}" return fi if [[ -f "${BACKEND_DIR}/package-lock.json" ]] && [[ ! -f "${STAMP_FILE}" || "${BACKEND_DIR}/package-lock.json" -nt "${STAMP_FILE}" ]]; then echo "📦 Aktualisiere Backend-Abhängigkeiten (npm install)..." (cd "${BACKEND_DIR}" && npm install) touch "${STAMP_FILE}" fi } ensure_node_modules pushd "${BACKEND_DIR}" >/dev/null # Standardmäßig teueres Preview-Rendering überspringen export SKIP_PREVIEW_GENERATION="${SKIP_PREVIEW_GENERATION:-1}" node "${NODE_SCRIPT}" "$@" popd >/dev/null