Update main.go
Browse files
main.go
CHANGED
|
@@ -10,6 +10,7 @@ import (
|
|
| 10 |
"net/http"
|
| 11 |
"net/url"
|
| 12 |
"os"
|
|
|
|
| 13 |
"strings"
|
| 14 |
"time"
|
| 15 |
|
|
@@ -368,66 +369,204 @@ func requestToken() (string, error) {
|
|
| 368 |
}
|
| 369 |
|
| 370 |
func requestTokenAndHash() (string, string, error) {
|
| 371 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 372 |
if err != nil {
|
| 373 |
-
return "", "", fmt.Errorf("
|
| 374 |
}
|
|
|
|
| 375 |
for k, v := range config.FakeHeaders {
|
| 376 |
req.Header.Set(k, v)
|
| 377 |
}
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
client := createHTTPClient(10 * time.Second)
|
| 381 |
-
|
| 382 |
-
log.Println("发送 token 请求")
|
| 383 |
resp, err := client.Do(req)
|
| 384 |
if err != nil {
|
| 385 |
-
return "", "", fmt.Errorf("
|
| 386 |
}
|
| 387 |
defer resp.Body.Close()
|
| 388 |
-
|
| 389 |
if resp.StatusCode != http.StatusOK {
|
| 390 |
bodyBytes, _ := io.ReadAll(resp.Body)
|
| 391 |
-
|
| 392 |
-
log.Printf("requestToken: 非200响应: %d, 内容: %s\n", resp.StatusCode, bodyString)
|
| 393 |
-
return "", "", fmt.Errorf("非200响应: %d, 内容: %s", resp.StatusCode, bodyString)
|
| 394 |
}
|
| 395 |
-
|
| 396 |
-
//
|
| 397 |
-
|
| 398 |
-
if
|
| 399 |
-
return "", "",
|
| 400 |
}
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 407 |
if err != nil {
|
| 408 |
-
log.Printf("
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 419 |
}
|
| 420 |
}
|
| 421 |
}
|
| 422 |
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 428 |
}
|
| 429 |
|
| 430 |
-
return
|
| 431 |
}
|
| 432 |
|
| 433 |
func prepareMessages(messages []struct {
|
|
@@ -532,4 +671,4 @@ func createHTTPClient(timeout time.Duration) *http.Client {
|
|
| 532 |
}
|
| 533 |
|
| 534 |
return client
|
| 535 |
-
}
|
|
|
|
| 10 |
"net/http"
|
| 11 |
"net/url"
|
| 12 |
"os"
|
| 13 |
+
"regexp"
|
| 14 |
"strings"
|
| 15 |
"time"
|
| 16 |
|
|
|
|
| 369 |
}
|
| 370 |
|
| 371 |
func requestTokenAndHash() (string, string, error) {
|
| 372 |
+
// Create a client with proper settings
|
| 373 |
+
client := createHTTPClient(30 * time.Second)
|
| 374 |
+
|
| 375 |
+
// First, visit the DuckDuckGo main page
|
| 376 |
+
req, err := http.NewRequest("GET", "https://duckduckgo.com/", nil)
|
| 377 |
if err != nil {
|
| 378 |
+
return "", "", fmt.Errorf("failed to create homepage request: %v", err)
|
| 379 |
}
|
| 380 |
+
|
| 381 |
for k, v := range config.FakeHeaders {
|
| 382 |
req.Header.Set(k, v)
|
| 383 |
}
|
| 384 |
+
|
| 385 |
+
log.Println("Sending request to DuckDuckGo homepage")
|
|
|
|
|
|
|
|
|
|
| 386 |
resp, err := client.Do(req)
|
| 387 |
if err != nil {
|
| 388 |
+
return "", "", fmt.Errorf("homepage request failed: %v", err)
|
| 389 |
}
|
| 390 |
defer resp.Body.Close()
|
| 391 |
+
|
| 392 |
if resp.StatusCode != http.StatusOK {
|
| 393 |
bodyBytes, _ := io.ReadAll(resp.Body)
|
| 394 |
+
return "", "", fmt.Errorf("homepage request returned status %d: %s", resp.StatusCode, string(bodyBytes))
|
|
|
|
|
|
|
| 395 |
}
|
| 396 |
+
|
| 397 |
+
// Read homepage content to extract vqd-related JavaScript
|
| 398 |
+
bodyBytes, err := io.ReadAll(resp.Body)
|
| 399 |
+
if err != nil {
|
| 400 |
+
return "", "", fmt.Errorf("failed to read homepage: %v", err)
|
| 401 |
}
|
| 402 |
+
|
| 403 |
+
bodyStr := string(bodyBytes)
|
| 404 |
+
|
| 405 |
+
// Method 1: Try to extract the vqd directly from the HTML attributes
|
| 406 |
+
// DuckDuckGo often embeds this in data attributes or JavaScript variables
|
| 407 |
+
vqdRegex := regexp.MustCompile(`vqd=["']([^"']+)["']`)
|
| 408 |
+
matches := vqdRegex.FindStringSubmatch(bodyStr)
|
| 409 |
+
|
| 410 |
+
if len(matches) < 2 {
|
| 411 |
+
// Try alternate regex patterns if the first one didn't match
|
| 412 |
+
alternatePatterns := []string{
|
| 413 |
+
`vqd[:=]["']([^"']+)["']`,
|
| 414 |
+
`"vqd":"([^"]+)"`,
|
| 415 |
+
`'vqd':'([^']+)'`,
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
for _, pattern := range alternatePatterns {
|
| 419 |
+
r := regexp.MustCompile(pattern)
|
| 420 |
+
matches = r.FindStringSubmatch(bodyStr)
|
| 421 |
+
if len(matches) >= 2 {
|
| 422 |
+
break
|
| 423 |
+
}
|
| 424 |
+
}
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
if len(matches) >= 2 {
|
| 428 |
+
token := matches[1]
|
| 429 |
+
log.Printf("Successfully extracted vqd token: %s", token)
|
| 430 |
+
return token, "", nil
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
// Method 2: Get the JavaScript file that contains the token generation logic
|
| 434 |
+
jsURLRegex := regexp.MustCompile(`(\/dist\/[^"']+\.js)`)
|
| 435 |
+
jsMatches := jsURLRegex.FindAllStringSubmatch(bodyStr, -1)
|
| 436 |
+
|
| 437 |
+
for _, match := range jsMatches {
|
| 438 |
+
if len(match) < 2 {
|
| 439 |
+
continue
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
jsURL := "https://duckduckgo.com" + match[1]
|
| 443 |
+
log.Printf("Trying to get vqd from JavaScript file: %s", jsURL)
|
| 444 |
+
|
| 445 |
+
jsReq, err := http.NewRequest("GET", jsURL, nil)
|
| 446 |
if err != nil {
|
| 447 |
+
log.Printf("Failed to create request for JS file: %v", err)
|
| 448 |
+
continue
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
for k, v := range config.FakeHeaders {
|
| 452 |
+
jsReq.Header.Set(k, v)
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
jsResp, err := client.Do(jsReq)
|
| 456 |
+
if err != nil {
|
| 457 |
+
log.Printf("Failed to get JS file: %v", err)
|
| 458 |
+
continue
|
| 459 |
+
}
|
| 460 |
+
|
| 461 |
+
jsBytes, err := io.ReadAll(jsResp.Body)
|
| 462 |
+
jsResp.Body.Close()
|
| 463 |
+
|
| 464 |
+
if err != nil {
|
| 465 |
+
log.Printf("Failed to read JS file: %v", err)
|
| 466 |
+
continue
|
| 467 |
+
}
|
| 468 |
+
|
| 469 |
+
jsContent := string(jsBytes)
|
| 470 |
+
|
| 471 |
+
// Look for vqd token patterns in the JS file
|
| 472 |
+
vqdInJSRegex := regexp.MustCompile(`vqd\s*[:=]\s*["']([^"']+)["']`)
|
| 473 |
+
jsMatches := vqdInJSRegex.FindStringSubmatch(jsContent)
|
| 474 |
+
|
| 475 |
+
if len(jsMatches) >= 2 {
|
| 476 |
+
token := jsMatches[1]
|
| 477 |
+
log.Printf("Found vqd token in JS file: %s", token)
|
| 478 |
+
return token, "", nil
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
// Try another pattern specific to the format in the JS file
|
| 482 |
+
vqdInJSRegex2 := regexp.MustCompile(`"vqd"\s*:\s*"([^"]+)"`)
|
| 483 |
+
jsMatches2 := vqdInJSRegex2.FindStringSubmatch(jsContent)
|
| 484 |
+
|
| 485 |
+
if len(jsMatches2) >= 2 {
|
| 486 |
+
token := jsMatches2[1]
|
| 487 |
+
log.Printf("Found vqd token in JS file (pattern 2): %s", token)
|
| 488 |
+
return token, "", nil
|
| 489 |
+
}
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
// Method 3 (Fallback): Try to request duck.js or related files which might contain the token
|
| 493 |
+
fallbackURLs := []string{
|
| 494 |
+
"https://duckduckgo.com/duck.js",
|
| 495 |
+
"https://duckduckgo.com/chat.js",
|
| 496 |
+
"https://duckduckgo.com/d.js",
|
| 497 |
+
}
|
| 498 |
+
|
| 499 |
+
for _, url := range fallbackURLs {
|
| 500 |
+
fallbackReq, err := http.NewRequest("GET", url, nil)
|
| 501 |
+
if err != nil {
|
| 502 |
+
log.Printf("Failed to create request for fallback URL %s: %v", url, err)
|
| 503 |
+
continue
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
for k, v := range config.FakeHeaders {
|
| 507 |
+
fallbackReq.Header.Set(k, v)
|
| 508 |
+
}
|
| 509 |
+
|
| 510 |
+
fallbackResp, err := client.Do(fallbackReq)
|
| 511 |
+
if err != nil {
|
| 512 |
+
log.Printf("Failed to get fallback URL %s: %v", url, err)
|
| 513 |
+
continue
|
| 514 |
+
}
|
| 515 |
+
|
| 516 |
+
fallbackBytes, err := io.ReadAll(fallbackResp.Body)
|
| 517 |
+
fallbackResp.Body.Close()
|
| 518 |
+
|
| 519 |
+
if err != nil {
|
| 520 |
+
log.Printf("Failed to read fallback URL %s: %v", url, err)
|
| 521 |
+
continue
|
| 522 |
+
}
|
| 523 |
+
|
| 524 |
+
fallbackContent := string(fallbackBytes)
|
| 525 |
+
|
| 526 |
+
// Try multiple regex patterns to find the vqd token
|
| 527 |
+
patterns := []string{
|
| 528 |
+
`vqd\s*[:=]\s*["']([^"']+)["']`,
|
| 529 |
+
`"vqd"\s*:\s*"([^"]+)"`,
|
| 530 |
+
`'vqd'\s*:\s*'([^']+)'`,
|
| 531 |
+
}
|
| 532 |
+
|
| 533 |
+
for _, pattern := range patterns {
|
| 534 |
+
r := regexp.MustCompile(pattern)
|
| 535 |
+
m := r.FindStringSubmatch(fallbackContent)
|
| 536 |
+
if len(m) >= 2 {
|
| 537 |
+
token := m[1]
|
| 538 |
+
log.Printf("Found vqd token in fallback URL %s: %s", url, token)
|
| 539 |
+
return token, "", nil
|
| 540 |
}
|
| 541 |
}
|
| 542 |
}
|
| 543 |
|
| 544 |
+
// Last resort: try the duckchat/v1/status endpoint which we know returns the token in headers
|
| 545 |
+
statusReq, err := http.NewRequest("GET", "https://duckduckgo.com/duckchat/v1/status", nil)
|
| 546 |
+
if err != nil {
|
| 547 |
+
return "", "", fmt.Errorf("failed to create status request: %v", err)
|
| 548 |
+
}
|
| 549 |
+
|
| 550 |
+
for k, v := range config.FakeHeaders {
|
| 551 |
+
statusReq.Header.Set(k, v)
|
| 552 |
+
}
|
| 553 |
+
statusReq.Header.Set("x-vqd-accept", "1")
|
| 554 |
+
|
| 555 |
+
log.Println("Trying duckchat/v1/status as last resort")
|
| 556 |
+
statusResp, err := client.Do(statusReq)
|
| 557 |
+
if err != nil {
|
| 558 |
+
return "", "", fmt.Errorf("status request failed: %v", err)
|
| 559 |
+
}
|
| 560 |
+
defer statusResp.Body.Close()
|
| 561 |
+
|
| 562 |
+
// Check X-VQD-4 header
|
| 563 |
+
token := statusResp.Header.Get("x-vqd-4")
|
| 564 |
+
if token != "" {
|
| 565 |
+
log.Printf("Found vqd token in status response header: %s", token)
|
| 566 |
+
return token, "", nil
|
| 567 |
}
|
| 568 |
|
| 569 |
+
return "", "", errors.New("could not find vqd token using any method")
|
| 570 |
}
|
| 571 |
|
| 572 |
func prepareMessages(messages []struct {
|
|
|
|
| 671 |
}
|
| 672 |
|
| 673 |
return client
|
| 674 |
+
}
|