Files
ALPHA-TRAIN2/check_tiktak.sh
T
bobiqqandClaude Opus 5 753d21c3e8
build-and-push / detect (push) Successful in 12s
build-and-push / build (${{ fromJSON(needs.detect.outputs.services) }}) (push) Successful in 33s
tiktak: принимать legacy-токены для старых видео + fail-open в probe
MUMBLE "failed to get access using private key": чекер держит share-токен,
выданный ещё старым keygen, а после перехода на HMAC ValidateKey его
отвергал.

- keygen/legacy.go: восстановленный из keygen.a алгоритм
  seed=(seed*17+42)%62 принимается ТОЛЬКО для video.id <= cutoff, то есть
  для видео, существовавших на момент перехода. Выше cutoff -- лишь HMAC.
- cutoff берётся из max(video.id) при первом старте и пишется в
  public/.legacy_cutoff на volume: рестарт не должен расширять окно.
  Не смогли прочитать -- fail closed, legacy выключен.
- Когда старые флаги протухнут: echo 0 > public/.legacy_cutoff + рестарт,
  и legacy отключается полностью.

Ещё MUMBLE "cannot create video" -- он же DoS, у NOP-команды то же самое:
- checkGeometry сделан FAIL-OPEN. Неразобранный ffprobe больше не отклоняет
  загрузку, режем только успешно прочитанную и абсурдную геометрию.
- ffmpeg -max_alloc 128M: 1080p кадру нужно ~8 МБ, бомбе ~1 ГБ. Работает
  даже когда probe промолчал.

check_tiktak.sh: smoke-тест для vulnbox, гоняет сценарий чекера целиком
и отдельно проверяет, что патчи реально в задеплоенном билде.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 12:25:45 +03:00

