diff --git a/Dockerfile b/Dockerfile index bb402d69..a543c7b9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,6 +10,10 @@ WORKDIR /tls # Set the working directory WORKDIR /app +# update CA certificates +RUN apk update && apk upgrade && apk add --no-cache ca-certificates +RUN update-ca-certificates + # Copy the Go Modules manifests (go.mod and go.sum files) COPY go.mod go.sum ./ diff --git a/README.md b/README.md index 1bfbeceb..138864d9 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ All authenticated access tokens and PUID will store in `access_tokens.json` Auto renew access tokens and PUID after 1 day -Caution! please use unblocked ip for authentication, first login to `https://chat.openai.com/` to check ip availability if you can. +Caution! please use unblocked ip for authentication, first login to `https://chatgpt.com/` to check ip availability if you can. ### HAR file pool @@ -35,9 +35,9 @@ Currently logged in account, using the GPT-4 model and most GPT-3.5 models, you 1. Use a chromium-based browser (Chrome, Edge) to open the browser developer tools (F12), switch to the Network tab, and check the **preserve log** option. - 2. Log in to `https://chat.openai.com/`, create a new chat and select the GPT-4 model, enter any text, switch to the GPT-3.5 model, and enter any text. + 2. Log in to `https://chatgpt.com/`, create a new chat and select the GPT-4 model, enter any text, switch to the GPT-3.5 model, and enter any text. - 3. Click the Export HAR button under the Network tab to export the file `chat.openai.com.har` and place it in the `harPool` folder of the same level as this program. + 3. Click the Export HAR button under the Network tab to export the file `chatgpt.com.har` and place it in the `harPool` folder of the same level as this program. ### API Authentication (Optional) diff --git a/README_CN.md b/README_CN.md deleted file mode 100644 index bf853c41..00000000 --- a/README_CN.md +++ /dev/null @@ -1,52 +0,0 @@ -# ChatGPT-to-API -创建一个模拟API(通过ChatGPT网页版)。使用AccessToken把ChatGPT模拟成OpenAI API,从而在各类应用程序中使用OpenAI的API且不需要为API额外付费,因为模拟成网页版的使用了,和官方API基本互相兼容。 - -本中文手册由 [@BlueSkyXN](https://github.com/BlueSkyXN) 编写 - -[英文文档(English Docs)](README.md) - -## 认证和各项准备工作 - -在使用之前,你需要完成一系列准备工作 - -1. 准备ChatGPT账号,最好的PLUS订阅的,有没有开API不重要 -2. 完善的运行环境和网络环境(否则你总是要寻找方法绕过) -3. Access Token和PUID,下面会教你怎么获取 -4. 选择一个代理后端或者自行搭建 -5. 你可以在 https://github.com/BlueSkyXN/OpenAI-Quick-DEV 项目找到一些常用组件以及一些快速运行的教程或程序。 - -### 获取PUID - -`_puid` cookie. - -### 获取Access Token -目前有多种方法和原理,这部分内容可以参考 [TOKEN中文手册](docs/TOKEN_CN.md) - -## 安装和运行 - -作者在[英文版介绍](README.md) 通过GO编译来构建二进制程序,但是我猜测这可能需要一个GO编译环境。所以我建议基于作者的Compose配置文件来Docker运行。 - -有关docker的指导请阅读 [DOCKER中文手册](docs/Docker_CN.md) - -安装好Docker和Docker-Compase后,通过Compase来启动 - -```docker-compose up -d``` - -注意,启动之前你需要配置 yml 配置文件,主要是端口和环境变量,各项参数、用法请参考 [中文指导手册](docs/GUIDE_CN.md) - -最后的API端点(Endpoint)是 - -```http://127.0.0.1:8080/v1/chat/completions``` - -注意域名/IP和端口要改成你自己的 - -### 环境变量 - - `PUID` - 用户ID - - `http_proxy` - SOCKS5 或 HTTP 代理 `socks5://HOST:PORT` - - `SERVER_HOST` - (default)比如 127.0.0.1 - - `SERVER_PORT` - (default)比如 8080 by - -### 文件选项 - - `access_tokens.json` - 附带AccessToken的Json文件 - - `proxies.txt` - 代理表 (格式: `USERNAME:PASSWORD:HOST:PORT`) - diff --git a/README_JA.md b/README_JA.md index 7195be7b..4a453879 100644 --- a/README_JA.md +++ b/README_JA.md @@ -26,7 +26,7 @@ email:password アクセストークンは 7 日後に自動更新されます -注意!認証にはブロックされていない ip を使用してください。可能であれば、まず `https://chat.openai.com/` にログインして ip の可用性を確認してください。 +注意!認証にはブロックされていない ip を使用してください。可能であれば、まず `https://chatgpt.com/` にログインして ip の可用性を確認してください。 ### API認証(オプション) diff --git a/README_ZH.md b/README_ZH.md index bb896e4d..baa6435d 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -24,7 +24,7 @@ 每天自动更新Access tokens和PUID -注意! 请使用未封锁的ip登录账号,请先打开浏览器登录`https://chat.openai.com/`以检查ip是否可用 +注意! 请使用未封锁的ip登录账号,请先打开浏览器登录`https://chatgpt.com/`以检查ip是否可用 ### HAR文件池 @@ -32,9 +32,9 @@ 1. 使用基于chromium的浏览器(Chrome,Edge)打开浏览器开发者工具(F12),并切换到网络标签页,勾选**保留日志**选项。 - 2. 登录`https://chat.openai.com/`,新建聊天并选择GPT-4模型,随意输入下文字,切换到GPT-3.5模型,随意输入下文字。 + 2. 登录`https://chatgpt.com/`,新建聊天并选择GPT-4模型,随意输入下文字,切换到GPT-3.5模型,随意输入下文字。 - 3. 点击网络标签页下的导出HAR按钮,导出文件`chat.openai.com.har`,放置到本程序同级的`harPool`文件夹里。 + 3. 点击网络标签页下的导出HAR按钮,导出文件`chatgpt.com.har`,放置到本程序同级的`harPool`文件夹里。 ### API 密钥(可选) diff --git a/conversion/requests/chatgpt/convert.go b/conversion/requests/chatgpt/convert.go index a0a67dc3..95b67a74 100644 --- a/conversion/requests/chatgpt/convert.go +++ b/conversion/requests/chatgpt/convert.go @@ -28,6 +28,7 @@ func ConvertAPIRequest(api_request official_types.APIRequest, account string, se val := api_request.Model[12:] chatgpt_request.ConversationMode.Kind = "gizmo_interaction" chatgpt_request.ConversationMode.GizmoId = val + chatgpt_request.Model = "text-davinci-002-render-sha" } } } diff --git a/docs/Docker_CN.md b/docs/Docker_CN.md index 1c48152d..50c87477 100644 --- a/docs/Docker_CN.md +++ b/docs/Docker_CN.md @@ -70,6 +70,6 @@ ``` - 这里的ports,左边是外部端口,用于外部访问。右边的Docker端口,需要匹配下面程序设置的监听Port。 -- 如果参数`API_REVERSE_PROXY`为空,则默认的请求URL为`https://chat.openai.com/backend-api/conversation`,并且需要提供PUID。PUID的获取参考 [README_CN.md](../README_CN.md) +- 如果参数`API_REVERSE_PROXY`为空,则默认的请求URL为`https://chatgpt.com/backend-api/conversation`,并且需要提供PUID。PUID的获取参考 [README_CN.md](../README_CN.md) - 这个密码需要自定义,我们构建请求的时候需要它来鉴权。默认是```TotallySecurePassword``` diff --git a/docs/TOKEN_CN.md b/docs/TOKEN_CN.md index 4f615720..b95bf9e0 100644 --- a/docs/TOKEN_CN.md +++ b/docs/TOKEN_CN.md @@ -12,7 +12,7 @@ http://ai.fakeopen.com/auth 你需要在这个新的网站的指导下安装浏览器插件,官方说明的有效期是14天。支持谷歌微软等第三方登录。(我谷歌注册的OpenAI就可以用这个) ## 官网获取 Token -https://chat.openai.com/api/auth/session +https://chatgpt.com/api/auth/session 打开后是个JSON,你需要先登录官方的ChatGPT网页版。里面有一个参数就是AccessToken。 diff --git a/go.mod b/go.mod index cc8d8941..170534d0 100644 --- a/go.mod +++ b/go.mod @@ -19,12 +19,12 @@ require ( github.com/joho/godotenv v1.5.1 github.com/sashabaranov/go-openai v1.21.0 github.com/tidwall/gjson v1.17.1 - github.com/xqdoo00o/OpenAIAuth v0.0.0-20240425072142-e599e4049d02 - github.com/xqdoo00o/funcaptcha v0.0.0-20240403090732-1b604d808f6c + github.com/xqdoo00o/OpenAIAuth v0.0.0-20240507071909-7f24aae29d9e + github.com/xqdoo00o/funcaptcha v0.0.0-20240507071758-6c32cfc34bdc github.com/zhu327/gemini-openai-proxy v0.0.0-20240328042054-d2c6c4cdff01 - golang.org/x/crypto v0.22.0 + golang.org/x/crypto v0.23.0 golang.org/x/image v0.15.0 - golang.org/x/net v0.24.0 + golang.org/x/net v0.25.0 google.golang.org/api v0.172.0 k8s.io/apimachinery v0.29.3 ) @@ -58,15 +58,13 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.8 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect - github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/quic-go/quic-go v0.43.0 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/quic-go/quic-go v0.43.1 // indirect github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect @@ -81,8 +79,8 @@ require ( golang.org/x/arch v0.7.0 // indirect golang.org/x/oauth2 v0.19.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.20.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be // indirect diff --git a/go.sum b/go.sum index 79f3ff9e..7c3038cc 100644 --- a/go.sum +++ b/go.sum @@ -35,7 +35,6 @@ github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJ github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -146,8 +145,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/quic-go/quic-go v0.43.0 h1:sjtsTKWX0dsHpuMJvLxGqoQdtgJnbAPWY+W+5vjYW/g= -github.com/quic-go/quic-go v0.43.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= +github.com/quic-go/quic-go v0.43.1 h1:fLiMNfQVe9q2JvSsiXo4fXOEguXHGGl9+6gLp4RPeZQ= +github.com/quic-go/quic-go v0.43.1/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/sashabaranov/go-openai v1.21.0 h1:isAf3zPSD3VLd0pC2/2Q6ZyRK7jzPAaz+X3rjsviaYQ= @@ -177,10 +176,10 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/xqdoo00o/OpenAIAuth v0.0.0-20240425072142-e599e4049d02 h1:l+ADAnV1KDjZkY0ccAvVYzSCGbA90xitA1aP+7yR0Yc= -github.com/xqdoo00o/OpenAIAuth v0.0.0-20240425072142-e599e4049d02/go.mod h1:XHxG7wI3Erk4nS0rwjXVF3FllYW5QxsRynnJ0GqAMCQ= -github.com/xqdoo00o/funcaptcha v0.0.0-20240403090732-1b604d808f6c h1:nj17XsSTwprsZUDXLldOUZmqz7VlHsLCeXXFOE6Q+Mk= -github.com/xqdoo00o/funcaptcha v0.0.0-20240403090732-1b604d808f6c/go.mod h1:7aCyoW5MHDUsoooMVLqKe0F7W9HMPUvDG3bXqw++8XA= +github.com/xqdoo00o/OpenAIAuth v0.0.0-20240507071909-7f24aae29d9e h1:tNV/b3/N7+5vnweAjhYlnhuF2olmj0NxvFD03R3xudE= +github.com/xqdoo00o/OpenAIAuth v0.0.0-20240507071909-7f24aae29d9e/go.mod h1:TOXe2RBzDx5/w2RYzP7C1WNfNJx1wEVOSkCBcGSaNrM= +github.com/xqdoo00o/funcaptcha v0.0.0-20240507071758-6c32cfc34bdc h1:GA82q8G/mh5LLaBAo3UWw4zvxk/BlarGSuonyK4tz3Y= +github.com/xqdoo00o/funcaptcha v0.0.0-20240507071758-6c32cfc34bdc/go.mod h1:MmsYdzgYjO6NQYNS8vtecBWUFWwD4TApVzMp8iwKiR0= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zhu327/gemini-openai-proxy v0.0.0-20240328042054-d2c6c4cdff01 h1:oTKr6NUPO0Q/8eUPf75hpZrUYfP8eQLHdVbLTWVuf/c= github.com/zhu327/gemini-openai-proxy v0.0.0-20240328042054-d2c6c4cdff01/go.mod h1:np6NnsU7xC3JTdGlOAOvWSudER6P43EnDhEvYrEL1Vc= @@ -204,8 +203,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= @@ -228,8 +227,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= @@ -254,8 +253,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -268,8 +267,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/handlers.go b/handlers.go index fafbdc45..d5554d5b 100644 --- a/handlers.go +++ b/handlers.go @@ -204,7 +204,7 @@ func nightmare(c *gin.Context) { for i := 3; i > 0; i-- { var continue_info *chatgpt.ContinueInfo var response_part string - response_part, continue_info = chatgpt.Handler(c, response, &secret, proxy_url, deviceId, uid, translated_request, original_request.Stream) + response_part, continue_info = chatgpt.Handler(c, response, &secret, proxy_url, deviceId, uid, original_request.Stream) full_response += response_part if continue_info == nil { break diff --git a/internal/chatgpt/request.go b/internal/chatgpt/request.go index d42715f1..819fc1d4 100644 --- a/internal/chatgpt/request.go +++ b/internal/chatgpt/request.go @@ -72,6 +72,7 @@ func init() { screen := screens[rand.Intn(3)] cachedHardware = core + screen } + func newRequest(method string, url string, body io.Reader, secret *tokens.Secret, deviceId string) (*http.Request, error) { request, err := http.NewRequest(method, url, body) if err != nil { @@ -94,7 +95,7 @@ func newRequest(method string, url string, body io.Reader, secret *tokens.Secret } func getWSURL(secret *tokens.Secret, deviceId string, retry int) (string, error) { - request, err := newRequest(http.MethodPost, "https://chat.openai.com/backend-api/register-websocket", nil, secret, deviceId) + request, err := newRequest(http.MethodPost, "https://chatgpt.com/backend-api/register-websocket", nil, secret, deviceId) if err != nil { return "", err } @@ -122,7 +123,7 @@ type rawDialer interface { func createWSConn(addr string, connInfo *connInfo, proxyURLString string, retry int) error { dialer := websocket.Dialer{ HandshakeTimeout: 8 * time.Second, - NetDialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + NetDialTLSContext: func(ctx context.Context, network string, addr string) (net.Conn, error) { host, _, _ := net.SplitHostPort(addr) config := &tls.Config{ServerName: host, OmitEmptyPsk: true} var rawDial rawDialer @@ -132,7 +133,7 @@ func createWSConn(addr string, connInfo *connInfo, proxyURLString string, retry } else { rawDial = &net.Dialer{} } - dialConn, err := rawDial.Dial("tcp", addr) + dialConn, err := rawDial.Dial(network, addr) if err != nil { return nil, err } @@ -253,10 +254,13 @@ func InitWSConn(secret *tokens.Secret, deviceId string, uuid string, proxy strin } func SetOAICookie(uuid string) { - u, _ := url.Parse("https://openai.com") + u, _ := url.Parse("https://chatgpt.com") client.GetCookieJar().SetCookies(u, []*http.Cookie{{ Name: "oai-did", Value: uuid, + }, { + Name: "oai-dm-tgt-c-240329", + Value: "2024-04-02", }}) } @@ -278,10 +282,11 @@ func GetDpl(proxy string) { if proxy != "" { client.SetProxy(proxy) } + cachedScripts = append(cachedScripts, "https://cdn.oaistatic.com/_next/static/chunks/9598-0150caea9526d55d.js?dpl=abad631f183104e6c8a323392d7bc30b933c5c7c") + cachedDpl = "dpl=abad631f183104e6c8a323392d7bc30b933c5c7c" request, err := http.NewRequest(http.MethodGet, "https://chatgpt.com/?oai-dm=1", nil) request.Header.Set("User-Agent", userAgent) request.Header.Set("Accept", "*/*") - request.Header.Set("Cookie", "oai-dm-tgt-c-240329=2024-04-02") if err != nil { return } @@ -291,11 +296,11 @@ func GetDpl(proxy string) { } defer response.Body.Close() doc, _ := goquery.NewDocumentFromReader(response.Body) - cachedScripts = nil + scripts := []string{} doc.Find("script[src]").Each(func(i int, s *goquery.Selection) { src, exists := s.Attr("src") if exists { - cachedScripts = append(cachedScripts, src) + scripts = append(scripts, src) if cachedDpl == "" { idx := strings.Index(src, "dpl") if idx >= 0 { @@ -304,16 +309,14 @@ func GetDpl(proxy string) { } } }) - if len(cachedScripts) == 0 { - cachedScripts = append(cachedScripts, "https://cdn.oaistatic.com/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js?dpl=baf36960d05dde6d8b941194fa4093fb5cb78c6a") - cachedDpl = "dpl=baf36960d05dde6d8b941194fa4093fb5cb78c6a" + if len(scripts) != 0 { + cachedScripts = scripts } } func getConfig() []interface{} { rand.New(rand.NewSource(time.Now().UnixNano())) script := cachedScripts[rand.Intn(len(cachedScripts))] return []interface{}{cachedHardware, getParseTime(), int64(4294705152), 0, userAgent, script, cachedDpl, "zh-CN", "zh-CN,en,en-GB,en-US", 0} - } func CalcProofToken(require *ChatRequire, proxy string) string { proof := generateAnswer(require.Proof.Seed, require.Proof.Difficulty, proxy) @@ -359,9 +362,9 @@ func CheckRequire(secret *tokens.Secret, deviceId string, proxy string) *ChatReq body := bytes.NewBuffer([]byte(`{"p":"` + cachedRequireProof + `"}`)) var apiUrl string if secret.Token == "" { - apiUrl = "https://chat.openai.com/backend-anon/sentinel/chat-requirements" + apiUrl = "https://chatgpt.com/backend-anon/sentinel/chat-requirements" } else { - apiUrl = "https://chat.openai.com/backend-api/sentinel/chat-requirements" + apiUrl = "https://chatgpt.com/backend-api/sentinel/chat-requirements" } request, err := newRequest(http.MethodPost, apiUrl, body, secret, deviceId) if err != nil { @@ -389,7 +392,7 @@ type urlAttr struct { } func getURLAttribution(secret *tokens.Secret, deviceId string, url string) string { - request, err := newRequest(http.MethodPost, "https://chat.openai.com/backend-api/attributions", bytes.NewBuffer([]byte(`{"urls":["`+url+`"]}`)), secret, deviceId) + request, err := newRequest(http.MethodPost, "https://chatgpt.com/backend-api/attributions", bytes.NewBuffer([]byte(`{"urls":["`+url+`"]}`)), secret, deviceId) if err != nil { return "" } @@ -415,7 +418,7 @@ func POSTconversation(message chatgpt_types.ChatGPTRequest, secret *tokens.Secre client.SetProxy(proxy) } - apiUrl := "https://chat.openai.com/backend-api/conversation" + apiUrl := "https://chatgpt.com/backend-api/conversation" if API_REVERSE_PROXY != "" { apiUrl = API_REVERSE_PROXY } @@ -449,8 +452,8 @@ func POSTconversation(message chatgpt_types.ChatGPTRequest, secret *tokens.Secre if proofToken != "" { request.Header.Set("Openai-Sentinel-Proof-Token", proofToken) } - request.Header.Set("Origin", "https://chat.openai.com") - request.Header.Set("Referer", "https://chat.openai.com/c/"+message.ConversationID) + request.Header.Set("Origin", "https://chatgpt.com") + request.Header.Set("Referer", "https://chatgpt.com/c/"+message.ConversationID) if err != nil { return &http.Response{}, err } @@ -530,7 +533,7 @@ func GetImageSource(wg *sync.WaitGroup, url string, prompt string, secret *token imgSource[idx] = "[![image](" + file_info.DownloadURL + " \"" + prompt + "\")](" + file_info.DownloadURL + ")" } -func Handler(c *gin.Context, response *http.Response, secret *tokens.Secret, proxy string, deviceId string, uuid string, translated_request chatgpt_types.ChatGPTRequest, stream bool) (string, *ContinueInfo) { +func Handler(c *gin.Context, response *http.Response, secret *tokens.Secret, proxy string, deviceId string, uuid string, stream bool) (string, *ContinueInfo) { max_tokens := false // Create a bufio.Reader from the response body @@ -548,10 +551,10 @@ func Handler(c *gin.Context, response *http.Response, secret *tokens.Secret, pro var previous_text typings.StringStruct var original_response chatgpt_types.ChatGPTResponse var isRole = true - var isEnd = false var imgSource []string var isWSS = false var convId string + var msgId string var respId string //var wssUrl string var connInfo *connInfo @@ -684,8 +687,15 @@ func Handler(c *gin.Context, response *http.Response, secret *tokens.Secret, pro if original_response.Message.Metadata.MessageType != "next" && original_response.Message.Metadata.MessageType != "continue" || !strings.HasSuffix(original_response.Message.Content.ContentType, "text") { continue } + if original_response.Message.Content.ContentType == "text" && original_response.Message.ID != msgId { + if msgId == "" && original_response.Message.Content.Parts[0].(string) == "" { + msgId = original_response.Message.ID + } else { + continue + } + } if original_response.Message.EndTurn != nil { - isEnd = true + msgId = "" } if len(original_response.Message.Metadata.Citations) != 0 { r := []rune(original_response.Message.Content.Parts[0].(string)) @@ -709,7 +719,7 @@ func Handler(c *gin.Context, response *http.Response, secret *tokens.Secret, pro } response_string := "" if original_response.Message.Content.ContentType == "multimodal_text" { - apiUrl := "https://chat.openai.com/backend-api/files/" + apiUrl := "https://chatgpt.com/backend-api/files/" if FILES_REVERSE_PROXY != "" { apiUrl = FILES_REVERSE_PROXY } @@ -737,11 +747,7 @@ func Handler(c *gin.Context, response *http.Response, secret *tokens.Secret, pro response_string = chatgpt_response_converter.ConvertToString(&original_response, &previous_text, isRole) } if response_string == "" { - if isEnd { - goto endProcess - } else { - continue - } + continue } isRole = false if stream { @@ -750,7 +756,6 @@ func Handler(c *gin.Context, response *http.Response, secret *tokens.Secret, pro return "", nil } } - endProcess: // Flush the response writer buffer to ensure that the client receives each line as it's written c.Writer.Flush() @@ -760,19 +765,25 @@ func Handler(c *gin.Context, response *http.Response, secret *tokens.Secret, pro } finish_reason = original_response.Message.Metadata.FinishDetails.Type } - if isEnd { - if stream { - final_line := official_types.StopChunk(finish_reason) - c.Writer.WriteString("data: " + final_line.String() + "\n\n") - } + } else { + if stream { + final_line := official_types.StopChunk(finish_reason) + c.Writer.WriteString("data: " + final_line.String() + "\n\n") + } + if isWSS { break } } } + respText := strings.Join(imgSource, "") + if respText != "" { + respText += "\n" + } + respText += previous_text.Text if !max_tokens { - return strings.Join(imgSource, "") + "\n" + previous_text.Text, nil + return respText, nil } - return strings.Join(imgSource, "") + "\n" + previous_text.Text, &ContinueInfo{ + return respText, &ContinueInfo{ ConversationID: original_response.ConversationID, ParentID: original_response.Message.ID, } diff --git a/tools/authenticator/README.md b/tools/authenticator/README.md deleted file mode 100644 index 98cd08db..00000000 --- a/tools/authenticator/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Automated authentication for ChatGPT -Fetches access tokens from a large number of accounts - -## Setup -### `proxies.txt` -Format: -``` -IP:Port:User:Password -... -``` - -### `accounts.txt` -Format: -``` -email:password -... -``` - -Remember to: -`touch access_tokens.txt authenticated_accounts.txt` diff --git a/tools/authenticator/auth/auth.go b/tools/authenticator/auth/auth.go deleted file mode 100644 index d7604c48..00000000 --- a/tools/authenticator/auth/auth.go +++ /dev/null @@ -1,431 +0,0 @@ -package auth - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/url" - "regexp" - "strings" - - http "github.com/bogdanfinn/fhttp" - tls_client "github.com/bogdanfinn/tls-client" - pkce "github.com/nirasan/go-oauth-pkce-code-verifier" -) - -type Error struct { - Location string - StatusCode int - Details string - Error error -} - -func NewError(location string, statusCode int, details string, err error) *Error { - return &Error{ - Location: location, - StatusCode: statusCode, - Details: details, - Error: err, - } -} - -type Authenticator struct { - EmailAddress string - Password string - Proxy string - Session tls_client.HttpClient - UserAgent string - State string - URL string - Verifier_code string - Verifier_challenge string - AuthResult AuthResult -} - -type AuthResult struct { - AccessToken string `json:"access_token"` - PUID string `json:"puid"` -} - -func NewAuthenticator(emailAddress, password, proxy string) *Authenticator { - auth := &Authenticator{ - EmailAddress: emailAddress, - Password: password, - Proxy: proxy, - UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36", - } - jar := tls_client.NewCookieJar() - options := []tls_client.HttpClientOption{ - tls_client.WithTimeoutSeconds(20), - tls_client.WithClientProfile(tls_client.Okhttp4Android13), - tls_client.WithNotFollowRedirects(), - tls_client.WithCookieJar(jar), // create cookieJar instance and pass it as argument - // Proxy - tls_client.WithProxyUrl(proxy), - } - auth.Session, _ = tls_client.NewHttpClient(tls_client.NewNoopLogger(), options...) - - // PKCE - verifier, _ := pkce.CreateCodeVerifier() - auth.Verifier_code = verifier.String() - auth.Verifier_challenge = verifier.CodeChallengeS256() - - return auth -} - -func (auth *Authenticator) URLEncode(str string) string { - return url.QueryEscape(str) -} - -func (auth *Authenticator) Begin() *Error { - - url := "https://chat.openai.com/api/auth/csrf" - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return NewError("begin", 0, "", err) - } - - req.Header.Set("Host", "chat.openai.com") - req.Header.Set("Accept", "*/*") - req.Header.Set("Connection", "keep-alive") - req.Header.Set("User-Agent", auth.UserAgent) - req.Header.Set("Accept-Language", "en-GB,en-US;q=0.9,en;q=0.8") - req.Header.Set("Referer", "https://chat.openai.com/auth/login") - req.Header.Set("Accept-Encoding", "gzip, deflate, br") - - resp, err := auth.Session.Do(req) - if err != nil { - return NewError("begin", 0, "", err) - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - if err != nil { - return NewError("begin", 0, "", err) - } - - if resp.StatusCode == 200 && strings.Contains(resp.Header.Get("Content-Type"), "json") { - - var csrfTokenResponse struct { - CsrfToken string `json:"csrfToken"` - } - err = json.Unmarshal(body, &csrfTokenResponse) - if err != nil { - return NewError("begin", 0, "", err) - } - - csrfToken := csrfTokenResponse.CsrfToken - return auth.partOne(csrfToken) - } else { - err := NewError("begin", resp.StatusCode, string(body), fmt.Errorf("error: Check details")) - return err - } -} - -func (auth *Authenticator) partOne(csrfToken string) *Error { - - auth_url := "https://chat.openai.com/api/auth/signin/auth0?prompt=login" - headers := map[string]string{ - "Host": "chat.openai.com", - "User-Agent": auth.UserAgent, - "Content-Type": "application/x-www-form-urlencoded", - "Accept": "*/*", - "Sec-Gpc": "1", - "Accept-Language": "en-US,en;q=0.8", - "Origin": "https://chat.openai.com", - "Sec-Fetch-Site": "same-origin", - "Sec-Fetch-Mode": "cors", - "Sec-Fetch-Dest": "empty", - "Referer": "https://chat.openai.com/auth/login", - "Accept-Encoding": "gzip, deflate", - } - - // Construct payload - payload := fmt.Sprintf("callbackUrl=%%2F&csrfToken=%s&json=true", csrfToken) - req, _ := http.NewRequest("POST", auth_url, strings.NewReader(payload)) - - for k, v := range headers { - req.Header.Set(k, v) - } - - resp, err := auth.Session.Do(req) - if err != nil { - return NewError("part_one", 0, "Failed to send request", err) - } - defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) - if err != nil { - return NewError("part_one", 0, "Failed to read body", err) - } - - if resp.StatusCode == 200 && strings.Contains(resp.Header.Get("Content-Type"), "json") { - var urlResponse struct { - URL string `json:"url"` - } - err = json.Unmarshal(body, &urlResponse) - if err != nil { - return NewError("part_one", 0, "Failed to decode JSON", err) - } - if urlResponse.URL == "https://chat.openai.com/api/auth/error?error=OAuthSignin" || strings.Contains(urlResponse.URL, "error") { - err := NewError("part_one", resp.StatusCode, "You have been rate limited. Please try again later.", fmt.Errorf("error: Check details")) - return err - } - return auth.partTwo(urlResponse.URL) - } else { - return NewError("part_one", resp.StatusCode, string(body), fmt.Errorf("error: Check details")) - } -} - -func (auth *Authenticator) partTwo(url string) *Error { - - headers := map[string]string{ - "Host": "auth0.openai.com", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - "Connection": "keep-alive", - "User-Agent": auth.UserAgent, - "Accept-Language": "en-US,en;q=0.9", - } - - req, _ := http.NewRequest("GET", url, nil) - for k, v := range headers { - req.Header.Set(k, v) - } - - resp, err := auth.Session.Do(req) - if err != nil { - return NewError("part_two", 0, "Failed to make request", err) - } - defer resp.Body.Close() - body, _ := io.ReadAll(resp.Body) - - if resp.StatusCode == 302 || resp.StatusCode == 200 { - - stateRegex := regexp.MustCompile(`state=(.*)`) - stateMatch := stateRegex.FindStringSubmatch(string(body)) - if len(stateMatch) < 2 { - return NewError("part_two", 0, "Could not find state in response", fmt.Errorf("error: Check details")) - } - - state := strings.Split(stateMatch[1], `"`)[0] - return auth.partThree(state) - } else { - return NewError("part_two", resp.StatusCode, string(body), fmt.Errorf("error: Check details")) - - } -} -func (auth *Authenticator) partThree(state string) *Error { - - url := fmt.Sprintf("https://auth0.openai.com/u/login/identifier?state=%s", state) - emailURLEncoded := auth.URLEncode(auth.EmailAddress) - - payload := fmt.Sprintf( - "state=%s&username=%s&js-available=false&webauthn-available=true&is-brave=false&webauthn-platform-available=true&action=default", - state, emailURLEncoded, - ) - - headers := map[string]string{ - "Host": "auth0.openai.com", - "Origin": "https://auth0.openai.com", - "Connection": "keep-alive", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - "User-Agent": auth.UserAgent, - "Referer": fmt.Sprintf("https://auth0.openai.com/u/login/identifier?state=%s", state), - "Accept-Language": "en-US,en;q=0.9", - "Content-Type": "application/x-www-form-urlencoded", - } - - req, _ := http.NewRequest("POST", url, strings.NewReader(payload)) - - for k, v := range headers { - req.Header.Set(k, v) - } - - resp, err := auth.Session.Do(req) - if err != nil { - return NewError("part_three", 0, "Failed to send request", err) - } - defer resp.Body.Close() - - if resp.StatusCode == 302 || resp.StatusCode == 200 { - return auth.partFour(state) - } else { - return NewError("part_three", resp.StatusCode, "Your email address is invalid.", fmt.Errorf("error: Check details")) - - } - -} -func (auth *Authenticator) partFour(state string) *Error { - - url := fmt.Sprintf("https://auth0.openai.com/u/login/password?state=%s", state) - emailURLEncoded := auth.URLEncode(auth.EmailAddress) - passwordURLEncoded := auth.URLEncode(auth.Password) - payload := fmt.Sprintf("state=%s&username=%s&password=%s&action=default", state, emailURLEncoded, passwordURLEncoded) - - headers := map[string]string{ - "Host": "auth0.openai.com", - "Origin": "https://auth0.openai.com", - "Connection": "keep-alive", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - "User-Agent": auth.UserAgent, - "Referer": fmt.Sprintf("https://auth0.openai.com/u/login/password?state=%s", state), - "Accept-Language": "en-US,en;q=0.9", - "Content-Type": "application/x-www-form-urlencoded", - } - - req, _ := http.NewRequest("POST", url, strings.NewReader(payload)) - - for k, v := range headers { - req.Header.Set(k, v) - } - - resp, err := auth.Session.Do(req) - if err != nil { - return NewError("part_four", 0, "Failed to send request", err) - } - defer resp.Body.Close() - - if resp.StatusCode == 302 { - redirectURL := resp.Header.Get("Location") - return auth.partFive(state, redirectURL) - } else { - body := bytes.NewBuffer(nil) - body.ReadFrom(resp.Body) - return NewError("part_four", resp.StatusCode, body.String(), fmt.Errorf("error: Check details")) - - } - -} -func (auth *Authenticator) partFive(oldState string, redirectURL string) *Error { - - url := "https://auth0.openai.com" + redirectURL - - headers := map[string]string{ - "Host": "auth0.openai.com", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - "Connection": "keep-alive", - "User-Agent": auth.UserAgent, - "Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8", - "Referer": fmt.Sprintf("https://auth0.openai.com/u/login/password?state=%s", oldState), - } - - req, _ := http.NewRequest("GET", url, nil) - - for k, v := range headers { - req.Header.Set(k, v) - } - - resp, err := auth.Session.Do(req) - if err != nil { - return NewError("part_five", 0, "Failed to send request", err) - } - defer resp.Body.Close() - - if resp.StatusCode == 302 { - return auth.partSix(resp.Header.Get("Location"), url) - } else { - return NewError("part_five", resp.StatusCode, resp.Status, fmt.Errorf("error: Check details")) - - } - -} -func (auth *Authenticator) partSix(url, redirect_url string) *Error { - req, _ := http.NewRequest("GET", url, nil) - for k, v := range map[string]string{ - "Host": "chat.openai.com", - "Accept": "application/json", - "Connection": "keep-alive", - "User-Agent": auth.UserAgent, - "Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8", - "Referer": redirect_url, - } { - req.Header.Set(k, v) - } - resp, err := auth.Session.Do(req) - if err != nil { - return NewError("part_six", 0, "Failed to send request", err) - } - defer resp.Body.Close() - if err != nil { - return NewError("part_six", 0, "Response was not JSON", err) - } - if resp.StatusCode != 302 { - return NewError("part_six", resp.StatusCode, url, fmt.Errorf("incorrect response code")) - } - // Check location header - if location := resp.Header.Get("Location"); location != "https://chat.openai.com/" { - return NewError("part_six", resp.StatusCode, location, fmt.Errorf("incorrect redirect")) - } - - url = "https://chat.openai.com/api/auth/session" - - req, _ = http.NewRequest("GET", url, nil) - - // Set user agent - req.Header.Set("User-Agent", auth.UserAgent) - - resp, err = auth.Session.Do(req) - if err != nil { - return NewError("get_access_token", 0, "Failed to send request", err) - } - - if resp.StatusCode != 200 { - return NewError("get_access_token", resp.StatusCode, "Incorrect response code", fmt.Errorf("error: Check details")) - } - var result map[string]interface{} - if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { - return NewError("get_access_token", 0, "", err) - } - - // Check if access token in data - if _, ok := result["accessToken"]; !ok { - result_string := fmt.Sprintf("%v", result) - return NewError("part_six", 0, result_string, fmt.Errorf("missing access token")) - } - auth.AuthResult.AccessToken = result["accessToken"].(string) - - return nil -} - -func (auth *Authenticator) GetAccessToken() string { - return auth.AuthResult.AccessToken -} - -func (auth *Authenticator) GetPUID() (string, *Error) { - // Check if user has access token - if auth.AuthResult.AccessToken == "" { - return "", NewError("get_puid", 0, "Missing access token", fmt.Errorf("error: Check details")) - } - // Make request to https://chat.openai.com/backend-api/models - req, _ := http.NewRequest("GET", "https://chat.openai.com/backend-api/models", nil) - // Add headers - req.Header.Add("Authorization", "Bearer "+auth.AuthResult.AccessToken) - req.Header.Add("User-Agent", auth.UserAgent) - req.Header.Add("Accept", "application/json") - req.Header.Add("Accept-Language", "en-US,en;q=0.9") - req.Header.Add("Referer", "https://chat.openai.com/") - req.Header.Add("Origin", "https://chat.openai.com") - req.Header.Add("Connection", "keep-alive") - - resp, err := auth.Session.Do(req) - if err != nil { - return "", NewError("get_puid", 0, "Failed to make request", err) - } - defer resp.Body.Close() - if resp.StatusCode != 200 { - return "", NewError("get_puid", resp.StatusCode, "Failed to make request", fmt.Errorf("error: Check details")) - } - // Find `_puid` cookie in response - for _, cookie := range resp.Cookies() { - if cookie.Name == "_puid" { - auth.AuthResult.PUID = cookie.Value - return cookie.Value, nil - } - } - // If cookie not found, return error - return "", NewError("get_puid", 0, "PUID cookie not found", fmt.Errorf("error: Check details")) -} - -func (auth *Authenticator) GetAuthResult() AuthResult { - return auth.AuthResult -} diff --git a/tools/authenticator/go.mod b/tools/authenticator/go.mod deleted file mode 100644 index 5bee707a..00000000 --- a/tools/authenticator/go.mod +++ /dev/null @@ -1,20 +0,0 @@ -module authenticator - -go 1.20 - -require ( - github.com/bogdanfinn/fhttp v0.5.23 - github.com/bogdanfinn/tls-client v1.5.0 - github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c -) - -require ( - github.com/andybalholm/brotli v1.0.5 // indirect - github.com/bogdanfinn/utls v1.5.16 // indirect - github.com/klauspost/compress v1.16.7 // indirect - github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 // indirect - golang.org/x/crypto v0.11.0 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/sys v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect -) diff --git a/tools/authenticator/go.sum b/tools/authenticator/go.sum deleted file mode 100644 index ccdde73b..00000000 --- a/tools/authenticator/go.sum +++ /dev/null @@ -1,22 +0,0 @@ -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/bogdanfinn/fhttp v0.5.23 h1:4Xb5OjYArB8GpnUw4A4r5jmt8UW0/Cvey3R9nS2dC9U= -github.com/bogdanfinn/fhttp v0.5.23/go.mod h1:brqi5woc5eSCVHdKYBV8aZLbO7HGqpwyDLeXW+fT18I= -github.com/bogdanfinn/tls-client v1.5.0 h1:L/d4AL+8RRw+6o9wwhpii45I6RO2CEkgRV4NeE0NAxo= -github.com/bogdanfinn/tls-client v1.5.0/go.mod h1:lgtqsHjoJYQMPz6H08bc8t30bmUaYnVjwtfVEzMGJDs= -github.com/bogdanfinn/utls v1.5.16 h1:NhhWkegEcYETBMj9nvgO4lwvc6NcLH+znrXzO3gnw4M= -github.com/bogdanfinn/utls v1.5.16/go.mod h1:mHeRCi69cUiEyVBkKONB1cAbLjRcZnlJbGzttmiuK4o= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c h1:4RYnE0ISVwRxm9Dfo7utw1dh0kdRDEmVYq2MFVLy5zI= -github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= -github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 h1:YqAladjX7xpA6BM04leXMWAEjS0mTZ5kUU9KRBriQJc= -github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5/go.mod h1:2JjD2zLQYH5HO74y5+aE3remJQvl6q4Sn6aWA2wD1Ng= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= diff --git a/tools/authenticator/main.go b/tools/authenticator/main.go deleted file mode 100644 index 0fc081f4..00000000 --- a/tools/authenticator/main.go +++ /dev/null @@ -1,173 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - "os/exec" - "strings" - "time" - - auth "authenticator/auth" -) - -type Account struct { - Email string `json:"username"` - Password string `json:"password"` -} -type Proxy struct { - IP string `json:"ip"` - Port string `json:"port"` - User string `json:"user"` - Pass string `json:"pass"` -} - -func (p Proxy) Socks5URL() string { - // Returns proxy URL (socks5) - if p.User == "" && p.Pass == "" { - return fmt.Sprintf("socks5://%s:%s", p.IP, p.Port) - } - return fmt.Sprintf("socks5://%s:%s@%s:%s", p.User, p.Pass, p.IP, p.Port) -} - -// Read accounts.txt and create a list of accounts -func readAccounts() []Account { - accounts := []Account{} - // Read accounts.txt and create a list of accounts - file, err := os.Open("accounts.txt") - if err != nil { - panic(err) - } - defer file.Close() - // Loop through each line in the file - scanner := bufio.NewScanner(file) - for scanner.Scan() { - // Split by : - line := strings.Split(scanner.Text(), ":") - // Create an account - account := Account{ - Email: line[0], - Password: line[1], - } - // Append to accounts - accounts = append(accounts, account) - } - return accounts -} - -// Read proxies from proxies.txt and create a list of proxies -func readProxies() []Proxy { - proxies := []Proxy{} - // Read proxies.txt and create a list of proxies - file, err := os.Open("proxies.txt") - if err != nil { - return []Proxy{} - } - defer file.Close() - // Loop through each line in the file - scanner := bufio.NewScanner(file) - for scanner.Scan() { - // Split by : - lines := strings.Split(scanner.Text(), ":") - var proxy Proxy - if len(lines) == 4 { - // Create a proxy - proxy = Proxy{ - IP: lines[0], - Port: lines[1], - User: lines[2], - Pass: lines[3], - } - } else if len(lines) == 2 { - proxy = Proxy{ - IP: lines[0], - Port: lines[1], - } - } else { - continue - } - // Append to proxies - proxies = append(proxies, proxy) - } - return proxies -} - -func main() { - // Read accounts and proxies - accounts := readAccounts() - proxies := readProxies() - - // Loop through each account - for _, account := range accounts { - if os.Getenv("CF_PROXY") != "" { - // exec warp-cli disconnect and connect - exec.Command("warp-cli", "disconnect").Run() - exec.Command("warp-cli", "connect").Run() - time.Sleep(5 * time.Second) - } - println(account.Email) - println(account.Password) - var proxy_url string - if len(proxies) == 0 { - if os.Getenv("http_proxy") != "" { - proxy_url = os.Getenv("http_proxy") - } - } else { - proxy_url = proxies[0].Socks5URL() - // Push used proxy to the back of the list - proxies = append(proxies[1:], proxies[0]) - } - println(proxy_url) - authenticator := auth.NewAuthenticator(account.Email, account.Password, proxy_url) - err := authenticator.Begin() - if err != nil { - // println("Error: " + err.Details) - println("Location: " + err.Location) - println("Status code: " + fmt.Sprint(err.StatusCode)) - println("Details: " + err.Details) - println("Embedded error: " + err.Error.Error()) - // Sleep for 10 seconds - panic(err) - } - access_token := authenticator.GetAccessToken() - // Append access token to access_tokens.txt - f, go_err := os.OpenFile("access_tokens.txt", os.O_APPEND|os.O_WRONLY, 0600) - if go_err != nil { - continue - } - defer f.Close() - if _, go_err = f.WriteString(access_token + "\n"); go_err != nil { - continue - } - // Write authenticated account to authenticated_accounts.txt - f, go_err = os.OpenFile("authenticated_accounts.txt", os.O_APPEND|os.O_WRONLY, 0600) - if go_err != nil { - continue - } - defer f.Close() - if _, go_err = f.WriteString(account.Email + ":" + account.Password + "\n"); go_err != nil { - continue - } - // Remove accounts.txt - os.Remove("accounts.txt") - // Create accounts.txt - f, go_err = os.Create("accounts.txt") - if go_err != nil { - continue - } - defer f.Close() - // Remove account from accounts - accounts = accounts[1:] - // Write unauthenticated accounts to accounts.txt - for _, acc := range accounts { - // Check if account is authenticated - if acc.Email == account.Email { - continue - } - if _, go_err = f.WriteString(acc.Email + ":" + acc.Password + "\n"); go_err != nil { - continue - } - } - - } -} diff --git a/tools/authenticator/remove_duplicates.py b/tools/authenticator/remove_duplicates.py deleted file mode 100644 index 97920982..00000000 --- a/tools/authenticator/remove_duplicates.py +++ /dev/null @@ -1,31 +0,0 @@ -# Removes duplicate lines from a file -# Usage: python remove_duplicates.py - -import sys -import json - - -def remove_duplicates(file_lines): - """ - Removes duplicate lines from a file - """ - lines_set = set() - for lin in file_lines: - #if json.loads(lin)["output"] == "": - # continue - lines_set.add(lin) - return lines_set - - -if __name__ == "__main__": - if len(sys.argv) != 2: - print("Usage: python remove_duplicates.py ") - sys.exit(1) - orig_file = open(sys.argv[1], "r", encoding="utf-8").readlines() - lines = remove_duplicates(orig_file) - file = open("clean_" + sys.argv[1], "w", encoding="utf-8") - for line in lines: - file.write(line) - file.close() - # Print difference - print(len(orig_file) - len(lines)) diff --git a/tools/authenticator/tojson.sh b/tools/authenticator/tojson.sh deleted file mode 100755 index e0f78634..00000000 --- a/tools/authenticator/tojson.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -# Check if a file name is provided as an argument -if [ $# -eq 0 ]; then - echo "Usage: $0 " - exit 1 -fi - -file="$1" -output="$2" -# Declare an empty array -lines=() - -# Read the file line by line and add each line to the array -while IFS= read -r line; do - lines+=("\"$line\"") -done < "$file" - -# Join array elements with commas and print the result enclosed in square brackets -result="[" -for ((i = 0; i < ${#lines[@]}; i++)); do - result+="${lines[i]}" - if ((i < ${#lines[@]} - 1)); then - result+="," - fi -done -result+="]" -if [ $# -eq 1 ]; then - echo "$result" -fi -if [ $# -eq 2 ]; then - echo "$result" | tee $output -fi - diff --git a/tools/plugin_check/check_access.go b/tools/plugin_check/check_access.go deleted file mode 100644 index 5f44cfaf..00000000 --- a/tools/plugin_check/check_access.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import ( - "bufio" - "encoding/json" - "net/http" - "os" -) - -func main() { - var access_tokens []string - // Read access_tokens.txt and split by new line - file, err := os.Open("access_tokens.txt") - if err != nil { - panic(err) - } - defer file.Close() - scanner := bufio.NewScanner(file) - for scanner.Scan() { - access_tokens = append(access_tokens, scanner.Text()) - } - if err := scanner.Err(); err != nil { - panic(err) - } - // Go routine to check access for each token (limit to 20 simultaneous) - sem := make(chan bool, 20) - for _, token := range access_tokens { - sem <- true - go func(token string) { - defer func() { <-sem }() - if check_access(token) { - println(token) - } - }(token) - } - for i := 0; i < cap(sem); i++ { - sem <- true - } -} - -func check_access(token string) bool { - print(".") - req, _ := http.NewRequest("GET", "https://ai.fakeopen.com/api/accounts/check", nil) - req.Header.Set("Authorization", "Bearer "+token) - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - panic(err) - } - defer resp.Body.Close() - if resp.StatusCode == 200 { - // Parse response body as JSON - var result map[string]interface{} - json.NewDecoder(resp.Body).Decode(&result) - // Check if "tool1", "tool2", or "tool3" is in the features array - for _, feature := range result["features"].([]interface{}) { - if feature == "tools1" || feature == "tools2" || feature == "tools3" { - return true - } - } - return false - } - println(resp.StatusCode) - return false -} diff --git a/tools/proxy_check/proxy_check.go b/tools/proxy_check/proxy_check.go deleted file mode 100644 index 2b850103..00000000 --- a/tools/proxy_check/proxy_check.go +++ /dev/null @@ -1,74 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - "strings" - "sync" - - tls_client "github.com/bogdanfinn/tls-client" -) - -var proxies []string - -// Read proxies.txt and check if they work -func init() { - // Check for proxies.txt - if _, err := os.Stat("proxies.txt"); err == nil { - // Each line is a proxy, put in proxies array - file, _ := os.Open("proxies.txt") - defer file.Close() - scanner := bufio.NewScanner(file) - for scanner.Scan() { - // Split line by : - proxy := scanner.Text() - proxy_parts := strings.Split(proxy, ":") - if len(proxy_parts) == 2 { - proxy = "socks5://" + proxy - } else if len(proxy_parts) == 4 { - proxy = "socks5://" + proxy_parts[2] + ":" + proxy_parts[3] + "@" + proxy_parts[0] + ":" + proxy_parts[1] - } else { - continue - } - proxies = append(proxies, proxy) - } - } - -} - -func main() { - wg := sync.WaitGroup{} - for _, proxy := range proxies { - wg.Add(1) - go func(proxy string) { - defer wg.Done() - jar := tls_client.NewCookieJar() - options := []tls_client.HttpClientOption{ - tls_client.WithTimeoutSeconds(360), - tls_client.WithClientProfile(tls_client.Chrome_110), - tls_client.WithNotFollowRedirects(), - tls_client.WithCookieJar(jar), // create cookieJar instance and pass it as argument - // Disable SSL verification - tls_client.WithInsecureSkipVerify(), - } - client, _ := tls_client.NewHttpClient(tls_client.NewNoopLogger(), options...) - - client.SetProxy(proxy) - resp, err := client.Get("https://example.com") - if err != nil { - fmt.Println("Error: ", err) - fmt.Println("Proxy: ", proxy) - return - } - if resp.StatusCode != 200 { - fmt.Println("Error: ", resp.StatusCode) - fmt.Println("Proxy: ", proxy) - return - } else { - fmt.Println(".") - } - }(proxy) - } - wg.Wait() -} diff --git a/typings/chatgpt/request.go b/typings/chatgpt/request.go index 9971eae3..d33bdabd 100644 --- a/typings/chatgpt/request.go +++ b/typings/chatgpt/request.go @@ -123,6 +123,11 @@ var ( ) func init() { + u, _ := url.Parse("https://chatgpt.com") + client.GetCookieJar().SetCookies(u, []*http.Cookie{{ + Name: "oai-dm-tgt-c-240329", + Value: "2024-04-02", + }}) // from https://chromium.googlesource.com/chromium/src/+/HEAD/net/base/mime_util.cc mimeMap := map[string]string{ "webm": "video/webm", @@ -356,7 +361,7 @@ func uploadBinary(data []byte, mime string, name string, isImg bool, secret *tok fileCase = "ace_upload" } dataLen := strconv.Itoa(len(data)) - request, err := newRequest(http.MethodPost, "https://chat.openai.com/backend-api/files", bytes.NewBuffer([]byte(`{"file_name":"`+name+`","file_size":`+dataLen+`,"use_case":"`+fileCase+`"}`)), secret, deviceId) + request, err := newRequest(http.MethodPost, "https://chatgpt.com/backend-api/files", bytes.NewBuffer([]byte(`{"file_name":"`+name+`","file_size":`+dataLen+`,"use_case":"`+fileCase+`"}`)), secret, deviceId) if err != nil { return "" } @@ -387,7 +392,7 @@ func uploadBinary(data []byte, mime string, name string, isImg bool, secret *tok if response.StatusCode != 201 { return "" } - request, err = newRequest(http.MethodPost, "https://chat.openai.com/backend-api/files/"+fileResp.File_id+"/uploaded", bytes.NewBuffer([]byte(`{}`)), secret, deviceId) + request, err = newRequest(http.MethodPost, "https://chatgpt.com/backend-api/files/"+fileResp.File_id+"/uploaded", bytes.NewBuffer([]byte(`{}`)), secret, deviceId) if err != nil { return "" } diff --git a/typings/chatgpt/response.go b/typings/chatgpt/response.go index e28a87ed..f297caf7 100644 --- a/typings/chatgpt/response.go +++ b/typings/chatgpt/response.go @@ -51,7 +51,6 @@ type Author struct { } type Metadata struct { - Timestamp string `json:"timestamp_"` Citations []Citation `json:"citations,omitempty"` MessageType string `json:"message_type"` FinishDetails *FinishDetails `json:"finish_details"`