diff --git a/packages/server-shell-setup/install-shell.sh b/packages/server-shell-setup/install-shell.sh index c1a7702..ea72f54 100644 --- a/packages/server-shell-setup/install-shell.sh +++ b/packages/server-shell-setup/install-shell.sh @@ -6,11 +6,11 @@ # Use interactive menu to install top dev tools and shell. # Systems Supported: Android (Termux), macOS, Ubuntu/Debian, Fedora, Arch, Alpine # -# Usage: bash -c "$( wget -q https://raw.githubusercontent.com/OpenSourceAGI/appdemo-starter-template/refs/heads/master/packages/server-shell-setup/install-shell.sh -O -)" -# Headless: -# wget -qO- https://raw.githubusercontent.com/OpenSourceAGI/appdemo-starter-template/refs/heads/master/packages/server-shell-setup/install-shell.sh | bash -s -- "all" +# Usage: wget -qO- https://raw.githubusercontent.com/OpenSourceAGI/starter-app-dev-tools/refs/heads/master/packages/server-shell-setup/install-shell.sh | bash +# Headless: +# wget -qO- https://raw.githubusercontent.com/OpenSourceAGI/starter-app-dev-tools/refs/heads/master/packages/server-shell-setup/install-shell.sh | bash -s -- "all" # SSH With Password: -# wget -qO- https://raw.githubusercontent.com/OpenSourceAGI/appdemo-starter-template/refs/heads/master/packages/server-shell-setup/install-shell.sh | bash -s -- ssh +# wget -qO- https://raw.githubusercontent.com/OpenSourceAGI/starter-app-dev-tools/refs/heads/master/packages/server-shell-setup/install-shell.sh | bash -s -- ssh # Available components: # - fish: Modern shell with auto-suggestions and improved syntax highlighting # - nushell: Data-oriented shell with structured data handling @@ -330,9 +330,11 @@ end - # Add apt install as in + # Add setup function to re-run this installer. + # Must be fish syntax: bash-style "$( ... )" makes fish error with + # "command substitutions not allowed here", so pipe to bash instead. echo 'function setup - bash -c "$( wget -q https://raw.githubusercontent.com/vtempest/server-shell-setup/refs/heads/master/install-shell.sh -O -)" + wget -qO- https://raw.githubusercontent.com/OpenSourceAGI/starter-app-dev-tools/refs/heads/master/packages/server-shell-setup/install-shell.sh | bash end' >~/.config/fish/functions/setup.fish @@ -579,13 +581,24 @@ install_node() { bash -c "$(curl -fsSL https://get.volta.sh)" - # Source bashrc to make volta available - source ~/.bashrc + # Make Volta available in the current session. + # Sourcing ~/.bashrc does not work here: in non-interactive shells + # (e.g. piped "wget ... | bash") .bashrc returns before Volta's + # PATH exports, leaving npm/node unavailable for the rest of the script. + export VOLTA_HOME="$HOME/.volta" + export PATH="$VOLTA_HOME/bin:$PATH" + + volta install node - ~/.volta/bin/volta install node - # print_success "Node.js installed with Volta" + if command_exists fish; then + fish -c "fish_add_path ~/.volta/bin" + fi - fish -c "fish_add_path ~/.volta/bin" + if command_exists node && command_exists npm; then + print_success "Node.js $(node -v) installed with Volta (npm $(npm -v))" + else + print_error "Node.js installation failed: node/npm not found on PATH" + fi fi @@ -602,9 +615,22 @@ install_bun() { print_header "Installing Bun" print_msg "$YELLOW" "Bun is a fast JavaScript runtime, bundler, transpiler and package manager" - bash -c "$(curl -fsSL https://bun.sh/install)" + curl -fsSL https://bun.sh/install | bash + + # The installer only updates shell profiles; export for the current + # session and register with fish so bun is usable immediately. + export BUN_INSTALL="$HOME/.bun" + export PATH="$BUN_INSTALL/bin:$PATH" - print_success "Bun installed" + if command_exists fish; then + fish -c "fish_add_path ~/.bun/bin" + fi + + if command_exists bun; then + print_success "Bun $(bun --version) installed" + else + print_error "Bun installation failed: bun not found on PATH" + fi } @@ -747,6 +773,67 @@ install_systeminfo() { print_success "System info greeting installed" } +# Check that root and user passwords are set; offer to set them if not. +# Passwords entered here are kept in ROOT_PASS/USER_PASS and reused by the +# rest of the script (sudo credential cache, ssh setup) so the user only +# types them once. +check_passwords() { + CURRENT_USER=$(whoami) + + # Cache sudo credentials first; passwd -S needs root to read /etc/shadow + sudo -v 2>/dev/null + + local root_status user_status + root_status=$(sudo passwd -S root 2>/dev/null | awk '{print $2}') + user_status=$(sudo passwd -S "$CURRENT_USER" 2>/dev/null | awk '{print $2}') + + # Second field of passwd -S: P/PS = password set, L/LK = locked, NP = none + if [[ "$root_status" == P* && "$user_status" == P* ]]; then + return + fi + + print_header "Account Password Setup" + [[ "$root_status" != P* ]] && print_msg "$YELLOW" "The root password is not set." + [[ "$user_status" != P* ]] && print_msg "$YELLOW" "The password for ${CURRENT_USER} is not set." + print_msg "$YELLOW" "Root and user passwords need to be set before continuing." + + # -e /dev/tty is true even without a controlling terminal; test opening it + if ! { : < /dev/tty; } 2>/dev/null; then + print_error "No terminal available to enter a password. Set them manually with: sudo passwd root && sudo passwd ${CURRENT_USER}" + return + fi + + local same_pass + read -rp "Use the same password for both root and ${CURRENT_USER}? [Y/n]: " same_pass < /dev/tty + + if [[ "$same_pass" =~ ^[Nn] ]]; then + read -srp "Enter new root password: " ROOT_PASS < /dev/tty + echo "" + read -srp "Enter new password for ${CURRENT_USER}: " USER_PASS < /dev/tty + echo "" + else + read -srp "Enter new password (used for both root and ${CURRENT_USER}): " USER_PASS < /dev/tty + echo "" + ROOT_PASS="$USER_PASS" + fi + + if [ -z "$USER_PASS" ]; then + print_error "Empty password entered; skipping password setup" + return + fi + + if [[ "$root_status" != P* ]]; then + echo "root:${ROOT_PASS}" | sudo chpasswd && print_success "Root password set" + fi + if [[ "$user_status" != P* ]]; then + echo "${CURRENT_USER}:${USER_PASS}" | sudo chpasswd && print_success "Password set for ${CURRENT_USER}" + fi + + # Refresh the sudo credential cache with the new password so the rest + # of the script can keep using sudo without prompting again + echo "$USER_PASS" | sudo -S -v 2>/dev/null +} + # Enable sudo without password enable_sudo_without_password() { print_header "Enable Sudo Without Password" @@ -884,29 +971,37 @@ install_components() { # Enable SSH with password authentication -# enable_ssh_with_password() { -# print_header "Enabling SSH with Password Authentication" -# print_msg "$YELLOW" "This is useful for AWS EC2 instances where password authentication is disabled by default" +enable_ssh_with_password() { + print_header "Enabling SSH with Password Authentication" + print_msg "$YELLOW" "This is useful for AWS EC2 instances where password authentication is disabled by default" -# read -p "Enter root password: " ROOT_PASS -# read -p "Enter user password: " USER_PASS -# read -p "Enter username: " USER + CURRENT_USER=$(whoami) + + # Reuse passwords collected by check_passwords; only prompt if missing + if [ -z "$ROOT_PASS" ]; then + read -srp "Enter root password: " ROOT_PASS < /dev/tty + echo "" + fi + if [ -z "$USER_PASS" ]; then + read -srp "Enter password for ${CURRENT_USER}: " USER_PASS < /dev/tty + echo "" + fi -# echo "root:$ROOT_PASS" | sudo chpasswd -# echo "$USER:$USER_PASS" | sudo chpasswd + echo "root:${ROOT_PASS}" | sudo chpasswd + echo "${CURRENT_USER}:${USER_PASS}" | sudo chpasswd -# sudo sed -re 's/^#?[[:space:]]*(PasswordAuthentication)[[:space:]]+no/\1 yes/' -i.bak /etc/ssh/sshd_config + sudo sed -re 's/^#?[[:space:]]*(PasswordAuthentication)[[:space:]]+no/\1 yes/' -i.bak /etc/ssh/sshd_config -# if [ -d "/etc/ssh/sshd_config.d/" ]; then -# for file in /etc/ssh/sshd_config.d/*; do -# sudo sed -re 's/^#?[[:space:]]*(PasswordAuthentication)[[:space:]]+no/\1 yes/' -i.bak "$file" -# done -# fi + if [ -d "/etc/ssh/sshd_config.d/" ]; then + for file in /etc/ssh/sshd_config.d/*; do + sudo sed -re 's/^#?[[:space:]]*(PasswordAuthentication)[[:space:]]+no/\1 yes/' -i.bak "$file" + done + fi -# sudo service ssh restart 2>/dev/null || sudo service sshd restart + sudo service ssh restart 2>/dev/null || sudo service sshd restart -# print_success "SSH password authentication enabled" -# } + print_success "SSH password authentication enabled" +} # Main function @@ -918,6 +1013,9 @@ main() { # exit 1 # fi + # Verify root/user passwords are set before installing anything + check_passwords + # Non-interactive mode with command line arguments if [ -n "$1" ]; then parse_args "$1"