block-proxy 0.1.12 → 0.1.13
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/.claude/settings.local.json +26 -1
- package/.claude/skills/build-client/skill.md +24 -0
- package/.claude/skills/release-client/skill.md +68 -0
- package/CLAUDE.md +69 -67
- package/Dockerfile +1 -1
- package/README.md +38 -24
- package/build/asset-manifest.json +6 -6
- package/build/index.html +1 -1
- package/build/static/css/main.3f317ce6.css +2 -0
- package/build/static/css/main.3f317ce6.css.map +1 -0
- package/build/static/js/{main.2247fb80.js → main.68f66be0.js} +3 -3
- package/build/static/js/main.68f66be0.js.map +1 -0
- package/client/app.py +312 -0
- package/client/build.sh +84 -0
- package/client/config.py +49 -0
- package/client/config_window.py +155 -0
- package/client/icons/app.icns +0 -0
- package/client/icons/app_example.png +0 -0
- package/client/icons/app_icon.png +0 -0
- package/client/icons/backup/app_example.png +0 -0
- package/client/icons/backup/christmas-sock_dark.png +0 -0
- package/client/icons/backup/christmas-sock_light.png +0 -0
- package/client/icons/backup/socks_on_G.png +0 -0
- package/client/icons/backup/socks_on_M.png +0 -0
- package/client/icons/christmas-sock_dark.png +0 -0
- package/client/icons/christmas-sock_light.png +0 -0
- package/client/icons/christmas-sock_light_bar.png +0 -0
- package/client/icons/socks_on_G.png +0 -0
- package/client/icons/socks_on_G_bar.png +0 -0
- package/client/icons/socks_on_M.png +0 -0
- package/client/icons/socks_on_M_bar.png +0 -0
- package/client/main.py +28 -0
- package/client/proxy_core.py +475 -0
- package/client/requirements.txt +3 -0
- package/client/scripts/download_xray.sh +30 -0
- package/client/setup.py +30 -0
- package/client/system_proxy.py +94 -0
- package/client/tests/__init__.py +0 -0
- package/client/tests/test_config.py +72 -0
- package/client/tests/test_system_proxy.py +69 -0
- package/client/watch-icons.js +31 -0
- package/config.json +28 -3
- package/docs/superpowers/plans/2026-05-27-blockproxyclient.md +1274 -0
- package/docs/superpowers/specs/2026-05-27-blockproxyclient-design.md +264 -0
- package/package.json +10 -4
- package/proxy/proxy.js +19 -15
- package/server/express.js +17 -1
- package/src/App.css +596 -276
- package/src/App.js +25 -22
- package/src/index.css +3 -4
- package/test/lib/mock-server.js +133 -0
- package/test/proxy-tests.js +708 -0
- package/test/run.js +330 -0
- package/build/static/css/main.8bfa3d5f.css +0 -2
- package/build/static/css/main.8bfa3d5f.css.map +0 -1
- package/build/static/js/main.2247fb80.js.map +0 -1
- package/hack-of-anyproxy/lib/requestHandler.js +0 -1060
- /package/build/static/js/{main.2247fb80.js.LICENSE.txt → main.68f66be0.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# BlockProxyClient macOS 桌面客户端设计
|
|
2
|
+
|
|
3
|
+
## 概述
|
|
4
|
+
|
|
5
|
+
BlockProxyClient 是一个 macOS 状态栏应用,用于连接 block-proxy 服务端的 SOCKS5 over TLS 代理服务。通过 xray-core 作为本地转发核心,提供本地 SOCKS5 和 HTTP 代理端口,并可选自动设置系统全局代理。
|
|
6
|
+
|
|
7
|
+
## 技术选型
|
|
8
|
+
|
|
9
|
+
| 层次 | 技术 | 理由 |
|
|
10
|
+
|------|------|------|
|
|
11
|
+
| UI 框架 | Python + rumps | 极简 macOS 状态栏库,几十行代码即可实现菜单+窗口 |
|
|
12
|
+
| 转发核心 | xray-core | 成熟稳定,原生支持 SOCKS5 over TLS、本地 SOCKS/HTTP inbound、UDP |
|
|
13
|
+
| 系统代理 | networksetup CLI | macOS 原生命令,无需额外依赖 |
|
|
14
|
+
| 配置窗口 | tkinter | 多字段表单需要完整窗口控件(rumps.Window 仅支持单行输入) |
|
|
15
|
+
| 打包 | py2app | 打包为 .app,内嵌 xray-core 二进制 |
|
|
16
|
+
|
|
17
|
+
## 目录结构
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
client/
|
|
21
|
+
├── main.py # 入口,启动 rumps 状态栏应用
|
|
22
|
+
├── app.py # BlockProxyClient 主类(rumps.App 子类)
|
|
23
|
+
├── config.py # 节点配置管理(读写 JSON)
|
|
24
|
+
├── xray_manager.py # xray-core 进程管理(启动/停止/生成配置)
|
|
25
|
+
├── system_proxy.py # macOS 系统代理设置(networksetup 封装)
|
|
26
|
+
├── resources/
|
|
27
|
+
│ ├── icon.png # 状态栏图标(已连接)
|
|
28
|
+
│ ├── icon_off.png # 状态栏图标(未连接)
|
|
29
|
+
│ └── xray-core # 内嵌的 xray-core 二进制(开发阶段可从 PATH 获取)
|
|
30
|
+
├── requirements.txt # rumps, py2app
|
|
31
|
+
└── setup.py # py2app 打包配置
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## UI 设计
|
|
35
|
+
|
|
36
|
+
### 状态栏菜单
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
[图标] BlockProxyClient
|
|
40
|
+
├── ● 开启代理 / ○ 关闭代理 (点击切换状态)
|
|
41
|
+
├── 节点配置... (打开配置窗口)
|
|
42
|
+
├── ─────────────
|
|
43
|
+
├── ◉ 全局代理 (自动设置系统 SOCKS/HTTP 代理)
|
|
44
|
+
├── ○ 手动模式 (仅启动本地监听,不修改系统设置)
|
|
45
|
+
├── ─────────────
|
|
46
|
+
└── 退出
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 状态栏图标
|
|
50
|
+
|
|
51
|
+
- 未连接:灰色图标
|
|
52
|
+
- 已连接:黑色/彩色图标
|
|
53
|
+
|
|
54
|
+
### 节点配置窗口
|
|
55
|
+
|
|
56
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
57
|
+
|------|------|--------|------|
|
|
58
|
+
| 地址 | 文本输入 | 空 | 服务器 IP 或域名 |
|
|
59
|
+
| 端口 | 数字输入 | 8002 | 服务端 SOCKS5 over TLS 端口 |
|
|
60
|
+
| 用户名 | 文本输入 | 空 | SOCKS5 认证用户名 |
|
|
61
|
+
| 密码 | 密码输入 | 空 | SOCKS5 认证密码 |
|
|
62
|
+
| 启用 TLS | 复选框 | 开启 | 是否使用 TLS 加密连接 |
|
|
63
|
+
| allowInsecure | 下拉 | true | 是否允许不安全证书(自签证书需设为 true) |
|
|
64
|
+
| 本地 SOCKS 监听端口 | 数字输入 | 1080 | 本地 SOCKS5 代理端口 |
|
|
65
|
+
| 本地 HTTP 监听端口 | 数字输入 | 1087 | 本地 HTTP 代理端口 |
|
|
66
|
+
| 启用 UDP | 复选框 | 开启 | 是否启用 UDP 转发 |
|
|
67
|
+
|
|
68
|
+
## 核心模块设计
|
|
69
|
+
|
|
70
|
+
### config.py - 配置管理
|
|
71
|
+
|
|
72
|
+
配置文件位置:`~/Library/Application Support/BlockProxyClient/config.json`
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"server": {
|
|
77
|
+
"address": "",
|
|
78
|
+
"port": 8002,
|
|
79
|
+
"username": "",
|
|
80
|
+
"password": "",
|
|
81
|
+
"tls": true,
|
|
82
|
+
"allowInsecure": true
|
|
83
|
+
},
|
|
84
|
+
"local": {
|
|
85
|
+
"socks_port": 1080,
|
|
86
|
+
"http_port": 1087,
|
|
87
|
+
"udp": true
|
|
88
|
+
},
|
|
89
|
+
"mode": "global"
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
功能:
|
|
94
|
+
- 读取/保存配置到 JSON 文件
|
|
95
|
+
- 配置变更后通知其他模块(用于重启 xray)
|
|
96
|
+
- 首次运行创建默认配置
|
|
97
|
+
|
|
98
|
+
### xray_manager.py - xray-core 进程管理
|
|
99
|
+
|
|
100
|
+
职责:
|
|
101
|
+
1. 根据用户配置生成 xray JSON 配置文件
|
|
102
|
+
2. 启动/停止 xray-core 子进程
|
|
103
|
+
3. 监控进程状态(意外退出时通知 UI)
|
|
104
|
+
|
|
105
|
+
生成的 xray 配置结构:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"inbounds": [
|
|
110
|
+
{
|
|
111
|
+
"tag": "socks-in",
|
|
112
|
+
"port": "<local.socks_port>",
|
|
113
|
+
"listen": "127.0.0.1",
|
|
114
|
+
"protocol": "socks",
|
|
115
|
+
"settings": { "udp": "<local.udp>" }
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"tag": "http-in",
|
|
119
|
+
"port": "<local.http_port>",
|
|
120
|
+
"listen": "127.0.0.1",
|
|
121
|
+
"protocol": "http"
|
|
122
|
+
}
|
|
123
|
+
],
|
|
124
|
+
"outbounds": [
|
|
125
|
+
{
|
|
126
|
+
"protocol": "socks",
|
|
127
|
+
"settings": {
|
|
128
|
+
"servers": [{
|
|
129
|
+
"address": "<server.address>",
|
|
130
|
+
"port": "<server.port>",
|
|
131
|
+
"users": [{ "user": "<server.username>", "pass": "<server.password>" }]
|
|
132
|
+
}]
|
|
133
|
+
},
|
|
134
|
+
"streamSettings": {
|
|
135
|
+
"network": "tcp",
|
|
136
|
+
"security": "<tls|none>",
|
|
137
|
+
"tlsSettings": {
|
|
138
|
+
"allowInsecure": "<server.allowInsecure>",
|
|
139
|
+
"serverName": "<server.address>"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
进程管理:
|
|
148
|
+
- 启动:`subprocess.Popen([xray_path, "run", "-c", config_path], stdout=PIPE, stderr=PIPE)`
|
|
149
|
+
- 停止:`process.terminate()` → 等待 3 秒 → `process.kill()`
|
|
150
|
+
- xray-core 路径:开发时从 PATH 查找,打包后从 .app bundle Resources 目录读取
|
|
151
|
+
- 健康检查:后台线程定期 poll 进程状态
|
|
152
|
+
|
|
153
|
+
### system_proxy.py - macOS 系统代理
|
|
154
|
+
|
|
155
|
+
通过 `networksetup` 命令操作:
|
|
156
|
+
|
|
157
|
+
开启全局代理:
|
|
158
|
+
```bash
|
|
159
|
+
# 自动检测活跃网络接口(Wi-Fi / Ethernet / etc.)
|
|
160
|
+
networksetup -setsocksfirewallproxy "<interface>" 127.0.0.1 <socks_port>
|
|
161
|
+
networksetup -setsocksfirewallproxystate "<interface>" on
|
|
162
|
+
networksetup -setwebproxy "<interface>" 127.0.0.1 <http_port>
|
|
163
|
+
networksetup -setwebproxystate "<interface>" on
|
|
164
|
+
networksetup -setsecurewebproxy "<interface>" 127.0.0.1 <http_port>
|
|
165
|
+
networksetup -setsecurewebproxystate "<interface>" on
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
关闭全局代理:
|
|
169
|
+
```bash
|
|
170
|
+
networksetup -setsocksfirewallproxystate "<interface>" off
|
|
171
|
+
networksetup -setwebproxystate "<interface>" off
|
|
172
|
+
networksetup -setsecurewebproxystate "<interface>" off
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
安全机制:
|
|
176
|
+
- `atexit` 注册清除代理的回调,防止程序崩溃后代理残留
|
|
177
|
+
- 信号处理(SIGTERM, SIGINT)也清除代理
|
|
178
|
+
|
|
179
|
+
网络接口检测:
|
|
180
|
+
- 通过 `networksetup -listallnetworkservices` 获取所有接口
|
|
181
|
+
- 通过 `networksetup -getinfo <interface>` 判断哪些接口活跃
|
|
182
|
+
- 对所有活跃接口设置代理
|
|
183
|
+
|
|
184
|
+
### app.py - 主应用
|
|
185
|
+
|
|
186
|
+
rumps.App 子类,负责:
|
|
187
|
+
1. 状态栏菜单渲染和事件处理
|
|
188
|
+
2. 协调 config / xray_manager / system_proxy 三个模块
|
|
189
|
+
3. 维护全局状态(是否已连接、当前模式)
|
|
190
|
+
|
|
191
|
+
状态机:
|
|
192
|
+
```
|
|
193
|
+
初始 → [用户点击开启] → 读取配置 → 生成 xray config → 启动 xray → (全局代理模式?) → 设置系统代理 → 已连接
|
|
194
|
+
已连接 → [用户点击关闭] → 清除系统代理 → 停止 xray → 未连接
|
|
195
|
+
已连接 → [切换模式] → 设置/清除系统代理(xray 不重启)
|
|
196
|
+
已连接 → [xray 意外退出] → 清除系统代理 → 更新 UI 为未连接
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## 打包与分发
|
|
200
|
+
|
|
201
|
+
### py2app 配置
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
# setup.py
|
|
205
|
+
from setuptools import setup
|
|
206
|
+
|
|
207
|
+
APP = ['main.py']
|
|
208
|
+
DATA_FILES = [('resources', ['resources/xray-core', 'resources/icon.png', 'resources/icon_off.png'])]
|
|
209
|
+
OPTIONS = {
|
|
210
|
+
'argv_emulation': False,
|
|
211
|
+
'iconfile': 'resources/app_icon.icns',
|
|
212
|
+
'plist': {
|
|
213
|
+
'LSUIElement': True,
|
|
214
|
+
'CFBundleName': 'BlockProxyClient',
|
|
215
|
+
'CFBundleIdentifier': 'com.jaylli.blockproxyclient',
|
|
216
|
+
},
|
|
217
|
+
'packages': ['rumps'],
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
setup(
|
|
221
|
+
app=APP,
|
|
222
|
+
data_files=DATA_FILES,
|
|
223
|
+
options={'py2app': OPTIONS},
|
|
224
|
+
setup_requires=['py2app'],
|
|
225
|
+
)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
- `LSUIElement: True`:无 Dock 图标,仅状态栏显示
|
|
229
|
+
- xray-core 二进制内嵌在 .app/Contents/Resources/ 中
|
|
230
|
+
- 构建命令:`python setup.py py2app`
|
|
231
|
+
|
|
232
|
+
### xray-core 获取
|
|
233
|
+
|
|
234
|
+
开发阶段:
|
|
235
|
+
- 从 xray-core GitHub Releases 下载对应平台二进制
|
|
236
|
+
- 放入 `client/resources/xray-core`
|
|
237
|
+
- 确保有执行权限
|
|
238
|
+
|
|
239
|
+
## 依赖清单
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
# requirements.txt
|
|
243
|
+
rumps>=0.4.0
|
|
244
|
+
py2app>=0.28
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
运行时无其他 Python 依赖(xray-core 是独立二进制)。
|
|
248
|
+
|
|
249
|
+
## 与服务端的协议兼容性
|
|
250
|
+
|
|
251
|
+
客户端通过 xray-core 的 SOCKS outbound + TLS streamSettings 连接服务端,协议流程:
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
本地应用 → 本地 SOCKS5/HTTP (xray inbound)
|
|
255
|
+
→ xray outbound: TLS 握手 → SOCKS5 认证 (username/password)
|
|
256
|
+
→ SOCKS5 CONNECT/UDP ASSOCIATE
|
|
257
|
+
→ 服务端 (socks5/server.js) → 下游 HTTP 代理 → 目标
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
兼容性要点:
|
|
261
|
+
- 服务端使用自签证书 → 客户端 `allowInsecure: true`
|
|
262
|
+
- 服务端认证方式:SOCKS5 username/password (RFC 1929)
|
|
263
|
+
- 服务端支持 TCP CONNECT 和 UDP ASSOCIATE
|
|
264
|
+
- TLS 最低版本:TLSv1.2(服务端设定)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "block-proxy",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "Small-scale network mitm proxy filter",
|
|
5
5
|
"bin": {
|
|
6
6
|
"block-proxy": "bin/start.js"
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
19
|
"cp": "echo '----- program start -----'",
|
|
20
|
-
"rm_bkconfig": "rm ./config_backup.json",
|
|
20
|
+
"rm_bkconfig": "rm -f ./config_backup.json",
|
|
21
21
|
"craco": "craco start",
|
|
22
22
|
"dev": "BLOCK_PROXY_DEV=1 npm run express",
|
|
23
23
|
"start": "npm run express",
|
|
@@ -25,9 +25,15 @@
|
|
|
25
25
|
"express": "npm run cp && node ./server/start.js",
|
|
26
26
|
"proxy": "npm run cp && node ./proxy/start.js",
|
|
27
27
|
"build": "npm run rm_bkconfig && react-scripts build",
|
|
28
|
-
"docker:build": "npm run build && docker build -t block-proxy .",
|
|
29
|
-
"docker:
|
|
28
|
+
"docker:build": "npm run build && docker buildx build --platform linux/amd64 --load -t block-proxy:amd64 .",
|
|
29
|
+
"docker:build:arm": "npm run build && docker buildx build --platform linux/arm64 --load -t block-proxy:arm64 .",
|
|
30
|
+
"docker:push": "npm run build && docker buildx build --platform linux/amd64 --push -t crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest-amd64 . && docker buildx build --platform linux/arm64 --push -t crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest-arm64 . && docker manifest create crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest-amd64 crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest-arm64 && docker manifest push crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest",
|
|
31
|
+
"docker:push:amd64": "npm run build && docker buildx build --platform linux/amd64 --push -t crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest-amd64 .",
|
|
32
|
+
"docker:push:arm64": "npm run build && docker buildx build --platform linux/arm64 --push -t crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest-arm64 .",
|
|
30
33
|
"test": "react-scripts test",
|
|
34
|
+
"gen-icons": "node client/watch-icons.js",
|
|
35
|
+
"watch:icons": "node client/watch-icons.js --watch",
|
|
36
|
+
"test:proxy": "node test/run.js",
|
|
31
37
|
"eject": "react-scripts eject"
|
|
32
38
|
},
|
|
33
39
|
"devDependencies": {
|
package/proxy/proxy.js
CHANGED
|
@@ -57,7 +57,8 @@ var is_running_in_docker = false;
|
|
|
57
57
|
var docker_host_IP = '';
|
|
58
58
|
var enable_express = "1"; // "0", "1"
|
|
59
59
|
var enable_socks5 = "1";
|
|
60
|
-
var enable_webinterface = "
|
|
60
|
+
var enable_webinterface = "0"; // "0", "1"
|
|
61
|
+
var enable_mitm = "1"; // "0", "1",是否对 HTTPS 启用 MITM 解密(关闭后纯隧道转发,不拦截)
|
|
61
62
|
// 域名判断,区分浏览器和 App
|
|
62
63
|
var filtered_mitm_domains = [
|
|
63
64
|
...uaFilter.filtered_mitm_domains
|
|
@@ -279,6 +280,9 @@ async function loadConfig() {
|
|
|
279
280
|
enable_webinterface = loadedConfig.enable_webinterface;
|
|
280
281
|
config.enable_webinterface = enable_webinterface;
|
|
281
282
|
|
|
283
|
+
enable_mitm = loadedConfig.enable_mitm || "1"; // 默认开启,兼容旧配置文件缺少此字段
|
|
284
|
+
config.enable_mitm = enable_mitm;
|
|
285
|
+
|
|
282
286
|
socks5Port = loadedConfig.socks5_port;
|
|
283
287
|
config.socks5_port = socks5Port;
|
|
284
288
|
|
|
@@ -315,6 +319,7 @@ async function loadConfig() {
|
|
|
315
319
|
socks5_port: socks5Port,
|
|
316
320
|
enable_socks5: enable_socks5,
|
|
317
321
|
enable_webinterface: enable_webinterface,
|
|
322
|
+
enable_mitm: enable_mitm,
|
|
318
323
|
vpn_proxy: ""
|
|
319
324
|
});
|
|
320
325
|
// fs.writeFileSync(configPath, JSON.stringify({
|
|
@@ -1086,30 +1091,29 @@ function getAnyProxyOptions() {
|
|
|
1086
1091
|
}
|
|
1087
1092
|
}
|
|
1088
1093
|
|
|
1089
|
-
// rewrite
|
|
1090
|
-
|
|
1091
|
-
|
|
1094
|
+
// rewrite 规则判断(YouTube 去广告、有道词典 VIP 等)
|
|
1095
|
+
// 这些规则需要 MITM 解密 response body,仅在 enable_mitm 开启时生效
|
|
1096
|
+
if (enable_mitm == "1" && shouldMitm(host)) {
|
|
1097
|
+
return true; // MITM 解密,执行 rewrite 规则
|
|
1092
1098
|
}
|
|
1093
1099
|
|
|
1094
|
-
// HTTPS 这里只判断 ip 源和域名
|
|
1095
|
-
// 域名不匹配的就直接转发
|
|
1096
|
-
// 域名匹配的情况下,再去看 match_rule 的判断,放到 beforeSendRequest 中
|
|
1097
|
-
|
|
1098
1100
|
// 如果是裸IP请求,全部放行
|
|
1099
1101
|
if (net.isIPv4(host) || net.isIPv6(host)) {
|
|
1100
1102
|
return false;
|
|
1101
1103
|
}
|
|
1102
1104
|
|
|
1103
|
-
//
|
|
1104
|
-
|
|
1105
|
-
if (blockRules.length === 0) {
|
|
1105
|
+
// enable_mitm 关闭时纯隧道转发,不做任何拦截
|
|
1106
|
+
if (enable_mitm != "1") {
|
|
1106
1107
|
return false;
|
|
1107
|
-
}
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
let shouldBlock = shouldBlockHost(host, blockRules, "");
|
|
1111
|
+
if (blockRules.length > 0 && shouldBlock) {
|
|
1112
|
+
// 有证书:走 MITM 解密后在 beforeSendRequest 中做完整 URL 路径级过滤
|
|
1108
1113
|
console.log('https 拦截', host, '接下来判断是否根据 match_rule 进行拦截');
|
|
1109
|
-
|
|
1110
|
-
return true; // 允许 HTTPS 拦截
|
|
1114
|
+
return true;
|
|
1111
1115
|
}
|
|
1112
|
-
return false; // 不拦截 HTTPS
|
|
1116
|
+
return false; // 不拦截 HTTPS,透明隧道转发
|
|
1113
1117
|
},
|
|
1114
1118
|
|
|
1115
1119
|
// 拦截 HTTP 请求以及 HTTPS 拆包的请求
|
package/server/express.js
CHANGED
|
@@ -11,7 +11,7 @@ const { exec, execSync } = require('child_process');
|
|
|
11
11
|
const LocalProxy = require('../proxy/proxy');
|
|
12
12
|
|
|
13
13
|
const app = express();
|
|
14
|
-
const PORT =
|
|
14
|
+
const PORT = 8003;
|
|
15
15
|
const DEV = process.env.BLOCK_PROXY_DEV || 0;
|
|
16
16
|
const configPath = path.join(__dirname, '../config.json');
|
|
17
17
|
|
|
@@ -199,6 +199,22 @@ app.use(/\/proxy\/*/, async (req, res) => {
|
|
|
199
199
|
}
|
|
200
200
|
});
|
|
201
201
|
|
|
202
|
+
// 证书下载接口
|
|
203
|
+
app.get('/fetchCrtFile', (req, res) => {
|
|
204
|
+
try {
|
|
205
|
+
const certPath = path.join(__dirname, '../cert/rootCA.crt');
|
|
206
|
+
if (fs.existsSync(certPath)) {
|
|
207
|
+
res.setHeader('Content-Type', 'application/x-x509-ca-cert');
|
|
208
|
+
res.setHeader('Content-Disposition', 'attachment; filename="rootCA.crt"');
|
|
209
|
+
res.sendFile(certPath);
|
|
210
|
+
} else {
|
|
211
|
+
res.status(404).json({ error: '证书文件不存在,请先生成根证书' });
|
|
212
|
+
}
|
|
213
|
+
} catch (error) {
|
|
214
|
+
res.status(500).json({ error: '证书下载失败: ' + error.message });
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
202
218
|
// 3. 所有其他请求都返回 index.html(支持 React Router 的前端路由)
|
|
203
219
|
app.get((req, res) => {
|
|
204
220
|
res.sendFile(path.join(__dirname, 'build', 'index.html'));
|