UI fixing
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env bash
|
||||
# Configure the GeoIntel operator login in .env.
|
||||
#
|
||||
# Writes GEOINTEL_AUTH_ENABLED, GEOINTEL_AUTH_USERNAME, a pbkdf2_sha256
|
||||
# password hash and a fresh random session secret. The plaintext password is
|
||||
# never written to disk, never printed and never passed as a command argument.
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/configure_operator_login.sh --username jens@itworx.tech
|
||||
# -> prompts for the password (nothing lands in shell history)
|
||||
#
|
||||
# GEOINTEL_OPERATOR_PASSWORD='...' bash scripts/configure_operator_login.sh \
|
||||
# --username jens@itworx.tech --non-interactive
|
||||
#
|
||||
# Options:
|
||||
# --username <value> Operator login name. Required.
|
||||
# --env-file <path> Target env file. Default: .env
|
||||
# --guest-access <bool> Keep the public guest demo. Default: false
|
||||
# --non-interactive Read the password from GEOINTEL_OPERATOR_PASSWORD.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
USERNAME=""
|
||||
ENV_FILE=".env"
|
||||
GUEST_ACCESS="false"
|
||||
NON_INTERACTIVE="false"
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--username) USERNAME="${2:-}"; shift 2 ;;
|
||||
--env-file) ENV_FILE="${2:-}"; shift 2 ;;
|
||||
--guest-access) GUEST_ACCESS="${2:-}"; shift 2 ;;
|
||||
--non-interactive) NON_INTERACTIVE="true"; shift ;;
|
||||
-h|--help) sed -n '2,22p' "$0"; exit 0 ;;
|
||||
*) echo "Unknown argument: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$USERNAME" ]; then
|
||||
echo "--username is required." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
case "$GUEST_ACCESS" in
|
||||
true|false) ;;
|
||||
*) echo "--guest-access must be true or false." >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
if [ -f deploy/unraid/geointel.env.example ]; then
|
||||
echo "Creating ${ENV_FILE} from deploy/unraid/geointel.env.example."
|
||||
cp deploy/unraid/geointel.env.example "$ENV_FILE"
|
||||
else
|
||||
echo "${ENV_FILE} does not exist and no template was found." >&2
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$NON_INTERACTIVE" = "true" ]; then
|
||||
if [ -z "${GEOINTEL_OPERATOR_PASSWORD:-}" ]; then
|
||||
echo "GEOINTEL_OPERATOR_PASSWORD must be set for --non-interactive." >&2
|
||||
exit 2
|
||||
fi
|
||||
else
|
||||
printf 'Password for %s: ' "$USERNAME" >&2
|
||||
read -r -s GEOINTEL_OPERATOR_PASSWORD
|
||||
printf '\n' >&2
|
||||
printf 'Repeat password: ' >&2
|
||||
read -r -s password_repeat
|
||||
printf '\n' >&2
|
||||
if [ "$GEOINTEL_OPERATOR_PASSWORD" != "$password_repeat" ]; then
|
||||
echo "Passwords do not match." >&2
|
||||
exit 2
|
||||
fi
|
||||
unset password_repeat
|
||||
fi
|
||||
|
||||
if [ "${#GEOINTEL_OPERATOR_PASSWORD}" -lt 12 ]; then
|
||||
echo "Refusing to configure an operator password shorter than 12 characters." >&2
|
||||
exit 2
|
||||
fi
|
||||
export GEOINTEL_OPERATOR_PASSWORD
|
||||
|
||||
HASH_SCRIPT="$(mktemp)"
|
||||
trap 'rm -f "$HASH_SCRIPT"' EXIT
|
||||
cat >"$HASH_SCRIPT" <<'PY'
|
||||
import base64
|
||||
import hashlib
|
||||
import os
|
||||
import secrets
|
||||
|
||||
# Must stay identical to AuthService.hash_password in
|
||||
# backend/app/services/auth_service.py.
|
||||
HASH_NAME = "pbkdf2_sha256"
|
||||
ITERATIONS = 600_000
|
||||
|
||||
|
||||
def b64(value: bytes) -> str:
|
||||
return base64.urlsafe_b64encode(value).decode("ascii").rstrip("=")
|
||||
|
||||
|
||||
password = os.environ["GEOINTEL_OPERATOR_PASSWORD"]
|
||||
salt = secrets.token_bytes(18)
|
||||
digest = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, ITERATIONS)
|
||||
|
||||
print("$".join((HASH_NAME, str(ITERATIONS), b64(salt), b64(digest))))
|
||||
print(secrets.token_urlsafe(48))
|
||||
PY
|
||||
|
||||
generated=""
|
||||
if command -v python3 >/dev/null 2>&1; then
|
||||
generated="$(python3 "$HASH_SCRIPT")"
|
||||
elif command -v docker >/dev/null 2>&1; then
|
||||
echo "No local python3 found; deriving the hash in a throwaway python container."
|
||||
generated="$(
|
||||
docker run --rm -i \
|
||||
-e GEOINTEL_OPERATOR_PASSWORD \
|
||||
python:3.11-slim python - <"$HASH_SCRIPT"
|
||||
)"
|
||||
else
|
||||
echo "Need either python3 or docker to derive the password hash." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
unset GEOINTEL_OPERATOR_PASSWORD
|
||||
|
||||
PASSWORD_HASH="$(printf '%s\n' "$generated" | sed -n '1p')"
|
||||
SESSION_SECRET="$(printf '%s\n' "$generated" | sed -n '2p')"
|
||||
|
||||
case "$PASSWORD_HASH" in
|
||||
pbkdf2_sha256\$*) ;;
|
||||
*) echo "Password hash generation failed." >&2; exit 1 ;;
|
||||
esac
|
||||
if [ "${#SESSION_SECRET}" -lt 32 ]; then
|
||||
echo "Session secret generation failed." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
backup="${ENV_FILE}.bak.$(date -u +%Y%m%d%H%M%S)"
|
||||
cp "$ENV_FILE" "$backup"
|
||||
|
||||
tmp_env="$(mktemp)"
|
||||
grep -v -E '^(GEOINTEL_AUTH_ENABLED|GEOINTEL_AUTH_USERNAME|GEOINTEL_AUTH_PASSWORD_HASH|GEOINTEL_AUTH_SESSION_SECRET|GEOINTEL_GUEST_ACCESS_ENABLED)=' \
|
||||
"$ENV_FILE" >"$tmp_env" || true
|
||||
|
||||
{
|
||||
printf '\n'
|
||||
printf '# Operator login, written by scripts/configure_operator_login.sh on %s.\n' \
|
||||
"$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
# Single quotes zijn verplicht: de pbkdf2-hash bevat '$'-tekens. Ongequote
|
||||
# zou Docker Compose ze als variabelen interpoleren en `source .env` onder
|
||||
# `set -u` afbreken met "unbound variable".
|
||||
printf 'GEOINTEL_AUTH_ENABLED=true\n'
|
||||
printf "GEOINTEL_AUTH_USERNAME='%s'\n" "$USERNAME"
|
||||
printf "GEOINTEL_AUTH_PASSWORD_HASH='%s'\n" "$PASSWORD_HASH"
|
||||
printf "GEOINTEL_AUTH_SESSION_SECRET='%s'\n" "$SESSION_SECRET"
|
||||
printf 'GEOINTEL_GUEST_ACCESS_ENABLED=%s\n' "$GUEST_ACCESS"
|
||||
} >>"$tmp_env"
|
||||
|
||||
cat "$tmp_env" >"$ENV_FILE"
|
||||
rm -f "$tmp_env"
|
||||
chmod 600 "$ENV_FILE"
|
||||
|
||||
echo "Operator login configured in ${ENV_FILE}."
|
||||
echo " username: ${USERNAME}"
|
||||
echo " password hash: pbkdf2_sha256, 600000 iterations"
|
||||
echo " session secret: regenerated (existing browser sessions are invalidated)"
|
||||
echo " guest access: ${GUEST_ACCESS}"
|
||||
echo " backup of the previous env file: ${backup}"
|
||||
echo
|
||||
echo "Apply with: bash deploy/unraid/deploy-release.sh"
|
||||
Reference in New Issue
Block a user