mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-07-29 13:59:40 +00:00
- Add Emergency Shell boot option for debugging - Enable ShowStatus=yes to see boot progress - Set 30s timeout for services to prevent infinite hangs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1071 lines
38 KiB
Bash
Executable File
1071 lines
38 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ══════════════════════════════════════════════════════════════════
|
|
# SecuBox-DEB — build-live-usb.sh v2.0
|
|
# Build a bootable live USB image for amd64 with:
|
|
# - UEFI + Legacy BIOS hybrid boot
|
|
# - All SecuBox packages slipstreamed
|
|
# - Root autologin
|
|
# - Optional GUI kiosk mode
|
|
# - Network auto-detection
|
|
# ══════════════════════════════════════════════════════════════════
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
REPO_DIR="$(dirname "$SCRIPT_DIR")"
|
|
|
|
# ── Defaults ──────────────────────────────────────────────────────
|
|
SUITE="bookworm"
|
|
IMG_SIZE="8G"
|
|
OUT_DIR="${REPO_DIR}/output"
|
|
APT_MIRROR="http://deb.debian.org/debian"
|
|
APT_SECUBOX="https://apt.secubox.in"
|
|
USE_LOCAL_CACHE=0
|
|
SLIPSTREAM_DEBS=1
|
|
INCLUDE_PERSISTENCE=1
|
|
INCLUDE_KIOSK=0
|
|
PRESEED_FILE=""
|
|
NO_COMPRESS=0
|
|
|
|
RED='\033[0;31m'; CYAN='\033[0;36m'; GOLD='\033[0;33m'
|
|
GREEN='\033[0;32m'; NC='\033[0m'; BOLD='\033[1m'
|
|
|
|
log() { echo -e "${CYAN}[live-usb]${NC} $*"; }
|
|
ok() { echo -e "${GREEN}[ OK ]${NC} $*"; }
|
|
err() { echo -e "${RED}[FAIL ]${NC} $*" >&2; exit 1; }
|
|
warn() { echo -e "${GOLD}[ WARN ]${NC} $*"; }
|
|
|
|
# ── Parse args ────────────────────────────────────────────────────
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: sudo bash build-live-usb.sh [OPTIONS]
|
|
|
|
--suite SUITE Debian suite (default: bookworm)
|
|
--out DIR Output directory (default: ./output)
|
|
--size SIZE Total image size (default: 8G)
|
|
--local-cache Use local APT cache
|
|
--kiosk Include GUI kiosk mode packages
|
|
--no-persistence Don't include persistent storage partition
|
|
--no-compress Skip gzip compression (faster, for local testing)
|
|
--preseed FILE Include preseed config archive
|
|
--help Show this help
|
|
|
|
Features:
|
|
- UEFI + Legacy BIOS boot
|
|
- All SecuBox packages pre-installed
|
|
- Root autologin on console
|
|
- Network auto-detection at first boot
|
|
- Optional kiosk mode (--kiosk)
|
|
|
|
Output:
|
|
secubox-live-amd64-bookworm.img - Raw bootable image
|
|
secubox-live-amd64-bookworm.img.gz - Compressed image
|
|
|
|
Flash to USB:
|
|
zcat output/secubox-live-amd64-bookworm.img.gz | sudo dd of=/dev/sdX bs=4M status=progress
|
|
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--suite) SUITE="$2"; shift 2 ;;
|
|
--out) OUT_DIR="$2"; shift 2 ;;
|
|
--size) IMG_SIZE="$2"; shift 2 ;;
|
|
--local-cache) USE_LOCAL_CACHE=1; shift ;;
|
|
--kiosk) INCLUDE_KIOSK=1; shift ;;
|
|
--no-persistence) INCLUDE_PERSISTENCE=0; shift ;;
|
|
--no-compress) NO_COMPRESS=1; shift ;;
|
|
--preseed) PRESEED_FILE="$2"; shift 2 ;;
|
|
--help|-h) usage ;;
|
|
*) err "Unknown argument: $1" ;;
|
|
esac
|
|
done
|
|
|
|
# ── Checks ────────────────────────────────────────────────────────
|
|
[[ $EUID -ne 0 ]] && err "This script must be run as root (sudo)"
|
|
|
|
# Required tools
|
|
log "Checking dependencies..."
|
|
apt-get install -y -qq debootstrap squashfs-tools grub-efi-amd64-bin grub-pc-bin \
|
|
xorriso mtools dosfstools parted e2fsprogs live-boot 2>/dev/null || true
|
|
|
|
for cmd in debootstrap parted mkfs.fat mkfs.ext4 mksquashfs grub-mkimage; do
|
|
command -v "$cmd" >/dev/null || err "Missing: $cmd"
|
|
done
|
|
|
|
# ── Local cache detection ─────────────────────────────────────
|
|
if [[ $USE_LOCAL_CACHE -eq 1 ]]; then
|
|
if curl -sf "http://127.0.0.1:3142" >/dev/null 2>&1; then
|
|
APT_MIRROR="http://127.0.0.1:3142/deb.debian.org/debian"
|
|
log "Using apt-cacher-ng"
|
|
fi
|
|
if curl -sf "http://127.0.0.1:8080/dists/${SUITE}/Release" >/dev/null 2>&1; then
|
|
APT_SECUBOX="http://127.0.0.1:8080"
|
|
log "Using local SecuBox repo"
|
|
fi
|
|
fi
|
|
|
|
# ── Setup ─────────────────────────────────────────────────────────
|
|
mkdir -p "$OUT_DIR"
|
|
WORK_DIR=$(mktemp -d /tmp/secubox-live-XXXXXX)
|
|
ROOTFS="${WORK_DIR}/rootfs"
|
|
LIVE_DIR="${WORK_DIR}/live"
|
|
IMG_FILE="${OUT_DIR}/secubox-live-amd64-${SUITE}.img"
|
|
|
|
log "══════════════════════════════════════════════════════════"
|
|
log "Building SecuBox Live USB (amd64)"
|
|
log "Suite : ${SUITE}"
|
|
log "Image : ${IMG_FILE}"
|
|
log "Size : ${IMG_SIZE}"
|
|
log "Work dir : ${WORK_DIR}"
|
|
log "Kiosk : $([[ $INCLUDE_KIOSK -eq 1 ]] && echo "yes" || echo "no")"
|
|
log "══════════════════════════════════════════════════════════"
|
|
|
|
cleanup() {
|
|
log "Cleaning up..."
|
|
umount -lf "${ROOTFS}/proc" 2>/dev/null || true
|
|
umount -lf "${ROOTFS}/sys" 2>/dev/null || true
|
|
umount -lf "${ROOTFS}/dev" 2>/dev/null || true
|
|
umount -lf "${WORK_DIR}/mnt/"* 2>/dev/null || true
|
|
[[ -n "${LOOP:-}" ]] && losetup -d "${LOOP}" 2>/dev/null || true
|
|
rm -rf "${WORK_DIR}" 2>/dev/null || true
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
# ══════════════════════════════════════════════════════════════════
|
|
# Step 1: Debootstrap
|
|
# ══════════════════════════════════════════════════════════════════
|
|
log "1/8 Debootstrap ${SUITE} amd64..."
|
|
mkdir -p "${ROOTFS}"
|
|
|
|
INCLUDE_PKGS="systemd,systemd-sysv,dbus,netplan.io,nftables,openssh-server"
|
|
INCLUDE_PKGS+=",python3,python3-pip,nginx,curl,wget,ca-certificates,gnupg"
|
|
INCLUDE_PKGS+=",iproute2,iputils-ping,ethtool,net-tools,wireguard-tools"
|
|
INCLUDE_PKGS+=",sudo,less,vim-tiny,logrotate,cron,rsync,jq,dnsmasq"
|
|
INCLUDE_PKGS+=",linux-image-amd64,live-boot,live-boot-initramfs-tools,live-config,live-config-systemd"
|
|
INCLUDE_PKGS+=",grub-efi-amd64,efibootmgr,pciutils,usbutils,lsb-release"
|
|
|
|
debootstrap --arch=amd64 --include="${INCLUDE_PKGS}" \
|
|
"${SUITE}" "${ROOTFS}" "${APT_MIRROR}"
|
|
|
|
ok "Debootstrap complete"
|
|
|
|
# ══════════════════════════════════════════════════════════════════
|
|
# Step 2: Base configuration
|
|
# ══════════════════════════════════════════════════════════════════
|
|
log "2/8 System configuration..."
|
|
|
|
mount -t proc proc "${ROOTFS}/proc"
|
|
mount -t sysfs sysfs "${ROOTFS}/sys"
|
|
mount --bind /dev "${ROOTFS}/dev"
|
|
|
|
# Hostname
|
|
echo "secubox-live" > "${ROOTFS}/etc/hostname"
|
|
cat > "${ROOTFS}/etc/hosts" <<EOF
|
|
127.0.0.1 localhost secubox-live secubox
|
|
::1 localhost ip6-localhost ip6-loopback
|
|
EOF
|
|
|
|
# Root password: secubox
|
|
chroot "${ROOTFS}" bash -c 'echo "root:secubox" | chpasswd'
|
|
|
|
# Timezone
|
|
echo "Europe/Paris" > "${ROOTFS}/etc/timezone"
|
|
chroot "${ROOTFS}" dpkg-reconfigure -f noninteractive tzdata 2>/dev/null || true
|
|
|
|
# Locale
|
|
chroot "${ROOTFS}" bash -c "locale-gen en_US.UTF-8 fr_FR.UTF-8 || true"
|
|
echo 'LANG=fr_FR.UTF-8' > "${ROOTFS}/etc/default/locale"
|
|
|
|
# French keyboard
|
|
cat > "${ROOTFS}/etc/default/keyboard" <<EOF
|
|
XKBMODEL="pc105"
|
|
XKBLAYOUT="fr"
|
|
XKBVARIANT="latin9"
|
|
EOF
|
|
echo 'KEYMAP=fr' > "${ROOTFS}/etc/vconsole.conf"
|
|
|
|
# Enable SSH root login
|
|
sed -i 's/#PermitRootLogin.*/PermitRootLogin yes/' "${ROOTFS}/etc/ssh/sshd_config"
|
|
|
|
# ── Autologin root on tty1 ────────────────────────────────────────
|
|
mkdir -p "${ROOTFS}/etc/systemd/system/getty@tty1.service.d"
|
|
cat > "${ROOTFS}/etc/systemd/system/getty@tty1.service.d/override.conf" <<EOF
|
|
[Service]
|
|
ExecStart=
|
|
ExecStart=-/sbin/agetty --autologin root --noclear %I \$TERM
|
|
Type=idle
|
|
EOF
|
|
|
|
# Enable getty@tty1 and set default target
|
|
chroot "${ROOTFS}" systemctl enable getty@tty1.service 2>/dev/null || true
|
|
chroot "${ROOTFS}" systemctl set-default multi-user.target 2>/dev/null || true
|
|
|
|
# Disable live-config autologin
|
|
mkdir -p "${ROOTFS}/etc/live/config.conf.d"
|
|
echo 'LIVE_CONFIG_NOAUTOLOGIN=true' > "${ROOTFS}/etc/live/config.conf.d/no-autologin.conf"
|
|
|
|
# Boot status (show for debugging)
|
|
mkdir -p "${ROOTFS}/etc/systemd/system.conf.d"
|
|
cat > "${ROOTFS}/etc/systemd/system.conf.d/boot.conf" <<EOF
|
|
[Manager]
|
|
ShowStatus=yes
|
|
DefaultTimeoutStartSec=30s
|
|
DefaultTimeoutStopSec=30s
|
|
EOF
|
|
|
|
# Disable console spam
|
|
cat > "${ROOTFS}/etc/sysctl.d/99-secubox.conf" <<EOF
|
|
kernel.consoleblank=0
|
|
net.ipv4.conf.all.log_martians=0
|
|
kernel.printk=1 1 1 1
|
|
EOF
|
|
|
|
# ── Hardware Check Service ──────────────────────────────────────────
|
|
# Auto-check hardware and report at boot when secubox.hwcheck=1
|
|
cat > "${ROOTFS}/usr/local/bin/secubox-hwcheck" <<'HWCHECK'
|
|
#!/bin/bash
|
|
# SecuBox Hardware Check - Evaluates system hardware and reports status
|
|
|
|
REPORT_FILE="/var/log/secubox-hwcheck.log"
|
|
REPORT_CONSOLE="/dev/tty1"
|
|
|
|
log() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$REPORT_FILE"
|
|
[ -c "$REPORT_CONSOLE" ] && echo "$*" > "$REPORT_CONSOLE"
|
|
}
|
|
|
|
cyber_banner() {
|
|
# VT100 green phosphor style
|
|
echo -e "\033[32m"
|
|
cat << 'BANNER'
|
|
|
|
____ _____ ____ _ _ ____ _____ __
|
|
/ ___|| ____/ ___| | | | __ ) / _ \ \/ /
|
|
\___ \| _|| | | | | | _ \| | | \ /
|
|
___) | |__| |___| |_| | |_) | |_| / \
|
|
|____/|_____\____|\___/|____/ \___/_/\_\
|
|
|
|
================================================================
|
|
DEC PDP-11/70 COMPATIBLE - HARDWARE EVALUATION MODE
|
|
================================================================
|
|
|
|
BANNER
|
|
}
|
|
|
|
check_hw() {
|
|
clear
|
|
cyber_banner
|
|
sleep 1
|
|
|
|
log ">>>> SYSTEM HARDWARE SCAN INITIATED <<<<"
|
|
log "================================================================"
|
|
echo ""
|
|
|
|
# CPU
|
|
CPU_MODEL=$(grep -m1 "model name" /proc/cpuinfo | cut -d: -f2 | xargs)
|
|
CPU_CORES=$(grep -c processor /proc/cpuinfo)
|
|
log "CPU.......... $CPU_MODEL"
|
|
log " ($CPU_CORES PROCESSOR UNITS)"
|
|
|
|
# Memory
|
|
MEM_TOTAL=$(free -h | awk '/Mem:/ {print $2}')
|
|
MEM_AVAIL=$(free -h | awk '/Mem:/ {print $7}')
|
|
log "MEMORY....... $MEM_TOTAL TOTAL / $MEM_AVAIL AVAILABLE"
|
|
|
|
# Storage
|
|
log "STORAGE DEVICES:"
|
|
lsblk -d -o NAME,SIZE,TYPE,MODEL 2>/dev/null | grep -v "^NAME" | while read line; do
|
|
log " * $line"
|
|
done
|
|
|
|
# Network
|
|
log "NETWORK INTERFACES:"
|
|
for iface in /sys/class/net/*; do
|
|
name=$(basename "$iface")
|
|
[ "$name" = "lo" ] && continue
|
|
state=$(cat "$iface/operstate" 2>/dev/null || echo "unknown")
|
|
mac=$(cat "$iface/address" 2>/dev/null || echo "n/a")
|
|
if [ "$state" = "up" ]; then
|
|
log " [+] $name: $state ($mac)"
|
|
else
|
|
log " [-] $name: $state ($mac)"
|
|
fi
|
|
done
|
|
|
|
# Graphics
|
|
log "GRAPHICS ADAPTER:"
|
|
lspci 2>/dev/null | grep -iE "vga|3d|display" | while read line; do
|
|
log " * $line"
|
|
done
|
|
|
|
# Boot mode
|
|
if [ -d /sys/firmware/efi ]; then
|
|
log "BOOT MODE.... UEFI"
|
|
else
|
|
log "BOOT MODE.... BIOS/LEGACY"
|
|
fi
|
|
|
|
# Virtualization detection
|
|
VIRT=$(systemd-detect-virt 2>/dev/null || echo "none")
|
|
if [ "$VIRT" = "none" ]; then
|
|
log "PLATFORM..... BARE METAL"
|
|
else
|
|
log "PLATFORM..... VIRTUAL ($VIRT)"
|
|
fi
|
|
|
|
echo ""
|
|
log "================================================================"
|
|
log ">>>> HARDWARE CHECK COMPLETE - ALL SYSTEMS NOMINAL <<<<"
|
|
log ">>>> SECUBOX CYBER DEFENSE PLATFORM READY <<<<"
|
|
log "================================================================"
|
|
echo ""
|
|
}
|
|
|
|
# Cyber boot splash with status - VT100 style
|
|
cyber_splash() {
|
|
clear
|
|
echo -e "\033[32m"
|
|
cyber_banner
|
|
|
|
local steps=(
|
|
"INITIALIZING SECURE ENVIRONMENT.......... OK"
|
|
"LOADING CRYPTOGRAPHIC MODULES............ OK"
|
|
"CONFIGURING NETWORK STACK................ OK"
|
|
"ACTIVATING FIREWALL RULES................ OK"
|
|
"SCANNING FOR THREATS..................... CLEAR"
|
|
"HARDENING SYSTEM......................... OK"
|
|
"OPTIMIZING PERFORMANCE................... OK"
|
|
)
|
|
|
|
for step in "${steps[@]}"; do
|
|
echo -e " > $step"
|
|
sleep 0.3
|
|
done
|
|
|
|
echo ""
|
|
echo " >>>> SECURE BOOT SEQUENCE COMPLETE <<<<"
|
|
echo ""
|
|
sleep 1
|
|
}
|
|
|
|
# Check if hwcheck requested via kernel cmdline
|
|
if grep -q "secubox.hwcheck=1" /proc/cmdline; then
|
|
cyber_splash
|
|
check_hw
|
|
fi
|
|
HWCHECK
|
|
chmod +x "${ROOTFS}/usr/local/bin/secubox-hwcheck"
|
|
|
|
# Create retro CRT VT100 DEC PDP-style boot splash
|
|
cat > "${ROOTFS}/usr/local/bin/secubox-splash" <<'SPLASH'
|
|
#!/bin/bash
|
|
# SecuBox Cyber Boot Splash - VT100/DEC PDP Style
|
|
|
|
# VT100 escape codes
|
|
ESC="\033"
|
|
GREEN="${ESC}[32m"
|
|
BRIGHT="${ESC}[1m"
|
|
DIM="${ESC}[2m"
|
|
BLINK="${ESC}[5m"
|
|
RESET="${ESC}[0m"
|
|
CLEAR="${ESC}[2J${ESC}[H"
|
|
|
|
# Clear screen and set green phosphor look
|
|
echo -ne "$CLEAR$GREEN"
|
|
|
|
# Simulated boot delay
|
|
type_slow() {
|
|
local text="$1"
|
|
for ((i=0; i<${#text}; i++)); do
|
|
echo -n "${text:$i:1}"
|
|
sleep 0.02
|
|
done
|
|
echo ""
|
|
}
|
|
|
|
cat << 'BANNER'
|
|
|
|
____ _____ ____ _ _ ____ _____ __
|
|
/ ___|| ____/ ___| | | | __ ) / _ \ \/ /
|
|
\___ \| _|| | | | | | _ \| | | \ /
|
|
___) | |__| |___| |_| | |_) | |_| / \
|
|
|____/|_____\____|\___/|____/ \___/_/\_\
|
|
|
|
BANNER
|
|
|
|
echo ""
|
|
echo -e "${BRIGHT}================================================================${RESET}${GREEN}"
|
|
echo " DEC PDP-11/70 COMPATIBLE SECURITY TERMINAL"
|
|
echo " SECUBOX CYBER DEFENSE SYSTEM v1.3"
|
|
echo -e "${BRIGHT}================================================================${RESET}${GREEN}"
|
|
echo ""
|
|
|
|
type_slow "BOOT SEQUENCE INITIATED..."
|
|
echo ""
|
|
|
|
# Boot status messages
|
|
steps=(
|
|
"MEMORY TEST.................... 4096K OK"
|
|
"LOADING KERNEL................. DONE"
|
|
"CRYPTOGRAPHIC MODULES.......... LOADED"
|
|
"NETWORK STACK.................. INITIALIZED"
|
|
"FIREWALL RULES................. ACTIVE"
|
|
"INTRUSION DETECTION............ ARMED"
|
|
"SECURE SHELL................... READY"
|
|
)
|
|
|
|
for step in "${steps[@]}"; do
|
|
echo -n " > "
|
|
type_slow "$step"
|
|
sleep 0.1
|
|
done
|
|
|
|
echo ""
|
|
echo -e "${BRIGHT}================================================================${RESET}${GREEN}"
|
|
echo ""
|
|
echo -e " ${BLINK}*${RESET}${GREEN} SYSTEM READY"
|
|
echo ""
|
|
echo " .------------------------------------------------."
|
|
echo " | SECUBOX CYBER SECURITY PLATFORM |"
|
|
echo " | TYPE 'help' FOR AVAILABLE COMMANDS |"
|
|
echo " | UNAUTHORIZED ACCESS WILL BE PROSECUTED |"
|
|
echo " '------------------------------------------------'"
|
|
echo ""
|
|
echo -e "${DIM} Press ENTER to continue...${RESET}${GREEN}"
|
|
read -t 5 || true
|
|
echo -ne "$RESET"
|
|
SPLASH
|
|
chmod +x "${ROOTFS}/usr/local/bin/secubox-splash"
|
|
|
|
# Add splash to root's bashrc for login
|
|
cat >> "${ROOTFS}/root/.bashrc" <<'BASHRC'
|
|
|
|
# SecuBox Cyber Splash on login
|
|
if [ -t 0 ] && [ -z "$SECUBOX_SPLASH_SHOWN" ]; then
|
|
export SECUBOX_SPLASH_SHOWN=1
|
|
/usr/local/bin/secubox-splash 2>/dev/null || true
|
|
fi
|
|
BASHRC
|
|
|
|
# Systemd service for hardware check
|
|
cat > "${ROOTFS}/etc/systemd/system/secubox-hwcheck.service" <<'HWSVC'
|
|
[Unit]
|
|
Description=SecuBox Hardware Check
|
|
After=local-fs.target
|
|
Before=getty@tty1.service
|
|
ConditionKernelCommandLine=secubox.hwcheck=1
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=/usr/local/bin/secubox-hwcheck
|
|
RemainAfterExit=yes
|
|
StandardOutput=journal+console
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
HWSVC
|
|
chroot "${ROOTFS}" systemctl enable secubox-hwcheck.service 2>/dev/null || true
|
|
|
|
# ── Network config with dummy interface for kiosk ─────────────────
|
|
mkdir -p "${ROOTFS}/etc/netplan"
|
|
|
|
# Main netplan config - DHCP on all interfaces, optional so no boot block
|
|
cat > "${ROOTFS}/etc/netplan/00-secubox.yaml" <<'NETPLAN'
|
|
network:
|
|
version: 2
|
|
renderer: networkd
|
|
ethernets:
|
|
all-en:
|
|
match:
|
|
name: "en*"
|
|
dhcp4: true
|
|
optional: true
|
|
all-eth:
|
|
match:
|
|
name: "eth*"
|
|
dhcp4: true
|
|
optional: true
|
|
NETPLAN
|
|
chmod 600 "${ROOTFS}/etc/netplan/00-secubox.yaml"
|
|
|
|
# Dummy interface with fixed IP - always available for kiosk/local access
|
|
cat > "${ROOTFS}/etc/systemd/network/10-dummy0.netdev" <<EOF
|
|
[NetDev]
|
|
Name=dummy0
|
|
Kind=dummy
|
|
EOF
|
|
|
|
cat > "${ROOTFS}/etc/systemd/network/10-dummy0.network" <<EOF
|
|
[Match]
|
|
Name=dummy0
|
|
|
|
[Network]
|
|
Address=192.168.255.1/24
|
|
EOF
|
|
|
|
# Fallback network script - runs after boot, adds link-local if no IP
|
|
cat > "${ROOTFS}/usr/sbin/secubox-net-fallback" <<'FALLBACK'
|
|
#!/bin/bash
|
|
# SecuBox Network Fallback - adds link-local IP if DHCP failed
|
|
sleep 10
|
|
|
|
for iface in /sys/class/net/en* /sys/class/net/eth*; do
|
|
[ -e "$iface" ] || continue
|
|
IFACE=$(basename "$iface")
|
|
[ "$IFACE" = "lo" ] && continue
|
|
|
|
# Check if interface has an IP
|
|
if ! ip addr show "$IFACE" | grep -q "inet "; then
|
|
echo "[net-fallback] No IP on $IFACE, adding fallback 169.254.1.1/16"
|
|
ip addr add 169.254.1.1/16 dev "$IFACE" 2>/dev/null || true
|
|
ip link set "$IFACE" up
|
|
fi
|
|
done
|
|
FALLBACK
|
|
chmod +x "${ROOTFS}/usr/sbin/secubox-net-fallback"
|
|
|
|
# Systemd service for fallback
|
|
cat > "${ROOTFS}/etc/systemd/system/secubox-net-fallback.service" <<EOF
|
|
[Unit]
|
|
Description=SecuBox Network Fallback
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=/usr/sbin/secubox-net-fallback
|
|
RemainAfterExit=yes
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
chroot "${ROOTFS}" systemctl enable systemd-networkd.service 2>/dev/null || true
|
|
chroot "${ROOTFS}" systemctl enable secubox-net-fallback.service 2>/dev/null || true
|
|
chroot "${ROOTFS}" systemctl disable systemd-networkd-wait-online.service 2>/dev/null || true
|
|
chroot "${ROOTFS}" systemctl mask systemd-networkd-wait-online.service 2>/dev/null || true
|
|
|
|
ok "Base configuration complete"
|
|
|
|
# ══════════════════════════════════════════════════════════════════
|
|
# Step 3: Firmware
|
|
# ══════════════════════════════════════════════════════════════════
|
|
log "3/8 Installing firmware..."
|
|
|
|
cat > "${ROOTFS}/etc/apt/sources.list" <<EOF
|
|
deb ${APT_MIRROR} ${SUITE} main contrib non-free non-free-firmware
|
|
deb ${APT_MIRROR} ${SUITE}-updates main contrib non-free non-free-firmware
|
|
EOF
|
|
|
|
chroot "${ROOTFS}" apt-get update -q
|
|
chroot "${ROOTFS}" apt-get install -y -q --no-install-recommends \
|
|
firmware-linux-free firmware-linux-nonfree firmware-misc-nonfree \
|
|
firmware-realtek firmware-iwlwifi firmware-atheros \
|
|
amd64-microcode intel-microcode 2>/dev/null || warn "Some firmware unavailable"
|
|
|
|
ok "Firmware installed"
|
|
|
|
# ══════════════════════════════════════════════════════════════════
|
|
# Step 4: SecuBox packages (slipstream ALL from cache/repo)
|
|
# ══════════════════════════════════════════════════════════════════
|
|
log "4/8 Installing ALL SecuBox packages..."
|
|
|
|
# Find all .deb files in cache/repo
|
|
CACHE_DEBS="${REPO_DIR}/cache/repo/pool"
|
|
if [[ -d "$CACHE_DEBS" ]] && find "$CACHE_DEBS" -name "*.deb" | head -1 | grep -q .; then
|
|
log "Slipstream: Found packages in cache/repo/pool"
|
|
install -d "${ROOTFS}/tmp/secubox-debs"
|
|
|
|
# Copy ALL secubox debs
|
|
find "$CACHE_DEBS" -name "secubox-*.deb" -exec cp {} "${ROOTFS}/tmp/secubox-debs/" \;
|
|
DEB_COUNT=$(ls "${ROOTFS}/tmp/secubox-debs/"*.deb 2>/dev/null | wc -l)
|
|
|
|
# List all packages to be installed
|
|
log "Slipstream: ${DEB_COUNT} packages to install:"
|
|
echo ""
|
|
ls -1 "${ROOTFS}/tmp/secubox-debs/"*.deb | xargs -I{} basename {} | sed 's/_.*$//' | sort -u | while read pkg; do
|
|
echo " - ${pkg}"
|
|
done
|
|
echo ""
|
|
|
|
# Install core first (dependency for all)
|
|
if ls "${ROOTFS}/tmp/secubox-debs/secubox-core_"*.deb >/dev/null 2>&1; then
|
|
log "Installing secubox-core (dependency)..."
|
|
chroot "${ROOTFS}" dpkg -i /tmp/secubox-debs/secubox-core_*.deb 2>/dev/null || true
|
|
fi
|
|
|
|
# Install all packages
|
|
log "Installing all packages..."
|
|
chroot "${ROOTFS}" dpkg -i /tmp/secubox-debs/*.deb 2>/dev/null || true
|
|
|
|
# Fix dependencies
|
|
log "Fixing dependencies..."
|
|
chroot "${ROOTFS}" apt-get install -f -y -q 2>/dev/null || true
|
|
|
|
# Verify installations
|
|
log "Verifying installations..."
|
|
INSTALLED_COUNT=$(chroot "${ROOTFS}" dpkg -l 'secubox-*' 2>/dev/null | grep "^ii" | wc -l)
|
|
|
|
# List installed packages
|
|
echo ""
|
|
log "Installed SecuBox packages (${INSTALLED_COUNT}):"
|
|
chroot "${ROOTFS}" dpkg -l 'secubox-*' 2>/dev/null | grep "^ii" | awk '{print " ✓ " $2 " (" $3 ")"}' || true
|
|
echo ""
|
|
|
|
# Save list to image
|
|
chroot "${ROOTFS}" dpkg -l 'secubox-*' 2>/dev/null | grep "^ii" > "${ROOTFS}/var/lib/secubox/installed-packages.txt" || true
|
|
|
|
rm -rf "${ROOTFS}/tmp/secubox-debs"
|
|
ok "Slipstream: ${INSTALLED_COUNT}/${DEB_COUNT} packages installed successfully"
|
|
else
|
|
warn "No packages in cache/repo, trying APT..."
|
|
if curl -sf "${APT_SECUBOX}/dists/${SUITE}/Release" >/dev/null 2>&1; then
|
|
cat > "${ROOTFS}/etc/apt/sources.list.d/secubox.list" <<EOF
|
|
deb [trusted=yes] ${APT_SECUBOX} ${SUITE} main
|
|
EOF
|
|
chroot "${ROOTFS}" apt-get update -q
|
|
chroot "${ROOTFS}" apt-get install -y -q secubox-full 2>/dev/null || true
|
|
|
|
# Verify secubox-core installed (dependency of secubox-full)
|
|
if ! chroot "${ROOTFS}" dpkg -l secubox-core 2>/dev/null | grep -q "^ii"; then
|
|
warn "secubox-full unavailable"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Python deps
|
|
chroot "${ROOTFS}" pip3 install --break-system-packages -q \
|
|
fastapi uvicorn python-jose httpx jinja2 tomli pyroute2 psutil 2>/dev/null || true
|
|
|
|
ok "SecuBox packages installed"
|
|
|
|
# ══════════════════════════════════════════════════════════════════
|
|
# Step 5: Network detection & kiosk scripts
|
|
# ══════════════════════════════════════════════════════════════════
|
|
log "5/8 Installing SecuBox scripts..."
|
|
|
|
mkdir -p "${ROOTFS}/usr/sbin"
|
|
mkdir -p "${ROOTFS}/usr/lib/secubox"
|
|
|
|
# Copy scripts
|
|
for script in secubox-net-detect secubox-kiosk-setup secubox-cmdline-handler; do
|
|
if [[ -f "${SCRIPT_DIR}/sbin/${script}" ]]; then
|
|
cp "${SCRIPT_DIR}/sbin/${script}" "${ROOTFS}/usr/sbin/"
|
|
chmod +x "${ROOTFS}/usr/sbin/${script}"
|
|
fi
|
|
done
|
|
|
|
# Copy firstboot
|
|
if [[ -f "${SCRIPT_DIR}/firstboot.sh" ]]; then
|
|
cp "${SCRIPT_DIR}/firstboot.sh" "${ROOTFS}/usr/lib/secubox/"
|
|
chmod +x "${ROOTFS}/usr/lib/secubox/firstboot.sh"
|
|
fi
|
|
|
|
# Systemd services
|
|
mkdir -p "${ROOTFS}/etc/systemd/system"
|
|
for svc in secubox-net-detect secubox-cmdline secubox-kiosk; do
|
|
if [[ -f "${SCRIPT_DIR}/systemd/${svc}.service" ]]; then
|
|
cp "${SCRIPT_DIR}/systemd/${svc}.service" "${ROOTFS}/etc/systemd/system/"
|
|
fi
|
|
done
|
|
|
|
# Enable net-detect and cmdline services
|
|
chroot "${ROOTFS}" systemctl enable secubox-cmdline.service 2>/dev/null || true
|
|
|
|
# Firstboot service
|
|
cat > "${ROOTFS}/etc/systemd/system/secubox-firstboot.service" <<EOF
|
|
[Unit]
|
|
Description=SecuBox First Boot
|
|
After=network-online.target
|
|
ConditionPathExists=!/var/lib/secubox/.firstboot-done
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=/usr/lib/secubox/firstboot.sh
|
|
ExecStartPost=/bin/touch /var/lib/secubox/.firstboot-done
|
|
RemainAfterExit=yes
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
chroot "${ROOTFS}" systemctl enable secubox-firstboot.service 2>/dev/null || true
|
|
|
|
# ── Kiosk mode packages ───────────────────────────────────────────
|
|
if [[ $INCLUDE_KIOSK -eq 1 ]]; then
|
|
log "Installing kiosk mode packages..."
|
|
chroot "${ROOTFS}" apt-get install -y -q --no-install-recommends \
|
|
cage chromium fonts-dejavu-core \
|
|
xwayland \
|
|
libinput10 libegl1 libgles2 libgbm1 libdrm2 \
|
|
mesa-utils xdg-utils 2>/dev/null || true
|
|
|
|
# Verify key kiosk packages installed
|
|
if ! chroot "${ROOTFS}" dpkg -l cage chromium 2>/dev/null | grep -q "^ii"; then
|
|
warn "Kiosk packages failed"
|
|
fi
|
|
|
|
# Create kiosk user with UID 1000
|
|
if ! chroot "${ROOTFS}" id secubox-kiosk &>/dev/null; then
|
|
chroot "${ROOTFS}" useradd -r -u 1000 -m -d /home/secubox-kiosk -s /usr/sbin/nologin \
|
|
-G video,audio,input,render secubox-kiosk 2>/dev/null || \
|
|
chroot "${ROOTFS}" useradd -r -m -d /home/secubox-kiosk -s /usr/sbin/nologin \
|
|
-G video,audio,input,render secubox-kiosk
|
|
ok "Created kiosk user"
|
|
fi
|
|
|
|
# Create kiosk start script
|
|
mkdir -p "${ROOTFS}/home/secubox-kiosk/.config"
|
|
cat > "${ROOTFS}/home/secubox-kiosk/start-kiosk.sh" <<'KIOSK_SCRIPT'
|
|
#!/bin/bash
|
|
# SecuBox Kiosk Launcher
|
|
|
|
# Wait for services to be ready
|
|
for i in {1..30}; do
|
|
if curl -sk https://192.168.255.1:9443/ >/dev/null 2>&1; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
# Kiosk URL (local SecuBox WebUI via dummy interface or localhost)
|
|
URL="${KIOSK_URL:-https://192.168.255.1:9443/}"
|
|
|
|
# Chromium flags for kiosk mode (native Wayland via Ozone)
|
|
CHROMIUM_FLAGS=(
|
|
--ozone-platform=wayland
|
|
--kiosk
|
|
--no-first-run
|
|
--disable-translate
|
|
--disable-infobars
|
|
--disable-session-crashed-bubble
|
|
--disable-restore-background-contents
|
|
--disable-sync
|
|
--disable-features=TranslateUI
|
|
--ignore-certificate-errors
|
|
--noerrdialogs
|
|
--enable-features=OverlayScrollbar
|
|
--start-fullscreen
|
|
--window-position=0,0
|
|
--check-for-update-interval=604800
|
|
--disable-component-update
|
|
--disable-default-apps
|
|
--disable-extensions
|
|
--disable-background-networking
|
|
--disable-domain-reliability
|
|
--disable-client-side-phishing-detection
|
|
"$URL"
|
|
)
|
|
|
|
exec chromium "${CHROMIUM_FLAGS[@]}"
|
|
KIOSK_SCRIPT
|
|
chmod +x "${ROOTFS}/home/secubox-kiosk/start-kiosk.sh"
|
|
chroot "${ROOTFS}" chown -R secubox-kiosk:secubox-kiosk /home/secubox-kiosk
|
|
|
|
# Mark as installed AND enabled (so kiosk starts on first boot)
|
|
mkdir -p "${ROOTFS}/var/lib/secubox"
|
|
echo "installed=$(date -Iseconds)" > "${ROOTFS}/var/lib/secubox/.kiosk-installed"
|
|
touch "${ROOTFS}/var/lib/secubox/.kiosk-enabled"
|
|
|
|
# Enable kiosk service and set graphical target
|
|
chroot "${ROOTFS}" systemctl enable secubox-kiosk.service 2>/dev/null || true
|
|
chroot "${ROOTFS}" systemctl set-default graphical.target 2>/dev/null || true
|
|
chroot "${ROOTFS}" systemctl disable getty@tty1.service 2>/dev/null || true
|
|
|
|
# Setup root autologin on tty2 (console access while kiosk runs on tty1)
|
|
mkdir -p "${ROOTFS}/etc/systemd/system/getty@tty2.service.d"
|
|
cat > "${ROOTFS}/etc/systemd/system/getty@tty2.service.d/autologin.conf" <<EOF
|
|
[Service]
|
|
ExecStart=
|
|
ExecStart=-/sbin/agetty --autologin root --noclear %I \$TERM
|
|
Type=idle
|
|
EOF
|
|
chroot "${ROOTFS}" systemctl enable getty@tty2.service 2>/dev/null || true
|
|
|
|
ok "Kiosk packages and user installed (console on tty2)"
|
|
fi
|
|
|
|
ok "Scripts installed"
|
|
|
|
# ══════════════════════════════════════════════════════════════════
|
|
# Step 6: Cleanup rootfs
|
|
# ══════════════════════════════════════════════════════════════════
|
|
log "6/8 Cleaning up rootfs..."
|
|
|
|
# Preseed
|
|
if [[ -n "$PRESEED_FILE" ]] && [[ -f "$PRESEED_FILE" ]]; then
|
|
mkdir -p "${ROOTFS}/usr/share/secubox"
|
|
cp "$PRESEED_FILE" "${ROOTFS}/usr/share/secubox/preseed.tar.gz"
|
|
ok "Preseed included"
|
|
fi
|
|
|
|
# Mask problematic services
|
|
for svc in lxc-net lxc; do
|
|
chroot "${ROOTFS}" systemctl disable ${svc}.service 2>/dev/null || true
|
|
chroot "${ROOTFS}" systemctl mask ${svc}.service 2>/dev/null || true
|
|
done
|
|
|
|
# Ensure squashfs module loads at boot
|
|
echo "squashfs" >> "${ROOTFS}/etc/modules-load.d/live.conf"
|
|
echo "loop" >> "${ROOTFS}/etc/modules-load.d/live.conf"
|
|
echo "overlay" >> "${ROOTFS}/etc/modules-load.d/live.conf"
|
|
|
|
# Regenerate initramfs with live-boot hooks
|
|
log "Regenerating initramfs..."
|
|
chroot "${ROOTFS}" update-initramfs -u -k all 2>/dev/null || warn "initramfs update failed"
|
|
|
|
# Clean APT
|
|
chroot "${ROOTFS}" apt-get clean
|
|
rm -rf "${ROOTFS}/var/lib/apt/lists"/*
|
|
rm -rf "${ROOTFS}/var/cache/apt"/*.bin
|
|
rm -rf "${ROOTFS}/tmp"/*
|
|
|
|
# Welcome message
|
|
cat > "${ROOTFS}/etc/motd" <<'EOF'
|
|
|
|
╔═══════════════════════════════════════════════════════════════╗
|
|
║ ███████╗███████╗ ██████╗██╗ ██╗██████╗ ██████╗ ██╗ ██╗ ║
|
|
║ ██╔════╝██╔════╝██╔════╝██║ ██║██╔══██╗██╔═══██╗╚██╗██╔╝ ║
|
|
║ ███████╗█████╗ ██║ ██║ ██║██████╔╝██║ ██║ ╚███╔╝ ║
|
|
║ ╚════██║██╔══╝ ██║ ██║ ██║██╔══██╗██║ ██║ ██╔██╗ ║
|
|
║ ███████║███████╗╚██████╗╚██████╔╝██████╔╝╚██████╔╝██╔╝ ██╗ ║
|
|
║ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ║
|
|
║ LIVE USB ║
|
|
╚═══════════════════════════════════════════════════════════════╝
|
|
|
|
Web UI: https://<IP>:9443 SSH: root / secubox
|
|
|
|
EOF
|
|
|
|
# Unmount
|
|
umount -lf "${ROOTFS}/proc" 2>/dev/null || true
|
|
umount -lf "${ROOTFS}/sys" 2>/dev/null || true
|
|
umount -lf "${ROOTFS}/dev" 2>/dev/null || true
|
|
|
|
ok "Rootfs cleaned"
|
|
|
|
# ══════════════════════════════════════════════════════════════════
|
|
# Step 7: Create SquashFS
|
|
# ══════════════════════════════════════════════════════════════════
|
|
log "7/8 Creating SquashFS filesystem..."
|
|
mkdir -p "${LIVE_DIR}/live"
|
|
|
|
mksquashfs "${ROOTFS}" "${LIVE_DIR}/live/filesystem.squashfs" \
|
|
-comp xz -b 1M -Xdict-size 100% -e boot/grub -e boot/efi
|
|
|
|
cp "${ROOTFS}/boot/vmlinuz-"* "${LIVE_DIR}/live/vmlinuz"
|
|
cp "${ROOTFS}/boot/initrd.img-"* "${LIVE_DIR}/live/initrd.img"
|
|
|
|
SQUASHFS_SIZE=$(du -sh "${LIVE_DIR}/live/filesystem.squashfs" | cut -f1)
|
|
ok "SquashFS: ${SQUASHFS_SIZE}"
|
|
|
|
# ══════════════════════════════════════════════════════════════════
|
|
# Step 8: Create bootable image
|
|
# ══════════════════════════════════════════════════════════════════
|
|
log "8/8 Creating bootable image (${IMG_SIZE})..."
|
|
|
|
# Delete old image
|
|
rm -f "${IMG_FILE}" "${IMG_FILE}.gz"
|
|
|
|
# Create image
|
|
truncate -s "${IMG_SIZE}" "${IMG_FILE}"
|
|
|
|
# Partition: GPT with hybrid boot
|
|
# 1: BIOS boot (2MB) - legacy grub
|
|
# 2: ESP (512MB) - UEFI
|
|
# 3: LIVE (4GB) - squashfs
|
|
# 4: persistence (rest) - optional
|
|
if [[ $INCLUDE_PERSISTENCE -eq 1 ]]; then
|
|
parted -s "${IMG_FILE}" \
|
|
mklabel gpt \
|
|
mkpart bios 1MiB 3MiB \
|
|
mkpart ESP fat32 3MiB 515MiB \
|
|
mkpart LIVE ext4 515MiB 4611MiB \
|
|
mkpart persistence ext4 4611MiB 100% \
|
|
set 1 bios_grub on \
|
|
set 2 esp on \
|
|
set 2 boot on
|
|
else
|
|
parted -s "${IMG_FILE}" \
|
|
mklabel gpt \
|
|
mkpart bios 1MiB 3MiB \
|
|
mkpart ESP fat32 3MiB 515MiB \
|
|
mkpart LIVE ext4 515MiB 100% \
|
|
set 1 bios_grub on \
|
|
set 2 esp on \
|
|
set 2 boot on
|
|
fi
|
|
|
|
# Setup loop
|
|
LOOP=$(losetup -f --show -P "${IMG_FILE}")
|
|
log "Loop: ${LOOP}"
|
|
|
|
# Wait for partitions
|
|
sleep 1
|
|
partprobe "${LOOP}" 2>/dev/null || true
|
|
sleep 1
|
|
|
|
# Verify partitions exist
|
|
[[ -b "${LOOP}p2" ]] || err "Partition ${LOOP}p2 not found"
|
|
|
|
# Format
|
|
mkfs.fat -F32 -n ESP "${LOOP}p2"
|
|
mkfs.ext4 -L LIVE -q "${LOOP}p3"
|
|
if [[ $INCLUDE_PERSISTENCE -eq 1 ]] && [[ -b "${LOOP}p4" ]]; then
|
|
mkfs.ext4 -L persistence -q "${LOOP}p4"
|
|
fi
|
|
|
|
# Mount
|
|
MNT="${WORK_DIR}/mnt"
|
|
mkdir -p "${MNT}/esp" "${MNT}/live"
|
|
mount "${LOOP}p2" "${MNT}/esp"
|
|
mount "${LOOP}p3" "${MNT}/live"
|
|
|
|
# Copy live files
|
|
mkdir -p "${MNT}/live/live"
|
|
cp "${LIVE_DIR}/live/filesystem.squashfs" "${MNT}/live/live/"
|
|
cp "${LIVE_DIR}/live/vmlinuz" "${MNT}/live/live/"
|
|
cp "${LIVE_DIR}/live/initrd.img" "${MNT}/live/live/"
|
|
|
|
# Setup ESP
|
|
mkdir -p "${MNT}/esp/EFI/BOOT"
|
|
mkdir -p "${MNT}/esp/boot/grub/x86_64-efi"
|
|
mkdir -p "${MNT}/esp/boot/grub/i386-pc"
|
|
|
|
# Also copy to ESP for some UEFI
|
|
mkdir -p "${MNT}/esp/live"
|
|
cp "${LIVE_DIR}/live/vmlinuz" "${MNT}/esp/live/"
|
|
cp "${LIVE_DIR}/live/initrd.img" "${MNT}/esp/live/"
|
|
|
|
# GRUB config
|
|
cat > "${MNT}/esp/boot/grub/grub.cfg" <<'GRUBCFG'
|
|
set default=0
|
|
set timeout=5
|
|
|
|
insmod part_gpt
|
|
insmod fat
|
|
insmod ext2
|
|
insmod all_video
|
|
|
|
search --no-floppy --label LIVE --set=live
|
|
|
|
set menu_color_normal=cyan/black
|
|
set menu_color_highlight=white/blue
|
|
|
|
menuentry "SecuBox Live" {
|
|
linux ($live)/live/vmlinuz boot=live live-media-path=live components persistence console=tty0
|
|
initrd ($live)/live/initrd.img
|
|
}
|
|
|
|
menuentry "SecuBox Live (Kiosk GUI)" {
|
|
linux ($live)/live/vmlinuz boot=live live-media-path=live components persistence quiet secubox.kiosk=1 systemd.unit=graphical.target
|
|
initrd ($live)/live/initrd.img
|
|
}
|
|
|
|
menuentry "SecuBox Live (Bridge Mode)" {
|
|
linux ($live)/live/vmlinuz boot=live live-media-path=live components persistence console=tty0 secubox.netmode=bridge
|
|
initrd ($live)/live/initrd.img
|
|
}
|
|
|
|
menuentry "SecuBox Live (Safe Mode)" {
|
|
linux ($live)/live/vmlinuz boot=live live-media-path=live components nomodeset console=tty0
|
|
initrd ($live)/live/initrd.img
|
|
}
|
|
|
|
menuentry "SecuBox Live (To RAM)" {
|
|
linux ($live)/live/vmlinuz boot=live live-media-path=live components toram console=tty0
|
|
initrd ($live)/live/initrd.img
|
|
}
|
|
|
|
menuentry "SecuBox Live (Auto-Check HW)" {
|
|
linux ($live)/live/vmlinuz boot=live live-media-path=live components nomodeset console=tty0 secubox.hwcheck=1
|
|
initrd ($live)/live/initrd.img
|
|
}
|
|
|
|
menuentry "SecuBox Live (Emergency Shell)" {
|
|
linux ($live)/live/vmlinuz boot=live live-media-path=live components nomodeset console=tty0 systemd.unit=emergency.target
|
|
initrd ($live)/live/initrd.img
|
|
}
|
|
GRUBCFG
|
|
|
|
cp "${MNT}/esp/boot/grub/grub.cfg" "${MNT}/esp/EFI/BOOT/grub.cfg"
|
|
|
|
# Build GRUB EFI
|
|
GRUB_MODS="part_gpt part_msdos fat ext2 normal linux boot configfile loopback chain efi_gop efi_uga ls search search_label gfxterm all_video"
|
|
|
|
cat > "${WORK_DIR}/grub-embed.cfg" <<'EMBEDCFG'
|
|
search --no-floppy --label ESP --set=root
|
|
set prefix=($root)/boot/grub
|
|
configfile $prefix/grub.cfg
|
|
EMBEDCFG
|
|
|
|
grub-mkimage -o "${MNT}/esp/EFI/BOOT/BOOTX64.EFI" \
|
|
-O x86_64-efi \
|
|
-c "${WORK_DIR}/grub-embed.cfg" \
|
|
-p /boot/grub \
|
|
${GRUB_MODS}
|
|
|
|
cp "${MNT}/esp/EFI/BOOT/BOOTX64.EFI" "${MNT}/esp/EFI/BOOT/grubx64.efi"
|
|
|
|
# Copy GRUB modules
|
|
cp /usr/lib/grub/x86_64-efi/*.mod "${MNT}/esp/boot/grub/x86_64-efi/" 2>/dev/null || true
|
|
|
|
# Install BIOS GRUB
|
|
grub-install --target=i386-pc --boot-directory="${MNT}/esp/boot" --recheck "${LOOP}" 2>/dev/null || warn "BIOS GRUB failed"
|
|
cp /usr/lib/grub/i386-pc/*.mod "${MNT}/esp/boot/grub/i386-pc/" 2>/dev/null || true
|
|
|
|
ok "GRUB installed (UEFI + BIOS)"
|
|
|
|
# Persistence
|
|
if [[ $INCLUDE_PERSISTENCE -eq 1 ]] && [[ -b "${LOOP}p4" ]]; then
|
|
mkdir -p "${MNT}/pers"
|
|
mount "${LOOP}p4" "${MNT}/pers"
|
|
echo "/ union" > "${MNT}/pers/persistence.conf"
|
|
umount "${MNT}/pers"
|
|
ok "Persistence configured"
|
|
fi
|
|
|
|
# Sync and unmount
|
|
sync
|
|
umount "${MNT}/esp"
|
|
umount "${MNT}/live"
|
|
losetup -d "${LOOP}"
|
|
LOOP=""
|
|
|
|
ok "Bootable image created"
|
|
|
|
# ══════════════════════════════════════════════════════════════════
|
|
# Compress (optional)
|
|
# ══════════════════════════════════════════════════════════════════
|
|
if [[ $NO_COMPRESS -eq 0 ]]; then
|
|
log "Compressing..."
|
|
gzip -9 -f "${IMG_FILE}"
|
|
sha256sum "${IMG_FILE}.gz" > "${IMG_FILE}.gz.sha256"
|
|
FINAL_SIZE=$(du -sh "${IMG_FILE}.gz" | cut -f1)
|
|
FINAL_IMG="${IMG_FILE}.gz"
|
|
FLASH_CMD="zcat ${IMG_FILE}.gz | sudo dd of=/dev/sdX bs=4M status=progress"
|
|
else
|
|
log "Skipping compression (--no-compress)"
|
|
sha256sum "${IMG_FILE}" > "${IMG_FILE}.sha256"
|
|
FINAL_SIZE=$(du -sh "${IMG_FILE}" | cut -f1)
|
|
FINAL_IMG="${IMG_FILE}"
|
|
FLASH_CMD="sudo dd if=${IMG_FILE} of=/dev/sdX bs=4M status=progress"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${GREEN}${BOLD}════════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${GREEN}${BOLD} SecuBox Live USB Ready!${NC}"
|
|
echo ""
|
|
echo -e " Image: ${FINAL_IMG}"
|
|
echo -e " Size: ${FINAL_SIZE}"
|
|
echo ""
|
|
echo -e " ${BOLD}Flash:${NC}"
|
|
echo -e " ${FLASH_CMD}"
|
|
echo ""
|
|
echo -e " ${BOLD}Credentials:${NC}"
|
|
echo -e " SSH/Console: root / secubox"
|
|
echo -e " Web UI: https://192.168.255.1:9443"
|
|
echo ""
|
|
echo -e "${GREEN}${BOLD}════════════════════════════════════════════════════════════${NC}"
|