Skip to content

Commit bfd58c5

Browse files
feat: ⚡ 可选聊天服务器、cloudflare 聊天服务器部署
1 parent 842e02b commit bfd58c5

35 files changed

+2055
-1306
lines changed

.vscode/launch.json

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
// "Go_Proxy_BingAI_SOCKS_PWD": "xxx",
1919
// "Go_Proxy_BingAI_USER_TOKEN_1": "xxx",
2020
// "Go_Proxy_BingAI_USER_TOKEN_2": "xxx"
21+
// "Go_Proxy_BingAI_AUTH_KEY": "xxx",
2122
}
2223
}
2324
]

README.md

+26-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
基于微软 New Bing 简单定制,拥有一致的 UI 体验,支持 ChatGPT 提示词,国内可用,基本兼容微软 Bing AI 所有功能,无需登录即可畅聊。
44

5+
⭐ Bing 官方聊天服务器(相对较快和稳定,推荐)不可用时, 可用 ModHeader 添加 X-Forwarded-For 请求头,对应 URL 是 wss://sydney.bing.com/sydney/ChatHub,具体可参考 https://zhuanlan.zhihu.com/p/606655303
6+
7+
⭐ 聊天服务器 (暂时默认 Cloudflare ) 可在右上角 设置 => 服务选择 中切换
8+
9+
⭐ 自定义聊天服务器参考下面 [部署聊天服务器](#部署聊天服务器) 章节
10+
511
⭐ 国内可用 (部署服务器需要直连 www.bing.com 不重定向 CN ,可配置 socks 连接)
612

713
⭐ 支持现有开源提示词库
@@ -22,6 +28,7 @@
2228
- [Railway](#Railway)
2329
- [Vercel](#Vercel)
2430
- [Render](#Render)
31+
- [部署聊天服务器](#部署聊天服务器)
2532
- [TODO](#TODO)
2633

2734
## 网页展示
@@ -104,6 +111,8 @@ Go_Proxy_BingAI_SOCKS_PWD=xxx
104111
Go_Proxy_BingAI_USER_TOKEN_1=xxx
105112
Go_Proxy_BingAI_USER_TOKEN_2=xxx
106113
Go_Proxy_BingAI_USER_TOKEN_3=xxx ...
114+
# 简单授权认证密码,可选
115+
Go_Proxy_BingAI_AUTH_KEY=xxx
107116
```
108117

109118
## 部署
@@ -153,7 +162,7 @@ services:
153162

154163
### Release
155164

156-
[Github Releases](https://github.com/adams549659584/go-proxy-bingai/releases) 下载适用于对应平台的压缩包,解压后可得到可执行文件 go-proxy-bingai,直接运行即可。
165+
[GitHub Releases](https://github.com/adams549659584/go-proxy-bingai/releases) 下载适用于对应平台的压缩包,解压后可得到可执行文件 go-proxy-bingai,直接运行即可。
157166

158167
### Railway
159168

@@ -176,6 +185,8 @@ RAILWAY_DOCKERFILE_PATH=docker/Dockerfile
176185

177186
### Vercel
178187

188+
> ⭐ Vercel 部署不支持 Websocket ,需选择 官方聊天服务器 或 Cloudflare
189+
179190
一键部署,点这里 => [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/adams549659584/go-proxy-bingai&project-name=go-proxy-bingai&repository-name=go-proxy-bingai-vercel)
180191

181192
![Vercel 一键部署](./docs/img/vercel-1.png)
@@ -190,11 +201,23 @@ RAILWAY_DOCKERFILE_PATH=docker/Dockerfile
190201

191202
![Render 域名](./docs/img/render-2.png)
192203

204+
## 部署聊天服务器
205+
206+
> 核心代码 [worker.js](./cloudflare/worker.js)
207+
208+
> 具体部署 Cloudflare Workers 教程自行查询,大概如下
209+
210+
- [注册 Cloudflare 账号](https://dash.cloudflare.com/sign-up)
211+
212+
- 创建 Worker 服务,复制 [worker.js](./cloudflare/worker.js) 全部代码,粘贴至创建的服务中,保存并部署。
213+
214+
- 触发器 中自定义访问域名。
215+
193216
## TODO
194217

195218
- [x] 撰写
196219
- [x] Vue3 重构
197220
- [x] 提示词
198221
- [x] 历史聊天
199-
- [ ] 导出消息到本地(Markdown、图片、PDF)
200-
- [ ] 简单访问权限控制
222+
- [x] 导出消息到本地(Markdown、图片、PDF)
223+
- [x] 简单访问权限控制

api/chathub.go

-10
This file was deleted.

api/helper/helper.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package helper
2+
3+
import (
4+
"adams549659584/go-proxy-bingai/common"
5+
"encoding/json"
6+
"net/http"
7+
)
8+
9+
type Response struct {
10+
Code int `json:"code"`
11+
Message string `json:"message"`
12+
Data interface{} `json:"data"`
13+
}
14+
15+
func CommonResult(w http.ResponseWriter, code int, msg string, data interface{}) error {
16+
res := Response{
17+
Code: code,
18+
Message: msg,
19+
Data: data,
20+
}
21+
w.Header().Set("Content-Type", "application/json")
22+
err := json.NewEncoder(w).Encode(res)
23+
if err != nil {
24+
return err
25+
}
26+
return nil
27+
}
28+
29+
func SuccessResult(w http.ResponseWriter, data interface{}) error {
30+
return CommonResult(w, http.StatusOK, "success", data)
31+
}
32+
33+
func ErrorResult(w http.ResponseWriter, code int, msg string) error {
34+
return CommonResult(w, code, msg, nil)
35+
}
36+
37+
func UnauthorizedResult(w http.ResponseWriter) error {
38+
return ErrorResult(w, http.StatusUnauthorized, "unauthorized")
39+
}
40+
41+
func CheckAuth(r *http.Request) bool {
42+
isAuth := true
43+
if len(common.AUTH_KEY) > 0 {
44+
ckAuthKey, _ := r.Cookie(common.AUTH_KEY_COOKIE_NAME)
45+
isAuth = ckAuthKey != nil && len(ckAuthKey.Value) > 0 && common.AUTH_KEY == ckAuthKey.Value
46+
}
47+
return isAuth
48+
}

api/index.go

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package api
22

33
import (
4+
"adams549659584/go-proxy-bingai/api/helper"
45
"adams549659584/go-proxy-bingai/common"
56
"net/http"
67
)
@@ -9,6 +10,10 @@ func Index(w http.ResponseWriter, r *http.Request) {
910
if r.URL.Path == "/" {
1011
http.Redirect(w, r, common.PROXY_WEB_PAGE_PATH, http.StatusFound)
1112
} else {
13+
if !helper.CheckAuth(r) {
14+
helper.UnauthorizedResult(w)
15+
return
16+
}
1217
common.NewSingleHostReverseProxy(common.BING_URL).ServeHTTP(w, r)
1318
}
1419
}

api/sydney.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package api
2+
3+
import (
4+
"adams549659584/go-proxy-bingai/api/helper"
5+
"adams549659584/go-proxy-bingai/common"
6+
"net/http"
7+
)
8+
9+
func Sydney(w http.ResponseWriter, r *http.Request) {
10+
if !helper.CheckAuth(r) {
11+
helper.UnauthorizedResult(w)
12+
return
13+
}
14+
common.NewSingleHostReverseProxy(common.BING_SYDNEY_URL).ServeHTTP(w, r)
15+
}

api/sysConfig.go

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package api
2+
3+
import (
4+
"adams549659584/go-proxy-bingai/api/helper"
5+
"adams549659584/go-proxy-bingai/common"
6+
"net/http"
7+
)
8+
9+
type SysConfig struct {
10+
// 是否系统配置 cookie
11+
IsSysCK bool `json:"isSysCK"`
12+
// 是否已授权
13+
IsAuth bool `json:"isAuth"`
14+
SydneyBaseUrl string `json:"sydneyBaseUrl"`
15+
}
16+
17+
func SysConf(w http.ResponseWriter, r *http.Request) {
18+
isAuth := helper.CheckAuth(r)
19+
conf := SysConfig{
20+
IsSysCK: len(common.USER_TOKEN_LIST) > 0,
21+
IsAuth: isAuth,
22+
}
23+
helper.SuccessResult(w, conf)
24+
}

api/web.go

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package api
22

33
import (
4+
"adams549659584/go-proxy-bingai/api/helper"
45
"adams549659584/go-proxy-bingai/common"
56
"adams549659584/go-proxy-bingai/web"
67
"net/http"
@@ -10,6 +11,10 @@ func WebStatic(w http.ResponseWriter, r *http.Request) {
1011
if _, ok := web.WEB_PATH_MAP[r.URL.Path]; ok || r.URL.Path == common.PROXY_WEB_PREFIX_PATH {
1112
http.StripPrefix(common.PROXY_WEB_PREFIX_PATH, http.FileServer(web.GetWebFS())).ServeHTTP(w, r)
1213
} else {
14+
if !helper.CheckAuth(r) {
15+
helper.UnauthorizedResult(w)
16+
return
17+
}
1318
common.NewSingleHostReverseProxy(common.BING_URL).ServeHTTP(w, r)
1419
}
1520
}

cloudflare/worker.js

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
const SYDNEY_ORIGIN = 'https://sydney.bing.com';
2+
const KEEP_REQ_HEADERS = [
3+
'accept',
4+
'accept-encoding',
5+
'accept-language',
6+
'connection',
7+
'cookie',
8+
'upgrade',
9+
'user-agent',
10+
'sec-websocket-extensions',
11+
'sec-websocket-key',
12+
'sec-websocket-version',
13+
'x-request-id',
14+
'content-length',
15+
'content-type',
16+
'access-control-request-headers',
17+
'access-control-request-method',
18+
];
19+
const IP_RANGE = [
20+
['3.2.50.0', '3.5.31.255'], //192,000
21+
['3.12.0.0', '3.23.255.255'], //786,432
22+
['3.30.0.0', '3.33.34.255'], //205,568
23+
['3.40.0.0', '3.63.255.255'], //1,572,864
24+
['3.80.0.0', '3.95.255.255'], //1,048,576
25+
['3.100.0.0', '3.103.255.255'], //262,144
26+
['3.116.0.0', '3.119.255.255'], //262,144
27+
['3.128.0.0', '3.247.255.255'], //7,864,320
28+
];
29+
30+
/**
31+
* 随机整数 [min,max)
32+
* @param {number} min
33+
* @param {number} max
34+
* @returns
35+
*/
36+
const getRandomInt = (min, max) => Math.floor(Math.random() * (max - min)) + min;
37+
38+
/**
39+
* ip 转 int
40+
* @param {string} ip
41+
* @returns
42+
*/
43+
const ipToInt = (ip) => {
44+
const ipArr = ip.split('.');
45+
let result = 0;
46+
result += +ipArr[0] << 24;
47+
result += +ipArr[1] << 16;
48+
result += +ipArr[2] << 8;
49+
result += +ipArr[3];
50+
return result;
51+
};
52+
53+
/**
54+
* int 转 ip
55+
* @param {number} intIP
56+
* @returns
57+
*/
58+
const intToIp = (intIP) => {
59+
return `${(intIP >> 24) & 255}.${(intIP >> 16) & 255}.${(intIP >> 8) & 255}.${intIP & 255}`;
60+
};
61+
62+
const getRandomIP = () => {
63+
const randIndex = getRandomInt(0, IP_RANGE.length);
64+
const startIp = IP_RANGE[randIndex][0];
65+
const endIp = IP_RANGE[randIndex][1];
66+
const startIPInt = ipToInt(startIp);
67+
const endIPInt = ipToInt(endIp);
68+
const randomInt = getRandomInt(startIPInt, endIPInt);
69+
const randomIP = intToIp(randomInt);
70+
return randomIP;
71+
};
72+
73+
export default {
74+
/**
75+
* fetch
76+
* @param {Request} request
77+
* @param {*} env
78+
* @param {*} ctx
79+
* @returns
80+
*/
81+
async fetch(request, env, ctx) {
82+
const currentUrl = new URL(request.url);
83+
const targetUrl = new URL(SYDNEY_ORIGIN + currentUrl.pathname + currentUrl.search);
84+
85+
const newHeaders = new Headers();
86+
request.headers.forEach((value, key) => {
87+
// console.log(`old : ${key} : ${value}`);
88+
if (KEEP_REQ_HEADERS.includes(key)) {
89+
newHeaders.set(key, value);
90+
}
91+
});
92+
newHeaders.set('host', targetUrl.host);
93+
newHeaders.set('origin', targetUrl.origin);
94+
newHeaders.set('referer', 'https://www.bing.com/search?q=Bing+AI');
95+
const randIP = getRandomIP();
96+
// console.log('randIP : ', randIP);
97+
newHeaders.set('X-Forwarded-For', randIP);
98+
const oldUA = request.headers.get('user-agent');
99+
const isMobile = oldUA.includes('Mobile') || oldUA.includes('Android');
100+
if (isMobile) {
101+
newHeaders.set(
102+
'user-agent',
103+
'Mozilla/5.0 (iPhone; CPU iPhone OS 15_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.7 Mobile/15E148 Safari/605.1.15 BingSapphire/1.0.410427012'
104+
);
105+
} else {
106+
newHeaders.set('user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35');
107+
}
108+
109+
// newHeaders.forEach((value, key) => console.log(`${key} : ${value}`));
110+
const newReq = new Request(targetUrl, {
111+
method: request.method,
112+
headers: newHeaders,
113+
body: request.body,
114+
});
115+
// console.log('request url : ', newReq.url);
116+
const res = await fetch(newReq);
117+
return res;
118+
// const newRes = new Response(res.body, res);
119+
// newRes.headers.set('access-control-allow-origin', '*');
120+
// newRes.headers.set('access-control-allow-methods', '*');
121+
// newRes.headers.set('access-control-allow-headers', '*');
122+
// return newRes;
123+
},
124+
};

common/ip.go

-4
Original file line numberDiff line numberDiff line change
@@ -2322,9 +2322,6 @@ var IP_RANGE = [][]string{
23222322
{"100.43.0.0", "100.43.95.255"}, //24,576
23232323
{"100.43.128.0", "100.63.255.255"}, //1,343,488
23242324
{"100.128.0.0", "100.255.255.255"}, //8,388,608
2325-
{"101.45.0.0", "101.45.255.255"}, //65,536
2326-
{"101.49.0.0", "101.49.127.255"}, //32,768
2327-
{"101.49.192.0", "101.49.255.255"}, //16,384
23282325
{"104.0.0.0", "104.28.7.255"}, //1,837,056
23292326
{"104.28.157.0", "104.28.255.255"}, //25,344
23302327
{"104.29.105.0", "104.30.1.255"}, //39,168
@@ -2926,7 +2923,6 @@ var IP_RANGE = [][]string{
29262923
{"137.167.0.0", "137.169.40.255"}, //141,568
29272924
{"137.169.43.0", "137.170.255.255"}, //120,064
29282925
{"137.173.0.0", "137.173.255.255"}, //65,536
2929-
{"137.175.0.0", "137.175.127.255"}, //32,768
29302926
{"137.176.0.0", "137.177.34.255"}, //74,496
29312927
{"137.177.36.0", "137.184.159.255"}, //490,496
29322928
{"137.184.176.0", "137.184.247.255"}, //18,432

0 commit comments

Comments
 (0)