Files
ALPHA-TRAIN2/services/tiktak/keygen/keygen.go
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

48 lines
1.6 KiB
Go

package keygen
import (
"crypto/hmac"
"crypto/sha256"
"strconv"
)
// The legacy C implementation (legacy/keygen.a, no source shipped) derived the
// share token from the video id ALONE -- no key, no salt. Worse, its state
// collapsed to (seed*17+42)%62 after the first round, so the token depended
// only on id%62: 62 distinct tokens for the whole service. Anyone could upload
// 62 private videos, copy the tokens off their own /home and unlock every
// private video on every team's box. Replaced with a keyed HMAC.
//
// Same signatures, same 30-char base62 alphabet, so nothing else changes.
// keygen.h / legacy/keygen.a are no longer part of the build (cgo is gone).
const (
tokenLen = 30
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
// Server-side secret. Rotating it invalidates every token already handed
// out, so change it only between rounds.
secret = "D1gkxNv7_HphLJjNuFag_stjaByXLZ1Y0l12RGppZtw"
)
func GenerateKey(vid int) string {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(strconv.Itoa(vid)))
sum := mac.Sum(nil)
out := make([]byte, tokenLen)
for i := 0; i < tokenLen; i++ {
out[i] = alphabet[int(sum[i%len(sum)])%len(alphabet)]
}
return string(out)
}
func ValidateKey(token string, vid int) bool {
// Constant-time: never leak how much of the token was correct.
if hmac.Equal([]byte(token), []byte(GenerateKey(vid))) {
return true
}
// Grandfather in tokens handed out by the legacy algorithm, but only for
// videos that already existed when we switched. See legacy.go.
return legacyAccepted(token, vid)
}