#!/bin/bash
# Ubuntu 24.04 - 利用 whiptail 介面選擇各功能類別的安裝與設定腳本
# 功能分為：
#  1. 基礎設定：更新系統與安裝基本套件
#     (包含 PHP8.3-FPM、Apache、MySQL、ClamAV、Git、nmap、curl、lynx、wget、Composer、mutt、ntp)
#     並設定時區為 Asia/Taipei
#  2. PHP 設定：調整 Apache 使用 PHP-FPM 與必要模組
#  3. MSSQL 資料庫設定：安裝 ODBC 驅動、mssql-tools18 與 PHP MSSQL 擴展
#  4. log 設定：調整全域及 Apache 的 logrotate 設定
#     (設定為 daily、rotate 180、不壓縮且帶上日期)
#  5. ClamAV 設定：檢查 ClamAV 是否安裝並更新病毒資料庫
#  6. Apache 安全設定：更新 /etc/apache2/conf-enabled/security.conf
#
# 執行前會先檢查是否已安裝 whiptail，若未安裝則自動安裝。
# 每個項目在執行前會顯示詳細說明並確認後執行，且會先檢查是否已完成設定，
# 若已完成則跳過，避免重複作業。
#
# 執行結束後，將顯示一個總結介面，列出所有已完成項目與主要服務版本資訊，
# 包括 Apache、PHP、MySQL、ClamAV（使用 clamscan --version）以及時區設定。

set -e
PHPVER="8.3"

#---------------------------------------------------
# 檢查 whiptail 是否安裝，若未安裝則先安裝
if ! command -v whiptail &>/dev/null; then
    echo "whiptail 未安裝，正在安裝..."
    sudo apt-get update
    sudo apt-get install -y whiptail
fi

#---------------------------------------------------
# 輔助函式：檢查指定套件是否已安裝
package_installed() {
    dpkg -s "$1" &>/dev/null
}

#---------------------------------------------------
# 0. 時區設定：設定時區為 Asia/Taipei
configure_timezone() {
    echo "【時區設定】將時區設定為 Asia/Taipei..."
    sudo timedatectl set-timezone Asia/Taipei
    echo "【時區設定】完成。"
}

#---------------------------------------------------
# 1. 基礎設定：更新系統並安裝基本套件
install_base_settings() {
    echo "【基礎設定】開始檢查並安裝基本套件..."
    sudo apt update && sudo apt upgrade -y
    packages=(software-properties-common apt-transport-https ca-certificates wget curl gnupg build-essential \
	    php${PHPVER} php${PHPVER}-fpm php${PHPVER}-dev php-pear php${PHPVER}-sybase  php${PHPVER}-mysql  php${PHPVER}-gd   php${PHPVER}-ldap   php${PHPVER}-soap   php${PHPVER}-zip   php${PHPVER}-xml   php${PHPVER}-mbstring  unixodbc-dev apache2 mysql-server clamav \
      git nmap lynx wget composer mutt ntp)
    for pkg in "${packages[@]}"; do
        if package_installed "$pkg"; then
            echo "【基礎設定】$pkg 已安裝，跳過。"
        else
            echo "【基礎設定】安裝 $pkg ..."
            sudo apt install -y "$pkg"
        fi
    done
    configure_timezone
    echo "【基礎設定】完成。"
}

