#!/bin/bash # SecuBox Repository Deployment Script # Deploys all built packages to repo.secubox.in (c3box.local) # Unifies secubox-app-bonus and secubox-app-repo into one repository set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" # Configuration REPO_HOST="${REPO_HOST:-root@c3box.local}" REPO_PATH="${REPO_PATH:-/srv/repo.secubox.in}" SDK_PATH="${SDK_PATH:-$SCRIPT_DIR/sdk}" LOCAL_STAGING="${LOCAL_STAGING:-/tmp/secubox-repo-staging}" # SSH multiplexing SSH_CONTROL_PATH="/tmp/ssh-repo-%r@%h:%p" SSH_OPTS="-o RequestTTY=no -o ForwardX11=no -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=$SSH_CONTROL_PATH -o ControlPersist=600" # Architectures to include ARCHS=( "aarch64_cortex-a72" "aarch64_cortex-a53" "aarch64_generic" "x86_64" "mips_24kc" "mipsel_24kc" ) usage() { cat <<'USAGE' Usage: repo-deploy.sh [command] [options] Commands: stage Prepare packages locally (default) deploy [host] Deploy to remote host (default: c3box.local) local Deploy to local directory index Generate Packages indexes only status Show staging status Options: --sdk SDK path (default: secubox-tools/sdk) --staging Local staging directory (default: /tmp/secubox-repo-staging) --arch Process only specific architecture --clean Clean staging before processing -h, --help Show this message Examples: ./repo-deploy.sh stage # Stage packages from SDK build ./repo-deploy.sh deploy # Deploy to c3box.local ./repo-deploy.sh deploy root@192.168.255.1 # Deploy to specific host ./repo-deploy.sh local /srv/repo # Deploy to local path USAGE exit 1 } log() { echo -e "[$(date +'%H:%M:%S')] $*" } error() { echo -e "[ERROR] $*" >&2 exit 1 } remote_exec() { ssh $SSH_OPTS "$REPO_HOST" "$@" } # Find all built packages find_packages() { local arch="$1" local sdk_pkg_dir="$SDK_PATH/bin/packages/$arch" if [[ -d "$sdk_pkg_dir" ]]; then find "$sdk_pkg_dir" -type f -name "*.ipk" 2>/dev/null fi } # Generate Packages index for a directory generate_index() { local dir="$1" if [[ ! -d "$dir" ]]; then log " Skipping $dir (not found)" return fi local pkg_count=0 # Generate Packages file rm -f "$dir/Packages" "$dir/Packages.gz" for ipk in "$dir"/*.ipk; do [[ -f "$ipk" ]] || continue pkg_count=$((pkg_count + 1)) local filename=$(basename "$ipk") local size=$(stat -c%s "$ipk" 2>/dev/null || ls -l "$ipk" | awk '{print $5}') local md5=$(md5sum "$ipk" | cut -d' ' -f1) local sha256=$(sha256sum "$ipk" | cut -d' ' -f1) # Extract package info from ipk local pkg_name=$(echo "$filename" | sed 's/_.*//g') local version=$(echo "$filename" | sed 's/^[^_]*_//; s/_[^_]*$//') local arch_name=$(echo "$filename" | sed 's/.*_//; s/\.ipk$//') cat >> "$dir/Packages" < "$dir/Packages.gz" log " Generated index: $pkg_count packages" else log " No packages found" fi } # Stage packages locally cmd_stage() { log "Staging packages to $LOCAL_STAGING" if [[ "$CLEAN" == "1" ]]; then log "Cleaning staging directory..." rm -rf "$LOCAL_STAGING" fi mkdir -p "$LOCAL_STAGING/luci" "$LOCAL_STAGING/packages" local total_luci=0 local total_pkg=0 local source_arch="" # First pass: find which architectures have actual build output for arch in "${ARCHS[@]}"; do local sdk_pkg_dir="$SDK_PATH/bin/packages/$arch" if [[ -d "$sdk_pkg_dir" ]]; then source_arch="$arch" break fi done if [[ -z "$source_arch" ]]; then error "No SDK build output found for any architecture" fi log "Source architecture: $source_arch" log "Will replicate _all.ipk packages to all architectures" # Collect architecture-independent packages (all.ipk) local all_luci_pkgs=() local all_other_pkgs=() local arch_specific_pkgs=() local secubox_dir="$SDK_PATH/bin/packages/$source_arch/secubox" if [[ -d "$secubox_dir" ]]; then for ipk in "$secubox_dir"/*.ipk; do [[ -f "$ipk" ]] || continue local name=$(basename "$ipk") if [[ "$name" == *_all.ipk ]]; then if [[ "$name" == luci-* ]]; then all_luci_pkgs+=("$ipk") else all_other_pkgs+=("$ipk") fi else arch_specific_pkgs+=("$ipk") fi done fi local deps_dir="$SDK_PATH/bin/packages/$source_arch/packages" if [[ -d "$deps_dir" ]]; then for ipk in "$deps_dir"/*.ipk; do [[ -f "$ipk" ]] || continue local name=$(basename "$ipk") if [[ "$name" == *_all.ipk ]]; then all_other_pkgs+=("$ipk") else arch_specific_pkgs+=("$ipk") fi done fi # Process each target architecture for arch in "${ARCHS[@]}"; do if [[ -n "$SINGLE_ARCH" && "$arch" != "$SINGLE_ARCH" ]]; then continue fi log "Processing architecture: $arch" mkdir -p "$LOCAL_STAGING/luci/$arch" mkdir -p "$LOCAL_STAGING/packages/$arch" # Copy architecture-independent LuCI packages for ipk in "${all_luci_pkgs[@]}"; do cp "$ipk" "$LOCAL_STAGING/luci/$arch/" total_luci=$((total_luci + 1)) done # Copy architecture-independent other packages for ipk in "${all_other_pkgs[@]}"; do cp "$ipk" "$LOCAL_STAGING/packages/$arch/" total_pkg=$((total_pkg + 1)) done # Copy architecture-specific packages only to matching arch if [[ "$arch" == "$source_arch" ]]; then for ipk in "${arch_specific_pkgs[@]}"; do local name=$(basename "$ipk") if [[ "$name" == luci-* ]]; then cp "$ipk" "$LOCAL_STAGING/luci/$arch/" total_luci=$((total_luci + 1)) else cp "$ipk" "$LOCAL_STAGING/packages/$arch/" total_pkg=$((total_pkg + 1)) fi done fi # Generate indexes log " Generating indexes..." generate_index "$LOCAL_STAGING/luci/$arch" generate_index "$LOCAL_STAGING/packages/$arch" done # Create index.html landing page create_landing_page log "" log "Staging complete:" log " LuCI packages: $total_luci" log " Other packages: $total_pkg" log " Location: $LOCAL_STAGING" } # Create landing page create_landing_page() { cat > "$LOCAL_STAGING/index.html" <<'HTML' SecuBox Package Repository

