diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..20042cb --- /dev/null +++ b/.drone.yml @@ -0,0 +1,55 @@ +kind: pipeline +type: kubernetes +name: default + +node_selector: + physical-node: dev1 + +trigger: + event: + - push + - tag + +workspace: + path: /drone/src + +steps: + - name: pull image to dockerhub + image: docker.io/owncloudci/drone-docker-buildx:4 + privileged: true + settings: + cache-from: [ "safebox/matrix-setup" ] + repo: safebox/matrix-setup + tags: latest + username: + from_secret: dockerhub-username + password: + from_secret: dockerhub-password + platforms: + - linux/amd64 + - linux/arm64 + when: + event: + - tag + + - name: build multiarch from dev + image: docker.io/owncloudci/drone-docker-buildx:4 + privileged: true + #environment: + # DOCKER_PLUGIN_MIRROR: "https://mirror.dev.format.hu" + settings: + cache-from: [ "registry.dev.format.hu/matrix-setup" ] + registry: registry.dev.format.hu + repo: registry.dev.format.hu/matrix-setup + tags: latest + dockerfile: Dockerfile + username: + from_secret: dev-hu-registry-username + password: + from_secret: dev-hu-registry-password + platforms: + - linux/amd64 + - linux/arm64 + when: + event: + - push \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2cb2a72 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM alpine:latest + +RUN apk add --no-cache yq + +COPY start.sh /start.sh + +RUN chmod +x /start.sh + +CMD ["/start.sh"] \ No newline at end of file diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..5af9052 --- /dev/null +++ b/start.sh @@ -0,0 +1,198 @@ +#!/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 "$@"