#!/bin/bash # Configuration module for Transmission RSS Manager Installation # Configuration variables with defaults INSTALL_DIR="/opt/transmission-rss-manager" SERVICE_NAME="transmission-rss-manager" PORT=3000 # Get default user safely - avoid using root get_default_user() { local default_user # Try logname first to get the user who invoked sudo if command -v logname &> /dev/null; then default_user=$(logname 2>/dev/null) fi # If logname failed, try SUDO_USER if [ -z "$default_user" ] && [ -n "$SUDO_USER" ]; then default_user="$SUDO_USER" fi # Fallback to current user if both methods failed if [ -z "$default_user" ]; then default_user="$(whoami)" fi # Ensure the user is not root if [ "$default_user" = "root" ]; then echo "nobody" else echo "$default_user" fi } # Initialize default user USER=$(get_default_user) # Transmission configuration variables TRANSMISSION_REMOTE=false TRANSMISSION_HOST="localhost" TRANSMISSION_PORT=9091 TRANSMISSION_USER="" TRANSMISSION_PASS="" TRANSMISSION_RPC_PATH="/transmission/rpc" TRANSMISSION_DOWNLOAD_DIR="/var/lib/transmission-daemon/downloads" TRANSMISSION_DIR_MAPPING="{}" # Media path defaults MEDIA_DIR="/mnt/media" ENABLE_BOOK_SORTING=true # Helper function to validate port number validate_port() { local port="$1" if [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ]; then return 0 else return 1 fi } # Helper function to validate URL hostname validate_hostname() { local hostname="$1" if [[ "$hostname" =~ ^[a-zA-Z0-9]([a-zA-Z0-9\-\.]+[a-zA-Z0-9])?$ ]]; then return 0 elif [[ "$hostname" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then return 0 else return 1 fi } function gather_configuration() { log "INFO" "Starting configuration gathering" echo -e "${BOLD}Installation Configuration:${NC}" echo -e "Please provide the following configuration parameters:" echo read -p "Installation directory [$INSTALL_DIR]: " input_install_dir if [ -n "$input_install_dir" ]; then # Validate installation directory if [[ ! "$input_install_dir" =~ ^/ ]]; then log "WARN" "Installation directory must be an absolute path. Using default." else INSTALL_DIR="$input_install_dir" fi fi # Get and validate port while true; do read -p "Web interface port [$PORT]: " input_port if [ -z "$input_port" ]; then break elif validate_port "$input_port"; then PORT="$input_port" break else log "WARN" "Invalid port number. Port must be between 1 and 65535." fi done # Get user read -p "Run as user [$USER]: " input_user if [ -n "$input_user" ]; then # Check if user exists if id "$input_user" &>/dev/null; then USER="$input_user" else log "WARN" "User $input_user does not exist. Using $USER instead." fi fi echo echo -e "${BOLD}Transmission Configuration:${NC}" echo -e "Configure connection to your Transmission client:" echo # Ask if Transmission is remote read -p "Is Transmission running on a remote server? (y/n) [n]: " input_remote if [[ $input_remote =~ ^[Yy]$ ]]; then TRANSMISSION_REMOTE=true # Get and validate hostname while true; do read -p "Remote Transmission host [localhost]: " input_trans_host if [ -z "$input_trans_host" ]; then break elif validate_hostname "$input_trans_host"; then TRANSMISSION_HOST="$input_trans_host" break else log "WARN" "Invalid hostname format." fi done # Get and validate port while true; do read -p "Remote Transmission port [9091]: " input_trans_port if [ -z "$input_trans_port" ]; then break elif validate_port "$input_trans_port"; then TRANSMISSION_PORT="$input_trans_port" break else log "WARN" "Invalid port number. Port must be between 1 and 65535." fi done # Get credentials read -p "Remote Transmission username []: " input_trans_user TRANSMISSION_USER=${input_trans_user:-$TRANSMISSION_USER} # Use read -s for password to avoid showing it on screen read -s -p "Remote Transmission password []: " input_trans_pass echo # Add a newline after the password input if [ -n "$input_trans_pass" ]; then # TODO: In a production environment, consider encrypting this password TRANSMISSION_PASS="$input_trans_pass" fi read -p "Remote Transmission RPC path [/transmission/rpc]: " input_trans_path if [ -n "$input_trans_path" ]; then # Ensure path starts with / for consistency if [[ ! "$input_trans_path" =~ ^/ ]]; then input_trans_path="/$input_trans_path" fi TRANSMISSION_RPC_PATH="$input_trans_path" fi # Configure directory mapping for remote setup echo echo -e "${YELLOW}Directory Mapping Configuration${NC}" echo -e "When using a remote Transmission server, you need to map paths between servers." echo -e "For each directory on the remote server, specify the corresponding local directory." echo # Get remote download directory read -p "Remote Transmission download directory: " REMOTE_DOWNLOAD_DIR REMOTE_DOWNLOAD_DIR=${REMOTE_DOWNLOAD_DIR:-"/var/lib/transmission-daemon/downloads"} # Get local directory that corresponds to remote download directory read -p "Local directory that corresponds to the remote download directory: " LOCAL_DOWNLOAD_DIR LOCAL_DOWNLOAD_DIR=${LOCAL_DOWNLOAD_DIR:-"/mnt/transmission-downloads"} # Create mapping JSON - use proper JSON escaping for directory paths REMOTE_DOWNLOAD_DIR_ESCAPED=$(echo "$REMOTE_DOWNLOAD_DIR" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g') LOCAL_DOWNLOAD_DIR_ESCAPED=$(echo "$LOCAL_DOWNLOAD_DIR" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g') TRANSMISSION_DIR_MAPPING="{\"$REMOTE_DOWNLOAD_DIR_ESCAPED\": \"$LOCAL_DOWNLOAD_DIR_ESCAPED\"}" # Create the local directory if ! mkdir -p "$LOCAL_DOWNLOAD_DIR"; then log "ERROR" "Failed to create local download directory: $LOCAL_DOWNLOAD_DIR" else if ! chown -R "$USER:$USER" "$LOCAL_DOWNLOAD_DIR"; then log "ERROR" "Failed to set permissions on local download directory: $LOCAL_DOWNLOAD_DIR" fi fi # Ask if want to add more mappings while true; do read -p "Add another directory mapping? (y/n) [n]: " add_another if [[ ! $add_another =~ ^[Yy]$ ]]; then break fi read -p "Remote directory path: " remote_dir read -p "Corresponding local directory path: " local_dir if [ -n "$remote_dir" ] && [ -n "$local_dir" ]; then # Escape directory paths for JSON remote_dir_escaped=$(echo "$remote_dir" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g') local_dir_escaped=$(echo "$local_dir" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g') # Update mapping JSON (proper JSON manipulation) # Remove the closing brace, add a comma and the new mapping, then close with brace TRANSMISSION_DIR_MAPPING="${TRANSMISSION_DIR_MAPPING%\}}, \"$remote_dir_escaped\": \"$local_dir_escaped\"}" # Create the local directory if ! mkdir -p "$local_dir"; then log "ERROR" "Failed to create directory: $local_dir" else if ! chown -R "$USER:$USER" "$local_dir"; then log "WARN" "Failed to set permissions on directory: $local_dir" fi log "INFO" "Mapping added: $remote_dir → $local_dir" fi fi done # Set Transmission download dir for configuration TRANSMISSION_DOWNLOAD_DIR=$REMOTE_DOWNLOAD_DIR else read -p "Transmission download directory [/var/lib/transmission-daemon/downloads]: " input_trans_dir if [ -n "$input_trans_dir" ]; then if [[ ! "$input_trans_dir" =~ ^/ ]]; then log "WARN" "Download directory must be an absolute path. Using default." else TRANSMISSION_DOWNLOAD_DIR="$input_trans_dir" fi fi fi echo echo -e "${BOLD}Media Destination Configuration:${NC}" read -p "Media destination base directory [/mnt/media]: " input_media_dir if [ -n "$input_media_dir" ]; then if [[ ! "$input_media_dir" =~ ^/ ]]; then log "WARN" "Media directory must be an absolute path. Using default." else MEDIA_DIR="$input_media_dir" fi fi # Ask about enabling book/magazine sorting echo echo -e "${BOLD}Content Type Configuration:${NC}" read -p "Enable book and magazine sorting? (y/n) [y]: " input_book_sorting if [[ $input_book_sorting =~ ^[Nn]$ ]]; then ENABLE_BOOK_SORTING=false else ENABLE_BOOK_SORTING=true fi # Security configuration echo echo -e "${BOLD}Security Configuration:${NC}" # Ask about enabling authentication read -p "Enable authentication? (y/n) [n]: " input_auth_enabled AUTH_ENABLED=false ADMIN_USERNAME="" ADMIN_PASSWORD="" if [[ $input_auth_enabled =~ ^[Yy]$ ]]; then AUTH_ENABLED=true # Get admin username and password read -p "Admin username [admin]: " input_admin_username ADMIN_USERNAME=${input_admin_username:-"admin"} # Use read -s for password to avoid showing it on screen read -s -p "Admin password: " input_admin_password echo # Add a newline after the password input if [ -z "$input_admin_password" ]; then # Generate a random password if none provided ADMIN_PASSWORD=$(openssl rand -base64 12) echo -e "${YELLOW}Generated random admin password: $ADMIN_PASSWORD${NC}" echo -e "${YELLOW}Please save this password somewhere safe!${NC}" else ADMIN_PASSWORD="$input_admin_password" fi fi # Ask about enabling HTTPS read -p "Enable HTTPS? (requires SSL certificate) (y/n) [n]: " input_https_enabled HTTPS_ENABLED=false SSL_CERT_PATH="" SSL_KEY_PATH="" if [[ $input_https_enabled =~ ^[Yy]$ ]]; then HTTPS_ENABLED=true # Get SSL certificate paths read -p "SSL certificate path: " input_ssl_cert_path if [ -n "$input_ssl_cert_path" ]; then # Check if file exists if [ -f "$input_ssl_cert_path" ]; then SSL_CERT_PATH="$input_ssl_cert_path" else log "WARN" "SSL certificate file not found. HTTPS will be disabled." HTTPS_ENABLED=false fi else log "WARN" "SSL certificate path not provided. HTTPS will be disabled." HTTPS_ENABLED=false fi # Only ask for key if cert was found if [ "$HTTPS_ENABLED" = true ]; then read -p "SSL key path: " input_ssl_key_path if [ -n "$input_ssl_key_path" ]; then # Check if file exists if [ -f "$input_ssl_key_path" ]; then SSL_KEY_PATH="$input_ssl_key_path" else log "WARN" "SSL key file not found. HTTPS will be disabled." HTTPS_ENABLED=false fi else log "WARN" "SSL key path not provided. HTTPS will be disabled." HTTPS_ENABLED=false fi fi fi echo log "INFO" "Configuration gathering complete" echo -e "${GREEN}Configuration complete!${NC}" echo }