Rewrite first-boot wizard using whiptail TUI

Replace manual read prompts with whiptail dialogs for reliable
user input. Whiptail is pre-installed on Raspberry Pi OS.

Features:
- Modal dialogs that properly wait for input
- Progress gauge for key generation and setup
- Cleaner, more professional look
- No more input buffer issues

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Aaron D. Lee
2026-01-04 16:11:48 -05:00
parent b568026253
commit 419b491737

View File

@@ -6,56 +6,40 @@
# This script is triggered by /etc/profile.d/stegasoo-wizard.sh # This script is triggered by /etc/profile.d/stegasoo-wizard.sh
# After completion, it removes itself to prevent re-running # After completion, it removes itself to prevent re-running
# #
# Uses whiptail for reliable TUI dialogs (pre-installed on Pi OS)
# Colors #
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
BOLD='\033[1m'
NC='\033[0m'
# Configuration # Configuration
INSTALL_DIR="/opt/stegasoo" INSTALL_DIR="/opt/stegasoo"
FLAG_FILE="/etc/stegasoo-first-boot" FLAG_FILE="/etc/stegasoo-first-boot"
PROFILE_HOOK="/etc/profile.d/stegasoo-wizard.sh" PROFILE_HOOK="/etc/profile.d/stegasoo-wizard.sh"
# Terminal dimensions
TERM_HEIGHT=$(tput lines 2>/dev/null || echo 24)
TERM_WIDTH=$(tput cols 2>/dev/null || echo 80)
BOX_HEIGHT=$((TERM_HEIGHT - 4))
BOX_WIDTH=$((TERM_WIDTH - 4))
[ $BOX_HEIGHT -gt 20 ] && BOX_HEIGHT=20
[ $BOX_WIDTH -gt 70 ] && BOX_WIDTH=70
# Check if this is first boot # Check if this is first boot
if [ ! -f "$FLAG_FILE" ]; then if [ ! -f "$FLAG_FILE" ]; then
exit 0 exit 0
fi fi
clear # =============================================================================
# Welcome
# =============================================================================
echo "" whiptail --title "Stegasoo First Boot Wizard" --msgbox "\
echo -e "${GRAY} . · . · . · . · . · . · . · . · . · . · . · . · . · . · . · . · .${NC}" Welcome to Stegasoo!
echo -e "${GRAY} · . · . · . · . · . · . · . · . · . · . · . · . · . · . · . · . ·${NC}"
echo -e "${GRAY} . · . · . · . · . · . ${CYAN}/\\\\${GRAY} · . · ${CYAN}/\\\\${GRAY} · . · ${CYAN}/\\\\${GRAY} · . · ${CYAN}/\\\\${GRAY} · . · . · . .${NC}"
echo -e "${GRAY} · . · . · . · . · . · ${CYAN}\\\\/${GRAY} · . · ${CYAN}\\\\/${GRAY} · . · ${CYAN}\\\\/${GRAY} · . · ${CYAN}\\\\/${GRAY} · . · . · . ·${NC}"
echo -e "${GRAY} . · . · . · . · . · . · . · . · . · . · . · . · . · . · . · . · .${NC}"
echo -e "${GRAY} · . ${CYAN} ___ _____ ___ ___ _ ___ ___ ___ ${GRAY} . · . ·${NC}"
echo -e "${GRAY} . · ${CYAN}/ __||_ _|| __| / __| /_\\\\ / __| / _ \\\\ / _ \\\\${GRAY} · . · ·${NC}"
echo -e "${GRAY} · . ${CYAN}/ __||_ _|| __| / __| /_\\\\ / __| / _ \\\\ / _ \\\\${GRAY} . · . ·${NC}"
echo -e "${GRAY} . · ${CYAN}\\\\__ \\\\ | | | _| | (_ | / _ \\\\ \\\\__ \\\\ | (_) || (_) |${GRAY} · . · ·${NC}"
echo -e "${GRAY} · . ${CYAN}\\\\__ \\\\ | | | _| | (_ | / _ \\\\ \\\\__ \\\\ | (_) || (_) |${GRAY} . · . ·${NC}"
echo -e "${GRAY} . · ${CYAN}|___/ |_| |___| \\\\___|/_/ \\\\_\\\\|___/ \\\\___/ \\\\___/${GRAY} · . · ·${NC}"
echo -e "${GRAY} · . ${CYAN}|___/ |_| |___| \\\\___|/_/ \\\\_\\\\|___/ \\\\___/ \\\\___/${GRAY} . · . ·${NC}"
echo -e "${GRAY} · . · . · . · . · . · . · . · . · . · . · . · . · . · . · . · . ·${NC}"
echo -e "${GRAY} . · . · . · . · . · . · . · . · . · . · . · . · . · . · . · . · .${NC}"
echo -e "${GRAY} · . · ${CYAN}~~~~${NC} ${GRAY}· . · . · .${NC} ${CYAN}First Boot Wizard${NC} ${GRAY}· . · . · ${CYAN}~~~~${NC} ${GRAY}· . · . ·${NC}"
echo -e "${GRAY} . · . ${CYAN}~~~~${NC} ${GRAY}· . · . · . · . · . · . · . · . · . · . ${CYAN}~~~~${NC} ${GRAY}· . · . .${NC}"
echo -e "${GRAY} · . · . · . · . · . · . · . · . · . · . · . · . · . · . · . · . ·${NC}"
echo ""
echo -e "${BOLD}Welcome to Stegasoo!${NC}" This wizard will help you configure your Stegasoo server.
echo ""
echo "This wizard will help you configure your Stegasoo server." You can reconfigure later by editing:
echo "You can reconfigure later by editing /etc/systemd/system/stegasoo.service" /etc/systemd/system/stegasoo.service
echo ""
echo -e "${YELLOW}Press Enter to begin setup...${NC}" Press OK to begin setup..." $BOX_HEIGHT $BOX_WIDTH
read
# ============================================================================= # =============================================================================
# Configuration Variables # Configuration Variables
@@ -69,28 +53,13 @@ CHANNEL_KEY=""
# Step 1: HTTPS Configuration # Step 1: HTTPS Configuration
# ============================================================================= # =============================================================================
clear if whiptail --title "Step 1 of 3: HTTPS Configuration" --yesno "\
echo -e "${BOLD}Step 1 of 3: HTTPS Configuration${NC}" HTTPS encrypts all traffic between your browser and this server using a self-signed certificate.
echo -e "${BLUE}-------------------------------------------------------${NC}"
echo "" NOTE: Your browser will show a security warning because the certificate is self-signed. This is normal for home networks.
echo "HTTPS encrypts all traffic between your browser and this server"
echo "using a self-signed certificate." Enable HTTPS? (Recommended)" $BOX_HEIGHT $BOX_WIDTH; then
echo ""
echo -e "${YELLOW}Note:${NC} Your browser will show a security warning because the"
echo "certificate is self-signed. This is normal for home networks."
echo ""
echo " [Y] Enable HTTPS (recommended for home network security)"
echo " [n] Use HTTP only (unencrypted, not recommended)"
echo ""
# Flush input buffer to prevent stray keystrokes from auto-answering
read -t 0.1 -n 10000 discard 2>/dev/null || true
read -p "Enable HTTPS? [Y/n] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
ENABLE_HTTPS="true" ENABLE_HTTPS="true"
echo ""
echo -e " ${GREEN}${NC} HTTPS will be enabled"
sleep 1
fi fi
# ============================================================================= # =============================================================================
@@ -98,30 +67,16 @@ fi
# ============================================================================= # =============================================================================
if [ "$ENABLE_HTTPS" = "true" ]; then if [ "$ENABLE_HTTPS" = "true" ]; then
clear if whiptail --title "Step 2 of 3: Port Configuration" --yesno "\
echo -e "${BOLD}Step 2 of 3: Port Configuration${NC}" The standard HTTPS port is 443, which means you can access Stegasoo without specifying a port in the URL.
echo -e "${BLUE}-------------------------------------------------------${NC}"
echo "" Port 443: https://stegasoo.local
echo "The standard HTTPS port is 443, which means you can access" Port 5000: https://stegasoo.local:5000
echo "Stegasoo without specifying a port in the URL."
echo "" NOTE: Port 443 requires an iptables redirect rule.
echo " Port 443: https://stegasoo.local"
echo " Port 5000: https://stegasoo.local:5000" Use standard port 443? (Cleaner URLs)" $BOX_HEIGHT $BOX_WIDTH; then
echo ""
echo -e "${YELLOW}Note:${NC} Port 443 requires an iptables redirect rule."
echo ""
echo " [Y] Use port 443 (cleaner URLs)"
echo " [n] Use port 5000 (default, no extra config)"
echo ""
# Flush input buffer to prevent stray keystrokes from auto-answering
read -t 0.1 -n 10000 discard 2>/dev/null || true
read -p "Use standard port 443? [Y/n] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
USE_PORT_443="true" USE_PORT_443="true"
echo ""
echo -e " ${GREEN}${NC} Port 443 will be configured"
sleep 1
fi fi
fi fi
@@ -129,72 +84,57 @@ fi
# Step 3: Channel Key Configuration # Step 3: Channel Key Configuration
# ============================================================================= # =============================================================================
clear if whiptail --title "Step 3 of 3: Channel Key" --yesno "\
echo -e "${BOLD}Step 3 of 3: Channel Key Configuration${NC}" A channel key creates a private encoding channel.
echo -e "${BLUE}-------------------------------------------------------${NC}"
echo ""
echo "A channel key creates a private encoding channel."
echo ""
echo -e " ${BOLD}Without a key:${NC} Anyone with Stegasoo can decode your images"
echo -e " ${BOLD}With a key:${NC} Only people with YOUR key can decode your images"
echo ""
echo "This is useful if you want to share encoded images only with"
echo "specific people (family, team, etc)."
echo ""
echo " [y] Generate a private channel key"
echo " [N] Use public mode (anyone can decode)"
echo ""
# Flush input buffer to prevent stray keystrokes from auto-answering
read -t 0.1 -n 10000 discard 2>/dev/null || true
read -p "Generate a private channel key? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo ""
echo "Generating channel key..."
# Source the venv and generate key WITHOUT a key: Anyone with Stegasoo can decode your images
WITH a key: Only people with YOUR key can decode
This is useful if you want to share encoded images only with specific people (family, team, etc).
Generate a private channel key?" $BOX_HEIGHT $BOX_WIDTH --defaultno; then
# Generate key (use temp file to preserve across subshell)
KEY_FILE=$(mktemp)
{
echo 50
source "$INSTALL_DIR/venv/bin/activate" 2>/dev/null source "$INSTALL_DIR/venv/bin/activate" 2>/dev/null
CHANNEL_KEY=$(python -c "from stegasoo.channel import generate_channel_key; print(generate_channel_key())" 2>/dev/null) python -c "from stegasoo.channel import generate_channel_key; print(generate_channel_key())" > "$KEY_FILE" 2>/dev/null
echo 100
} | whiptail --title "Generating Key" --gauge "Generating channel key..." 6 50 0
CHANNEL_KEY=$(cat "$KEY_FILE" 2>/dev/null)
rm -f "$KEY_FILE"
if [ -n "$CHANNEL_KEY" ]; then if [ -n "$CHANNEL_KEY" ]; then
echo "" whiptail --title "Channel Key Generated" --msgbox "\
echo -e " ${GREEN}${NC} Channel key generated!" Your private channel key:
echo ""
echo -e " ${BOLD}${YELLOW}$CHANNEL_KEY${NC}" $CHANNEL_KEY
echo ""
echo -e " ${RED}*** IMPORTANT: Write down or copy this key NOW! ***${NC}" *** IMPORTANT: Write down or copy this key NOW! ***
echo -e " ${RED}You'll need to share it with anyone who should decode${NC}"
echo -e " ${RED}your images. This key won't be shown again.${NC}" You'll need to share it with anyone who should decode your images. This key won't be shown again after you press OK." $BOX_HEIGHT $BOX_WIDTH
echo ""
# Flush input buffer before waiting
read -t 0.1 -n 10000 discard 2>/dev/null || true
sleep 0.3
read -p "Press Enter when you've saved the key..."
else else
echo -e " ${RED}${NC} Failed to generate key. Using public mode." whiptail --title "Error" --msgbox "Failed to generate channel key. Using public mode." 8 50
CHANNEL_KEY="" CHANNEL_KEY=""
fi fi
else
echo ""
echo -e " ${YELLOW}${NC} Using public mode"
sleep 1
fi fi
# ============================================================================= # =============================================================================
# Apply Configuration # Apply Configuration
# ============================================================================= # =============================================================================
clear {
echo -e "${BOLD}Applying Configuration...${NC}" echo 10
echo -e "${BLUE}-------------------------------------------------------${NC}" echo "XXX"
echo "" echo "Updating systemd service..."
echo "XXX"
# Find the stegasoo user (whoever owns the install dir) # Find the stegasoo user (whoever owns the install dir)
STEGASOO_USER=$(stat -c '%U' "$INSTALL_DIR" 2>/dev/null || echo "pi") STEGASOO_USER=$(stat -c '%U' "$INSTALL_DIR" 2>/dev/null || echo "pi")
echo " Updating systemd service..." sudo tee /etc/systemd/system/stegasoo.service >/dev/null <<EOF
sudo tee /etc/systemd/system/stegasoo.service >/dev/null <<EOF
[Unit] [Unit]
Description=Stegasoo Web UI Description=Stegasoo Web UI
After=network.target After=network.target
@@ -216,24 +156,23 @@ RestartSec=5
WantedBy=multi-user.target WantedBy=multi-user.target
EOF EOF
echo -e " ${GREEN}${NC} Service configured" echo 30
# Setup port 443 if requested # Setup port 443 if requested
if [ "$USE_PORT_443" = "true" ]; then if [ "$USE_PORT_443" = "true" ]; then
echo " Setting up port 443 redirect..." echo "XXX"
echo "Setting up port 443 redirect..."
echo "XXX"
# Install iptables if needed
if ! command -v iptables &>/dev/null; then if ! command -v iptables &>/dev/null; then
sudo apt-get install -y iptables >/dev/null 2>&1 sudo apt-get install -y iptables >/dev/null 2>&1
fi fi
# Add redirect rule (check if it already exists)
if ! sudo iptables -t nat -C PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 5000 2>/dev/null; then if ! sudo iptables -t nat -C PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 5000 2>/dev/null; then
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 5000 sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 5000
fi fi
sudo sh -c 'iptables-save > /etc/iptables.rules' sudo sh -c 'iptables-save > /etc/iptables.rules'
# Create/update persistence service
sudo tee /etc/systemd/system/iptables-restore.service >/dev/null <<EOF sudo tee /etc/systemd/system/iptables-restore.service >/dev/null <<EOF
[Unit] [Unit]
Description=Restore iptables rules Description=Restore iptables rules
@@ -247,85 +186,95 @@ ExecStart=/sbin/iptables-restore /etc/iptables.rules
WantedBy=multi-user.target WantedBy=multi-user.target
EOF EOF
sudo systemctl enable iptables-restore.service >/dev/null 2>&1 sudo systemctl enable iptables-restore.service >/dev/null 2>&1
echo -e " ${GREEN}${NC} Port 443 redirect configured" fi
fi
echo " Reloading systemd..." echo 50
sudo systemctl daemon-reload echo "XXX"
echo -e " ${GREEN}${NC} Systemd reloaded" echo "Reloading systemd..."
echo "XXX"
sudo systemctl daemon-reload
echo " Starting Stegasoo..." echo 70
sudo systemctl restart stegasoo echo "XXX"
sleep 2 echo "Starting Stegasoo..."
echo "XXX"
sudo systemctl restart stegasoo
sleep 2
if systemctl is-active --quiet stegasoo; then echo 90
echo -e " ${GREEN}${NC} Stegasoo started successfully" echo "XXX"
else echo "Cleaning up wizard..."
echo -e " ${RED}${NC} Failed to start (check: journalctl -u stegasoo)" echo "XXX"
fi sudo rm -f "$FLAG_FILE"
sudo rm -f "$PROFILE_HOOK"
# Remove first-boot flag and profile hook echo 100
echo " Cleaning up first-boot wizard..." } | whiptail --title "Applying Configuration" --gauge "Starting..." 6 50 0
sudo rm -f "$FLAG_FILE"
sudo rm -f "$PROFILE_HOOK"
echo -e " ${GREEN}${NC} Wizard complete"
# ============================================================================= # =============================================================================
# Final Summary # Final Summary
# ============================================================================= # =============================================================================
clear
PI_IP=$(hostname -I | awk '{print $1}') PI_IP=$(hostname -I | awk '{print $1}')
HOSTNAME=$(hostname) HOSTNAME=$(hostname)
echo -e "${GREEN}" # Build the access URL
cat <<'BANNER'
_____ _
/ ____| |
| (___ | |_ ___ __ _ __ _ ___ ___ ___
\___ \| __/ _ \/ _` |/ _` / __|/ _ \ / _ \
____) | || __/ (_| | (_| \__ \ (_) | (_) |
|_____/ \__\___|\__, |\__,_|___/\___/ \___/
__/ |
|___/ Setup Complete!
BANNER
echo -e "${NC}"
echo -e "${BOLD}Your Stegasoo server is ready!${NC}"
echo ""
echo -e "${GREEN}Access URL:${NC}"
if [ "$ENABLE_HTTPS" = "true" ]; then if [ "$ENABLE_HTTPS" = "true" ]; then
if [ "$USE_PORT_443" = "true" ]; then if [ "$USE_PORT_443" = "true" ]; then
echo -e " ${BOLD}${YELLOW}https://$PI_IP${NC}" ACCESS_URL="https://$PI_IP"
echo -e " ${BOLD}${YELLOW}https://$HOSTNAME.local${NC} (if mDNS works)" ACCESS_URL_LOCAL="https://$HOSTNAME.local"
else else
echo -e " ${BOLD}${YELLOW}https://$PI_IP:5000${NC}" ACCESS_URL="https://$PI_IP:5000"
echo -e " ${BOLD}${YELLOW}https://$HOSTNAME.local:5000${NC} (if mDNS works)" ACCESS_URL_LOCAL="https://$HOSTNAME.local:5000"
fi fi
else else
echo -e " ${BOLD}${YELLOW}http://$PI_IP:5000${NC}" ACCESS_URL="http://$PI_IP:5000"
ACCESS_URL_LOCAL="http://$HOSTNAME.local:5000"
fi fi
echo ""
# Build channel key message
CHANNEL_MSG=""
if [ -n "$CHANNEL_KEY" ]; then if [ -n "$CHANNEL_KEY" ]; then
echo -e "${GREEN}Channel Key:${NC}" CHANNEL_MSG="
echo -e " ${YELLOW}$CHANNEL_KEY${NC}" Channel Key: $CHANNEL_KEY"
echo ""
fi fi
echo -e "${GREEN}First Steps:${NC}" # Check if service started
echo " 1. Open the URL above in your browser" if systemctl is-active --quiet stegasoo; then
echo " 2. Accept the security warning (self-signed cert)" SERVICE_STATUS="Running"
echo " 3. Create your admin account" else
echo " 4. Start encoding secret messages!" SERVICE_STATUS="Failed to start (check: journalctl -u stegasoo)"
echo "" fi
echo -e "${GREEN}Useful Commands:${NC}" whiptail --title "Setup Complete!" --msgbox "\
echo " sudo systemctl status stegasoo # Check status" Your Stegasoo server is ready!
echo " sudo systemctl restart stegasoo # Restart"
echo " journalctl -u stegasoo -f # View logs"
echo ""
echo -e "${CYAN}Enjoy Stegasoo!${NC}" Access URL:
$ACCESS_URL
$ACCESS_URL_LOCAL (if mDNS works)
Service Status: $SERVICE_STATUS
$CHANNEL_MSG
First Steps:
1. Open the URL above in your browser
2. Accept the security warning (self-signed cert)
3. Create your admin account
4. Start encoding secret messages!
Useful Commands:
sudo systemctl status stegasoo # Check status
sudo systemctl restart stegasoo # Restart
journalctl -u stegasoo -f # View logs
Enjoy Stegasoo!" $((BOX_HEIGHT + 4)) $BOX_WIDTH
clear
echo ""
echo "Stegasoo setup complete!"
echo ""
echo "Access your server at: $ACCESS_URL"
if [ -n "$CHANNEL_KEY" ]; then
echo "Channel Key: $CHANNEL_KEY"
fi
echo "" echo ""