Fix wizard: defaults for all prompts, random hostname/device-id, download robustness
- Add prompt_default() helper: shows defaults, accepts Enter to use them - WiFi: default=n (skip), keeps passphrase prompt loop - Root password: auto-generate with openssl, show in summary if used, operator can override - SSH key: default=1 (generate new) - Device ID: auto-generate bb-<8-char-uuid> - Boot mode: default=1 (passive) - VPN: default=1 (none) - Hostname: NEW section with auto-generated node-<6-char-uuid> default - Alerter: default=n (disabled) - Download: use curl -L (no -f), verify file exists and >50MB - Config summary: show hostname, mask password (show auto-generated clearly) - Apply config: write BB_HOSTNAME to /etc/hostname and /etc/hosts - No eval with user input: use printf -v for variable assignment
This commit is contained in:
+66
-41
@@ -51,6 +51,19 @@ banner() {
|
|||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prompt_default() {
|
||||||
|
local var="$1" prompt="$2" default="$3"
|
||||||
|
echo -n -e "${CYAN}${prompt}${NC}"
|
||||||
|
[[ -n "$default" ]] && echo -n -e " ${BOLD}[${default}]${NC}"
|
||||||
|
echo -n ": "
|
||||||
|
read -r input
|
||||||
|
if [[ -z "$input" ]]; then
|
||||||
|
printf -v "$var" '%s' "$default"
|
||||||
|
else
|
||||||
|
printf -v "$var" '%s' "$input"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# ══════════════════════════════════════════════════════════════════════════════
|
# ══════════════════════════════════════════════════════════════════════════════
|
||||||
# PREFLIGHT
|
# PREFLIGHT
|
||||||
# ══════════════════════════════════════════════════════════════════════════════
|
# ══════════════════════════════════════════════════════════════════════════════
|
||||||
@@ -127,7 +140,12 @@ if [[ -z "$IMAGE" ]]; then
|
|||||||
IMAGE="${CACHE_DIR}/${IMAGE_FILENAME}"
|
IMAGE="${CACHE_DIR}/${IMAGE_FILENAME}"
|
||||||
|
|
||||||
if [[ ! -f "$IMAGE" ]]; then
|
if [[ ! -f "$IMAGE" ]]; then
|
||||||
curl -fL --progress-bar "$IMAGE_URL" -o "$IMAGE" || error "Failed to download image"
|
curl -L --progress-bar "$IMAGE_URL" -o "$IMAGE" || error "Failed to download image"
|
||||||
|
# Verify download: file exists and is > 50MB
|
||||||
|
if [[ ! -s "$IMAGE" ]] || [[ $(stat -c%s "$IMAGE" 2>/dev/null || echo 0) -lt 52428800 ]]; then
|
||||||
|
rm -f "$IMAGE"
|
||||||
|
error "Download failed or file too small (expected > 50MB)"
|
||||||
|
fi
|
||||||
info "Image downloaded: $IMAGE_FILENAME"
|
info "Image downloaded: $IMAGE_FILENAME"
|
||||||
else
|
else
|
||||||
info "Image already cached: $IMAGE_FILENAME"
|
info "Image already cached: $IMAGE_FILENAME"
|
||||||
@@ -150,16 +168,20 @@ section "Configuration Wizard"
|
|||||||
|
|
||||||
# WiFi (optional)
|
# WiFi (optional)
|
||||||
step "WiFi Configuration"
|
step "WiFi Configuration"
|
||||||
echo -n -e "${CYAN}Configure WiFi? (y/n):${NC} "
|
prompt_default enable_wifi "Configure WiFi? (y/n)" "n"
|
||||||
read -r enable_wifi
|
|
||||||
if [[ "$enable_wifi" =~ ^[yY]$ ]]; then
|
if [[ "$enable_wifi" =~ ^[yY]$ ]]; then
|
||||||
echo -n -e "${CYAN}WiFi SSID:${NC} "
|
prompt_default wifi_ssid "WiFi SSID" ""
|
||||||
read -r wifi_ssid
|
while true; do
|
||||||
echo -n -e "${CYAN}WiFi Passphrase:${NC} "
|
echo -n -e "${CYAN}WiFi Passphrase${NC}: "
|
||||||
read -s -r wifi_pass; echo
|
read -s -r wifi_pass; echo
|
||||||
echo -n -e "${CYAN}Confirm Passphrase:${NC} "
|
echo -n -e "${CYAN}Confirm Passphrase${NC}: "
|
||||||
read -s -r wifi_pass2; echo
|
read -s -r wifi_pass2; echo
|
||||||
[[ "$wifi_pass" == "$wifi_pass2" ]] || error "Passphrases do not match"
|
if [[ "$wifi_pass" == "$wifi_pass2" ]]; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
warn "Passphrases do not match. Try again."
|
||||||
|
fi
|
||||||
|
done
|
||||||
WIFI_SSID="$wifi_ssid"
|
WIFI_SSID="$wifi_ssid"
|
||||||
WIFI_PASS="$wifi_pass"
|
WIFI_PASS="$wifi_pass"
|
||||||
unset wifi_pass wifi_pass2
|
unset wifi_pass wifi_pass2
|
||||||
@@ -170,33 +192,29 @@ fi
|
|||||||
|
|
||||||
# Root password (required)
|
# Root password (required)
|
||||||
step "Root Password"
|
step "Root Password"
|
||||||
while true; do
|
DEFAULT_ROOT_PASS=$(openssl rand -base64 16 | tr -d '=+/')
|
||||||
echo -n -e "${CYAN}Root password:${NC} "
|
ROOT_PASS_IS_AUTO=false
|
||||||
read -s -r root_pass; echo
|
echo -e "${YELLOW}Auto-generated password: ${BOLD}${DEFAULT_ROOT_PASS}${NC}"
|
||||||
echo -n -e "${CYAN}Confirm:${NC} "
|
prompt_default root_pass "Enter custom password or press Enter to use auto-generated" ""
|
||||||
read -s -r root_pass2; echo
|
if [[ -z "$root_pass" ]]; then
|
||||||
if [[ "$root_pass" == "$root_pass2" && -n "$root_pass" ]]; then
|
ROOT_PASS="$DEFAULT_ROOT_PASS"
|
||||||
|
ROOT_PASS_IS_AUTO=true
|
||||||
|
else
|
||||||
ROOT_PASS="$root_pass"
|
ROOT_PASS="$root_pass"
|
||||||
unset root_pass root_pass2
|
fi
|
||||||
break
|
unset root_pass
|
||||||
else
|
|
||||||
warn "Passwords do not match or empty. Try again."
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# SSH Key
|
# SSH Key
|
||||||
step "SSH Key Configuration"
|
step "SSH Key Configuration"
|
||||||
echo " [1] Generate new keypair (stored in Infisical)"
|
echo " [1] Generate new keypair (stored in Infisical)"
|
||||||
echo " [2] Use existing public key file"
|
echo " [2] Use existing public key file"
|
||||||
echo -n -e "${CYAN}SSH option (1-2):${NC} "
|
prompt_default ssh_opt "SSH option (1-2)" "1"
|
||||||
read -r ssh_opt
|
|
||||||
|
|
||||||
if [[ "$ssh_opt" == "1" ]]; then
|
if [[ "$ssh_opt" == "1" ]]; then
|
||||||
SSH_MODE="generate"
|
SSH_MODE="generate"
|
||||||
elif [[ "$ssh_opt" == "2" ]]; then
|
elif [[ "$ssh_opt" == "2" ]]; then
|
||||||
SSH_MODE="existing"
|
SSH_MODE="existing"
|
||||||
echo -n -e "${CYAN}Path to public key file:${NC} "
|
prompt_default ssh_pubkey_path "Path to public key file" ""
|
||||||
read -r ssh_pubkey_path
|
|
||||||
[[ -f "$ssh_pubkey_path" ]] || error "File not found: $ssh_pubkey_path"
|
[[ -f "$ssh_pubkey_path" ]] || error "File not found: $ssh_pubkey_path"
|
||||||
SSH_PUBKEY=$(cat "$ssh_pubkey_path")
|
SSH_PUBKEY=$(cat "$ssh_pubkey_path")
|
||||||
else
|
else
|
||||||
@@ -205,18 +223,22 @@ fi
|
|||||||
|
|
||||||
# Device ID
|
# Device ID
|
||||||
step "Device ID"
|
step "Device ID"
|
||||||
echo -n -e "${CYAN}Device label (e.g. bb-01):${NC} "
|
DEFAULT_DEVICE_ID="bb-$(cat /proc/sys/kernel/random/uuid | cut -c1-8)"
|
||||||
read -r device_id
|
prompt_default device_id "Device label (e.g. bb-a3f2c1)" "$DEFAULT_DEVICE_ID"
|
||||||
[[ -n "$device_id" ]] || error "Device ID cannot be empty"
|
|
||||||
DEVICE_ID="$device_id"
|
DEVICE_ID="$device_id"
|
||||||
|
|
||||||
|
# Hostname
|
||||||
|
step "Hostname"
|
||||||
|
DEFAULT_HOSTNAME="node-$(cat /proc/sys/kernel/random/uuid | cut -c1-6)"
|
||||||
|
prompt_default bb_hostname "Hostname" "$DEFAULT_HOSTNAME"
|
||||||
|
BB_HOSTNAME="$bb_hostname"
|
||||||
|
|
||||||
# Auto-start mode
|
# Auto-start mode
|
||||||
step "Auto-start Mode on Boot"
|
step "Auto-start Mode on Boot"
|
||||||
echo " [1] Passive only (capture + analysis, no active offense)"
|
echo " [1] Passive only (capture + analysis, no active offense)"
|
||||||
echo " [2] Full autonomous (all modules)"
|
echo " [2] Full autonomous (all modules)"
|
||||||
echo " [3] Manual (operator SSHs in to start)"
|
echo " [3] Manual (operator SSHs in to start)"
|
||||||
echo -n -e "${CYAN}Select mode (1-3):${NC} "
|
prompt_default mode_opt "Select mode (1-3)" "1"
|
||||||
read -r mode_opt
|
|
||||||
|
|
||||||
if [[ "$mode_opt" == "1" ]]; then
|
if [[ "$mode_opt" == "1" ]]; then
|
||||||
BB_MODE="passive"
|
BB_MODE="passive"
|
||||||
@@ -233,8 +255,7 @@ step "VPN Tunnel"
|
|||||||
echo " [1] None"
|
echo " [1] None"
|
||||||
echo " [2] Tailscale"
|
echo " [2] Tailscale"
|
||||||
echo " [3] WireGuard"
|
echo " [3] WireGuard"
|
||||||
echo -n -e "${CYAN}Select VPN (1-3):${NC} "
|
prompt_default vpn_opt "Select VPN (1-3)" "1"
|
||||||
read -r vpn_opt
|
|
||||||
|
|
||||||
BB_VPN="none"
|
BB_VPN="none"
|
||||||
TAILSCALE_KEY=""
|
TAILSCALE_KEY=""
|
||||||
@@ -244,13 +265,11 @@ if [[ "$vpn_opt" == "1" ]]; then
|
|||||||
BB_VPN="none"
|
BB_VPN="none"
|
||||||
elif [[ "$vpn_opt" == "2" ]]; then
|
elif [[ "$vpn_opt" == "2" ]]; then
|
||||||
BB_VPN="tailscale"
|
BB_VPN="tailscale"
|
||||||
echo -n -e "${CYAN}Tailscale auth key:${NC} "
|
prompt_default tailscale_key "Tailscale auth key" ""
|
||||||
read -r tailscale_key
|
|
||||||
TAILSCALE_KEY="$tailscale_key"
|
TAILSCALE_KEY="$tailscale_key"
|
||||||
elif [[ "$vpn_opt" == "3" ]]; then
|
elif [[ "$vpn_opt" == "3" ]]; then
|
||||||
BB_VPN="wireguard"
|
BB_VPN="wireguard"
|
||||||
echo -n -e "${CYAN}Path to WireGuard config (wg0.conf):${NC} "
|
prompt_default wg_config_path "Path to WireGuard config (wg0.conf)" ""
|
||||||
read -r wg_config_path
|
|
||||||
[[ -f "$wg_config_path" ]] || error "File not found: $wg_config_path"
|
[[ -f "$wg_config_path" ]] || error "File not found: $wg_config_path"
|
||||||
WG_CONFIG=$(cat "$wg_config_path")
|
WG_CONFIG=$(cat "$wg_config_path")
|
||||||
else
|
else
|
||||||
@@ -259,11 +278,9 @@ fi
|
|||||||
|
|
||||||
# Network alerter webhook
|
# Network alerter webhook
|
||||||
step "Network Alerter"
|
step "Network Alerter"
|
||||||
echo -n -e "${CYAN}Enable alerter webhook? (y/n):${NC} "
|
prompt_default enable_alerter "Enable alerter webhook? (y/n)" "n"
|
||||||
read -r enable_alerter
|
|
||||||
if [[ "$enable_alerter" =~ ^[yY]$ ]]; then
|
if [[ "$enable_alerter" =~ ^[yY]$ ]]; then
|
||||||
echo -n -e "${CYAN}Webhook URL (Slack/Discord/Matrix):${NC} "
|
prompt_default webhook_url "Webhook URL (Slack/Discord/Matrix)" ""
|
||||||
read -r webhook_url
|
|
||||||
BB_ALERTER_WEBHOOK="$webhook_url"
|
BB_ALERTER_WEBHOOK="$webhook_url"
|
||||||
else
|
else
|
||||||
BB_ALERTER_WEBHOOK=""
|
BB_ALERTER_WEBHOOK=""
|
||||||
@@ -275,11 +292,16 @@ fi
|
|||||||
section "Configuration Summary"
|
section "Configuration Summary"
|
||||||
|
|
||||||
echo "Device ID: ${BOLD}${DEVICE_ID}${NC}"
|
echo "Device ID: ${BOLD}${DEVICE_ID}${NC}"
|
||||||
|
echo "Hostname: ${BOLD}${BB_HOSTNAME}${NC}"
|
||||||
echo "Target: ${BOLD}/dev/${DEVICE}${NC}"
|
echo "Target: ${BOLD}/dev/${DEVICE}${NC}"
|
||||||
echo "Image: ${BOLD}$(basename $IMAGE)${NC}"
|
echo "Image: ${BOLD}$(basename $IMAGE)${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
|
if [[ "$ROOT_PASS_IS_AUTO" == true ]]; then
|
||||||
|
echo "Root Pass: ${BOLD}${RED}AUTO-GENERATED — RECORD THIS: ${DEFAULT_ROOT_PASS}${NC}"
|
||||||
|
else
|
||||||
|
echo "Root Pass: ${BOLD}[custom]${NC}"
|
||||||
|
fi
|
||||||
echo "WiFi: ${BOLD}$([ -n "$WIFI_SSID" ] && echo "$WIFI_SSID" || echo "disabled")${NC}"
|
echo "WiFi: ${BOLD}$([ -n "$WIFI_SSID" ] && echo "$WIFI_SSID" || echo "disabled")${NC}"
|
||||||
echo "Root Pass: ${BOLD}[set]${NC}"
|
|
||||||
echo "SSH Mode: ${BOLD}${SSH_MODE}${NC}"
|
echo "SSH Mode: ${BOLD}${SSH_MODE}${NC}"
|
||||||
echo "Auto-start: ${BOLD}${BB_MODE}${NC}"
|
echo "Auto-start: ${BOLD}${BB_MODE}${NC}"
|
||||||
echo "VPN: ${BOLD}${BB_VPN}${NC}"
|
echo "VPN: ${BOLD}${BB_VPN}${NC}"
|
||||||
@@ -398,7 +420,10 @@ chmod 600 "${SSH_DIR}/authorized_keys"
|
|||||||
info "SSH authorized_keys configured"
|
info "SSH authorized_keys configured"
|
||||||
|
|
||||||
# Hostname
|
# Hostname
|
||||||
echo "orangepi" > "${MOUNT_POINT}/etc/hostname"
|
step "Setting hostname..."
|
||||||
|
echo "$BB_HOSTNAME" > "${MOUNT_POINT}/etc/hostname"
|
||||||
|
sed -i "s/orangepi/$BB_HOSTNAME/g" "${MOUNT_POINT}/etc/hosts" 2>/dev/null || true
|
||||||
|
info "Hostname set to: $BB_HOSTNAME"
|
||||||
|
|
||||||
# Disable first-login wizard
|
# Disable first-login wizard
|
||||||
rm -f "${MOUNT_POINT}/root/.not_logged_in_yet"
|
rm -f "${MOUNT_POINT}/root/.not_logged_in_yet"
|
||||||
|
|||||||
Reference in New Issue
Block a user