block-proxy 0.1.14 → 0.1.16

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.
@@ -1,43 +1,97 @@
1
1
  {
2
2
  "permissions": {
3
3
  "allow": [
4
- "Bash(git commit:*)",
5
4
  "Bash(git add:*)",
6
- "Bash(tshark:*)",
7
- "Bash(python3:*)",
8
- "Bash(gh issue create:*)",
9
- "Bash(docker system *)",
10
- "Bash(grep -rn --include=\"*.js\" --include=\"*.ts\" --include=\"*.json\" -l \"benchmark\\\\|speed.test\\\\|speed_test\\\\|performance\\\\|latency\\\\|perf_test\\\\|perfTest\" /Users/hfy/jayli/block-proxy/ ! -path \"*/node_modules/*\")",
11
- "Bash(grep -rn \"ping\\\\|latency\\\\|speed\\\\|perf\\\\|benchmark\\\\|timeout\" /Users/hfy/jayli/block-proxy/ --include=\"*.js\" --include=\"*.ts\" --include=\"*.sh\" ! -path \"*/node_modules/*\" ! -path \"*/build/*\")",
12
- "Bash(oha *)",
13
- "Bash(ping *)",
14
- "Bash(brew install *)",
15
- "Bash(npm run *)",
16
- "Bash(pnpm i *)",
17
- "Bash(break)",
18
- "Bash(pkill -f \"node ./proxy/start.js\")",
19
- "Bash(pkill -f \"node ./socks5/start.js\")",
20
- "Bash(pkill -f \"node proxy/start.js\")",
21
- "Bash(pkill -f \"node socks5/start.js\")",
22
- "Bash(gh release *)",
23
- "Read(//Library/Frameworks/Python.framework/Versions/**)",
24
- "Bash(/Library/Frameworks/Python.framework/Versions/3.13/bin/python3 -m nuitka --version)",
25
- "Bash(ps *)",
26
- "Bash(pkill -f nuitka)",
27
- "Bash(sips *)",
5
+ "Bash(git commit:*)",
6
+ "Bash(npm test:*)",
7
+ "Bash(pnpm add:*)",
8
+ "Bash(npm install:*)",
9
+ "Bash(find:*)",
10
+ "Bash(.venv/bin/pip install *)",
28
11
  "Bash(git *)",
29
- "Bash(command -v fswatch)",
12
+ "Read(//Library/Frameworks/Python.framework/Versions/3.13/bin/**)",
13
+ "Bash(/Users/bachi/jaylli/block-proxy/client/.venv/bin/python -m pytest --version)",
14
+ "Bash(.venv/bin/python -m pytest tests/test_config.py -v)",
15
+ "Bash(.venv/bin/python --version)",
16
+ "Bash(chmod +x *)",
17
+ "Bash(bash *)",
18
+ "Bash(xxd)",
19
+ "Bash(md5 *)",
20
+ "Bash(python *)",
21
+ "Bash(mkdir -p \"/Users/bachi/Library/Application Support/SocksProxy\")",
22
+ "Bash(cp \"/Users/bachi/Library/Application Support/BlockProxyClient/config.json\" \"/Users/bachi/Library/Application Support/SocksProxy/config.json\")",
23
+ "Bash(rm -rf \"/Users/bachi/Library/Application Support/BlockProxyClient\")",
24
+ "Bash(shasum -a 256 /Users/bachi/jaylli/block-proxy/client/dist/SocksClient.app/Contents/MacOS/SocksClient)",
25
+ "Bash(xargs file)",
26
+ "Bash(shasum -a 256 /Users/bachi/Library/Python/3.13/lib/python/site-packages/py2app/apptemplate/prebuilt/main-universal2)",
27
+ "Bash(pip3 list *)",
28
+ "Bash(pip3 install *)",
29
+ "Bash(pip install *)",
30
+ "Bash(rm -rf build dist)",
31
+ "Bash(/Users/bachi/Library/Python/3.13/bin/pyinstaller --windowed --name SocksClient --icon icons/app_example.png --add-data \"icons:icons\" --osx-bundle-identifier com.jaylli.socksclient main.py)",
32
+ "Bash(sips -z 256 256 icons/app_example.png --out icons/app.iconset/icon_256x256.png)",
33
+ "Bash(sips -z 128 128 icons/app_example.png --out icons/app.iconset/icon_128x128.png)",
34
+ "Bash(sips -z 16 16 icons/app_example.png --out icons/app.iconset/icon_16x16.png)",
35
+ "Bash(iconutil -c icns icons/app.iconset -o icons/app.icns)",
36
+ "Bash(/Users/bachi/Library/Python/3.13/bin/pyinstaller --windowed --name SocksClient --icon icons/app.icns --add-data \"icons:icons\" --osx-bundle-identifier com.jaylli.socksclient main.py)",
37
+ "Bash(plutil *)",
38
+ "Bash(/Users/bachi/jaylli/block-proxy/client/dist/SocksClient.app/Contents/MacOS/SocksClient *)",
39
+ "Bash(pkill -f SocksClient)",
40
+ "Bash(./SocksClient -c ' *)",
41
+ "Bash(cat)",
42
+ "Bash(/Library/Frameworks/Python.framework/Versions/3.13/bin/python3 /tmp/test_socksclient.py)",
43
+ "Bash(cp /Users/bachi/jaylli/block-proxy/client/dist/SocksClient.app/Contents/MacOS/SocksClient /tmp/SocksClient_backup)",
44
+ "Read(//tmp/**)",
45
+ "Bash(networksetup *)",
46
+ "Bash(sw_vers *)",
47
+ "Bash(echo \"exit: $?\")",
48
+ "Bash(pytest *)",
49
+ "Bash(.venv/bin/python -m pytest tests/ -q)",
30
50
  "Bash(npm view *)",
31
- "Bash(npx react-scripts *)",
32
- "Bash(npm config *)",
33
- "Bash(npm whoami *)",
34
- "Bash(docker info *)",
35
- "Bash(docker manifest *)",
36
- "Bash(mkdir -p ~/JS-PERF_SERVER/downloads/block-proxy/arm)",
37
- "Bash(docker save *)",
38
- "Bash(pnpm install *)",
39
- "Bash(docker buildx ls *)",
40
- "Bash(npm version *)"
51
+ "Bash(gh release *)",
52
+ "Bash(zip -r -q SocksClient-macos-arm64.zip SocksClient.app)",
53
+ "Bash(sips -g pixelWidth -g pixelHeight socks_on_G_bar.png socks_on_M_bar.png christmas-sock_light_bar.png)",
54
+ "Bash(sips *)",
55
+ "WebSearch",
56
+ "Bash(iconutil -c iconset --output /tmp/check_iconset client/dist/SocksClient.app/Contents/Resources/app.icns)",
57
+ "Bash(iconutil -c iconset -o /tmp/check_iconset.iconset client/dist/SocksClient.app/Contents/Resources/app.icns)",
58
+ "WebFetch(domain:stackoverflow.com)",
59
+ "WebFetch(domain:forums.developer.apple.com)",
60
+ "Bash(echo \"Network OK: $?\")",
61
+ "Read(//System/Applications/Calculator.app/Contents/Resources/**)",
62
+ "Bash(codesign -dv client/dist/SocksClient.app)",
63
+ "Read(//System/Library/**)",
64
+ "Bash(defaults read *)",
65
+ "Read(//Applications/Visual Studio Code.app/Contents/Resources/**)",
66
+ "Read(//Applications/iTerm.app/Contents/Resources/**)",
67
+ "Bash(xcode-select -p)",
68
+ "Read(//Library/Developer/**)",
69
+ "Bash(xcrun --version)",
70
+ "Read(//Applications/**)",
71
+ "Bash(mdfind \"kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode'\")",
72
+ "Bash(brew list *)",
73
+ "Bash(assetutil --info \"/Applications/iTerm.app/Contents/Resources/Assets.car\")",
74
+ "Bash(brew search *)",
75
+ "Bash(brew info *)",
76
+ "Bash(pip3 search *)",
77
+ "Bash(xcode-select --install)",
78
+ "Bash(swift --version)",
79
+ "Bash(/tmp/set_icon client/icons/app_icon.png client/dist/SocksClient.app)",
80
+ "Bash(xattr -l client/dist/SocksClient.app)",
81
+ "Bash(xattr client/dist/SocksClient.app)",
82
+ "Bash(GetFileInfo client/dist/SocksClient.app)",
83
+ "Bash(mdfind \"kMDItemFSName == 'Icon Composer*'\")",
84
+ "Bash(/usr/bin/actool --version)",
85
+ "Bash(/usr/bin/actool --help)",
86
+ "Bash(brew install *)",
87
+ "Bash(fileicon set *)",
88
+ "Bash(echo \"Exit: $?\")",
89
+ "Bash(fileicon test *)",
90
+ "Bash(.venv/bin/pytest tests/ -v)",
91
+ "Bash(.venv/bin/pytest *)",
92
+ "Bash(.venv/bin/python3 *)",
93
+ "Bash(/usr/local/bin/python3 *)",
94
+ "Bash(.venv/bin/python -m pytest tests/ -v)"
41
95
  ]
42
96
  }
43
97
  }
