diff --git a/install/install_nomad.sh b/install/install_nomad.sh index e67f4e5..a7d12b6 100644 --- a/install/install_nomad.sh +++ b/install/install_nomad.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -euo pipefail # Project N.O.M.A.D. Installation Script @@ -133,7 +134,8 @@ generateRandomPass() { local password # Generate random password using /dev/urandom - password=$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c "$length") + # tr may receive SIGPIPE when head closes early; this is expected behavior + password=$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c "$length" || true) echo "$password" } @@ -337,7 +339,7 @@ setup_nvidia_container_toolkit() { get_install_confirmation(){ echo -e "${YELLOW}#${RESET} This script will install Project N.O.M.A.D. and its dependencies on your machine." echo -e "${YELLOW}#${RESET} If you already have Project N.O.M.A.D. installed with customized config or data, please be aware that running this installation script may overwrite existing files and configurations. It is highly recommended to back up any important data/configs before proceeding." - read -p "Are you sure you want to continue? (y/N): " choice + read -p "Are you sure you want to continue? (y/N): " choice || true case "$choice" in y|Y ) echo -e "${GREEN}#${RESET} User chose to continue with the installation." @@ -358,7 +360,7 @@ accept_terms() { printf "\n" echo "By accepting this agreement, you acknowledge that you have read and understood the terms and conditions of the Apache License 2.0 and agree to be bound by them while using Project N.O.M.A.D." echo -e "\n\n" - read -p "I have read and accept License Agreement & Terms of Use (y/N)? " choice + read -p "I have read and accept License Agreement & Terms of Use (y/N)? " choice || true case "$choice" in y|Y ) accepted_terms='true' @@ -399,18 +401,36 @@ download_management_compose_file() { fi echo -e "${GREEN}#${RESET} Docker compose file downloaded successfully to $compose_file_path.\\n" - local app_key=$(generateRandomPass) - local db_root_password=$(generateRandomPass) - local db_user_password=$(generateRandomPass) + local app_key + local db_root_password + local db_user_password + app_key=$(generateRandomPass) + db_root_password=$(generateRandomPass) + db_user_password=$(generateRandomPass) # Inject dynamic env values into the compose file + # Escape sed special characters in variables to prevent injection + # Using '#' as sed delimiter to avoid conflicts with '/' in URLs and IPs + # Escaping &, \, #, and . (regex special) in both patterns and replacements echo -e "${YELLOW}#${RESET} Configuring docker-compose file env variables...\\n" - sed -i "s|URL=replaceme|URL=http://${local_ip_address}:8080|g" "$compose_file_path" - sed -i "s|APP_KEY=replaceme|APP_KEY=${app_key}|g" "$compose_file_path" - - sed -i "s|DB_PASSWORD=replaceme|DB_PASSWORD=${db_user_password}|g" "$compose_file_path" - sed -i "s|MYSQL_ROOT_PASSWORD=replaceme|MYSQL_ROOT_PASSWORD=${db_root_password}|g" "$compose_file_path" - sed -i "s|MYSQL_PASSWORD=replaceme|MYSQL_PASSWORD=${db_user_password}|g" "$compose_file_path" + + # Escape function for sed replacement strings (using '#' as delimiter) + # Escapes: backslash, ampersand, hash (our delimiter), and newline + sed_escape_replacement() { + printf '%s\n' "$1" | sed 's/[&#\\/]/\\&/g' + } + + local escaped_ip escaped_app_key escaped_db_user_password escaped_db_root_password + escaped_ip=$(sed_escape_replacement "${local_ip_address}") + escaped_app_key=$(sed_escape_replacement "${app_key}") + escaped_db_user_password=$(sed_escape_replacement "${db_user_password}") + escaped_db_root_password=$(sed_escape_replacement "${db_root_password}") + + sed -i "s#URL=replaceme#URL=http://${escaped_ip}:8080#g" "$compose_file_path" + sed -i "s#APP_KEY=replaceme#APP_KEY=${escaped_app_key}#g" "$compose_file_path" + sed -i "s#DB_PASSWORD=replaceme#DB_PASSWORD=${escaped_db_user_password}#g" "$compose_file_path" + sed -i "s#MYSQL_ROOT_PASSWORD=replaceme#MYSQL_ROOT_PASSWORD=${escaped_db_root_password}#g" "$compose_file_path" + sed -i "s#MYSQL_PASSWORD=replaceme#MYSQL_PASSWORD=${escaped_db_user_password}#g" "$compose_file_path" echo -e "${GREEN}#${RESET} Docker compose file configured successfully.\\n" } diff --git a/install/sidecar-updater/update-watcher.sh b/install/sidecar-updater/update-watcher.sh index fbb515d..6cda1a3 100644 --- a/install/sidecar-updater/update-watcher.sh +++ b/install/sidecar-updater/update-watcher.sh @@ -42,6 +42,12 @@ perform_update() { sleep 1 # Apply target image tag to compose.yml before pulling + # Validate target_tag contains only safe characters (alphanumeric, dots, hyphens, underscores) + if ! echo "$target_tag" | grep -qE '^[a-zA-Z0-9._-]+$'; then + log "ERROR: Invalid target tag '${target_tag}' - contains unsafe characters" + write_status "error" 0 "Invalid target tag - contains unsafe characters" + return 1 + fi log "Applying image tag '${target_tag}' to compose.yml..." if sed -i "s|\(image: ghcr\.io/crosstalk-solutions/project-nomad\):.*|\1:${target_tag}|" "$COMPOSE_FILE" 2>> "$LOG_FILE"; then log "Successfully updated compose.yml admin image tag to '${target_tag}'" @@ -78,7 +84,7 @@ perform_update() { for service in $SERVICES_TO_UPDATE; do log "Updating service: $service" - write_status "recreating" $current_progress "Recreating $service..." + write_status "recreating" "$current_progress" "Recreating $service..." # Stop the service log " Stopping $service..." @@ -94,7 +100,7 @@ perform_update() { log " ✓ Successfully recreated $service" else log " ERROR: Failed to recreate $service" - write_status "error" $current_progress "Failed to recreate $service - check logs" + write_status "error" "$current_progress" "Failed to recreate $service - check logs" return 1 fi diff --git a/install/start_nomad.sh b/install/start_nomad.sh index f17f805..f8c0e4b 100644 --- a/install/start_nomad.sh +++ b/install/start_nomad.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -euo pipefail echo "Finding Project N.O.M.A.D containers..." diff --git a/install/stop_nomad.sh b/install/stop_nomad.sh index 5d46289..1ede6cd 100644 --- a/install/stop_nomad.sh +++ b/install/stop_nomad.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -euo pipefail echo "Finding running Docker containers for Project N.O.M.A.D..." diff --git a/install/update_nomad.sh b/install/update_nomad.sh index 4e35528..f2ce520 100644 --- a/install/update_nomad.sh +++ b/install/update_nomad.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -euo pipefail # Project N.O.M.A.D. Update Script @@ -22,6 +23,15 @@ GRAY_R='\033[39m' RED='\033[1;31m' # Light Red. GREEN='\033[1;32m' # Light Green. +################################################################################################################################################################################################### +# # +# Constants & Variables # +# # +################################################################################################################################################################################################### + +NOMAD_DIR="/opt/project-nomad" +local_ip_address='' + ################################################################################################################################################################################################### # # # Functions # @@ -61,7 +71,7 @@ check_is_debian_based() { } get_update_confirmation(){ - read -p "This script will update Project N.O.M.A.D. and its dependencies on your machine. No data loss is expected, but you should always back up your data before proceeding. Are you sure you want to continue? (y/n): " choice + read -p "This script will update Project N.O.M.A.D. and its dependencies on your machine. No data loss is expected, but you should always back up your data before proceeding. Are you sure you want to continue? (y/n): " choice || true case "$choice" in y|Y ) echo -e "${GREEN}#${RESET} User chose to continue with the update." @@ -136,7 +146,7 @@ get_local_ip() { success_message() { echo -e "${GREEN}#${RESET} Project N.O.M.A.D installation completed successfully!\\n" echo -e "${GREEN}#${RESET} Installation files are located at /opt/project-nomad\\n\n" - echo -e "${GREEN}#${RESET} Project N.O.M.A.D's Command Center should automatically start whenever your device reboots. However, if you need to start it manually, you can always do so by running: ${WHITE_R}${nomad_dir}/start_nomad.sh${RESET}\\n" + echo -e "${GREEN}#${RESET} Project N.O.M.A.D's Command Center should automatically start whenever your device reboots. However, if you need to start it manually, you can always do so by running: ${WHITE_R}${NOMAD_DIR}/start_nomad.sh${RESET}\\n" echo -e "${GREEN}#${RESET} You can now access the management interface at http://localhost:8080 or http://${local_ip_address}:8080\\n" echo -e "${GREEN}#${RESET} Thank you for supporting Project N.O.M.A.D!\\n" }