#!/usr/bin/env bash set -euo pipefail ENV_FILE="${APP_DATA_DIR}/settings.env" TMP_DIR="${APP_DATA_DIR}/tmp" DB_DATA_DIR="${APP_DATA_DIR}/data/db" REDIS_DATA_DIR="${APP_DATA_DIR}/data/redis" RUSTFS_DATA_DIR="${APP_DATA_DIR}/data/rustfs" RUSTFS_LOGS_DIR="${APP_DATA_DIR}/data/rustfs-logs" SEARXNG_DATA_DIR="${APP_DATA_DIR}/data/searxng" mkdir -p "${TMP_DIR}" mkdir -p "${DB_DATA_DIR}" "${REDIS_DATA_DIR}" "${RUSTFS_DATA_DIR}" "${RUSTFS_LOGS_DIR}" "${SEARXNG_DATA_DIR}" touch "${ENV_FILE}" chown -R 1000:1000 "${DB_DATA_DIR}" "${REDIS_DATA_DIR}" 2>/dev/null || true chown -R 10001:10001 "${RUSTFS_DATA_DIR}" "${RUSTFS_LOGS_DIR}" 2>/dev/null || true if [[ ! -f "${SEARXNG_DATA_DIR}/settings.yml" ]]; then cat > "${SEARXNG_DATA_DIR}/settings.yml" <<'EOF' use_default_settings: true search: formats: - html - json EOF fi get_var() { local key="$1" if grep -q "^${key}=" "${ENV_FILE}"; then grep "^${key}=" "${ENV_FILE}" | tail -n 1 | cut -d= -f2- fi } set_var() { local key="$1" local value="$2" python3 - "$ENV_FILE" "$key" "$value" <<'PY' import pathlib import sys path = pathlib.Path(sys.argv[1]) key = sys.argv[2] value = sys.argv[3] lines = path.read_text().splitlines() if path.exists() else [] updated = False for index, line in enumerate(lines): if line.startswith(f"{key}="): lines[index] = f"{key}={value}" updated = True break if not updated: lines.append(f"{key}={value}") path.write_text("\n".join(lines) + "\n") PY } generate_secret() { openssl rand -base64 32 | tr -d '\n' } generate_jwks() { local pem_file="${TMP_DIR}/jwks.pem" openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out "${pem_file}" >/dev/null 2>&1 python3 - "${pem_file}" <<'PY' import base64 import hashlib import json import re import subprocess import sys pem_file = sys.argv[1] text = subprocess.check_output( ["openssl", "rsa", "-in", pem_file, "-text", "-noout"], stderr=subprocess.DEVNULL, text=True, ) mapping = { "modulus": "n", "privateExponent": "d", "prime1": "p", "prime2": "q", "exponent1": "dp", "exponent2": "dq", "coefficient": "qi", } values = {} current = None for line in text.splitlines(): stripped = line.strip() if stripped.startswith("publicExponent:"): exponent = int(stripped.split()[1]) values["e"] = exponent.to_bytes((exponent.bit_length() + 7) // 8, "big") current = None continue if stripped.endswith(":") and stripped[:-1] in mapping: current = mapping[stripped[:-1]] values[current] = b"" continue if current and re.fullmatch(r"[0-9a-f:]+", stripped): values[current] += bytes.fromhex(stripped.replace(":", "")) continue current = None for key in ("n", "d", "p", "q", "dp", "dq", "qi"): value = values[key] while len(value) > 1 and value[0] == 0: value = value[1:] values[key] = value def b64url(data): return base64.urlsafe_b64encode(data).decode().rstrip("=") kid = hashlib.sha256(values["n"]).hexdigest()[:16] print( json.dumps( { "keys": [ { "kty": "RSA", "use": "sig", "alg": "RS256", "kid": kid, "n": b64url(values["n"]), "e": b64url(values["e"]), "d": b64url(values["d"]), "p": b64url(values["p"]), "q": b64url(values["q"]), "dp": b64url(values["dp"]), "dq": b64url(values["dq"]), "qi": b64url(values["qi"]), } ] }, separators=(",", ":"), ) ) PY rm -f "${pem_file}" } if [[ -z "$(get_var KEY_VAULTS_SECRET)" ]]; then set_var KEY_VAULTS_SECRET "$(generate_secret)" fi if [[ -z "$(get_var AUTH_SECRET)" ]]; then set_var AUTH_SECRET "$(generate_secret)" fi if [[ -z "$(get_var JWKS_KEY)" ]]; then set_var JWKS_KEY "$(generate_jwks)" fi