access []string
}
-// token returns a new access token that expires after ttl, for a token file
-// that a test writes.
-func (f *ChatGPTFake) token(ttl time.Duration) string {
- f.mutex.Lock()
- defer f.mutex.Unlock()
+func newChatGPTFake(t *testing.T) *ChatGPTFake {
+ t.Helper()
- return f.newToken(ttl)
-}
+ f := &ChatGPTFake{}
+ mux := http.NewServeMux()
+ mux.HandleFunc("POST /api/accounts/deviceauth/usercode", f.userCode)
+ mux.HandleFunc("POST /api/accounts/deviceauth/token", f.deviceToken)
+ mux.HandleFunc("POST /oauth/token", f.oauthToken)
-// newToken returns a new fake JWT with the expiry and the account claim, and
-// keeps it in access. The caller holds the mutex.
-func (f *ChatGPTFake) newToken(ttl time.Duration) string {
- claims, err := json.Marshal(map[string]any{
- "exp": time.Now().Add(ttl).Unix(),
- chatgptAuthClaim: map[string]any{
- "chatgpt_account_id": chatgptTestAccount,
- },
- "serial": len(f.access),
- })
- if err != nil {
- panic(err)
- }
+ f.Server = httptest.NewServer(mux)
+ t.Cleanup(f.Close)
- encode := base64.RawURLEncoding.EncodeToString
- token := encode([]byte(`{"alg":"none"}`)) + "." + encode(claims) + "." + encode([]byte("fake"))
- f.access = append(f.access, token)
+ return f
+}
- return token
+func newTestChatGPTAuth(t *testing.T, server *ChatGPTFake) *ChatGPTAuth {
+ t.Helper()
+
+ return newChatGPTAuth(filepath.Join(t.TempDir(), chatgptTokenFileName), server.URL)
}
func (f *ChatGPTFake) userCode(w http.ResponseWriter, r *http.Request) {
var body map[string]string
+
err := json.NewDecoder(r.Body).Decode(&body)
if err != nil || body["client_id"] != chatgptClientID {
http.Error(w, "bad client", http.StatusBadRequest)
+
return
}
defer f.mutex.Unlock()
var body map[string]string
+
err := json.NewDecoder(r.Body).Decode(&body)
if err != nil || body["device_auth_id"] != "device-1" || body["user_code"] != "CODE-1234" {
http.Error(w, "bad device", http.StatusBadRequest)
+
return
}
f.polls++
if f.deny {
http.Error(w, "denied", http.StatusBadRequest)
+
return
}
if f.polls <= f.pending {
http.Error(w, "pending", http.StatusForbidden)
+
return
}
err := r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
+
return
}
}
var body map[string]string
+
err := json.NewDecoder(r.Body).Decode(&body)
if err != nil || body["grant_type"] != "refresh_token" || body["client_id"] != chatgptClientID {
http.Error(w, "bad refresh", http.StatusBadRequest)
+
return
}
f.refreshed = body["refresh_token"]
if f.failRefresh {
http.Error(w, `{"error": "invalid_grant", "token": "`+body["refresh_token"]+`"}`, http.StatusUnauthorized)
+
return
}
chatgptWriteJSON(w, answer)
}
-func newChatGPTFake(t *testing.T) *ChatGPTFake {
- t.Helper()
+// newToken returns a new fake JWT with the expiry and the account claim, and
+// keeps it in access. The caller holds the mutex.
+func (f *ChatGPTFake) newToken(ttl time.Duration) string {
+ claims, err := json.Marshal(map[string]any{
+ "exp": time.Now().Add(ttl).Unix(),
+ chatgptAuthClaim: map[string]any{
+ "chatgpt_account_id": chatgptTestAccount,
+ },
+ "serial": len(f.access),
+ })
+ if err != nil {
+ panic(err)
+ }
- f := &ChatGPTFake{}
- mux := http.NewServeMux()
- mux.HandleFunc("POST /api/accounts/deviceauth/usercode", f.userCode)
- mux.HandleFunc("POST /api/accounts/deviceauth/token", f.deviceToken)
- mux.HandleFunc("POST /oauth/token", f.oauthToken)
- f.Server = httptest.NewServer(mux)
- t.Cleanup(f.Close)
+ encode := base64.RawURLEncoding.EncodeToString
+ token := encode([]byte(`{"alg":"none"}`)) + "." + encode(claims) + "." + encode([]byte("fake"))
+ f.access = append(f.access, token)
- return f
+ return token
}
-func newTestChatGPTAuth(t *testing.T, server *ChatGPTFake) *ChatGPTAuth {
- t.Helper()
+// token returns a new access token that expires after ttl, for a token file
+// that a test writes.
+func (f *ChatGPTFake) token(ttl time.Duration) string {
+ f.mutex.Lock()
+ defer f.mutex.Unlock()
- return newChatGPTAuth(filepath.Join(t.TempDir(), chatgptTokenFileName), server.URL)
+ return f.newToken(ttl)
+}
+
+func chatgptWriteJSON(w http.ResponseWriter, value any) {
+ w.Header().Set("Content-Type", "application/json")
+
+ err := json.NewEncoder(w).Encode(value)
+ if err != nil {
+ panic(fmt.Sprint("encode answer: ", err))
+ }
}
func chatgptWriteTestTokens(t *testing.T, auth *ChatGPTAuth, access, refresh string) {
})
require.NoError(t, err)
}
-
-func chatgptWriteJSON(w http.ResponseWriter, value any) {
- w.Header().Set("Content-Type", "application/json")
- err := json.NewEncoder(w).Encode(value)
- if err != nil {
- panic(fmt.Sprint("encode answer: ", err))
- }
-}