-// write replaces the token file atomically. The file has mode 0600.
-func (a *ChatGPTAuth) write(tokens ChatGPTTokenFile) error {
- data, err := json.Marshal(tokens)
- if err != nil {
- return fmt.Errorf("encode tokens: %w", err)
- }
-
- err = writeFileAtomic(a.path, append(data, '\n'))
- if err != nil {
- return fmt.Errorf("write token file: %w", err)
- }
-
- return nil
-}
-
-// post posts body to the path of the login service and decodes a 200 answer
-// into result. It returns the HTTP status, or 0 when no answer came. The error
-// holds the status, but not the body, which can hold a token.
-func (a *ChatGPTAuth) post(ctx context.Context, path, contentType string, body []byte, result any) (status int, err error) {
- request, err := http.NewRequestWithContext(ctx, http.MethodPost, a.issuer+path, bytes.NewReader(body))
- if err != nil {
- return 0, fmt.Errorf("create request: %w", err)
- }
-
- request.Header.Set("Content-Type", contentType)
- response, err := a.http.Do(request)
- if err != nil {
- return 0, fmt.Errorf("send request: %w", err)
- }
-
- defer func() {
- err = errors.Join(err, response.Body.Close())
- }()
-
- if response.StatusCode != http.StatusOK {
- return response.StatusCode, fmt.Errorf("HTTP %d", response.StatusCode)
- }
-
- err = json.NewDecoder(response.Body).Decode(result)
- if err != nil {
- return response.StatusCode, fmt.Errorf("decode answer: %w", err)
- }
-
- return response.StatusCode, nil
-}
-
-// ChatGPTDeviceCode is the answer of the user code endpoint. The interval is a
-// number or a string of seconds.
-type ChatGPTDeviceCode struct {
- DeviceAuthID string `json:"device_auth_id"`
- UserCode string `json:"user_code"`
- UserCodeAlt string `json:"usercode"`
- Interval json.RawMessage `json:"interval"`
-}
-
-// ChatGPTTokenFile is the content of the token file.
-type ChatGPTTokenFile struct {
- AccessToken string `json:"access_token"`
- RefreshToken string `json:"refresh_token"`
- IDToken string `json:"id_token"`
- AccountID string `json:"account_id"`
-}
-
-// ChatGPTTokenResponse is the answer of the token endpoint.
-type ChatGPTTokenResponse struct {
- AccessToken string `json:"access_token"`
- RefreshToken string `json:"refresh_token"`
- IDToken string `json:"id_token"`
-}
-
-// ChatGPTDeviceGrant is the answer of the device token endpoint after the user
-// approves the code.
-type ChatGPTDeviceGrant struct {
- AuthorizationCode string `json:"authorization_code"`
- CodeVerifier string `json:"code_verifier"`
-}
-