#!/bin/sh
# ============================================================================
#
# ██╗ █████╗ ███████╗██╗ ██╗██╗ ██╗██████╗ ██╗███████╗ Z
# ██║ ██╔══██╗╚══███╔╝╚██╗ ██╔╝██║ ██╔╝██╔══██╗██║██╔════╝ Z
# ██║ ███████║ ███╔╝ ╚████╔╝ █████╔╝ ██████╔╝██║███████╗ z
# ██║ ██╔══██║ ███╔╝ ╚██╔╝ ██╔═██╗ ██╔══██╗██║╚════██║ z
# ███████╗██║ ██║███████╗ ██║ ██║ ██╗██║ ██║██║███████║
# ╚══════╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚══════╝
#
# sdeploy - Kris's Auto Rice Bootstrapping Scripts
# "The only way to do great work is to automate the boring parts."
#
# System: Wired (Artix OpenRC pentesting workstation)
# Author: Kris Yotam
# Contact: kris@krisyotam.com
# License: GPL-3.0-only
# Repository: https://git.sr.ht/~krisyotam/sdeploy
# ============================================================================
### OPTIONS AND VARIABLES ###
dotfilesrepo="https://git.sr.ht/~krisyotam/srice"
progsfile="https://git.sr.ht/~krisyotam/sdeploy/blob/main/system/sd-wired/progs.csv"
aurhelper="yay"
repobranch="main"
blackarchstrap="https://blackarch.org/strap.sh"
export TERM=ansi
### FUNCTIONS ###
installpkg() {
pacman --noconfirm --needed -S "$1" >/dev/null 2>&1
}
error() {
printf "%s\n" "$1" >&2
exit 1
}
welcomemsg() {
whiptail --title "Wired Deploy" \
--msgbox "This script bootstraps an Artix OpenRC pentesting workstation with dwm, srice dotfiles, and BlackArch tools.\n\n-Kris" 10 60
whiptail --title "Preflight" --yes-button "Ready" \
--no-button "Cancel" \
--yesno "Ensure:\n\n1. Running as root\n2. Pacman is synced\n3. Keyrings are current\n4. Internet is up" 12 60
}
getuserandpass() {
name=$(whiptail --inputbox "Enter a username for the account." 10 60 3>&1 1>&2 2>&3 3>&1) || exit 1
while ! echo "$name" | grep -q "^[a-z_][a-z0-9_-]*$"; do
name=$(whiptail --nocancel --inputbox "Invalid. Lowercase letters, digits, - or _ only." 10 60 3>&1 1>&2 2>&3 3>&1)
done
pass1=$(whiptail --nocancel --passwordbox "Enter a password for $name." 10 60 3>&1 1>&2 2>&3 3>&1)
pass2=$(whiptail --nocancel --passwordbox "Confirm password." 10 60 3>&1 1>&2 2>&3 3>&1)
while [ "$pass1" != "$pass2" ]; do
unset pass2
pass1=$(whiptail --nocancel --passwordbox "Mismatch. Enter password again." 10 60 3>&1 1>&2 2>&3 3>&1)
pass2=$(whiptail --nocancel --passwordbox "Confirm password." 10 60 3>&1 1>&2 2>&3 3>&1)
done
}
usercheck() {
! { id -u "$name" >/dev/null 2>&1; } ||
whiptail --title "WARNING" --yes-button "CONTINUE" \
--no-button "Cancel" \
--yesno "User \`$name\` already exists. Conflicting dotfiles will be overwritten. Personal files are untouched.\n\nPassword will be changed to what you entered." 12 70
}
preinstallmsg() {
whiptail --title "Ready" --yes-button "Go" \
--no-button "Cancel" \
--yesno "Installation is fully automated from here. This will take a while.\n\nPress <Go> to begin." 10 60 || {
clear
exit 1
}
}
adduserandpass() {
whiptail --infobox "Adding user \"$name\"..." 7 50
useradd -m -g wheel -s /bin/mksh "$name" >/dev/null 2>&1 ||
usermod -a -G wheel "$name" && mkdir -p /home/"$name" && chown "$name":wheel /home/"$name"
export repodir="/home/$name/.local/src"
mkdir -p "$repodir"
chown -R "$name":wheel "$(dirname "$repodir")"
echo "$name:$pass1" | chpasswd
unset pass1 pass2
}
refreshkeys() {
case "$(readlink -f /sbin/init)" in
*systemd*)
whiptail --infobox "Refreshing Arch keyring..." 7 40
pacman --noconfirm -S archlinux-keyring >/dev/null 2>&1
;;
*)
whiptail --infobox "Enabling Arch repos for Artix..." 7 50
pacman --noconfirm --needed -S \
artix-keyring artix-archlinux-support >/dev/null 2>&1
grep -q "^\[extra\]" /etc/pacman.conf ||
echo "[extra]
Include = /etc/pacman.d/mirrorlist-arch" >>/etc/pacman.conf
pacman -Sy --noconfirm >/dev/null 2>&1
pacman-key --populate archlinux >/dev/null 2>&1
;;
esac
}
setupblackarch() {
whiptail --infobox "Adding BlackArch repository..." 7 50
curl -Ls "$blackarchstrap" | sh >/dev/null 2>&1
pacman -Sy --noconfirm >/dev/null 2>&1
}
manualinstall() {
pacman -Qq "$1" && return 0
whiptail --infobox "Installing \"$1\" manually..." 7 50
sudo -u "$name" mkdir -p "$repodir/$1"
sudo -u "$name" git -C "$repodir" clone --depth 1 --single-branch \
--no-tags -q "https://aur.archlinux.org/$1.git" "$repodir/$1" ||
{
cd "$repodir/$1" || return 1
sudo -u "$name" git pull --force origin master
}
cd "$repodir/$1" || exit 1
sudo -u "$name" makepkg --noconfirm -si >/dev/null 2>&1 || return 1
}
maininstall() {
whiptail --title "Wired" --infobox "[$n/$total] $1 $2" 7 70
installpkg "$1"
}
aurinstall() {
whiptail --title "Wired" --infobox "[$n/$total] (AUR) $1 $2" 7 70
echo "$aurinstalled" | grep -q "^$1$" && return 0
sudo -u "$name" $aurhelper -S --noconfirm "$1" >/dev/null 2>&1
}
gitmakeinstall() {
progname="${1##*/}"
progname="${progname%.git}"
dir="$repodir/$progname"
whiptail --title "Wired" --infobox "[$n/$total] (git) $progname $2" 7 70
sudo -u "$name" git -C "$repodir" clone --depth 1 --single-branch \
--no-tags -q "$1" "$dir" ||
{
cd "$dir" || return 1
sudo -u "$name" git pull --force origin master
}
cd "$dir" || exit 1
make >/dev/null 2>&1
make install >/dev/null 2>&1
cd /tmp || return 1
}
installationloop() {
([ -f "$progsfile" ] && cp "$progsfile" /tmp/progs.csv) ||
curl -Ls "$progsfile" | sed '/^#/d' >/tmp/progs.csv
total=$(wc -l </tmp/progs.csv)
aurinstalled=$(pacman -Qqm)
while IFS=, read -r tag program comment; do
n=$((n + 1))
echo "$comment" | grep -q "^\".*\"$" &&
comment="$(echo "$comment" | sed -E "s/(^\"|\"$)//g")"
case "$tag" in
"A") aurinstall "$program" "$comment" ;;
"G") gitmakeinstall "$program" "$comment" ;;
*) maininstall "$program" "$comment" ;;
esac
done </tmp/progs.csv
}
putgitrepo() {
whiptail --infobox "Deploying dotfiles..." 7 50
dir=$(mktemp -d)
[ ! -d "$2" ] && mkdir -p "$2"
chown "$name":wheel "$dir" "$2"
sudo -u "$name" git -C "$dir" clone --depth 1 \
--single-branch --no-tags -q --recursive -b "$repobranch" \
--recurse-submodules "$1" "$dir/repo"
sudo -u "$name" cp -rfT "$dir/repo" "$2"
rm -rf "$2/.git" "$2/README.md" "$2/LICENSE" "$2/FUNDING.yml" "$2/.stowrc" "$2/.stow-local-ignore"
rm -rf "$dir"
}
finalize() {
whiptail --title "Done" \
--msgbox "Wired is deployed.\n\n1. Log out of root\n2. Log in as $name\n3. Run startx\n\n-Kris" 12 60
}
### THE ACTUAL SCRIPT ###
pacman --noconfirm --needed -Sy libnewt ||
error "Must be root on an Arch-based system with internet."
welcomemsg || error "User exited."
getuserandpass || error "User exited."
usercheck || error "User exited."
preinstallmsg || error "User exited."
# Keyrings
refreshkeys || error "Failed to refresh keyrings."
# Bootstrap packages
for x in curl ca-certificates base-devel git ntp mksh dash; do
whiptail --infobox "Installing \`$x\`..." 7 50
installpkg "$x"
done
# Sync time
ntpd -q -g >/dev/null 2>&1
# Create user
adduserandpass || error "Error creating user."
[ -f /etc/sudoers.pacnew ] && cp /etc/sudoers.pacnew /etc/sudoers
# Temp passwordless sudo for builds
trap 'rm -f /etc/sudoers.d/wired-temp' HUP INT QUIT TERM PWR EXIT
echo "%wheel ALL=(ALL) NOPASSWD: ALL
Defaults:%wheel,root runcwd=*" >/etc/sudoers.d/wired-temp
# Pacman tweaks
grep -q "ILoveCandy" /etc/pacman.conf || sed -i "/#VerbosePkgLists/a ILoveCandy" /etc/pacman.conf
sed -Ei "s/^#(ParallelDownloads).*/\1 = 5/;/^#Color$/s/#//" /etc/pacman.conf
# Use all cores for compilation
sed -i "s/-j2/-j$(nproc)/;/^#MAKEFLAGS/s/^#//" /etc/makepkg.conf
# AUR helper
manualinstall "$aurhelper" || error "Failed to install AUR helper."
$aurhelper -Y --save --devel
# BlackArch repo
setupblackarch || error "Failed to add BlackArch repo."
# Install everything from progs.csv
installationloop
# Deploy dotfiles
putgitrepo "$dotfilesrepo" "/home/$name"
# Kill the beep
rmmod pcspkr 2>/dev/null
echo "blacklist pcspkr" >/etc/modprobe.d/nobeep.conf
# mksh as default interactive shell
chsh -s /bin/mksh "$name" >/dev/null 2>&1
# Home directory scaffold
for d in downloads src slipbox mail pix vids; do
sudo -u "$name" mkdir -p "/home/$name/$d"
done
sudo -u "$name" mkdir -p "/home/$name/.config/abook"
sudo -u "$name" mkdir -p "/home/$name/.config/mpd/playlists"
# Clone repos
whiptail --infobox "Cloning slipbox..." 7 50
sudo -u "$name" git clone --depth 1 -q \
"https://git.sr.ht/~krisyotam/slipbox" "/home/$name/slipbox" >/dev/null 2>&1 || true
whiptail --infobox "Cloning ctfs..." 7 50
sudo -u "$name" git clone --depth 1 -q \
"https://git.sr.ht/~krisyotam/ctfs" "/home/$name/ctfs" >/dev/null 2>&1 || true
# Dash as /bin/sh
ln -sfT /bin/dash /bin/sh >/dev/null 2>&1
# dbus UUID for Artix
dbus-uuidgen >/var/lib/dbus/machine-id
# dbus-launch for non-systemd session
[ "$(readlink -f /sbin/init)" != "/usr/lib/systemd/systemd" ] &&
echo "export \$(dbus-launch)" >/etc/profile.d/dbus.sh
# Tap to click
[ ! -f /etc/X11/xorg.conf.d/40-libinput.conf ] && printf 'Section "InputClass"
Identifier "libinput touchpad catchall"
MatchIsTouchpad "on"
MatchDevicePath "/dev/input/event*"
Driver "libinput"
Option "Tapping" "on"
EndSection' >/etc/X11/xorg.conf.d/40-libinput.conf
# Sudoers
echo "%wheel ALL=(ALL:ALL) ALL" >/etc/sudoers.d/00-wheel-can-sudo
echo "%wheel ALL=(ALL:ALL) NOPASSWD: /usr/bin/shutdown,/usr/bin/reboot,/usr/bin/mount,/usr/bin/umount,/usr/bin/pacman -Syu,/usr/bin/pacman -Syyu,/usr/bin/pacman -Syyu --noconfirm,/usr/bin/loadkeys,/usr/bin/pacman -Syyuw --noconfirm" >/etc/sudoers.d/01-cmds-without-password
echo "Defaults editor=/usr/bin/nvim" >/etc/sudoers.d/02-visudo-editor
mkdir -p /etc/sysctl.d
echo "kernel.dmesg_restrict = 0" >/etc/sysctl.d/dmesg.conf
# Cleanup
rm -f /etc/sudoers.d/wired-temp
finalize