#!/usr/bin/env bash # ============================================== # Matrix Bot Account Setup Script # ============================================== # # Creates the Mosaic bot user on the local Synapse instance and retrieves # an access token. Idempotent — safe to run multiple times. # # Usage: # docker/matrix/scripts/setup-bot.sh # docker/matrix/scripts/setup-bot.sh --username custom-bot --password custom-pass # # Prerequisites: # - Synapse must be running (docker compose -f ... up synapse) # - Synapse must be healthy (check with: curl http://localhost:8008/health) # # Output: # Prints the environment variables needed for MatrixService configuration. # # ============================================== set -euo pipefail # Defaults SYNAPSE_URL="${SYNAPSE_URL:-http://localhost:8008}" BOT_USERNAME="${BOT_USERNAME:-mosaic-bot}" BOT_PASSWORD="${BOT_PASSWORD:-mosaic-bot-dev-password}" BOT_DISPLAY_NAME="${BOT_DISPLAY_NAME:-Mosaic Bot}" ADMIN_USERNAME="${ADMIN_USERNAME:-admin}" ADMIN_PASSWORD="${ADMIN_PASSWORD:-admin-dev-password}" # Parse arguments while [[ $# -gt 0 ]]; do case $1 in --username) BOT_USERNAME="$2"; shift 2 ;; --password) BOT_PASSWORD="$2"; shift 2 ;; --synapse-url) SYNAPSE_URL="$2"; shift 2 ;; --admin-username) ADMIN_USERNAME="$2"; shift 2 ;; --admin-password) ADMIN_PASSWORD="$2"; shift 2 ;; --help|-h) echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" echo " --username NAME Bot username (default: mosaic-bot)" echo " --password PASS Bot password (default: mosaic-bot-dev-password)" echo " --synapse-url URL Synapse URL (default: http://localhost:8008)" echo " --admin-username NAME Admin username (default: admin)" echo " --admin-password PASS Admin password (default: admin-dev-password)" echo " --help, -h Show this help" exit 0 ;; *) echo "Unknown option: $1"; exit 1 ;; esac done echo "=== Mosaic Stack — Matrix Bot Setup ===" echo "" echo "Synapse URL: ${SYNAPSE_URL}" echo "Bot username: ${BOT_USERNAME}" echo "" # Wait for Synapse to be ready echo "Checking Synapse health..." for i in $(seq 1 30); do if curl -fsSo /dev/null "${SYNAPSE_URL}/health" 2>/dev/null; then echo "Synapse is healthy." break fi if [ "$i" -eq 30 ]; then echo "ERROR: Synapse is not responding at ${SYNAPSE_URL}/health after 30 attempts." echo "Make sure Synapse is running:" echo " docker compose -f docker/docker-compose.yml -f docker/docker-compose.matrix.yml up -d" exit 1 fi echo " Waiting for Synapse... (attempt ${i}/30)" sleep 2 done echo "" # Step 1: Register admin account (if not exists) echo "Step 1: Registering admin account '${ADMIN_USERNAME}'..." ADMIN_REGISTER_RESPONSE=$(curl -sS -X POST "${SYNAPSE_URL}/_synapse/admin/v1/register" \ -H "Content-Type: application/json" \ -d "{}" 2>/dev/null || true) NONCE=$(echo "${ADMIN_REGISTER_RESPONSE}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('nonce',''))" 2>/dev/null || true) if [ -n "${NONCE}" ]; then # Generate HMAC for admin registration using the nonce # For dev, we use register_new_matrix_user via docker exec instead echo " Using docker exec to register admin via Synapse CLI..." docker exec mosaic-synapse register_new_matrix_user \ -u "${ADMIN_USERNAME}" \ -p "${ADMIN_PASSWORD}" \ -a \ -c /data/homeserver.yaml \ http://localhost:8008 2>/dev/null && echo " Admin account created." || echo " Admin account already exists (or registration failed — continuing)." else echo " Attempting registration via docker exec..." docker exec mosaic-synapse register_new_matrix_user \ -u "${ADMIN_USERNAME}" \ -p "${ADMIN_PASSWORD}" \ -a \ -c /data/homeserver.yaml \ http://localhost:8008 2>/dev/null && echo " Admin account created." || echo " Admin account already exists (or registration failed — continuing)." fi echo "" # Step 2: Get admin access token echo "Step 2: Obtaining admin access token..." ADMIN_LOGIN_RESPONSE=$(curl -sS -X POST "${SYNAPSE_URL}/_matrix/client/v3/login" \ -H "Content-Type: application/json" \ -d "{ \"type\": \"m.login.password\", \"identifier\": { \"type\": \"m.id.user\", \"user\": \"${ADMIN_USERNAME}\" }, \"password\": \"${ADMIN_PASSWORD}\" }" 2>/dev/null) ADMIN_TOKEN=$(echo "${ADMIN_LOGIN_RESPONSE}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('access_token',''))" 2>/dev/null || true) if [ -z "${ADMIN_TOKEN}" ]; then echo "ERROR: Could not obtain admin access token." echo "Response: ${ADMIN_LOGIN_RESPONSE}" echo "" echo "Try registering the admin account manually:" echo " docker exec -it mosaic-synapse register_new_matrix_user -u ${ADMIN_USERNAME} -p ${ADMIN_PASSWORD} -a -c /data/homeserver.yaml http://localhost:8008" exit 1 fi echo " Admin token obtained." echo "" # Step 3: Register bot account via admin API (idempotent) echo "Step 3: Registering bot account '${BOT_USERNAME}'..." BOT_REGISTER_RESPONSE=$(curl -sS -X PUT "${SYNAPSE_URL}/_synapse/admin/v2/users/@${BOT_USERNAME}:localhost" \ -H "Authorization: Bearer ${ADMIN_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ \"password\": \"${BOT_PASSWORD}\", \"displayname\": \"${BOT_DISPLAY_NAME}\", \"admin\": false, \"deactivated\": false }" 2>/dev/null) BOT_EXISTS=$(echo "${BOT_REGISTER_RESPONSE}" | python3 -c "import sys,json; d=json.load(sys.stdin); print('yes' if d.get('name') else 'no')" 2>/dev/null || echo "no") if [ "${BOT_EXISTS}" = "yes" ]; then echo " Bot account '@${BOT_USERNAME}:localhost' is ready." else echo " WARNING: Bot registration response unexpected: ${BOT_REGISTER_RESPONSE}" echo " Continuing anyway — bot may already exist." fi echo "" # Step 4: Get bot access token echo "Step 4: Obtaining bot access token..." BOT_LOGIN_RESPONSE=$(curl -sS -X POST "${SYNAPSE_URL}/_matrix/client/v3/login" \ -H "Content-Type: application/json" \ -d "{ \"type\": \"m.login.password\", \"identifier\": { \"type\": \"m.id.user\", \"user\": \"${BOT_USERNAME}\" }, \"password\": \"${BOT_PASSWORD}\" }" 2>/dev/null) BOT_TOKEN=$(echo "${BOT_LOGIN_RESPONSE}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('access_token',''))" 2>/dev/null || true) if [ -z "${BOT_TOKEN}" ]; then echo "ERROR: Could not obtain bot access token." echo "Response: ${BOT_LOGIN_RESPONSE}" exit 1 fi echo " Bot token obtained." echo "" # Step 5: Output configuration echo "============================================" echo " Matrix Bot Setup Complete" echo "============================================" echo "" echo "Add the following to your .env file:" echo "" echo " # Matrix Bridge Configuration" echo " MATRIX_HOMESERVER_URL=http://localhost:8008" echo " MATRIX_ACCESS_TOKEN=${BOT_TOKEN}" echo " MATRIX_BOT_USER_ID=@${BOT_USERNAME}:localhost" echo " MATRIX_SERVER_NAME=localhost" echo "" echo "Or, if running the API inside Docker (same compose network):" echo "" echo " MATRIX_HOMESERVER_URL=http://synapse:8008" echo " MATRIX_ACCESS_TOKEN=${BOT_TOKEN}" echo " MATRIX_BOT_USER_ID=@${BOT_USERNAME}:localhost" echo " MATRIX_SERVER_NAME=localhost" echo "" echo "Element Web is available at: http://localhost:8501" echo " Login with any registered user to test messaging." echo "" echo "Admin account: ${ADMIN_USERNAME} / ${ADMIN_PASSWORD}" echo "Bot account: ${BOT_USERNAME} / ${BOT_PASSWORD}" echo "============================================"