package storage import ( "encoding/json" "fmt" "os" "path/filepath" "time" "gpt-plus/pkg/chatgpt" ) // SaveAccount saves an AccountResult to a JSON file named {email}.json in outputDir. func SaveAccount(outputDir string, result *chatgpt.AccountResult) error { if err := os.MkdirAll(outputDir, 0o755); err != nil { return fmt.Errorf("create output dir: %w", err) } filename := filepath.Join(outputDir, result.Email+".json") data, err := json.MarshalIndent(result, "", " ") if err != nil { return fmt.Errorf("marshal account result: %w", err) } if err := os.WriteFile(filename, data, 0o644); err != nil { return fmt.Errorf("write account file: %w", err) } return nil } // authFile mirrors the auth.json format used by sub2api / other tools. type authFile struct { OpenAIAPIKey string `json:"OPENAI_API_KEY"` AccessToken string `json:"access_token"` IDToken string `json:"id_token"` LastRefresh string `json:"last_refresh"` RefreshToken string `json:"refresh_token"` Tokens authTokens `json:"tokens"` } type authTokens struct { AccessToken string `json:"access_token"` AccountID string `json:"account_id"` IDToken string `json:"id_token"` LastRefresh string `json:"last_refresh"` RefreshToken string `json:"refresh_token"` } // SavePlusAuthFile saves a Plus auth.json file (personal token) to outputDir/plus/. func SavePlusAuthFile(outputDir string, result *chatgpt.AccountResult) error { dir := filepath.Join(outputDir, "plus") if err := os.MkdirAll(dir, 0o755); err != nil { return fmt.Errorf("create plus output dir: %w", err) } now := time.Now().UTC().Format("2006-01-02T15:04:05Z") auth := &authFile{ OpenAIAPIKey: "", AccessToken: result.AccessToken, IDToken: result.IDToken, LastRefresh: now, RefreshToken: result.RefreshToken, Tokens: authTokens{ AccessToken: result.AccessToken, AccountID: result.ChatGPTAccountID, IDToken: result.IDToken, LastRefresh: now, RefreshToken: result.RefreshToken, }, } filename := filepath.Join(dir, result.Email+".auth.json") data, err := json.MarshalIndent(auth, "", " ") if err != nil { return fmt.Errorf("marshal plus auth file: %w", err) } if err := os.WriteFile(filename, data, 0o644); err != nil { return fmt.Errorf("write plus auth file: %w", err) } return nil } // SaveTeamAuthFile saves a Team auth.json file (workspace token) to outputDir/team/. func SaveTeamAuthFile(outputDir string, result *chatgpt.AccountResult) error { dir := filepath.Join(outputDir, "team") if err := os.MkdirAll(dir, 0o755); err != nil { return fmt.Errorf("create team output dir: %w", err) } now := time.Now().UTC().Format("2006-01-02T15:04:05Z") // Prefer WorkspaceToken, fallback to AccessToken token := result.WorkspaceToken if token == "" { token = result.AccessToken } auth := &authFile{ OpenAIAPIKey: "", AccessToken: token, IDToken: result.IDToken, LastRefresh: now, RefreshToken: result.RefreshToken, Tokens: authTokens{ AccessToken: token, AccountID: result.TeamAccountID, IDToken: result.IDToken, LastRefresh: now, RefreshToken: result.RefreshToken, }, } filename := filepath.Join(dir, result.Email+".auth.json") data, err := json.MarshalIndent(auth, "", " ") if err != nil { return fmt.Errorf("marshal team auth file: %w", err) } if err := os.WriteFile(filename, data, 0o644); err != nil { return fmt.Errorf("write team auth file: %w", err) } return nil } // SaveFreeAuthFile saves a free account auth.json file (personal token) to outputDir/free/. func SaveFreeAuthFile(outputDir string, result *chatgpt.AccountResult) error { dir := filepath.Join(outputDir, "free") if err := os.MkdirAll(dir, 0o755); err != nil { return fmt.Errorf("create free output dir: %w", err) } now := time.Now().UTC().Format("2006-01-02T15:04:05Z") auth := &authFile{ OpenAIAPIKey: "", AccessToken: result.AccessToken, IDToken: result.IDToken, LastRefresh: now, RefreshToken: result.RefreshToken, Tokens: authTokens{ AccessToken: result.AccessToken, AccountID: result.ChatGPTAccountID, IDToken: result.IDToken, LastRefresh: now, RefreshToken: result.RefreshToken, }, } filename := filepath.Join(dir, result.Email+".auth.json") data, err := json.MarshalIndent(auth, "", " ") if err != nil { return fmt.Errorf("marshal free auth file: %w", err) } if err := os.WriteFile(filename, data, 0o644); err != nil { return fmt.Errorf("write free auth file: %w", err) } return nil }