package chatgpt import ( "encoding/json" "fmt" "log" "net/http" "gpt-plus/pkg/httpclient" ) const ( defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36" chatGPTOrigin = "https://chatgpt.com" ) // defaultLanguage is the package-level language setting used by standalone functions // that don't have access to a Session. Set via SetDefaultLanguage(). var defaultLanguage = "en-US" // StatusFunc is a callback for reporting progress to the user. type StatusFunc func(format string, args ...interface{}) // GetDefaultUA returns the default User-Agent string. func GetDefaultUA() string { return defaultUserAgent } // SetDefaultLanguage sets the default oai-language for standalone functions (CheckAccount, etc.). func SetDefaultLanguage(lang string) { if lang != "" { defaultLanguage = lang } } // GetDefaultLanguage returns the current default language setting. func GetDefaultLanguage() string { return defaultLanguage } // Session holds authentication state for a ChatGPT session. type Session struct { Client *httpclient.Client AccessToken string RefreshToken string IDToken string DeviceID string AccountID string UserID string Language string // browser locale e.g. "en-US" — derived from card country } // NewSession creates a new Session with all auth details. func NewSession(client *httpclient.Client, accessToken, refreshToken, idToken, deviceID, accountID, userID string) *Session { return &Session{ Client: client, AccessToken: accessToken, RefreshToken: refreshToken, IDToken: idToken, DeviceID: deviceID, AccountID: accountID, UserID: userID, } } // AuthHeaders returns common headers required for ChatGPT API requests. func (s *Session) AuthHeaders() map[string]string { lang := s.Language if lang == "" { lang = defaultLanguage } return map[string]string{ "Authorization": "Bearer " + s.AccessToken, "User-Agent": defaultUserAgent, "Accept": "*/*", "Content-Type": "application/json", "Origin": chatGPTOrigin, "Referer": chatGPTOrigin + "/", "oai-device-id": s.DeviceID, "oai-language": lang, } } // RefreshSession calls /api/auth/session to get a fresh access token // (reflecting current plan status after Plus/Team activation). func (s *Session) RefreshSession() error { sessionURL := "https://chatgpt.com/api/auth/session" headers := map[string]string{ "User-Agent": defaultUserAgent, "Accept": "application/json", "Origin": chatGPTOrigin, "Referer": chatGPTOrigin + "/", } resp, err := s.Client.Get(sessionURL, headers) if err != nil { return fmt.Errorf("refresh session request: %w", err) } body, err := httpclient.ReadBody(resp) if err != nil { return fmt.Errorf("read refresh session body: %w", err) } if resp.StatusCode != http.StatusOK { return fmt.Errorf("refresh session returned %d: %s", resp.StatusCode, string(body)) } var result struct { AccessToken string `json:"accessToken"` RefreshToken string `json:"refreshToken"` IDToken string `json:"idToken"` } if err := json.Unmarshal(body, &result); err != nil { return fmt.Errorf("parse refresh session response: %w", err) } if result.AccessToken != "" { s.AccessToken = result.AccessToken } if result.RefreshToken != "" { s.RefreshToken = result.RefreshToken } if result.IDToken != "" { s.IDToken = result.IDToken } log.Printf("[session] tokens refreshed successfully") return nil }