package main import ( "encoding/json" "fmt" "io/ioutil" "math/rand" "net/http" "sort" "sync" "time" ) type BrowserVersion struct { Version string `json:"version"` Global float64 `json:"global"` } type BrowserData struct { Firefox []BrowserVersion `json:"firefox"` Chromium []BrowserVersion `json:"chrome"` } var ( cache = struct { sync.RWMutex data map[string]string }{ data: make(map[string]string), } browserCache = struct { sync.RWMutex data BrowserData expires time.Time }{ expires: time.Now(), } ) func fetchLatestBrowserVersions() (BrowserData, error) { url := "https://raw.githubusercontent.com/Fyrd/caniuse/master/fulldata-json/data-2.0.json" resp, err := http.Get(url) if err != nil { return BrowserData{}, err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return BrowserData{}, err } var rawData map[string]interface{} if err := json.Unmarshal(body, &rawData); err != nil { return BrowserData{}, err } stats := rawData["agents"].(map[string]interface{}) var data BrowserData if firefoxData, ok := stats["firefox"].(map[string]interface{}); ok { for version, usage := range firefoxData["usage_global"].(map[string]interface{}) { data.Firefox = append(data.Firefox, BrowserVersion{ Version: version, Global: usage.(float64), }) } } if chromeData, ok := stats["chrome"].(map[string]interface{}); ok { for version, usage := range chromeData["usage_global"].(map[string]interface{}) { data.Chromium = append(data.Chromium, BrowserVersion{ Version: version, Global: usage.(float64), }) } } return data, nil } func getLatestBrowserVersions() (BrowserData, error) { browserCache.RLock() if time.Now().Before(browserCache.expires) { data := browserCache.data browserCache.RUnlock() return data, nil } browserCache.RUnlock() data, err := fetchLatestBrowserVersions() if err != nil { return BrowserData{}, err } browserCache.Lock() browserCache.data = data browserCache.expires = time.Now().Add(24 * time.Hour) browserCache.Unlock() return data, nil } func randomUserAgent() (string, error) { browsers, err := getLatestBrowserVersions() if err != nil { return "", err } rand.Seed(time.Now().UnixNano()) // Simulated browser usage statistics (in percentages) usageStats := map[string]float64{ "Firefox": 30.0, "Chromium": 70.0, } // Calculate the probabilities for the versions probabilities := []float64{0.5, 0.25, 0.125, 0.0625, 0.03125, 0.015625, 0.0078125, 0.00390625} // Select a browser based on usage statistics browserType := "" randVal := rand.Float64() * 100 cumulative := 0.0 for browser, usage := range usageStats { cumulative += usage if randVal < cumulative { browserType = browser break } } var versions []BrowserVersion switch browserType { case "Firefox": versions = browsers.Firefox case "Chromium": versions = browsers.Chromium } if len(versions) == 0 { return "", fmt.Errorf("no versions found for browser: %s", browserType) } // Sort versions by usage (descending order) sort.Slice(versions, func(i, j int) bool { return versions[i].Global > versions[j].Global }) // Select a version based on the probabilities version := "" randVal = rand.Float64() cumulative = 0.0 for i, p := range probabilities { cumulative += p if randVal < cumulative && i < len(versions) { version = versions[i].Version break } } if version == "" { version = versions[len(versions)-1].Version } // Generate the user agent string userAgent := generateUserAgent(browserType, version) return userAgent, nil } func generateUserAgent(browser, version string) string { oses := []struct { os string probability float64 }{ {"Windows NT 10.0; Win64; x64", 44.0}, {"Windows NT 11.0; Win64; x64", 44.0}, {"X11; Linux x86_64", 1.0}, {"X11; Ubuntu; Linux x86_64", 1.0}, {"Macintosh; Intel Mac OS X 10_15_7", 10.0}, } // Select an OS based on probabilities randVal := rand.Float64() * 100 cumulative := 0.0 selectedOS := "" for _, os := range oses { cumulative += os.probability if randVal < cumulative { selectedOS = os.os break } } switch browser { case "Firefox": return fmt.Sprintf("Mozilla/5.0 (%s; rv:%s) Gecko/20100101 Firefox/%s", selectedOS, version, version) case "Chromium": return fmt.Sprintf("Mozilla/5.0 (%s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36", selectedOS, version) } return "" } func updateCachedUserAgents(newVersions BrowserData) { cache.Lock() defer cache.Unlock() for key, userAgent := range cache.data { randVal := rand.Float64() if randVal < 0.5 { updatedUserAgent := updateUserAgentVersion(userAgent, newVersions) cache.data[key] = updatedUserAgent } } } func updateUserAgentVersion(userAgent string, newVersions BrowserData) string { // Parse the current user agent to extract browser and version var browserType, version string if _, err := fmt.Sscanf(userAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36", &version); err == nil { browserType = "Chromium" } else if _, err := fmt.Sscanf(userAgent, "Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36", &version); err == nil { browserType = "Chromium" } else if _, err := fmt.Sscanf(userAgent, "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36", &version); err == nil { browserType = "Chromium" } else if _, err := fmt.Sscanf(userAgent, "Mozilla/5.0 (X11; Ubuntu; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36", &version); err == nil { browserType = "Chromium" } else if _, err := fmt.Sscanf(userAgent, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36", &version); err == nil { browserType = "Chromium" } else if _, err := fmt.Sscanf(userAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:%s) Gecko/20100101 Firefox/%s", &version, &version); err == nil { browserType = "Firefox" } else if _, err := fmt.Sscanf(userAgent, "Mozilla/5.0 (Windows NT 11.0; Win64; x64; rv:%s) Gecko/20100101 Firefox/%s", &version, &version); err == nil { browserType = "Firefox" } else if _, err := fmt.Sscanf(userAgent, "Mozilla/5.0 (X11; Linux x86_64; rv:%s) Gecko/20100101 Firefox/%s", &version, &version); err == nil { browserType = "Firefox" } else if _, err := fmt.Sscanf(userAgent, "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:%s) Gecko/20100101 Firefox/%s", &version, &version); err == nil { browserType = "Firefox" } else if _, err := fmt.Sscanf(userAgent, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7; rv:%s) Gecko/20100101 Firefox/%s", &version, &version); err == nil { browserType = "Firefox" } // Get the latest version for the browser type var latestVersion string if browserType == "Firefox" { latestVersion = newVersions.Firefox[0].Version } else if browserType == "Chromium" { latestVersion = newVersions.Chromium[0].Version } // Update the user agent string with the new version return generateUserAgent(browserType, latestVersion) } func periodicUpdate() { for { // Sleep for a random interval between 1 and 2 days time.Sleep(time.Duration(24+rand.Intn(24)) * time.Hour) // Fetch the latest browser versions newVersions, err := fetchLatestBrowserVersions() if err != nil { printWarn("Error fetching latest browser versions: %v", err) continue } // Update the browser version cache browserCache.Lock() browserCache.data = newVersions browserCache.expires = time.Now().Add(24 * time.Hour) browserCache.Unlock() // Update the cached user agents updateCachedUserAgents(newVersions) } } func GetUserAgent(cacheKey string) (string, error) { cache.RLock() userAgent, found := cache.data[cacheKey] cache.RUnlock() if found { return userAgent, nil } userAgent, err := randomUserAgent() if err != nil { return "", err } cache.Lock() cache.data[cacheKey] = userAgent cache.Unlock() return userAgent, nil } func GetNewUserAgent(cacheKey string) (string, error) { userAgent, err := randomUserAgent() if err != nil { return "", err } cache.Lock() cache.data[cacheKey] = userAgent cache.Unlock() return userAgent, nil } func init() { go periodicUpdate() } // func main() { // go periodicUpdate() // not needed here // cacheKey := "image-search" // userAgent, err := GetUserAgent(cacheKey) // if err != nil { // fmt.Println("Error:", err) // return // } // fmt.Println("Generated User Agent:", userAgent) // // Request a new user agent for the same key // newUserAgent, err := GetNewUserAgent(cacheKey) // if err != nil { // fmt.Println("Error:", err) // return // } // fmt.Println("New User Agent:", newUserAgent) // AcacheKey := "image-search" // AuserAgent, err := GetUserAgent(AcacheKey) // if err != nil { // fmt.Println("Error:", err) // return // } // fmt.Println("Generated User Agent:", AuserAgent) // DcacheKey := "image-search" // DuserAgent, err := GetUserAgent(DcacheKey) // if err != nil { // fmt.Println("Error:", err) // return // } // fmt.Println("Generated User Agent:", DuserAgent) // }