package tools import ( "WarpGPT/pkg/env" "WarpGPT/pkg/funcaptcha" "WarpGPT/pkg/logger" "encoding/json" "fmt" http "github.com/bogdanfinn/fhttp" tls_client "github.com/bogdanfinn/tls-client" "github.com/bogdanfinn/tls-client/profiles" "io" "net/url" "os" "regexp" "strings" ) type Error struct { Location string StatusCode int Details string Error error } func NewError(location string, statusCode int, details string, err error) *Error { return &Error{ Location: location, StatusCode: statusCode, Details: details, Error: err, } } type Authenticator struct { EmailAddress string Password string Proxy string Session tls_client.HttpClient UserAgent string State string URL string PUID string Verifier_code string Verifier_challenge string AuthResult AuthResult } type ArkoseToken struct { Token string `json:"token"` ChallengeURL string `json:"challenge_url"` ChallengeURLCDN string `json:"challenge_url_cdn"` ChallengeURLCDNSRI *string `json:"challenge_url_cdn_sri"` } type AuthResult struct { AccessToken map[string]interface{} `json:"access_token"` PUID string `json:"puid"` FreshToken string `json:"fresh_token"` Model map[string]interface{} `json:"model"` } func NewAuthenticator(emailAddress, password string, puid string) *Authenticator { auth := &Authenticator{ EmailAddress: emailAddress, Password: password, Proxy: os.Getenv("proxy"), PUID: puid, UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36", } jar := tls_client.NewCookieJar() cookie := &http.Cookie{ Name: "_puid", Value: puid, Path: "/", Domain: ".openai.com", } urls, _ := url.Parse("https://openai.com") jar.SetCookies(urls, []*http.Cookie{cookie}) options := []tls_client.HttpClientOption{ tls_client.WithTimeoutSeconds(20), tls_client.WithClientProfile(profiles.Chrome_109), tls_client.WithNotFollowRedirects(), tls_client.WithCookieJar(jar), tls_client.WithProxyUrl(env.E.Proxy), } auth.Session, _ = tls_client.NewHttpClient(tls_client.NewNoopLogger(), options...) return auth } func (auth *Authenticator) URLEncode(str string) string { return url.QueryEscape(str) } func (auth *Authenticator) Begin() *Error { logger.Log.Debug("Auth Begin") target := "https://" + env.E.OpenaiHost + "/api/auth/csrf" req, err := http.NewRequest("GET", target, nil) if err != nil { return NewError("begin", 0, "", err) } req.Header.Set("Host", ""+env.E.OpenaiHost+"") req.Header.Set("Accept", "*/*") req.Header.Set("Connection", "keep-alive") req.Header.Set("User-Agent", auth.UserAgent) req.Header.Set("Accept-Language", "en-GB,en-US;q=0.9,en;q=0.8") req.Header.Set("Referer", "https://"+env.E.OpenaiHost+"/auth/login") req.Header.Set("Accept-Encoding", "gzip, deflate, br") resp, err := auth.Session.Do(req) if err != nil { return NewError("begin", 0, "", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return NewError("begin", 0, "", err) } if resp.StatusCode == 200 && strings.Contains(resp.Header.Get("Content-Type"), "json") { var csrfTokenResponse struct { CsrfToken string `json:"csrfToken"` } err = json.Unmarshal(body, &csrfTokenResponse) if err != nil { return NewError("begin", 0, "", err) } csrfToken := csrfTokenResponse.CsrfToken return auth.partOne(csrfToken) } else { err := NewError("begin", resp.StatusCode, string(body), fmt.Errorf("error: Check details")) return err } } func (auth *Authenticator) partOne(csrfToken string) *Error { logger.Log.Debug("Auth One") auth_url := "https://" + env.E.OpenaiHost + "/api/auth/signin/auth0?prompt=login" headers := map[string]string{ "Host": "" + env.E.OpenaiHost + "", "User-Agent": auth.UserAgent, "Content-Type": "application/x-www-form-urlencoded", "Accept": "*/*", "Sec-Gpc": "1", "Accept-Language": "en-US,en;q=0.8", "Origin": "https://" + env.E.OpenaiHost + "", "Sec-Fetch-Site": "same-origin", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Dest": "empty", "Referer": "https://" + env.E.OpenaiHost + "/auth/login", "Accept-Encoding": "gzip, deflate", } // Construct payload payload := fmt.Sprintf("callbackUrl=%%2F&csrfToken=%s&json=true", csrfToken) req, _ := http.NewRequest("POST", auth_url, strings.NewReader(payload)) for k, v := range headers { req.Header.Set(k, v) } resp, err := auth.Session.Do(req) if err != nil { return NewError("part_one", 0, "Failed to send request", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return NewError("part_one", 0, "Failed to read requestbody", err) } if resp.StatusCode == 200 && strings.Contains(resp.Header.Get("Content-Type"), "json") { var urlResponse struct { URL string `json:"url"` } err = json.Unmarshal(body, &urlResponse) if err != nil { return NewError("part_one", 0, "Failed to decode JSON", err) } if urlResponse.URL == "https://"+env.E.OpenaiHost+"/api/auth/error?error=OAuthSignin" || strings.Contains(urlResponse.URL, "error") { err := NewError("part_one", resp.StatusCode, "You have been rate limited. Please try again later.", fmt.Errorf("error: Check details")) return err } return auth.partTwo(urlResponse.URL) } else { return NewError("part_one", resp.StatusCode, string(body), fmt.Errorf("error: Check details")) } } func (auth *Authenticator) partTwo(target string) *Error { logger.Log.Debug("Auth Two") headers := map[string]string{ "Host": "auth0.openai.com", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Connection": "keep-alive", "User-Agent": auth.UserAgent, "Accept-Language": "en-US,en;q=0.9", "Referer": "https://chat.openai.com/", "Sec-Ch-Ua": "\"Not A(Brand\";v=\"99\", \"Google Chrome\";v=\"121\", \"Chromium\";v=\"121\"", "Sec-Ch-Ua-Arch": "\"x86\"", "Sec-Ch-Ua-Bitness": "\"64\"", "Sec-Ch-Ua-Full-Version": "\"121.0.6167.161\"", "Sec-Ch-Ua-Full-Version-List": "\"Not A(Brand\";v=\"99.0.0.0\", \"Google Chrome\";v=\"121.0.6167.161\", \"Chromium\";v=\"121.0.6167.161\"", } req, _ := http.NewRequest("GET", target, nil) for k, v := range headers { req.Header.Set(k, v) } resp, err := auth.Session.Do(req) if err != nil { return NewError("part_two", 0, "Failed to make request", err) } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) if resp.StatusCode == 302 || resp.StatusCode == 200 { stateRegex := regexp.MustCompile(`state=(.*)`) stateMatch := stateRegex.FindStringSubmatch(string(body)) if len(stateMatch) < 2 { return NewError("part_two", 0, "Could not find state in response", fmt.Errorf("error: Check details")) } state := strings.Split(stateMatch[1], `"`)[0] return auth.partThree(state) } else { return NewError("part_two", resp.StatusCode, string(body), fmt.Errorf("error: Check details")) } } func (auth *Authenticator) partThree(state string) *Error { logger.Log.Debug("Auth Three") target := fmt.Sprintf("https://auth0.openai.com/u/login/identifier?state=%s", state) emailURLEncoded := auth.URLEncode(auth.EmailAddress) payload := fmt.Sprintf( "state=%s&username=%s&js-available=false&webauthn-available=true&is-brave=false&webauthn-platform-available=true&action=default", state, emailURLEncoded, ) headers := map[string]string{ "Host": "auth0.openai.com", "Origin": "https://auth0.openai.com", "Connection": "keep-alive", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "User-Agent": auth.UserAgent, "Referer": fmt.Sprintf("https://auth0.openai.com/u/login/identifier?state=%s", state), "Accept-Language": "en-US,en;q=0.9", "Content-Type": "application/x-www-form-urlencoded", } req, _ := http.NewRequest("POST", target, strings.NewReader(payload)) for k, v := range headers { req.Header.Set(k, v) } resp, err := auth.Session.Do(req) if err != nil { return NewError("part_three", 0, "Failed to send request", err) } defer resp.Body.Close() if resp.StatusCode == 302 || resp.StatusCode == 200 { return auth.partFour(state) } else { return NewError("part_three", resp.StatusCode, "Your email address is invalid.", fmt.Errorf("error: Check details")) } } func (auth *Authenticator) partFour(state string) *Error { logger.Log.Debug("Auth Four") target := fmt.Sprintf("https://auth0.openai.com/u/login/password?state=%s", state) emailURLEncoded := auth.URLEncode(auth.EmailAddress) passwordURLEncoded := auth.URLEncode(auth.Password) payload := fmt.Sprintf("state=%s&username=%s&password=%s", state, emailURLEncoded, passwordURLEncoded) headers := map[string]string{ "Host": "auth0.openai.com", "Origin": "https://auth0.openai.com", "Connection": "keep-alive", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "User-Agent": auth.UserAgent, "Referer": fmt.Sprintf("https://auth0.openai.com/u/login/password?state=%s", state), "Accept-Language": "en-US,en;q=0.9", "Content-Type": "application/x-www-form-urlencoded", } req, _ := http.NewRequest("POST", target, strings.NewReader(payload)) for k, v := range headers { req.Header.Set(k, v) } token, err := funcaptcha.GetOpenAIArkoseToken(0, auth.PUID) if err != nil { return NewError("part_four", 0, "get arkose_token failed", err) } cookie := &http.Cookie{ Name: "arkoseToken", Value: token, Path: "/", } req.AddCookie(cookie) resp, err := auth.Session.Do(req) if err != nil { return NewError("part_four", 0, "Failed to send request", err) } defer resp.Body.Close() if resp.StatusCode == 302 { redirectURL := resp.Header.Get("Location") println(redirectURL) return auth.partFive(state, redirectURL) } else { var body interface{} if err := json.NewDecoder(resp.Body).Decode(&body); err != nil { return NewError("part_four", 0, "", err) } return NewError("part_four", resp.StatusCode, body.(string), fmt.Errorf("error: Check details")) } } func (auth *Authenticator) partFive(oldState string, redirectURL string) *Error { logger.Log.Debug("Auth Five") target := "https://auth0.openai.com" + redirectURL headers := map[string]string{ "Host": "auth0.openai.com", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Connection": "keep-alive", "User-Agent": auth.UserAgent, "Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8", "Referer": fmt.Sprintf("https://auth0.openai.com/u/login/password?state=%s", oldState), } req, _ := http.NewRequest("GET", target, nil) for k, v := range headers { req.Header.Set(k, v) } resp, err := auth.Session.Do(req) if err != nil { return NewError("part_five", 0, "Failed to send request", err) } defer resp.Body.Close() if resp.StatusCode == 302 { return auth.partSix(resp.Header.Get("Location"), target) } else { return NewError("part_five", resp.StatusCode, resp.Status, fmt.Errorf("error: Check details")) } } func (auth *Authenticator) partSix(urls, redirect_url string) *Error { logger.Log.Debug("Auth Six") req, _ := http.NewRequest("GET", urls, nil) for k, v := range map[string]string{ "Host": "" + env.E.OpenaiHost + "", "Accept": "application/json", "Connection": "keep-alive", "User-Agent": auth.UserAgent, "Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8", "Referer": redirect_url, } { req.Header.Set(k, v) } resp, err := auth.Session.Do(req) if err != nil { return NewError("part_six", 0, "Failed to send request", err) } defer resp.Body.Close() if err != nil { return NewError("part_six", 0, "Response was not JSON", err) } if resp.StatusCode != 302 { return NewError("part_six", resp.StatusCode, urls, fmt.Errorf("incorrect response code")) } // Check location header if location := resp.Header.Get("Location"); location != "https://"+env.E.OpenaiHost+"/" { return NewError("part_six", resp.StatusCode, location, fmt.Errorf("incorrect redirect")) } sessionUrl := "https://" + env.E.OpenaiHost + "/api/auth/session" req, _ = http.NewRequest("GET", sessionUrl, nil) // Set user agent req.Header.Set("User-Agent", auth.UserAgent) resp, err = auth.Session.Do(req) if err != nil { return NewError("get_access_token", 0, "Failed to send request", err) } if resp.StatusCode != 200 { return NewError("get_access_token", resp.StatusCode, "Incorrect response code", fmt.Errorf("error: Check details")) } var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return NewError("get_access_token", 0, "", err) } // Check if access token in data if _, ok := result["accessToken"]; !ok { resultString := fmt.Sprintf("%v", result) return NewError("part_six", 0, resultString, fmt.Errorf("missing access token")) } cookieUrl, _ := url.Parse("https://" + env.E.OpenaiHost + "") jar := auth.Session.GetCookies(cookieUrl) auth.AuthResult.AccessToken = result for _, cookie := range jar { if cookie.Name == "__Secure-next-auth.session-token" { auth.AuthResult.FreshToken = cookie.Value } } return nil } func (auth *Authenticator) GetAccessTokenByRefreshToken(freshToken string) *Error { logger.Log.Debug("GetAccessTokenByRefreshToken") sessionUrl := "https://" + env.E.OpenaiHost + "/api/auth/session" req, _ := http.NewRequest("GET", sessionUrl, nil) cookies := &http.Cookie{ Name: "__Secure-next-auth.session-token", Value: freshToken, } req.AddCookie(cookies) // Set user agent req.Header.Set("User-Agent", auth.UserAgent) resp, err := auth.Session.Do(req) if err != nil { return NewError("GetAccessTokenByRefreshToken", 0, "Failed to send request", err) } if resp.StatusCode != 200 { return NewError("GetAccessTokenByRefreshToken", resp.StatusCode, "Incorrect response code", fmt.Errorf("error: Check details")) } var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return NewError("GetAccessTokenByRefreshToken", 0, "", err) } // Check if access token in data if _, ok := result["accessToken"]; !ok { resultString := fmt.Sprintf("%v", result) return NewError("GetAccessTokenByRefreshToken", 0, resultString, fmt.Errorf("missing access token")) } cookieUrl, _ := url.Parse("https://" + env.E.OpenaiHost + "") jar := auth.Session.GetCookies(cookieUrl) auth.AuthResult.AccessToken = result for _, cookie := range jar { if cookie.Name == "__Secure-next-auth.session-token" { auth.AuthResult.FreshToken = cookie.Value } } return nil } func (auth *Authenticator) GetAccessToken() map[string]interface{} { logger.Log.Debug("GetAccessToken") return auth.AuthResult.AccessToken } func (auth *Authenticator) GetRefreshToken() string { logger.Log.Debug("GetRefreshToken") return auth.AuthResult.FreshToken } func (auth *Authenticator) GetModels() (map[string]interface{}, *Error) { logger.Log.Debug("GetModels") if len(auth.AuthResult.AccessToken) == 0 { return nil, NewError("get_model", 0, "Missing access token", fmt.Errorf("error: Check details")) } // Make request to https://"+common.E.OpenAI_HOST+"/backend-api/models req, _ := http.NewRequest("GET", "https://"+env.E.OpenaiHost+"/backend-api/models", nil) // Add headers req.Header.Add("Authorization", "Bearer "+auth.AuthResult.AccessToken["accessToken"].(string)) req.Header.Add("User-Agent", auth.UserAgent) req.Header.Add("Accept", "application/json") req.Header.Add("Accept-Language", "en-US,en;q=0.9") req.Header.Add("Referer", "https://"+env.E.OpenaiHost+"/") req.Header.Add("Origin", "https://"+env.E.OpenaiHost+"") req.Header.Add("Connection", "keep-alive") resp, err := auth.Session.Do(req) if err != nil { return nil, NewError("get_model", 0, "Failed to make request", err) } defer resp.Body.Close() if resp.StatusCode != 200 { return nil, NewError("get_model", resp.StatusCode, "Failed to make request", fmt.Errorf("error: Check details")) } var responseBody map[string]interface{} r, err := io.ReadAll(resp.Body) if err != nil { return nil, NewError("get_model", resp.StatusCode, "Failed to get response", fmt.Errorf("error: Check details")) } if err := json.Unmarshal(r, &responseBody); err != nil { return nil, NewError("get_model", resp.StatusCode, "Failed to get response", fmt.Errorf("error: Check details")) } auth.AuthResult.Model = responseBody return responseBody, nil } func (auth *Authenticator) GetPUID() (string, *Error) { logger.Log.Debug("GetPUID") // Check if user has access token if len(auth.AuthResult.AccessToken) == 0 { return "", NewError("get_puid", 0, "Missing access token", fmt.Errorf("error: Check details")) } // Make request to https://"+common.E.OpenAI_HOST+"/backend-api/models req, _ := http.NewRequest("GET", "https://"+env.E.OpenaiHost+"/backend-api/models", nil) // Add headers req.Header.Add("Authorization", "Bearer "+auth.AuthResult.AccessToken["accessToken"].(string)) req.Header.Add("User-Agent", auth.UserAgent) req.Header.Add("Accept", "application/json") req.Header.Add("Accept-Language", "en-US,en;q=0.9") req.Header.Add("Referer", "https://"+env.E.OpenaiHost+"/") req.Header.Add("Origin", "https://"+env.E.OpenaiHost+"") req.Header.Add("Connection", "keep-alive") resp, err := auth.Session.Do(req) if err != nil { return "", NewError("get_puid", 0, "Failed to make request", err) } defer resp.Body.Close() if resp.StatusCode != 200 { return "", NewError("get_puid", resp.StatusCode, "Failed to make request", fmt.Errorf("error: Check details")) } // Find `_puid` cookie in response for _, cookie := range resp.Cookies() { if cookie.Name == "_puid" { auth.AuthResult.PUID = cookie.Value return cookie.Value, nil } } // If cookie not found, return error return "", NewError("get_puid", 0, "PUID cookie not found", fmt.Errorf("error: Check details")) } func (auth *Authenticator) GetAuthResult() AuthResult { logger.Log.Debug("GetAuthResult") return auth.AuthResult }