From 1134fd915c46cde10ad8710d4ac5682cd93839b2 Mon Sep 17 00:00:00 2001 From: gyurix Date: Mon, 1 Sep 2025 16:08:08 +0200 Subject: [PATCH] Enhance Dockerfile and start.sh: add curl, openssl, and jq; update HOMESERVER_URL to use HTTPS; improve admin user registration logic and error handling --- Dockerfile | 2 +- start.sh | 126 ++++++++++++++++++++++++----------------------------- 2 files changed, 58 insertions(+), 70 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2cb2a72..e7c46f4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM alpine:latest -RUN apk add --no-cache yq +RUN apk add --no-cache yq curl openssl jq COPY start.sh /start.sh diff --git a/start.sh b/start.sh index 2b1a19d..a9e4037 100644 --- a/start.sh +++ b/start.sh @@ -8,10 +8,9 @@ POSTGRES_HOST=matrixpostgres-db DB_PORT="5432" SYNAPSE_HOST="${SYNAPSE_SERVER_NAME:-localhost}" -SYNAPSE_PORT="${SYNAPSE_PORT:-8008}" ADMIN_USERNAME="${ADMIN_USERNAME:-admin}" ADMIN_PASSWORD="${ADMIN_PASSWORD:-changeme}" -HOMESERVER_URL="${HOMESERVER_URL:-http://$SYNAPSE_HOST:$SYNAPSE_PORT}" +HOMESERVER_URL="${HOMESERVER_URL:-https://$SYNAPSE_HOST}" prepare_postgres () { if [ -f /data/homeserver.yaml ]; then @@ -37,6 +36,10 @@ prepare_postgres () { get_registration_secret() { if [ -f "/data/homeserver.yaml" ]; then SHARED_SECRET=$(yq '.registration_shared_secret' /data/homeserver.yaml 2>/dev/null) + echo "$SHARED_SECRET" + if [ -n "$SHARED_SECRET" ] && [ "$SHARED_SECRET" != "null" ]; then + return 0 + fi fi } @@ -47,7 +50,7 @@ wait_for_synapse() { local attempt=1 while [ $attempt -le $max_attempts ]; do - if curl -s "$HOMESERVER_URL/_matrix/client/versions" >/dev/null 2>&1; then + if curl -sk "$HOMESERVER_URL/_matrix/client/versions" >/dev/null 2>&1; then echo "Synapse is ready!" return 0 fi @@ -60,56 +63,58 @@ wait_for_synapse() { return 1 } -# Check if any admin users exist using admin API -check_admin_exists() { - # Try to get a temporary admin token first - local temp_token=$(get_admin_token) - - if [ -n "$temp_token" ]; then - local response=$(curl -s -X GET \ - "$HOMESERVER_URL/_synapse/admin/v2/users?deactivated=false" \ - -H "Authorization: Bearer $temp_token" 2>/dev/null || echo "") - - if echo "$response" | grep -q '"admin": true'; then - return 0 # Admin exists - fi - fi - - return 1 # No admin or couldn't check -} - -# Get admin token (this requires an existing admin user) -get_admin_token() { - # This function would need an existing admin to work - # For initial setup, we'll rely on registration shared secret - echo "" -} # Register admin user using shared secret register_admin_user() { local SHARED_SECRET=$1 echo "Registering admin user: $ADMIN_USERNAME" - - # Generate registration MAC - local nonce=$(date +%s) - local username_lower=$(echo "$ADMIN_USERNAME" | tr '[:upper:]' '[:lower:]') - - # Calculate HMAC (simplified - in practice you'd want to use proper HMAC) - local mac=$(echo -n "${nonce}${username_lower}${ADMIN_PASSWORD}admin" | openssl dgst -sha1 -hmac "$SHARED_SECRET" -binary | base64) - - # Register user - local response=$(curl -s -X POST "$HOMESERVER_URL/_synapse/admin/v1/register" \ - -H "Content-Type: application/json" \ - -d "{ - \"nonce\": \"$nonce\", - \"username\": \"$username_lower\", - \"password\": \"$ADMIN_PASSWORD\", - \"admin\": true, - \"mac\": \"$mac\" - }" 2>/dev/null) - - if echo "$response" | grep -q "access_token"; then + + # Derive localpart (strip leading @ and :domain) and lowercase + local localpart + localpart=$(printf '%s' "$ADMIN_USERNAME" | sed -e 's/^@//' -e 's/:.*$//' | tr '[:upper:]' '[:lower:]') + + # Fetch server-issued nonce + local url nonce + url="${HOMESERVER_URL%/}/_synapse/admin/v1/register" + nonce=$(curl -kfsS "$url" | jq -r '.nonce') + + if [ -z "$nonce" ] || [ "$nonce" = "null" ]; then + echo "Failed to fetch nonce from $url" + return 1 + fi + + # Admin flag and user_type + local admin_word admin_json user_type user_type_json + user_type="${USER_TYPE:-}" + case "${ADMIN:-true}" in + true|1|yes|y|True|TRUE) admin_word="admin"; admin_json=true ;; + *) admin_word="notadmin"; admin_json=false ;; + esac + if [ -n "$user_type" ]; then + user_type_json=$(printf '"%s"' "$user_type") + else + user_type_json=null + fi + + # Compute MAC exactly like Python (no trailing NUL unless user_type present) + local mac + if [ -n "$user_type" ]; then + mac=$(printf '%s\0%s\0%s\0%s\0%s' "$nonce" "$localpart" "$ADMIN_PASSWORD" "$admin_word" "$user_type" \ + | openssl dgst -sha1 -hmac "$SHARED_SECRET" -binary | od -An -tx1 | tr -d ' \n') + else + mac=$(printf '%s\0%s\0%s\0%s' "$nonce" "$localpart" "$ADMIN_PASSWORD" "$admin_word" \ + | openssl dgst -sha1 -hmac "$SHARED_SECRET" -binary | od -An -tx1 | tr -d ' \n') + fi + + # Build payload and register + local payload response + payload=$(printf '{"nonce":"%s","username":"%s","password":"%s","admin":%s,"user_type":%s,"mac":"%s"}' \ + "$nonce" "$localpart" "$ADMIN_PASSWORD" "$admin_json" "$user_type_json" "$mac") + + response=$(curl -kfsS -X POST "$url" -H 'Content-Type: application/json' -d "$payload" || true) + + if echo "$response" | grep -q '"user_id"\|"access_token"'; then echo "Admin user created successfully!" return 0 else @@ -118,28 +123,9 @@ register_admin_user() { fi } -# Alternative method using registration endpoint -register_user_simple() { - local SHARED_SECRET=$1 - - echo "Attempting simple registration for: $ADMIN_USERNAME" - - # Try the simpler registration method - local response=$(curl -s -X POST "$HOMESERVER_URL/_matrix/client/r0/admin/register" \ - -H "Content-Type: application/json" \ - -d "{ - \"username\": \"$ADMIN_USERNAME\", - \"password\": \"$ADMIN_PASSWORD\", - \"admin\": true, - \"shared_secret\": \"$SHARED_SECRET\" - }" 2>/dev/null) - - echo "Registration response: $response" -} - # Check if admin exists by trying to login check_admin_by_login() { - local response=$(curl -s -X POST "$HOMESERVER_URL/_matrix/client/r0/login" \ + local response=$(curl -sk -X POST "$HOMESERVER_URL/_matrix/client/r0/login" \ -H "Content-Type: application/json" \ -d "{ \"type\": \"m.login.password\", @@ -147,8 +133,11 @@ check_admin_by_login() { \"password\": \"$ADMIN_PASSWORD\" }" 2>/dev/null) - if echo "$response" | grep -q "access_token"; then + if echo "$response" | grep -q access_token; then + echo "Successfully logged in as admin user" + yq eval '.registration_shared_secret = ""' /data/homeserver.yaml > /data/homeserver.yaml.tmp && mv /data/homeserver.yaml.tmp /data/homeserver.yaml return 0 # User exists and password is correct + fi return 1 # User doesn't exist or wrong password } @@ -182,7 +171,6 @@ main() { # Try to register admin user if ! register_admin_user "$SHARED_SECRET"; then echo "Primary registration method failed, trying alternative..." - register_user_simple "$SHARED_SECRET" fi }