#!/bin/bash # Superball Thrower Daemon Installation Script # This script installs and configures the Superball Thrower daemon set -e echo "🏀 Superball Thrower Daemon Installation" echo "========================================" # Check if running as root if [[ $EUID -eq 0 ]]; then echo "❌ This script should not be run as root for security reasons" echo " Please run as a regular user with sudo privileges" exit 1 fi # Function to check if command exists command_exists() { command -v "$1" >/dev/null 2>&1 } # Check for required system dependencies echo "📋 Checking system dependencies..." # Check for curl if ! command_exists curl; then echo "❌ curl is required but not installed" echo " Please install curl: sudo apt update && sudo apt install curl" exit 1 fi # Check for systemctl (systemd) if ! command_exists systemctl; then echo "❌ systemd is required but not found" echo " This script requires a systemd-based system" exit 1 fi # Install latest Node.js using nvm echo "🔧 Installing latest Node.js using nvm..." # Download and install nvm if [ ! -d "$HOME/.nvm" ]; then echo " Downloading and installing nvm..." curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash fi # Load nvm export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # Install Node.js 22 (latest LTS) echo " Installing Node.js 22..." nvm install 22 nvm use 22 # Verify installation NODE_VERSION=$(node --version) NPM_VERSION=$(npm --version) echo "✅ Node.js $NODE_VERSION installed" echo "✅ npm $NPM_VERSION installed" # Copy Node.js binaries to system-wide location echo "📋 Installing Node.js binaries system-wide..." NODE_PATH=$(which node) NPM_PATH=$(which npm) if [ -n "$NODE_PATH" ] && [ -x "$NODE_PATH" ]; then # Remove any existing symlinks first sudo rm -f /usr/local/bin/node sudo cp "$NODE_PATH" /usr/local/bin/node sudo chmod +x /usr/local/bin/node echo "✅ Node.js binary copied to /usr/local/bin/node" else echo "❌ Failed to find Node.js executable" exit 1 fi if [ -n "$NPM_PATH" ] && [ -x "$NPM_PATH" ]; then # Remove any existing symlinks first sudo rm -f /usr/local/bin/npm sudo cp "$NPM_PATH" /usr/local/bin/npm sudo chmod +x /usr/local/bin/npm echo "✅ npm binary copied to /usr/local/bin/npm" else echo "❌ Failed to find npm executable" exit 1 fi # Install npm dependencies echo "📦 Installing npm dependencies..." if ! npm install; then echo "❌ Failed to install npm dependencies" exit 1 fi echo "✅ Dependencies installed successfully" # Interactive configuration echo "" echo "⚙️ Thrower Configuration" echo "========================" echo "Please provide the following information for your Superball Thrower:" echo "" # Prompt for configuration values read -p "Enter your private key (hex format, leave empty to generate new): " PRIVATE_KEY read -p "Enter your public key (hex format, leave empty if generating new): " PUBLIC_KEY read -p "Enter thrower name (e.g., 'My Superball Thrower'): " THROWER_NAME read -p "Enter thrower description: " THROWER_DESCRIPTION read -p "Enter banner URL (optional, press enter to skip): " BANNER_URL read -p "Enter icon URL (optional, press enter to skip): " ICON_URL # Generate keypair if not provided if [ -z "$PRIVATE_KEY" ] || [ -z "$PUBLIC_KEY" ]; then echo "🔑 Generating new keypair..." # We'll let the daemon generate the keypair on first run PRIVATE_KEY="" PUBLIC_KEY="" fi # Update config.json with user input echo "📝 Updating configuration file..." # Create a temporary config file with user values cat > config.json << EOF { "thrower": { "privateKey": "$PRIVATE_KEY", "publicKey": "$PUBLIC_KEY", "name": "$THROWER_NAME", "description": "$THROWER_DESCRIPTION", "banner": "$BANNER_URL", "icon": "$ICON_URL", "adminPubkey": "", "contact": "", "supportedSups": "1,2,3,4,5,6", "software": "https://git.laantungir.net/laantungir/super_ball.git", "version": "1.0.0", "privacyPolicy": "", "termsOfService": "", "refreshRate": 300, "maxDelay": 86460 }, "relays": [ { "url": "wss://relay.laantungir.net", "read": true, "write": true, "authStatus": "unknown" }, { "url": "wss://relay.damus.io", "read": true, "write": true, "authStatus": "unknown" }, { "url": "wss://nos.lol", "read": true, "write": true, "authStatus": "unknown" }, { "url": "wss://relay.snort.social", "read": true, "write": true, "authStatus": "unknown" }, { "url": "wss://relay.primal.net", "read": true, "write": true, "authStatus": "unknown" }, { "url": "wss://relay.nostr.band", "read": true, "write": true, "authStatus": "unknown" }, { "url": "wss://nostr.oxtr.dev", "read": true, "write": true, "authStatus": "unknown" }, { "url": "wss://offchain.pub", "read": true, "write": true, "authStatus": "unknown" }, { "url": "wss://nostr-pub.wellorder.net", "read": true, "write": true, "authStatus": "unknown" } ], "daemon": { "logLevel": "info", "maxQueueSize": 1000, "maxLogEntries": 1000, "autoStart": false } } EOF echo "✅ Configuration updated" # Create system user for the daemon echo "👤 Creating system user..." DAEMON_USER="superball-thrower" if id "$DAEMON_USER" &>/dev/null; then echo "✅ User $DAEMON_USER already exists" else echo " Creating user: $DAEMON_USER" sudo useradd --system --no-create-home --shell /bin/false "$DAEMON_USER" echo "✅ User $DAEMON_USER created" fi # Create installation directory INSTALL_DIR="/opt/superball-thrower" echo "📁 Setting up installation directory: $INSTALL_DIR" sudo mkdir -p "$INSTALL_DIR" sudo cp daemon.js "$INSTALL_DIR/" sudo cp package.json "$INSTALL_DIR/" sudo cp config.json "$INSTALL_DIR/" # Copy node_modules if it exists if [ -d "node_modules" ]; then sudo cp -r node_modules "$INSTALL_DIR/" fi # Set ownership and permissions sudo chown -R "$DAEMON_USER:$DAEMON_USER" "$INSTALL_DIR" sudo chmod 755 "$INSTALL_DIR" sudo chmod 644 "$INSTALL_DIR"/*.js "$INSTALL_DIR"/*.json sudo chmod -R 755 "$INSTALL_DIR/node_modules" 2>/dev/null || true echo "✅ Files installed to $INSTALL_DIR" # Create log directory LOG_DIR="/var/log/superball-thrower" echo "📝 Creating log directory: $LOG_DIR" sudo mkdir -p "$LOG_DIR" sudo chown "$DAEMON_USER:$DAEMON_USER" "$LOG_DIR" sudo chmod 755 "$LOG_DIR" echo "✅ Log directory created" # Install systemd service echo "⚙️ Installing systemd service..." sudo cp superball-thrower.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable superball-thrower.service echo "✅ Systemd service installed and enabled" # Initialize daemon if no keypair was provided if [ -z "$PRIVATE_KEY" ]; then echo "🔑 Initializing daemon to generate keypair..." # Create a simple init script that generates keypair sudo -u "$DAEMON_USER" bash -c " cd \"$INSTALL_DIR\" /usr/local/bin/node -e \" const { generateSecretKey, getPublicKey } = require('nostr-tools/pure'); const fs = require('fs'); const config = JSON.parse(fs.readFileSync('config.json', 'utf8')); const sk = generateSecretKey(); const pk = getPublicKey(sk); config.thrower.privateKey = Buffer.from(sk).toString('hex'); config.thrower.publicKey = pk; fs.writeFileSync('config.json', JSON.stringify(config, null, 2)); console.log('Generated keypair:'); console.log('Private key:', Buffer.from(sk).toString('hex')); console.log('Public key:', pk); \" " echo "✅ Keypair generated" fi # Installation complete echo "" echo "🎉 Installation completed successfully!" echo "" echo "📋 Next steps:" echo " 1. Start the service: sudo systemctl start superball-thrower" echo " 2. Check status: sudo systemctl status superball-thrower" echo " 3. View logs: sudo journalctl -u superball-thrower -f" echo "" echo "📖 For more information, see the README.md file" echo "" echo "🔐 Security notes:" echo " - The daemon runs as user '$DAEMON_USER' with limited privileges" echo " - Configuration files are owned by the daemon user" echo " - Logs are written to $LOG_DIR" echo "" echo "⚙️ Configuration summary:" echo " - Thrower name: $THROWER_NAME" echo " - Description: $THROWER_DESCRIPTION" echo " - Config file: $INSTALL_DIR/config.json" echo ""