Files
felhom.eu/documentation/audits/filebrowser-memory-ci-2026-10-17/tools/fbenv-spike.sh
T
admin f6511dc5c2
gates / gates (push) Successful in 6m53s
FileBrowser never on its default password (D11 = A), real memory amounts (D10 = A), CI mail: report, register, docs
Closed R-1126, R-1125 and R-1129 (not a defect: a misreading of the CI log by the session that filed it); opened
R-1135..R-1137; R-1124 noted. 01 §5 [DESIGN]: the tunnel runs before the claim; FileBrowser is published only after
its default login is checked. STATUS D10-D12 decided. N100 diary: the 21-minute file-manager gap after 0.327.0.
Controller 0.327.1 is the floor since 12:06 UTC.

Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-17 14:12:02 +02:00

40 lines
3.6 KiB
Bash
Executable File

#!/bin/bash
# fbenv-spike.sh — R-1126 Part 1a, inside scratch guest 9202. A THROWAWAY FileBrowser (r1126-fb, its own volume) with
# FILEBROWSER_ADMIN_PASSWORD from a 0600 env file (generated here, never printed). Prints status codes only.
set -u
IMG=gtstef/filebrowser:1.5.6-stable; W=/root/r1126; rm -rf $W; mkdir -m 700 -p $W/srv
docker rm -f r1126-fb >/dev/null 2>&1; docker volume rm r1126_data >/dev/null 2>&1
cat > $W/config.yaml <<'C'
server:
port: 80
database: "/home/filebrowser/data/database.db"
sources:
- path: "/srv/t"
name: "T"
C
umask 077; printf 'FILEBROWSER_ADMIN_PASSWORD=%s\n' "$(head -c 18 /dev/urandom | base64 | tr -dc A-Za-z0-9 | head -c 16)" > $W/env
cfgpw() { sed -n 's/^FILEBROWSER_ADMIN_PASSWORD=//p' $W/env; }
ip() { docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' r1126-fb; }
login() { printf 'X-Password: %s\n' "$1" | curl -s -o /dev/null -w '%{http_code}' --max-time 5 -X POST -H @- "http://$(ip):80/api/auth/login?username=admin"; }
token() { printf 'X-Password: %s\n' "$1" | curl -s --max-time 5 -X POST -H @- "http://$(ip):80/api/auth/login?username=admin" | tr -d '"'; }
start() { docker run -d --name r1126-fb -v r1126_data:/home/filebrowser/data -v $W/config.yaml:/home/filebrowser/config.yaml:ro \
-v $W/srv:/srv/t -e FILEBROWSER_CONFIG=/home/filebrowser/config.yaml --env-file $W/env $IMG >/dev/null; }
echo "== 1. a NEW database with the env password: probe the default login from the first answer (1 s apart, 5 answers —"
echo " FileBrowser 1.5.6 limits login tries: the first run of this spike probed 4/s and was answered 429 after 8 tries)"
start; seen=""; n=0
for i in $(seq 1 120); do c=$(login admin 2>/dev/null); if [ -n "$c" ] && [ "$c" != "000" ]; then seen="$seen $c"; n=$((n+1)); [ $n -ge 5 ] && break; sleep 1; else sleep 0.25; fi; done
echo " default-login answers seen: $(echo $seen | tr ' ' '\n' | sort | uniq -c | tr '\n' ' ')"
echo " waiting 90 s for FileBrowser's login limiter to clear"; sleep 90
echo " env password login: $(login "$(cfgpw)")"
echo "== 2. the household sets its own password in FileBrowser (the API the box uses), then a restart"
tok=$(token "$(cfgpw)"); own="$(head -c 18 /dev/urandom | base64 | tr -dc A-Za-z0-9 | head -c 16)"
id=$(curl -s --max-time 5 -H "X-Auth: $tok" -H "Authorization: Bearer $tok" "http://$(ip):80/api/users?id=self" | python3 -c 'import json,sys;d=json.load(sys.stdin);print(d.get("id", ""))')
body=$(python3 -c 'import json,sys;print(json.dumps({"which":["password"],"data":{"id":int(sys.argv[1]),"username":"admin","password":sys.stdin.read()}}))' "$id" <<< "$own" | sed 's/\\n"/"/')
code=$(printf 'X-Password: %s\n' "$(cfgpw)" | curl -s -o /dev/null -w '%{http_code}' --max-time 5 -X PUT -H @- -H "X-Auth: $tok" -H "Authorization: Bearer $tok" -H 'Content-Type: application/json' --data "$body" "http://$(ip):80/api/users?id=$id")
echo " PUT own password: $code; own login: $(login "$own"); env login: $(login "$(cfgpw)")"
docker restart r1126-fb >/dev/null; for i in $(seq 1 60); do c=$(curl -s -o /dev/null -w '%{http_code}' --max-time 3 "http://$(ip):80/"); [ "$c" != "000" ] && break; sleep 0.5; done
echo " AFTER RESTART — own login: $(login "$own"); env login: $(login "$(cfgpw)"); default login: $(login admin)"
docker logs r1126-fb 2>&1 | grep -iE "Resetting admin|admin password from" | sed 's/^/ log: /' | tail -3
docker rm -f r1126-fb >/dev/null; docker volume rm r1126_data >/dev/null; rm -rf $W
echo "== cleanup: $(docker ps -a --filter name=r1126 --format '{{.Names}}' | wc -l) containers, $(docker volume ls -q | grep -c r1126) volumes left"