#!/bin/bash
# Derek's Debian initialization script, only support Debian 11-12
# curl -LO https://repo.sxl.net/nix/debinit12.sh ; chmod +x debinit12.sh


## log everything to debinit.log
# exec &> >(tee -a "debinit.log")

### my functions
die() { printf '\n%s\nScript Aborted!\n' "ERROR: $1" >&2 ; exit 1; } ### die <msg> ^echo message and then die
require() { for n in "$@" ; do [[ $(command -v "$n" 2>&1) ]] || die "required command $n not found"; done; }
help() { echo "syntax: debinit.sh <fqdn>"; }

config_ssh() {
    echo "## allow root ssh"
    tasksel install ssh-server 
    apt install openssh-server openssh-client 
    echo 'PermitRootLogin yes' > /etc/ssh/sshd_config.d/PermitRootLogin_yes
    echo 'HashKnownHosts no' > /etc/ssh/ssh_config.d/HashKnownHosts_no
    systemctl restart sshd
}

config_apt() {
    echo "## update debian source.list"
    apt-get -yq install lsb-release
    url="http://deb.debian.org/debian"
    out="/etc/apt/sources.list"
    ver="$(lsb_release -sc)"
    repo="main contrib non-free non-free-firmware"
    mv -bf "$out" "${out}.orig"
    touch "$out"
    {
    echo "deb ${url} ${ver} ${repo}"                       
    echo "deb ${url}-security ${ver}-security ${repo}"     
    echo "deb ${url} ${ver}-updates ${repo}"               
    echo "#deb ${url} ${ver}-backports ${repo}"             
    echo "#deb-src ${url} ${ver} ${repo}"                   
    echo "#deb-src ${url}-security ${ver}-security ${repo}" 
    echo "#deb-src ${url} ${ver}-updates ${repo}"           
    echo "#deb-src ${url} ${ver}-backports ${repo}"         
    } >> "$out"
    cat /etc/apt/sources.list
    apt-get -yq update
    apt-get -yq dist-upgrade
}

config_locale() {
    echo "## set locale"
    apt-get -yq install locales
    sed -i '/^en_US/d' /etc/locale.gen # delete previous entries
    echo 'en_US ISO-8859-1' >> /etc/locale.gen
    echo 'en_US.UTF_8 UTF-8' >> /etc/locale.gen
    locale-gen
    update-locale LANG=en_US.UTF-8
    update-locale LANGUAGE=en_US:en
    update-locale LC_CTYPE="en_US.UTF-8"
    update-locale LC_NUMERIC="en_US.UTF-8"
    update-locale LC_TIME="en_US.UTF-8"
    update-locale LC_COLLATE="en_US.UTF-8"
    update-locale LC_MONETARY="en_US.UTF-8"
    update-locale LC_MESSAGES="en_US.UTF-8"
    update-locale LC_PAPER="en_US.UTF-8"
    update-locale LC_NAME="en_US.UTF-8"
    update-locale LC_ADDRESS="en_US.UTF-8"
    update-locale LC_TELEPHONE="en_US.UTF-8"
    update-locale LC_MEASUREMENT="en_US.UTF-8"
    update-locale LC_IDENTIFICATION="en_US.UTF-8"
    update-locale LC_ALL
}

inst_pkg() {
    echo "## install essential packages"
    apt-get -yq update
    apt-get -yq dist-upgrade
    apt-get install -yq openssh-server sudo wget curl aria2 man gnupg gnupg2
    apt-get install -yq vim-nox htop iotop dialog net-tools tmux fail2ban ufw
    apt-get install -yq lsb-release dnsutils
    apt-get -yq autoclean
    apt-get -yq autoremove
    # fix fail2ban bug in debian12
    echo -e "[sshd]\nbackend=systemd\nenabled=true" | sudo tee /etc/fail2ban/jail.local
    systemctl restart fail2ban
}

config_mail() {
    # put hostname in postfix main.cf
    DEBIAN_FRONTEND=noninteractive apt-get install -yq postfix mailutils
    sed -i '/^myhostname/d' /etc/postfix/main.cf # delete previous entries
    echo "myhostname=$(hostname -f)" > /etc/mailname
    systemctl restart postfix
    # forward root email to systems mailbox
    echo "systems@sxl.net" > /root/.forward
    echo "Testing message" | mail -s "Testing sent from server: $(hostname -f)" root
}

config_upgrade() {
    echo "## enable unattended upgrade"
    apt-get -y install unattended-upgrades
    echo 'Unattended-Upgrade::Mail "root";' > /etc/apt/apt.conf.d/50unattended-upgrades-mailtoroot
    systemctl start unattended-upgrades
    systemctl enable unattended-upgrades

}

disable_ipv6() {
    echo "## disable IPv6"
    echo 'net.ipv6.conf.all.disable_ipv6 = 1' >> /etc/sysctl.conf
    sysctl -p
}


