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
# After completion, it removes itself to prevent re-running
#
# 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'
# Uses whiptail for reliable TUI dialogs (pre-installed on Pi OS)
#
# Configuration
INSTALL_DIR="/opt/stegasoo"
FLAG_FILE="/etc/stegasoo-first-boot"
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
if [ ! -f "$FLAG_FILE" ]; then
exit 0
fi
clear
# =============================================================================
# Welcome
# =============================================================================
echo ""
echo -e "${GRAY} . · . · . · . · . · . · . · . · . · . · . · . · . · . · . · . · .${NC}"
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 ""
whiptail --title "Stegasoo First Boot Wizard" --msgbox "\
Welcome to Stegasoo!
echo -e "${BOLD}Welcome to Stegasoo!${NC}"
echo ""
echo "This wizard will help you configure your Stegasoo server."
echo "You can reconfigure later by editing /etc/systemd/system/stegasoo.service"
echo ""
echo -e "${YELLOW}Press Enter to begin setup...${NC}"
read
This wizard will help you configure your Stegasoo server.
You can reconfigure later by editing:
/etc/systemd/system/stegasoo.service
Press OK to begin setup..." $BOX_HEIGHT $BOX_WIDTH
# =============================================================================
# Configuration Variables
@@ -69,28 +53,13 @@ CHANNEL_KEY=""
# Step 1: HTTPS Configuration
# =============================================================================
clear
echo -e "${BOLD}Step 1 of 3: HTTPS Configuration${NC}"
echo -e "${BLUE}-------------------------------------------------------${NC}"
echo ""
echo "HTTPS encrypts all traffic between your browser and this server"
echo "using a self-signed certificate."
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
if whiptail --title "Step 1 of 3: HTTPS Configuration" --yesno "\
HTTPS encrypts all traffic between your browser and this server using a self-signed certificate.
NOTE: Your browser will show a security warning because the certificate is self-signed. This is normal for home networks.
Enable HTTPS? (Recommended)" $BOX_HEIGHT $BOX_WIDTH; then
ENABLE_HTTPS="true"
echo ""
echo -e " ${GREEN}${NC} HTTPS will be enabled"
sleep 1
fi
# =============================================================================
@@ -98,30 +67,16 @@ fi
# =============================================================================
if [ "$ENABLE_HTTPS" = "true" ]; then
clear
echo -e "${BOLD}Step 2 of 3: Port Configuration${NC}"
echo -e "${BLUE}-------------------------------------------------------${NC}"
echo ""
echo "The standard HTTPS port is 443, which means you can access"
echo "Stegasoo without specifying a port in the URL."
echo ""
echo " Port 443: https://stegasoo.local"
echo " Port 5000: https://stegasoo.local:5000"
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
if whiptail --title "Step 2 of 3: Port Configuration" --yesno "\
The standard HTTPS port is 443, which means you can access Stegasoo without specifying a port in the URL.
Port 443: https://stegasoo.local
Port 5000: https://stegasoo.local:5000
NOTE: Port 443 requires an iptables redirect rule.
Use standard port 443? (Cleaner URLs)" $BOX_HEIGHT $BOX_WIDTH; then
USE_PORT_443="true"
echo ""
echo -e " ${GREEN}${NC} Port 443 will be configured"
sleep 1
fi
fi
@@ -129,72 +84,57 @@ fi
# Step 3: Channel Key Configuration
# =============================================================================
clear
echo -e "${BOLD}Step 3 of 3: Channel Key Configuration${NC}"
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..."
if whiptail --title "Step 3 of 3: Channel Key" --yesno "\
A channel key creates a private encoding channel.
# 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
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
echo ""
echo -e " ${GREEN}${NC} Channel key generated!"
echo ""
echo -e " ${BOLD}${YELLOW}$CHANNEL_KEY${NC}"
echo ""
echo -e " ${RED}*** IMPORTANT: Write down or copy this key NOW! ***${NC}"
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}"
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..."
whiptail --title "Channel Key Generated" --msgbox "\
Your private channel key:
$CHANNEL_KEY
*** IMPORTANT: Write down or copy this key NOW! ***
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
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=""
fi
else
echo ""
echo -e " ${YELLOW}${NC} Using public mode"
sleep 1
fi
# =============================================================================
# Apply Configuration
# =============================================================================
clear
echo -e "${BOLD}Applying Configuration...${NC}"
echo -e "${BLUE}-------------------------------------------------------${NC}"
echo ""
{
echo 10
echo "XXX"
echo "Updating systemd service..."
echo "XXX"
# Find the stegasoo user (whoever owns the install dir)
STEGASOO_USER=$(stat -c '%U' "$INSTALL_DIR" 2>/dev/null || echo "pi")
# Find the stegasoo user (whoever owns the install dir)
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]
Description=Stegasoo Web UI
After=network.target
@@ -216,24 +156,23 @@ RestartSec=5
WantedBy=multi-user.target
EOF
echo -e " ${GREEN}${NC} Service configured"
echo 30
# Setup port 443 if requested
if [ "$USE_PORT_443" = "true" ]; then
echo " Setting up port 443 redirect..."
# Setup port 443 if requested
if [ "$USE_PORT_443" = "true" ]; then
echo "XXX"
echo "Setting up port 443 redirect..."
echo "XXX"
# Install iptables if needed
if ! command -v iptables &>/dev/null; then
sudo apt-get install -y iptables >/dev/null 2>&1
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
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 5000
fi
sudo sh -c 'iptables-save > /etc/iptables.rules'
# Create/update persistence service
sudo tee /etc/systemd/system/iptables-restore.service >/dev/null <<EOF
[Unit]
Description=Restore iptables rules
@@ -247,85 +186,95 @@ ExecStart=/sbin/iptables-restore /etc/iptables.rules
WantedBy=multi-user.target
EOF
sudo systemctl enable iptables-restore.service >/dev/null 2>&1
echo -e " ${GREEN}${NC} Port 443 redirect configured"
fi
fi
echo " Reloading systemd..."
sudo systemctl daemon-reload
echo -e " ${GREEN}${NC} Systemd reloaded"
echo 50
echo "XXX"
echo "Reloading systemd..."
echo "XXX"
sudo systemctl daemon-reload
echo " Starting Stegasoo..."
sudo systemctl restart stegasoo
sleep 2
echo 70
echo "XXX"
echo "Starting Stegasoo..."
echo "XXX"
sudo systemctl restart stegasoo
sleep 2
if systemctl is-active --quiet stegasoo; then
echo -e " ${GREEN}${NC} Stegasoo started successfully"
else
echo -e " ${RED}${NC} Failed to start (check: journalctl -u stegasoo)"
fi
echo 90
echo "XXX"
echo "Cleaning up wizard..."
echo "XXX"
sudo rm -f "$FLAG_FILE"
sudo rm -f "$PROFILE_HOOK"
# Remove first-boot flag and profile hook
echo " Cleaning up first-boot wizard..."
sudo rm -f "$FLAG_FILE"
sudo rm -f "$PROFILE_HOOK"
echo -e " ${GREEN}${NC} Wizard complete"
echo 100
} | whiptail --title "Applying Configuration" --gauge "Starting..." 6 50 0
# =============================================================================
# Final Summary
# =============================================================================
clear
PI_IP=$(hostname -I | awk '{print $1}')
HOSTNAME=$(hostname)
echo -e "${GREEN}"
cat <<'BANNER'
_____ _
/ ____| |
| (___ | |_ ___ __ _ __ _ ___ ___ ___
\___ \| __/ _ \/ _` |/ _` / __|/ _ \ / _ \
____) | || __/ (_| | (_| \__ \ (_) | (_) |
|_____/ \__\___|\__, |\__,_|___/\___/ \___/
__/ |
|___/ Setup Complete!
BANNER
echo -e "${NC}"
echo -e "${BOLD}Your Stegasoo server is ready!${NC}"
echo ""
echo -e "${GREEN}Access URL:${NC}"
# Build the access URL
if [ "$ENABLE_HTTPS" = "true" ]; then
if [ "$USE_PORT_443" = "true" ]; then
echo -e " ${BOLD}${YELLOW}https://$PI_IP${NC}"
echo -e " ${BOLD}${YELLOW}https://$HOSTNAME.local${NC} (if mDNS works)"
ACCESS_URL="https://$PI_IP"
ACCESS_URL_LOCAL="https://$HOSTNAME.local"
else
echo -e " ${BOLD}${YELLOW}https://$PI_IP:5000${NC}"
echo -e " ${BOLD}${YELLOW}https://$HOSTNAME.local:5000${NC} (if mDNS works)"
ACCESS_URL="https://$PI_IP:5000"
ACCESS_URL_LOCAL="https://$HOSTNAME.local:5000"
fi
else
echo -e " ${BOLD}${YELLOW}http://$PI_IP:5000${NC}"
ACCESS_URL="http://$PI_IP:5000"
ACCESS_URL_LOCAL="http://$HOSTNAME.local:5000"
fi
echo ""
# Build channel key message
CHANNEL_MSG=""
if [ -n "$CHANNEL_KEY" ]; then
echo -e "${GREEN}Channel Key:${NC}"
echo -e " ${YELLOW}$CHANNEL_KEY${NC}"
echo ""
CHANNEL_MSG="
Channel Key: $CHANNEL_KEY"
fi
echo -e "${GREEN}First Steps:${NC}"
echo " 1. Open the URL above in your browser"
echo " 2. Accept the security warning (self-signed cert)"
echo " 3. Create your admin account"
echo " 4. Start encoding secret messages!"
echo ""
# Check if service started
if systemctl is-active --quiet stegasoo; then
SERVICE_STATUS="Running"
else
SERVICE_STATUS="Failed to start (check: journalctl -u stegasoo)"
fi
echo -e "${GREEN}Useful Commands:${NC}"
echo " sudo systemctl status stegasoo # Check status"
echo " sudo systemctl restart stegasoo # Restart"
echo " journalctl -u stegasoo -f # View logs"
echo ""
whiptail --title "Setup Complete!" --msgbox "\
Your Stegasoo server is ready!
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 ""