SecuBox Package Repository

Official package repository for SecuBox - Security modules for OpenWrt.

Quick Setup

Add to /etc/opkg/customfeeds.conf:

src/gz secubox_luci https://repo.secubox.in/luci/{ARCH}
src/gz secubox_packages https://repo.secubox.in/packages/{ARCH}

Replace {ARCH} with your architecture below.

Available Architectures

aarch64_cortex-a72

Raspberry Pi 4, MochaBin

aarch64_cortex-a53

EspressoBin, Sheeva64

aarch64_generic

NanoPi R4S/R5S, Rockchip

x86_64

VMs, x86-64 devices

mips_24kc

Atheros/QCA routers

mipsel_24kc

MT7621 (Xiaomi, etc)

Installation Example

# Update feeds
opkg update

# Install SecuBox Hub
opkg install luci-app-secubox

# Install CrowdSec WAF
opkg install luci-app-secubox-crowdsec secubox-app-crowdsec

# Install bandwidth manager
opkg install luci-app-bandwidth-manager

Documentation

Updated: __TIMESTAMP__

HTML # Replace timestamp sed -i "s/__TIMESTAMP__/$(date -Iseconds)/" "$LOCAL_STAGING/index.html" } # Deploy to remote host cmd_deploy() { local target="${1:-$REPO_HOST}" REPO_HOST="$target" log "Deploying to $REPO_HOST:$REPO_PATH" # Check if staging exists if [[ ! -d "$LOCAL_STAGING" || ! -f "$LOCAL_STAGING/index.html" ]]; then log "Staging directory not found. Running stage first..." cmd_stage fi # Test SSH connection log "Testing connection..." if ! remote_exec "echo ok" >/dev/null 2>&1; then error "Cannot connect to $REPO_HOST" fi # Create target directory remote_exec "mkdir -p '$REPO_PATH'" # Sync using rsync or scp+tar fallback log "Syncing packages..." if command -v rsync >/dev/null 2>&1; then rsync -avz --delete \ -e "ssh $SSH_OPTS" \ "$LOCAL_STAGING/" \ "$REPO_HOST:$REPO_PATH/" else # Fallback: tar and scp local archive="/tmp/secubox-repo-$(date +%s).tar.gz" tar -czf "$archive" -C "$LOCAL_STAGING" . scp -o "ControlPath=$SSH_CONTROL_PATH" "$archive" "$REPO_HOST:/tmp/" remote_exec "cd '$REPO_PATH' && tar -xzf /tmp/$(basename "$archive") && rm -f /tmp/$(basename "$archive")" rm -f "$archive" fi # Sign packages on router (regenerates indexes with signatures) log "Signing packages on router..." if remote_exec "/usr/libexec/rpcd/luci.repo call refresh" >/dev/null 2>&1; then log "Package indexes signed successfully" else log "Warning: Could not sign packages. Run manually:" log " /usr/libexec/rpcd/luci.repo call refresh" fi log "" log "Deployment complete to $REPO_HOST:$REPO_PATH" log "Repository URL: https://repo.secubox.in/" } # Deploy to local directory cmd_local() { local target="${1:-}" if [[ -z "$target" ]]; then error "Local path required: repo-deploy.sh local /path/to/repo" fi log "Deploying to local path: $target" # Check if staging exists if [[ ! -d "$LOCAL_STAGING" || ! -f "$LOCAL_STAGING/index.html" ]]; then log "Staging directory not found. Running stage first..." cmd_stage fi mkdir -p "$target" # Copy with rsync or cp if command -v rsync >/dev/null 2>&1; then rsync -av --delete "$LOCAL_STAGING/" "$target/" else rm -rf "$target"/* cp -r "$LOCAL_STAGING"/* "$target/" fi log "Deployed to $target" } # Show status cmd_status() { log "SecuBox Repository Staging Status" log "==================================" log "" log "SDK Path: $SDK_PATH" log "Staging: $LOCAL_STAGING" log "" if [[ ! -d "$LOCAL_STAGING" ]]; then log "Staging directory not found. Run 'repo-deploy.sh stage' first." return fi log "Staged packages:" for arch in "${ARCHS[@]}"; do local luci_count=0 local pkg_count=0 if [[ -d "$LOCAL_STAGING/luci/$arch" ]]; then luci_count=$(ls "$LOCAL_STAGING/luci/$arch"/*.ipk 2>/dev/null | wc -l || echo 0) fi if [[ -d "$LOCAL_STAGING/packages/$arch" ]]; then pkg_count=$(ls "$LOCAL_STAGING/packages/$arch"/*.ipk 2>/dev/null | wc -l || echo 0) fi if [[ $luci_count -gt 0 || $pkg_count -gt 0 ]]; then log " $arch: $luci_count LuCI, $pkg_count packages" fi done } # Parse arguments COMMAND="${1:-stage}" shift || true CLEAN=0 SINGLE_ARCH="" while [[ $# -gt 0 ]]; do case "$1" in --sdk) SDK_PATH="$2"; shift 2 ;; --staging) LOCAL_STAGING="$2"; shift 2 ;; --arch) SINGLE_ARCH="$2"; shift 2 ;; --clean) CLEAN=1; shift ;; -h|--help) usage ;; *) # Pass remaining args to command break ;; esac done case "$COMMAND" in stage|index) cmd_stage ;; deploy) cmd_deploy "$@" ;; local) cmd_local "$@" ;; status) cmd_status ;; *) usage ;; esac