56993d2ca3
Security
- Sign pending_restore.json (SHA256 stored in AppSetting, verified on
startup apply) + refuse path outside data_dir, tighten to 0600.
- Require same-origin Origin/Referer on POST /api/backup/apply-restart —
Bearer-in-localStorage is CSRF-reachable from any XSS'd admin tab.
- Bump token_version on role/username change and admin password reset so
demoted admins lose admin in already-issued JWTs. Guard last-admin
TOCTOU via COUNT + post-commit re-check that rolls back a race.
- SSRF guard (validate_outbound_url) in ImmichClient.__init__ and the
external_domain setter — admin-mutable URLs were bypassing the check
that webhook/slack/discord paths already used. Dev restart script now
sets NOTIFY_BRIDGE_ALLOW_PRIVATE_URLS=1 so homelab Immich still works.
- Redact + cap Immich error bodies to ~120 chars before they flow into
ActionExecution.error / EventLog.details (both UI-visible).
- Deny-list sensitive keys (api_key / token / secret / password /
authorization / cookie / ...) in template-context merges so a rogue
template can't exfiltrate provider creds via {{ api_key }}.
- Cap user-controlled Immich search params (query ≤256, person_ids ≤50,
size ≤100) so a Telegram listener can't DoS upstream.
- Stream upload reads with running byte counter + content-length precheck
instead of buffering the full body and then rejecting.
- Log Telegram parse_mode fallbacks instead of swallowing silently;
template escape bugs now surface in server logs.
- Rollback partial imports on pending-restore failure (error recorded on
a fresh session).
Performance
- Fix N+1 in _refresh_telegram_chat_titles: single IN query instead of
session.get per chat.
- Parallelize album + shared-link fetches in test_dispatch (asyncio.gather)
and per-receiver Telegram test sends in notifier (semaphore 5).
- Early-exit collect_scheduled_assets(limit=0) so the periodic-summary
test path skips full per-album filter/sample (was O(album_assets)).
- Emit explicit CREATE INDEX IF NOT EXISTS for event_log user_id /
action_id / provider_id so the first boot after upgrade isn't left
unindexed for the dashboard query.
- Add AbortController timeout (120s) to fetchAuth so uploads/downloads
don't hang indefinitely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
43 lines
1.3 KiB
Bash
43 lines
1.3 KiB
Bash
#!/usr/bin/env bash
|
|
# Restart the backend dev server.
|
|
# Usage: bash scripts/restart-backend.sh
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
# Kill existing backend
|
|
PID=$(netstat -ano 2>/dev/null | grep ':8420.*LISTENING' | awk '{print $5}' | head -1)
|
|
if [ -n "$PID" ]; then
|
|
taskkill //F //PID "$PID" 2>/dev/null || true
|
|
sleep 1
|
|
fi
|
|
|
|
# Resolve python — prefer py launcher on Windows (python3 may be the Store stub)
|
|
if command -v py &>/dev/null; then
|
|
PYTHON=$(py -3 -c "import sys; print(sys.executable)" 2>/dev/null)
|
|
elif command -v python3 &>/dev/null && python3 --version &>/dev/null; then
|
|
PYTHON=python3
|
|
elif command -v python &>/dev/null && python --version &>/dev/null; then
|
|
PYTHON=python
|
|
else
|
|
echo "Python not found"; exit 1
|
|
fi
|
|
|
|
# Start backend
|
|
export NOTIFY_BRIDGE_DATA_DIR=./test-data
|
|
export NOTIFY_BRIDGE_SECRET_KEY=test-secret-key-minimum-32-chars
|
|
# Dev targets (homelab Immich / Gitea / etc.) live on RFC1918 ranges; the SSRF
|
|
# guard rejects private addresses by default, which would make trackers fail.
|
|
export NOTIFY_BRIDGE_ALLOW_PRIVATE_URLS=1
|
|
nohup "$PYTHON" -m uvicorn notify_bridge_server.main:app \
|
|
--host 0.0.0.0 --port 8420 > .backend.log 2>&1 &
|
|
|
|
sleep 3
|
|
if curl -sf http://localhost:8420/api/health; then
|
|
echo ""
|
|
echo "Backend started (PID $!)"
|
|
else
|
|
echo "Backend failed to start. Log:"
|
|
tail -20 .backend.log
|
|
exit 1
|
|
fi
|