fix: миграция на ru домен

This commit is contained in:
samosvalishe
2026-06-17 01:11:52 +03:00
parent a82c472e67
commit 4084cce091
12 changed files with 26 additions and 26 deletions
+1 -1
View File
@@ -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) |
+1 -1
View File
@@ -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/<code>` (нормализуется до join-кода).
- `-link` — VK callroom URL вида `https://vk.ru/call/join/<code>` (нормализуется до join-кода).
**Опциональные:**
- `-streams-per-cred` (default 10) — сколько TURN-стримов делят один кеш креденшалов.
+1 -1
View File
@@ -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/...` (создайте сами, звонок не завершайте).
---
+1 -1
View File
@@ -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` по-прежнему требуется.
+1 -1
View File
@@ -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` ...).
+1 -1
View File
@@ -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")
+3 -3
View File
@@ -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)
}
@@ -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")
}
@@ -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)(<style[^>]*>)(.*?)(</style>)`
// 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") {
@@ -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},
@@ -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)
@@ -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,
)