#!/bin/bash

# Example device UUID
# a015b120b1cb08d0a03ae12093253c736db0656e

# Git clone URL
GIT_URL=ssh://gitolite@git.pebblesnetwork.com:23114/kobalt-source.git

# The user that X?ubuntu was installed with
USER=pebbles

# Passwords for various things
GRUB_PASSWORD=monkey11
ROOT_PASSWORD=pebbles11
USER_PASSWORD=stone11

# The version of X?ubuntu being used
VERSION=16.10

# The netctl security configuration script
NETCTL_SECURITY=/etc/sysctl.d/60-pebbles-network-security.conf

# SSH information
SSH_PASSPHRASE=lerk44

# Private key
SSH_ID_RSA=$(cat << 'EOF'
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,AAC7324133A90B15

XPVKFxhlwq11Yh2oz5r3TSe1ks2/9IwvQHlXumNP0J46fEFow7UbK0ca0U4E0X8H
0Gd0sI10eWRnBTiYneYq4/r93eiGMR2pTcZE3DaUYHzis2fiyx2JRdLEvbQ1VU6v
YH7cUDQUM+RMvBViMiaWxetUJQXCSQaWTcbQDK277JvwlUSPqGsN7ckErOQCMxRN
Fv8mopqNujKjoVG12JmLm6KtvX6vkD9iehxLFUnZeXm0loWWU2nKZpkqt7j0MqHF
T/A++iNrDWms/rlaaQrFu2tPh0h923yCbaOUUw1EPmNmbh/GkxC/2PYbp5Akg07+
L7xXRhO72e8y7wCPNHJafc1Y+zxW8TREz2+JTbo8oe3cHp0gIaSi4+2fPQ9CrdAT
RmvSI4M9doH6s1yNAl1hD435aAd3Bwxqm1inj7L6SjeSYF68zbKlEUuq/fanWF5K
jpP+3khEa6xb+bYO1Nh11wDOSvsuofhLswN9iRb2xHpy6UZ/gWnizw8YaoeV+aMQ
CklJeXfWLYhPJg9HoZO48Lqfv0bDW35tyjsTKgeIiGddzsUIvEb0gN3FxbGj7ChN
2dQQXn+rZ+HJOfGRrpVwWYGdA2FHDplWmOgUf9eeOxUct6o0VZt8hmMYkykqjQQi
0yeqoq4JHD3JOSr/HLOjtQNJA9sCeRVd1NOFHTDh2JGbzd9fGJ0V5eFjMelbGy0C
ysu0D+xYAHQk1txEmlkB408Y732L3y+ks4EpsxYFdMAr1i36F1DxjP1aCa+GHKaO
kJCttQ7Lh6cI35S41hZlAC96rQOu4BlmH332scAMOH8tLoHNEuhjb1A6nJhErdW9
y0h/hL6F46BXKRrKVQde2G9GmSygmQt+1aqZJ3daqLQ88Tv0Q9eVNtaEfeRSZJiY
utX3te3nHkQcIWzZHqH18F0OHhpBjVyBY382pKM/TVvkrIPqb7EZ3BHgAi5Uh/k4
oCuwUWaGMXTdnjnnMVjlUzH8a2gAQ+2ITGSJAdu3woD2B6jlmoSiM6p25Hh5Tqae
GzLxuJ82aSWyselc2cfrnNFw9HgTuIhjP4hFuebTLDS0LEwGcEqlxuxFvLhuE2Zq
atp7m+qCqoYbp5sf7dXKjq1fm/yNXCoUrXPHJQlipPGV7XEa7jM12FDxotyaLATR
qyOSjCd8g7q3SLdYED0xZyxJy2LkiQJjS5HBrAd9CbukzZkam7i7fPqHLE71s29K
06dI+te5Q1pnMS0ocMaj6uHwjDNWd/KCiXOquSsRxu6f2NLlPWFdl+8H0XSu19Cu
m4Ly8+EmuqpOpl1Y9StYx23joF8tWNzp7rgUrUatc9oTt3pnipOHv8LF2w1X22wg
bLmXC9ICFspRNJrPGSN78I37IP0jBqsOPTm1yR+VyA59yT2cidVtoH7AThIn0WnA
G6JI7BvpzGYo5LeyDhjJev7Azxf0eYVuDrs00dZeos2jSZIrBgsi5N1uURb7N9uM
UaOKnwhRA1U7qWEh/6CDc9P/i1VjI+6jA/S50W4s43bfGjxeSRQXUdPOyrjZtOqQ
a/47N1SfgYKM55VG+2jQ+3wMRroot6pyIgnOCxBiT3WzSY+5lb+oQw==
-----END RSA PRIVATE KEY-----
EOF
)

