From 61e90b47b0ab143ea5df30034752d83b294432ea Mon Sep 17 00:00:00 2001 From: Brian Zalewski <59970525+ProfessorManhattan@users.noreply.github.com> Date: Mon, 13 Nov 2023 04:53:44 +0000 Subject: [PATCH] Latest --- scripts/cloudflared-ssh.sh | 213 ++++++++--- scripts/homebrew.sh | 73 ++-- scripts/partials/basic-deps | 78 ++-- scripts/partials/homebrew | 78 ++-- scripts/partials/logg | 7 +- scripts/pfsense.sh | 116 ++++++ scripts/provision.sh | 574 ++++++++++++++++------------ scripts/src/cloudflared-ssh.sh.tmpl | 6 +- scripts/src/homebrew.sh.tmpl | 2 +- scripts/src/pfsense.sh.tmpl | 4 +- scripts/src/provision.sh.tmpl | 10 +- 11 files changed, 731 insertions(+), 430 deletions(-) create mode 100644 scripts/pfsense.sh diff --git a/scripts/cloudflared-ssh.sh b/scripts/cloudflared-ssh.sh index b61c2b1e..396fd772 100644 --- a/scripts/cloudflared-ssh.sh +++ b/scripts/cloudflared-ssh.sh @@ -34,77 +34,164 @@ # setup and updates are applied using this script (via a cronjob that does not need to run initialization tasks during # the cronjobs). # +# ## TODO +# +# * Automatically add UFW exceptions using [this script](https://github.com/Paul-Reed/cloudflare-ufw) +# # ## Links # # [SSH with short-lived certificates](https://developers.cloudflare.com/cloudflare-one/tutorials/ssh-cert-bastion/) -# @description Ensure dependencies like `git` and `curl` are installed (among a few other lightweight system packages) -if ! command -v curl > /dev/null || ! command -v git > /dev/null || ! command -v expect > /dev/null || ! command -v rsync > /dev/null; then - if command -v apt-get > /dev/null; then - # @description Ensure `build-essential`, `curl`, `expect`, `git`, and `rsync` are installed on Debian / Ubuntu - sudo apt-get update - sudo apt-get install -y build-essential curl expect git rsync - elif command -v dnf > /dev/null; then - # @description Ensure `curl`, `expect`, `git`, and `rsync` are installed on Fedora - sudo dnf install -y curl expect git rsync - elif command -v yum > /dev/null; then - # @description Ensure `curl`, `expect`, `git`, and `rsync` are installed on CentOS - sudo yum install -y curl expect git rsync - elif command -v pacman > /dev/null; then - # @description Ensure `curl`, `expect`, `git`, and `rsync` are installed on Archlinux - sudo pacman update - sudo pacman -Sy curl expect git rsync - elif command -v zypper > /dev/null; then - # @description Ensure `curl`, `expect`, `git`, and `rsync` are installed on OpenSUSE - sudo zypper install -y curl expect git rsync - elif command -v apk > /dev/null; then - # @description Ensure `curl`, `expect`, `git`, and `rsync` are installed on Alpine - apk add curl expect git rsync - elif [ -d /Applications ] && [ -d /Library ]; then - # @description Ensure CLI developer tools are available on macOS (via `xcode-select`) - sudo xcode-select -p >/dev/null 2>&1 || xcode-select --install - elif [[ "$OSTYPE" == 'cygwin' ]] || [[ "$OSTYPE" == 'msys' ]] || [[ "$OSTYPE" == 'win32' ]]; then - # @description Ensure `curl`, `expect`, `git`, and `rsync` are installed on Windows - choco install -y curl expect git rsync - fi -fi - -# @description Ensure Homebrew is installed and available in the `PATH` -if ! command -v brew > /dev/null; then - if [ -d /home/linuxbrew/.linuxbrew/bin ]; then - eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv) - if ! command -v brew > /dev/null; then - echo "The /home/linuxbrew/.linuxbrew directory exists but something is not right. Try removing it and running the script again." && exit 1 - fi +# @description Logs with style using Gum if it is installed, otherwise it uses `echo`. It also leverages Glow to render markdown. +# When Glow is not installed, it uses `cat`. +# @example +# logger info "An informative log" +logg() { + TYPE="$1" + MSG="$2" + if [ "$TYPE" == 'error' ]; then + if command -v gum > /dev/null; then + gum style --border="thick" "$(gum style --foreground="#ff0000" "✖") $(gum style --bold --background="#ff0000" --foreground="#ffffff" " ERROR ") $(gum style --bold "$MSG")" else - # @description Installs Homebrew and addresses a couple potential issues - if command -v sudo > /dev/null && sudo -n true; then - echo | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - else - echo "Homebrew is not installed. The script will attempt to install Homebrew and you might be prompted for your password." - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || BREW_EXIT_CODE="$?" - if [ -n "$BREW_EXIT_CODE" ]; then - if command -v brew > /dev/null; then - echo "Homebrew was installed but part of the installation failed. Trying a few things to fix the installation.." - BREW_DIRS="share/man share/doc share/zsh/site-functions etc/bash_completion.d" - for BREW_DIR in $BREW_DIRS; do - if [ -d "$(brew --prefix)/$BREW_DIR" ]; then - sudo chown -R "$(whoami)" "$(brew --prefix)/$BREW_DIR" - fi - done - brew update --force --quiet - fi - fi - fi - - # @description Ensures the `brew` binary is available on Linux machines. macOS installs `brew` into the default `PATH` - # so nothing needs to be done for macOS. - if [ -d /home/linuxbrew/.linuxbrew/bin ]; then - eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv) - fi + echo "ERROR: $MSG" fi + elif [ "$TYPE" == 'info' ]; then + if command -v gum > /dev/null; then + gum style " $(gum style --foreground="#00ffff" "○") $(gum style --faint "$MSG")" + else + echo "INFO: $MSG" + fi + elif [ "$TYPE" == 'md' ]; then + if command -v glow > /dev/null; then + glow "$MSG" + else + cat "$MSG" + fi + elif [ "$TYPE" == 'prompt' ]; then + if command -v gum > /dev/null; then + gum style " $(gum style --foreground="#00008b" "▶") $(gum style --bold "$MSG")" + else + echo "PROMPT: $MSG" + fi + elif [ "$TYPE" == 'star' ]; then + if command -v gum > /dev/null; then + gum style " $(gum style --foreground="#d1d100" "◆") $(gum style --bold "$MSG")" + else + echo "STAR: $MSG" + fi + elif [ "$TYPE" == 'start' ]; then + if command -v gum > /dev/null; then + gum style " $(gum style --foreground="#00ff00" "▶") $(gum style --bold "$MSG")" + else + echo "START: $MSG" + fi + elif [ "$TYPE" == 'success' ]; then + if command -v gum > /dev/null; then + gum style "$(gum style --foreground="#00ff00" "✔") $(gum style --bold "$MSG")" + else + echo "SUCCESS: $MSG" + fi + elif [ "$TYPE" == 'warn' ]; then + if command -v gum > /dev/null; then + gum style " $(gum style --foreground="#d1d100" "◆") $(gum style --bold --background="#ffff00" --foreground="#000000" " WARNING ") $(gum style --bold "$MSG")" + else + echo "WARNING: $MSG" + fi + else + if command -v gum > /dev/null; then + gum style " $(gum style --foreground="#00ff00" "▶") $(gum style --bold "$TYPE")" + else + echo "$MSG" + fi + fi +} +# @description Ensure dependencies like `git` and `curl` are installed (among a few other lightweight system packages) +if ! command -v curl > /dev/null || ! command -v git > /dev/null || ! command -v expect > /dev/null || ! command -v rsync > /dev/null || ! command -v unbuffer; then + if command -v apt-get > /dev/null; then + ### Debian / Ubuntu + logg info 'Running sudo apt-get update' && sudo apt-get update + logg info 'Running sudo apt-get install -y build-essential curl expect git rsync' && sudo apt-get install -y build-essential curl expect git rsync + elif command -v dnf > /dev/null; then + ### Fedora + logg info 'Running sudo dnf install -y curl expect git rsync' && sudo dnf install -y curl expect git rsync + elif command -v yum > /dev/null; then + ### CentOS + logg info 'Running sudo yum install -y curl expect git rsync' && sudo yum install -y curl expect git rsync + elif command -v pacman > /dev/null; then + ### Archlinux + logg info 'Running sudo pacman update' && sudo pacman update + logg info 'Running sudo pacman -Syu base-devel curl expect git rsync procps-ng file' && sudo pacman -Syu base-devel curl expect git rsync procps-ng file + elif command -v zypper > /dev/null; then + ### OpenSUSE + logg info 'Running sudo zypper install -y curl expect git rsync' && sudo zypper install -y curl expect git rsync + elif command -v apk > /dev/null; then + ### Alpine + logg info 'Running apk add curl expect git rsync' && apk add curl expect git rsync + elif [ -d /Applications ] && [ -d /Library ]; then + ### macOS + logg info 'Running sudo xcode-select -p >/dev/null 2>&1 || xcode-select --install' && sudo xcode-select -p >/dev/null 2>&1 || xcode-select --install + elif [[ "$OSTYPE" == 'cygwin' ]] || [[ "$OSTYPE" == 'msys' ]] || [[ "$OSTYPE" == 'win32' ]]; then + ### Windows + logg info 'Running choco install -y curl expect git rsync' && choco install -y curl expect git rsync + elif command -v nix-env > /dev/null; then + ### NixOS + logg warn "TODO - Add support for NixOS" + elif [[ "$OSTYPE" == 'freebsd'* ]]; then + ### FreeBSD + logg warn "TODO - Add support for FreeBSD" + elif command -v pkg > /dev/null; then + ### Termux + logg warn "TODO - Add support for Termux" + elif command -v xbps-install > /dev/null; then + ### Void + logg warn "TODO - Add support for Void" + fi +fi# @description Ensure Homebrew is installed and available in the `PATH` +if ! command -v brew > /dev/null; then + if [ -d /home/linuxbrew/.linuxbrew/bin ]; then + logg info "Sourcing from /home/linuxbrew/.linuxbrew/bin/brew" && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + if ! command -v brew > /dev/null; then + logg error "The /home/linuxbrew/.linuxbrew directory exists but something is not right. Try removing it and running the script again." && exit 1 + fi + else + ### Installs Homebrew and addresses a couple potential issues + if command -v sudo > /dev/null && sudo -n true; then + logg info "Installing Homebrew" + echo | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + else + logg info "Homebrew is not installed. The script will attempt to install Homebrew and you might be prompted for your password." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || BREW_EXIT_CODE="$?" + if [ -n "$BREW_EXIT_CODE" ]; then + if command -v brew > /dev/null; then + logg warn "Homebrew was installed but part of the installation failed. Trying a few things to fix the installation.." + BREW_DIRS="share/man share/doc share/zsh/site-functions etc/bash_completion.d" + for BREW_DIR in $BREW_DIRS; do + if [ -d "$(brew --prefix)/$BREW_DIR" ]; then + logg info "Chowning $(brew --prefix)/$BREW_DIR" && sudo chown -R "$(whoami)" "$(brew --prefix)/$BREW_DIR" + fi + done + logg info "Running brew update --force --quiet" && brew update --force --quiet && logg success "Successfully ran brew update --force --quiet" + fi + fi + fi + + ### Ensures the `brew` binary is available on Linux machines. macOS installs `brew` into the default `PATH` so nothing needs to be done for macOS. + if [ -d /home/linuxbrew/.linuxbrew/bin ]; then + logg info "Sourcing shellenv from /home/linuxbrew/.linuxbrew/bin/brew" && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + elif [ -f /opt/homebrew/bin/brew ]; then + logg info "Sourcing shellenv from /opt/homebrew/bin/brew" && eval "$(/opt/homebrew/bin/brew shellenv)" + fi + fi fi +### Ensure GCC is installed via Homebrew +if command -v brew > /dev/null; then + if ! brew list | grep gcc > /dev/null; then + logg info "Installing Homebrew gcc" && brew install gcc + fi +else + logg error "Failed to initialize Homebrew" && exit 2 +fi # @description Ensures `cloudflared` is installed via Homebrew if ! command -v cloudflared > /dev/null; then brew install cloudflared diff --git a/scripts/homebrew.sh b/scripts/homebrew.sh index 633118e1..c4fe0fe3 100644 --- a/scripts/homebrew.sh +++ b/scripts/homebrew.sh @@ -12,36 +12,47 @@ # **Note**: `https://install.doctor/brew` points to this file. if ! command -v brew > /dev/null; then - if [ -d /home/linuxbrew/.linuxbrew/bin ]; then - eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv) - if ! command -v brew > /dev/null; then - echo "The /home/linuxbrew/.linuxbrew directory exists but something is not right. Try removing it and running the script again." && exit 1 - fi - else - # @description Installs Homebrew and addresses a couple potential issues - if command -v sudo > /dev/null && sudo -n true; then - echo | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - else - echo "Homebrew is not installed. The script will attempt to install Homebrew and you might be prompted for your password." - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || BREW_EXIT_CODE="$?" - if [ -n "$BREW_EXIT_CODE" ]; then - if command -v brew > /dev/null; then - echo "Homebrew was installed but part of the installation failed. Trying a few things to fix the installation.." - BREW_DIRS="share/man share/doc share/zsh/site-functions etc/bash_completion.d" - for BREW_DIR in $BREW_DIRS; do - if [ -d "$(brew --prefix)/$BREW_DIR" ]; then - sudo chown -R "$(whoami)" "$(brew --prefix)/$BREW_DIR" - fi - done - brew update --force --quiet - fi - fi - fi - - # @description Ensures the `brew` binary is available on Linux machines. macOS installs `brew` into the default `PATH` - # so nothing needs to be done for macOS. - if [ -d /home/linuxbrew/.linuxbrew/bin ]; then - eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv) - fi + if [ -d /home/linuxbrew/.linuxbrew/bin ]; then + logg info "Sourcing from /home/linuxbrew/.linuxbrew/bin/brew" && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + if ! command -v brew > /dev/null; then + logg error "The /home/linuxbrew/.linuxbrew directory exists but something is not right. Try removing it and running the script again." && exit 1 fi + else + ### Installs Homebrew and addresses a couple potential issues + if command -v sudo > /dev/null && sudo -n true; then + logg info "Installing Homebrew" + echo | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + else + logg info "Homebrew is not installed. The script will attempt to install Homebrew and you might be prompted for your password." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || BREW_EXIT_CODE="$?" + if [ -n "$BREW_EXIT_CODE" ]; then + if command -v brew > /dev/null; then + logg warn "Homebrew was installed but part of the installation failed. Trying a few things to fix the installation.." + BREW_DIRS="share/man share/doc share/zsh/site-functions etc/bash_completion.d" + for BREW_DIR in $BREW_DIRS; do + if [ -d "$(brew --prefix)/$BREW_DIR" ]; then + logg info "Chowning $(brew --prefix)/$BREW_DIR" && sudo chown -R "$(whoami)" "$(brew --prefix)/$BREW_DIR" + fi + done + logg info "Running brew update --force --quiet" && brew update --force --quiet && logg success "Successfully ran brew update --force --quiet" + fi + fi + fi + + ### Ensures the `brew` binary is available on Linux machines. macOS installs `brew` into the default `PATH` so nothing needs to be done for macOS. + if [ -d /home/linuxbrew/.linuxbrew/bin ]; then + logg info "Sourcing shellenv from /home/linuxbrew/.linuxbrew/bin/brew" && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + elif [ -f /opt/homebrew/bin/brew ]; then + logg info "Sourcing shellenv from /opt/homebrew/bin/brew" && eval "$(/opt/homebrew/bin/brew shellenv)" + fi + fi +fi + +### Ensure GCC is installed via Homebrew +if command -v brew > /dev/null; then + if ! brew list | grep gcc > /dev/null; then + logg info "Installing Homebrew gcc" && brew install gcc + fi +else + logg error "Failed to initialize Homebrew" && exit 2 fi diff --git a/scripts/partials/basic-deps b/scripts/partials/basic-deps index 6fb8f010..14fe2b64 100644 --- a/scripts/partials/basic-deps +++ b/scripts/partials/basic-deps @@ -1,41 +1,41 @@ if ! command -v curl > /dev/null || ! command -v git > /dev/null || ! command -v expect > /dev/null || ! command -v rsync > /dev/null || ! command -v unbuffer; then - if command -v apt-get > /dev/null; then - ### Debian / Ubuntu - sudo apt-get update - sudo apt-get install -y build-essential curl expect git rsync - elif command -v dnf > /dev/null; then - ### Fedora - sudo dnf install -y curl expect git rsync - elif command -v yum > /dev/null; then - ### CentOS - sudo yum install -y curl expect git rsync - elif command -v pacman > /dev/null; then - ### Archlinux - sudo pacman update - sudo pacman -Syu base-devel curl expect git rsync procps-ng file - elif command -v zypper > /dev/null; then - ### OpenSUSE - sudo zypper install -y curl expect git rsync - elif command -v apk > /dev/null; then - ### Alpine - apk add curl expect git rsync - elif [ -d /Applications ] && [ -d /Library ]; then - ### macOS - sudo xcode-select -p >/dev/null 2>&1 || xcode-select --install - elif [[ "$OSTYPE" == 'cygwin' ]] || [[ "$OSTYPE" == 'msys' ]] || [[ "$OSTYPE" == 'win32' ]]; then - ### Windows - choco install -y curl expect git rsync - elif command -v nix-env > /dev/null; then - ### NixOS - echo "TODO - Add support for NixOS" - elif [[ "$OSTYPE" == 'freebsd'* ]]; then - ### FreeBSD - echo "TODO - Add support for FreeBSD" - elif command -v pkg > /dev/null; then - ### Termux - echo "TODO - Add support for Termux" - elif command -v xbps-install > /dev/null; then - ### Void - echo "TODO - Add support for Void" - fi + if command -v apt-get > /dev/null; then + ### Debian / Ubuntu + logg info 'Running sudo apt-get update' && sudo apt-get update + logg info 'Running sudo apt-get install -y build-essential curl expect git rsync' && sudo apt-get install -y build-essential curl expect git rsync + elif command -v dnf > /dev/null; then + ### Fedora + logg info 'Running sudo dnf install -y curl expect git rsync' && sudo dnf install -y curl expect git rsync + elif command -v yum > /dev/null; then + ### CentOS + logg info 'Running sudo yum install -y curl expect git rsync' && sudo yum install -y curl expect git rsync + elif command -v pacman > /dev/null; then + ### Archlinux + logg info 'Running sudo pacman update' && sudo pacman update + logg info 'Running sudo pacman -Syu base-devel curl expect git rsync procps-ng file' && sudo pacman -Syu base-devel curl expect git rsync procps-ng file + elif command -v zypper > /dev/null; then + ### OpenSUSE + logg info 'Running sudo zypper install -y curl expect git rsync' && sudo zypper install -y curl expect git rsync + elif command -v apk > /dev/null; then + ### Alpine + logg info 'Running apk add curl expect git rsync' && apk add curl expect git rsync + elif [ -d /Applications ] && [ -d /Library ]; then + ### macOS + logg info 'Running sudo xcode-select -p >/dev/null 2>&1 || xcode-select --install' && sudo xcode-select -p >/dev/null 2>&1 || xcode-select --install + elif [[ "$OSTYPE" == 'cygwin' ]] || [[ "$OSTYPE" == 'msys' ]] || [[ "$OSTYPE" == 'win32' ]]; then + ### Windows + logg info 'Running choco install -y curl expect git rsync' && choco install -y curl expect git rsync + elif command -v nix-env > /dev/null; then + ### NixOS + logg warn "TODO - Add support for NixOS" + elif [[ "$OSTYPE" == 'freebsd'* ]]; then + ### FreeBSD + logg warn "TODO - Add support for FreeBSD" + elif command -v pkg > /dev/null; then + ### Termux + logg warn "TODO - Add support for Termux" + elif command -v xbps-install > /dev/null; then + ### Void + logg warn "TODO - Add support for Void" + fi fi \ No newline at end of file diff --git a/scripts/partials/homebrew b/scripts/partials/homebrew index a2595761..5075ff9a 100644 --- a/scripts/partials/homebrew +++ b/scripts/partials/homebrew @@ -1,45 +1,45 @@ if ! command -v brew > /dev/null; then - if [ -d /home/linuxbrew/.linuxbrew/bin ]; then - logg info "Sourcing from /home/linuxbrew/.linuxbrew/bin/brew" && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - if ! command -v brew > /dev/null; then - logg error "The /home/linuxbrew/.linuxbrew directory exists but something is not right. Try removing it and running the script again." && exit 1 - fi - else - ### Installs Homebrew and addresses a couple potential issues - if command -v sudo > /dev/null && sudo -n true; then - logg info "Installing Homebrew" - echo | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - else - logg info "Homebrew is not installed. The script will attempt to install Homebrew and you might be prompted for your password." - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || BREW_EXIT_CODE="$?" - if [ -n "$BREW_EXIT_CODE" ]; then - if command -v brew > /dev/null; then - logg warn "Homebrew was installed but part of the installation failed. Trying a few things to fix the installation.." - BREW_DIRS="share/man share/doc share/zsh/site-functions etc/bash_completion.d" - for BREW_DIR in $BREW_DIRS; do - if [ -d "$(brew --prefix)/$BREW_DIR" ]; then - logg info "Chowning $(brew --prefix)/$BREW_DIR" && sudo chown -R "$(whoami)" "$(brew --prefix)/$BREW_DIR" - fi - done - logg info "Running brew update --force --quiet" && brew update --force --quiet && logg success "Successfully ran brew update --force --quiet" - fi - fi - fi - - ### Ensures the `brew` binary is available on Linux machines. macOS installs `brew` into the default `PATH` - # so nothing needs to be done for macOS. - if [ -d /home/linuxbrew/.linuxbrew/bin ]; then - logg info "Sourcing shellenv from /home/linuxbrew/.linuxbrew/bin/brew" && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - elif [ -f /opt/homebrew/bin/brew ]; then - logg info "Sourcing shellenv from /opt/homebrew/bin/brew" && eval "$(/opt/homebrew/bin/brew shellenv)" - fi + if [ -d /home/linuxbrew/.linuxbrew/bin ]; then + logg info "Sourcing from /home/linuxbrew/.linuxbrew/bin/brew" && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + if ! command -v brew > /dev/null; then + logg error "The /home/linuxbrew/.linuxbrew directory exists but something is not right. Try removing it and running the script again." && exit 1 fi + else + ### Installs Homebrew and addresses a couple potential issues + if command -v sudo > /dev/null && sudo -n true; then + logg info "Installing Homebrew" + echo | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + else + logg info "Homebrew is not installed. The script will attempt to install Homebrew and you might be prompted for your password." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || BREW_EXIT_CODE="$?" + if [ -n "$BREW_EXIT_CODE" ]; then + if command -v brew > /dev/null; then + logg warn "Homebrew was installed but part of the installation failed. Trying a few things to fix the installation.." + BREW_DIRS="share/man share/doc share/zsh/site-functions etc/bash_completion.d" + for BREW_DIR in $BREW_DIRS; do + if [ -d "$(brew --prefix)/$BREW_DIR" ]; then + logg info "Chowning $(brew --prefix)/$BREW_DIR" && sudo chown -R "$(whoami)" "$(brew --prefix)/$BREW_DIR" + fi + done + logg info "Running brew update --force --quiet" && brew update --force --quiet && logg success "Successfully ran brew update --force --quiet" + fi + fi + fi + + ### Ensures the `brew` binary is available on Linux machines. macOS installs `brew` into the default `PATH` so nothing needs to be done for macOS. + if [ -d /home/linuxbrew/.linuxbrew/bin ]; then + logg info "Sourcing shellenv from /home/linuxbrew/.linuxbrew/bin/brew" && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + elif [ -f /opt/homebrew/bin/brew ]; then + logg info "Sourcing shellenv from /opt/homebrew/bin/brew" && eval "$(/opt/homebrew/bin/brew shellenv)" + fi + fi fi +### Ensure GCC is installed via Homebrew if command -v brew > /dev/null; then - if ! brew list | grep gcc > /dev/null; then - logg info "Installing Homebrew gcc" && brew install gcc - fi + if ! brew list | grep gcc > /dev/null; then + logg info "Installing Homebrew gcc" && brew install gcc + fi else - logg error "Failed to initialize Homebrew" && exit 2 -fi \ No newline at end of file + logg error "Failed to initialize Homebrew" && exit 2 +fi diff --git a/scripts/partials/logg b/scripts/partials/logg index 92b56fa3..e7ad3fe7 100644 --- a/scripts/partials/logg +++ b/scripts/partials/logg @@ -1,6 +1,7 @@ # @description Logs with style using Gum if it is installed, otherwise it uses `echo`. It also leverages Glow to render markdown. -# When Glow is not installed, it uses `cat`. -# @example logger info "An informative log" +# When Glow is not installed, it uses `cat`. +# @example +# logger info "An informative log" logg() { TYPE="$1" MSG="$2" @@ -59,4 +60,4 @@ logg() { echo "$MSG" fi fi -} \ No newline at end of file +} diff --git a/scripts/pfsense.sh b/scripts/pfsense.sh new file mode 100644 index 00000000..fe229be2 --- /dev/null +++ b/scripts/pfsense.sh @@ -0,0 +1,116 @@ +#!/bin/sh +# @file pfSense Setup +# @brief Configures pfSense +# @description +# This script sets up pfSense with features like: +# +# 1. [Netdata Cloud](https://learn.netdata.cloud/docs/installing/pfsense) + +# @description Logs with style using Gum if it is installed, otherwise it uses `echo`. It also leverages Glow to render markdown. +# When Glow is not installed, it uses `cat`. +# @example +# logger info "An informative log" +logg() { + TYPE="$1" + MSG="$2" + if [ "$TYPE" == 'error' ]; then + if command -v gum > /dev/null; then + gum style --border="thick" "$(gum style --foreground="#ff0000" "✖") $(gum style --bold --background="#ff0000" --foreground="#ffffff" " ERROR ") $(gum style --bold "$MSG")" + else + echo "ERROR: $MSG" + fi + elif [ "$TYPE" == 'info' ]; then + if command -v gum > /dev/null; then + gum style " $(gum style --foreground="#00ffff" "○") $(gum style --faint "$MSG")" + else + echo "INFO: $MSG" + fi + elif [ "$TYPE" == 'md' ]; then + if command -v glow > /dev/null; then + glow "$MSG" + else + cat "$MSG" + fi + elif [ "$TYPE" == 'prompt' ]; then + if command -v gum > /dev/null; then + gum style " $(gum style --foreground="#00008b" "▶") $(gum style --bold "$MSG")" + else + echo "PROMPT: $MSG" + fi + elif [ "$TYPE" == 'star' ]; then + if command -v gum > /dev/null; then + gum style " $(gum style --foreground="#d1d100" "◆") $(gum style --bold "$MSG")" + else + echo "STAR: $MSG" + fi + elif [ "$TYPE" == 'start' ]; then + if command -v gum > /dev/null; then + gum style " $(gum style --foreground="#00ff00" "▶") $(gum style --bold "$MSG")" + else + echo "START: $MSG" + fi + elif [ "$TYPE" == 'success' ]; then + if command -v gum > /dev/null; then + gum style "$(gum style --foreground="#00ff00" "✔") $(gum style --bold "$MSG")" + else + echo "SUCCESS: $MSG" + fi + elif [ "$TYPE" == 'warn' ]; then + if command -v gum > /dev/null; then + gum style " $(gum style --foreground="#d1d100" "◆") $(gum style --bold --background="#ffff00" --foreground="#000000" " WARNING ") $(gum style --bold "$MSG")" + else + echo "WARNING: $MSG" + fi + else + if command -v gum > /dev/null; then + gum style " $(gum style --foreground="#00ff00" "▶") $(gum style --bold "$TYPE")" + else + echo "$MSG" + fi + fi +} + +### Enable FreeBSD package repo +logg info 'Enabling FreeBSD package repo' +FILE_PATH="/usr/local/etc/pkg/repos/pfSense.conf" +TMP_FILE=$(mktemp) +REPLACEMENT="FreeBSD: { enabled: yes }" +echo "$REPLACEMENT" > "$TMP_FILE" +tail -n +2 "$FILE_PATH" >> "$TMP_FILE" +mv -f "$TMP_FILE" "$FILE_PATH" +rm -f "$TMP_FILE" + +### Install Netdata / dependencies +logg info 'Installing Netdata system package dependencies' +pkg update +pkg install -y curl pkgconf bash e2fsprogs-libuuid libuv nano +pkg install -y json-c-0.15_1 +pkg install -y py39-certifi-2023.5.7 +pkg install -y py39-asn1crypto +pkg install -y py39-pycparser +pkg install -y py39-cffi +pkg install -y py39-six +pkg install -y py39-cryptography +pkg install -y py39-idna +pkg install -y py39-openssl +pkg install -y py39-pysocks +pkg install -y py39-urllib3 +pkg install -y py39-yaml +pkg install -y netdata + +### Modify Netdata configuration +logg info 'Configuring Netdata to work with Netdata Cloud' +# TODO: Add below to netdata.conf +# bind to = 127.0.0.1 to bind to = 0.0.0.0 +NETDATA_CLOUD_API_TOKEN="YOUR_API_TOKEN_HERE" +cat < /usr/local/etc/netdata/netdata.conf +[backend] + enabled = yes + data source = netdata + destination = https://app.netdata.cloud + api key = ${NETDATA_CLOUD_API_TOKEN} +EOF + +### Start Netdata +logg info 'Starting Netdata service' +service netdata onestart diff --git a/scripts/provision.sh b/scripts/provision.sh index bc6486f9..12b3bcc2 100644 --- a/scripts/provision.sh +++ b/scripts/provision.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# @file Quick Start +# @file Quick Start Provision Script # @brief Main entry point for Install Doctor that ensures Homebrew and a few dependencies are installed before cloning the repository and running Chezmoi. # @description # This script ensures Homebrew is installed and then installs a few dependencies that Install Doctor relies on. @@ -37,11 +37,11 @@ # environment variables, this script can be run completely headlessly. This allows us to do things like test our # provisioning script on a wide variety of operating systems. # -# | Variable | Description | -# |------------------------|-----------------------------------------------------------------------------------| -# | `START_REPO` (or `REPO`) | Variable to specify the Git fork to use when provisioning | -# | `ANSIBLE_PROVISION_VM` | **For Qubes**, determines the name of the VM used to provision the system | -# | `DEBUG_MODE` | Set to true to enable verbose logging | +# | Variable | Description | +# |---------------------------|-----------------------------------------------------------------------------------| +# | `START_REPO` (or `REPO`) | Variable to specify the Git fork to use when provisioning | +# | `ANSIBLE_PROVISION_VM` | **For Qubes**, determines the name of the VM used to provision the system | +# | `DEBUG_MODE` (or `DEBUG`) | Set to true to enable verbose logging | # # For a full list of variables you can use to customize Install Doctor, check out our [Customization](https://install.doctor/docs/customization) # and [Secrets](https://install.doctor/docs/customization/secrets) documentation. @@ -51,52 +51,10 @@ # [Install Doctor homepage](https://install.doctor) # [Install Doctor documentation portal](https://install.doctor/docs) (includes tips, tricks, and guides on how to customize the system to your liking) -# @description Ensure Ubuntu / Debian run in `noninteractive` mode -export DEBIAN_FRONTEND=noninteractive - -# @description Load default settings if it is in a CI setting -if [ -n "$CI" ]; then - export HOST="$HOST" - export NO_RESTART=true - export HEADLESS_INSTALL=true - export SOFTWARE_GROUP="Full" - export FULL_NAME="Brian Zalewski" - export PRIMARY_EMAIL="help@megabyte.space" - export PUBLIC_SERVICES_DOMAIN="lab.megabyte.space" - export RESTRICTED_ENVIRONMENT=false - export WORK_ENVIRONMENT=false -fi - -# @description Detect `START_REPO` format and determine appropriate git address, otherwise use the master Install Doctor branch -setStartRepo() { - if [ -z "$START_REPO" ]; then - START_REPO="https://github.com/megabyte-labs/install.doctor.git" - else - if [[ "$START_REPO" == *"/"* ]]; then - # Either full git address or GitHubUser/RepoName - if [[ "$START_REPO" == *":"* ]] || [[ "$START_REPO" == *"//"* ]]; then - START_REPO="$START_REPO" - else - START_REPO="https://github.com/${START_REPO}.git" - fi - else - START_REPO="https://github.com/$START_REPO/install.doctor.git" - fi - fi -} - -# @description Disconnect from WARP, if connected -warpDisconnect() { - if command -v warp-cli > /dev/null; then - if warp-cli status | grep 'Connected' > /dev/null; then - warp-cli disconnect && echo "Disconnected WARP to prevent conflicts" - fi - fi -} - # @description Logs with style using Gum if it is installed, otherwise it uses `echo`. It also leverages Glow to render markdown. -# When Glow is not installed, it uses `cat`. -# @example logger info "An informative log" +# When Glow is not installed, it uses `cat`. +# @example +# logger info "An informative log" logg() { TYPE="$1" MSG="$2" @@ -108,7 +66,7 @@ logg() { fi elif [ "$TYPE" == 'info' ]; then if command -v gum > /dev/null; then - gum style " $(gum style --foreground="#00ffff" "○") $(gum style --faint --foreground="#ffffff" "$MSG")" + gum style " $(gum style --foreground="#00ffff" "○") $(gum style --faint "$MSG")" else echo "INFO: $MSG" fi @@ -156,29 +114,169 @@ logg() { fi fi } - -# @description Notify user that they can press CTRL+C to prevent /etc/sudoers from being modified (which is currently required for headless installs on some systems) -sudo -n true || SUDO_EXIT_CODE=$? -logg info 'Your user will temporarily be granted passwordless sudo for the duration of the script' -if [ -n "$SUDO_EXIT_CODE" ]; then - logg info 'Press CTRL+C to bypass this prompt to either enter your password when needed or perform a non-privileged installation' - logg info 'Note: Non-privileged installations are not yet supported' -fi - -# @description Add current user to /etc/sudoers so that headless automation is possible -if ! sudo cat /etc/sudoers | grep '# TEMPORARY FOR INSTALL DOCTOR' > /dev/null; then - if [ -n "$SUDO_PASSWORD" ]; then - printf '%s\n' "$SUDO_PASSWORD" | sudo -p "" -S echo "$(whoami) ALL=(ALL:ALL) NOPASSWD: ALL # TEMPORARY FOR INSTALL DOCTOR" | sudo tee -a /etc/sudoers +# @section Environment variables and system dependencies +# @description Ensure Ubuntu / Debian run in `noninteractive` mode. Detect `START_REPO` format and determine appropriate git address, +# otherwise use the master Install Doctor branch +setEnvironmentVariables() { + export DEBIAN_FRONTEND=noninteractive + if [ -z "$START_REPO" ] && [ -z "$REPO" ]; then + export START_REPO="https://github.com/megabyte-labs/install.doctor.git" else - echo "$(whoami) ALL=(ALL:ALL) NOPASSWD: ALL # TEMPORARY FOR INSTALL DOCTOR" | sudo tee -a /etc/sudoers + if [ -n "$REPO" ] && [ -z "$START_REPO" ]; then + export START_REPO="$REPO" + fi + if [[ "$START_REPO" == *"/"* ]]; then + # Either full git address or GitHubUser/RepoName + if [[ "$START_REPO" == *":"* ]] || [[ "$START_REPO" == *"//"* ]]; then + export START_REPO="$START_REPO" + else + export START_REPO="https://github.com/${START_REPO}.git" + fi + else + export START_REPO="https://github.com/$START_REPO/install.doctor.git" + fi + fi +} + +# @description Ensure dependencies like `git` and `curl` are installed (among a few other lightweight system packages) +ensureBasicDeps() { + if ! command -v curl > /dev/null || ! command -v git > /dev/null || ! command -v expect > /dev/null || ! command -v rsync > /dev/null || ! command -v unbuffer; then + if command -v apt-get > /dev/null; then + ### Debian / Ubuntu + logg info 'Running sudo apt-get update' && sudo apt-get update + logg info 'Running sudo apt-get install -y build-essential curl expect git rsync' && sudo apt-get install -y build-essential curl expect git rsync + elif command -v dnf > /dev/null; then + ### Fedora + logg info 'Running sudo dnf install -y curl expect git rsync' && sudo dnf install -y curl expect git rsync + elif command -v yum > /dev/null; then + ### CentOS + logg info 'Running sudo yum install -y curl expect git rsync' && sudo yum install -y curl expect git rsync + elif command -v pacman > /dev/null; then + ### Archlinux + logg info 'Running sudo pacman update' && sudo pacman update + logg info 'Running sudo pacman -Syu base-devel curl expect git rsync procps-ng file' && sudo pacman -Syu base-devel curl expect git rsync procps-ng file + elif command -v zypper > /dev/null; then + ### OpenSUSE + logg info 'Running sudo zypper install -y curl expect git rsync' && sudo zypper install -y curl expect git rsync + elif command -v apk > /dev/null; then + ### Alpine + logg info 'Running apk add curl expect git rsync' && apk add curl expect git rsync + elif [ -d /Applications ] && [ -d /Library ]; then + ### macOS + logg info 'Running sudo xcode-select -p >/dev/null 2>&1 || xcode-select --install' && sudo xcode-select -p >/dev/null 2>&1 || xcode-select --install + elif [[ "$OSTYPE" == 'cygwin' ]] || [[ "$OSTYPE" == 'msys' ]] || [[ "$OSTYPE" == 'win32' ]]; then + ### Windows + logg info 'Running choco install -y curl expect git rsync' && choco install -y curl expect git rsync + elif command -v nix-env > /dev/null; then + ### NixOS + logg warn "TODO - Add support for NixOS" + elif [[ "$OSTYPE" == 'freebsd'* ]]; then + ### FreeBSD + logg warn "TODO - Add support for FreeBSD" + elif command -v pkg > /dev/null; then + ### Termux + logg warn "TODO - Add support for Termux" + elif command -v xbps-install > /dev/null; then + ### Void + logg warn "TODO - Add support for Void" + fi +fi} + +# @description Ensure Homebrew is installed and available in the `PATH` +ensureHomebrew() { + if ! command -v brew > /dev/null; then + if [ -d /home/linuxbrew/.linuxbrew/bin ]; then + logg info "Sourcing from /home/linuxbrew/.linuxbrew/bin/brew" && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + if ! command -v brew > /dev/null; then + logg error "The /home/linuxbrew/.linuxbrew directory exists but something is not right. Try removing it and running the script again." && exit 1 + fi + else + ### Installs Homebrew and addresses a couple potential issues + if command -v sudo > /dev/null && sudo -n true; then + logg info "Installing Homebrew" + echo | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + else + logg info "Homebrew is not installed. The script will attempt to install Homebrew and you might be prompted for your password." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || BREW_EXIT_CODE="$?" + if [ -n "$BREW_EXIT_CODE" ]; then + if command -v brew > /dev/null; then + logg warn "Homebrew was installed but part of the installation failed. Trying a few things to fix the installation.." + BREW_DIRS="share/man share/doc share/zsh/site-functions etc/bash_completion.d" + for BREW_DIR in $BREW_DIRS; do + if [ -d "$(brew --prefix)/$BREW_DIR" ]; then + logg info "Chowning $(brew --prefix)/$BREW_DIR" && sudo chown -R "$(whoami)" "$(brew --prefix)/$BREW_DIR" + fi + done + logg info "Running brew update --force --quiet" && brew update --force --quiet && logg success "Successfully ran brew update --force --quiet" + fi + fi + fi + + ### Ensures the `brew` binary is available on Linux machines. macOS installs `brew` into the default `PATH` so nothing needs to be done for macOS. + if [ -d /home/linuxbrew/.linuxbrew/bin ]; then + logg info "Sourcing shellenv from /home/linuxbrew/.linuxbrew/bin/brew" && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + elif [ -f /opt/homebrew/bin/brew ]; then + logg info "Sourcing shellenv from /opt/homebrew/bin/brew" && eval "$(/opt/homebrew/bin/brew shellenv)" + fi fi fi -# @section Qubes dom0 Bootstrap -# @description Perform Qubes dom0 specific logic like updating system packages, setting up the Tor VM, updating TemplateVMs, and -# beginning the provisioning process using Ansible and an AppVM used to handle the provisioning process -if command -v qubesctl > /dev/null; then - # @description Ensure sys-whonix is configured (for Qubes dom0) +### Ensure GCC is installed via Homebrew +if command -v brew > /dev/null; then + if ! brew list | grep gcc > /dev/null; then + logg info "Installing Homebrew gcc" && brew install gcc + fi +else + logg error "Failed to initialize Homebrew" && exit 2 +fi +} + +# @description Load default settings if it is in a CI setting +setCIEnvironmentVariables() { + if [ -n "$CI" ]; then + logg info "Automatically setting environment variables since the CI environment variable is defined" + logg info "Setting HOST to $HOST" && export HOST="$HOST" + logg info "Setting NO_RESTART to true" && export NO_RESTART=true + logg info "Setting HEADLESS_INSTALL to true " && export HEADLESS_INSTALL=true + logg info "Setting SOFTWARE_GROUP to Full-Desktop" && export SOFTWARE_GROUP="Full-Desktop" + logg info "Setting FULL_NAME to Brian Zalewski" && export FULL_NAME="Brian Zalewski" + logg info "Setting PRIMARY_EMAIL to help@megabyte.space" && export PRIMARY_EMAIL="help@megabyte.space" + logg info "Setting PUBLIC_SERVICES_DOMAIN to lab.megabyte.space" && export PUBLIC_SERVICES_DOMAIN="lab.megabyte.space" + logg info "Setting RESTRICTED_ENVIRONMENT to false" && export RESTRICTED_ENVIRONMENT=false + logg info "Setting WORK_ENVIRONMENT to false" && export WORK_ENVIRONMENT=false + fi +} + +# @description Disconnect from WARP, if connected +ensureWarpDisconnected() { + if command -v warp-cli > /dev/null; then + if warp-cli status | grep 'Connected' > /dev/null; then + logg info "Disconnecting from WARP" && warp-cli disconnect && logg success "Disconnected WARP to prevent conflicts" + fi + fi +} + +# @description Notify user that they can press CTRL+C to prevent `/etc/sudoers` from being modified (which is currently required for headless installs on some systems). +# Additionally, this function will add the current user to `/etc/sudoers` so that headless automation is possible. +setupPasswordlessSudo() { + sudo -n true || SUDO_EXIT_CODE=$? + logg info 'Your user will temporarily be granted passwordless sudo for the duration of the script' + if [ -n "$SUDO_EXIT_CODE" ]; then + logg info 'Press CTRL+C to bypass this prompt to either enter your password when needed or perform a non-privileged installation' + logg info 'Note: Non-privileged installations are not yet supported' + fi + if ! sudo cat /etc/sudoers | grep '# TEMPORARY FOR INSTALL DOCTOR' > /dev/null; then + if [ -n "$SUDO_PASSWORD" ]; then + printf '%s\n' "$SUDO_PASSWORD" | sudo -p "" -S echo "$(whoami) ALL=(ALL:ALL) NOPASSWD: ALL # TEMPORARY FOR INSTALL DOCTOR" | sudo tee -a /etc/sudoers + else + echo "$(whoami) ALL=(ALL:ALL) NOPASSWD: ALL # TEMPORARY FOR INSTALL DOCTOR" | sudo tee -a /etc/sudoers + fi + fi +} + +# @section Qubes dom0 +# @description Ensure sys-whonix is configured (for Qubes dom0) +ensureSysWhonix() { CONFIG_WIZARD_COUNT=0 function configureWizard() { if xwininfo -root -tree | grep "Anon Connection Wizard"; then @@ -205,21 +303,27 @@ if command -v qubesctl > /dev/null; then fi fi } +} - # @description Ensure dom0 is updated +# @description Ensure dom0 is updated +ensureDom0Updated() { if [ ! -f /root/dom0-updated ]; then sudo qubesctl --show-output state.sls update.qubes-dom0 sudo qubes-dom0-update --clean -y touch /root/dom0-updated fi +} - # @description Ensure sys-whonix is running +# @description Ensure sys-whonix is running +ensureSysWhonixRunning() { if ! qvm-check --running sys-whonix; then qvm-start sys-whonix --skip-if-running configureWizard > /dev/null fi +} - # @description Ensure TemplateVMs are updated +# @description Ensure TemplateVMs are updated +ensureTemplateVMsUpdated() { if [ ! -f /root/templatevms-updated ]; then # timeout of 10 minutes is added here because the whonix-gw VM does not like to get updated # with this method. Anyone know how to fix this? @@ -229,17 +333,20 @@ if command -v qubesctl > /dev/null; then done< <(qvm-ls --all --no-spinner --fields=name,state | grep Running | grep -v sys-net | grep -v sys-firewall | grep -v sys-whonix | grep -v dom0 | awk '{print $1}') sudo touch /root/templatevms-updated fi +} - # @description Ensure provisioning VM can run commands on any VM +# @description Ensure provisioning VM can run commands on any VM +ensureProvisioningVMPermissions() { echo "/bin/bash" | sudo tee /etc/qubes-rpc/qubes.VMShell sudo chmod 755 /etc/qubes-rpc/qubes.VMShell echo "${ANSIBLE_PROVISION_VM:=provision}"' dom0 allow' | sudo tee /etc/qubes-rpc/policy/qubes.VMShell echo "$ANSIBLE_PROVISION_VM"' $anyvm allow' | sudo tee -a /etc/qubes-rpc/policy/qubes.VMShell sudo chown "$(whoami):$(whoami)" /etc/qubes-rpc/policy/qubes.VMShell sudo chmod 644 /etc/qubes-rpc/policy/qubes.VMShell +} - - # @description Create provisioning VM and initialize the provisioning process from there +# @description Create provisioning VM and initialize the provisioning process from there +createAndInitProvisionVM() { qvm-create --label red --template debian-11 "$ANSIBLE_PROVISION_VM" &> /dev/null || true qvm-volume extend "$ANSIBLE_PROVISION_VM:private" "40G" if [ -f ~/.vaultpass ]; then @@ -247,208 +354,185 @@ if command -v qubesctl > /dev/null; then qvm-copy-to-vm "$ANSIBLE_PROVISION_VM" ~/.vaultpass qvm-run "$ANSIBLE_PROVISION_VM" 'cp ~/QubesIncoming/dom0/.vaultpass ~/.vaultpass' fi +} - # @description Restart the provisioning process with the same script but from the provisioning VM +# @description Restart the provisioning process with the same script but from the provisioning VM +runStartScriptInProvisionVM() { qvm-run --pass-io "$ANSIBLE_PROVISION_VM" 'curl -sSL https://install.doctor/start > ~/start.sh && bash ~/start.sh' - exit 0 -fi +} -# @description Ensure basic system packages are available on the device -if ! command -v curl > /dev/null || ! command -v git > /dev/null || ! command -v expect > /dev/null || ! command -v rsync > /dev/null; then - if command -v apt-get > /dev/null; then - # @description Ensure `build-essential`, `curl`, `expect`, `git`, `rsync`, `procps`, and `file` are installed on Debian / Ubuntu - sudo apt-get update - sudo apt-get install -y build-essential curl expect git rsync procps file - elif command -v dnf > /dev/null; then - # @description Ensure `curl`, `expect`, `git`, `rsync`, `procps-ng`, and `file` are installed on Fedora (as well as the Development Tools package) - sudo dnf groupinstall -y 'Development Tools' - sudo dnf install -y curl expect git rsync procps-ng file - elif command -v yum > /dev/null; then - # @description Ensure `curl`, `expect`, `git`, `rsync`, `procps-ng`, and `file` are installed on CentOS (as well as the Development Tools package) - sudo yum groupinstall -y 'Development Tools' - sudo yum install -y curl expect git rsync procps-ng file - elif command -v pacman > /dev/null; then - # @description Ensure `base-devel`, `curl`, `expect`, `git`, `rsync`, `procps-ng`, and `file` are installed on Archlinux - sudo pacman update - sudo pacman -Syu base-devel curl expect git rsync procps-ng file - elif command -v zypper > /dev/null; then - # @description Ensure `curl`, `expect`, `git`, `rsync`, `procps`, and `file` are installed on OpenSUSE (as well as the devel_basis pattern) - sudo zypper install -yt pattern devel_basis - sudo zypper install -y curl expect git rsync procps file - elif command -v apk > /dev/null; then - # @description Ensure `curl`, `expect`, `git`, `rsync`, `procps`, and `file` are installed on Alpine - apk add build-base curl expect git rsync procps file - elif [ -d /Applications ] && [ -d /Library ]; then - # @description Ensure CLI developer tools are available on macOS (via `xcode-select`) - sudo xcode-select -p >/dev/null 2>&1 || xcode-select --install - elif [[ "$OSTYPE" == 'cygwin' ]] || [[ "$OSTYPE" == 'msys' ]] || [[ "$OSTYPE" == 'win32' ]]; then - # @description Ensure `curl`, `expect`, `git`, and `rsync` are installed on Windows - choco install -y curl expect git rsync - fi -fi +# @description Perform Qubes dom0 specific logic like updating system packages, setting up the Tor VM, updating TemplateVMs, and +# beginning the provisioning process using Ansible and an AppVM used to handle the provisioning process +handleQubesDom0() { + if command -v qubesctl > /dev/null; then + ensureSysWhonix + ensureDom0Updated + ensureSysWhonixRunning + ensureTemplateVMsUpdated + ensureProvisioningVMPermissions + createAndInitProvisionVM + runStartScriptInProvisionVM + exit 0 + fi +} -# @description Ensure Homebrew is installed and available -if ! command -v brew > /dev/null; then - if [ -d /home/linuxbrew/.linuxbrew/bin ]; then - eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv) - if ! command -v brew > /dev/null; then - echo "The /home/linuxbrew/.linuxbrew directory exists but something is not right. Try removing it and running the script again." && exit 1 - fi - else - # @description Installs Homebrew and addresses a couple potential issues - if command -v sudo > /dev/null && sudo -n true; then - echo | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - else - echo "Homebrew is not installed. The script will attempt to install Homebrew and you might be prompted for your password." - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || BREW_EXIT_CODE="$?" - if [ -n "$BREW_EXIT_CODE" ]; then - if command -v brew > /dev/null; then - echo "Homebrew was installed but part of the installation failed. Trying a few things to fix the installation.." - BREW_DIRS="share/man share/doc share/zsh/site-functions etc/bash_completion.d" - for BREW_DIR in $BREW_DIRS; do - if [ -d "$(brew --prefix)/$BREW_DIR" ]; then - sudo chown -R "$(whoami)" "$(brew --prefix)/$BREW_DIR" - fi - done - brew update --force --quiet - fi - fi - fi +# @section Homebrew dependencies +# @description Helper function used by [[ensureHomebrewDeps]] to ensure a Homebrew package is installed after +# first checking if it is already available on the system. +installBrewPackage() { + if ! command -v "$1" > /dev/null; then + logg 'Installing '"$1"'' + brew install "$1" + fi +} - # @description Ensures the `brew` binary is available on Linux machines. macOS installs `brew` into the default `PATH` - # so nothing needs to be done for macOS. - if [ -d /home/linuxbrew/.linuxbrew/bin ]; then - eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv) - elif [ -f /opt/homebrew/bin/brew ]; then - eval "$(/opt/homebrew/bin/brew shellenv)" - fi - fi -fi +# @description Installs various dependencies using Homebrew. +# +# 1. Ensures Chezmoi, Node.js, and ZX are installed. +# 2. Installs Glow and Gum if the `HEADLESS_INSTALL` environment variable is not set. +# 3. If the system is macOS, then also install `gsed`. +ensureHomebrewDeps() { + ### TUI experience + if [ -z "$HEADLESS_INSTALL" ]; then + installBrewPackage "gum" + installBrewPackage "glow" + fi -# @description Ensure Chezmoi is installed -if ! command -v chezmoi > /dev/null; then - brew install chezmoi -fi + ### Base dependencies + installBrewPackage "chezmoi" + installBrewPackage "node" + installBrewPackage "zx" -# @description Ensure Node.js is installed -if ! command -v node > /dev/null; then - brew install node -fi + ### macOS + if [ -d /Applications ] && [ -d /System ]; then + installBrewPackage "gsed" + fi +} -# @description Ensure ZX is installed -if ! command -v zx > /dev/null; then - brew install zx -fi +# @section Chezmoi +# @description Ensure the `${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi` directory is cloned and up-to-date using the previously +# set `START_REPO` as the source repository. +cloneChezmoiSourceRepo() { + logg info 'Setting git http.postBuffer value high for large source repository' && git config --global http.postBuffer 524288000 + if [ -d "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/.git" ]; then + logg info "Changing directory to ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi" && cd "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi" + logg info "Pulling the latest changes in ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi" && git pull origin master + else + logg info "Ensuring ${XDG_DATA_HOME:-$HOME/.local/share} is a folder" && mkdir -p "${XDG_DATA_HOME:-$HOME/.local/share}" + logg info "Cloning ${START_REPO} to ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi" && git clone "${START_REPO}" "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi" + fi +} -# @description Install Glow / Gum if the `HEADLESS_INSTALL` variable is not set to true -if [ "$HEADLESS_INSTALL" != 'true' ]; then - # @description Ensure Gum is installed - if ! command -v gum > /dev/null; then - brew install gum - fi - - # @description Ensure Glow is installed - if ! command -v glow > /dev/null; then - brew install glow - fi -fi - -# @description Ensure the ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi directory is cloned and up-to-date -logg info 'Setting git http.postBuffer value high for large source repository' -git config --global http.postBuffer 524288000 -if [ -d "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/.git" ]; then - cd "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi" - logg info "Pulling the latest changes from ${START_REPO:-https://github.com/megabyte-labs/install.doctor.git}" - git pull origin master -else - logg info "Cloning ${START_REPO} to ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi" - git clone ${START_REPO} "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi" -fi - -# @description If the `${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml` file is missing, then guide the user through the initial setup -if [ ! -f "${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml" ]; then - # @description Show introduction message if Glow is installed +# @description Guide the user through the initial setup by showing TUI introduction and accepting input through various prompts. +# +# 1. Show `chezmoi-intro.md` with `glow` +# 2. Prompt for the software group if the `SOFTWARE_GROUP` variable is not defined +# 3. Run `chezmoi init` when the Chezmoi configuration is missing (i.e. `${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml`) +initChezmoiAndPrompt() { + ### Show `chezmoi-intro.md` with `glow` if command -v glow > /dev/null; then glow "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/docs/terminal/chezmoi-intro.md" fi - # @description Prompt for the software group if the `SOFTWARE_GROUP` variable is not defined + ### Prompt for the software group if the `SOFTWARE_GROUP` variable is not defined if command -v gum > /dev/null; then if [ -z "$SOFTWARE_GROUP" ]; then logg prompt 'Select the software group you would like to install. If your environment is a macOS, Windows, or environment with the DISPLAY environment variable then desktop software will be installed too. The software groups are in the '"${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml"' file.' - SOFTWARE_GROUP="$(gum choose "Basic" "Standard" "Full")" + SOFTWARE_GROUP="$(gum choose "Basic" "Server" "Standard" "Full")" export SOFTWARE_GROUP fi else logg error 'Woops! Gum needs to be installed for the guided installation. Try running brew install gum' && exit 1 fi - # @description Run `chezmoi init` when the Chezmoi configuration is missing - logg info 'Running chezmoi init since the '"${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml"' is not present' - chezmoi init -fi + if [ ! -f "${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml" ]; then + ### Run `chezmoi init` when the Chezmoi configuration is missing + logg info 'Running chezmoi init since the '"${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml"' is not present' + chezmoi init + fi +} -# @description Run `chezmoi apply` and enable verbose mode if the `DEBUG_MODE` environment variable is set to true -if [ "$DEBUG_MODE" = 'true' ]; then - DEBUG_MODIFIER="-vvvvv" -fi +# @description Run `chezmoi apply` and enable verbose mode if the `DEBUG_MODE` or `DEBUG` environment variable is set to true +configureDebugMode() { + if [ -n "$DEBUG_MODE" ] || [ -n "$DEBUG" ]; then + logg info "Either DEBUG_MODE or DEBUG environment variables were set so Chezmoi will be run in debug mode" + export DEBUG_MODIFIER="-vvvvv" + fi +} # @description Save the log of the provision process to `$HOME/.local/var/log/install.doctor/install.doctor.$(date +%s).log` and add the Chezmoi -# `--force` flag if the `HEADLESS_INSTALL` variable is set to true. -mkdir -p "$HOME/.local/var/log/install.doctor" -LOG_FILE="$HOME/.local/var/log/install.doctor/install.doctor.$(date +%s).log" -if [ "$HEADLESS_INSTALL" = 'true' ]; then - logg info 'Running chezmoi apply forcefully' - if command -v unbuffer > /dev/null; then - if command -v caffeinate > /dev/null; then - caffeinate unbuffer -p chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE" +# `--force` flag if the `HEADLESS_INSTALL` variable is set to `true`. +runChezmoi() { + mkdir -p "$HOME/.local/var/log/install.doctor" + LOG_FILE="$HOME/.local/var/log/install.doctor/install.doctor.$(date +%s).log" + if [ "$HEADLESS_INSTALL" = 'true' ]; then + logg info 'Running chezmoi apply forcefully' + if command -v unbuffer > /dev/null; then + if command -v caffeinate > /dev/null; then + caffeinate unbuffer -p chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE" + else + unbuffer -p chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE" + fi else - unbuffer -p chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE" + if command -v caffeinate > /dev/null; then + caffeinate chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE" + else + chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE" + fi fi else - if command -v caffeinate > /dev/null; then - caffeinate chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE" + logg info 'Running chezmoi apply' + if command -v unbuffer > /dev/null; then + if command -v caffeinate > /dev/null; then + caffeinate unbuffer -p chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE" + else + unbuffer -p chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE" + fi else - chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE" + if command -v caffeinate > /dev/null; then + caffeinate chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE" + else + chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE" + fi fi fi -else - logg info 'Running chezmoi apply' - if command -v unbuffer > /dev/null; then - if command -v caffeinate > /dev/null; then - caffeinate unbuffer -p chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE" - else - unbuffer -p chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE" - fi - else - if command -v caffeinate > /dev/null; then - caffeinate chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE" - else - chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE" - fi - fi -fi - -# @description Ensure gsed is available on macOS (for modifying `/etc/sudoers` to remove passwordless sudo) -if [ -d /Applications ] && [ -d /System ]; then - if ! command -v gsed > /dev/null; then - if command -v brew > /dev/null; then - brew install gsed - else - logg warn 'Homebrew is not available and passwordless sudo might still be enabled in /etc/sudoers. Modify the file manually if you wish to disable passwordless sudo.' - fi - fi -fi +} +# @section Post-provision logic # @description Ensure temporary passwordless sudo privileges are removed from `/etc/sudoers` -if command -v gsed > /dev/null; then +removePasswordlessSudo() { + if command -v gsed > /dev/null; then sudo gsed -i '/# TEMPORARY FOR INSTALL DOCTOR/d' /etc/sudoers || logg warn 'Failed to remove passwordless sudo from the /etc/sudoers file' -else + else sudo sed -i '/# TEMPORARY FOR INSTALL DOCTOR/d' /etc/sudoers || logg warn 'Failed to remove passwordless sudo from the /etc/sudoers file' -fi + fi +} # @description Render the `docs/terminal/post-install.md` file to the terminal at the end of the provisioning process -logg success 'Provisioning complete!' -if command -v glow > /dev/null && [ -f "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/docs/terminal/post-install.md" ]; then - glow "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/docs/terminal/post-install.md" -fi +postProvision() { + logg success 'Provisioning complete!' + if command -v glow > /dev/null && [ -f "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/docs/terminal/post-install.md" ]; then + glow "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/docs/terminal/post-install.md" + fi +} + + +# @section Execution order +# @description The `provisionLogic` function is used to define the order of the script. All of the functions it relies on are defined +# above. +provisionLogic() { + logg info "Setting environment variables" && setEnvironmentVariables + logg info "Handling CI variables" && setCIEnvironmentVariables + logg info "Ensuring WARP is disconnected" && ensureWarpDisconnected + logg info "Ensuring system Homebrew dependencies are installed" && ensureBasicDeps + logg info "Ensuring Homebrew is available" && ensureHomebrew + logg info "Applying passwordless sudo" && setupPasswordlessSudo + logg info "Handling Qubes dom0 logic (if applicable)" && handleQubesDom0 + logg info "Cloning / updating source repository" && cloneChezmoiSourceRepo + logg info "Handling pre-provision logic" && initChezmoiAndPrompt + logg info "Handling debug mode if DEBUG or DEBUG_MODE are defined" && configureDebugMode + logg info "Running the Chezmoi provisioning" && runChezmoi + logg info "Ensuring temporary passwordless sudo is removed" && removePasswordlessSudo + logg info "Handling post-provision logic" && postProvision +} +provisionLogic diff --git a/scripts/src/cloudflared-ssh.sh.tmpl b/scripts/src/cloudflared-ssh.sh.tmpl index 56072b22..83f9e22e 100644 --- a/scripts/src/cloudflared-ssh.sh.tmpl +++ b/scripts/src/cloudflared-ssh.sh.tmpl @@ -42,11 +42,13 @@ # # [SSH with short-lived certificates](https://developers.cloudflare.com/cloudflare-one/tutorials/ssh-cert-bastion/) +{{ include "partials" "logg" -}} + # @description Ensure dependencies like `git` and `curl` are installed (among a few other lightweight system packages) -{{ include "partials" "basic-deps" }} +{{ include "partials" "basic-deps" -}} # @description Ensure Homebrew is installed and available in the `PATH` -{{ include "partials" "homebrew" }} +{{ include "partials" "homebrew" -}} # @description Ensures `cloudflared` is installed via Homebrew if ! command -v cloudflared > /dev/null; then diff --git a/scripts/src/homebrew.sh.tmpl b/scripts/src/homebrew.sh.tmpl index 9498b11c..4796d62c 100644 --- a/scripts/src/homebrew.sh.tmpl +++ b/scripts/src/homebrew.sh.tmpl @@ -11,4 +11,4 @@ # # **Note**: `https://install.doctor/brew` points to this file. -{{ include "partials" "homebrew" }} +{{ include "partials" "homebrew" -}} diff --git a/scripts/src/pfsense.sh.tmpl b/scripts/src/pfsense.sh.tmpl index c0cda96c..60aa866e 100644 --- a/scripts/src/pfsense.sh.tmpl +++ b/scripts/src/pfsense.sh.tmpl @@ -6,6 +6,6 @@ # # 1. [Netdata Cloud](https://learn.netdata.cloud/docs/installing/pfsense) -{{ include "partials" "logg" }} +{{ include "partials" "logg" -}} -{{ include "partials" "pfsense" }} +{{ include "partials" "pfsense" -}} diff --git a/scripts/src/provision.sh.tmpl b/scripts/src/provision.sh.tmpl index 5f356712..0ef2d8c7 100644 --- a/scripts/src/provision.sh.tmpl +++ b/scripts/src/provision.sh.tmpl @@ -51,7 +51,7 @@ # [Install Doctor homepage](https://install.doctor) # [Install Doctor documentation portal](https://install.doctor/docs) (includes tips, tricks, and guides on how to customize the system to your liking) -{{ include "partials" "logg" }} +{{ include "partials" "logg" -}} # @section Environment variables and system dependencies # @description Ensure Ubuntu / Debian run in `noninteractive` mode. Detect `START_REPO` format and determine appropriate git address, @@ -79,12 +79,12 @@ setEnvironmentVariables() { # @description Ensure dependencies like `git` and `curl` are installed (among a few other lightweight system packages) ensureBasicDeps() { - {{ include "partials" "basic-deps" }} + {{ include "partials" "basic-deps" -}} } # @description Ensure Homebrew is installed and available in the `PATH` ensureHomebrew() { - {{ include "partials" "homebrew" }} + {{ include "partials" "homebrew" -}} } # @description Load default settings if it is in a CI setting @@ -294,7 +294,7 @@ initChezmoiAndPrompt() { if command -v gum > /dev/null; then if [ -z "$SOFTWARE_GROUP" ]; then logg prompt 'Select the software group you would like to install. If your environment is a macOS, Windows, or environment with the DISPLAY environment variable then desktop software will be installed too. The software groups are in the '"${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml"' file.' - SOFTWARE_GROUP="$(gum choose "General-Purpose-Server" "Basic" "Standard" "Full")" + SOFTWARE_GROUP="$(gum choose "Basic" "Server" "Standard" "Full")" export SOFTWARE_GROUP fi else @@ -317,7 +317,7 @@ configureDebugMode() { } # @description Save the log of the provision process to `$HOME/.local/var/log/install.doctor/install.doctor.$(date +%s).log` and add the Chezmoi -# `--force` flag if the `HEADLESS_INSTALL` variable is set to `true``. +# `--force` flag if the `HEADLESS_INSTALL` variable is set to `true`. runChezmoi() { mkdir -p "$HOME/.local/var/log/install.doctor" LOG_FILE="$HOME/.local/var/log/install.doctor/install.doctor.$(date +%s).log"