#---------------------------------------------------
# 2. PHP 設定：調整 Apache 使用 PHP-FPM 與啟用必要模組
configure_php() {
    echo "【PHP 設定】開始檢查 Apache PHP-FPM 設定..."
    if [ -f "/etc/apache2/conf-available/php${PHPVER}-fpm.conf" ]; then
        echo "【PHP 設定】Apache PHP-FPM 共用設定已存在，跳過此項。"
    else
        echo "【PHP 設定】設定 Apache 使用 PHP${PHPVER}-FPM..."
        sudo a2dismod php${PHPVER} mpm_prefork || true
        sudo a2enconf php${PHPVER}-fpm
    fi
    for mod in http2 mpm_event proxy_fcgi setenvif rewrite headers; do
        if sudo apache2ctl -M 2>/dev/null | grep -q "${mod}_module"; then
            echo "【PHP 設定】Apache 模組 ${mod} 已啟用。"
        else
            echo "【PHP 設定】啟用 Apache 模組 ${mod} ..."
            sudo a2enmod "$mod"
        fi
    done
    CONF_FILE="/etc/apache2/conf-available/http2-php${PHPVER}.conf"
    if [ -f "$CONF_FILE" ]; then
        echo "【PHP 設定】Apache 轉接設定檔已存在，跳過建立。"
    else
        echo "【PHP 設定】建立 Apache 轉接設定檔..."
        sudo tee "$CONF_FILE" > /dev/null <<'EOF'
# 啟用 HTTP/2 與 HTTP/3 (h3) 支援，並設定優先順序
Protocols h3 h2 h2c
ProtocolsHonorOrder On
H2Push on
H2PushPriority * after
H2PushPriority text/css before
H2PushPriority image/jpg after 32
H2PushPriority image/jpeg after 32
H2PushPriority image/png after 32
H2PushPriority application/javascript interleaved

<FilesMatch ".+\.ph(ar|p|tml)$">
     SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
</FilesMatch>
EOF
        sudo a2enconf "http2-php${PHPVER}"
    fi
    sudo systemctl restart apache2
    echo "【PHP 設定】完成。"
}

#---------------------------------------------------
# 3. MSSQL 資料庫設定：安裝 Microsoft ODBC 驅動、mssql-tools18 與 PHP MSSQL 擴展
install_mssql_settings() {
    echo "【MSSQL 設定】開始檢查 Microsoft ODBC 驅動與 mssql-tools18..."
    if package_installed "msodbcsql18"; then
        echo "【MSSQL 設定】msodbcsql18 已安裝，跳過。"
    else
        sudo mkdir -p /etc/apt/keyrings
        curl -sSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/keyrings/microsoft.gpg > /dev/null
        # 設定發行代號，這裡以 noble 為例，請根據您的實際版本調整
        echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/ubuntu/24.04/prod/ noble main" | sudo tee /etc/apt/sources.list.d/mssql-release.list
        sudo apt update
        sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 mssql-tools18
    fi
    if ! grep -q "/opt/mssql-tools/bin" ~/.bashrc; then
        echo 'export PATH="$PATH:/opt/mssql-tools/bin"' | sudo tee -a ~/.bashrc
        source ~/.bashrc
    fi
    echo "【MSSQL 設定】開始檢查 PHP MSSQL 擴展..."
    if [ -f "/etc/php/${PHPVER}/fpm/conf.d/20-sqlsrv.ini" ] && [ -f "/etc/php/${PHPVER}/fpm/conf.d/20-pdo_sqlsrv.ini" ]; then
        echo "【MSSQL 設定】PHP MSSQL 擴展已設定，跳過安裝。"
    else
        sudo pecl uninstall sqlsrv || true
        sudo pecl uninstall pdo_sqlsrv || true
        sudo pecl install sqlsrv
        sudo pecl install pdo_sqlsrv
        echo "extension=sqlsrv.so" | sudo tee /etc/php/${PHPVER}/fpm/conf.d/20-sqlsrv.ini
        echo "extension=pdo_sqlsrv.so" | sudo tee /etc/php/${PHPVER}/fpm/conf.d/20-pdo_sqlsrv.ini
        sudo systemctl restart php${PHPVER}-fpm
    fi
    echo "【MSSQL 設定】完成。"
}

