diff --git a/docs/flags.md b/docs/flags.md index d816dae..318fc88 100644 --- a/docs/flags.md +++ b/docs/flags.md @@ -7,7 +7,7 @@ | `-listen` | `127.0.0.1:9000` | локальный адрес `ip:port`, куда подключается WireGuard или Xray клиент | | `-peer` | **обязательный** | адрес сервера на VPS, `host:port` | | `-provider` | `vk` | источник TURN-creds: `vk` (см. `docs/providers.md`) | -| `-link` | **обязательный для `-provider vk`** | ссылка VK Calls `https://vk.com/call/join/...` | +| `-link` | **обязательный для `-provider vk`** | ссылка VK Calls `https://vk.ru/call/join/...` | | `-n` | `10` | параллельных TURN-потоков | | `-transport` | `tcp` | транспорт до TURN-реле: `tcp` (TCP/TLS) \| `udp` | | `-mode` | `udp` | режим туннеля: `udp` (UDP-релей для WireGuard) \| `tcp` (TCP-форвардер для Xray/sing-box) | diff --git a/docs/providers.md b/docs/providers.md index 4220976..bfc5ead 100644 --- a/docs/providers.md +++ b/docs/providers.md @@ -9,7 +9,7 @@ VK Calls API. Перебирает встроенные `app_id/app_secret`, получает короткоживущие (≈10 мин) TURN-creds через 4-шаговый token chain. Solver captcha auto+manual. **Обязательные флаги:** -- `-link` — VK callroom URL вида `https://vk.com/call/join/` (нормализуется до join-кода). +- `-link` — VK callroom URL вида `https://vk.ru/call/join/` (нормализуется до join-кода). **Опциональные:** - `-streams-per-cred` (default 10) — сколько TURN-стримов делят один кеш креденшалов. diff --git a/docs/quickstart.md b/docs/quickstart.md index 51e84f2..57fd757 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -2,7 +2,7 @@ ## Требования - **VPS с публичным IP**, на котором установлен VPN-сервер (например, WireGuard). VPN должен слушать локальный порт (например, `127.0.0.1:51820/udp`). -- **Активная ссылка VK Calls**: `https://vk.com/call/join/...` (создайте сами, звонок не завершайте). +- **Активная ссылка VK Calls**: `https://vk.ru/call/join/...` (создайте сами, звонок не завершайте). --- diff --git a/docs/sub.md b/docs/sub.md index c272c0f..03840d7 100644 --- a/docs/sub.md +++ b/docs/sub.md @@ -6,7 +6,7 @@ ## Использование в клиенте ```bash -./client -sub https://example.com/sub.md -link "https://vk.com/call/join/..." +./client -sub https://example.com/sub.md -link "https://vk.ru/call/join/..." ``` Клиент скачает подписку, найдет первый доступный сервер и автоматически применит его конфигурацию. Уникальная ссылка `-link` по-прежнему требуется. diff --git a/docs/uri.md b/docs/uri.md index 2f0c283..01726de 100644 --- a/docs/uri.md +++ b/docs/uri.md @@ -54,7 +54,7 @@ Payload - JSON-объект, закодированный `base64url` (без pa ## Пример использования ```bash -./client "freeturn://eyJ2IjoxLCJwcm92aWRlciI6InZrIiwicGVlciI6..." -link "https://vk.com/call/join/..." +./client "freeturn://eyJ2IjoxLCJwcm92aWRlciI6InZrIiwicGVlciI6..." -link "https://vk.ru/call/join/..." ``` Параметры из URI переопределяют базовые флаги (`-peer`, `-mode`, `-obf-key`, `-n` ...). diff --git a/internal/config/config.go b/internal/config/config.go index ba835b8..7aac47f 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -163,7 +163,7 @@ func ParseClient(args []string, errOut io.Writer) (*Client, error) { port := fs.String("port", "", "порт TURN-сервера; override creds провайдера") listen := fs.String("listen", "127.0.0.1:9000", "локальный ip:port для WireGuard/Xray клиента") provider := fs.String("provider", ProviderVK, "источник TURN-creds: vk") - link := fs.String("link", "", "ссылка VK Calls https://vk.com/call/join/...; обязательно для -provider vk") + link := fs.String("link", "", "ссылка VK Calls https://vk.ru/call/join/...; обязательно для -provider vk") peer := fs.String("peer", "", "адрес сервера на VPS, host:port; обязательно") n := fs.Int("n", 10, "число параллельных TURN-потоков") transport := fs.String("transport", "tcp", "транспорт до TURN-реле: tcp | udp") diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 093cf06..5c88a36 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -12,7 +12,7 @@ import ( func validClientArgs() []string { return []string{ "-peer", "1.2.3.4:5000", - "-link", "https://vk.com/call/join/abcdef", + "-link", "https://vk.ru/call/join/abcdef", } } @@ -56,7 +56,7 @@ func TestParseClient_Defaults(t *testing.T) { func TestParseClient_VKLinkStrip(t *testing.T) { args := []string{ "-peer", "1.2.3.4:5000", - "-link", "https://vk.com/call/join/CODE123?foo=bar", + "-link", "https://vk.ru/call/join/CODE123?foo=bar", } c, err := ParseClient(args, io.Discard) if err != nil { @@ -68,7 +68,7 @@ func TestParseClient_VKLinkStrip(t *testing.T) { } func TestParseClient_MissingPeer(t *testing.T) { - _, err := ParseClient([]string{"-link", "https://vk.com/call/join/X"}, io.Discard) + _, err := ParseClient([]string{"-link", "https://vk.ru/call/join/X"}, io.Discard) if err == nil || !strings.Contains(err.Error(), "peer") { t.Errorf("expected peer error, got %v", err) } diff --git a/internal/provider/vk/internal/captcha/captcha.go b/internal/provider/vk/internal/captcha/captcha.go index c8a503a..1209b24 100644 --- a/internal/provider/vk/internal/captcha/captcha.go +++ b/internal/provider/vk/internal/captcha/captcha.go @@ -262,7 +262,7 @@ func (s *captchaSession) solveOnce(captchaErr *Error) (string, error) { func captchaBaseValues(sessionToken string) [][2]string { return [][2]string{ {"session_token", sessionToken}, - {"domain", "vk.com"}, + {"domain", "vk.ru"}, {"adFp", ""}, {"access_token", ""}, } @@ -298,7 +298,7 @@ func (s *captchaSession) fetchDebugInfo(scriptURL string) (string, error) { } body, err := s.doRaw(fhttp.MethodGet, scriptURL, nil, map[string]string{ "Accept": "text/javascript,*/*", - "Referer": "https://id.vk.com/", + "Referer": "https://id.vk.ru/", }) if err != nil { return "", err @@ -354,8 +354,8 @@ func parseCaptchaPage(html string) (*captchaPage, error) { func (s *captchaSession) captchaRequest(method string, form [][2]string) (map[string]any, error) { endpoint := "https://api.vk.ru/method/" + method + "?v=" + captchaAPIVersion body, err := s.doRaw(fhttp.MethodPost, endpoint, form, map[string]string{ - "Origin": "https://id.vk.com", - "Referer": "https://id.vk.com/", + "Origin": "https://id.vk.ru", + "Referer": "https://id.vk.ru/", "Priority": "u=1, i", }) if err != nil { @@ -378,7 +378,7 @@ func (s *captchaSession) performCaptchaCheck( ) (*captchaCheck, error) { values := [][2]string{ {"session_token", sessionToken}, - {"domain", "vk.com"}, + {"domain", "vk.ru"}, {"adFp", ""}, {"accelerometer", "[]"}, {"gyroscope", "[]"}, @@ -437,7 +437,7 @@ func (s *captchaSession) solveCheckboxCaptcha( } if _, err := s.captchaRequest("captchaNotRobot.componentDone", [][2]string{ {"session_token", sessionToken}, - {"domain", "vk.com"}, + {"domain", "vk.ru"}, {"adFp", ""}, {"browser_fp", browserFP}, {"device", deviceJSON}, @@ -520,8 +520,8 @@ func (s *captchaSession) doRaw( req.Header.Set("Sec-Fetch-Site", "same-site") req.Header.Set("Sec-Fetch-Mode", "cors") req.Header.Set("Sec-Fetch-Dest", "empty") - req.Header.Set("Origin", "https://vk.com") - req.Header.Set("Referer", "https://vk.com/") + req.Header.Set("Origin", "https://vk.ru") + req.Header.Set("Referer", "https://vk.ru/") if form != nil { req.Header.Set("Content-Type", "application/x-www-form-urlencoded") } diff --git a/internal/provider/vk/internal/captcha/manual/manual.go b/internal/provider/vk/internal/captcha/manual/manual.go index 0c40c48..4785320 100644 --- a/internal/provider/vk/internal/captcha/manual/manual.go +++ b/internal/provider/vk/internal/captcha/manual/manual.go @@ -68,7 +68,7 @@ func localCaptchaHosts() []string { func isAllowedProxyHost(hostname string) bool { allowed := []string{ - ".vk.com", ".vk.ru", ".vkontakte.ru", + ".vk.ru", ".vk.ru", ".vkontakte.ru", ".userapi.com", ".okcdn.ru", ".mycdn.me", ".api.vk.ru", } @@ -218,7 +218,7 @@ var htmlStyleContentRe = regexp.MustCompile(`(?is)(]*>)(.*?)()` // rewriteHTMLAttrsServerSide переписывает абсолютные и protocol-relative URL // в src/href/action HTML на стороне сервера. URL, совпадающие с upstream origin, // идут на localhost; остальные — через /generic_proxy, чтобы cross-domain -// ресурсы (st.vk.com, userapi.com и т.д.) грузились через прокси. +// ресурсы (st.vk.ru, userapi.com и т.д.) грузились через прокси. func rewriteHTMLAttrsServerSide(html string, targetURL *neturl.URL) string { localOrigin := localCaptchaOrigin() upstreamOrigin := targetOrigin(targetURL) @@ -837,7 +837,7 @@ func SolveViaProxy(ctx context.Context, redirectURI string, dialer net.Dialer) ( res.Header.Set("Access-Control-Allow-Origin", "*") // captchaNotRobot.check уходит на api.vk.ru (другой хост, чем - // upstream vk.com), поэтому идёт через /generic_proxy. Извлекаем + // upstream vk.ru), поэтому идёт через /generic_proxy. Извлекаем // success_token здесь — серверный путь работает на iOS даже если // JS-callback в браузере не сработал. if strings.Contains(targetAuthURL, "captchaNotRobot.check") { diff --git a/internal/provider/vk/internal/captcha/slider.go b/internal/provider/vk/internal/captcha/slider.go index 1e82b57..baa44ce 100644 --- a/internal/provider/vk/internal/captcha/slider.go +++ b/internal/provider/vk/internal/captcha/slider.go @@ -45,7 +45,7 @@ func (s *captchaSession) solveSliderCaptcha( ) (string, error) { values := [][2]string{ {"session_token", sessionToken}, - {"domain", "vk.com"}, + {"domain", "vk.ru"}, {"adFp", ""}, {"access_token", ""}, {"captcha_settings", settings}, @@ -81,7 +81,7 @@ func (s *captchaSession) solveSliderCaptcha( } if _, err := s.captchaRequest("captchaNotRobot.componentDone", [][2]string{ {"session_token", sessionToken}, - {"domain", "vk.com"}, + {"domain", "vk.ru"}, {"adFp", ""}, {"access_token", ""}, {"browser_fp", browserFP}, diff --git a/internal/provider/vk/internal/vkauth/token.go b/internal/provider/vk/internal/vkauth/token.go index 4fe16b3..6d30abd 100644 --- a/internal/provider/vk/internal/vkauth/token.go +++ b/internal/provider/vk/internal/vkauth/token.go @@ -43,7 +43,7 @@ func (c *Client) getTokenChain(ctx context.Context, link string, streamID int, c } // Шаг 1a: прогрев getCallPreview (не критично). - previewData := fmt.Sprintf("vk_join_link=https://vk.com/call/join/%s&fields=photo_200&access_token=%s", link, token1) + previewData := fmt.Sprintf("vk_join_link=https://vk.ru/call/join/%s&fields=photo_200&access_token=%s", link, token1) if _, prevErr := c.doRequest(ctx, httpClient, profile, previewData, "https://api.vk.ru/method/calls.getCallPreview?v=5.275&client_id="+creds.ClientID); prevErr != nil { c.log.Warnf("[STREAM %d] [VK Auth] getCallPreview failed: %v", streamID, prevErr) diff --git a/internal/provider/vk/internal/vkauth/token_call.go b/internal/provider/vk/internal/vkauth/token_call.go index 75bae3e..1deaba5 100644 --- a/internal/provider/vk/internal/vkauth/token_call.go +++ b/internal/provider/vk/internal/vkauth/token_call.go @@ -24,7 +24,7 @@ func (c *Client) fetchCallToken( creds VKCredentials, ) (string, error) { urlAddr := fmt.Sprintf("https://api.vk.ru/method/calls.getAnonymousToken?v=5.275&client_id=%s", creds.ClientID) - data := fmt.Sprintf("vk_join_link=https://vk.com/call/join/%s&name=%s&access_token=%s", + data := fmt.Sprintf("vk_join_link=https://vk.ru/call/join/%s&name=%s&access_token=%s", link, escapedName, token1) for attempt := 0; ; attempt++ { @@ -171,12 +171,12 @@ func (c *Client) solveCaptcha( func buildCaptchaRetryData(link, escapedName, token1 string, captchaErr *captcha.Error, successToken, captchaKey string) string { if captchaKey != "" { return fmt.Sprintf( - "vk_join_link=https://vk.com/call/join/%s&name=%s&captcha_key=%s&captcha_sid=%s&access_token=%s", + "vk_join_link=https://vk.ru/call/join/%s&name=%s&captcha_key=%s&captcha_sid=%s&access_token=%s", link, escapedName, neturl.QueryEscape(captchaKey), captchaErr.CaptchaSid, token1, ) } return fmt.Sprintf( - "vk_join_link=https://vk.com/call/join/%s&name=%s&captcha_key=&captcha_sid=%s&is_sound_captcha=0&success_token=%s&captcha_ts=%s&captcha_attempt=%s&access_token=%s", + "vk_join_link=https://vk.ru/call/join/%s&name=%s&captcha_key=&captcha_sid=%s&is_sound_captcha=0&success_token=%s&captcha_ts=%s&captcha_attempt=%s&access_token=%s", link, escapedName, captchaErr.CaptchaSid, neturl.QueryEscape(successToken), captchaErr.CaptchaTs, captchaErr.CaptchaAttempt, token1, )