127 lines
6.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Smoke-test для tiktak. Запускать НА VULNBOX из каталога репы.
# ./check_tiktak.sh -> проверяет 127.0.0.1:5000
# ./check_tiktak.sh 10.10.10.3 -> проверяет чужой/свой бокс по сети
#
# Повторяет сценарий чекера (register -> create -> watch -> vtt -> share по
# токену) и отдельно проверяет, что патчи действительно в задеплоенном билде.
set -uo pipefail
HOST="${1:-127.0.0.1}"
BASE="http://${HOST}:5000"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
PASS=0; FAIL=0
ok() { printf ' \033[32mOK\033[0m %s\n' "$1"; PASS=$((PASS+1)); }
bad() { printf ' \033[31mFAIL\033[0m %s\n' "$1"; FAIL=$((FAIL+1)); }
info() { printf '\n\033[1m%s\033[0m\n' "$1"; }
req() { curl -sS -m 10 "$@"; }
# ---------- тестовый webm ----------
VIDEO="$TMP/clip.webm"
if ls services/tiktak/public/video/*.webm >/dev/null 2>&1; then
cp "$(ls -S services/tiktak/public/video/*.webm | tail -1)" "$VIDEO"
elif command -v ffmpeg >/dev/null 2>&1; then
ffmpeg -y -v error -f lavfi -i testsrc=size=320x240:rate=5 -t 1 -c:v libvpx "$VIDEO" </dev/null
else
docker compose -f services/tiktak/docker-compose.yml exec -T tiktak \
ffmpeg -v error -f lavfi -i testsrc=size=320x240:rate=5 -t 1 -c:v libvpx -f webm - > "$VIDEO" 2>/dev/null
fi
[ -s "$VIDEO" ] || { echo "не смог получить тестовый webm — положи любой в services/tiktak/public/video/"; exit 1; }
echo "тестовое видео: $(wc -c < "$VIDEO") байт"
# ---------- 1. живость ----------
info "1. сервис отвечает"
code=$(req -o /dev/null -w '%{http_code}' "$BASE/") || true
[ "$code" = "302" ] && ok "GET / -> 302" || bad "GET / -> ${code:-нет ответа} (ждали 302)"
code=$(req -o /dev/null -w '%{http_code}' "$BASE/feed")
[ "$code" = "200" ] && ok "GET /feed -> 200" || bad "GET /feed -> $code"
# ---------- 2. регистрация ----------
info "2. регистрация и сессия"
U1="chk_$RANDOM$RANDOM"; J1="$TMP/j1"
HDR=$(req -D - -o /dev/null -c "$J1" -X POST "$BASE/register" -d "login=$U1&password=pw123456")
grep -q 'Location: /home' <<<"$HDR" && ok "register -> 302 /home" || bad "register не дал редирект на /home"
if grep -qi 'set-cookie:.*httponly' <<<"$HDR"; then
ok "куки с HttpOnly — ПАТЧИ В БИЛДЕ"
else
bad "куки БЕЗ HttpOnly — на боксе СТАРЫЙ билд, деплой не доехал"
fi
code=$(req -o /dev/null -w '%{http_code}' -b "$J1" "$BASE/home")
[ "$code" = "200" ] && ok "GET /home -> 200" || bad "GET /home -> $code"
# ---------- 3. публичное видео ----------
info "3. публичное видео: create -> watch -> vtt"
SUB="checker-canary-$RANDOM"
LOC=$(req -o /dev/null -w '%{redirect_url}' -b "$J1" -X POST "$BASE/create" \
-F "description=smoke" -F "subtitles=$SUB" -F "video=@$VIDEO;type=video/webm")
VID="${LOC##*/}"
if [[ "$VID" =~ ^[0-9]+$ ]]; then ok "create -> /watch/$VID"; else bad "create не создал видео (redirect='$LOC')"; VID=""; fi
if [ -n "$VID" ]; then
body=$(req -b "$J1" "$BASE/watch/$VID")
grep -q 'smoke' <<<"$body" && ok "watch отдаёт description" || bad "watch без description"
vtt=$(req -b "$J1" "$BASE/vtt/?id=$VID")
grep -q 'WEBVTT' <<<"$vtt" && grep -q "$SUB" <<<"$vtt" && ok "vtt отдаёт субтитры" || bad "vtt не отдал субтитры"
fi
# ---------- 4. приватное видео и шаринг ----------
info "4. приватное видео: home -> token -> access -> watch"
PSUB="private-canary-$RANDOM"
LOC=$(req -o /dev/null -w '%{redirect_url}' -b "$J1" -X POST "$BASE/create" \
-F "description=secret" -F "subtitles=$PSUB" -F "private=on" -F "video=@$VIDEO;type=video/webm")
PVID="${LOC##*/}"
if [[ "$PVID" =~ ^[0-9]+$ ]]; then ok "create private -> /watch/$PVID"; else bad "приватное видео не создалось"; PVID=""; fi
if [ -n "$PVID" ]; then
TOKEN=$(req -b "$J1" "$BASE/home" | grep -A0 'Share Token' | sed -n 's/.*Share Token: *\([A-Za-z0-9]\{30\}\).*/\1/p' | head -1)
[ -n "$TOKEN" ] && ok "токен на /home: $TOKEN" || bad "на /home нет Share Token"
U2="chk2_$RANDOM$RANDOM"; J2="$TMP/j2"
req -o /dev/null -c "$J2" -X POST "$BASE/register" -d "login=$U2&password=pw123456"
code=$(req -o /dev/null -w '%{http_code}' -b "$J2" "$BASE/watch/$PVID")
[ "$code" = "403" ] && ok "чужой без токена -> 403" || bad "чужой без токена -> $code (ждали 403)"
if [ -n "$TOKEN" ]; then
LOC=$(req -o /dev/null -w '%{redirect_url}' -b "$J2" -c "$J2" -X POST "$BASE/access" \
-d "videoID=$PVID&token=$TOKEN")
if [[ "$LOC" == */watch/$PVID ]]; then
ok "access по токену -> /watch/$PVID"
grep -q 'secret' <<<"$(req -b "$J2" "$BASE/watch/$PVID")" && ok "шаринг работает" || bad "после access watch пустой"
else
bad "access отверг валидный токен (redirect='$LOC') — ЧЕКЕР СЛОМАЕТСЯ"
fi
fi
fi
# ---------- 5. патчи ----------
info "5. закрыты ли дыры"
for p in "./$VID" "x/../$VID" "/$VID" "../../etc/passwd"; do
code=$(req -o /dev/null -w '%{http_code}' -G "$BASE/vtt/" --data-urlencode "id=$p")
[ "$code" = "404" ] && ok "LFI '$p' -> 404" || bad "LFI '$p' -> $code (дыра ОТКРЫТА)"
done
if [ -n "$PVID" ]; then
code=$(req -o /dev/null -w '%{http_code}' "$BASE/public/static/preview_${PVID}.png")
[ "$code" = "404" ] && ok "резкое превью приватного -> 404" || bad "резкое превью отдаётся ($code)"
code=$(req -o /dev/null -w '%{http_code}' "$BASE/public/static/preview_${PVID}_blured.png")
[ "$code" = "200" ] && ok "размытое превью на месте" || bad "размытое превью -> $code (сломает фид)"
fi
# ---------- 6. бомба ----------
info "6. decompression bomb"
BOMB="$TMP/bomb.webm"
if command -v ffmpeg >/dev/null 2>&1 && \
ffmpeg -y -v error -f lavfi -i color=c=black:s=8192x8192:d=1 -c:v libvpx "$BOMB" </dev/null 2>/dev/null && [ -s "$BOMB" ]; then
t0=$(date +%s)
code=$(req -o /dev/null -w '%{http_code}' -b "$J1" -X POST "$BASE/create" \
-F "description=b" -F "subtitles=b" -F "video=@$BOMB;type=video/webm")
dt=$(( $(date +%s) - t0 ))
[ "$code" = "422" ] && ok "бомба 8192x8192 отбита за ${dt}s" || bad "бомба -> $code за ${dt}s (ждали 422)"
else
echo " -- пропуск: нет ffmpeg для генерации бомбы"
fi
# ---------- итог ----------
info "ИТОГ: $PASS ok, $FAIL fail"
[ "$FAIL" -eq 0 ] || exit 1