#---------------------------------------------------
# 4. log 設定：調整全域與 Apache 的 logrotate 設定
configure_logrotate() {
    echo "【log 設定】檢查並調整 logrotate 設定..."
    sudo sed -i 's/weekly/daily/g' /etc/logrotate.conf
    sudo sed -i 's/rotate [0-9]\+/rotate 180/g' /etc/logrotate.conf
    sudo sed -i 's/compress/nocompress/g' /etc/logrotate.conf
    if ! grep -q "dateext" /etc/logrotate.conf; then
        echo "dateext" | sudo tee -a /etc/logrotate.conf
    fi
    if [ -f "/etc/logrotate.d/apache2" ]; then
        echo "【log 設定】Apache logrotate 設定已存在，備份原檔後重新建立。"
        sudo mv /etc/logrotate.d/apache2 /etc/logrotate.d/apache2.bak || true
    fi
    sudo tee /etc/logrotate.d/apache2 > /dev/null <<'EOF'
/var/log/apache2/*.log {
    daily
    rotate 180
    missingok
    notifempty
    nocompress
    dateext
    sharedscripts
    postrotate
        if [ -f /var/run/apache2/apache2.pid ]; then
            /usr/sbin/apache2ctl graceful > /dev/null;
        fi;
    endscript
}
EOF
    echo "【log 設定】完成。"
}

#---------------------------------------------------
# 5. ClamAV 設定：檢查並更新 ClamAV（若未安裝則安裝）
configure_clamav() {
    echo "【ClamAV 設定】檢查 ClamAV 安裝狀況..."
    if package_installed "clamav"; then
        echo "【ClamAV 設定】ClamAV 已安裝。"
    else
        sudo apt install -y clamav
    fi
    echo "【ClamAV 設定】更新病毒資料庫..."
    sudo freshclam
    echo "【ClamAV 設定】完成。"
}

#---------------------------------------------------
# 6. Apache 安全設定：更新 /etc/apache2/conf-enabled/security.conf
configure_apache_security() {
    echo "【Apache 安全設定】更新 security.conf ..."
    SECURITY_CONF="/etc/apache2/conf-enabled/security.conf"
    sudo tee "$SECURITY_CONF" > /dev/null <<'EOF'
ServerTokens Prod
ServerSignature Off
TraceEnable off
Header always append X-Frame-Options "SAMEORIGIN"
Header always append Frame-Options "SAMEORIGIN"
Header always set Strict-Transport-Security "max-age=315360000; includeSubDomains"

# IE8+ and variants, XSS Protection
Header always append X-XSS-Protection "1; mode=block"

# Protection from drive-by dynamic/executable IE files
Header always append X-Content-Type-Options "nosniff"

Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure

# Hide PHP version
Header unset X-Powered-By

# Apache Range Exploit
RequestHeader unset Range
RequestHeader unset Request-Range

# Referrer Policy
Header always set Referrer-Policy "strict-origin-when-cross-origin"

Header always set Permissions-Policy "geolocation=(self 'https://www.steps.com.tw'), camera=(), microphone=(), payment=()"

Header always set Content-Security-Policy "default-src 'self'; base-uri 'self'; connect-src 'self'; font-src 'self' data: https:; frame-src 'self' https://*.google.com https://*.googleapis.com https://www.youtube.com https://airtw.epa.gov.tw https://airtw.moenv.gov.tw https://www.facebook.com https://embed.windy.com https://weatherwidget.io; frame-ancestors 'self'; form-action 'self'; img-src 'self' data: https://trusted.cdn.com; media-src 'self'; object-src 'none'; script-src 'self' https://trusted.cdn.com https://code.jquery.com https://cdn.jsdelivr.net https://stackpath.bootstrapcdn.com 'unsafe-inline'; style-src 'self' https://trusted.cdn.com https://stackpath.bootstrapcdn.com 'unsafe-inline'; style-src-elem 'self' https://trusted.cdn.com https://stackpath.bootstrapcdn.com https://cdn.jsdelivr.net 'unsafe-inline'"
EOF
    sudo systemctl restart apache2
    echo "【Apache 安全設定】完成。"
}

#---------------------------------------------------
# 使用 whiptail 以 checklist 方式讓使用者選擇要執行的類別
CHOICES=$(whiptail --title "選擇安裝項目" --checklist "請選擇要執行的類別（按空格選取，方向鍵移動）：" 22 78 12 \
"1" "基礎設定：更新系統與安裝基本套件 (含 ntp 並設定時區 Asia/Taipei)" ON \
"2" "PHP 設定：調整 Apache 使用 PHP-FPM 與必要模組" ON \
"3" "MSSQL 資料庫設定：安裝 ODBC 驅動、mssql-tools18 與 PHP MSSQL 擴展" ON \
"4" "log 設定：調整 logrotate 設定" ON \
"5" "ClamAV 設定：檢查安裝並更新病毒資料庫" ON \
"6" "Apache 安全設定：更新 security.conf" ON 3>&1 1>&2 2>&3)

if [ $? -ne 0 ]; then
    echo "使用者取消，退出。"
    exit 1
fi

# 移除回傳字串中的雙引號（若有）
CHOICES=$(echo "$CHOICES" | sed 's/"//g')

#---------------------------------------------------
# 根據選擇執行各類別
for choice in $CHOICES; do
    case $choice in
        1)
            if whiptail --title "基礎設定" --yesno "【基礎設定】將執行更新系統與安裝基本套件\n(包含 PHP${PHPVER}-FPM、Apache、MySQL、ClamAV、Git、nmap、curl、lynx、wget、Composer、mutt、ntp 並設定時區 Asia/Taipei)。" 10 70; then
                install_base_settings
            fi
            ;;
        2)
            if whiptail --title "PHP 設定" --yesno "【PHP 設定】將執行 Apache 調整設定\n(關閉 mod_php 與 mpm_prefork，啟用 PHP${PHPVER}-FPM、http2、mpm_event、proxy_fcgi、setenvif、rewrite、headers 模組，並建立轉接設定檔)。" 10 70; then
                configure_php
            fi
            ;;
        3)
            if whiptail --title "MSSQL 資料庫設定" --yesno "【MSSQL 設定】將執行 MSSQL 資料庫設定\n(安裝 Microsoft ODBC 驅動與 mssql-tools18，並安裝 PHP MSSQL 擴展)。" 10 70; then
                install_mssql_settings
            fi
            ;;
        4)
            if whiptail --title "log 設定" --yesno "【log 設定】將執行 logrotate 設定調整\n(全域及 Apache logrotate 設定調整為 daily、rotate 180、不壓縮且帶上日期)。" 10 70; then
                configure_logrotate
            fi
            ;;
        5)
            if whiptail --title "ClamAV 設定" --yesno "【ClamAV 設定】將檢查並更新 ClamAV 病毒資料庫\n(若尚未安裝則進行安裝)。" 10 70; then
                configure_clamav
            fi
            ;;
        6)
            if whiptail --title "Apache 安全設定" --yesno "【Apache 安全設定】將更新 /etc/apache2/conf-enabled/security.conf\n(更新內容包含 ServerTokens Prod、ServerSignature Off 等安全性設定)。" 10 70; then
                configure_apache_security
            fi
            ;;
        *)
            echo "未知選項：$choice"
            ;;
    esac
done

#---------------------------------------------------
# 結束後取得各主要服務版本資訊
APACHE_VER=$(apache2 -v | head -n1)
PHP_VER=$(php -v | head -n1)
MYSQL_VER=$(mysql --version)
CLAMAV_VER=$(clamscan --version | head -n1)
TIMEZONE=$(timedatectl | grep "Time zone" | awk '{print $3}')

SUMMARY="【完成】所有選擇的項目已完成！
-------------------------------------
Apache: ${APACHE_VER}
PHP: ${PHP_VER}
MySQL: ${MYSQL_VER}
ClamAV: ${CLAMAV_VER}
時區: ${TIMEZONE}
-------------------------------------
請檢查各服務狀態。"

whiptail --title "完成" --msgbox "$SUMMARY" 15 78

