| package bootstrap |
|
|
| import ( |
| "os" |
| "strings" |
| "time" |
|
|
| "aurora/internal/accounts" |
| "aurora/internal/browserfp" |
| "aurora/internal/chatgpt" |
| "aurora/internal/config" |
| "aurora/internal/handler" |
| "aurora/internal/proxy" |
|
|
| "github.com/gin-gonic/gin" |
| "github.com/google/uuid" |
| "github.com/joho/godotenv" |
| ) |
|
|
| |
| type App struct { |
| Router *gin.Engine |
| Config *config.Config |
| AccountPool *accounts.Pool |
| Cleanup func() |
| } |
|
|
| |
| func Init() (*App, error) { |
| gin.SetMode(gin.ReleaseMode) |
| _ = godotenv.Load(".env") |
| browserfp.Init() |
|
|
| cfg := config.Load() |
|
|
| proxies := loadProxyList() |
| proxyPool := proxy.NewPool(proxies) |
|
|
| |
|
|
| profiles := accounts.DefaultProfiles |
| var accs []*accounts.Account |
|
|
| |
| seen := make(map[string]bool) |
|
|
| |
| for _, t := range accounts.LoadTokensFromFile("access_tokens.txt") { |
| |
| chatGPTID := accounts.ExtractChatGPTAccountID(t.Token) |
| key := "access:" + chatGPTID |
| if seen[key] { |
| continue |
| } |
| seen[key] = true |
|
|
| acct := accounts.CreateAccount(t.Token, accounts.TypeFree, profiles) |
| acct.TeamUserID = t.TeamID |
| acct.ChatGPTAccountID = chatGPTID |
| acct.Status = accounts.StatusActive |
| acct.Proxy = proxyPool.Allocate() |
| accs = append(accs, acct) |
| } |
|
|
| |
| for _, t := range accounts.LoadTokensFromFile("refresh_tokens.txt") { |
| |
| |
| key := "refresh:" + t.Token |
| if seen[key] { |
| continue |
| } |
| seen[key] = true |
|
|
| acct := accounts.CreateAccount("", accounts.TypeFree, profiles) |
| acct.RefreshToken = t.Token |
| acct.TeamUserID = t.TeamID |
| acct.Proxy = proxyPool.Allocate() |
| |
| if exchangeRefreshToken(acct) { |
| |
| acct.ChatGPTAccountID = accounts.ExtractChatGPTAccountID(acct.Token) |
| acct.Status = accounts.StatusActive |
| } else { |
| acct.Status = accounts.StatusExpired |
| } |
| accs = append(accs, acct) |
| } |
|
|
| |
| for _, t := range accounts.LoadTokensFromFile("session_tokens.txt") { |
| key := "session:" + t.Token |
| if seen[key] { |
| continue |
| } |
| seen[key] = true |
|
|
| acct := accounts.CreateAccount("", accounts.TypeFree, profiles) |
| acct.SessionToken = t.Token |
| acct.Proxy = proxyPool.Allocate() |
| |
| if exchangeSessionToken(acct) { |
| |
| acct.ChatGPTAccountID = accounts.ExtractChatGPTAccountID(acct.Token) |
| acct.Status = accounts.StatusActive |
| } else { |
| acct.Status = accounts.StatusExpired |
| } |
| accs = append(accs, acct) |
| } |
|
|
| |
| for _, t := range accounts.LoadTokensFromFile("free_tokens.txt") { |
| key := "free:" + t.Token |
| if seen[key] { |
| continue |
| } |
| seen[key] = true |
|
|
| acct := accounts.CreateAccount(t.Token, accounts.TypeNoAuth, profiles) |
| acct.Proxy = proxyPool.Allocate() |
| acct.Status = accounts.StatusActive |
| accs = append(accs, acct) |
| } |
|
|
| |
| if cfg.FreeAccounts { |
| for i := 0; i < cfg.FreeAccountsNum; i++ { |
| uid := uuid.NewString() |
| |
| acct := accounts.CreateAccount(uid, accounts.TypeNoAuth, profiles) |
| acct.Proxy = proxyPool.Allocate() |
| acct.Status = accounts.StatusActive |
| accs = append(accs, acct) |
| } |
| } |
|
|
| |
| for _, acct := range accs { |
| _ = acct.InitClient() |
| } |
|
|
| accountPool := accounts.NewPool(accs) |
|
|
| |
| renewFn := func(acct *accounts.Account) bool { |
| if acct.RefreshToken != "" { |
| return exchangeRefreshToken(acct) |
| } |
| if acct.SessionToken != "" { |
| return exchangeSessionToken(acct) |
| } |
| return false |
| } |
| stopHealthCheck := accountPool.StartHealthCheck(10*time.Minute, renewFn) |
| stopTempGC := accountPool.StartTempAccountGC(10*time.Minute, 1*time.Minute) |
|
|
| |
| router := handler.RegisterRouter(accountPool, &cfg) |
|
|
| return &App{ |
| Router: router, |
| Config: &cfg, |
| AccountPool: accountPool, |
| Cleanup: func() { |
| stopHealthCheck() |
| stopTempGC() |
| }, |
| }, nil |
| } |
|
|
| |
| func exchangeRefreshToken(acct *accounts.Account) bool { |
| if acct.RefreshToken == "" { |
| return false |
| } |
| if acct.Client == nil { |
| _ = acct.InitClient() |
| } |
| result, _, err := chatgpt.GETTokenForRefreshToken(acct.Client, acct.RefreshToken, "") |
| if err != nil { |
| return false |
| } |
| |
| if r, ok := result.(interface{ GetAccessToken() string }); ok { |
| if at := r.GetAccessToken(); at != "" { |
| acct.Token = at |
| return true |
| } |
| } |
| |
| if data, ok := result.(map[string]interface{}); ok { |
| if accessToken, ok := data["access_token"].(string); ok && accessToken != "" { |
| acct.Token = accessToken |
| return true |
| } |
| } |
| return false |
| } |
|
|
| |
| func exchangeSessionToken(acct *accounts.Account) bool { |
| if acct.SessionToken == "" { |
| return false |
| } |
| if acct.Client == nil { |
| _ = acct.InitClient() |
| } |
| result, _, err := chatgpt.GETTokenForSessionToken(acct.Client, acct.SessionToken, "") |
| if err != nil { |
| return false |
| } |
| |
| if r, ok := result.(interface{ GetAccessToken() string }); ok { |
| if at := r.GetAccessToken(); at != "" { |
| acct.Token = at |
| return true |
| } |
| } |
| |
| if data, ok := result.(map[string]interface{}); ok { |
| if accessToken, ok := data["accessToken"].(string); ok && accessToken != "" { |
| acct.Token = accessToken |
| return true |
| } |
| } |
| return false |
| } |
|
|
| |
| func loadProxyList() []string { |
| var proxies []string |
| proxyUrl := os.Getenv("PROXY_URL") |
| if proxyUrl != "" { |
| proxies = append(proxies, proxyUrl) |
| } |
|
|
| if _, err := os.Stat("proxies.txt"); err == nil { |
| data, err := os.ReadFile("proxies.txt") |
| if err == nil { |
| lines := string(data) |
| for _, line := range strings.Split(lines, "\n") { |
| line = strings.TrimSpace(line) |
| if line != "" { |
| proxies = append(proxies, line) |
| } |
| } |
| } |
| } |
|
|
| if len(proxies) == 0 { |
| proxy := os.Getenv("http_proxy") |
| if proxy != "" { |
| proxies = append(proxies, proxy) |
| } |
| } |
|
|
| return proxies |
| } |
|
|