diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 8cd6318e..00954ad9 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -605,7 +605,8 @@ "Bash({ echo \"=== ROOT .md FILES ===\")", "Bash(if [ -f \"$d/README.md\" ])", "Bash([ ! -f \"$d/README.fr.md\" ])", - "Bash(basename:*)" + "Bash(basename:*)", + "Bash(VBoxManage internalcommands sethduuid:*)" ] } } diff --git a/.github/workflows/build-secubox-images.yml b/.github/workflows/build-secubox-images.yml index 5104e146..b8a9c381 100644 --- a/.github/workflows/build-secubox-images.yml +++ b/.github/workflows/build-secubox-images.yml @@ -232,6 +232,92 @@ jobs: echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + - name: Slipstream SecuBox configuration + if: ${{ github.event.inputs.include_secubox == 'true' || github.event_name == 'push' }} + run: | + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "🔧 SLIPSTREAMING SECUBOX CONFIGURATION" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + # Determine architecture for this device + ARCH="${{ matrix.subtarget }}" + case "$ARCH" in + cortexa72) OPKG_ARCH="aarch64_cortex-a72" ;; + cortexa53) OPKG_ARCH="aarch64_cortex-a53" ;; + *) OPKG_ARCH="aarch64_generic" ;; + esac + + # Create files directory for slipstream content + mkdir -p openwrt/files/etc/opkg + mkdir -p openwrt/files/etc/uci-defaults + mkdir -p openwrt/files/usr/sbin + + # Add SecuBox repository configuration + cat > openwrt/files/etc/opkg/customfeeds.conf << EOF + # SecuBox Package Repository + # Pre-configured by GitHub Actions build + # Device: ${{ matrix.device }} + src/gz secubox_packages https://repo.secubox.in/packages/${OPKG_ARCH} + src/gz secubox_luci https://repo.secubox.in/luci/${OPKG_ARCH} + EOF + echo " ✅ Repository configured for ${OPKG_ARCH}" + + # Copy seed script + if [[ -f "scripts/secubox-seed.sh" ]]; then + cp scripts/secubox-seed.sh openwrt/files/usr/sbin/secubox-seed + chmod +x openwrt/files/usr/sbin/secubox-seed + echo " ✅ Seed script installed" + fi + + # Create first-boot setup script + cat > openwrt/files/etc/uci-defaults/99-secubox-setup << 'FIRSTBOOT' + #!/bin/sh + # SecuBox First-Boot Setup + LOG="/tmp/secubox-firstboot.log" + echo "[$(date)] SecuBox first-boot starting..." >> "$LOG" + + # Update package lists + opkg update >> "$LOG" 2>&1 || true + + # Try to install core packages if repo is available + for pkg in secubox-core secubox-base; do + if opkg list | grep -q "^$pkg "; then + opkg install "$pkg" >> "$LOG" 2>&1 || true + fi + done + + # Set SecuBox theme as default + if [ -f /etc/config/luci ]; then + uci set luci.main.mediaurlbase='/luci-static/secubox' 2>/dev/null || true + uci commit luci 2>/dev/null || true + fi + + echo "[$(date)] SecuBox first-boot complete" >> "$LOG" + exit 0 + FIRSTBOOT + chmod +x openwrt/files/etc/uci-defaults/99-secubox-setup + echo " ✅ First-boot script created" + + # Create SecuBox banner + cat > openwrt/files/etc/banner << BANNER + + ____ ____ + / ___| ___ ___ _ _| __ ) _____ __ + \___ \ / _ \/ __| | | | _ \ / _ \ \/ / + ___) | __/ (__| |_| | |_) | (_) > < + |____/ \___|\___|\__,_|____/ \___/_/\_\ + + SecuBox - ${{ matrix.description }} + https://secubox.in + + Run 'secubox-seed --help' for setup options + + BANNER + echo " ✅ SecuBox banner created" + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + - name: Generate SecuBox config run: | cd openwrt diff --git a/.github/workflows/build-secubox-vm.yml b/.github/workflows/build-secubox-vm.yml index 7a54b8b2..742aeb2d 100644 --- a/.github/workflows/build-secubox-vm.yml +++ b/.github/workflows/build-secubox-vm.yml @@ -170,6 +170,81 @@ jobs: echo "📊 Total: $PKG_COUNT SecuBox packages copied" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + - name: Slipstream SecuBox configuration + run: | + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "🔧 SLIPSTREAMING SECUBOX CONFIGURATION" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + # Create files directory for slipstream content + mkdir -p openwrt/files/etc/opkg + mkdir -p openwrt/files/etc/uci-defaults + mkdir -p openwrt/files/usr/sbin + + # Add SecuBox repository configuration + cat > openwrt/files/etc/opkg/customfeeds.conf << 'EOF' + # SecuBox Package Repository + # Pre-configured by GitHub Actions build + src/gz secubox_packages https://repo.secubox.in/packages/x86_64 + src/gz secubox_luci https://repo.secubox.in/luci/x86_64 + EOF + + # Copy seed script + if [[ -f "scripts/secubox-seed.sh" ]]; then + cp scripts/secubox-seed.sh openwrt/files/usr/sbin/secubox-seed + chmod +x openwrt/files/usr/sbin/secubox-seed + echo " ✅ Seed script installed" + fi + + # Create first-boot setup script + cat > openwrt/files/etc/uci-defaults/99-secubox-setup << 'FIRSTBOOT' + #!/bin/sh + # SecuBox First-Boot Setup + LOG="/tmp/secubox-firstboot.log" + echo "[$(date)] SecuBox first-boot starting..." >> "$LOG" + + # Update package lists + opkg update >> "$LOG" 2>&1 || true + + # Try to install core packages if repo is available + for pkg in secubox-core secubox-base; do + if opkg list | grep -q "^$pkg "; then + opkg install "$pkg" >> "$LOG" 2>&1 || true + fi + done + + # Set SecuBox theme as default + if [ -f /etc/config/luci ]; then + uci set luci.main.mediaurlbase='/luci-static/secubox' 2>/dev/null || true + uci commit luci 2>/dev/null || true + fi + + echo "[$(date)] SecuBox first-boot complete" >> "$LOG" + exit 0 + FIRSTBOOT + chmod +x openwrt/files/etc/uci-defaults/99-secubox-setup + echo " ✅ First-boot script created" + + # Create SecuBox banner + cat > openwrt/files/etc/banner << 'BANNER' + + ____ ____ + / ___| ___ ___ _ _| __ ) _____ __ + \___ \ / _ \/ __| | | | _ \ / _ \ \/ / + ___) | __/ (__| |_| | |_) | (_) > < + |____/ \___|\___|\__,_|____/ \___/_/\_\ + + SecuBox VM - Security Gateway for OpenWrt + https://secubox.in + + Run 'secubox-seed --help' for setup options + + BANNER + echo " ✅ SecuBox banner created" + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + - name: Generate VM configuration run: | cd openwrt diff --git a/scripts/README.md b/scripts/README.md index b950f78e..9c9cdd5f 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -1,16 +1,66 @@ -# Documentation Publishing Scripts +# SecuBox Scripts English | [Francais](README.fr.md) | [中文](README.zh.md) -**Version:** 1.0.0 -**Last Updated:** 2025-12-28 -**Purpose:** Automated scripts for publishing SecuBox documentation +**Version:** 1.1.0 +**Last Updated:** 2026-03-20 +**Purpose:** Automated scripts for SecuBox installation and documentation publishing --- ## 📜 Available Scripts -### 1. setup-wiki.sh +### 1. secubox-seed.sh +**Purpose:** Bootstrap a fresh OpenWrt installation with SecuBox packages + +**Usage:** +```bash +# Remote install (recommended) +wget -O- https://repo.secubox.in/seed.sh | sh + +# Or with curl +curl -fsSL https://repo.secubox.in/seed.sh | sh + +# Local install with options +./scripts/secubox-seed.sh --profile=full +``` + +**Installation Profiles:** + +| Profile | Description | Packages | +|---------|-------------|----------| +| `minimal` | Core only | secubox-core, secubox-base, luci-theme-secubox | +| `standard` | Core + Security + Network | + crowdsec, haproxy, mitmproxy, ipblocklist | +| `full` | Everything | + tor, exposure, glances, master-link, p2p | + +**Options:** +- `--profile=PROFILE` - Choose installation profile (minimal/standard/full) +- `--mirror=URL` - Override repository URL +- `--dry-run` - Show what would be installed +- `--skip-update` - Skip opkg update + +**Environment Variables:** +- `SECUBOX_PROFILE` - Same as --profile +- `SECUBOX_MIRROR` - Same as --mirror +- `SECUBOX_DRY_RUN=1` - Same as --dry-run +- `SECUBOX_SKIP_UPDATE=1` - Same as --skip-update + +**What it does:** +1. Detects system architecture (x86_64, aarch64, armv7l) +2. Configures SecuBox package repository +3. Updates package lists +4. Installs packages based on selected profile +5. Runs post-installation setup +6. Enables and starts services + +**Requirements:** +- OpenWrt 24.10+ +- Internet connectivity +- Root access + +--- + +### 2. setup-wiki.sh **Purpose:** Sync DOCS/ to GitHub Wiki **Usage:** diff --git a/scripts/secubox-seed.sh b/scripts/secubox-seed.sh new file mode 100755 index 00000000..68afa4fe --- /dev/null +++ b/scripts/secubox-seed.sh @@ -0,0 +1,479 @@ +#!/bin/sh +# +# SecuBox Seed Script +# Bootstrap a fresh OpenWrt installation with SecuBox packages +# +# Usage: +# wget -O- https://repo.secubox.in/seed.sh | sh +# OR +# curl -fsSL https://repo.secubox.in/seed.sh | sh +# +# Options (via environment): +# SECUBOX_PROFILE=minimal|standard|full (default: standard) +# SECUBOX_MIRROR=url (override repo URL) +# SECUBOX_SKIP_UPDATE=1 (skip opkg update) +# SECUBOX_DRY_RUN=1 (show what would be installed) +# + +set -e + +# Colors (if terminal supports it) +if [ -t 1 ]; then + RED='\033[0;31m' + GREEN='\033[0;32m' + YELLOW='\033[1;33m' + BLUE='\033[0;34m' + NC='\033[0m' +else + RED='' GREEN='' YELLOW='' BLUE='' NC='' +fi + +log_info() { printf "${BLUE}[INFO]${NC} %s\n" "$1"; } +log_ok() { printf "${GREEN}[OK]${NC} %s\n" "$1"; } +log_warn() { printf "${YELLOW}[WARN]${NC} %s\n" "$1"; } +log_error() { printf "${RED}[ERROR]${NC} %s\n" "$1"; } + +# Detect architecture +detect_arch() { + local arch + if [ -f /etc/openwrt_release ]; then + arch=$(grep "DISTRIB_ARCH" /etc/openwrt_release | cut -d"'" -f2) + fi + + if [ -z "$arch" ]; then + # Fallback: detect from uname + case "$(uname -m)" in + x86_64) arch="x86_64" ;; + aarch64) arch="aarch64_cortex-a72" ;; + armv7l) arch="arm_cortex-a7_neon-vfpv4" ;; + *) arch="$(uname -m)" ;; + esac + fi + + echo "$arch" +} + +# Repository URLs in order of preference +REPO_URLS=" +https://repo.secubox.in +https://secubox.in/repo +https://github.com/CyberMind-FR/secubox-openwrt/releases/download/packages +" + +# Check connectivity and find working repo +check_connectivity() { + log_info "Checking network connectivity..." + + # First check general connectivity + if ! ping -c 1 -W 3 "downloads.openwrt.org" >/dev/null 2>&1; then + if ! wget -q -T 5 --spider "https://downloads.openwrt.org" 2>/dev/null; then + log_error "No network connectivity. Please check your network configuration." + return 1 + fi + fi + + log_ok "Network connectivity OK" + return 0 +} + +# Find a working SecuBox repository +find_working_repo() { + local arch="$1" + + # If user specified a mirror, use it directly + if [ -n "$SECUBOX_MIRROR" ]; then + log_info "Using user-specified mirror: $SECUBOX_MIRROR" + echo "$SECUBOX_MIRROR" + return 0 + fi + + # Check local feed first (for bonus package) + if [ -d "/www/secubox-feed" ] && [ -f "/www/secubox-feed/Packages" ]; then + log_info "Found local SecuBox feed at /www/secubox-feed" + echo "file:///www/secubox-feed" + return 0 + fi + + # Try each remote URL + log_info "Searching for working SecuBox repository..." + for base_url in $REPO_URLS; do + local test_url="${base_url}/packages/${arch}/Packages.gz" + log_info "Trying: $base_url" + + # Try wget first (more common on OpenWrt) + if wget -q -T 10 --spider "$test_url" 2>/dev/null; then + log_ok "Found working repository: $base_url" + echo "$base_url" + return 0 + fi + + # Try curl as fallback + if command -v curl >/dev/null 2>&1; then + if curl -sf -m 10 "$test_url" >/dev/null 2>&1; then + log_ok "Found working repository: $base_url" + echo "$base_url" + return 0 + fi + fi + done + + log_warn "No remote SecuBox repository available" + return 1 +} + +# Configure SecuBox repository +configure_repo() { + local arch="$1" + local feeds_file="/etc/opkg/customfeeds.conf" + + log_info "Configuring SecuBox package repository..." + + # Find a working repository + local repo_url + repo_url=$(find_working_repo "$arch") + + if [ -z "$repo_url" ]; then + log_warn "No SecuBox repository found. Packages will need to be installed manually." + log_info "You can set SECUBOX_MIRROR to specify a custom repository URL." + + # Still configure the default URL for future use + repo_url="https://repo.secubox.in" + SECUBOX_REPO_AVAILABLE=0 + else + SECUBOX_REPO_AVAILABLE=1 + fi + + # Backup existing customfeeds.conf + if [ -f "$feeds_file" ]; then + cp "$feeds_file" "${feeds_file}.bak" + fi + + # Check if SecuBox feed already configured + if grep -q "secubox_packages" "$feeds_file" 2>/dev/null; then + log_warn "SecuBox feeds already configured, updating..." + sed -i '/secubox_/d' "$feeds_file" + fi + + # Handle local file:// URLs differently + if echo "$repo_url" | grep -q "^file://"; then + cat >> "$feeds_file" << EOF + +# SecuBox Local Package Repository +# Added by secubox-seed.sh on $(date +%Y-%m-%d) +src secubox_local ${repo_url} +EOF + else + cat >> "$feeds_file" << EOF + +# SecuBox Package Repository +# Added by secubox-seed.sh on $(date +%Y-%m-%d) +src/gz secubox_packages ${repo_url}/packages/${arch} +src/gz secubox_luci ${repo_url}/luci/${arch} +EOF + fi + + log_ok "Repository configured: ${repo_url}" +} + +# Update package lists +update_packages() { + if [ "${SECUBOX_SKIP_UPDATE:-0}" = "1" ]; then + log_warn "Skipping package list update (SECUBOX_SKIP_UPDATE=1)" + return 0 + fi + + log_info "Updating package lists..." + + if ! opkg update 2>&1; then + log_warn "Some feeds failed to update, continuing anyway..." + fi + + log_ok "Package lists updated" +} + +# Install a package with fallback +install_pkg() { + local pkg="$1" + local optional="${2:-0}" + + if [ "${SECUBOX_DRY_RUN:-0}" = "1" ]; then + log_info "[DRY RUN] Would install: $pkg" + return 0 + fi + + # Check if already installed + if opkg list-installed | grep -q "^${pkg} "; then + log_ok "$pkg already installed" + return 0 + fi + + log_info "Installing $pkg..." + + if opkg install "$pkg" 2>&1; then + log_ok "$pkg installed successfully" + return 0 + else + if [ "$optional" = "1" ]; then + log_warn "$pkg installation failed (optional, continuing)" + return 0 + else + log_error "$pkg installation failed" + return 1 + fi + fi +} + +# Install package group with error handling +install_group() { + local group_name="$1" + shift + local packages="$@" + local failed="" + + log_info "Installing $group_name packages..." + + for pkg in $packages; do + # Check if package is optional (prefixed with ?) + local optional=0 + if echo "$pkg" | grep -q "^?"; then + optional=1 + pkg="${pkg#?}" + fi + + if ! install_pkg "$pkg" "$optional"; then + failed="$failed $pkg" + fi + done + + if [ -n "$failed" ]; then + log_warn "Some packages failed to install:$failed" + return 1 + fi + + log_ok "$group_name packages installed" + return 0 +} + +# Define package profiles +get_profile_packages() { + local profile="${1:-standard}" + + case "$profile" in + minimal) + # Minimal: Just core + theme + echo "CORE:secubox-core secubox-base" + echo "THEME:luci-theme-secubox" + ;; + standard) + # Standard: Core + Security + Basic LuCI apps + echo "CORE:secubox-core secubox-base secubox-identity" + echo "THEME:luci-theme-secubox" + echo "SECURITY:?secubox-app-crowdsec ?secubox-app-cs-firewall-bouncer secubox-app-ipblocklist" + echo "NETWORK:secubox-app-haproxy secubox-app-mitmproxy" + echo "LUCI:luci-app-secubox luci-app-haproxy ?luci-app-crowdsec-dashboard" + ;; + full) + # Full: Everything + echo "CORE:secubox-core secubox-base secubox-identity secubox-master-link secubox-p2p" + echo "THEME:luci-theme-secubox" + echo "SECURITY:?secubox-app-crowdsec ?secubox-app-cs-firewall-bouncer secubox-app-ipblocklist secubox-app-mitmproxy" + echo "NETWORK:secubox-app-haproxy secubox-app-dns-master secubox-app-exposure secubox-app-tor" + echo "MONITORING:secubox-app-glances secubox-app-netifyd secubox-app-watchdog" + echo "LUCI:luci-app-secubox luci-app-haproxy luci-app-exposure luci-app-dns-master" + echo "LUCI:?luci-app-crowdsec-dashboard luci-app-glances luci-app-master-link" + echo "BONUS:?secubox-app-bonus" + ;; + *) + log_error "Unknown profile: $profile" + log_info "Available profiles: minimal, standard, full" + return 1 + ;; + esac +} + +# Post-installation setup +post_install() { + log_info "Running post-installation setup..." + + # Initialize SecuBox if secubox-core is installed + if [ -x /usr/sbin/secuboxctl ]; then + log_info "Initializing SecuBox..." + /usr/sbin/secuboxctl init 2>/dev/null || true + fi + + # Enable and start key services + local services="secubox haproxy" + for svc in $services; do + if [ -f "/etc/init.d/$svc" ]; then + log_info "Enabling $svc service..." + /etc/init.d/$svc enable 2>/dev/null || true + fi + done + + # Reload rpcd for new RPC methods + if [ -f /etc/init.d/rpcd ]; then + log_info "Reloading RPCD..." + /etc/init.d/rpcd restart 2>/dev/null || true + fi + + log_ok "Post-installation setup complete" +} + +# Print summary +print_summary() { + local profile="$1" + + echo "" + echo "==========================================" + printf "${GREEN}SecuBox Installation Complete${NC}\n" + echo "==========================================" + echo "" + echo "Profile: $profile" + echo "Architecture: $(detect_arch)" + echo "" + echo "Access LuCI at: http://$(uci get network.lan.ipaddr 2>/dev/null || echo '192.168.1.1')" + echo "" + echo "Installed packages:" + opkg list-installed | grep -E "^secubox-|^luci-.*secubox|^luci-theme-secubox" | while read line; do + echo " - $line" + done + echo "" + echo "For more information:" + echo " https://docs.secubox.in" + echo "" +} + +# Main installation flow +main() { + local profile="${SECUBOX_PROFILE:-standard}" + + echo "" + echo "==========================================" + printf "${BLUE}SecuBox Seed Installer${NC}\n" + echo "==========================================" + echo "" + log_info "Profile: $profile" + + # Pre-flight checks + if [ "$(id -u)" != "0" ]; then + log_error "This script must be run as root" + exit 1 + fi + + if ! command -v opkg >/dev/null 2>&1; then + log_error "opkg not found. Is this an OpenWrt system?" + exit 1 + fi + + # Detect architecture + local arch + arch=$(detect_arch) + log_info "Detected architecture: $arch" + + # Check connectivity + if ! check_connectivity; then + exit 1 + fi + + # Configure repository + configure_repo "$arch" + + # Update package lists + update_packages + + # Check if repo is available before trying to install + if [ "${SECUBOX_REPO_AVAILABLE:-1}" = "0" ]; then + log_warn "SecuBox repository not available. Skipping package installation." + log_info "Repository has been configured for future use." + log_info "When packages are available, run: opkg update && opkg install secubox-core" + if [ "${SECUBOX_DRY_RUN:-0}" != "1" ]; then + echo "" + echo "==========================================" + printf "${YELLOW}SecuBox Setup Incomplete${NC}\n" + echo "==========================================" + echo "" + echo "Repository configured but packages not available." + echo "To complete installation later:" + echo " opkg update" + echo " opkg install secubox-core secubox-base luci-theme-secubox" + echo "" + fi + exit 0 + fi + + # Get packages for selected profile + local profile_data + profile_data=$(get_profile_packages "$profile") + + if [ -z "$profile_data" ]; then + exit 1 + fi + + # Install each package group + local install_failed=0 + echo "$profile_data" | while IFS=: read group packages; do + if ! install_group "$group" $packages; then + install_failed=1 + fi + done + + # Post-installation + if [ "${SECUBOX_DRY_RUN:-0}" != "1" ]; then + post_install + print_summary "$profile" + else + log_info "[DRY RUN] Skipping post-installation" + fi + + if [ "$install_failed" = "1" ]; then + log_warn "Installation completed with some errors" + exit 1 + fi + + log_ok "SecuBox installation completed successfully!" +} + +# Handle command-line arguments +while [ $# -gt 0 ]; do + case "$1" in + --profile=*) + SECUBOX_PROFILE="${1#*=}" + ;; + --mirror=*) + SECUBOX_MIRROR="${1#*=}" + ;; + --dry-run) + SECUBOX_DRY_RUN=1 + ;; + --skip-update) + SECUBOX_SKIP_UPDATE=1 + ;; + --help|-h) + echo "SecuBox Seed Installer" + echo "" + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Options:" + echo " --profile=PROFILE Installation profile (minimal|standard|full)" + echo " --mirror=URL Override repository URL" + echo " --dry-run Show what would be installed" + echo " --skip-update Skip opkg update" + echo " --help Show this help" + echo "" + echo "Environment variables:" + echo " SECUBOX_PROFILE Same as --profile" + echo " SECUBOX_MIRROR Same as --mirror" + echo " SECUBOX_DRY_RUN=1 Same as --dry-run" + echo " SECUBOX_SKIP_UPDATE=1 Same as --skip-update" + echo "" + exit 0 + ;; + *) + log_error "Unknown option: $1" + exit 1 + ;; + esac + shift +done + +main diff --git a/scripts/secubox-slipstream.sh b/scripts/secubox-slipstream.sh new file mode 100755 index 00000000..d96f8a43 --- /dev/null +++ b/scripts/secubox-slipstream.sh @@ -0,0 +1,396 @@ +#!/bin/sh +# +# SecuBox Slipstream Script +# Bakes SecuBox repository configuration into OpenWrt images during build +# +# This script is designed to be run during the OpenWrt build process +# to pre-configure the SecuBox repository and optionally pre-install packages. +# +# Usage (during OpenWrt build): +# ./scripts/secubox-slipstream.sh [--profile=PROFILE] +# +# Or as a standalone image modifier: +# ./scripts/secubox-slipstream.sh --image= [--profile=PROFILE] +# + +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_URL="${SECUBOX_REPO_URL:-https://repo.secubox.in}" +PROFILE="${SECUBOX_PROFILE:-standard}" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +log_info() { printf "${BLUE}[SLIPSTREAM]${NC} %s\n" "$1"; } +log_ok() { printf "${GREEN}[SLIPSTREAM]${NC} %s\n" "$1"; } +log_warn() { printf "${YELLOW}[SLIPSTREAM]${NC} %s\n" "$1"; } +log_error() { printf "${RED}[SLIPSTREAM]${NC} %s\n" "$1"; } + +# Detect architecture from rootfs +detect_arch() { + local rootfs="$1" + local arch="" + + # Try reading from openwrt_release + if [ -f "$rootfs/etc/openwrt_release" ]; then + arch=$(grep "DISTRIB_ARCH" "$rootfs/etc/openwrt_release" 2>/dev/null | cut -d"'" -f2) + fi + + # Fallback: check for common arch indicators + if [ -z "$arch" ]; then + if [ -d "$rootfs/lib/aarch64-linux-gnu" ] || file "$rootfs/bin/busybox" 2>/dev/null | grep -q "aarch64"; then + arch="aarch64_cortex-a72" + elif file "$rootfs/bin/busybox" 2>/dev/null | grep -q "x86-64"; then + arch="x86_64" + elif file "$rootfs/bin/busybox" 2>/dev/null | grep -q "ARM"; then + arch="arm_cortex-a7_neon-vfpv4" + fi + fi + + echo "$arch" +} + +# Create the customfeeds.conf with SecuBox repository +create_feeds_config() { + local rootfs="$1" + local arch="$2" + local feeds_file="$rootfs/etc/opkg/customfeeds.conf" + + log_info "Creating SecuBox feed configuration..." + + mkdir -p "$rootfs/etc/opkg" + + cat > "$feeds_file" << EOF +# SecuBox Package Repository +# Pre-configured by secubox-slipstream.sh +# Architecture: $arch +# Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ) + +src/gz secubox_packages ${REPO_URL}/packages/${arch} +src/gz secubox_luci ${REPO_URL}/luci/${arch} +EOF + + log_ok "Feed configuration created: $feeds_file" +} + +# Install the seed script into the image +install_seed_script() { + local rootfs="$1" + local seed_script="$SCRIPT_DIR/secubox-seed.sh" + + log_info "Installing seed script..." + + mkdir -p "$rootfs/usr/sbin" + + if [ -f "$seed_script" ]; then + cp "$seed_script" "$rootfs/usr/sbin/secubox-seed" + chmod +x "$rootfs/usr/sbin/secubox-seed" + log_ok "Seed script installed: /usr/sbin/secubox-seed" + else + log_warn "Seed script not found: $seed_script" + fi +} + +# Create first-boot script for auto-setup +create_firstboot_script() { + local rootfs="$1" + local profile="$2" + + log_info "Creating first-boot setup script..." + + mkdir -p "$rootfs/etc/uci-defaults" + + cat > "$rootfs/etc/uci-defaults/99-secubox-setup" << 'FIRSTBOOT' +#!/bin/sh +# +# SecuBox First-Boot Setup +# Runs once on first boot to complete SecuBox installation +# + +PROFILE="${SECUBOX_PROFILE:-standard}" +LOG_FILE="/tmp/secubox-firstboot.log" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" +} + +log "SecuBox first-boot setup starting..." + +# Check if opkg feeds are already configured +if grep -q "secubox_packages" /etc/opkg/customfeeds.conf 2>/dev/null; then + log "SecuBox feeds already configured" +else + log "Error: SecuBox feeds not configured!" + exit 1 +fi + +# Update package lists +log "Updating package lists..." +if opkg update 2>&1 | tee -a "$LOG_FILE"; then + log "Package lists updated successfully" +else + log "Warning: opkg update had errors" +fi + +# Install core packages if not already installed +CORE_PACKAGES="secubox-core secubox-base luci-theme-secubox" + +for pkg in $CORE_PACKAGES; do + if ! opkg list-installed | grep -q "^$pkg "; then + log "Installing $pkg..." + if opkg install "$pkg" 2>&1 | tee -a "$LOG_FILE"; then + log "$pkg installed successfully" + else + log "Warning: $pkg installation failed" + fi + else + log "$pkg already installed" + fi +done + +# Set SecuBox theme as default +if [ -f /etc/config/luci ]; then + uci set luci.main.mediaurlbase='/luci-static/secubox' 2>/dev/null || true + uci commit luci 2>/dev/null || true + log "SecuBox theme set as default" +fi + +# Mark setup complete +touch /etc/secubox-installed +log "SecuBox first-boot setup complete" + +# Remove this script (run once) +exit 0 +FIRSTBOOT + + chmod +x "$rootfs/etc/uci-defaults/99-secubox-setup" + log_ok "First-boot script created" +} + +# Create SecuBox branding +create_branding() { + local rootfs="$1" + + log_info "Adding SecuBox branding..." + + # Custom banner + mkdir -p "$rootfs/etc" + cat > "$rootfs/etc/banner" << 'BANNER' + + ____ ____ + / ___| ___ ___ _ _| __ ) _____ __ + \___ \ / _ \/ __| | | | _ \ / _ \ \/ / + ___) | __/ (__| |_| | |_) | (_) > < + |____/ \___|\___|\__,_|____/ \___/_/\_\ + + SecuBox - Security Gateway for OpenWrt + https://secubox.in + + Run 'secubox-seed --help' for setup options + +BANNER + + # Version info + cat > "$rootfs/etc/secubox-release" << EOF +SECUBOX_VERSION="1.0.0" +SECUBOX_CODENAME="Genesis" +SECUBOX_BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)" +SECUBOX_PROFILE="${PROFILE}" +EOF + + log_ok "Branding added" +} + +# Slipstream into an existing rootfs directory +slipstream_rootfs() { + local rootfs="$1" + local profile="$2" + + log_info "Slipstreaming SecuBox into rootfs: $rootfs" + + if [ ! -d "$rootfs" ]; then + log_error "Rootfs directory not found: $rootfs" + exit 1 + fi + + # Detect architecture + local arch + arch=$(detect_arch "$rootfs") + if [ -z "$arch" ]; then + log_warn "Could not detect architecture, using x86_64" + arch="x86_64" + fi + log_info "Detected architecture: $arch" + + # Apply slipstream + create_feeds_config "$rootfs" "$arch" + install_seed_script "$rootfs" + create_firstboot_script "$rootfs" "$profile" + create_branding "$rootfs" + + log_ok "Slipstream complete for: $rootfs" +} + +# Slipstream into a compressed image file +slipstream_image() { + local image="$1" + local profile="$2" + + log_info "Slipstreaming SecuBox into image: $image" + + if [ ! -f "$image" ]; then + log_error "Image file not found: $image" + exit 1 + fi + + # Create temp directory + local tmpdir + tmpdir=$(mktemp -d) + trap "rm -rf '$tmpdir'" EXIT + + local mount_point="$tmpdir/rootfs" + local work_image="$tmpdir/work.img" + mkdir -p "$mount_point" + + # Decompress if needed + case "$image" in + *.gz) + log_info "Decompressing image..." + gunzip -c "$image" > "$work_image" + ;; + *.img|*.raw) + cp "$image" "$work_image" + ;; + *) + log_error "Unsupported image format: $image" + exit 1 + ;; + esac + + # Find and mount rootfs partition + log_info "Mounting image..." + + # Try to find rootfs partition offset + local offset + offset=$(fdisk -l "$work_image" 2>/dev/null | grep -E "Linux|ext4" | tail -1 | awk '{print $2}') + + if [ -n "$offset" ]; then + offset=$((offset * 512)) + sudo mount -o loop,offset=$offset "$work_image" "$mount_point" + else + # Try mounting as-is (might be raw rootfs) + sudo mount -o loop "$work_image" "$mount_point" + fi + + # Apply slipstream + slipstream_rootfs "$mount_point" "$profile" + + # Unmount + log_info "Unmounting image..." + sudo umount "$mount_point" + + # Recompress if original was compressed + case "$image" in + *.gz) + log_info "Recompressing image..." + local output="${image%.gz}-secubox.img.gz" + gzip -c "$work_image" > "$output" + log_ok "Output: $output" + ;; + *) + local output="${image%.*}-secubox.${image##*.}" + mv "$work_image" "$output" + log_ok "Output: $output" + ;; + esac +} + +# Print usage +usage() { + cat << EOF +SecuBox Slipstream Script + +Usage: + $0 Slipstream into rootfs directory + $0 --image= Slipstream into image file + +Options: + --profile=PROFILE Installation profile (minimal|standard|full) + --repo=URL Override repository URL + --help Show this help + +Environment: + SECUBOX_REPO_URL Repository URL (default: https://repo.secubox.in) + SECUBOX_PROFILE Installation profile (default: standard) + +Examples: + # During OpenWrt build (in files/): + $0 ../build_dir/target-*/root-*/ + + # Modify existing image: + $0 --image=openwrt-x86-64-generic-ext4-combined.img.gz + + # With custom profile: + $0 --profile=full /path/to/rootfs +EOF +} + +# Main +main() { + local rootfs="" + local image="" + + # Parse arguments + while [ $# -gt 0 ]; do + case "$1" in + --image=*) + image="${1#*=}" + ;; + --profile=*) + PROFILE="${1#*=}" + ;; + --repo=*) + REPO_URL="${1#*=}" + ;; + --help|-h) + usage + exit 0 + ;; + -*) + log_error "Unknown option: $1" + usage + exit 1 + ;; + *) + rootfs="$1" + ;; + esac + shift + done + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo " SecuBox Slipstream" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo " Profile: $PROFILE" + echo " Repo: $REPO_URL" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + + if [ -n "$image" ]; then + slipstream_image "$image" "$PROFILE" + elif [ -n "$rootfs" ]; then + slipstream_rootfs "$rootfs" "$PROFILE" + else + log_error "No rootfs directory or image specified" + usage + exit 1 + fi +} + +main "$@"