@@ -0,0 +1,45 @@
1
+ # Skill: Icon Generate
2
+
3
+ 从源图标生成状态栏 bar 图标。将白色区域镂空为透明,缩放并添加 padding 后输出 44x44 @ 144 DPI 的状态栏图标。
4
+
5
+ ## Instructions
6
+
7
+ 1. **镂空白色区域**:
8
+ - 读取 `client/icons/socks_on_M.png` 和 `client/icons/socks_on_G.png`
9
+ - 将白色像素(R>240, G>240, B>240)的 alpha 设为 0(透明)
10
+ - 保存回原文件
11
+
12
+ 2. **生成 bar 图标**:
13
+ - 将镂空后的图片缩放至 38x38(内容区)
14
+ - 放置在 44x44 透明画布中央(四周各 3px padding)
15
+ - 设置 DPI 为 144x144
16
+ - 输出为 `client/icons/socks_on_M_bar.png` 和 `client/icons/socks_on_G_bar.png`
17
+
18
+ 3. **执行脚本**:
19
+ ```bash
20
+ python3 << 'PYEOF'
21
+ from PIL import Image
22
+
23
+ for name in ["socks_on_M", "socks_on_G"]:
24
+ img = Image.open(f"client/icons/{name}.png").convert("RGBA")
25
+ pixels = img.load()
26
+ w, h = img.size
27
+ for y in range(h):
28
+ for x in range(w):
29
+ r, g, b, a = pixels[x, y]
30
+ if r > 240 and g > 240 and b > 240:
31
+ pixels[x, y] = (r, g, b, 0)
32
+ img.save(f"client/icons/{name}.png")
33
+ print(f"{name}.png: 白色已镂空")
34
+
35
+ canvas = Image.new("RGBA", (44, 44), (0, 0, 0, 0))
36
+ resized = img.resize((38, 38), Image.LANCZOS)
37
+ canvas.paste(resized, (3, 3), resized)
38
+ canvas.save(f"client/icons/{name}_bar.png", dpi=(144, 144))
39
+ print(f"{name}_bar.png: 44x44 @ 144 DPI")
40
+ PYEOF
41
+ ```
42
+
43
+ 4. **报告结果**:
44
+ - 确认源文件白色已镂空
45
+ - 确认 bar 图标尺寸(44x44)和分辨率(144 DPI)
package/CLAUDE.md CHANGED
@@ -50,7 +50,7 @@ Block-Proxy is a MITM-based proxy filtering tool designed for parental control a
50
50
 