# Public key
SSH_ID_RSA_PUB=$(cat << 'EOF'
ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQBw5d4tnIQUXbDjIeUXf8ej4VJNSUPA
orKVVJIwgKb0X5qghaHV/KIlrLAIhwUaUh+eBOj2aZ9whKZQFVf2EkzTr5QkX5vR
1kVA1hLKvM0vASY3DtMLQ3aQ8tZuxBa+hAnNVTmSZSjUAOsMUQYd2gLZGRVTra0i
VGaDLwamb6JsWyydqwiP5Pw0HD2ganCiZq0LyQTPQtcLpkzEK432/oRZu6FBA5An
i2zFSHAwL1eSppY+vLqkKyIOME4QULfJhlJFVMVrnEg8QZ+bZe/tmxBcVfLCH5L1
AFod51z3o7x8cfWiL7RWOANQ8vDnRyHG2OcwMu9vWD/N7WPi4K1snc+9
EOF
)

# Function to check if a command exists or not
function exists {
   type "$1" > /dev/null 2>&1
}

# Prints a colorized failure and exits
function fail {
   tput bold
   tput setaf 1
   echo "$1"
   tput sgr0
   exit 1
}

# Prints a colorized message
function message {
   tput bold
   tput setaf 3
   echo ">> $1"
   tput sgr0
}

function heading {
   tput bold
   tput setaf 5
   echo ""
   echo "  [ $1 ]  "
   echo ""
   tput sgr0
}

function success {
   tput bold
   tput setaf 2
   echo ">> Completed installation <<"
   tput sgr0
}

function getpkg {
   if dpkg --get-selections | grep -q "^$1[[:space:]]*install$" ; then
       message "Updating $1"
   else
       message "Installing $1"
   fi
   apt-get install -y $1 > /dev/null
}

