4.1.4: QR sharing, venv tarball, flash script improvements

QR Channel Key Sharing:
- Admin-only QR generator in about.html (was visible to all)
- QR button for saved keys on account page
- Fixed about() route missing channel status vars (bug)

Pi Build Optimization:
- Pre-built venv tarball support (39MB zstd, skips 20+ min compile)
- setup.sh auto-detects and extracts tarball if present
- Strip __pycache__/tests before tarball (295MB → 208MB)

Flash Script Improvements:
- flash-image.sh now uses config.json for headless WiFi setup
- Consistent wipe prompt on both flash scripts
- pull-image.sh re-enables auto-expand before shrinking

Build Docs:
- Added zstd and jq to pre-setup apt-get
- Documented fast build option with pre-built venv

🤖 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-06 15:03:46 -05:00
parent cc46993d80
commit d58f3c6fb6
9 changed files with 513 additions and 48 deletions

View File

@@ -8,9 +8,14 @@
# Supports: .img, .img.zst, .img.xz, .img.gz, .img.zst.zip (GitHub release format)
# If device is specified, skips auto-detection (useful for NVMe/large drives)
#
# Optional: Place config.json in same directory for headless WiFi setup
#
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="$SCRIPT_DIR/config.json"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
@@ -18,6 +23,28 @@ BLUE='\033[0;34m'
BOLD='\033[1m'
NC='\033[0m'
# Load config if present (optional - for headless WiFi setup)
HAS_CONFIG=false
if [ -f "$CONFIG_FILE" ] && command -v jq &> /dev/null; then
WIFI_SSID=$(jq -r '.wifiSSID // empty' "$CONFIG_FILE")
WIFI_PASS=$(jq -r '.wifiPassword // empty' "$CONFIG_FILE")
WIFI_COUNTRY=$(jq -r '.wifiCountry // "US"' "$CONFIG_FILE")
PI_HOSTNAME=$(jq -r '.hostname // empty' "$CONFIG_FILE")
if [ -n "$WIFI_SSID" ] && [ -n "$WIFI_PASS" ]; then
HAS_CONFIG=true
echo -e "${GREEN}Found config.json - will configure WiFi after flash${NC}"
echo -e " WiFi: ${YELLOW}$WIFI_SSID${NC}"
if [ -n "$PI_HOSTNAME" ]; then
echo -e " Hostname: ${YELLOW}$PI_HOSTNAME${NC}"
fi
echo ""
fi
elif [ -f "$CONFIG_FILE" ]; then
echo -e "${YELLOW}Note: config.json found but jq not installed (apt install jq)${NC}"
echo -e "${YELLOW} WiFi will need to be configured manually after boot${NC}"
echo ""
fi
# Check for required tools
for cmd in dd lsblk; do
if ! command -v $cmd &> /dev/null; then
@@ -222,6 +249,17 @@ if [ -n "$MOUNTED" ]; then
done
fi
# Ask about wiping
echo
read -p "Wipe partition table first? (recommended if having issues) [y/N] " wipe_confirm
if [[ "$wipe_confirm" =~ ^[Yy]$ ]]; then
echo "Wiping partition table..."
sudo wipefs -a "$SELECTED"
sudo dd if=/dev/zero of="$SELECTED" bs=1M count=10 status=none
sync
echo " Wiped clean"
fi
# Final confirmation
echo -e "${RED}╔═══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${RED}║ WARNING: ALL DATA ON THIS DEVICE WILL BE DESTROYED! ║${NC}"
@@ -284,6 +322,109 @@ echo ""
echo -e "${GREEN}Syncing...${NC}"
sync
# Inject WiFi config if config.json was loaded
if [ "$HAS_CONFIG" = true ]; then
echo ""
echo -e "${GREEN}Configuring WiFi from config.json...${NC}"
# Wait for partitions to appear
sleep 2
partprobe "$SELECTED" 2>/dev/null || true
sleep 1
# Determine boot partition
if [[ "$SELECTED" == *"nvme"* ]] || [[ "$SELECTED" == *"mmcblk"* ]]; then
BOOT_PART="${SELECTED}p1"
else
BOOT_PART="${SELECTED}1"
fi
if [ -b "$BOOT_PART" ]; then
MOUNT_DIR=$(mktemp -d)
if mount "$BOOT_PART" "$MOUNT_DIR" 2>/dev/null; then
# Create firstrun.sh for WiFi setup
cat > "$MOUNT_DIR/firstrun.sh" << 'EOFSCRIPT'
#!/bin/bash
set +e
# Set hostname if provided
if [ -n "PLACEHOLDER_HOSTNAME" ] && [ "PLACEHOLDER_HOSTNAME" != "" ]; then
CURRENT_HOSTNAME=$(cat /etc/hostname | tr -d " \t\n\r")
if [ -f /usr/lib/raspberrypi-sys-mods/imager_custom ]; then
/usr/lib/raspberrypi-sys-mods/imager_custom set_hostname PLACEHOLDER_HOSTNAME
else
echo PLACEHOLDER_HOSTNAME >/etc/hostname
sed -i "s/127.0.1.1.*$CURRENT_HOSTNAME/127.0.1.1\tPLACEHOLDER_HOSTNAME/g" /etc/hosts
fi
fi
# Configure WiFi
if [ -f /usr/lib/raspberrypi-sys-mods/imager_custom ]; then
/usr/lib/raspberrypi-sys-mods/imager_custom set_wlan 'PLACEHOLDER_SSID' 'PLACEHOLDER_WIFIPASS' 'PLACEHOLDER_COUNTRY'
else
# NetworkManager method (Trixie)
cat >/etc/NetworkManager/system-connections/preconfigured.nmconnection <<'NMEOF'
[connection]
id=preconfigured
type=wifi
autoconnect=true
[wifi]
mode=infrastructure
ssid=PLACEHOLDER_SSID
[wifi-security]
auth-alg=open
key-mgmt=wpa-psk
psk=PLACEHOLDER_WIFIPASS
[ipv4]
method=auto
[ipv6]
method=auto
NMEOF
chmod 600 /etc/NetworkManager/system-connections/preconfigured.nmconnection
rfkill unblock wifi
fi
# Cleanup
rm -f /boot/firstrun.sh
rm -f /boot/firmware/firstrun.sh
sed -i 's| systemd.run.*||g' /boot/cmdline.txt 2>/dev/null
sed -i 's| systemd.run.*||g' /boot/firmware/cmdline.txt 2>/dev/null
exit 0
EOFSCRIPT
# Replace placeholders
sed -i "s/PLACEHOLDER_SSID/$WIFI_SSID/g" "$MOUNT_DIR/firstrun.sh"
sed -i "s/PLACEHOLDER_WIFIPASS/$WIFI_PASS/g" "$MOUNT_DIR/firstrun.sh"
sed -i "s/PLACEHOLDER_COUNTRY/$WIFI_COUNTRY/g" "$MOUNT_DIR/firstrun.sh"
if [ -n "$PI_HOSTNAME" ]; then
sed -i "s/PLACEHOLDER_HOSTNAME/$PI_HOSTNAME/g" "$MOUNT_DIR/firstrun.sh"
else
sed -i "s/PLACEHOLDER_HOSTNAME//g" "$MOUNT_DIR/firstrun.sh"
fi
chmod +x "$MOUNT_DIR/firstrun.sh"
# Update cmdline.txt to run firstrun.sh
CMDLINE="$MOUNT_DIR/cmdline.txt"
if [ -f "$CMDLINE" ]; then
CURRENT=$(cat "$CMDLINE" | tr -d '\n' | sed 's| systemd.run.*||g')
echo "$CURRENT systemd.run=/boot/firmware/firstrun.sh systemd.run_success_action=reboot systemd.unit=kernel-command-line.target" > "$CMDLINE"
fi
umount "$MOUNT_DIR"
echo -e " ${GREEN}${NC} WiFi configured for: $WIFI_SSID"
else
echo -e " ${YELLOW}${NC} Could not mount boot partition"
fi
rmdir "$MOUNT_DIR" 2>/dev/null || true
else
echo -e " ${YELLOW}${NC} Boot partition not found"
fi
fi
echo ""
echo -e "${GREEN}╔═══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ Flash Complete! ║${NC}"
@@ -291,5 +432,11 @@ echo -e "${GREEN}╚════════════════════
echo ""
echo -e "You can now remove the SD card and boot your Raspberry Pi."
echo ""
echo -e "${YELLOW}Tip:${NC} On first boot, SSH in and the setup wizard will run automatically."
if [ "$HAS_CONFIG" = true ]; then
echo -e "${GREEN}WiFi pre-configured${NC} - Pi will connect to $WIFI_SSID on boot"
echo -e "SSH: ${YELLOW}ssh admin@${PI_HOSTNAME:-stegasoo}.local${NC} (password: stegasoo)"
else
echo -e "${YELLOW}Tip:${NC} On first boot, the setup wizard will help configure WiFi."
echo -e "${YELLOW}Tip:${NC} Or place config.json in rpi/ for headless setup next time."
fi
echo ""