51
51
  6. **CLI** (`/bin/start.js`) – 全局命令入口,失败自动重启(max 10000 次),退出时清理全局配置
52
52
 
53
- 7. **AnyProxy Fork** (`node_modules/@bachi/anyproxy/`) – 核心 MITM 代理引擎,fork 自 AnyProxy 的私有 npm 包(v0.1.5)。关键源码:`proxy.js`(入口)、`lib/requestHandler.js`(HTTP/HTTPS 请求处理与转发)、`lib/httpsServerMgr.js`(HTTPS MITM 服务管理、动态证书生成)、`lib/certMgr.js`(根证书与域名证书管理)。所有底层连接处理、TLS 拦截、请求转发的实现分析都应从此包查找
53
+ 7. **AnyProxy Fork** (`node_modules/@bachi/anyproxy/`) – 核心 MITM 代理引擎,fork 自 AnyProxy 的私有 npm 包(v0.1.6)。关键源码:`proxy.js`(入口)、`lib/requestHandler.js`(HTTP/HTTPS 请求处理与转发)、`lib/httpsServerMgr.js`(HTTPS MITM 服务管理、动态证书生成)、`lib/certMgr.js`(根证书与域名证书管理)。所有底层连接处理、TLS 拦截、请求转发的实现分析都应从此包查找
54
54
 
55
55
  8. **TLS Certificates** (`/cert/`) – `rootCA.key` + `rootCA.crt`,Docker 构建时复制到容器的 `~/.anyproxy/certificates/`,客户端需安装此证书才能 HTTPS MITM