# The following function checks if the argument passed to it
# is a valid MD5 hash as a perliminary test for the device UUID
function is_valid_hash {
   case $1 in
       ( *[![0-9A-Fa-f]* | "" ) return 1 ;;
       ( * )
           case ${#1} in
               ( 32 | 40 )    return 0 ;;
               ( * )        return 1 ;;
           esac
   esac
}

# The following technique uses DEBUG trap to cache each command line
# before actually executing and then uses ERR trap to fail the command
# early
#
# On failures of any command we can fail the whole installation instead
# of being left with a partially completed install. This is further
# annoying because output from the install will clobber the terminal
# and hide the failures
function trap_debug {
   if [ "${BASH_COMMAND:0:6}" != "trap_err" ] ; then
       _lastcmd="$BASH_COMMAND"
   fi
}

function trap_err {
   if [ -n "$_lastcmd" ] ; then
       fail "\"$_lastcmd\" failed"
   fi
}

trap 'trap_err $? ${PIPESTATUS[*]}' ERR
trap 'trap_debug' DEBUG

# Ensure this is an Ubuntu installation
if ! exists lsb_release || ! exists apt-get ; then
   fail "This does not appear to be a Ubuntu installation"
fi

# Ensure we're running this script as root
if [ "$(id -u)" -ne "0" ] ; then
   fail "This script must be run as root"
fi

# Extra brownie points
cat << 'EOF'
 _  __     _           _ _     ___           _        _ _
| |/ /___ | |__   __ _| | |_  |_ _|_ __  ___| |_ __ _| | | ___ _ __
| ' // _ \| '_ \ / _` | | __|  | || '_ \/ __| __/ _` | | |/ _ \ '__|
| . \ (_) | |_) | (_| | | |_   | || | | \__ \ || (_| | | |  __/ |
|_|\_\___/|_.__/ \__,_|_|\__| |___|_| |_|___/\__\__,_|_|_|\___|_|

EOF

SKIP_UPDATE=0

# Prompt for device UUID
if [ -f "/home/${USER}/kobalt/kobalt/device-uuid.txt" ] ; then
   read -r -p "Would you like to skip to updating Kobalt [y/N] " response
   case $response in
       [yY][eE][sS]|[yY])
           SKIP_UPDATE=1
           ;;
       *)
           SKIP_UPDATE=0
           ;;
   esac
   DEVICE_UUID="$(</home/${USER}/kobalt/kobalt/device-uuid.txt)"
   if ! is_valid_hash "${DEVICE_UUID}" ; then
       fail "Existing device UUID ${DEVICE_UUID} is not a valid device UUID"
   else
       echo -n "Using device UUID: "
       tput bold
       tput setaf 7
       echo "${DEVICE_UUID}"
       tput sgr 0
   fi
else
   echo -n "Please enter a device UUID: "
   tput bold
   tput setaf 7
   read DEVICE_UUID
   if ! is_valid_hash "${DEVICE_UUID}" ; then
       fail "${DEVICE_UUID} is not a valid device UUID"
   fi
   tput sgr 0
fi

# Do system updates if enabled
if [ "${SKIP_UPDATE}" -eq "0" ] ; then
   heading "Updating system"

   # Update the package list
   message "Updating package list"
   apt-get update -y

   # Upgrade distribution
   if do-release-upgrade -c /dev/null 2>&1 ; then
       message "Upgrading distribution"
       yes | do-release-upgrade
   fi

   heading "Configuring system"

   # Install packages
   message "Installing base packages"
   getpkg xinput-calibrator
   getpkg openssh-server
   getpkg x11vnc
   getpkg openbox
   getpkg ssh
   getpkg git
   getpkg tmux
   getpkg wget
   getpkg geany
   getpkg lm-sensors
   getpkg expect

   message "Installing development packages"
   getpkg build-essential
   getpkg yasm
   getpkg nasm
   getpkg cmake
   getpkg libcupsimage2-dev
   getpkg libx11-dev
   getpkg libgtkglext1
   getpkg libasound2-dev
   getpkg libgl1-mesa-dev
   getpkg libreadline-dev
   getpkg libgtkglext1-dev
   getpkg libgtk2.0-dev

   # Enable if you want nightly Intel drivers

   # Check if there is an Intel GPU
   #if lspci | grep -i vga | grep -i intel ; then
   #    message "Installing Intel GPU drivers"
   #    # Get the signing key
   #    wget --no-check-certificate https://download.01.org/gfx/RPM-GPG-KEY-ilg -O - | apt-key add -
   #    # Add to our sources
   #    echo "deb https://download.01.org/gfx/ubuntu/${VERSION}/main Ubuntu ${VERSION}" >> /etc/apt/sources.list
   #    # Update sources
   #    apt-get update
   #    # Download and install the driver
   #    getpkg intel-linux-graphics-installer
   #fi

   heading "Configuring session"

   # Setup LightDM entry for OpenBox
   cat << 'EOF' > /usr/share/xsessions/openbox.desktop
[Desktop Entry]
Encoding=UTF-8
Name=Openbox
Exec=/usr/bin/openbox-session
TryExec=/usr/bin/openbox-session
Icon=openbox.png
Type=XSession
EOF
   chmod +x /usr/share/xsessions/openbox.desktop

   # Ensure we always start from Openbox
   cat << 'EOF' > "/home/${USER}/.dmrc"
[Desktop]
Session=openbox
EOF
   chmod +x "/home/${USER}/.dmrc"
   chown "${USER}:${USER}" "/home/${USER}/.dmrc"

   # Ensure we autologin as the user from LightDM
   cat << EOF > /etc/lightdm/lightdm.conf
[SeatDefaults]
autologin-user=${USER}
autologin-user-timeout=0
user-session=openbox
EOF

   # Ensure we autostart the engine from Openbox
   mkdir -p "/home/${USER}/.config/openbox"
   touch "/home/${USER}/.config/openbox/autostart.sh"
   cat << 'EOF' > "/home/${USER}/.config/openbox/autostart.sh"
sleep 5
~/kobalt/kobalt/kobalt-release
EOF
   chown "${USER}:${USER}" "/home/${USER}/.config/openbox"
   chown "${USER}:${USER}" "/home/${USER}/.config/openbox/autostart.sh"
   chmod +x "/home/${USER}/.config/openbox/autostart.sh"

   # Setup SSH
   message "Setting up SSH"

   # Create the users .ssh directory with everything
   mkdir -p "/home/${USER}/.ssh"
   echo "${SSH_ID_RSA}" > "/home/${USER}/.ssh/id_rsa"
   echo "${SSH_ID_RSA_PUB}" | tr --delete '\n' > "/home/${USER}/.ssh/id_rsa.pub"
   chmod 700 "/home/${USER}/.ssh"
   chmod 600 "/home/${USER}/.ssh/id_rsa"
   chmod 644 "/home/${USER}/.ssh/id_rsa.pub"
   chown -R "${USER}:${USER}" "/home/${USER}/.ssh"
   # Disable strict host key checking
   echo "StrictHostKeyChecking=no" >> /etc/ssh/ssh_config

   # Remove unwanted autostart items
   if [ -e /etc/xdg/autostart/update-notifier.desktop ]; then
       message "Removing unwanted autostart items"
       mv /etc/xdg/autostart/update-notifier.desktop /etc/xdg/autostart/update-notifier.desktop-dontuse
   fi

   # Secure the installation
   heading "Securing installation"

   # Set up passwords
   # (REF::WAKEFERN.SECURITY : lilo-linux-single-user-mode)
   message "Setting root password"
   passwd root << EOF > /dev/null 2>&1
${ROOT_PASSWORD}
${ROOT_PASSWORD}
EOF

   message "Setting user password"
   passwd "${USER}" << EOF > /dev/null 2>&1
${USER_PASSWORD}
${USER_PASSWORD}
EOF

   # Password protect bootloader
   # (REF::WAKEFERN.SECURITY : linux-grub-missing-passwd)
   if ! grep -q superusers /etc/grub.d/00_header; then
       message "Setting bootloader password"
       # Create the super user
       echo >>/etc/grub.d/00_header \# security - require a login for administration of boot menu
       echo >>/etc/grub.d/00_header cat \<\< EOF
       echo >>/etc/grub.d/00_header set superusers=\"admin\"
       echo >>/etc/grub.d/00_header password admin ${GRUB_PASSWORD}
       echo >>/etc/grub.d/00_header EOF
       # Mark each menu entry as not requiring a user (otherwise we'd be prompted for the superuser login on every boot)
       cp /etc/grub.d/10_linux /etc/grub.d/10_linux.orig
       sed "s/CLASS} \\\\$menuentry_id_option/CLASS} --unrestricted \\\\$menuentry_id_option/" </etc/grub.d/10_linux.orig >/etc/grub.d/10_linux
       rm /etc/grub.d/10_linux.orig
       update-grub
   fi

   # Disable root login at terminals
   # (REF::WAKEFERN.SECURITY : unix-anonymous-root-logins)
   message "Disabling root TTY login"
   echo > /etc/securetty

   # Disable root login via SSH
   # (REF::WAKEFERN.SECURITY : unix-anonymous-root-logins)
   message "Disabling root SSH login"
   cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig
   sed s/PermitRootLogin\ yes/PermitRootLogin\ no/ </etc/ssh/sshd_config.orig >/etc/ssh/sshd_config
   rm /etc/ssh/sshd_config.orig

   # Disable ICMP redirect packets
   # (REF::WAKEFERN.SECURITY : linux-icmp-redirect)
   message "Disabling ICMP redirect packets"
   echo net.ipv4.conf.all.accept_redirects=0 > ${NETCTL_SECURITY}
   echo net.ipv4.conf.default.accept_redirects=0 >> ${NETCTL_SECURITY}
   echo net.ipv4.conf.all.secure_redirects=0 >> ${NETCTL_SECURITY}
   echo net.ipv4.conf.default.secure_redirects=0 >> ${NETCTL_SECURITY}

   # Disable IP source routing
   # (REF::WAKEFERN.SECURITY : generic-ip-source-routing-enabled)
   message "Disabling IP source routing"
   echo net.ipv4.conf.all.accept_source_route=0 >> ${NETCTL_SECURITY}
   echo net.ipv4.conf.all.forwarding=0 >> ${NETCTL_SECURITY}
   echo net.ipv4.conf.all.mc_forwarding=0 >> ${NETCTL_SECURITY}
   echo net.ipv4.conf.default.accept_source_route=0 >> ${NETCTL_SECURITY}
   echo net.ipv4.conf.default.forwarding=0 >> ${NETCTL_SECURITY}
   echo net.ipv4.conf.default.mc_forwarding=0 >> ${NETCTL_SECURITY}

   # Rate limit SSH access to three connections
   message "Rate limiting SSH access"
   iptables -A INPUT -p tcp --syn --dport 22 -m connlimit --connlimit-above 3 -j REJECT
fi

if [ ! -d "/home/${USER}/kobalt" ] ; then
   heading "Installing Kobalt"
else
   heading "Updating Kobalt"
fi

# Disable the SSH keyring
unset SSH_AUTH_SOCK
# Bring up an SSH agent with our password
eval $(ssh-agent)
# Send the password into the agent
expect <<- EOF
   spawn ssh-add "/home/${USER}/.ssh/id_rsa"
   expect "Enter passphrase"
   send ${SSH_PASSPHRASE}\r
   expect eof
EOF

if [ ! -d "/home/${USER}/kobalt" ] ; then
   pushd "/home/${USER}"
       git clone --depth 1 "${GIT_URL}" kobalt
   popd
else
   # Disable the SSH keyriong
   pushd "/home/${USER}/kobalt"
       git pull
   popd
fi

# Calculate the number of threads we can use to build things
CORES=$(nproc --all)

# Compile everything
message "Compiling Kobalt"
pushd "/home/${USER}"
   pushd kobalt
       message "Building third party dependencies"
       pushd thirdparty
           make -j${CORES} install
       popd
       pushd source
           # Check if this device has nvidia so we can enable nvbug workaround
           if lspci | grep -i vga | grep -i nvidia ; then
               message "Building NVIDIA workaround"
               pushd nvbug
                   make -j${CORES} install
               popd
           fi
           message "Building printer drivers"
           pushd cups
               make -j${CORES} install
           popd
           message "Building libKobalt"
           pushd libkobalt
               make -j${CORES}
           popd
           message "Building Kobalt"
           pushd engine
               make -j${CORES} install
           popd
       popd
   popd
popd

message "Configuring Kobalt"

# Install device UUID
echo "${DEVICE_UUID}" > "/home/${USER}/kobalt/kobalt/device-uuid.txt"
chown -R "${USER}:${USER}" "/home/${USER}/kobalt"

success

heading "Rebooting"

reboot
