knowly 6.45.0 → 6.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/knowly-darwin +0 -0
- package/bin/knowly-darwin-arm64 +0 -0
- package/bin/knowly-linux +0 -0
- package/package.json +1 -1
- package/scripts/deepseek-proxy-worker.js +139 -0
package/bin/knowly-darwin
CHANGED
|
Binary file
|
package/bin/knowly-darwin-arm64
CHANGED
|
Binary file
|
package/bin/knowly-linux
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// DeepSeek Reverse Proxy - Cloudflare Worker
|
|
2
|
+
// 部署到: deepseek.yuanguangshan.workers.dev
|
|
3
|
+
// 功能:代理 chat.deepseek.com + fe-static.deepseek.com,剥离安全头
|
|
4
|
+
// 手机/电脑都可以通过 iframe 加载 DeepSeek
|
|
5
|
+
|
|
6
|
+
const TARGET_MAIN = 'https://chat.deepseek.com';
|
|
7
|
+
const TARGET_CDN = 'https://fe-static.deepseek.com';
|
|
8
|
+
const CDN_PREFIX = '/_cdn';
|
|
9
|
+
|
|
10
|
+
const HEADERS_TO_REMOVE = [
|
|
11
|
+
'x-frame-options',
|
|
12
|
+
'content-security-policy',
|
|
13
|
+
'content-security-policy-report-only',
|
|
14
|
+
'x-content-type-options',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export default {
|
|
18
|
+
async fetch(request, env) {
|
|
19
|
+
const url = new URL(request.url);
|
|
20
|
+
const workerOrigin = url.origin;
|
|
21
|
+
|
|
22
|
+
// 健康检查
|
|
23
|
+
if (url.pathname === '/health') {
|
|
24
|
+
return new Response('OK', { status: 200 });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// OPTIONS 预检
|
|
28
|
+
if (request.method === 'OPTIONS') {
|
|
29
|
+
return new Response(null, {
|
|
30
|
+
status: 204,
|
|
31
|
+
headers: {
|
|
32
|
+
'access-control-allow-origin': '*',
|
|
33
|
+
'access-control-allow-methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
|
34
|
+
'access-control-allow-headers': '*',
|
|
35
|
+
'access-control-max-age': '86400',
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 路由:/_cdn/xxx -> fe-static.deepseek.com/xxx,其余 -> chat.deepseek.com
|
|
41
|
+
let targetUrl;
|
|
42
|
+
let targetOrigin;
|
|
43
|
+
if (url.pathname.startsWith(CDN_PREFIX + '/')) {
|
|
44
|
+
const realPath = url.pathname.slice(CDN_PREFIX.length);
|
|
45
|
+
targetUrl = TARGET_CDN + realPath + url.search;
|
|
46
|
+
targetOrigin = TARGET_CDN;
|
|
47
|
+
} else {
|
|
48
|
+
targetUrl = TARGET_MAIN + url.pathname + url.search;
|
|
49
|
+
targetOrigin = TARGET_MAIN;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 构造转发 headers
|
|
53
|
+
const headers = new Headers(request.headers);
|
|
54
|
+
headers.delete('host');
|
|
55
|
+
headers.set('origin', TARGET_MAIN);
|
|
56
|
+
headers.set('referer', TARGET_MAIN + '/');
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const response = await fetch(targetUrl, {
|
|
60
|
+
method: request.method,
|
|
61
|
+
headers: headers,
|
|
62
|
+
body: ['GET', 'HEAD'].includes(request.method) ? undefined : request.body,
|
|
63
|
+
redirect: 'manual',
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// 构造新响应头
|
|
67
|
+
const newHeaders = new Headers(response.headers);
|
|
68
|
+
for (const h of HEADERS_TO_REMOVE) {
|
|
69
|
+
newHeaders.delete(h);
|
|
70
|
+
}
|
|
71
|
+
newHeaders.set('access-control-allow-origin', '*');
|
|
72
|
+
newHeaders.set('access-control-allow-methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
|
|
73
|
+
newHeaders.set('access-control-allow-headers', '*');
|
|
74
|
+
|
|
75
|
+
// 处理 Set-Cookie
|
|
76
|
+
const setCookieHeader = response.headers.get('set-cookie');
|
|
77
|
+
if (setCookieHeader) {
|
|
78
|
+
newHeaders.delete('set-cookie');
|
|
79
|
+
const cookies = setCookieHeader.split(/,(?=\s*\w+=)/);
|
|
80
|
+
for (const cookie of cookies) {
|
|
81
|
+
const cleaned = cookie
|
|
82
|
+
.replace(/;\s*domain=[^;]*/gi, '')
|
|
83
|
+
.replace(/;\s*secure/gi, '')
|
|
84
|
+
.replace(/;\s*samesite=[^;]*/gi, '; SameSite=None');
|
|
85
|
+
newHeaders.append('set-cookie', cleaned.trim());
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 处理重定向
|
|
90
|
+
if (newHeaders.has('location')) {
|
|
91
|
+
let location = newHeaders.get('location');
|
|
92
|
+
location = location.replace(TARGET_CDN, workerOrigin + CDN_PREFIX);
|
|
93
|
+
location = location.replace(TARGET_MAIN, workerOrigin);
|
|
94
|
+
newHeaders.set('location', location);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const contentType = response.headers.get('content-type') || '';
|
|
98
|
+
|
|
99
|
+
// HTML 响应:替换域名 + 移除 SRI integrity 属性
|
|
100
|
+
if (contentType.includes('text/html')) {
|
|
101
|
+
let body = await response.text();
|
|
102
|
+
// 移除 integrity 属性(因为我们修改了 JS/CSS 内容,哈希会变)
|
|
103
|
+
body = body.replace(/\s+integrity="[^"]*"/g, '');
|
|
104
|
+
body = body.replace(/\s+integrity='[^']*'/g, '');
|
|
105
|
+
// 移除 crossorigin 属性(避免不必要的 CORS 校验)
|
|
106
|
+
body = body.replace(/\s+crossorigin(?:="[^"]*")?/g, '');
|
|
107
|
+
// CDN 域名 → Worker/_cdn(必须先替换,因为更具体)
|
|
108
|
+
body = body.replace(/https?:\/\/fe-static\.deepseek\.com/g, workerOrigin + CDN_PREFIX);
|
|
109
|
+
// 主站域名 → Worker
|
|
110
|
+
body = body.replace(/https?:\/\/chat\.deepseek\.com/g, workerOrigin);
|
|
111
|
+
return new Response(body, { status: response.status, headers: newHeaders });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// JS/CSS 响应:替换 CDN 域名 + 主站域名
|
|
115
|
+
// 主站域名也必须替换,因为 DeepSeek JS 有 hostname 白名单校验
|
|
116
|
+
if (contentType.includes('javascript') || contentType.includes('text/css')) {
|
|
117
|
+
let body = await response.text();
|
|
118
|
+
// 1. 先替换带协议的完整 URL
|
|
119
|
+
body = body.replace(/https?:\/\/fe-static\.deepseek\.com/g, workerOrigin + CDN_PREFIX);
|
|
120
|
+
body = body.replace(/https?:\/\/chat\.deepseek\.com/g, workerOrigin);
|
|
121
|
+
// 2. 再替换裸域名(hostname 白名单校验用的是不带协议的域名)
|
|
122
|
+
const workerHost = new URL(workerOrigin).hostname;
|
|
123
|
+
body = body.replace(/chat\.deepseek\.com/g, workerHost);
|
|
124
|
+
return new Response(body, { status: response.status, headers: newHeaders });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 如果响应是 wasm 文件,需要确保 Content-Type 为 application/wasm
|
|
128
|
+
if (url.pathname.endsWith('.wasm')) {
|
|
129
|
+
newHeaders.set('content-type', 'application/wasm');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// JSON / 其他类型(图片、字体、wasm等)直接透传
|
|
133
|
+
return new Response(response.body, { status: response.status, headers: newHeaders });
|
|
134
|
+
|
|
135
|
+
} catch (err) {
|
|
136
|
+
return new Response('Proxy Error: ' + err.message, { status: 502 });
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
};
|