56
56
 
@@ -127,7 +127,7 @@ SOCKS5 先做 TLS 握手和认证,然后通过 CONNECT 命令建立隧道,
127
127
  ### Dependencies
128
128
  **Note:** `@bachi/anyproxy` 与较新 Node.js 版本不完全兼容,因此连同大多数运行时依赖一起放在 `devDependencies` 中(查看 package.json 了解完整列表)
129
129
 
130
- **核心依赖 `@bachi/anyproxy`(v0.1.5):** fork 自开源 AnyProxy 的私有 npm 包,是整个代理系统的底层引擎。分析连接处理、TLS 拦截、请求转发等底层逻辑时,应直接阅读 `node_modules/@bachi/anyproxy/` 的源码(而非项目根目录下的其他备份)。关键文件:
130
+ **核心依赖 `@bachi/anyproxy`(v0.1.6):** fork 自开源 AnyProxy 的私有 npm 包,是整个代理系统的底层引擎。分析连接处理、TLS 拦截、请求转发等底层逻辑时,应直接阅读 `node_modules/@bachi/anyproxy/` 的源码(而非项目根目录下的其他备份)。关键文件:
131
131
  - `proxy.js` — 包入口,创建代理服务器实例
132
132
  - `lib/requestHandler.js` — HTTP/HTTPS 请求处理与转发核心
133
133
  - `lib/httpsServerMgr.js` — HTTPS MITM 服务管理、动态伪造证书
@@ -171,6 +171,6 @@ main.py (入口, 文件锁单实例) → app.py (rumps 状态栏 App)
171
171
 
172
172
  # Project Rules & Skills
173
173
 
174
- - **Local Skills**: 实时遵循 `.claude/skills/*/skill.md` 中的指令。可用技能: `commit`, `pcap-analyse`
174
+ - **Local Skills**: 实时遵循 `.claude/skills/*/skill.md` 中的指令。可用技能: `commit`, `build-client`, `release-client`, `icon_generate`, `pcap-analyse`
175
175
  - **CLI入口**: 全局命令 `block-proxy` 注册在 `bin/start.js`,通过 `npm i -g` 安装后可直接调用
176
176
  - **config.json** 是运行时配置文件(非源码),由 `proxy/fs.js` 管理读写和备份,不在 git 中追踪变更
package/README.md CHANGED
@@ -1,213 +1,54 @@
1
-
2
1
  <img width="287" alt="image" src="https://github.com/user-attachments/assets/2bb069d8-508a-41b9-9fee-94a1e31cc0cb" />
3
2
 
4
- ---------------------------
5
-
6
3
  <a href="https://nodei.co/npm/block-proxy/"><img src="https://nodei.co/npm/block-proxy.svg?style=mini"></a>
7
4
 
8
- > **Block-Proxy**
9
-
10
- Socks5/http 代理工具,支持 MITM 和二次开发
11
-
12
- 用在家庭网关,限制小朋友上网用。特性:
5
+ > Socks5/HTTP 代理工具,支持 MITM 和二次开发。用于家庭网关限制小朋友上网。
13
6
 
14
7
  - HTTP 代理 + Socks5 over TLS 代理
