@@ -340,18 +340,18 @@ func vkDelayRandom(minMs, maxMs int) {
340340 time .Sleep (time .Duration (ms ) * time .Millisecond )
341341}
342342
343- func getVkCredsWithFallback (link string , resolver * protectedResolver , allowInteractiveFallback bool ) (string , string , string , time.Duration , error ) {
343+ func getVkCredsWithFallback (link string , resolver * protectedResolver , allowInteractiveFallback bool ) (string , string , [] string , time.Duration , error ) {
344344 if remaining := captchaLockoutRemaining (); remaining > 0 {
345345 emitCaptchaLockoutStatus (remaining )
346- return "" , "" , "" , 0 , fmt .Errorf ("CAPTCHA_WAIT_REQUIRED: global lockout active for %s" , remaining .Round (time .Second ))
346+ return "" , "" , nil , 0 , fmt .Errorf ("CAPTCHA_WAIT_REQUIRED: global lockout active for %s" , remaining .Round (time .Second ))
347347 }
348348
349349 profile := getRandomProfile ()
350350 name := generateName ()
351351 escapedName := neturl .QueryEscape (name )
352352 client , err := resolver .newTLSHTTPClient (profile , 20 * time .Second )
353353 if err != nil {
354- return "" , "" , "" , 0 , fmt .Errorf ("failed to initialize tls client: %w" , err )
354+ return "" , "" , nil , 0 , fmt .Errorf ("failed to initialize tls client: %w" , err )
355355 }
356356 defer client .CloseIdleConnections ()
357357
@@ -410,16 +410,16 @@ func getVkCredsWithFallback(link string, resolver *protectedResolver, allowInter
410410
411411 resp , err = doRequest (data , url )
412412 if err != nil {
413- return "" , "" , "" , 0 , fmt .Errorf ("request error:%s" , err )
413+ return "" , "" , nil , 0 , fmt .Errorf ("request error:%s" , err )
414414 }
415415
416416 dataMap , ok := resp ["data" ].(map [string ]interface {})
417417 if ! ok {
418- return "" , "" , "" , 0 , fmt .Errorf ("unexpected anon token response: %v" , resp )
418+ return "" , "" , nil , 0 , fmt .Errorf ("unexpected anon token response: %v" , resp )
419419 }
420420 token1 , ok := dataMap ["access_token" ].(string )
421421 if ! ok {
422- return "" , "" , "" , 0 , fmt .Errorf ("missing access_token in response: %v" , resp )
422+ return "" , "" , nil , 0 , fmt .Errorf ("missing access_token in response: %v" , resp )
423423 }
424424
425425 vkDelayRandom (100 , 150 )
@@ -440,14 +440,14 @@ func getVkCredsWithFallback(link string, resolver *protectedResolver, allowInter
440440 for attempt := 0 ; attempt <= maxCaptchaAttempts ; attempt ++ {
441441 resp , err = doRequest (data , url )
442442 if err != nil {
443- return "" , "" , "" , 0 , fmt .Errorf ("request error:%s" , err )
443+ return "" , "" , nil , 0 , fmt .Errorf ("request error:%s" , err )
444444 }
445445
446446 if errObj , hasErr := resp ["error" ].(map [string ]interface {}); hasErr {
447447 errCode , _ := errObj ["error_code" ].(float64 )
448448 if errCode == 14 {
449449 if attempt == maxCaptchaAttempts {
450- return "" , "" , "" , 0 , wrapCaptchaFailure (fmt .Errorf ("captcha failed after %d attempts" , maxCaptchaAttempts ), allowInteractiveFallback )
450+ return "" , "" , nil , 0 , wrapCaptchaFailure (fmt .Errorf ("captcha failed after %d attempts" , maxCaptchaAttempts ), allowInteractiveFallback )
451451 }
452452
453453 captchaErr := parseVkCaptchaError (errObj )
@@ -507,7 +507,7 @@ func getVkCredsWithFallback(link string, resolver *protectedResolver, allowInter
507507 }
508508 }
509509 if solveErr != nil {
510- return "" , "" , "" , 0 , wrapCaptchaFailure (fmt .Errorf ("smart captcha solve error: %w" , solveErr ), allowInteractiveFallback )
510+ return "" , "" , nil , 0 , wrapCaptchaFailure (fmt .Errorf ("smart captcha solve error: %w" , solveErr ), allowInteractiveFallback )
511511 }
512512 storeCachedCaptchaToken (successToken )
513513 captchaAttempt := captchaErr .CaptchaAttempt
@@ -538,7 +538,7 @@ func getVkCredsWithFallback(link string, resolver *protectedResolver, allowInter
538538 profile .UserAgent ,
539539 )
540540 if solveErr != nil {
541- return "" , "" , "" , 0 , wrapCaptchaFailure (fmt .Errorf ("captcha solve error: %w" , solveErr ), false )
541+ return "" , "" , nil , 0 , wrapCaptchaFailure (fmt .Errorf ("captcha solve error: %w" , solveErr ), false )
542542 }
543543 data = fmt .Sprintf (
544544 "vk_join_link=https://vk.com/call/join/%s&name=%s&access_token=%s&captcha_sid=%s&captcha_key=%s" ,
@@ -562,7 +562,7 @@ func getVkCredsWithFallback(link string, resolver *protectedResolver, allowInter
562562 profile .UserAgent ,
563563 )
564564 if solveErr != nil {
565- return "" , "" , "" , 0 , wrapCaptchaFailure (fmt .Errorf ("captcha solve error: %w" , solveErr ), true )
565+ return "" , "" , nil , 0 , wrapCaptchaFailure (fmt .Errorf ("captcha solve error: %w" , solveErr ), true )
566566 }
567567 data = fmt .Sprintf (
568568 "vk_join_link=https://vk.com/call/join/%s&name=%s&access_token=%s&captcha_sid=%s&captcha_key=%s" ,
@@ -575,16 +575,16 @@ func getVkCredsWithFallback(link string, resolver *protectedResolver, allowInter
575575 }
576576 continue
577577 }
578- return "" , "" , "" , 0 , fmt .Errorf ("VK API error: %v" , errObj )
578+ return "" , "" , nil , 0 , fmt .Errorf ("VK API error: %v" , errObj )
579579 }
580580
581581 responseMap , ok := resp ["response" ].(map [string ]interface {})
582582 if ! ok {
583- return "" , "" , "" , 0 , fmt .Errorf ("unexpected getAnonymousToken response: %v" , resp )
583+ return "" , "" , nil , 0 , fmt .Errorf ("unexpected getAnonymousToken response: %v" , resp )
584584 }
585585 token2 , ok = responseMap ["token" ].(string )
586586 if ! ok {
587- return "" , "" , "" , 0 , fmt .Errorf ("missing token in response: %v" , resp )
587+ return "" , "" , nil , 0 , fmt .Errorf ("missing token in response: %v" , resp )
588588 }
589589 if usedAutoCaptcha {
590590 log .Printf ("VK smart captcha accepted by auth endpoint" )
@@ -598,7 +598,7 @@ func getVkCredsWithFallback(link string, resolver *protectedResolver, allowInter
598598
599599 resp , err = doRequest (data , url )
600600 if err != nil {
601- return "" , "" , "" , 0 , fmt .Errorf ("request error:%s" , err )
601+ return "" , "" , nil , 0 , fmt .Errorf ("request error:%s" , err )
602602 }
603603
604604 token3 := resp ["session_key" ].(string )
@@ -609,13 +609,16 @@ func getVkCredsWithFallback(link string, resolver *protectedResolver, allowInter
609609
610610 resp , err = doRequest (data , url )
611611 if err != nil {
612- return "" , "" , "" , 0 , fmt .Errorf ("request error:%s" , err )
612+ return "" , "" , nil , 0 , fmt .Errorf ("request error:%s" , err )
613613 }
614614
615615 turnServer := resp ["turn_server" ].(map [string ]interface {})
616616 user := turnServer ["username" ].(string )
617617 pass := turnServer ["credential" ].(string )
618- turn := turnServer ["urls" ].([]interface {})[0 ].(string )
618+ urlsRaw , ok := turnServer ["urls" ].([]interface {})
619+ if ! ok || len (urlsRaw ) == 0 {
620+ return "" , "" , nil , 0 , fmt .Errorf ("missing or empty urls in turn_server" )
621+ }
619622
620623 var lifetime time.Duration
621624 if rawLifetime , ok := turnServer ["lifetime" ].(float64 ); ok && rawLifetime > 0 {
@@ -624,10 +627,22 @@ func getVkCredsWithFallback(link string, resolver *protectedResolver, allowInter
624627 lifetime = time .Duration (rawTTL ) * time .Second
625628 }
626629
627- clean := strings .Split (turn , "?" )[0 ]
628- address := strings .TrimPrefix (strings .TrimPrefix (clean , "turn:" ), "turns:" )
630+ var addresses []string
631+ for _ , u := range urlsRaw {
632+ urlStr , ok := u .(string )
633+ if ! ok {
634+ continue
635+ }
636+ clean := strings .Split (urlStr , "?" )[0 ]
637+ address := strings .TrimPrefix (strings .TrimPrefix (clean , "turn:" ), "turns:" )
638+ addresses = append (addresses , address )
639+ }
640+ if len (addresses ) == 0 {
641+ return "" , "" , nil , 0 , fmt .Errorf ("no valid TURN addresses parsed from urls" )
642+ }
643+ log .Printf ("VK Auth: TURN urls (%d) %v" , len (addresses ), addresses )
629644
630- return user , pass , address , lifetime , nil
645+ return user , pass , addresses , lifetime , nil
631646}
632647
633648func getYandexCreds (link string , resolver * protectedResolver ) (string , string , string , error ) {
@@ -1941,11 +1956,11 @@ func main() { //nolint:cyclop
19411956 credsGroupSize := max (1 , opts .credsGroupSize )
19421957 numGroups := max (1 , ceilDiv (opts .n , credsGroupSize ))
19431958 vkFetch := func (fctx context.Context , hash string , allowInteractive bool ) (turnCred , error ) {
1944- user , pass , addr , lifetime , err := getVkCredsWithFallback (hash , peerResolver , allowInteractive )
1959+ user , pass , addrs , lifetime , err := getVkCredsWithFallback (hash , peerResolver , allowInteractive )
19451960 if err != nil {
19461961 return turnCred {}, err
19471962 }
1948- return turnCred {user : user , pass : pass , addr : addr , lifetime : lifetime }, nil
1963+ return turnCred {user : user , pass : pass , addrs : addrs , lifetime : lifetime }, nil
19491964 }
19501965 vkLinkManager = newGroupedCredsManager (ctx , numGroups , credsGroupSize , tracker , vkFetch )
19511966 log .Printf (
@@ -1967,14 +1982,17 @@ func main() { //nolint:cyclop
19671982 if opts .n <= 0 {
19681983 opts .n = 1
19691984 }
1970- yandexBase := func (s string , _ bool ) (string , string , string , time.Duration , error ) {
1985+ yandexBase := func (s string , _ bool ) (string , string , [] string , time.Duration , error ) {
19711986 user , pass , addr , err := getYandexCreds (s , peerResolver )
1972- return user , pass , addr , 0 , err
1987+ if err != nil {
1988+ return "" , "" , nil , 0 , err
1989+ }
1990+ return user , pass , []string {addr }, 0 , nil
19731991 }
19741992 yandexPool := poolCreds (yandexBase , 1 )
19751993 yandexLink := link
1976- unifiedGetCreds = func (_ int ) (string , string , string , error ) {
1977- return yandexPool (yandexLink )
1994+ unifiedGetCreds = func (workerID int ) (string , string , string , error ) {
1995+ return yandexPool (yandexLink , workerID )
19781996 }
19791997 }
19801998 configuredPoolSize := max (1 , opts .n )
0 commit comments