185 lines
6.1 KiB
Bash
185 lines
6.1 KiB
Bash
#!/bin/sh
|
|
|
|
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}"
|
|
ADMIN_USERNAME="${ADMIN_USERNAME:-admin}"
|
|
ADMIN_PASSWORD="${ADMIN_PASSWORD:-changeme}"
|
|
HOMESERVER_URL="${HOMESERVER_URL:-https://$SYNAPSE_HOST}"
|
|
|
|
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)
|
|
echo "$SHARED_SECRET"
|
|
if [ -n "$SHARED_SECRET" ] && [ "$SHARED_SECRET" != "null" ]; then
|
|
return 0
|
|
fi
|
|
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 -sk "$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
|
|
}
|
|
|
|
|
|
# Register admin user using shared secret
|
|
register_admin_user() {
|
|
local SHARED_SECRET=$1
|
|
|
|
echo "Registering admin user: $ADMIN_USERNAME"
|
|
|
|
# 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
|
|
echo "Failed to create admin user. Response: $response"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Check if admin exists by trying to login
|
|
check_admin_by_login() {
|
|
local response=$(curl -sk -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
|
|
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
|
|
}
|
|
|
|
# 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..."
|
|
fi
|
|
}
|
|
|
|
# Validate environment
|
|
if [ -z "$ADMIN_PASSWORD" ] || [ "$ADMIN_PASSWORD" = "changeme" ]; then
|
|
echo "Warning: Please set a secure ADMIN_PASSWORD"
|
|
fi
|
|
|
|
prepare_postgres
|
|
|
|
main "$@"
|