Files
ESP32_ZACUS/scripts/generate_ui_assets_fs.sh
T
L'électron rare f7bd3bed97 feat: P0/P1 security & stability hardening - WiFi, Bearer token, audio leak, watchdog
SECURITY (P0 CRITICAL):
- Remove hardcoded WiFi credentials from storage_manager.cpp
- Implement Bearer token auth on 40+ REST API endpoints
- New wifi_config API: NVS-backed credential management (UART: WIFI_CONFIG)
- New auth_service API: 32-hex token generation/validation/rotation

STABILITY (P1 HIGH):
- Fix audio memory leak with std::make_unique (playOnChannel locations)
- Add ESP32 Task Watchdog Timer 30s timeout + auto-reboot detection
- Prevents silent hangs, detects infinite loops via UART

FILES MODIFIED:
- storage_manager.cpp: Remove APP_WIFI hardcoded defaults (line 65)
- main.cpp: Integrate auth_service init, validateApiToken middleware, watchdog feed
- audio_manager.cpp: Replace raw new/delete with unique_ptr pattern

FILES CREATED:
- include/core/wifi_config.h/cpp: WiFi NVS + validation API
- include/auth/auth_service.h/cpp: Bearer token service

COMPILATION: SUCCESS (43s, 0 errors, 0 warnings)
MEMORY: RAM 87.5%, Flash 41.1%
CVSS IMPACT: 8.5 → 2.1 (75% risk reduction)
2026-03-11 00:03:57 +01:00

