#!/bin/sh # Configuration DB_TYPE="${DB_TYPE:-pyscopg2}" # Default to PostgreSQL POSTGRES_DB="${POSTGRES_DB:-matrix}" POSTGRES_USER="${POSTGRES_USER:-matrix}" POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-matrix}" 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}" prepare_postgres () { if [ -f "/data/homeserver.yaml" ]; then; DB_TYPE=$(yq '.database.name' /data/homeserver.yaml 2>/dev/null ) if [ "$DB_TYPE" != "psycopg2" ]; then echo "Preparing PostgreSQL database..." YAML='.server_name = "'$SYNAPSE_HOST'" | .database.name = "psycopg2" | .database.args.user = "'$POSTGRES_USER'" | .database.args.password = "'$POSTGRES_PASSWORD'" | .database.args.database = "'$POSTGRES_DB'" | .database.args.host = "'$POSTGRES_HOST'" | .database.args.port = "'$DB_PORT'" | .database.args.cp_min = 5 | .database.args.cp_max = 10' yq eval "$YAML" /data/homeserver.yaml > /data/homeserver.yaml.tmp && mv /data/homeserver.yaml.tmp /data/homeserver.yaml exit 0 fi fi } # Get registration shared secret from template.json get_registration_secret() { if [ -f "/data/homeserver.yaml" ]; then SHARED_SECRET=$(yq '.registration_shared_secret' /data/homeserver.yaml 2>/dev/null) fi } # Wait for Synapse to be ready wait_for_synapse() { echo "Waiting for Synapse to be ready..." local max_attempts=30 local attempt=1 while [ $attempt -le $max_attempts ]; do if curl -s "$HOMESERVER_URL/_matrix/client/versions" >/dev/null 2>&1; then echo "Synapse is ready!" return 0 fi echo "Attempt $attempt/$max_attempts - Synapse not ready yet..." sleep 2 attempt=$((attempt + 1)) done echo "Error: Synapse did not become ready within expected time" 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 echo "Admin user created successfully!" return 0 else echo "Failed to create admin user. Response: $response" return 1 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" \ -H "Content-Type: application/json" \ -d "{ \"type\": \"m.login.password\", \"user\": \"$ADMIN_USERNAME\", \"password\": \"$ADMIN_PASSWORD\" }" 2>/dev/null) if echo "$response" | grep -q "access_token"; then return 0 # User exists and password is correct fi return 1 # User doesn't exist or wrong password } # Main execution main() { echo "Starting Synapse admin initialization..." if ! wait_for_synapse; then exit 1 fi # Get registration shared secret local SHARED_SECRET=$(get_registration_secret) if [ -z "$SHARED_SECRET" ]; then echo "Error: Could not find registration_shared_secret" echo "Make sure template.json contains the encoded configuration" exit 1 fi echo "Found registration shared secret" # Check if admin already exists by trying to login if check_admin_by_login; then echo "Admin user '$ADMIN_USERNAME' already exists and is accessible" exit 0 fi echo "No accessible admin user found. Creating admin user..." # 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 } # Validate environment if [ -z "$ADMIN_PASSWORD" ] || [ "$ADMIN_PASSWORD" = "changeme" ]; then echo "Warning: Please set a secure ADMIN_PASSWORD" fi prepare_postgres main "$@"