15
- - 域名拦截、url 正则、Mac 地址拦截
16
- - 设定日期和时间段、顺便过滤广告
17
- - 提供服务端和客户端
18
-
19
- ### 1)服务端使用方法
8
+ - 域名拦截、URL 正则匹配、MAC 地址定向拦截
9
+ - 按时间段和星期拦截,内置广告过滤
10
+ - [macOS 客户端](https://github.com/jayli/block-proxy/releases) 一键连接
20
11
 
21
- #### ① 方式一:快速部署
12
+ ## 快速开始
22
13
 
23
- 安装:
24
-
25
- ```
14
+ ```bash
26
15
  npm install -g block-proxy
27
- ```
28
-
29
- 启动:
30
-
31
- ```
32
16
  block-proxy
33
17
  ```
34
18
 
35
- 或者带配置文件启动
36
-
37
- ```
38
- block-proxy -c rule.js
39
- ```
40
-
41
- 配置文件参照 [rule.js](example/rule.js),可留空
42
-
43
- #### ② 方式二,Docker 部署(推荐)
44
-
45
- 1. 拉取镜像(自动匹配架构):
46
-
47
- ```
48
- docker pull crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest
49
- ```
50
-
51
- 2. 启动:
19
+ 或使用 Docker(推荐):
52
20
 
53
- ```
21
+ ```bash
54
22
  docker run --init -d --restart=unless-stopped \
55
- -e TZ=Asia/Shanghai --network=host \
56
- --user=root \
57
- --log-driver local \
58
- --log-opt max-size=10m \
59
- --log-opt max-file=3 \
60
- --cpus="5" \
61
- --memory 400m \
62
- -v "$(pwd)/":/app/config \
63
- --name block-proxy crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest
23
+ -e TZ=Asia/Shanghai --network=host \
24
+ -v "$(pwd)/":/app/config \
25
+ --name block-proxy \
26
+ crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest
64
27
  ```
65
28
 
66
- 其中挂载目录 `$(pws)/` 下的 `rule.js` 是需要额外挂载的配置文件,可留空。
29
+ 首次启动后访问 `http://代理IP:8003` 进入后台配置面板。
67
30
 
68
- > block-proxy 可以配置只启动 proxy 不启动后台面板,首次启动后访问 http://代理IP:8001 根据提示操作。
31
+ ## 端口说明
69
32
 
70
- 网关里为了方便获取子网机器 ip mac 地址,docker 容器需要和宿主机共享同一个网络,同时指定时区。
33
+ | 端口 | 说明 | 可否关闭 |
34
+ |:----:|:----|:------:|
35
+ | 8001 | HTTP 代理端口 | 不可 |
36
+ | 8002 | Socks5 over TLS 代理端口 | 可 |
37
+ | 8003 | 后台配置面板 | 可 |
71
38
 
72
- 如果是在 Window/Mac 中,需要手动指定端口绑定(不推荐):
39
+ ## 开发
73
40
 
41
+ ```bash
42
+ pnpm i
43
+ npm run dev # 开发模式(含 React HMR,端口 3000)
44
+ npm run start # 生产启动
45
+ npm run proxy # 仅启动代理,不开后台面板
74
46
  ```
75
- docker run --init -d --restart=unless-stopped --user=root \
76
- -v "$(pwd)/":/app/config \
77
- -e TZ=Asia/Shanghai -p 8001:8001 -p 8002:8002 \
78
- --name block-proxy crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest
79
- ```
80
-
81
- ### 2)服务侧端口配置
82
-
83
- 1. 服务端配置:配置面板 <http://server-ip:8003>,关闭、启用配置面板:<http://server-ip:8001>
84
- 2. 客户端配置:http 代理直接在 iphone wifi 详情里手动配置,socks5 代理只支持 socks5 over TLS,用小火箭配置。配置信息参照[配置面板](http://localhost:8003)
85
-
86
- ### 3)服务侧代码的开发和调试
87
-
88
- 代码 clone 下来后执行`pnpm i`,执行 `npm run dev` 运行本地服务。默认开启 5 个端口:
89
-
90
- |端口 |说明 |可否关闭|
91
- |:----:|:------:|:------:|
92
- |3000 |调试端口(仅开发调试配置面板用)| 生产环境不启用|
93
- |8001 |HTTP 代理端口 | 不可禁用 |
94
- |8002 |Socks5(Over TLS)代理端口 | 可禁用 |
95
- |8003 |后台配置页端口 | 可禁用 |
96
- |8004 |~~已废弃~~ | 原后台配置页,已迁移至 8003 |
97
-
98
-
99
- ### 4)Block-Proxy 的 Docker 构建说明
100
-
101
- 准备工作,构建 docker 包,先启动本地 Docker:
102
-
103
- - 开发调试:`npm run dev`,开发调试用3000端口
104
- - 生产启动:`npm run start`,生产环境使用
105
- - 只启动代理:`npm run proxy`,不启动配置后台,只启动代理
106
- - 后台构建:`npm run build`
107
- - 本地构建 amd64:`npm run docker:build`
108
- - 本地构建 arm64:`npm run docker:build:arm`
109
- - 推送 amd64 + arm64 双架构到 ACR:`npm run docker:push`
110
- - 仅推送 amd64:`npm run docker:push:amd64`
111
- - 仅推送 arm64:`npm run docker:push:arm64`
112
-
113
- > 首次使用 `docker:push` 前需要先 ACR 登录:
114
- > ```
115
- > docker login --username=hi50078584@aliyun.com crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com
116
- > ```
117
- > 要是打包 docker 空间不够就执行 `docker system prune -a --volumes`
118
-
119
- 拷贝 tar 到 openwrt 后启动容器:参照上文 Docker部署。
120
-
121
- ### 5)客户端配置说明
122
-
123
- #### ① 代理端口
124
-
125
- - 8001:HTTP 代理
126
- - 8002:socks5 over TLS
127
-
128
- ⚠️ Socks5 代理不支持对 Mac 地址的定向拦截,Mac 地址的拦截只对局域网内的 HTTP 代理绑定生效。建议局域网绑定 http 代理,公网绑定 Socks5 代理。
129
-
130
- ⚠️ 使用小火箭的 Socks5 over TLS 代理,TLS 选项里勾选“允许不安全”
131
-
132
- #### ② 后台配置
133
-
134
- 访问路径:`http://proxy-ip:8003`
135
-
136
- 路由表间隔两小时刷新一次。如果新加入网的设备没生效,刷新一下路由表。添加限制条件后,点击重启代理按钮。
137
-
138
- <img src="https://github.com/user-attachments/assets/16f47d3f-1ef9-47a2-8640-c7e04ec64e1a" width=300 />
139
-
140
-
141
- #### ③ 设备配置
142
-
143
- 1. 证书设置:进入后台配置,扫码安装证书,在手机设置中安装该证书,同时配置完全信任:设置→通用→关于本机→证书信任设置→打开对AnyProxy的完全信任
144
- 2. 代理设置:iPhone/iPad 为例:设置 → 无线局域网 → 点击当前网络 → HTTP代理/配置代理,设置服务器和端口。
145
-
146
- 如果要通过 mac 地址拦截小朋友上网,小朋友的设备里把 Mac 固定下来:
147
-
148
- <img width="350" alt="image" src="https://github.com/user-attachments/assets/f9bfab89-7194-4a72-b1ae-5cca27911bc9" />
149
-
150
- #### ④ 禁掉设备直连
151
-
152
- 防止小朋友修改网Wifi连接,只允许设备通过代理访问,把直连上网权限关掉。网关里配置防火墙规则:
153
-
154
- ```
155
- iptables -I FORWARD -m mac --mac-source D2:9E:8D:1B:F1:4E -j REJECT
156
- ip6tables -I forwarding_rule -m mac --mac-source D2:9E:8D:1B:F1:4E -j REJECT
157
- ```
158
-
159
- 然后重启防火墙
160
-
161
-
162
- ### 6)关于 MITM
163
-
164
- #### 应用条件:
165
-
166
- 1. MITM 基于 AnyProxy 的规则实现,客户端设备必须要安装 AnyProxy 的证书。
167
- 2. 服务需要根据 ip 反查 mac 地址,需要代理服务工作在对子网有扫描权限的节点,最好是部署在 openwrt 网关,可以`arp -a`看下是否可以扫描完全。
168
- 3. 服务会自动更新路由表,每 2 个小时更新一次,对于新入网的设备,最好在后台手动刷新并重启代理,以免拦截规则不能立即生效。
169
- 4. 所有规则都在 HTTP 代理中生效,Socks5 on tls 是指向 AnyProxy 的反向代理,内网 Mac 地址的拦截只对直接绑定 HTTP 代理的情况生效。
170
-
171
- #### Youtube 去广告
172
-
173
- 一共六条拦截规则,这几条 reject 规则直接配置在后台里:
174
-
175
- - *youtube.com*:`^https?:\/\/(www|s)\.youtube\.com\/(pagead|ptracking)`
176
- - *youtube.com*:`^https?:\/\/s\.youtube\.com\/api\/stats\/qoe\?adcontext`
177
- - *youtube.com*:`^https?:\/\/(www|s)\.youtube\.com\/api\/stats\/ads`
178
- - *googlevideo.com*:`^https?:\/\/[\w-]+\.googlevideo\.com\/(?!(dclk_video_ads|videoplayback\?)).+&oad`
179
-
180
- 另外两条规则在这里:<https://github.com/jayli/block-proxy/blob/main/proxy/mitm/rule.js>(手工添加上面四条规则就够了)
181
-
182
- #### 有道词典会员
183
-
184
- done!
185
-
186
- #### 代理性能
187
-
188
- **并发测试**:
189
-
190
- |直连测试 |代理测试 |
191
- |:---------:|:----------------:|
192
- |<img height="500" alt="image" src="https://github.com/user-attachments/assets/8268bc5c-956f-4b67-89c1-cdd5725114b3" /> | <img height="500" alt="image" src="https://github.com/user-attachments/assets/abf4bfa1-c8b8-4907-ba0e-bcc76e8899fa" />|
193
-
194
- **网速测试**:
195
-
196
- <img width="544" alt="image" src="https://github.com/user-attachments/assets/67c61e34-67ae-4345-97ca-d266cd35ddf4" />
197
-
198
- > ⚠️ 提示:如果把 block-proxy 部署在 openwrt 网关上,代理地址和网关地址一致,iOS Safari 有一个默认安全限制,不支持带认证的代理和网关 IP 一致,两个解决办法:
199
- >
200
- >1. 不要填代理认证用户名和密码
201
- >2. 给 openwrt lan 口再绑定一个 IP,ios 设备在局域网内绑定这个 IP
202
- >
203
- ><img width="300" alt="image" src="https://github.com/user-attachments/assets/0f46d6b4-00b1-44aa-9be7-fa23a09bb199" />
204
-
205
- ### 7)客户端软件
206
47
 
207
- 提供了客户端桌面端连接代理工具 SocksClient.app,支持 MacOS(M系列)。
48
+ ## 更多文档
208
49
 
209
- 下载地址:[GitHub Release](https://github.com/jayli/block-proxy/releases/latest)
50
+ 详见 [wiki.md](wiki.md)
210
51
 
211
- ### License
52
+ ## License
212
53
 
213
54
  MIT
package/client/app.py CHANGED
@@ -4,6 +4,7 @@ import subprocess
4
4
  import threading
5
5
  import platform
6
6
  import rumps
7
+ from AppKit import NSImage, NSSize
7
8
  from PyObjCTools import AppHelper
8
9
  from Foundation import NSObject
9
10
  from config import Config
@@ -36,6 +37,7 @@ class SocksClient(rumps.App):
36
37
  self.proxy = ProxyCore()
37
38
  self.sys_proxy = SystemProxy()
38
39
  self.connected = False
40
+ self._config_proc = None
39
41
 
40
42
  self._measuring = False
41
43
  self._build_menu()
@@ -55,7 +57,7 @@ class SocksClient(rumps.App):
55
57
 
56
58
  def _build_menu(self):
57
59
  self.toggle_item = rumps.MenuItem("启动代理", callback=self.toggle_proxy)
58
- self.config_item = rumps.MenuItem("Socks 节点配置...", callback=self.open_config)
60
+ self.config_item = rumps.MenuItem("Socks/HTTP 节点配置...", callback=self.open_config)
59
61
 
60
62
  self.global_item = rumps.MenuItem("全局代理(设置系统代理)", callback=self.set_global_mode)
61
63
  self.manual_item = rumps.MenuItem("手动模式(关闭系统代理)", callback=self.set_manual_mode)
@@ -93,10 +95,19 @@ class SocksClient(rumps.App):
93
95
  if self.connected:
94
96
  icon_name = "socks_on_G_bar.png" if self.config.data["mode"] == "global" else "socks_on_M_bar.png"
95
97
  else:
96
- icon_name = "christmas-sock_light_bar.png"
98
+ icon_name = "christmas-sock_light_bar_off.png"
97
99
  icon_path = os.path.join(self._icon_dir(), icon_name)
98
100
  if os.path.exists(icon_path):
99
- self.icon = icon_path
101
+ image = NSImage.alloc().initByReferencingFile_(icon_path)
102
+ image.setSize_(NSSize(22, 22))
103
+ if self._template is not None:
104
+ image.setTemplate_(self._template)
105
+ self._icon = icon_path
106
+ self._icon_nsimage = image
107
+ try:
108
+ self._nsapp.setStatusBarIcon()
109
+ except AttributeError:
110
+ pass
100
111
  self.title = None
101
112
 
102
113
  def _is_compiled(self):
@@ -135,11 +146,17 @@ class SocksClient(rumps.App):
135
146
  "SocksClient", "启动失败", str(e),
136
147
  )
137
148
  return
149
+ if (self.proxy.socks_port != self.config.data["local"]["socks_port"]
150
+ or self.proxy.http_port != self.config.data["local"]["http_port"]):
151
+ self.config.data["local"]["socks_port"] = self.proxy.socks_port
152
+ self.config.data["local"]["http_port"] = self.proxy.http_port
153
+ self.config.save()
154
+
138
155
  if self.config.data["mode"] == "global":
139
156
  try:
140
157
  self.sys_proxy.enable(
141
- socks_port=self.config.data["local"]["socks_port"],
142
- http_port=self.config.data["local"]["http_port"],
158
+ socks_port=self.proxy.socks_port,
159
+ http_port=self.proxy.http_port,
143
160
  )
144
161
  except Exception as e:
145
162
  rumps.notification(
@@ -179,10 +196,11 @@ class SocksClient(rumps.App):
179
196
  self.config.save()
180
197
  script_path = os.path.join(self._bundle_resource_dir(), "config_window.py")
181
198
  python_path = self._find_python() if self._is_compiled() else sys.executable
182
- proc = subprocess.Popen([python_path, script_path, self.config.config_path])
199
+ self._config_proc = subprocess.Popen([python_path, script_path, self.config.config_path])
183
200
 
184
201
  def _reload_after_window():
185
- proc.wait()
202
+ self._config_proc.wait()
203
+ self._config_proc = None
186
204
  old_data = self.config.data.copy()
187
205
  self.config.load()
188
206
  if self.connected and self.config.data != old_data:
@@ -198,8 +216,8 @@ class SocksClient(rumps.App):
198
216
  self._update_icon()
199
217
  if self.connected:
200
218
  self.sys_proxy.enable(
201
- socks_port=self.config.data["local"]["socks_port"],
202
- http_port=self.config.data["local"]["http_port"],
219
+ socks_port=self.proxy.socks_port,
220
+ http_port=self.proxy.http_port,
203
221
  )
204
222
 
205
223
  def set_manual_mode(self, sender):
@@ -257,6 +275,8 @@ class SocksClient(rumps.App):
257
275
  )
258
276
 
259
277
  def quit_app(self, sender):
278
+ if self._config_proc and self._config_proc.poll() is None:
279
+ self._config_proc.terminate()
260
280
  if self.connected:
261
281
  self.sys_proxy.disable()
262
282
  threading.Thread(target=self.proxy.stop, daemon=True).start()
package/client/build.sh CHANGED
@@ -43,6 +43,8 @@ sips -z 128 128 "$SCRIPT_DIR/icons/app_icon.png" --out "$ICONSET/icon_128x128.pn
43
43
  sips -z 256 256 "$SCRIPT_DIR/icons/app_icon.png" --out "$ICONSET/icon_128x128@2x.png" &>/dev/null
44
44
  sips -z 256 256 "$SCRIPT_DIR/icons/app_icon.png" --out "$ICONSET/icon_256x256.png" &>/dev/null
45
45
  sips -z 512 512 "$SCRIPT_DIR/icons/app_icon.png" --out "$ICONSET/icon_256x256@2x.png" &>/dev/null
46
+ sips -z 512 512 "$SCRIPT_DIR/icons/app_icon.png" --out "$ICONSET/icon_512x512.png" &>/dev/null
47
+ sips -z 1024 1024 "$SCRIPT_DIR/icons/app_icon.png" --out "$ICONSET/icon_512x512@2x.png" &>/dev/null
46
48
  iconutil -c icns "$ICONSET" -o "$SCRIPT_DIR/icons/app.icns"
47
49
  rm -rf "$(dirname "$ICONSET")"
48
50
 
@@ -71,6 +73,10 @@ plutil -replace CFBundleExecutable -string "$APP_NAME" "$APP_DIR/Contents/Info.p
71
73
  plutil -replace CFBundleIdentifier -string "$BUNDLE_ID" "$APP_DIR/Contents/Info.plist"
72
74
  plutil -replace CFBundleVersion -string "$VERSION" "$APP_DIR/Contents/Info.plist"
73
75
  plutil -replace CFBundleShortVersionString -string "$VERSION" "$APP_DIR/Contents/Info.plist"
76
+ plutil -replace NSSupportsAutomaticIconComposition -bool false "$APP_DIR/Contents/Info.plist"
77
+
78
+ echo "==> Setting custom icon (bypass Liquid Glass)..."
79
+ fileicon set "$APP_DIR" "$SCRIPT_DIR/icons/app_icon.png"
74
80
 
75
81
  echo "==> Cleaning Nuitka build artifacts..."
76
82
  rm -rf "$DIST_DIR/main.build" "$DIST_DIR/main.dist"
package/client/config.py CHANGED
@@ -4,6 +4,7 @@ import copy
4
4
 
5
5
  DEFAULT_CONFIG = {
6
6
  "server": {
7
+ "protocol": "socks5",
7
8
  "address": "",
8
9
  "port": 8002,
9
10
  "username": "",