mirror of
https://github.com/hackdiaz-dev/free-turn-proxy.git
synced 2026-10-12 09:41:53 +02:00
2167ba990b
- server/main.go → cmd/vk-turn-server/main.go. Несёт остаточные правки сервера
(drop параметра useBond, убрано поле startup-лога).
- client/internal/{browserprofile,captcha,dnsdial,namegen,vkauth} →
internal/client/* (единая иерархия internal/; параллельное дерево
client/internal/ убрано). Все Go import-пути обновлены.
- .github/workflows/{ci,release}.yml, Dockerfile, README.md — пути сборки
переключены на ./cmd/vk-turn-client и ./cmd/vk-turn-server.
- README: убран устаревший пример "server -vless-bond" (флаг удалён ранее);
добавлены рецепты сборки .so для Android arm64 + Linux arm64/amd64 под
ручную упаковку для мобилок.
- internal/proxy/udp/udp.go, internal/config/config.go: обновлены устаревшие
ссылки client/internal/* в doc-комментариях.
- notes/GLOSSARY.md (новый, ~20 терминов): фиксирует DTLS-как-обфускацию,
wrap=AEAD-не-XOR, четыре значения "client", три значения "stream", пять
ортогональных переключателей "mode", заметки по сборке libvkturn.so, iSH,
хрупкость init globalBondRegistry и удаления флагов.
cmd/vk-turn-client/ намеренно оставлен вне этого коммита; сворачивается вместе
с извлечением ручной captcha в следующем коммите, т.к. переименование и правки
импортов manualcaptcha.* попадают в один файл.
Wire-форматы не тронуты. Поведение не изменено кроме уже закоммиченных
удалений CLI.
113 lines
2.9 KiB
Go
113 lines
2.9 KiB
Go
package captcha
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
neturl "net/url"
|
|
)
|
|
|
|
// Error describes a VK API "captcha required" error (error_code 14) and the
|
|
// fields the solver needs to drive the challenge.
|
|
type Error struct {
|
|
ErrorCode int
|
|
ErrorMsg string
|
|
CaptchaSid string
|
|
CaptchaImg string
|
|
RedirectURI string
|
|
IsSoundCaptchaAvailable bool
|
|
SessionToken string
|
|
CaptchaTs string
|
|
CaptchaAttempt string
|
|
}
|
|
|
|
// ParseError extracts a captcha challenge from a VK API error payload. Returns
|
|
// nil if required fields are missing.
|
|
func ParseError(errData map[string]any) *Error {
|
|
codeFloat, ok := errData["error_code"].(float64)
|
|
if !ok {
|
|
log.Printf("missing error_code in captcha error data")
|
|
return nil
|
|
}
|
|
code := int(codeFloat)
|
|
|
|
redirectURI, ok := errData["redirect_uri"].(string)
|
|
if !ok {
|
|
log.Printf("missing redirect_uri in captcha error data")
|
|
return nil
|
|
}
|
|
|
|
captchaSid, ok := errData["captcha_sid"].(string)
|
|
if !ok {
|
|
if sidNum, ok2 := errData["captcha_sid"].(float64); ok2 {
|
|
captchaSid = fmt.Sprintf("%.0f", sidNum)
|
|
} else {
|
|
log.Printf("missing captcha_sid in captcha error data")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
captchaImg, ok := errData["captcha_img"].(string)
|
|
if !ok {
|
|
log.Printf("missing captcha_img in captcha error data")
|
|
return nil
|
|
}
|
|
|
|
errorMsg, ok := errData["error_msg"].(string)
|
|
if !ok {
|
|
log.Printf("missing error_msg in captcha error data")
|
|
return nil
|
|
}
|
|
|
|
var sessionToken string
|
|
if redirectURI != "" {
|
|
if parsed, err := neturl.Parse(redirectURI); err == nil {
|
|
sessionToken = parsed.Query().Get("session_token")
|
|
} else {
|
|
log.Printf("failed to parse redirect_uri: %v", err)
|
|
return nil
|
|
}
|
|
}
|
|
if sessionToken == "" {
|
|
if st, stOk := errData["session_token"].(string); stOk {
|
|
sessionToken = st
|
|
}
|
|
}
|
|
|
|
isSound, ok := errData["is_sound_captcha_available"].(bool)
|
|
if !ok {
|
|
isSound = false
|
|
}
|
|
|
|
var captchaTs string
|
|
if tsFloat, ok := errData["captcha_ts"].(float64); ok {
|
|
captchaTs = fmt.Sprintf("%.0f", tsFloat)
|
|
} else if tsStr, ok := errData["captcha_ts"].(string); ok {
|
|
captchaTs = tsStr
|
|
}
|
|
|
|
var captchaAttempt string
|
|
if attFloat, ok := errData["captcha_attempt"].(float64); ok {
|
|
captchaAttempt = fmt.Sprintf("%.0f", attFloat)
|
|
} else if attStr, ok := errData["captcha_attempt"].(string); ok {
|
|
captchaAttempt = attStr
|
|
}
|
|
|
|
return &Error{
|
|
ErrorCode: code,
|
|
ErrorMsg: errorMsg,
|
|
CaptchaSid: captchaSid,
|
|
CaptchaImg: captchaImg,
|
|
RedirectURI: redirectURI,
|
|
IsSoundCaptchaAvailable: isSound,
|
|
SessionToken: sessionToken,
|
|
CaptchaTs: captchaTs,
|
|
CaptchaAttempt: captchaAttempt,
|
|
}
|
|
}
|
|
|
|
// IsCaptcha reports whether this error represents an actionable captcha
|
|
// challenge (error_code 14 with both redirect_uri and session_token present).
|
|
func (e *Error) IsCaptcha() bool {
|
|
return e.ErrorCode == 14 && e.RedirectURI != "" && e.SessionToken != ""
|
|
}
|