342 lines
10 KiB
Bash
Executable File
342 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Ginxsom Interactive Setup Wizard
|
|
# Creates signed configuration events for first-run server setup
|
|
|
|
set -e
|
|
|
|
# Configuration
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
CONFIG_PATH="${1:-}"
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Helper functions
|
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
|
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
|
|
|
# Check dependencies
|
|
check_dependencies() {
|
|
log_info "Checking dependencies..."
|
|
local missing_deps=()
|
|
|
|
for cmd in nak jq; do
|
|
if ! command -v $cmd &> /dev/null; then
|
|
missing_deps+=("$cmd")
|
|
fi
|
|
done
|
|
|
|
if [ ${#missing_deps[@]} -ne 0 ]; then
|
|
log_error "Missing dependencies: ${missing_deps[*]}"
|
|
echo ""
|
|
echo "Please install the missing dependencies:"
|
|
echo "- nak: https://github.com/fiatjaf/nak"
|
|
echo "- jq: sudo apt install jq (or equivalent for your system)"
|
|
exit 1
|
|
fi
|
|
|
|
log_success "All dependencies found"
|
|
}
|
|
|
|
# Validate private key format
|
|
validate_private_key() {
|
|
local key="$1"
|
|
if [[ ! "$key" =~ ^[a-fA-F0-9]{64}$ ]]; then
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# Setup key pairs with user choice
|
|
setup_keys() {
|
|
log_info "Setting up cryptographic key pairs..."
|
|
echo ""
|
|
echo "=== Admin Key Setup ==="
|
|
echo "Choose an option for your admin private key:"
|
|
echo "1. Generate a new random admin key"
|
|
echo "2. Use an existing admin private key"
|
|
echo ""
|
|
|
|
while true; do
|
|
echo -n "Choice (1/2): "
|
|
read -r ADMIN_KEY_CHOICE
|
|
case "$ADMIN_KEY_CHOICE" in
|
|
1)
|
|
log_info "Generating new admin key pair..."
|
|
ADMIN_PRIVKEY=$(nak key generate)
|
|
ADMIN_PUBKEY=$(echo "$ADMIN_PRIVKEY" | nak key public)
|
|
log_success "New admin key pair generated"
|
|
break
|
|
;;
|
|
2)
|
|
echo -n "Enter your admin private key (64 hex characters): "
|
|
read -r ADMIN_PRIVKEY
|
|
if validate_private_key "$ADMIN_PRIVKEY"; then
|
|
ADMIN_PUBKEY=$(echo "$ADMIN_PRIVKEY" | nak key public)
|
|
if [ $? -eq 0 ]; then
|
|
log_success "Admin private key validated"
|
|
break
|
|
else
|
|
log_error "Invalid private key format or nak error"
|
|
fi
|
|
else
|
|
log_error "Invalid private key format (must be 64 hex characters)"
|
|
fi
|
|
;;
|
|
*)
|
|
log_error "Please choose 1 or 2"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
echo ""
|
|
echo "=== Server Key Setup ==="
|
|
echo "Choose an option for your Ginxsom server private key:"
|
|
echo "1. Generate a new random server key"
|
|
echo "2. Use an existing server private key"
|
|
echo ""
|
|
|
|
while true; do
|
|
echo -n "Choice (1/2): "
|
|
read -r SERVER_KEY_CHOICE
|
|
case "$SERVER_KEY_CHOICE" in
|
|
1)
|
|
log_info "Generating new server key pair..."
|
|
SERVER_PRIVKEY=$(nak key generate)
|
|
SERVER_PUBKEY=$(echo "$SERVER_PRIVKEY" | nak key public)
|
|
log_success "New server key pair generated"
|
|
break
|
|
;;
|
|
2)
|
|
echo -n "Enter your server private key (64 hex characters): "
|
|
read -r SERVER_PRIVKEY
|
|
if validate_private_key "$SERVER_PRIVKEY"; then
|
|
SERVER_PUBKEY=$(echo "$SERVER_PRIVKEY" | nak key public)
|
|
if [ $? -eq 0 ]; then
|
|
log_success "Server private key validated"
|
|
break
|
|
else
|
|
log_error "Invalid private key format or nak error"
|
|
fi
|
|
else
|
|
log_error "Invalid private key format (must be 64 hex characters)"
|
|
fi
|
|
;;
|
|
*)
|
|
log_error "Please choose 1 or 2"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
echo ""
|
|
log_success "Key pairs configured:"
|
|
echo " Admin Public Key: $ADMIN_PUBKEY"
|
|
echo " Server Public Key: $SERVER_PUBKEY"
|
|
|
|
# Save keys securely
|
|
echo "ADMIN_PRIVKEY='$ADMIN_PRIVKEY'" > "$PROJECT_ROOT/.admin_keys"
|
|
echo "ADMIN_PUBKEY='$ADMIN_PUBKEY'" >> "$PROJECT_ROOT/.admin_keys"
|
|
echo "SERVER_PRIVKEY='$SERVER_PRIVKEY'" >> "$PROJECT_ROOT/.admin_keys"
|
|
echo "SERVER_PUBKEY='$SERVER_PUBKEY'" >> "$PROJECT_ROOT/.admin_keys"
|
|
chmod 600 "$PROJECT_ROOT/.admin_keys"
|
|
|
|
log_warning "Keys saved to $PROJECT_ROOT/.admin_keys (keep this file secure!)"
|
|
}
|
|
|
|
# Collect server configuration
|
|
collect_configuration() {
|
|
log_info "Collecting server configuration..."
|
|
|
|
echo ""
|
|
echo "=== Server Configuration Setup ==="
|
|
|
|
# CDN Origin
|
|
echo -n "CDN Origin URL (default: http://localhost:9001): "
|
|
read -r CDN_ORIGIN
|
|
CDN_ORIGIN="${CDN_ORIGIN:-http://localhost:9001}"
|
|
|
|
# Max file size
|
|
echo -n "Maximum file size in MB (default: 100): "
|
|
read -r MAX_SIZE_MB
|
|
MAX_SIZE_MB="${MAX_SIZE_MB:-100}"
|
|
MAX_FILE_SIZE=$((MAX_SIZE_MB * 1024 * 1024))
|
|
|
|
# NIP-94 support
|
|
echo -n "Enable NIP-94 metadata (y/n, default: y): "
|
|
read -r ENABLE_NIP94
|
|
case "$ENABLE_NIP94" in
|
|
[Nn]*) NIP94_ENABLED="false" ;;
|
|
*) NIP94_ENABLED="true" ;;
|
|
esac
|
|
|
|
# Authentication rules
|
|
echo -n "Enable authentication rules system (y/n, default: n): "
|
|
read -r ENABLE_AUTH_RULES
|
|
case "$ENABLE_AUTH_RULES" in
|
|
[Yy]*) AUTH_RULES_ENABLED="true" ;;
|
|
*) AUTH_RULES_ENABLED="false" ;;
|
|
esac
|
|
|
|
# Cache TTL
|
|
echo -n "Authentication cache TTL in seconds (default: 300): "
|
|
read -r CACHE_TTL
|
|
CACHE_TTL="${CACHE_TTL:-300}"
|
|
|
|
echo ""
|
|
log_success "Configuration collected:"
|
|
echo " CDN Origin: $CDN_ORIGIN"
|
|
echo " Max File Size: ${MAX_SIZE_MB}MB"
|
|
echo " NIP-94 Enabled: $NIP94_ENABLED"
|
|
echo " Auth Rules Enabled: $AUTH_RULES_ENABLED"
|
|
echo " Cache TTL: ${CACHE_TTL}s"
|
|
}
|
|
|
|
# Create configuration event
|
|
create_config_event() {
|
|
log_info "Creating signed configuration event..."
|
|
|
|
local expiration=$(($(date +%s) + 31536000)) # 1 year from now
|
|
|
|
# Create configuration event with all settings
|
|
CONFIG_EVENT=$(nak event -k 33333 -c "Ginxsom server configuration" \
|
|
--tag server_privkey="$SERVER_PRIVKEY" \
|
|
--tag cdn_origin="$CDN_ORIGIN" \
|
|
--tag max_file_size="$MAX_FILE_SIZE" \
|
|
--tag nip94_enabled="$NIP94_ENABLED" \
|
|
--tag auth_rules_enabled="$AUTH_RULES_ENABLED" \
|
|
--tag auth_cache_ttl="$CACHE_TTL" \
|
|
--tag expiration="$expiration" \
|
|
--sec "$ADMIN_PRIVKEY")
|
|
|
|
if [ $? -ne 0 ]; then
|
|
log_error "Failed to create configuration event"
|
|
exit 1
|
|
fi
|
|
|
|
log_success "Configuration event created and signed"
|
|
}
|
|
|
|
# Save configuration file
|
|
save_config_file() {
|
|
local config_file="$1"
|
|
|
|
log_info "Saving configuration to $config_file"
|
|
|
|
# Create directory if it doesn't exist
|
|
local config_dir=$(dirname "$config_file")
|
|
mkdir -p "$config_dir"
|
|
|
|
# Save configuration event to file
|
|
echo "$CONFIG_EVENT" | jq . > "$config_file"
|
|
|
|
if [ $? -ne 0 ]; then
|
|
log_error "Failed to save configuration file"
|
|
exit 1
|
|
fi
|
|
|
|
chmod 600 "$config_file"
|
|
log_success "Configuration saved to $config_file"
|
|
}
|
|
|
|
# Setup database
|
|
setup_database() {
|
|
log_info "Setting up database configuration..."
|
|
|
|
local db_path="$PROJECT_ROOT/db/ginxsom.db"
|
|
|
|
if [ ! -f "$db_path" ]; then
|
|
log_warning "Database not found at $db_path"
|
|
log_warning "Please ensure the database is initialized before starting the server"
|
|
return
|
|
fi
|
|
|
|
# Insert admin configuration into database
|
|
sqlite3 "$db_path" << EOF
|
|
INSERT OR REPLACE INTO server_config (key, value, description) VALUES
|
|
('admin_pubkey', '$ADMIN_PUBKEY', 'Admin public key from setup wizard'),
|
|
('admin_enabled', 'true', 'Enable admin interface');
|
|
EOF
|
|
|
|
if [ $? -eq 0 ]; then
|
|
log_success "Database configuration updated"
|
|
else
|
|
log_warning "Failed to update database (this is OK if database doesn't exist yet)"
|
|
fi
|
|
}
|
|
|
|
# Display setup summary
|
|
show_setup_summary() {
|
|
echo ""
|
|
echo "================================================================="
|
|
echo " GINXSOM SETUP COMPLETE"
|
|
echo "================================================================="
|
|
echo ""
|
|
log_success "Configuration file created: $CONFIG_PATH"
|
|
log_success "Admin keys saved: $PROJECT_ROOT/.admin_keys"
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo "1. Start the Ginxsom server:"
|
|
echo " cd $PROJECT_ROOT"
|
|
echo " make run"
|
|
echo ""
|
|
echo "2. Test admin API access:"
|
|
echo " source .admin_keys"
|
|
echo " ./scripts/test_admin.sh"
|
|
echo ""
|
|
echo "3. Access web admin (when implemented):"
|
|
echo " http://localhost:9001/admin"
|
|
echo ""
|
|
log_warning "Keep the .admin_keys file secure - it contains your admin private key!"
|
|
echo ""
|
|
}
|
|
|
|
# Main setup workflow
|
|
main() {
|
|
echo "=== Ginxsom Interactive Setup Wizard ==="
|
|
echo ""
|
|
|
|
# Validate config path
|
|
if [ -z "$CONFIG_PATH" ]; then
|
|
# Determine default config path
|
|
if [ -n "$XDG_CONFIG_HOME" ]; then
|
|
CONFIG_PATH="$XDG_CONFIG_HOME/ginxsom/ginxsom_config_event.json"
|
|
else
|
|
CONFIG_PATH="$HOME/.config/ginxsom/ginxsom_config_event.json"
|
|
fi
|
|
fi
|
|
|
|
log_info "Configuration will be saved to: $CONFIG_PATH"
|
|
|
|
# Check if config already exists
|
|
if [ -f "$CONFIG_PATH" ]; then
|
|
log_warning "Configuration file already exists at $CONFIG_PATH"
|
|
echo -n "Overwrite existing configuration? (y/n): "
|
|
read -r OVERWRITE
|
|
case "$OVERWRITE" in
|
|
[Yy]*) ;;
|
|
*) log_info "Setup cancelled"; exit 0 ;;
|
|
esac
|
|
fi
|
|
|
|
# Run setup steps
|
|
check_dependencies
|
|
setup_keys
|
|
collect_configuration
|
|
create_config_event
|
|
save_config_file "$CONFIG_PATH"
|
|
setup_database
|
|
show_setup_summary
|
|
}
|
|
|
|
# Allow sourcing for testing individual functions
|
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
main "$@"
|
|
fi |