#!/usr/bin/env bash set -eox pipefail {{ includeTemplate "universal/logg" }} ### Qubes dom0 if command -v qubesctl > /dev/null; then # The VM name that will manage the Ansible provisioning (for Qubes dom0) ANSIBLE_PROVISION_VM="provision" # Ensure sys-whonix is configured (for Qubes dom0) CONFIG_WIZARD_COUNT=0 ENABLE_OBFSC='false' function configureWizard() { if xwininfo -root -tree | grep "Anon Connection Wizard"; then WINDOW_ID="$(xwininfo -root -tree | grep "Anon Connection Wizard" | sed 's/^ *\([^ ]*\) .*/\1/')" xdotool windowactivate "$WINDOW_ID" && sleep 1 && xdotool key 'Enter' && sleep 1 && xdotool key 'Tab Tab Enter' && sleep 24 && xdotool windowactivate "$WINDOW_ID" && sleep 1 && xdotool key 'Enter' && sleep 300 qvm-shutdown --wait sys-whonix sleep 3 qvm-start sys-whonix if xwininfo -root -tree | grep "systemcheck | Whonix" > /dev/null; then WINDOW_ID_SYSCHECK="$(xwininfo -root -tree | grep "systemcheck | Whonix" | sed 's/^ *\([^ ]*\) .*/\1/')" if xdotool windowactivate "$WINDOW_ID_SYS_CHECK"; then sleep 1 xdotool key 'Enter' fi fi else sleep 3 CONFIG_WIZARD_COUNT=$((CONFIG_WIZARD_COUNT + 1)) if [[ "$CONFIG_WIZARD_COUNT" == '4' ]]; then echo "The sys-whonix anon-connection-wizard utility did not open." else echo "Checking for anon-connection-wizard again.." configureWizard fi fi } ### Ensure dom0 is updated 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 ### Ensure sys-whonix is running if ! qvm-check --running sys-whonix; then qvm-start sys-whonix --skip-if-running configureWizard > /dev/null fi ### Ensure TemplateVMs are updated 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? sudo timeout 600 qubesctl --show-output --skip-dom0 --templates state.sls update.qubes-vm &> /dev/null || EXIT_CODE=$? while read RESTART_VM; do qvm-shutdown --wait "$RESTART_VM" 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 ### Ensure provisioning VM can run commands on any VM echo "/bin/bash" | sudo tee /etc/qubes-rpc/qubes.VMShell sudo chmod 755 /etc/qubes-rpc/qubes.VMShell echo "$ANSIBLE_PROVISION_VM"' 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 ### Create provisioning VM and initialize the provisioning process from there qvm-create --label red --template debian-11 "$ANSIBLE_PROVISION_VM" &> /dev/null || EXIT_CODE=$? qvm-volume extend "$ANSIBLE_PROVISION_VM:private" "40G" if [ -f ~/.vaultpass ]; then qvm-run "$ANSIBLE_PROVISION_VM" 'rm -f ~/QubesIncoming/dom0/.vaultpass' qvm-copy-to-vm "$ANSIBLE_PROVISION_VM" ~/.vaultpass qvm-run "$ANSIBLE_PROVISION_VM" 'cp ~/QubesIncoming/dom0/.vaultpass ~/.vaultpass' fi qvm-run --pass-io "$ANSIBLE_PROVISION_VM" 'curl -sSL https://install.doctor/start > ~/start.sh && bash ~/start.sh' exit 0 fi ### System package manager update / Homebrew dependencies if ! command -v curl > /dev/null || ! command -v git > /dev/null; then logg 'Ensuring `curl` and `git` are installed via the system package manager' if command -v apt-get > /dev/null; then # Debian / Ubuntu sudo apt-get update sudo apt-get install -y curl git elif command -v dnf > /dev/null; then # Fedora sudo dnf install -y curl git elif command -v yum > /dev/null; then # CentOS sudo yum install -y curl git elif command -v pacman > /dev/null; then # Archlinux sudo pacman update sudo pacman -Sy curl git elif command -v zypper > /dev/null; then # OpenSUSE sudo zypper install -y curl git nodejs elif command -v apk > /dev/null; then # Alpine apk add curl git elif [ -d /Applications ] && [ -d /Library ]; then # macOS sudo xcode-select -p >/dev/null 2>&1 || xcode-select --install 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" elif [[ "$OSTYPE" == 'cygwin' ]] || [[ "$OSTYPE" == 'msys' ]] || [[ "$OSTYPE" == 'win32' ]]; then # Windows choco install -y curl git node fi fi ### Install Homebrew ensurePackageManagerHomebrew() { if ! command -v brew > /dev/null; then logg info 'Installing Homebrew' if command -v sudo > /dev/null && sudo -n true; then echo | bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" else logg info 'Looks like the user does not have passwordless sudo privileges. A sudo password may be required.' 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. Attempting to fix..' 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 fi } ensurePackageManagerHomebrew ### Install installer dependencies via Homebrew installBrewPackage() { if ! command -v "$1" > /dev/null; then logg 'Installing `'"$1"'`' brew install "$1" fi } if command -v brew > /dev/null; then installBrewPackage chezmoi installBrewPackage glow installBrewPackage gum installBrewPackage node installBrewPackage zx fi ### Ensure source files are present logg 'Ensuring /usr/local/src/hiawatha is owned by the user' if [ -d /usr/local/src/hiawatha ] && [ ! -w /usr/local/src/hiawatha ]; then sudo chown -Rf "$USER":"$(id -g -n)" /usr/local/src/hiawatha fi if [ -d /usr/local/src/hiawatha/.git ]; then logg info 'Pulling the latest changes from https://gitlab.com/megabyte-labs/dotfiles.git to /usr/local/src/hiawatha' cd /usr/local/src/hiawatha git config pull.rebase false git reset --hard HEAD git clean -fxd git pull origin master else logg info 'Cloning https://gitlab.com/megabyte-labs/dotfiles.git to /usr/local/src/hiawatha' rm -rf /usr/local/src/hiawatha sudo git clone https://gitlab.com/megabyte-labs/dotfiles.git /usr/local/src/hiawatha chown -Rf "$USER":"$(id -g -n)" /usr/local/src/hiawatha fi ### Copy folders logg info 'Copying folders from /usr/local/src/hiawatha to the HOME directory' find /usr/local/src/hiawatha -maxdepth 1 -mindepth 1 -type d | while read FOLDER; do BASENAME="$(basename "$FOLDER")" # Prevent initial-scaffolding of OS-specific files since Chezmoi will handle them if [ "$BASENAME" != 'AppData' ] && [ "$BASENAME" != 'Library' ] && [ "$BASENAME" != '.git' ]; then if [ ! -d "$HOME/$BASENAME" ]; then mkdir -p "$HOME/$BASENAME" fi cp -rf "$FOLDER/"* "$HOME/$BASENAME" fi done ### Copy files logg info 'Copying files from /usr/local/src/hiawatha to the HOME directory' find /usr/local/src/hiawatha -maxdepth 1 -mindepth 1 -type f | while read FILE; do BASENAME="$(basename "$FILE")" # Prevent repository-specific files from being copied over to user's HOME if [[ "$BASENAME" != *'.md' ]] && [[ "$BASENAME" != *'.sh' ]] && [ "$BASENAME" != '.chezmoiroot' ] && [ "$BASENAME" != 'logo.png' ] && [ "$BASENAME" != '.gitlab-ci.yml' ]; then cp "$FILE" "$HOME/$BASENAME" chmod 600 "$HOME/$BASENAME" fi done ### Ensure ~/.local/bin files are executable logg info 'Ensuring scripts in ~/.local/bin are executable' find "$HOME/.local/bin" -maxdepth 1 -mindepth 1 -type f | while read BINFILE; do chmod +x "$BINFILE" done ### Chezmoi if [ ! -f "$HOME/.config/chezmoi/chezmoi.yaml" ]; then logg info 'Running `chezmoi init` since the ~/.config/chezmoi/chezmoi.yaml is not present' chezmoi init fi logg info 'Running `chezmoi apply`' cat <> /tmp/chezmoi-intro # User / Environment Variable Configuration This script will automatically set up a handful of different configurations / integrations if you decide to add your information. The script will first check for environment variables and then show prompts to fill in the gaps if the system is not headless. Below you can find a description of what each piece of information is used for as well as the name of the environment variable you can specify to bypass the prompt. ### Work Environment Set to true if you are setting up a work environment where things like Tor should not be installed. * Environment variable: `WORK_ENVIRONMENT` ### Restricted Environment Set to true if you are setting up an environment that should not use sudo / administrator privileges. This is a WIP. * Environment variable: `RESTRICTED_ENVIRONMENT` ### Software Group The category you select for software group will determine which list of software should be installed. The lists are configurable by modifying `~/.local/share/chezmoi/software.yml`. * Environment variable: `SOFTWARE_GROUP` ### Name Enter your full name as you would like it to appear in configuration files such as the Git configuration. * Environment variable: `FULL_NAME` ### E-mail Enter your primary e-mail address. * Environment variable: `PRIMARY_EMAIL` ### Public GPG Key ID If you have a public GPG key available on the Ubuntu or MIT keyservers, then you can enter it so that it is automatically imported. * Environment variable: `KEYID` ### Timezone Enter your timezone in the format of `America/New_York`. It should be available in the TZ database. * Environment variable: `TIMEZONE` ### Domain The domain address you would like to use for any part of the deployment that involves launching a publicly web service. * Environment variable: `PUBLIC_SERVICES_DOMAIN` ### CloudFlare API Token The API token is used to automatically configure various web services that rely on public DNS records. * Environment variable: `CLOUDFLARE_API_TOKEN` ### GitHub Read-Only Token Pass in a GitHub read-only token linked to your account to automatically save a backup of your GitHub repositories. For more information, see [this link](https://github.com/gabrie30/ghorg#scm-provider-setup). * Environment variable: `GITHUB_READ_TOKEN` ### GitLab Read-Only Token Pass in a GitLab read-only token linked to your account to automatically save a backup of your GitLab repositories. For more information, see [this link](https://github.com/gabrie30/ghorg#scm-provider-setup). * Environment variable: `GITLAB_READ_TOKEN` ### G-mail Address Add a G-mail address which you would like to use as the handler for outgoing SMTP mail. * Environment variable: `GMAIL_ADDRESS` ### G-mail App Password Add the app password to your G-mail address so that outgoing mail can be handled by G-mail. * Environment variable: `GMAIL_APP_PASSWORD` ### Ngrok Authentication Token Add your Ngrok authentication token so that the configuration file can be automatically generated. * Environment Variable: `NGROK_AUTH_TOKEN` ### Slack API Token Add your Slack API token so that `slackterm` can be automatically set up. * Environment Variable: `SLACK_API_TOKEN` ### Tabby Configuration ID Add your Tabby configuration ID to automatically sync Tabby settings. * Environment Variable: `TABBY_CONFIG_ID` ### Tabby Sync Token Add your Tabby sync token to automatically sync Tabby settings. This works in conjunction with the Tabby Configuration ID mentioned above. * Environment Variable: `TABBY_SYNC_TOKEN` ## EOF ### Show README.md snippet if command -v glow > /dev/null; then glow /tmp/chezmoi-intro fi ### Prompt for variables 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 ~/.local/share/chezmoi/home/.chezmoidata.yaml file.' SOFTWARE_GROUP="$(gum choose "Basic" "Standard" "Development" "Experimental")" fi fi ### Run chezmoi apply logg info 'Running `chezmoi apply`' chezmoi apply