fix: single-quote passwords in .env to handle special characters

Passwords with $, &, ;, [, etc. were written unquoted to .env and
cameleer.conf, causing Docker Compose to mangle them. Now all password
and secret fields are written as KEY='value' with embedded single
quotes escaped as '\''.

Also removes inline DB_URL from docker-compose.saas.yml — the Logto
entrypoint now builds it from PG_USER/PG_PASSWORD/PG_HOST using
node's encodeURIComponent for URL-safe encoding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-25 16:33:32 +02:00
parent a9aee77077
commit 4380aa790d
3 changed files with 54 additions and 32 deletions

View File

@@ -156,6 +156,14 @@ generate_password() {
tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 32 || :
}
# Write KEY='escaped_value' to a file. Single-quotes prevent Docker Compose
# from interpreting $, &, ;, etc. Embedded single quotes are escaped as '\''.
env_val() {
local file="$1" key="$2" val="$3"
val="${val//\'/\'\\\'\'}"
printf "%s='%s'\n" "$key" "$val" >> "$file"
}
# --- Argument parsing ---
parse_args() {
@@ -259,8 +267,9 @@ load_config_file() {
case "$key" in
\#*|"") continue ;;
esac
key=$(echo "$key" | tr -d ' ')
value=$(echo "$value" | sed 's/^[ ]*//;s/[ ]*$//')
key=$(printf '%s' "$key" | tr -d ' ')
# Trim whitespace, strip surrounding quotes, unescape '\''
value=$(printf '%s' "$value" | sed "s/^[ ]*//;s/[ ]*$//;s/^'\\(.*\\)'$/\\1/;s/^\"\\(.*\\)\"$/\\1/" | sed "s/'\\\\''/'/g")
case "$key" in
install_dir) [ -z "$INSTALL_DIR" ] && INSTALL_DIR="$value" ;;
public_host) [ -z "$PUBLIC_HOST" ] && PUBLIC_HOST="$value" ;;
@@ -663,15 +672,10 @@ HTTPS_PORT=${HTTPS_PORT}
# PostgreSQL
POSTGRES_USER=cameleer
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
POSTGRES_DB=cameleer
# ClickHouse
CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD}
# Server admin
SERVER_ADMIN_USER=${ADMIN_USER}
SERVER_ADMIN_PASS=${ADMIN_PASS}
# Bootstrap token (required by server, not used externally in standalone mode)
BOOTSTRAP_TOKEN=$(generate_password)
@@ -694,6 +698,10 @@ SERVER_UI_IMAGE=${REGISTRY}/cameleer-server-ui
# Compose file assembly
COMPOSE_FILE=docker-compose.yml:docker-compose.server.yml$([ "$TLS_MODE" = "custom" ] && echo ":docker-compose.tls.yml")$([ -n "$MONITORING_NETWORK" ] && echo ":docker-compose.monitoring.yml")
EOF
# Passwords are appended with single-quoting to handle special characters
env_val "$f" POSTGRES_PASSWORD "$POSTGRES_PASSWORD"
env_val "$f" CLICKHOUSE_PASSWORD "$CLICKHOUSE_PASSWORD"
env_val "$f" SERVER_ADMIN_PASS "$ADMIN_PASS"
if [ "$TLS_MODE" = "custom" ]; then
echo "CERT_FILE=/user-certs/cert.pem" >> "$f"
echo "KEY_FILE=/user-certs/key.pem" >> "$f"
@@ -729,15 +737,10 @@ LOGTO_CONSOLE_BIND=$([ "$LOGTO_CONSOLE_EXPOSED" = "true" ] && echo "0.0.0.0" ||
# PostgreSQL
POSTGRES_USER=cameleer
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
POSTGRES_DB=cameleer_saas
# ClickHouse
CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD}
# Admin user
SAAS_ADMIN_USER=${ADMIN_USER}
SAAS_ADMIN_PASS=${ADMIN_PASS}
# TLS
NODE_TLS_REJECT=${NODE_TLS_REJECT}
@@ -778,13 +781,18 @@ CAMELEER_SERVER_SECURITY_JWTSECRET=$(generate_password)
SMTP_HOST=${SMTP_HOST}
SMTP_PORT=${SMTP_PORT:-587}
SMTP_USER=${SMTP_USER}
SMTP_PASS=${SMTP_PASS}
SMTP_FROM_EMAIL=${SMTP_FROM_EMAIL:-noreply@${PUBLIC_HOST}}
# Compose file assembly
COMPOSE_FILE=docker-compose.yml:docker-compose.saas.yml$([ "$TLS_MODE" = "custom" ] && echo ":docker-compose.tls.yml")$([ -n "$MONITORING_NETWORK" ] && echo ":docker-compose.monitoring.yml")
EOF
# Passwords are appended with single-quoting to handle special characters
env_val "$f" POSTGRES_PASSWORD "$POSTGRES_PASSWORD"
env_val "$f" CLICKHOUSE_PASSWORD "$CLICKHOUSE_PASSWORD"
env_val "$f" SAAS_ADMIN_PASS "$ADMIN_PASS"
env_val "$f" SMTP_PASS "$SMTP_PASS"
if [ -n "$MONITORING_NETWORK" ]; then
echo "" >> "$f"
echo "# Monitoring" >> "$f"
@@ -967,12 +975,13 @@ deployment_mode=${DEPLOYMENT_MODE}
smtp_host=${SMTP_HOST}
smtp_port=${SMTP_PORT}
smtp_user=${SMTP_USER}
smtp_pass=${SMTP_PASS}
smtp_from_email=${SMTP_FROM_EMAIL}
registry=${REGISTRY}
registry_user=${REGISTRY_USER}
registry_token=${REGISTRY_TOKEN}
EOF
# Passwords appended with single-quoting for special character safety
env_val "$f" smtp_pass "$SMTP_PASS"
env_val "$f" registry_token "$REGISTRY_TOKEN"
log_info "Saved installer config to cameleer.conf"
}