acheong08 / ChatGPTProxy

Simple Cloudflare bypass for ChatGPT
The Unlicense
1.33k stars 325 forks source link

I have managed to resolve the SSL handshake issue with *.cdn.cloudflare.net, however, it still returns a 403 error. #76

Closed geometryEuclid closed 1 year ago

geometryEuclid commented 1 year ago

The code below has resolved the SSL handshake issue with https://chat.openai.com.cdn.cloudflare.net/backend-api/conversation, but it is still returning a 403 error. Do you have any solutions to resolve this matter?

package main

import (
    "bytes"
    "crypto/tls"
    "encoding/json"
    "fmt"
    "io"
    "net"
    "net/http"
    "os"
    "github.com/google/uuid"
)

type ConversationRequest struct {
    Action          string    `json:"action,omitempty"`
    Messages        []Message `json:"messages,omitempty"`
    ConversationID  string    `json:"conversation_id,omitempty"`
    ParentMessageID string    `json:"parent_message_id,omitempty"`
    Model           string    `json:"model,omitempty"`
    TimezoneOffset  int       `json:"timezone_offset_min,omitempty"`
    VariantPurpose  string    `json:"variant_purpose,omitempty"`
    HistoryDisabled bool      `json:"history_and_training_disabled,omitempty"`
    ArkoseToken     interface{} `json:"arkose_token,omitempty"`
}

type Message struct {
    ID       string                 `json:"id,omitempty"`
    Role     string                 `json:"role,omitempty"`
    Content  Content                `json:"content,omitempty"`
    Metadata map[string]interface{} `json:"metadata,omitempty"`
}

type Content struct {
    ContentType string   `json:"content_type,omitempty"`
    Parts       []string `json:"parts,omitempty"`
}

const accessToken = ""

func main() {

    data := &ConversationRequest{
        Action: "next",
        Messages: []Message{
            {
                ID:   uuid.NewString(),
                Role: "user",
                Content: Content{
                    ContentType: "text",
                    Parts:       []string{"hello"},
                },
                Metadata: map[string]interface{}{},
            },
        },
        ConversationID:  "",
        ParentMessageID: uuid.NewString(),
        Model:           "text-davinci-002-render-sha",
        TimezoneOffset:  0,
        VariantPurpose:  "none",
        HistoryDisabled: false,
        ArkoseToken:     nil,
    }
    jsonData, err := json.Marshal(data)
    if err != nil {
        fmt.Fprintf(os.Stderr, "error marshalling JSON: %v\n", err)
        os.Exit(1)
    }

    body := bytes.NewReader(jsonData)

    // Create TLS configuration
    config := &tls.Config{
        InsecureSkipVerify: true,
        ServerName:         "chat.openai.com.cdn.cloudflare.net",
    }

    // Establish TLS connection with the server
    conn, err := tls.Dial("tcp", "www.cloudflare.com:443", config)
    if err != nil {
        fmt.Println("Connection failed:", err)
        return
    }
    defer conn.Close()

    // Create a custom transport using the established TLS connection
    transport := &http.Transport{
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: true,
            ServerName:         "chat.openai.com.cdn.cloudflare.net",
        },
        DialTLS: func(network, addr string) (net.Conn, error) {
            return conn, nil
        },
    }

    // Create a custom HTTP client
    client := &http.Client{
        Transport: transport,
    }

    // Construct the JSON data for the POST request
    req, err := http.NewRequest("POST", "https://chat.openai.com.cdn.cloudflare.net/backend-api/conversation", body)
    if err != nil {
        fmt.Println("Failed to create request:", err)
        return
    }

    req.Header.Set("Host", "chat.openai.com")
    req.Header.Set("Origin", "https://chat.openai.com/")
    req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Connection", "keep-alive")
    req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36")

    // Send the request
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Failed to send request:", err)
        return
    }
    defer resp.Body.Close()

    // Read the response status code and body
    body2, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("Failed to read response:", err)
        return
    }

    // Print the status code and body
    fmt.Println("Status Code:", resp.StatusCode)
    fmt.Println("Response Body:", string(body2))
}
geometryEuclid commented 1 year ago

Do we have a solution or any ideas regarding the direction for problem-solving?

acheong08 commented 1 year ago

It's due to TLS fingerprinting. The current code already works with PUID (plus account)