mirror of
https://github.com/hackdiaz-dev/free-turn-proxy.git
synced 2026-10-12 09:41:53 +02:00
fix: миграция на ru домен
This commit is contained in:
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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` ...).
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user