This commit is contained in:
Your Name
2025-09-07 10:59:43 -04:00
parent f5bf1cd6ee
commit 67154164f1
60 changed files with 45716 additions and 58 deletions

260
scripts/README.md Normal file
View File

@@ -0,0 +1,260 @@
# Ginxsom Admin Scripts
This directory contains scripts for managing and testing the Ginxsom admin system.
## Scripts Overview
### 1. setup.sh - Interactive Setup Wizard
**Purpose**: Complete first-time setup with guided configuration
**Usage**:
```bash
./scripts/setup.sh [config_path]
```
**Features**:
- Generates admin and server key pairs
- Collects server configuration interactively
- Creates signed Nostr configuration event
- Sets up database configuration
- Provides setup completion summary
**Dependencies**: `nak`, `jq`, `sqlite3`
### 2. generate_config.sh - Manual Configuration Generator
**Purpose**: Create signed configuration events with command-line options
**Usage**:
```bash
./scripts/generate_config.sh [OPTIONS]
```
**Common Examples**:
```bash
# Generate new keys and create config
./scripts/generate_config.sh --generate-keys --output config.json
# Use existing keys
./scripts/generate_config.sh \
--admin-key abc123... \
--server-key def456... \
--output config.json
# Production server configuration
./scripts/generate_config.sh \
--admin-key abc123... \
--server-key def456... \
--cdn-origin https://cdn.example.com \
--max-size 209715200 \
--enable-auth-rules \
--output /etc/ginxsom/config.json
```
**Options**:
- `--admin-key KEY`: Admin private key (64 hex chars)
- `--server-key KEY`: Server private key (64 hex chars)
- `--cdn-origin URL`: CDN origin URL
- `--max-size BYTES`: Maximum file size
- `--enable-nip94` / `--disable-nip94`: NIP-94 metadata
- `--enable-auth-rules` / `--disable-auth-rules`: Authentication rules
- `--cache-ttl SECONDS`: Auth cache TTL
- `--output FILE`: Output file path
- `--generate-keys`: Generate new key pairs
- `--help`: Show detailed help
**Dependencies**: `nak`, `jq`
### 3. test_admin.sh - Admin API Test Suite
**Purpose**: Test admin API endpoints with Nostr authentication
**Usage**:
```bash
# Load keys from .admin_keys file (created by setup.sh)
./scripts/test_admin.sh
# Use environment variable
export ADMIN_PRIVKEY="your_admin_private_key"
./scripts/test_admin.sh
```
**Tests**:
- Health endpoint (no auth)
- Statistics endpoint
- Configuration get/put
- Files listing
- Authentication verification
- Database configuration check
**Dependencies**: `nak`, `curl`, `jq`, `sqlite3`
## Quick Start Workflows
### First-Time Setup (Recommended)
```bash
# Run interactive setup wizard
./scripts/setup.sh
# Test the configuration
./scripts/test_admin.sh
```
### Manual Setup for Advanced Users
```bash
# Generate configuration with specific settings
./scripts/generate_config.sh \
--generate-keys \
--cdn-origin "https://myserver.com" \
--max-size 209715200 \
--enable-auth-rules
# Configure database manually
sqlite3 db/ginxsom.db << EOF
INSERT OR REPLACE INTO server_config (key, value, description) VALUES
('admin_pubkey', 'your_admin_public_key', 'Admin authorized pubkey'),
('admin_enabled', 'true', 'Enable admin interface');
EOF
# Test configuration
./scripts/test_admin.sh
```
### Production Deployment
```bash
# Generate production config with existing keys
./scripts/generate_config.sh \
--admin-key "$ADMIN_PRIVATE_KEY" \
--server-key "$SERVER_PRIVATE_KEY" \
--cdn-origin "https://cdn.production.com" \
--max-size 536870912 \
--enable-auth-rules \
--cache-ttl 1800 \
--output "/etc/ginxsom/config.json"
# Verify configuration
./scripts/test_admin.sh
```
## Configuration Files
### Generated Files
- **Config file**: `$XDG_CONFIG_HOME/ginxsom/ginxsom_config_event.json` (or `~/.config/ginxsom/`)
- **Admin keys**: `.admin_keys` (created by setup.sh)
### Config File Format
The configuration file is a signed Nostr event (kind 33333) containing server settings:
```json
{
"kind": 33333,
"created_at": 1704067200,
"tags": [
["server_privkey", "server_private_key_hex"],
["cdn_origin", "https://cdn.example.com"],
["max_file_size", "104857600"],
["nip94_enabled", "true"],
["auth_rules_enabled", "false"],
["auth_cache_ttl", "300"]
],
"content": "Ginxsom server configuration",
"pubkey": "admin_public_key_hex",
"id": "event_id_hash",
"sig": "event_signature"
}
```
## Security Notes
### Key Management
- **Admin private key**: Required for all admin operations
- **Server private key**: Used for server identity, stored in memory only
- **Key storage**: Keep `.admin_keys` file secure (600 permissions)
- **Key rotation**: Generate new keys periodically
### Configuration Security
- Config files contain server private keys - protect with appropriate permissions
- Configuration events are cryptographically signed and verified
- Event expiration prevents replay of old configurations
- Database admin settings override file settings
### Production Considerations
- Use strong, randomly generated keys
- Set appropriate file permissions (600) on config files
- Use HTTPS for CDN origins
- Enable authentication rules for production deployments
- Regular key rotation and config updates
## Troubleshooting
### Common Issues
**"nak command not found"**
```bash
# Install nak from GitHub
go install github.com/fiatjaf/nak@latest
```
**"Admin authentication failed"**
```bash
# Check admin pubkey in database
sqlite3 db/ginxsom.db "SELECT * FROM server_config WHERE key = 'admin_pubkey';"
# Verify keys match
echo "$ADMIN_PRIVKEY" | nak key public
```
**"Server not responding"**
```bash
# Check if server is running
curl http://localhost:9001/api/health
# Start server if needed
make run
```
**"Invalid configuration event"**
```bash
# Verify event signature
nak verify < config.json
# Check event expiration
jq '.tags[][] | select(.[0] == "expiration") | .[1]' config.json
```
### Debug Mode
Most scripts support verbose output for debugging:
```bash
# Enable bash debug mode
bash -x ./scripts/setup.sh
# Check individual functions
source ./scripts/test_admin.sh
check_dependencies
load_admin_keys
```
## Integration with Ginxsom
### Server Integration
The server automatically:
1. Checks for file-based config on startup
2. Falls back to database config if file missing
3. Validates Nostr events cryptographically
4. Stores server private key in memory only
### API Integration
Admin API endpoints require:
- Valid Nostr event authorization (kind 24242)
- Admin pubkey verification against database
- Event expiration checking
- Method-specific tags ('t' tag with HTTP method)
### Development Integration
For development and testing:
```bash
# Generate development config
./scripts/setup.sh
# Run server
make run
# Test admin API
./scripts/test_admin.sh
```
This script collection provides a complete admin management system for Ginxsom, from initial setup through ongoing administration and testing.