153 lines
6.6 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
DATA_DIR="${ROOT_DIR}/data"
APPS=(
audio_player
camera_video
dictaphone
timer_tools
flashlight
calculator
qr_scanner
audiobook_player
kids_webradio
kids_podcast
kids_drawing
kids_coloring
kids_music
kids_yoga
kids_meditation
kids_languages
kids_math
kids_science
kids_geography
nes_emulator
)
palette_bg=("#0F2A5C" "#2A1E5C" "#1E4A50" "#49331A" "#213059")
palette_ac=("#FFD166" "#FF8ED8" "#7CFFEA" "#8BC6FF" "#FFB870")
mkdir -p "${DATA_DIR}/apps/shared/audio"
mkdir -p "${DATA_DIR}/webui/assets"
mkdir -p "${DATA_DIR}/webui/assets/fonts"
fetch_font() {
local url="$1"
local output="$2"
if [[ -s "${output}" ]]; then
return 0
fi
curl -fsSL "${url}" -o "${output}"
}
fetch_font "https://raw.githubusercontent.com/google/fonts/main/ofl/pressstart2p/PressStart2P-Regular.ttf" \
"${DATA_DIR}/webui/assets/fonts/PressStart2P-Regular.ttf"
fetch_font "https://raw.githubusercontent.com/google/fonts/main/ofl/comicneue/ComicNeue-Regular.ttf" \
"${DATA_DIR}/webui/assets/fonts/ComicNeue-Regular.ttf"
fetch_font "https://raw.githubusercontent.com/google/fonts/main/ofl/comicneue/ComicNeue-Bold.ttf" \
"${DATA_DIR}/webui/assets/fonts/ComicNeue-Bold.ttf"
has_cmd() {
command -v "$1" >/dev/null 2>&1
}
HAS_MAGICK=0
if has_cmd magick; then
HAS_MAGICK=1
fi
# Global UI SFX
sox -n -r 16000 -c 1 "${DATA_DIR}/apps/shared/audio/ui_click.wav" synth 0.07 sine 1300 vol 0.35 fade q 0.001 0.07 0.01
sox -n -r 16000 -c 1 "${DATA_DIR}/apps/shared/audio/ui_back.wav" synth 0.08 sine 760 vol 0.35 fade q 0.001 0.08 0.02
sox -n -r 16000 -c 1 "${DATA_DIR}/apps/shared/audio/ui_success.wav" synth 0.12 sine 980 vol 0.35 fade q 0.001 0.12 0.02
sox -n -r 16000 -c 1 "${DATA_DIR}/apps/shared/audio/ui_error.wav" synth 0.13 sine 240 vol 0.35 fade q 0.001 0.13 0.03
sox -n -r 16000 -c 1 "${DATA_DIR}/apps/shared/audio/app_open.wav" synth 0.10 sine 660 vol 0.35 fade q 0.001 0.10 0.02
# WebUI assets
if [[ "${HAS_MAGICK}" == "1" ]]; then
magick -size 640x220 "xc:#0B1E4A" \
-fill "#FFD166" -draw "roundrectangle 8,8 632,212 28,28" \
-fill "#0B1E4A" -draw "rectangle 24,24 616,196" \
-fill "#6FE7FF" -draw "roundrectangle 56,56 584,164 20,20" \
-fill "#0B1E4A" -draw "rectangle 80,80 560,140" \
-fill "#FFD166" -draw "rectangle 108,90 140,130" \
-fill "#FFD166" -draw "rectangle 156,90 188,130" \
-fill "#FFD166" -draw "rectangle 204,90 236,130" \
-fill "#FFD166" -draw "rectangle 252,90 284,130" \
-fill "#FFD166" -draw "rectangle 300,90 332,130" \
-fill "#FFD166" -draw "rectangle 348,90 380,130" \
-fill "#FFD166" -draw "rectangle 396,90 428,130" \
-fill "#FFD166" -draw "rectangle 444,90 476,130" \
-fill "#FFD166" -draw "rectangle 492,90 524,130" \
"${DATA_DIR}/webui/assets/header.png"
magick -size 96x96 "xc:#172A56" \
-fill "#6FE7FF" -draw "roundrectangle 4,4 92,92 14,14" \
-fill "#172A56" -draw "rectangle 14,14 82,82" \
-fill "#FFD166" -draw "rectangle 24,24 72,36" \
-fill "#FFD166" -draw "rectangle 24,44 72,56" \
-fill "#FFD166" -draw "rectangle 24,64 72,76" \
"${DATA_DIR}/webui/assets/favicon.png"
else
ffmpeg -loglevel error -y -f lavfi -i "color=c=#0B1E4A:s=640x220:d=0.1" \
-vf "drawbox=x=8:y=8:w=624:h=204:color=#FFD166:t=fill,drawbox=x=24:y=24:w=592:h=172:color=#0B1E4A:t=fill,drawbox=x=56:y=56:w=528:h=108:color=#6FE7FF:t=fill,drawbox=x=80:y=80:w=480:h=60:color=#0B1E4A:t=fill,drawbox=x=108:y=90:w=32:h=40:color=#FFD166:t=fill,drawbox=x=156:y=90:w=32:h=40:color=#FFD166:t=fill,drawbox=x=204:y=90:w=32:h=40:color=#FFD166:t=fill,drawbox=x=252:y=90:w=32:h=40:color=#FFD166:t=fill,drawbox=x=300:y=90:w=32:h=40:color=#FFD166:t=fill,drawbox=x=348:y=90:w=32:h=40:color=#FFD166:t=fill,drawbox=x=396:y=90:w=32:h=40:color=#FFD166:t=fill,drawbox=x=444:y=90:w=32:h=40:color=#FFD166:t=fill,drawbox=x=492:y=90:w=32:h=40:color=#FFD166:t=fill" \
-frames:v 1 "${DATA_DIR}/webui/assets/header.png"
ffmpeg -loglevel error -y -f lavfi -i "color=c=#172A56:s=96x96:d=0.1" \
-vf "drawbox=x=4:y=4:w=88:h=88:color=#6FE7FF:t=fill,drawbox=x=14:y=14:w=68:h=68:color=#172A56:t=fill,drawbox=x=24:y=24:w=48:h=12:color=#FFD166:t=fill,drawbox=x=24:y=44:w=48:h=12:color=#FFD166:t=fill,drawbox=x=24:y=64:w=48:h=12:color=#FFD166:t=fill" \
-frames:v 1 "${DATA_DIR}/webui/assets/favicon.png"
fi
sox -n -r 16000 -c 1 "${DATA_DIR}/webui/assets/sfx_click.wav" synth 0.07 sine 1260 vol 0.30 fade q 0.001 0.07 0.01
sox -n -r 16000 -c 1 "${DATA_DIR}/webui/assets/sfx_ok.wav" synth 0.11 sine 960 vol 0.32 fade q 0.001 0.11 0.02
sox -n -r 16000 -c 1 "${DATA_DIR}/webui/assets/sfx_error.wav" synth 0.12 sine 240 vol 0.32 fade q 0.001 0.12 0.02
idx=0
for app in "${APPS[@]}"; do
app_dir="${DATA_DIR}/apps/${app}"
audio_dir="${app_dir}/audio"
content_dir="${app_dir}/content"
cache_dir="${app_dir}/cache"
mkdir -p "${app_dir}" "${audio_dir}" "${content_dir}" "${cache_dir}"
bg="${palette_bg[$((idx % ${#palette_bg[@]}))]}"
ac="${palette_ac[$((idx % ${#palette_ac[@]}))]}"
radius=$((18 + (idx % 12)))
if [[ "${HAS_MAGICK}" == "1" ]]; then
magick -size 96x96 "xc:${bg}" \
-fill "${ac}" -draw "roundrectangle 4,4 92,92 14,14" \
-fill "${bg}" -draw "rectangle 14,14 82,82" \
-fill "${ac}" -draw "circle 48,48 48,$((48 - radius))" \
-fill "${bg}" -draw "circle 48,48 48,$((48 - radius + 8))" \
-fill "${ac}" -draw "rectangle 30,44 66,52" \
"${app_dir}/icon.png"
else
ffmpeg -loglevel error -y -f lavfi -i "color=c=${bg}:s=96x96:d=0.1" \
-vf "drawbox=x=4:y=4:w=88:h=88:color=${ac}:t=fill,drawbox=x=14:y=14:w=68:h=68:color=${bg}:t=fill,drawbox=x=30:y=44:w=36:h=8:color=${ac}:t=fill" \
-frames:v 1 "${app_dir}/icon.png"
fi
# Per-app short SFX
sox -n -r 16000 -c 1 "${audio_dir}/open.wav" synth 0.09 sine $((520 + (idx * 17 % 220))) vol 0.3 fade q 0.001 0.09 0.02
sox -n -r 16000 -c 1 "${audio_dir}/action.wav" synth 0.08 sine $((880 + (idx * 11 % 260))) vol 0.3 fade q 0.001 0.08 0.02
# Offline/session fallback for streaming kids apps and audiobook.
if [[ "${app}" == kids_* || "${app}" == "audiobook_player" || "${app}" == "audio_player" ]]; then
ffmpeg -loglevel error -y -f lavfi \
-i "sine=frequency=$((380 + idx * 13)):duration=1.6" \
-ar 22050 -ac 1 -b:a 64k "${audio_dir}/offline.mp3"
ffmpeg -loglevel error -y -f lavfi \
-i "sine=frequency=$((300 + idx * 9)):duration=1.2" \
-ar 22050 -ac 1 -b:a 64k "${audio_dir}/session.mp3"
cp -f "${audio_dir}/offline.mp3" "${audio_dir}/default.mp3"
fi
idx=$((idx + 1))
done
echo "UI assets generated in ${DATA_DIR}/apps"