Rewrite first-boot wizard using gum TUI

Replace whiptail with gum (Charm.sh) for beautiful, modern TUI.
Features spinners, styled boxes, colored text, and reliable prompts.

🤖 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:16:57 -05:00
parent 419b491737
commit 00dd15b8fb

View File

@@ -6,7 +6,8 @@
# 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) # Uses gum (Charm.sh) for beautiful TUI - install with:
# sudo apt install gum OR go install github.com/charmbracelet/gum@latest
# #
# Configuration # Configuration
@@ -14,32 +15,39 @@ 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
# Check for gum, fall back to basic prompts if not available
if ! command -v gum &>/dev/null; then
echo "Error: gum not found. Install with: sudo apt install gum"
exit 1
fi
clear
# ============================================================================= # =============================================================================
# Welcome # Welcome
# ============================================================================= # =============================================================================
whiptail --title "Stegasoo First Boot Wizard" --msgbox "\ gum style \
Welcome to Stegasoo! --border double \
--border-foreground 212 \
--padding "1 2" \
--margin "1" \
--align center \
"🦕 STEGASOO" \
"" \
"First Boot Wizard"
This wizard will help you configure your Stegasoo server. echo ""
gum style --foreground 245 "This wizard will help you configure your Stegasoo server."
gum style --foreground 245 "You can reconfigure later by editing /etc/systemd/system/stegasoo.service"
echo ""
You can reconfigure later by editing: gum confirm "Ready to begin setup?" || exit 0
/etc/systemd/system/stegasoo.service
Press OK to begin setup..." $BOX_HEIGHT $BOX_WIDTH
# ============================================================================= # =============================================================================
# Configuration Variables # Configuration Variables
@@ -53,88 +61,126 @@ CHANNEL_KEY=""
# Step 1: HTTPS Configuration # Step 1: HTTPS Configuration
# ============================================================================= # =============================================================================
if whiptail --title "Step 1 of 3: HTTPS Configuration" --yesno "\ clear
HTTPS encrypts all traffic between your browser and this server using a self-signed certificate. gum style \
--foreground 212 --bold \
"Step 1 of 3: HTTPS Configuration"
echo ""
NOTE: Your browser will show a security warning because the certificate is self-signed. This is normal for home networks. gum style --foreground 245 "\
HTTPS encrypts all traffic between your browser and this server
using a self-signed certificate.
Enable HTTPS? (Recommended)" $BOX_HEIGHT $BOX_WIDTH; then NOTE: Your browser will show a security warning because the
certificate is self-signed. This is normal for home networks."
echo ""
if gum confirm "Enable HTTPS?" --default=true; then
ENABLE_HTTPS="true" ENABLE_HTTPS="true"
gum style --foreground 82 "✓ HTTPS will be enabled"
else
gum style --foreground 214 "→ Using HTTP (unencrypted)"
fi fi
sleep 0.5
# ============================================================================= # =============================================================================
# Step 2: Port Configuration (only if HTTPS) # Step 2: Port Configuration (only if HTTPS)
# ============================================================================= # =============================================================================
if [ "$ENABLE_HTTPS" = "true" ]; then if [ "$ENABLE_HTTPS" = "true" ]; then
if whiptail --title "Step 2 of 3: Port Configuration" --yesno "\ clear
The standard HTTPS port is 443, which means you can access Stegasoo without specifying a port in the URL. gum style \
--foreground 212 --bold \
"Step 2 of 3: Port Configuration"
echo ""
gum style --foreground 245 "\
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 443: https://stegasoo.local
Port 5000: https://stegasoo.local:5000 Port 5000: https://stegasoo.local:5000
NOTE: Port 443 requires an iptables redirect rule. NOTE: Port 443 requires an iptables redirect rule."
echo ""
Use standard port 443? (Cleaner URLs)" $BOX_HEIGHT $BOX_WIDTH; then if gum confirm "Use standard port 443?" --default=true; then
USE_PORT_443="true" USE_PORT_443="true"
gum style --foreground 82 "✓ Port 443 will be configured"
else
gum style --foreground 214 "→ Using port 5000"
fi fi
sleep 0.5
fi fi
# ============================================================================= # =============================================================================
# Step 3: Channel Key Configuration # Step 3: Channel Key Configuration
# ============================================================================= # =============================================================================
if whiptail --title "Step 3 of 3: Channel Key" --yesno "\ clear
gum style \
--foreground 212 --bold \
"Step 3 of 3: Channel Key Configuration"
echo ""
gum style --foreground 245 "\
A channel key creates a private encoding channel. A channel key creates a private encoding channel.
WITHOUT a key: Anyone with Stegasoo can decode your images WITHOUT a key: Anyone with Stegasoo can decode your images
WITH a key: Only people with YOUR key can decode 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). This is useful if you want to share encoded images only with
specific people (family, team, etc)."
echo ""
Generate a private channel key?" $BOX_HEIGHT $BOX_WIDTH --defaultno; then if gum confirm "Generate a private channel key?" --default=false; then
echo ""
# Generate key (use temp file to preserve across subshell) CHANNEL_KEY=$(gum spin --spinner dot --title "Generating channel key..." -- \
KEY_FILE=$(mktemp) bash -c "source '$INSTALL_DIR/venv/bin/activate' 2>/dev/null && python -c \"from stegasoo.channel import generate_channel_key; print(generate_channel_key())\"")
{
echo 50
source "$INSTALL_DIR/venv/bin/activate" 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
whiptail --title "Channel Key Generated" --msgbox "\ echo ""
Your private channel key: gum style --foreground 82 "✓ Channel key generated!"
echo ""
$CHANNEL_KEY gum style \
--border rounded \
*** IMPORTANT: Write down or copy this key NOW! *** --border-foreground 226 \
--padding "1 2" \
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 --foreground 226 --bold \
"$CHANNEL_KEY"
echo ""
gum style --foreground 196 --bold \
"*** IMPORTANT: Write down or copy this key NOW! ***"
gum style --foreground 196 \
"You'll need to share it with anyone who should decode" \
"your images. This key won't be shown again."
echo ""
gum confirm "I've saved the key" --default=true --affirmative="Continue" --negative=""
else else
whiptail --title "Error" --msgbox "Failed to generate channel key. Using public mode." 8 50 gum style --foreground 196 "Failed to generate key. Using public mode."
CHANNEL_KEY="" CHANNEL_KEY=""
sleep 1
fi fi
else
gum style --foreground 214 "→ Using public mode"
sleep 0.5
fi fi
# ============================================================================= # =============================================================================
# Apply Configuration # Apply Configuration
# ============================================================================= # =============================================================================
{ clear
echo 10 gum style \
echo "XXX" --foreground 212 --bold \
echo "Updating systemd service..." "Applying Configuration..."
echo "XXX" echo ""
# 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")
sudo tee /etc/systemd/system/stegasoo.service >/dev/null <<EOF gum spin --spinner dot --title "Updating systemd service..." -- bash -c "
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
@@ -143,11 +189,11 @@ After=network.target
Type=simple Type=simple
User=$STEGASOO_USER User=$STEGASOO_USER
WorkingDirectory=$INSTALL_DIR/frontends/web WorkingDirectory=$INSTALL_DIR/frontends/web
Environment="PATH=$INSTALL_DIR/venv/bin:/usr/bin" Environment=\"PATH=$INSTALL_DIR/venv/bin:/usr/bin\"
Environment="STEGASOO_AUTH_ENABLED=true" Environment=\"STEGASOO_AUTH_ENABLED=true\"
Environment="STEGASOO_HTTPS_ENABLED=$ENABLE_HTTPS" Environment=\"STEGASOO_HTTPS_ENABLED=$ENABLE_HTTPS\"
Environment="STEGASOO_PORT=5000" Environment=\"STEGASOO_PORT=5000\"
Environment="STEGASOO_CHANNEL_KEY=$CHANNEL_KEY" Environment=\"STEGASOO_CHANNEL_KEY=$CHANNEL_KEY\"
ExecStart=$INSTALL_DIR/venv/bin/python app.py ExecStart=$INSTALL_DIR/venv/bin/python app.py
Restart=on-failure Restart=on-failure
RestartSec=5 RestartSec=5
@@ -155,24 +201,19 @@ RestartSec=5
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
EOF EOF
"
gum style --foreground 82 "✓ Service configured"
echo 30 # Setup port 443 if requested
if [ "$USE_PORT_443" = "true" ]; then
# Setup port 443 if requested gum spin --spinner dot --title "Setting up port 443 redirect..." -- bash -c "
if [ "$USE_PORT_443" = "true" ]; then
echo "XXX"
echo "Setting up port 443 redirect..."
echo "XXX"
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
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'
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
@@ -186,35 +227,35 @@ 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
fi "
gum style --foreground 82 "✓ Port 443 redirect configured"
fi
echo 50 gum spin --spinner dot --title "Reloading systemd..." -- sudo systemctl daemon-reload
echo "XXX" gum style --foreground 82 "✓ Systemd reloaded"
echo "Reloading systemd..."
echo "XXX"
sudo systemctl daemon-reload
echo 70 gum spin --spinner dot --title "Starting Stegasoo..." -- bash -c "sudo systemctl restart stegasoo && sleep 2"
echo "XXX"
echo "Starting Stegasoo..."
echo "XXX"
sudo systemctl restart stegasoo
sleep 2
echo 90 if systemctl is-active --quiet stegasoo; then
echo "XXX" gum style --foreground 82 "✓ Stegasoo started successfully"
echo "Cleaning up wizard..." else
echo "XXX" gum style --foreground 196 "✗ Failed to start (check: journalctl -u stegasoo)"
sudo rm -f "$FLAG_FILE" fi
sudo rm -f "$PROFILE_HOOK"
echo 100 gum spin --spinner dot --title "Cleaning up wizard..." -- bash -c "
} | whiptail --title "Applying Configuration" --gauge "Starting..." 6 50 0 sudo rm -f '$FLAG_FILE'
sudo rm -f '$PROFILE_HOOK'
"
gum style --foreground 82 "✓ Wizard complete"
sleep 1
# ============================================================================= # =============================================================================
# Final Summary # Final Summary
# ============================================================================= # =============================================================================
clear
PI_IP=$(hostname -I | awk '{print $1}') PI_IP=$(hostname -I | awk '{print $1}')
HOSTNAME=$(hostname) HOSTNAME=$(hostname)
@@ -232,49 +273,42 @@ else
ACCESS_URL_LOCAL="http://$HOSTNAME.local:5000" ACCESS_URL_LOCAL="http://$HOSTNAME.local:5000"
fi fi
# Build channel key message gum style \
CHANNEL_MSG="" --border double \
--border-foreground 82 \
--padding "1 2" \
--margin "1" \
--align center \
"🦕 STEGASOO" \
"" \
"Setup Complete!"
echo ""
gum style --foreground 82 --bold "Access URL:"
gum style --foreground 226 " $ACCESS_URL"
gum style --foreground 245 " $ACCESS_URL_LOCAL (if mDNS works)"
echo ""
if [ -n "$CHANNEL_KEY" ]; then if [ -n "$CHANNEL_KEY" ]; then
CHANNEL_MSG=" gum style --foreground 82 --bold "Channel Key:"
Channel Key: $CHANNEL_KEY" gum style --foreground 226 " $CHANNEL_KEY"
echo ""
fi fi
# Check if service started gum style --foreground 82 --bold "First Steps:"
if systemctl is-active --quiet stegasoo; then gum style --foreground 255 \
SERVICE_STATUS="Running" " 1. Open the URL above in your browser" \
else " 2. Accept the security warning (self-signed cert)" \
SERVICE_STATUS="Failed to start (check: journalctl -u stegasoo)" " 3. Create your admin account" \
fi " 4. Start encoding secret messages!"
whiptail --title "Setup Complete!" --msgbox "\
Your Stegasoo server is ready!
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 ""
echo "Stegasoo setup complete!"
gum style --foreground 82 --bold "Useful Commands:"
gum style --foreground 245 \
" sudo systemctl status stegasoo # Check status" \
" sudo systemctl restart stegasoo # Restart" \
" journalctl -u stegasoo -f # View logs"
echo "" echo ""
echo "Access your server at: $ACCESS_URL"
if [ -n "$CHANNEL_KEY" ]; then gum style --foreground 212 --bold "Enjoy Stegasoo! 🦕"
echo "Channel Key: $CHANNEL_KEY"
fi
echo "" echo ""