make_swap() {
    echo "## make swapfile if necessary"
    makeswap=Y
    [[ $(swapon --show) ]] && makeswap=N   ## already has swap
    [[ $(systemd-detect-virt -c) = "none" ]] || makeswap=N ## running in a container
    echo $makeswap
    if [[ $makeswap == Y ]]; then
        echo "## create swap file"
        ram_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
        ram_b=$((ram_kb*1024/2)) # half of ram size
        fallocate -l $ram_b /swapfile || exit
        chmod 600 /swapfile || exit
        mkswap /swapfile || exit
        swapon /swapfile || exit
        echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
        #sysctl vm.swappiness=10
        #sysctl vm.vfs_cache_pressure=50
        echo 'vm.swappiness=10' >> /etc/sysctl.conf
        echo 'vm.vfs_cache_pressure=50' >> /etc/sysctl.conf
        sysctl -p
    fi
}

inst_vmtools() {
    echo "## install various machine specific tools"
    case $(systemd-detect-virt) in
    	none)
    		echo "Running in physical machine"
    		apt-get install -y haveged ;;
    	vmware)
    		echo "Running in VMWARE"
    		apt-get install -y haveged open-vm-tools  ;;
    	kvm)
    	    echo "Running in KVM"
    		apt-get install -y haveged qemu-guest-agent ;;
    	oracle)
    		echo "Running in Virtualbox, please install guest additions manually"
    		apt-get install -y haveged ;;
    esac
}

config_pref() {
    echo "installing Derek's preferences and scripts"
    update-alternatives --set editor /usr/bin/vim.nox
    cd ~ || exit
    curl -o ~/.bashrc https://repo.sxl.net/nix/bashrc.txt
    curl -o ~/.vimrc https://repo.sxl.net/nix/vimrc.txt
    curl -o ~/backup-etc.sh https://repo.sxl.net/nix/backup-etc.sh
    mkdir ~/.ssh && touch ~/.ssh/authorized_keys
    curl -o ~/.ssh/authorized_keys https://repo.sxl.net/.h/proj/cert/id_ed25519.pub
    # shellcheck disable=SC1090
    source ~/.bashrc 
    chmod +x backup-etc.sh
}

inst_cockpit() {
    #apt-get install -yq cockpit-system cockpit-ws ## cockpit
    cd ~ || exit
    apt-get install cockpit
    mv /etc/motd /etc/motd.orig && touch /etc/motd # empty mtod
    out="/etc/cockpit/ws-certs.d"
    repo="https://repo.sxl.net/.h/proj/cert"
    curl -o "$out/server.key" "$repo/star.sxl.net-wan.pem.key"
    curl -o "$out/server.crt" "$repo/star.sxl.net-wan.pem.crt"
    systemctl restart cockpit
    echo "You may open Cockpit at https://$(hostname -f):9090"
}


############################################################
### MAIN program

# exit if not running as root
[[ $EUID -ne 0 ]] && echo "ERROR: This script must be run as root" && exit 1

# check requirements
require lsb_release
OSDIST=$(lsb_release -si)
OSVER=$(lsb_release -sr)
OSARCH="$(uname -m)"
[[ "$OSDIST" != "Debian" ]] && die "Unsupported OS: $OSDIST"
[[ "$OSVER" -lt 12 ]]       && die "Unsupported version: $OSVER"
[[ "$OSARCH" != "x86_64" ]] && die "Unsupported architecture: $OSVER"

# validate parameters
if [ "$#" -ne 1 ]; then { help; die "require 1 parameter"; }; fi

fqdn="$1"
#ip="$2"
re="^([a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]\.)+[a-zA-Z]{2,}$" # valid fqdn
if [[ "$fqdn" =~ $re ]]; 
    then { echo "$1 is FQDN"; } 
    else { help; die "ERROR: $1 is not FQDN"; } 
fi
# re="^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
# if [[ "$ip" =~ $re ]];
#     then { echo "$2 is IPv4";}
#     else { help; die "ERROR: $2 is not valid IPv4"; }
# fi

hostname=${fqdn%%.*} # before first dot
#domainname=${fqdn#*.}


# ask for confirmation
echo "\
debinit started at $(date)
IMPORTANT !!!
1. Did you changed default password?
2. Are these settings correct?
   hostname   : $(hostname)
   FQDN       : $(hostname -f)
   IP address : $(hostname -I)
   Distro/Ver : ${OSDIST} ${OSVER}
   Arch       : ${OSARCH}"
read -r -p "Do you want to continue? [y/N] " response
[[ ! "$response" =~ [Yy] ]] && exit 0

# set /etc/hostname
echo "$hostname" > /etc/hostname

# /etc/hosts
#hostline="$ip    $fqdn    $hostname"
#sed -i "/^127\..*debian$/c\\$hostline" /etc/hosts
sed -i '/^127\..*debian$/d' /etc/hosts
cat /etc/hosts

# do config

config_ssh
config_apt
config_locale
inst_pkg
config_mail
config_upgrade
config_pref
#inst_cockpit

if [[ ! $(systemd-detect-virt -c) == "none" ]]; then {
    make_swap
    disable_ipv6
    inst_vmtools
}
fi