373
scripts/generate_config.sh Executable file
View File

@@ -0,0 +1,373 @@
#!/bin/bash
# Ginxsom Manual Configuration Generator
# Creates signed configuration events for server setup
set -e
# Default values
ADMIN_KEY=""
SERVER_KEY=""
CDN_ORIGIN="http://localhost:9001"
MAX_FILE_SIZE="104857600" # 100MB
NIP94_ENABLED="true"
AUTH_RULES_ENABLED="false"
AUTH_CACHE_TTL="300"
OUTPUT_FILE=""
EXPIRATION_HOURS="8760" # 1 year
# 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"; }
# Display usage
usage() {
cat << EOF
Usage: $0 [OPTIONS]
Generate a signed Ginxsom configuration event.
OPTIONS:
--admin-key KEY Admin private key (hex, 64 chars)
--server-key KEY Server private key (hex, 64 chars)
--cdn-origin URL CDN origin URL (default: http://localhost:9001)
--max-size BYTES Maximum file size in bytes (default: 104857600)
--enable-nip94 Enable NIP-94 metadata (default: true)
--disable-nip94 Disable NIP-94 metadata
--enable-auth-rules Enable authentication rules system
--disable-auth-rules Disable authentication rules system (default)
--cache-ttl SECONDS Auth cache TTL in seconds (default: 300)
--expiration HOURS Config expiration in hours (default: 8760)
--output FILE Output file path
--generate-keys Generate new admin and server keys
--help Show this help
EXAMPLES:
# Generate keys and create config interactively
$0 --generate-keys --output config.json
# Create config with existing keys
$0 --admin-key abc123... --server-key def456... --output config.json
# Create config for production server
$0 --admin-key abc123... --server-key def456... \\
--cdn-origin https://cdn.example.com \\
--max-size 209715200 \\
--enable-auth-rules \\
--output /etc/ginxsom/config.json
EOF
}
# Parse command line arguments
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
--admin-key)
ADMIN_KEY="$2"
shift 2
;;
--server-key)
SERVER_KEY="$2"
shift 2
;;
--cdn-origin)
CDN_ORIGIN="$2"
shift 2
;;
--max-size)
MAX_FILE_SIZE="$2"
shift 2
;;
--enable-nip94)
NIP94_ENABLED="true"
shift
;;
--disable-nip94)
NIP94_ENABLED="false"
shift
;;
--enable-auth-rules)
AUTH_RULES_ENABLED="true"
shift
;;
--disable-auth-rules)
AUTH_RULES_ENABLED="false"
shift
;;
--cache-ttl)
AUTH_CACHE_TTL="$2"
shift 2
;;
--expiration)
EXPIRATION_HOURS="$2"
shift 2
;;
--output)
OUTPUT_FILE="$2"
shift 2
;;
--generate-keys)
GENERATE_KEYS="true"
shift
;;
--help)
usage
exit 0
;;
*)
log_error "Unknown option: $1"
usage
exit 1
;;
esac
done
}
# 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"
}
# Generate new key pairs
generate_keys() {
log_info "Generating new key pairs..."
ADMIN_KEY=$(nak key generate)
SERVER_KEY=$(nak key generate)
local admin_pubkey=$(echo "$ADMIN_KEY" | nak key public)
local server_pubkey=$(echo "$SERVER_KEY" | nak key public)
log_success "New keys generated:"
echo " Admin Private Key: $ADMIN_KEY"
echo " Admin Public Key: $admin_pubkey"
echo " Server Private Key: $SERVER_KEY"
echo " Server Public Key: $server_pubkey"
echo ""
log_warning "Save these keys securely!"
}
# Validate keys
validate_keys() {
log_info "Validating keys..."
if [ -z "$ADMIN_KEY" ]; then
log_error "Admin key is required (use --admin-key or --generate-keys)"
exit 1
fi
if [ -z "$SERVER_KEY" ]; then
log_error "Server key is required (use --server-key or --generate-keys)"
exit 1
fi
# Validate key format (64 hex characters)
if [[ ! "$ADMIN_KEY" =~ ^[a-fA-F0-9]{64}$ ]]; then
log_error "Invalid admin key format (must be 64 hex characters)"
exit 1
fi
if [[ ! "$SERVER_KEY" =~ ^[a-fA-F0-9]{64}$ ]]; then
log_error "Invalid server key format (must be 64 hex characters)"
exit 1
fi
# Test key validity with nak
local admin_pubkey=$(echo "$ADMIN_KEY" | nak key public 2>/dev/null)
local server_pubkey=$(echo "$SERVER_KEY" | nak key public 2>/dev/null)
if [ -z "$admin_pubkey" ]; then
log_error "Invalid admin private key"
exit 1
fi
if [ -z "$server_pubkey" ]; then
log_error "Invalid server private key"
exit 1
fi
log_success "Keys validated"
}
# Validate configuration values
validate_config() {
log_info "Validating configuration..."
# Validate URL format
if [[ ! "$CDN_ORIGIN" =~ ^https?:// ]]; then
log_error "CDN origin must be a valid HTTP/HTTPS URL"
exit 1
fi
# Validate max file size
if [[ ! "$MAX_FILE_SIZE" =~ ^[0-9]+$ ]]; then
log_error "Max file size must be a number"
exit 1
fi
if [ "$MAX_FILE_SIZE" -lt 1024 ]; then
log_error "Max file size must be at least 1024 bytes"
exit 1
fi
# Validate boolean values
if [[ ! "$NIP94_ENABLED" =~ ^(true|false)$ ]]; then
log_error "NIP94 enabled must be 'true' or 'false'"
exit 1
fi
if [[ ! "$AUTH_RULES_ENABLED" =~ ^(true|false)$ ]]; then
log_error "Auth rules enabled must be 'true' or 'false'"
exit 1
fi
# Validate cache TTL
if [[ ! "$AUTH_CACHE_TTL" =~ ^[0-9]+$ ]]; then
log_error "Cache TTL must be a number"
exit 1
fi
if [ "$AUTH_CACHE_TTL" -lt 60 ]; then
log_error "Cache TTL must be at least 60 seconds"
exit 1
fi
log_success "Configuration validated"
}
# Create configuration event
create_config_event() {
log_info "Creating signed configuration event..."
local expiration=$(($(date +%s) + (EXPIRATION_HOURS * 3600)))
# Create configuration event with all settings
CONFIG_EVENT=$(nak event -k 33333 -c "Ginxsom server configuration" \
--tag server_privkey="$SERVER_KEY" \
--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="$AUTH_CACHE_TTL" \
--tag expiration="$expiration" \
--sec "$ADMIN_KEY")
if [ $? -ne 0 ]; then
log_error "Failed to create configuration event"
exit 1
fi
log_success "Configuration event created and signed"
}
# Save configuration
save_config() {
if [ -z "$OUTPUT_FILE" ]; then
# Default output location
if [ -n "$XDG_CONFIG_HOME" ]; then
OUTPUT_FILE="$XDG_CONFIG_HOME/ginxsom/ginxsom_config_event.json"
else
OUTPUT_FILE="$HOME/.config/ginxsom/ginxsom_config_event.json"
fi
fi
log_info "Saving configuration to $OUTPUT_FILE"
# Create directory if needed
local output_dir=$(dirname "$OUTPUT_FILE")
mkdir -p "$output_dir"
# Save formatted JSON
echo "$CONFIG_EVENT" | jq . > "$OUTPUT_FILE"
if [ $? -ne 0 ]; then
log_error "Failed to save configuration file"
exit 1
fi
chmod 600 "$OUTPUT_FILE"
log_success "Configuration saved to $OUTPUT_FILE"
}
# Display summary
show_summary() {
local admin_pubkey=$(echo "$ADMIN_KEY" | nak key public)
local server_pubkey=$(echo "$SERVER_KEY" | nak key public)
echo ""
echo "================================================================="
echo " GINXSOM CONFIGURATION GENERATED"
echo "================================================================="
echo ""
log_success "Configuration file: $OUTPUT_FILE"
echo ""
echo "Configuration summary:"
echo " Admin Public Key: $admin_pubkey"
echo " Server Public Key: $server_pubkey"
echo " CDN Origin: $CDN_ORIGIN"
echo " Max File Size: $(( MAX_FILE_SIZE / 1024 / 1024 ))MB"
echo " NIP-94 Enabled: $NIP94_ENABLED"
echo " Auth Rules Enabled: $AUTH_RULES_ENABLED"
echo " Cache TTL: ${AUTH_CACHE_TTL}s"
echo " Expires: $(date -d @$(($(date +%s) + (EXPIRATION_HOURS * 3600))))"
echo ""
echo "Next steps:"
echo "1. Place config file in server's config directory"
echo "2. Set admin_pubkey in server database:"
echo " sqlite3 db/ginxsom.db << EOF"
echo " INSERT OR REPLACE INTO server_config (key, value) VALUES"
echo " ('admin_pubkey', '$admin_pubkey'),"
echo " ('admin_enabled', 'true');"
echo " EOF"
echo "3. Start ginxsom server"
echo ""
}
# Main execution
main() {
parse_args "$@"
if [ "$GENERATE_KEYS" = "true" ]; then
check_dependencies
generate_keys
fi
validate_keys
validate_config
create_config_event
save_config
show_summary
}
# Run main function if script is executed directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi

342
scripts/setup.sh Executable file
View File

@@ -0,0 +1,342 @@
#!/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

296
scripts/test_admin.sh Executable file
View File

@@ -0,0 +1,296 @@
#!/bin/bash
# Ginxsom Admin API Test Script
# Tests admin API endpoints using nak (for Nostr events) and curl
set -e
# Configuration
GINXSOM_URL="http://localhost:9001"
ADMIN_PRIVKEY="${ADMIN_PRIVKEY:-}"
ADMIN_PUBKEY=""
# 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() {
log_info "Checking dependencies..."
for cmd in nak curl jq; do
if ! command -v $cmd &> /dev/null; then
log_error "$cmd is not installed"
echo ""
echo "Please install missing dependencies:"
echo "- nak: https://github.com/fiatjaf/nak"
echo "- curl: standard HTTP client"
echo "- jq: JSON processor (sudo apt install jq)"
exit 1
fi
done
log_success "All dependencies found"
}
load_admin_keys() {
if [ -f ".admin_keys" ]; then
log_info "Loading admin keys from .admin_keys file"
source .admin_keys
fi
if [ -z "$ADMIN_PRIVKEY" ]; then
log_error "Admin private key not found"
echo ""
echo "Please set ADMIN_PRIVKEY environment variable or create .admin_keys file:"
echo " export ADMIN_PRIVKEY='your_admin_private_key_here'"
echo ""
echo "Or run the setup wizard to generate keys:"
echo " ./scripts/setup.sh"
exit 1
fi
ADMIN_PUBKEY=$(echo "$ADMIN_PRIVKEY" | nak key public)
log_info "Admin public key: $ADMIN_PUBKEY"
}
create_admin_event() {
local method="$1"
local content="admin_request"
local expiration=$(($(date +%s) + 3600)) # 1 hour from now
# Create Nostr event with nak
local event=$(nak event -k 24242 -c "$content" \
--tag t="$method" \
--tag expiration="$expiration" \
--sec "$ADMIN_PRIVKEY")
echo "$event"
}
send_admin_request() {
local method="$1"
local endpoint="$2"
local data="$3"
log_info "Testing $method $endpoint"
# Create authenticated Nostr event
local event=$(create_admin_event "$method")
local auth_header="Nostr $(echo "$event" | base64 -w 0)"
# Send request with curl
local curl_args=(-s -w "%{http_code}" -H "Authorization: $auth_header")
if [[ "$method" == "PUT" && -n "$data" ]]; then
curl_args+=(-H "Content-Type: application/json" -d "$data")
fi
local response=$(curl "${curl_args[@]}" -X "$method" "$GINXSOM_URL$endpoint")
local http_code="${response: -3}"
local body="${response%???}"
if [[ "$http_code" =~ ^2 ]]; then
log_success "$method $endpoint - HTTP $http_code"
if [[ -n "$body" ]]; then
echo "$body" | jq . 2>/dev/null || echo "$body"
fi
return 0
else
log_error "$method $endpoint - HTTP $http_code"
echo "$body" | jq . 2>/dev/null || echo "$body"
return 1
fi
}
test_health_endpoint() {
echo "================================================================="
log_info "Testing Health Endpoint (no auth required)"
echo "================================================================="
local response=$(curl -s -w "%{http_code}" "$GINXSOM_URL/api/health")
local http_code="${response: -3}"
local body="${response%???}"
if [[ "$http_code" =~ ^2 ]]; then
log_success "GET /api/health - HTTP $http_code"
echo "$body" | jq .
return 0
else
log_error "GET /api/health - HTTP $http_code"
echo "$body"
return 1
fi
}
test_stats_endpoint() {
echo ""
echo "================================================================="
log_info "Testing Statistics Endpoint"
echo "================================================================="
send_admin_request "GET" "/api/stats"
}
test_config_endpoints() {
echo ""
echo "================================================================="
log_info "Testing Configuration Endpoints"
echo "================================================================="
# Get current config
log_info "Getting current configuration..."
send_admin_request "GET" "/api/config"
echo ""
# Update config
log_info "Updating configuration..."
local config_update='{
"max_file_size": "209715200",
"nip94_enabled": "true",
"auth_cache_ttl": "600"
}'
if send_admin_request "PUT" "/api/config" "$config_update"; then
echo ""
log_info "Verifying configuration update..."
send_admin_request "GET" "/api/config"
fi
}
test_files_endpoint() {
echo ""
echo "================================================================="
log_info "Testing Files Endpoint"
echo "================================================================="
send_admin_request "GET" "/api/files?limit=10&offset=0"
}
verify_server_status() {
log_info "Checking if Ginxsom server is running..."
if curl -s --connect-timeout 5 "$GINXSOM_URL/api/health" >/dev/null 2>&1; then
log_success "Server is responding"
return 0
else
log_error "Server is not responding at $GINXSOM_URL"
echo ""
echo "Please ensure the Ginxsom server is running:"
echo " make run"
echo ""
echo "Or check if the server is running on a different port."
return 1
fi
}
verify_admin_config() {
log_info "Verifying admin configuration in database..."
if [ ! -f "db/ginxsom.db" ]; then
log_warning "Database not found at db/ginxsom.db"
return 1
fi
local db_admin_pubkey=$(sqlite3 db/ginxsom.db "SELECT value FROM server_config WHERE key = 'admin_pubkey';" 2>/dev/null || echo "")
local admin_enabled=$(sqlite3 db/ginxsom.db "SELECT value FROM server_config WHERE key = 'admin_enabled';" 2>/dev/null || echo "")
if [ -z "$db_admin_pubkey" ]; then
log_warning "No admin_pubkey found in database"
echo ""
echo "Configure admin access with:"
echo "sqlite3 db/ginxsom.db << EOF"
echo "INSERT OR REPLACE INTO server_config (key, value, description) VALUES"
echo " ('admin_pubkey', '$ADMIN_PUBKEY', 'Admin authorized pubkey'),"
echo " ('admin_enabled', 'true', 'Enable admin interface');"
echo "EOF"
return 1
fi
if [ "$db_admin_pubkey" != "$ADMIN_PUBKEY" ]; then
log_warning "Admin pubkey mismatch!"
echo " Database: $db_admin_pubkey"
echo " Current: $ADMIN_PUBKEY"
return 1
fi
if [ "$admin_enabled" != "true" ]; then
log_warning "Admin interface is disabled in database"
return 1
fi
log_success "Admin configuration verified"
return 0
}
show_test_summary() {
echo ""
echo "================================================================="
log_success "Admin API testing complete!"
echo "================================================================="
echo ""
echo "Admin credentials:"
echo " Private Key: $ADMIN_PRIVKEY"
echo " Public Key: $ADMIN_PUBKEY"
echo ""
echo "Next steps:"
echo "1. Implement web admin interface"
echo "2. Set up monitoring dashboards"
echo "3. Configure additional admin features"
echo ""
}
main() {
echo "=== Ginxsom Admin API Test Suite ==="
echo ""
check_dependencies
load_admin_keys
if ! verify_server_status; then
exit 1
fi
if ! verify_admin_config; then
log_warning "Admin configuration issues detected - some tests may fail"
echo ""
fi
# Run API tests
local failed_tests=0
if ! test_health_endpoint; then
((failed_tests++))
fi
if ! test_stats_endpoint; then
((failed_tests++))
fi
if ! test_config_endpoints; then
((failed_tests++))
fi
if ! test_files_endpoint; then
((failed_tests++))
fi
show_test_summary
if [ $failed_tests -gt 0 ]; then
log_warning "$failed_tests tests failed"
exit 1
else
log_success "All tests passed!"
exit 0
fi
}
# Allow sourcing for individual function testing
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi