Fetcher mimicks Python libraries behavior for more reliabilty. Removed inline comments from env.example since Go hates it.
This commit is contained in:
21
.env.example
21
.env.example
@@ -2,13 +2,18 @@
|
||||
DISCORD_BOT_TOKEN=your_discord_bot_token_here
|
||||
DISCORD_CHANNEL_ID=your_discord_channel_id_here
|
||||
DISCORD_GUILD_ID=your_discord_guild_id_here
|
||||
DISCORD_PING_USER_ID=your_discord_user_id_here # Get this by right-clicking your Discord profile
|
||||
# Get this by right-clicking your Discord profile
|
||||
DISCORD_PING_USER_ID=your_discord_user_id_here
|
||||
DISCORD_WEBHOOK_URL=your_discord_webhook_url_here
|
||||
RECONNECT_INTERVAL=5 # Interval between reconnect attempts if connection is lost
|
||||
SNEEDCHAT_ROOM_ID=1 # Which room will be bridged, append integer at the end of room name. Current options: general.1, gunt.8, keno-kasino.15, fishtank.16, beauty-parlor.18, sports.19,
|
||||
ENABLE_FILE_LOGGING=false # Enable logging to bridge.log file (true/false, default: false)
|
||||
# Interval between reconnect attempts if connection is lost
|
||||
RECONNECT_INTERVAL=5
|
||||
# Which room will be bridged, append integer at the end of room name. Current options: general.1, gunt.8, keno-kasino.15, fishtank.16, beauty-parlor.18, sports.19,
|
||||
SNEEDCHAT_ROOM_ID=1
|
||||
# Enable logging to bridge.log file for debugging purposes(true/false, default: false)
|
||||
ENABLE_FILE_LOGGING=false
|
||||
|
||||
# Optional: Prevent echo loops by filtering messages from the bridge bot
|
||||
# BRIDGE_USER_ID=123456 # Numeric user ID of your bridge bot account on Sneedchat
|
||||
# BRIDGE_USERNAME=YourBridgeBot # Username of your bridge bot account on Sneedchat
|
||||
# BRIDGE_PASSWORD=Password # Password of your account
|
||||
#Use your Kiwifarm crendeitals for here
|
||||
#This USER_ID number is in the url when you go to your profile, its required to prevent Discord from echoing your own messages back to you and to allow pings/push notifications work on Discord
|
||||
# BRIDGE_USER_ID=123456
|
||||
# BRIDGE_USERNAME=YourBridgeBot
|
||||
# BRIDGE_PASSWORD=Password
|
||||
@@ -2,6 +2,7 @@ package cookie
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -33,14 +34,43 @@ type CookieRefreshService struct {
|
||||
|
||||
// NewCookieRefreshService initializes a new cookie service.
|
||||
func NewCookieRefreshService(username, password, domain string, debug bool) (*CookieRefreshService, error) {
|
||||
// Standard cookie jar (no additional dependencies needed)
|
||||
jar, err := cookiejar.New(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Configure TLS to match Python's behavior
|
||||
tlsConfig := &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
InsecureSkipVerify: false,
|
||||
// Support modern cipher suites
|
||||
CipherSuites: []uint16{
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
},
|
||||
}
|
||||
|
||||
// Configure transport to match Python's behavior
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
DisableCompression: false,
|
||||
ForceAttemptHTTP2: true, // Force HTTP/2 like Python's aiohttp
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Jar: jar,
|
||||
Timeout: 45 * time.Second,
|
||||
Jar: jar,
|
||||
Timeout: 45 * time.Second,
|
||||
Transport: transport,
|
||||
// CRITICAL: Disable automatic redirects - we handle them manually
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
}
|
||||
|
||||
return &CookieRefreshService{
|
||||
@@ -146,11 +176,24 @@ func (crs *CookieRefreshService) FetchFreshCookie() (string, error) {
|
||||
// attemptFetchCookie performs one complete login cycle.
|
||||
func (crs *CookieRefreshService) attemptFetchCookie() (string, error) {
|
||||
baseURL := fmt.Sprintf("https://%s", crs.domain)
|
||||
|
||||
// Validate credentials
|
||||
if crs.username == "" || crs.password == "" {
|
||||
return "", fmt.Errorf("username or password is empty")
|
||||
}
|
||||
|
||||
if crs.debug {
|
||||
log.Printf("🔐 Attempting login for user: '%s' (password length: %d)", crs.username, len(crs.password))
|
||||
}
|
||||
|
||||
// Step 1: KiwiFlare clearance
|
||||
log.Println("Step 1: Checking for KiwiFlare challenge...")
|
||||
req, _ := http.NewRequest("GET", baseURL+"/", nil)
|
||||
req.Header.Set("User-Agent", randomUserAgent())
|
||||
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
|
||||
req.Header.Set("Accept-Language", "en-US,en;q=0.5")
|
||||
req.Header.Set("Connection", "keep-alive")
|
||||
req.Header.Set("Upgrade-Insecure-Requests", "1")
|
||||
|
||||
start := time.Now()
|
||||
resp, err := crs.client.Do(req)
|
||||
@@ -188,6 +231,11 @@ func (crs *CookieRefreshService) attemptFetchCookie() (string, error) {
|
||||
loginURL := fmt.Sprintf("%s/login", baseURL)
|
||||
req, _ = http.NewRequest("GET", loginURL, nil)
|
||||
req.Header.Set("User-Agent", randomUserAgent())
|
||||
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
|
||||
req.Header.Set("Accept-Language", "en-US,en;q=0.5")
|
||||
req.Header.Set("Connection", "keep-alive")
|
||||
req.Header.Set("Upgrade-Insecure-Requests", "1")
|
||||
|
||||
resp, err = crs.client.Do(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get login page: %w", err)
|
||||
@@ -201,30 +249,45 @@ func (crs *CookieRefreshService) attemptFetchCookie() (string, error) {
|
||||
// Step 3: Extract CSRF token
|
||||
csrfToken := extractCSRF(string(body))
|
||||
if csrfToken == "" {
|
||||
if crs.debug {
|
||||
log.Printf("🔍 HTML body (first 2000 chars):\n%s", string(body)[:min(2000, len(body))])
|
||||
}
|
||||
return "", fmt.Errorf("missing CSRF token")
|
||||
}
|
||||
log.Printf("✅ Found CSRF token: %s...", trimLong(csrfToken, 10))
|
||||
|
||||
// Step 4: POST login credentials (full browser headers + both redirect fields)
|
||||
// Step 4: POST login credentials (matching Python exactly)
|
||||
loginPost := fmt.Sprintf("%s/login/login", baseURL)
|
||||
|
||||
// Build form data exactly like Python
|
||||
data := url.Values{
|
||||
"_xfToken": {csrfToken},
|
||||
"login": {crs.username},
|
||||
"password": {crs.password},
|
||||
"remember": {"1"},
|
||||
"redirect": {"/"},
|
||||
"_xfRedirect": {baseURL + "/"},
|
||||
"_xfToken": {csrfToken},
|
||||
"login": {crs.username},
|
||||
"password": {crs.password},
|
||||
"remember": {"1"},
|
||||
}
|
||||
|
||||
// Add redirect URL as separate parameter (without the key from Python that was causing issues)
|
||||
data.Set("_xfRedirect", baseURL+"/")
|
||||
|
||||
formData := data.Encode()
|
||||
|
||||
if crs.debug {
|
||||
log.Printf("🔐 POST form data: %s", strings.ReplaceAll(formData, crs.password, "***"))
|
||||
}
|
||||
|
||||
postReq, _ := http.NewRequest("POST", loginPost, strings.NewReader(data.Encode()))
|
||||
postReq, _ := http.NewRequest("POST", loginPost, strings.NewReader(formData))
|
||||
postReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
postReq.Header.Set("Content-Length", fmt.Sprintf("%d", len(formData)))
|
||||
postReq.Header.Set("User-Agent", randomUserAgent())
|
||||
postReq.Header.Set("Referer", loginURL)
|
||||
postReq.Header.Set("Origin", baseURL)
|
||||
postReq.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
|
||||
postReq.Header.Set("Accept-Language", "en-US,en;q=0.5")
|
||||
postReq.Header.Set("Accept-Encoding", "gzip, deflate, br")
|
||||
postReq.Header.Set("Connection", "keep-alive")
|
||||
postReq.Header.Set("Upgrade-Insecure-Requests", "1")
|
||||
postReq.Header.Set("Cache-Control", "max-age=0")
|
||||
|
||||
loginResp, err := crs.client.Do(postReq)
|
||||
if err != nil {
|
||||
@@ -232,84 +295,180 @@ func (crs *CookieRefreshService) attemptFetchCookie() (string, error) {
|
||||
}
|
||||
defer loginResp.Body.Close()
|
||||
|
||||
log.Printf("Login response status: %d", loginResp.StatusCode)
|
||||
|
||||
// 🧩 Diagnostic: if status 200, dump first KB of body for debugging
|
||||
if loginResp.StatusCode == 200 {
|
||||
bodyBytes, _ := io.ReadAll(loginResp.Body)
|
||||
snippet := string(bodyBytes)
|
||||
if len(snippet) > 1000 {
|
||||
snippet = snippet[:1000]
|
||||
log.Printf("Login POST response: %d %s (proto: %s)", loginResp.StatusCode, loginResp.Status, loginResp.Proto)
|
||||
|
||||
if crs.debug {
|
||||
log.Println("Login response headers:")
|
||||
for k, v := range loginResp.Header {
|
||||
for _, val := range v {
|
||||
log.Printf(" ← %s: %s", k, val)
|
||||
}
|
||||
}
|
||||
log.Printf("🧩 Login 200 body snippet:\n%s", snippet)
|
||||
// Recreate reader for downstream reuse
|
||||
loginResp.Body = io.NopCloser(strings.NewReader(string(bodyBytes)))
|
||||
}
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
// Check if we got a redirect (successful login returns 303)
|
||||
if loginResp.StatusCode >= 300 && loginResp.StatusCode < 400 {
|
||||
location := loginResp.Header.Get("Location")
|
||||
log.Printf("✅ Login successful - got redirect to: %s", location)
|
||||
io.Copy(io.Discard, loginResp.Body)
|
||||
} else if loginResp.StatusCode == 200 {
|
||||
// Status 200 on login POST might mean:
|
||||
// 1. Failed login (shows error)
|
||||
// 2. Already logged in / session reuse
|
||||
// 3. Two-factor auth required
|
||||
bodyBytes, _ := io.ReadAll(loginResp.Body)
|
||||
snippet := string(bodyBytes)
|
||||
|
||||
// Check what kind of 200 response this is
|
||||
isLoggedIn := strings.Contains(snippet, "data-logged-in=\"true\"")
|
||||
hasError := strings.Contains(snippet, "Incorrect password") ||
|
||||
strings.Contains(snippet, "requested user") ||
|
||||
strings.Contains(snippet, "error")
|
||||
|
||||
if isLoggedIn {
|
||||
log.Println("✅ Login successful - already authenticated (200 OK with logged-in=true)")
|
||||
} else if !hasError {
|
||||
// No error message but not logged in = might be session propagation delay
|
||||
log.Println("⚠️ Login POST returned 200 without errors - checking session state...")
|
||||
} else if strings.Contains(snippet, "Incorrect password") {
|
||||
return "", fmt.Errorf("login failed: incorrect password")
|
||||
} else if strings.Contains(snippet, "requested user") {
|
||||
return "", fmt.Errorf("login failed: user not found")
|
||||
} else {
|
||||
log.Println("⚠️ Login POST returned 200 with possible error - will check cookies")
|
||||
}
|
||||
|
||||
if crs.debug && len(snippet) > 1000 {
|
||||
snippet = snippet[:1000]
|
||||
}
|
||||
if crs.debug {
|
||||
log.Printf("🧩 Login 200 body snippet:\n%s", snippet)
|
||||
}
|
||||
} else {
|
||||
// Other status codes
|
||||
io.Copy(io.Discard, loginResp.Body)
|
||||
log.Printf("⚠️ Unexpected login response: %d %s", loginResp.StatusCode, loginResp.Status)
|
||||
}
|
||||
|
||||
// Step 5: Check cookies in jar
|
||||
time.Sleep(3 * time.Second) // Increased from 2s - give server more time
|
||||
|
||||
// Step 5: Manually extract Set-Cookie headers from POST response
|
||||
// This is critical - Go's cookie jar might not automatically process
|
||||
// Set-Cookie headers when we disable redirects
|
||||
log.Println("Step 5: Extracting cookies from POST response headers...")
|
||||
if setCookies := loginResp.Header["Set-Cookie"]; len(setCookies) > 0 {
|
||||
for _, sc := range setCookies {
|
||||
log.Printf("📩 Set-Cookie header: %s", trimLong(sc, 80))
|
||||
// Parse and add to jar manually if needed
|
||||
// The jar should do this automatically, but let's be explicit
|
||||
}
|
||||
}
|
||||
|
||||
// Step 6: Check cookies in jar
|
||||
cookieURL, _ := url.Parse(baseURL)
|
||||
cookies := crs.client.Jar.Cookies(cookieURL)
|
||||
hasXfUser := false
|
||||
hasXfSession := false
|
||||
for _, c := range cookies {
|
||||
log.Printf("🍪 [After Login POST] %s=%s", c.Name, trimLong(c.Value, 10))
|
||||
if c.Name == "xf_user" {
|
||||
hasXfUser = true
|
||||
}
|
||||
if c.Name == "xf_session" {
|
||||
hasXfSession = true
|
||||
}
|
||||
}
|
||||
|
||||
// If we have xf_session but not xf_user, login succeeded but we need to trigger xf_user
|
||||
if hasXfSession && !hasXfUser {
|
||||
log.Println("✅ Login successful (have xf_session) - will trigger xf_user cookie")
|
||||
} else if !hasXfSession {
|
||||
log.Println("❌ Login may have failed - no xf_session cookie present")
|
||||
return "", fmt.Errorf("login failed - no session cookie received")
|
||||
}
|
||||
|
||||
// 🔁 Follow redirect manually if missing xf_user
|
||||
if !hasXfUser {
|
||||
log.Println("🧭 Following post-login redirect manually to capture xf_user...")
|
||||
// Step 6: CRITICAL - Manually follow redirects if xf_user missing (Python does this automatically)
|
||||
maxRedirects := 5
|
||||
redirectCount := 0
|
||||
currentURL := baseURL + "/"
|
||||
|
||||
for !hasXfUser && redirectCount < maxRedirects {
|
||||
redirectCount++
|
||||
log.Printf("🧭 Following redirect manually (attempt %d) to capture xf_user...", redirectCount)
|
||||
time.Sleep(1 * time.Second)
|
||||
followReq, _ := http.NewRequest("GET", baseURL+"/", nil)
|
||||
|
||||
followReq, _ := http.NewRequest("GET", currentURL, nil)
|
||||
followReq.Header.Set("User-Agent", randomUserAgent())
|
||||
followReq.Header.Set("Referer", baseURL+"/login")
|
||||
followReq.Header.Set("Origin", baseURL)
|
||||
followReq.Header.Set("Referer", loginPost)
|
||||
followReq.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
|
||||
followReq.Header.Set("Accept-Language", "en-US,en;q=0.5")
|
||||
followReq.Header.Set("Connection", "keep-alive")
|
||||
followReq.Header.Set("Upgrade-Insecure-Requests", "1")
|
||||
|
||||
followResp, ferr := crs.client.Do(followReq)
|
||||
if ferr != nil {
|
||||
log.Printf("⚠️ Redirect follow failed: %v", ferr)
|
||||
} else {
|
||||
followResp.Body.Close()
|
||||
log.Printf("📩 [HTTP GET] %s/ -> %s", baseURL, followResp.Status)
|
||||
break
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
cookies = crs.client.Jar.Cookies(cookieURL)
|
||||
for _, c := range cookies {
|
||||
log.Printf("🍪 [After Redirect] %s=%s", c.Name, trimLong(c.Value, 10))
|
||||
if c.Name == "xf_user" {
|
||||
hasXfUser = true
|
||||
log.Printf("📩 [HTTP GET] %s -> %s (proto: %s)", currentURL, followResp.Status, followResp.Proto)
|
||||
|
||||
// Check for additional redirects
|
||||
if followResp.StatusCode >= 300 && followResp.StatusCode < 400 {
|
||||
location := followResp.Header.Get("Location")
|
||||
if location != "" {
|
||||
if !strings.HasPrefix(location, "http") {
|
||||
location = baseURL + location
|
||||
}
|
||||
currentURL = location
|
||||
log.Printf("🔄 Server returned redirect to: %s", currentURL)
|
||||
}
|
||||
}
|
||||
|
||||
io.Copy(io.Discard, followResp.Body)
|
||||
followResp.Body.Close()
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Check cookies again
|
||||
cookies = crs.client.Jar.Cookies(cookieURL)
|
||||
for _, c := range cookies {
|
||||
log.Printf("🍪 [After Redirect %d] %s=%s", redirectCount, c.Name, trimLong(c.Value, 10))
|
||||
if c.Name == "xf_user" {
|
||||
hasXfUser = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hasXfUser {
|
||||
log.Println("✅ xf_user cookie acquired after redirect follow")
|
||||
} else {
|
||||
log.Println("⚠️ xf_user cookie still missing after redirect follow")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 🧭 Secondary check — trigger /account/ to issue xf_user if still missing
|
||||
// Step 7: Secondary check — trigger /account/ to issue xf_user if still missing
|
||||
// CRITICAL: For rooms that don't require auth to view, we need to force
|
||||
// session validation by accessing an authenticated endpoint
|
||||
if !hasXfUser {
|
||||
log.Println("🧭 Performing secondary authenticated fetch to /account/ to trigger xf_user...")
|
||||
time.Sleep(1 * time.Second)
|
||||
time.Sleep(2 * time.Second) // Increased wait time for session propagation
|
||||
|
||||
accountReq, _ := http.NewRequest("GET", baseURL+"/account/", nil)
|
||||
accountReq.Header.Set("User-Agent", randomUserAgent())
|
||||
accountReq.Header.Set("Referer", baseURL+"/login")
|
||||
accountReq.Header.Set("Origin", baseURL)
|
||||
accountReq.Header.Set("Referer", loginPost)
|
||||
accountReq.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
|
||||
accountReq.Header.Set("Accept-Language", "en-US,en;q=0.5")
|
||||
accountReq.Header.Set("Connection", "keep-alive")
|
||||
accountReq.Header.Set("Upgrade-Insecure-Requests", "1")
|
||||
|
||||
accountResp, accErr := crs.client.Do(accountReq)
|
||||
if accErr != nil {
|
||||
log.Printf("⚠️ Account fetch failed: %v", accErr)
|
||||
} else {
|
||||
io.Copy(io.Discard, accountResp.Body)
|
||||
accountResp.Body.Close()
|
||||
log.Printf("📩 [HTTP GET] %s/account/ -> %s", baseURL, accountResp.Status)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
time.Sleep(2 * time.Second) // Additional wait after /account/ fetch
|
||||
|
||||
cookies = crs.client.Jar.Cookies(cookieURL)
|
||||
for _, c := range cookies {
|
||||
@@ -320,9 +479,53 @@ func (crs *CookieRefreshService) attemptFetchCookie() (string, error) {
|
||||
}
|
||||
if hasXfUser {
|
||||
log.Println("✅ xf_user cookie acquired after /account/ fetch")
|
||||
}
|
||||
}
|
||||
|
||||
// Step 8: FINAL ATTEMPT - Try accessing the actual forum to force session validation
|
||||
// This is critical for non-auth-required rooms like room 16
|
||||
if !hasXfUser {
|
||||
log.Println("🧭 Final attempt: accessing forum index to force session validation...")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
forumReq, _ := http.NewRequest("GET", baseURL+"/forums/", nil)
|
||||
forumReq.Header.Set("User-Agent", randomUserAgent())
|
||||
forumReq.Header.Set("Referer", baseURL)
|
||||
forumReq.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
|
||||
forumReq.Header.Set("Accept-Language", "en-US,en;q=0.5")
|
||||
forumReq.Header.Set("Connection", "keep-alive")
|
||||
forumReq.Header.Set("Upgrade-Insecure-Requests", "1")
|
||||
|
||||
forumResp, forumErr := crs.client.Do(forumReq)
|
||||
if forumErr != nil {
|
||||
log.Printf("⚠️ Forum fetch failed: %v", forumErr)
|
||||
} else {
|
||||
log.Println("⚠️ xf_user cookie still missing after /account/ fetch")
|
||||
return "", fmt.Errorf("xf_user still missing after all follow-ups")
|
||||
bodyBytes, _ := io.ReadAll(forumResp.Body)
|
||||
forumResp.Body.Close()
|
||||
log.Printf("📩 [HTTP GET] %s/forums/ -> %s", baseURL, forumResp.Status)
|
||||
|
||||
// Check if we're actually logged in by looking for username in page
|
||||
if strings.Contains(string(bodyBytes), crs.username) {
|
||||
log.Println("✅ Confirmed logged in - username found in forum page")
|
||||
}
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
cookies = crs.client.Jar.Cookies(cookieURL)
|
||||
for _, c := range cookies {
|
||||
log.Printf("🍪 [After /forums/] %s=%s", c.Name, trimLong(c.Value, 10))
|
||||
if c.Name == "xf_user" {
|
||||
hasXfUser = true
|
||||
}
|
||||
}
|
||||
if hasXfUser {
|
||||
log.Println("✅ xf_user cookie acquired after forum page fetch")
|
||||
} else {
|
||||
log.Println("⚠️ xf_user cookie still missing after all follow-ups")
|
||||
|
||||
// Don't return error - build cookie string with what we have
|
||||
// The xf_session and xf_csrf might be enough for websocket auth
|
||||
log.Println("⚠️ Proceeding with available cookies (xf_session + xf_csrf)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,11 +564,18 @@ func trimLong(s string, n int) string {
|
||||
return s
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func randomUserAgent() string {
|
||||
uas := []string{
|
||||
"Mozilla/5.0 (X11; Linux x86_64) Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Safari/605.1.15",
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
}
|
||||
return uas[rand.Intn(len(uas))]
|
||||
}
|
||||
@@ -417,7 +627,7 @@ func (crs *CookieRefreshService) solveKiwiFlare(body []byte) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
submit := fmt.Sprintf("%s/.sssg/api/answer", baseURL(crs.domain))
|
||||
submit := fmt.Sprintf("https://%s/.sssg/api/answer", crs.domain)
|
||||
form := url.Values{"a": {salt}, "b": {fmt.Sprintf("%d", nonce)}}
|
||||
req, _ := http.NewRequest("POST", submit, strings.NewReader(form.Encode()))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
@@ -436,8 +646,4 @@ func (crs *CookieRefreshService) solveKiwiFlare(body []byte) (string, error) {
|
||||
return auth, nil
|
||||
}
|
||||
return "", fmt.Errorf("no auth field in KiwiFlare response")
|
||||
}
|
||||
|
||||
func baseURL(domain string) string {
|
||||
return fmt.Sprintf("https://%s", domain)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user