lint all files

pull/396/head
starknt 2024-11-18 11:43:07 +08:00
parent 47608ffef9
commit 64795cc509
107 changed files with 1260 additions and 846 deletions

View File

@ -5,9 +5,11 @@ labels: Bug
--- ---
<!-- 如果搜索过但未找到,请将 `[ ]` 替换为 `[x]` --> <!-- 如果搜索过但未找到,请将 `[ ]` 替换为 `[x]` -->
- [ ] 你是否在现有 [Issue列表](/docmirror/dev-sidecar/issues) 中搜索过相同问题,但未找到? - [ ] 你是否在现有 [Issue列表](/docmirror/dev-sidecar/issues) 中搜索过相同问题,但未找到?
### . 请说明操作系统及DS的版本号 ### . 请说明操作系统及DS的版本号
1. 操作系统:? 1. 操作系统:?
2. DS版本号? <!-- 如:`1.8.6-node17` --> 2. DS版本号? <!-- 如:`1.8.6-node17` -->
@ -22,10 +24,15 @@ labels: Bug
3. xxx 3. xxx
### . 请提供相关的错误日志,尽可能的详细:(日志文件在 `${user.home}/.dev-sidecar/logs/` 目录下) ### . 请提供相关的错误日志,尽可能的详细:(日志文件在 `${user.home}/.dev-sidecar/logs/` 目录下)
```log ```log
``` ```
### Ⅵ. 有必要时,请提供 `${user.home}/.dev-sidecar/running.json` 文件内容: ### Ⅵ. 有必要时,请提供 `${user.home}/.dev-sidecar/running.json` 文件内容:
<!-- 请将 'running.json' 文件的内容粘贴在这里,方便我们排查问题是否由配置错误导致。 --> <!-- 请将 'running.json' 文件的内容粘贴在这里,方便我们排查问题是否由配置错误导致。 -->
```json ```json
``` ```

View File

@ -5,9 +5,11 @@ labels: Style Issue
--- ---
<!-- 如果搜索过但未找到,请将 `[ ]` 替换为 `[x]` --> <!-- 如果搜索过但未找到,请将 `[ ]` 替换为 `[x]` -->
- [ ] 你是否在现有 [Issue列表](/docmirror/dev-sidecar/issues) 中搜索过相同问题,但未找到? - [ ] 你是否在现有 [Issue列表](/docmirror/dev-sidecar/issues) 中搜索过相同问题,但未找到?
### . 请说明操作系统及DS的版本号 ### . 请说明操作系统及DS的版本号
1. 操作系统:? 1. 操作系统:?
2. DS版本号? <!-- 如:`1.8.6-node17` --> 2. DS版本号? <!-- 如:`1.8.6-node17` -->

View File

@ -5,6 +5,7 @@ labels: Config Issue
--- ---
### . 你对哪个功能的配置不了解? ### . 你对哪个功能的配置不了解?
<!-- 请选择一个或多个选项,将前面的 `[ ]` 修改为 `[x]` 即可。 --> <!-- 请选择一个或多个选项,将前面的 `[ ]` 修改为 `[x]` 即可。 -->
- [ ] 拦截设置: - [ ] 拦截设置:
@ -28,6 +29,9 @@ labels: Config Issue
### Ⅱ. 请详细描述你的问题: ### Ⅱ. 请详细描述你的问题:
### Ⅲ. 有必要时,请提供 `${user.home}/.dev-sidecar/running.json` 文件内容: ### Ⅲ. 有必要时,请提供 `${user.home}/.dev-sidecar/running.json` 文件内容:
<!-- 请将 'running.json' 文件的内容粘贴在这里,方便我们排查问题是否由配置错误导致。 --> <!-- 请将 'running.json' 文件的内容粘贴在这里,方便我们排查问题是否由配置错误导致。 -->
```json ```json
``` ```

View File

@ -5,10 +5,13 @@ labels: Feature Request
--- ---
### . 请描述你想要的新功能: ### . 请描述你想要的新功能:
<!-- 请简单描述你希望的新功能,例如:"在某某页面添加一个按钮点击按钮时弹出一个某某对话框用于xxx。" --> <!-- 请简单描述你希望的新功能,例如:"在某某页面添加一个按钮点击按钮时弹出一个某某对话框用于xxx。" -->
### Ⅱ. 请描述你心目中新功能的样子: ### Ⅱ. 请描述你心目中新功能的样子:
<!-- 可以讲讲你对新功能的看法,可以解释更多关于该功能的输入和输出的信息,或贴上你设想的界面设计。 --> <!-- 可以讲讲你对新功能的看法,可以解释更多关于该功能的输入和输出的信息,或贴上你设想的界面设计。 -->
### Ⅲ. 你希望该新功能修复哪个issue ### Ⅲ. 你希望该新功能修复哪个issue
<!-- 请将相关issue的编号填写在下面格式如#123 --> <!-- 请将相关issue的编号填写在下面格式如#123 -->

View File

@ -1,7 +1,9 @@
### . 描述此PR的作用 ### . 描述此PR的作用
### Ⅱ. 此PR修复了哪个issue吗 ### Ⅱ. 此PR修复了哪个issue吗
<!-- 如果是的话, 请在下一行写上 "fixes #xxx"比如fixes #97 --> <!-- 如果是的话, 请在下一行写上 "fixes #xxx"比如fixes #97 -->
### Ⅲ. 界面变化截屏 ### Ⅲ. 界面变化截屏
<!-- 如果存在界面上的变化,请截屏展示出来 --> <!-- 如果存在界面上的变化,请截屏展示出来 -->

View File

@ -1,4 +1,4 @@
name: 'Build And Release' name: Build And Release
on: on:
push: push:
@ -21,7 +21,7 @@ jobs:
node: node:
- 22 - 22
steps: steps:
- name: 'Checkout' - name: Checkout
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.1.7
- name: 'Setup Node.js "${{ matrix.node }}.x" environment' - name: 'Setup Node.js "${{ matrix.node }}.x" environment'
@ -30,22 +30,22 @@ jobs:
node-version: ${{ matrix.node }} node-version: ${{ matrix.node }}
registry-url: https://npm.pkg.github.com/ registry-url: https://npm.pkg.github.com/
- name: 'Setup pnpm' - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
- name: 'Setup Python environment (Mac) Because of electron-builder install-app-deps requires Python setup tools' - name: Setup Python environment (Mac) Because of electron-builder install-app-deps requires Python setup tools
if: matrix.os == 'macos' if: matrix.os == 'macos'
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version: '3.10' python-version: '3.10'
- name: 'Get package info' - name: Get package info
id: package-info id: package-info
uses: luizfelipelaviola/get-package-info@v1 uses: luizfelipelaviola/get-package-info@v1
with: with:
path: ./packages/mitmproxy path: ./packages/mitmproxy
- name: 'Print' - name: Print
run: | run: |
echo "version = ${{ steps.package-info.outputs.version }}"; echo "version = ${{ steps.package-info.outputs.version }}";
echo "github.ref_type = ${{ github.ref_type }}"; echo "github.ref_type = ${{ github.ref_type }}";
@ -69,7 +69,7 @@ jobs:
echo "--------------------"; echo "--------------------";
python --version; python --version;
- name: 'pnpm install' - name: pnpm install
run: | run: |
echo "======================================================================"; echo "======================================================================";
dir || ls -lah; dir || ls -lah;
@ -139,10 +139,10 @@ jobs:
needs: needs:
- build-and-upload - build-and-upload
steps: steps:
- name: 'Checkout' - name: Checkout
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.1.7
- name: 'Get package info' - name: Get package info
id: package-info id: package-info
uses: luizfelipelaviola/get-package-info@v1 uses: luizfelipelaviola/get-package-info@v1
with: with:
@ -177,7 +177,7 @@ jobs:
run: | run: |
ls -lah release; ls -lah release;
- name: 'Create a draft release' - name: Create a draft release
uses: wangliang181230/github-action-ghr@master uses: wangliang181230/github-action-ghr@master
env: env:
GITHUB_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ github.token }}

View File

@ -1,10 +1,10 @@
name: 'Test And Upload' name: Test And Upload
on: on:
push: push:
branches: branches:
- master - master
- '1.x' - 1.x
pull_request: pull_request:
branches: branches:
- master - master
@ -22,7 +22,7 @@ jobs:
node: node:
- 22 - 22
steps: steps:
- name: 'Checkout' - name: Checkout
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.1.7
- name: 'Setup Node.js "${{ matrix.node }}.x" environment' - name: 'Setup Node.js "${{ matrix.node }}.x" environment'
@ -31,22 +31,22 @@ jobs:
node-version: ${{ matrix.node }} node-version: ${{ matrix.node }}
registry-url: https://npm.pkg.github.com/ registry-url: https://npm.pkg.github.com/
- name: 'Setup pnpm' - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
- name: 'Setup Python environment (Mac) Because of electron-builder install-app-deps requires Python setup tools' - name: Setup Python environment (Mac) Because of electron-builder install-app-deps requires Python setup tools
if: matrix.os == 'macos' if: matrix.os == 'macos'
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version: '3.10' python-version: '3.10'
- name: 'Get package info' - name: Get package info
id: package-info id: package-info
uses: luizfelipelaviola/get-package-info@v1 uses: luizfelipelaviola/get-package-info@v1
with: with:
path: ./packages/mitmproxy path: ./packages/mitmproxy
- name: 'Print' - name: Print
run: | run: |
echo "version = ${{ steps.package-info.outputs.version }}"; echo "version = ${{ steps.package-info.outputs.version }}";
echo "github.ref_type = ${{ github.ref_type }}"; echo "github.ref_type = ${{ github.ref_type }}";
@ -70,7 +70,7 @@ jobs:
echo "--------------------"; echo "--------------------";
python --version; python --version;
- name: 'pnpm install' - name: pnpm install
run: | run: |
echo "======================================================================"; echo "======================================================================";
dir || ls -lah; dir || ls -lah;

176
README.md
View File

@ -5,80 +5,77 @@
<a href='https://github.com/docmirror/dev-sidecar'><img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"></a> <a href='https://github.com/docmirror/dev-sidecar'><img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"></a>
>
> Gitee上的同步项目已被封禁此项目将不再更新与维护 【狗头保命】 > Gitee上的同步项目已被封禁此项目将不再更新与维护 【狗头保命】
> >
> 我将继续奋战在开源一线,为社区贡献更多更好的开源项目。 > 我将继续奋战在开源一线,为社区贡献更多更好的开源项目。
> 感兴趣的可以关注我的主页 [【github】](https://github.com/greper) [【gitee】](https://gitee.com/greper) > 感兴趣的可以关注我的主页 [【github】](https://github.com/greper) [【gitee】](https://gitee.com/greper)
>
## 打个广告 ## 打个广告
>
> <https://github.com/certd/certd> > <https://github.com/certd/certd>
> 我的开源证书管理工具项目全自动申请和部署证书有需求的可以去试试帮忙点个star > 我的开源证书管理工具项目全自动申请和部署证书有需求的可以去试试帮忙点个star
## 重要提醒 ## 重要提醒
>
> ------------------------------重要提醒1--------------------------------- > ------------------------------重要提醒1---------------------------------
> >
> 注意由于electron无法监听windows的关机事件开着ds情况下直接重启电脑会导致无法上网你可以手动启动ds即可恢复网络你也可以将ds设置为开机自启。 > 注意由于electron无法监听windows的关机事件开着ds情况下直接重启电脑会导致无法上网你可以手动启动ds即可恢复网络你也可以将ds设置为开机自启。
> >
> 关于此问题的更多讨论请前往: > 关于此问题的更多讨论请前往:
> <https://github.com/docmirror/dev-sidecar/issues/109> > <https://github.com/docmirror/dev-sidecar/issues/109>
>
> ------------------------------重要提醒2--------------------------------- > ------------------------------重要提醒2---------------------------------
> >
> 注意:本应用启动会自动修改系统代理,所以会与其他代理软件有冲突,请务必不要一起使用。 > 注意:本应用启动会自动修改系统代理,所以会与其他代理软件有冲突,请务必不要一起使用。
> 本应用主要目的在于直连访问github如果你已经有飞机了那建议还是不要用这个自行车ds > 本应用主要目的在于直连访问github如果你已经有飞机了那建议还是不要用这个自行车ds
>
## 一、 特性 ## 一、 特性
### 1.1、 dns优选解决***污染问题) ### 1.1、 dns优选解决\*\*\*污染问题)
* 根据网络状况智能解析最佳域名ip地址获取最佳网络速度 - 根据网络状况智能解析最佳域名ip地址获取最佳网络速度
* 解决一些网站和库无法访问或访问速度慢的问题 - 解决一些网站和库无法访问或访问速度慢的问题
* 建议遇到打开比较慢的国外网站可以优先尝试将该域名添加到dns设置中注意被***封杀的无效) - 建议遇到打开比较慢的国外网站可以优先尝试将该域名添加到dns设置中注意\*\*\*封杀的无效)
### 1.2、 请求拦截 ### 1.2、 请求拦截
* 拦截打不开的网站,代理到加速镜像站点上去。 - 拦截打不开的网站,代理到加速镜像站点上去。
* 可配置多个镜像站作为备份 - 可配置多个镜像站作为备份
* 具备测速机制,当访问失败或超时之后,自动切换到备用站点,使得目标服务高可用 - 具备测速机制,当访问失败或超时之后,自动切换到备用站点,使得目标服务高可用
### 1.3、 github加速 ### 1.3、 github加速
* github 直连加速 (通过修改sni实现感谢 [fastGithub](https://github.com/dotnetcore/FastGithub) 提供的思路) - github 直连加速 (通过修改sni实现感谢 [fastGithub](https://github.com/dotnetcore/FastGithub) 提供的思路)
* release、source、zip下载加速 - release、source、zip下载加速
* clone 加速 - clone 加速
* 头像加速 - 头像加速
* 解决readme中图片引用无法加载的问题 - 解决readme中图片引用无法加载的问题
* gist.github.com 加速 - gist.github.com 加速
* 解决git push 偶尔失败需要输入账号密码的问题fatal: TaskCanceledException encountered / fatal: HttpRequestException encountered - 解决git push 偶尔失败需要输入账号密码的问题fatal: TaskCanceledException encountered / fatal: HttpRequestException encountered
* raw/blame加速 - raw/blame加速
> 以上部分功能通过`X.I.U`的油猴脚本实现, 以下是仓库和脚本下载链接,大家可以去支持一下。 > 以上部分功能通过`X.I.U`的油猴脚本实现, 以下是仓库和脚本下载链接,大家可以去支持一下。
> >
> * <https://github.com/XIU2/UserScript> > - <https://github.com/XIU2/UserScript>
> * <https://greasyfork.org/scripts/412245> > - <https://greasyfork.org/scripts/412245>
> >
> 由于此脚本在ds中是打包在本地的更新会不及时你可以直接通过浏览器安装油猴插件使用此脚本从而获得最新更新ds本地的可以通过`加速服务->基本设置->启用脚本`进行关闭)。 > 由于此脚本在ds中是打包在本地的更新会不及时你可以直接通过浏览器安装油猴插件使用此脚本从而获得最新更新ds本地的可以通过`加速服务->基本设置->启用脚本`进行关闭)。
### 1.4、 Stack Overflow 加速 ### 1.4、 Stack Overflow 加速
* 将ajax.google.com代理到加速CDN上 - 将ajax.google.com代理到加速CDN上
* recaptcha 图片验证码加速 - recaptcha 图片验证码加速
### 1.5、 npm加速 ### 1.5、 npm加速
* 支持开启npm代理 - 支持开启npm代理
* 官方与淘宝npm registry一键切换, - 官方与淘宝npm registry一键切换,
* 某些npm install的时候并且使用cnpm也无法安装时可以尝试开启npm代理再试 - 某些npm install的时候并且使用cnpm也无法安装时可以尝试开启npm代理再试
***安全警告*** **_安全警告_**
* 请勿使用来源不明的服务地址,有隐私和账号泄露风险 - 请勿使用来源不明的服务地址,有隐私和账号泄露风险
* 本应用及服务端承诺不收集任何信息。介意者请使用安全模式。 - 本应用及服务端承诺不收集任何信息。介意者请使用安全模式。
## 二、快速开始 ## 二、快速开始
@ -88,8 +85,8 @@
#### 1下载安装包 #### 1下载安装包
* release下载 - release下载
[Github Release](https://github.com/docmirror/dev-sidecar/releases) [Github Release](https://github.com/docmirror/dev-sidecar/releases)
> Windows: 请选择DevSidecar-x.x.x.exe > Windows: 请选择DevSidecar-x.x.x.exe
> Mac: 请选择DevSidecar-x.x.x.dmg > Mac: 请选择DevSidecar-x.x.x.dmg
@ -123,50 +120,52 @@
### 2.2、开启前 vs 开启后 ### 2.2、开启前 vs 开启后
| | 开启前 | 开启后 | | | 开启前 | 开启后 |
| ---- | ---- | ---- | | -------- | ------------------------------ | ------------------------------------------------- |
|头像| ![](./doc/avatar2.png) |![](./doc/avatar1.png) | | 头像 | ![](./doc/avatar2.png) | ![](./doc/avatar1.png) |
|clone |![](./doc/clone-before.png) |![](./doc/clone.png) | | clone | ![](./doc/clone-before.png) | ![](./doc/clone.png) |
|zip 下载 |![](./doc/download-before.png) |![](./doc/download.png)秒下的,实在截不到速度的图 | | zip 下载 | ![](./doc/download-before.png) | ![](./doc/download.png)秒下的,实在截不到速度的图 |
## 三、模式说明 ## 三、模式说明
### 3.1、安全模式 ### 3.1、安全模式
* 此模式关闭拦截、关闭增强、开启dns优选、开启测速 - 此模式关闭拦截、关闭增强、开启dns优选、开启测速
* 最安全,无需安装证书,可以在浏览器地址栏左侧查看域名证书 - 最安全,无需安装证书,可以在浏览器地址栏左侧查看域名证书
* 功能也最弱只有特性1相当于查询github的国外ip手动改hosts一个意思。 - 功能也最弱只有特性1相当于查询github的国外ip手动改hosts一个意思。
* github的可访问性不稳定取决于IP测速如果有绿色ip存在`有可能` 可以直连访问。 - github的可访问性不稳定取决于IP测速如果有绿色ip存在`有可能` 可以直连访问。
![](./doc/speed.png) ![](./doc/speed.png)
### 3.2、默认模式 ### 3.2、默认模式
* 此模式开启拦截、关闭增强、开启dns优选、开启测速 - 此模式开启拦截、关闭增强、开启dns优选、开启测速
* 需要安装证书通过修改sni直连访问github - 需要安装证书通过修改sni直连访问github
* 功能上包含特性1/2/3/4。 - 功能上包含特性1/2/3/4。
## 四、 最佳实践 ## 四、 最佳实践
* 把dev-sidecar一直开着就行了注意windows下开着ds重启电脑会无法上网重新打开ds即可。 - 把dev-sidecar一直开着就行了注意windows下开着ds重启电脑会无法上网重新打开ds即可。
* 建议遇到打开比较慢的国外网站可以尝试将该域名添加到dns设置中注意被***封杀的无效) - 建议遇到打开比较慢的国外网站可以尝试将该域名添加到dns设置中注意\*\*\*封杀的无效)
### 其他加速 ### 其他加速
#### 1git clone 加速 #### 1git clone 加速
方式1快捷复制 方式1快捷复制
> 开启脚本支持然后在复制clone链接下方即可复制到加速链接
方式2 > 开启脚本支持然后在复制clone链接下方即可复制到加速链接
> 使用方式用实际的名称替换{}的内容即可加速clone
> <https://hub.fastgit.org/{username}/{reponame}.git> 方式2
> clone 出来的 remote "origin" 为fastgit的地址需要手动改回来
> 你也可以直接使用他们的clone加速工具 [fgit-go](https://github.com/FastGitORG/fgit-go) > 使用方式用实际的名称替换{}的内容即可加速clone
> <https://hub.fastgit.org/{username}/{reponame}.git>
> clone 出来的 remote "origin" 为fastgit的地址需要手动改回来
> 你也可以直接使用他们的clone加速工具 [fgit-go](https://github.com/FastGitORG/fgit-go)
#### 2github.com的镜像网站(注意:不能登录) #### 2github.com的镜像网站(注意:不能登录)
>
> 1. [hub.fastgit.org](https://hub.fastgit.org/) > 1. [hub.fastgit.org](https://hub.fastgit.org/)
> 2. [github.com.cnpmjs.org](https://github.com.cnpmjs.org/) 这个很容易超限 > 2. [github.com.cnpmjs.org](https://github.com.cnpmjs.org/) 这个很容易超限
## 五、api ## 五、api
@ -252,16 +251,16 @@ networksetup -setwebproxy 'WiFi' 127.0.0.1 31181
如果有上面的错误提示,请尝试如下方法: 如果有上面的错误提示,请尝试如下方法:
>取消访问偏好设置需要管理员密码 > 取消访问偏好设置需要管理员密码
>系统偏好设置—>安全性与隐私—> 通用—> 高级—> 访问系统范围的偏好设置需要输入管理员密码(取消勾选) > 系统偏好设置—>安全性与隐私—> 通用—> 高级—> 访问系统范围的偏好设置需要输入管理员密码(取消勾选)
### 6.2、没有加速效果 ### 6.2、没有加速效果
>本应用仅支持https加速请务必确认你访问的网站地址是https开头的 > 本应用仅支持https加速请务必确认你访问的网站地址是https开头的
1. 本应用仅支持https加速 1. 本应用仅支持https加速
请务必确认你访问的地址是https开头的 请务必确认你访问的地址是https开头的
比如: <https://github.com/> 比如: <https://github.com/>
2. 检查浏览器是否装了什么插件与ds有冲突 2. 检查浏览器是否装了什么插件与ds有冲突
@ -269,10 +268,10 @@ networksetup -setwebproxy 'WiFi' 127.0.0.1 31181
4. 请确认浏览器的代理设置为使用IE代理/或者使用系统代理状态 4. 请确认浏览器的代理设置为使用IE代理/或者使用系统代理状态
6. 可以尝试换个浏览器试试 5. 可以尝试换个浏览器试试
7. 请确认网络代理设置处于勾选状态 6. 请确认网络代理设置处于勾选状态
正常情况下ds在“系统代理”开关打开时会自动设置系统代理。 正常情况下ds在“系统代理”开关打开时会自动设置系统代理。
### 6.3、浏览器打开提示证书不受信任 ### 6.3、浏览器打开提示证书不受信任
@ -293,8 +292,7 @@ networksetup -setwebproxy 'WiFi' 127.0.0.1 31181
### 6.4、打开github显示连接超时 ### 6.4、打开github显示连接超时
```html ```html
DevSidecar Warning: DevSidecar Warning: Error: www.github.com:443, 代理请求超时
Error: www.github.com:443, 代理请求超时
``` ```
1、检查测速界面github.com是否有ip 如果没有ip则可能是由于你的网络提供商封锁了dns服务商的ip试试能否ping通1.1.1.1 / 9.9.9.9 1、检查测速界面github.com是否有ip 如果没有ip则可能是由于你的网络提供商封锁了dns服务商的ip试试能否ping通1.1.1.1 / 9.9.9.9
@ -303,8 +301,8 @@ Error: www.github.com:443, 代理请求超时
### 6.5、查看日志是否有报错 ### 6.5、查看日志是否有报错
如果还是不行,请在下方加作者好友,将服务日志发送给作者进行分析 如果还是不行,请在下方加作者好友,将服务日志发送给作者进行分析
日志打开方式:加速服务->右边日志按钮->打开日志文件夹 日志打开方式:加速服务->右边日志按钮->打开日志文件夹
![](./doc/log.png) ![](./doc/log.png)
@ -318,10 +316,10 @@ Error: www.github.com:443, 代理请求超时
应用开启后会自动修改系统代理设置,正常退出会自动关闭系统代理 应用开启后会自动修改系统代理设置,正常退出会自动关闭系统代理
当应用意外关闭时,可能会因为没有将系统代理恢复,从而导致完全无法上网。 当应用意外关闭时,可能会因为没有将系统代理恢复,从而导致完全无法上网。
对于此问题有如下几种解决方案可供选择: 对于此问题有如下几种解决方案可供选择:
1、重新打开应用即可右键应用托盘图标可完全退出将会正常关闭系统代理设置 1、重新打开应用即可右键应用托盘图标可完全退出将会正常关闭系统代理设置
2、如果应用被卸载了此时需要[手动关闭系统代理设置](./doc/recover.md) 2、如果应用被卸载了此时需要[手动关闭系统代理设置](./doc/recover.md)
3、如果你是因为开着ds的情况下重启电脑导致无法上网你可以设置ds为开机自启 3、如果你是因为开着ds的情况下重启电脑导致无法上网你可以设置ds为开机自启
### 6.8、卸载应用后上不了网git请求不了 ### 6.8、卸载应用后上不了网git请求不了
@ -345,7 +343,7 @@ npm config delete https-proxy
## 七、在其他程序使用 ## 七、在其他程序使用
* [java程序使用](./doc/other.md#Java程序使用) - [java程序使用](./doc/other.md#Java程序使用)
## 八、贡献代码 ## 八、贡献代码
@ -358,6 +356,7 @@ npm config delete https-proxy
#### 2安装 `lerna` #### 2安装 `lerna`
运行如下命令即可安装所需依赖: 运行如下命令即可安装所需依赖:
> 注lerna指定为6.x版本更高版本会导致打包失败不兼容导致 > 注lerna指定为6.x版本更高版本会导致打包失败不兼容导致
```shell ```shell
@ -407,19 +406,20 @@ npm run electron:build
欢迎bug反馈需求建议技术交流等 欢迎bug反馈需求建议技术交流等
1、 加群请备注dev-sidecar或简称DS 1、 加群请备注dev-sidecar或简称DS
* QQ 1群390691483人数500 / 500
* QQ 2群[667666069](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=n4nksr4sji93vZtD5e8YEHRT6qbh6VyQ&authKey=XKBZnzmoiJrAFyOT4V%2BCrgX5c13ds59b84g%2FVRhXAIQd%2FlAiilsuwDRGWJct%2B570&noverify=0&group_code=667666069)人数447 / 500 - QQ 1群390691483人数500 / 500
* QQ 3群419807815人数500 / 500 - QQ 2群[667666069](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=n4nksr4sji93vZtD5e8YEHRT6qbh6VyQ&authKey=XKBZnzmoiJrAFyOT4V%2BCrgX5c13ds59b84g%2FVRhXAIQd%2FlAiilsuwDRGWJct%2B570&noverify=0&group_code=667666069)人数447 / 500
* QQ 4群[438148299](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=i_NCBB5f_Bkm2JsEV1tLs2TkQ79UlCID&authKey=nMsVJbJ6P%2FGNO7Q6vsVUadXRKnULUURwR8zvUZJnP3IgzhHYPhYdcBCHvoOh8vYr&noverify=0&group_code=438148299)人数203 / 1000 - QQ 3群419807815人数500 / 500
* QQ 5群[767622917](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=nAWi_Rxj7mM4Unp5LMiatmUWhGimtbcB&authKey=aswmlWGjbt3GIWXtvjB2GJqqAKuv7hWjk6UBs3MTb%2Biyvr%2Fsbb1kA9CjF6sK7Hgg&noverify=0&group_code=767622917)人数016 / 200new - QQ 4群[438148299](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=i_NCBB5f_Bkm2JsEV1tLs2TkQ79UlCID&authKey=nMsVJbJ6P%2FGNO7Q6vsVUadXRKnULUURwR8zvUZJnP3IgzhHYPhYdcBCHvoOh8vYr&noverify=0&group_code=438148299)人数203 / 1000
- QQ 5群[767622917](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=nAWi_Rxj7mM4Unp5LMiatmUWhGimtbcB&authKey=aswmlWGjbt3GIWXtvjB2GJqqAKuv7hWjk6UBs3MTb%2Biyvr%2Fsbb1kA9CjF6sK7Hgg&noverify=0&group_code=767622917)人数016 / 200new
## 十、求star ## 十、求star
我的其他项目求star 我的其他项目求star
* [fast-crud](https://github.com/fast-crud/fast-crud) : 开发crud快如闪电 - [fast-crud](https://github.com/fast-crud/fast-crud) : 开发crud快如闪电
* [certd](https://github.com/certd/certd) : 让你的证书永不过期 - [certd](https://github.com/certd/certd) : 让你的证书永不过期
* [trident-sync](https://github.com/handsfree-work/trident-sync) : 二次开发项目同步升级工具 - [trident-sync](https://github.com/handsfree-work/trident-sync) : 二次开发项目同步升级工具
## 十一、感谢 ## 十一、感谢
@ -429,14 +429,14 @@ npm run electron:build
本项目参考如下开源项目 本项目参考如下开源项目
* [node-mitmproxy](https://github.com/wuchangming/node-mitmproxy) - [node-mitmproxy](https://github.com/wuchangming/node-mitmproxy)
* [ReplaceGoogleCDN](https://github.com/justjavac/ReplaceGoogleCDN) - [ReplaceGoogleCDN](https://github.com/justjavac/ReplaceGoogleCDN)
特别感谢 特别感谢
* [github增强油猴脚本](https://greasyfork.org/zh-CN/scripts/412245-github-%E5%A2%9E%E5%BC%BA-%E9%AB%98%E9%80%9F%E4%B8%8B%E8%BD%BD) 本项目部分加速功能完全复制该脚本。 - [github增强油猴脚本](https://greasyfork.org/zh-CN/scripts/412245-github-%E5%A2%9E%E5%BC%BA-%E9%AB%98%E9%80%9F%E4%B8%8B%E8%BD%BD) 本项目部分加速功能完全复制该脚本。
* [中国域名白名单](https://github.com/pluwen/china-domain-allowlist),本项目的系统代理排除域名功能中,使用了该白名单。 - [中国域名白名单](https://github.com/pluwen/china-domain-allowlist),本项目的系统代理排除域名功能中,使用了该白名单。
本项目部分加速资源由如下组织提供 本项目部分加速资源由如下组织提供
* [FastGit UK](https://fastgit.org/) - [FastGit UK](https://fastgit.org/)

View File

@ -3,7 +3,9 @@
## 一、为什么要信任根证书。 ## 一、为什么要信任根证书。
要回答这个问题需要先掌握下面两个知识点 要回答这个问题需要先掌握下面两个知识点
### 知识点1什么是根证书 ### 知识点1什么是根证书
[百度百科-什么是根证书](https://baike.baidu.com/item/%E6%A0%B9%E8%AF%81%E4%B9%A6/9874620?fr=aladdin) [百度百科-什么是根证书](https://baike.baidu.com/item/%E6%A0%B9%E8%AF%81%E4%B9%A6/9874620?fr=aladdin)
当访问目标网站是https协议时服务器会发送一个由根证书签发的网站ssl证书给浏览器让浏览器用这个ssl证书给数据加密。 当访问目标网站是https协议时服务器会发送一个由根证书签发的网站ssl证书给浏览器让浏览器用这个ssl证书给数据加密。
@ -14,6 +16,7 @@
windows、mac、linux或者浏览器他们都内置了市面上可信的大型证书颁发机构的根证书。 windows、mac、linux或者浏览器他们都内置了市面上可信的大型证书颁发机构的根证书。
### 知识点2中间人攻击 ### 知识点2中间人攻击
本应用的实现原理如下图: 本应用的实现原理如下图:
![](./flow.jpg) ![](./flow.jpg)
@ -29,7 +32,7 @@ windows、mac、linux或者浏览器他们都内置了市面上可信的大型
例如加速github就需要修改如下几处 例如加速github就需要修改如下几处
1. 直连访问github需要修改tls握手时的sni域名规避***的sni阻断问题。 1. 直连访问github需要修改tls握手时的sni域名规避\*\*\*的sni阻断问题。
2. asserts.github.com等静态资源拦截替换成fastgit.org的镜像地址 2. asserts.github.com等静态资源拦截替换成fastgit.org的镜像地址
DevSidecar在第一次启动时会在本地随机生成一份根证书当有用户访问github时就用这份根证书来签发一份假的叫github.com的证书。 DevSidecar在第一次启动时会在本地随机生成一份根证书当有用户访问github时就用这份根证书来签发一份假的叫github.com的证书。
@ -50,7 +53,7 @@ DevSidecar在第一次启动时会在本地随机生成一份根证书当有
> 或者从源码自行编译安装 > 或者从源码自行编译安装
> 对于拦截配置里的替代网站风险: > 对于拦截配置里的替代网站风险:
>
> 1. 尽量缩小替代配置的范围 > 1. 尽量缩小替代配置的范围
> 2. 不使用来源不明的镜像地址,尽量使用知名度较高的镜像地址 > 2. 不使用来源不明的镜像地址,尽量使用知名度较高的镜像地址
> 3. 你甚至可以将其他拦截配置全部删除只保留github相关配置 > 3. 你甚至可以将其他拦截配置全部删除只保留github相关配置
>

View File

@ -1,4 +1,5 @@
# linux 支持 # linux 支持
`linux`使用说明,目前仅支持`ubuntu_x64GNOME`,其他`linux`未测试 `linux`使用说明,目前仅支持`ubuntu_x64GNOME`,其他`linux`未测试
> 注意:需要开启[sudo免密支持](https://www.jianshu.com/p/5d02428f313d) > 注意:需要开启[sudo免密支持](https://www.jianshu.com/p/5d02428f313d)
@ -6,30 +7,38 @@
## 安装 ## 安装
### 1. ubuntu ### 1. ubuntu
* 下载`DevSidecar-x.x.x.deb`
* 执行命令安装 `dpkg -i DevSidecar-x.x.x.deb` - 下载`DevSidecar-x.x.x.deb`
* 去应用列表里面找到dev-sidecar应用打开即可 - 执行命令安装 `dpkg -i DevSidecar-x.x.x.deb`
- 去应用列表里面找到dev-sidecar应用打开即可
### 2. 其他linux系统未测试 ### 2. 其他linux系统未测试
* 下载 `DevSidecar-x.x.x.AppImage`
* 设置可执行权限 `sudo chmod +X DevSidecar-x.x.x.AppImage` - 下载 `DevSidecar-x.x.x.AppImage`
* 双击运行 - 设置可执行权限 `sudo chmod +X DevSidecar-x.x.x.AppImage`
- 双击运行
## 证书安装 ## 证书安装
默认模式和增强模式需要系统信任CA证书。 默认模式和增强模式需要系统信任CA证书。
由于linux上火狐和chrome都不走系统证书所以除了安装系统证书之外还需要给浏览器安装证书 由于linux上火狐和chrome都不走系统证书所以除了安装系统证书之外还需要给浏览器安装证书
### 1. 系统证书安装 ### 1. 系统证书安装
根据弹出的提示: 根据弹出的提示:
* 点击首页右上角“安装根证书”按钮
* 点击“点此去安装” - 点击首页右上角“安装根证书”按钮
* 提示安装成功即可 - 点击“点此去安装”
- 提示安装成功即可
### 2. 火狐浏览器安装证书 ### 2. 火狐浏览器安装证书
* 火狐浏览器->选项->隐私与安全->证书->查看证书
* 证书颁发机构->导入 - 火狐浏览器->选项->隐私与安全->证书->查看证书
* 选择证书文件在`~/.dev-sidecar`目录下 - 证书颁发机构->导入
* 勾选信任由此证书颁发机构来标识网站,确定即可 - 选择证书文件在`~/.dev-sidecar`目录下
- 勾选信任由此证书颁发机构来标识网站,确定即可
### 3. chrome浏览器安装证书 ### 3. chrome浏览器安装证书
证书文件目录为`~/.dev-sidecar` 证书文件目录为`~/.dev-sidecar`
![](../packages/gui/public/setup-linux.png) ![](../packages/gui/public/setup-linux.png)

View File

@ -1,13 +1,15 @@
# 其他程序使用 # 其他程序使用
## Java程序使用 ## Java程序使用
> 由[Enaium](https://github.com/Enaium) 提供,未做验证,可供参考
> 由[Enaium](https://github.com/Enaium) 提供,未做验证,可供参考
> >
需要先通过keytool安装证书 > 需要先通过keytool安装证书
`keytool -import -alias dev-sidecar -keystore "jdk路径\security\cacerts" -file 用户目录\.dev-sidecar\dev-sidecar.ca.crt`默认密码为`changeit` > `keytool -import -alias dev-sidecar -keystore "jdk路径\security\cacerts" -file 用户目录\.dev-sidecar\dev-sidecar.ca.crt`默认密码为`changeit`
启动时还需要设置参数 > 启动时还需要设置参数
`-Dhttp.proxyHost=localhost -Dhttp.proxyPort=31181 -Dhttps.proxyHost=localhost -Dhttps.proxyPort=31181` > `-Dhttp.proxyHost=localhost -Dhttp.proxyPort=31181 -Dhttps.proxyHost=localhost -Dhttps.proxyPort=31181`
Gradle还需在`用户目录/.gradle/gradle.properties`创建配置文件 > Gradle还需在`用户目录/.gradle/gradle.properties`创建配置文件
```properties ```properties
systemProp.http.proxyHost=localhost systemProp.http.proxyHost=localhost
systemProp.http.proxyPort=31181 systemProp.http.proxyPort=31181

View File

@ -1,20 +1,26 @@
# 卸载与恢复网络 # 卸载与恢复网络
由于应用启动后会自动设置系统代理,正常退出时会关闭系统代理。 由于应用启动后会自动设置系统代理,正常退出时会关闭系统代理。
当应用意外关闭,或者未正常退出后被卸载,此时会因为系统代理没有恢复从而导致完全上不了网。 当应用意外关闭,或者未正常退出后被卸载,此时会因为系统代理没有恢复从而导致完全上不了网。
目前electron在windows系统上无法监听系统重启事件。更多相关资料 [electron issues](https://github.com/electron/electron/pull/24261) 目前electron在windows系统上无法监听系统重启事件。更多相关资料 [electron issues](https://github.com/electron/electron/pull/24261)
## 恢复代理设置 ## 恢复代理设置
### 1、windows 代理关闭 ### 1、windows 代理关闭
如何打开查看windows代理设置 如何打开查看windows代理设置
* win10: 开始->设置->网络和Internet->最下方代理
* win7: 开始->控制面板->网络和Internet->网络和共享中心->左下角Internet选项->连接选项卡->局域网设置 - win10: 开始->设置->网络和Internet->最下方代理
- win7: 开始->控制面板->网络和Internet->网络和共享中心->左下角Internet选项->连接选项卡->局域网设置
![windows](./proxy.png) ![windows](./proxy.png)
### 2、mac 代理关闭 ### 2、mac 代理关闭
网络->网卡->代理->去掉http和https的两个勾 网络->网卡->代理->去掉http和https的两个勾
![](./mac-proxy.png) ![](./mac-proxy.png)
### 3、LinuxUbuntu ### 3、LinuxUbuntu
网络->代理->选择禁用 网络->代理->选择禁用

View File

@ -5,16 +5,20 @@ export default antfu({
vueVersion: 2, vueVersion: 2,
}, },
rules: { rules: {
"style/space-before-function-paren": ["error", "always"], 'style/space-before-function-paren': ['error', 'always'],
"no-console": 'off' 'node/prefer-global/buffer': 'off',
'node/prefer-global/process': 'off',
'no-console': 'off',
}, },
isInEditor: true,
ignore: [ ignore: [
'**/test/**', '**/node_modules/*',
'**/build/*',
'**/test/*',
'**/dist_electron/*',
], ],
formatters: { formatters: {
css: true, css: true,
html: true, html: true,
markdown: 'prettier', markdown: 'prettier',
} },
}) })

View File

@ -1,17 +1,17 @@
{ {
"name": "dev-sidecar-parent", "name": "dev-sidecar-parent",
"type": "module", "type": "module",
"packageManager": "pnpm@9.13.2",
"private": false, "private": false,
"packageManager": "pnpm@9.13.2",
"author": "Greper", "author": "Greper",
"license": "MPL-2.0", "license": "MPL-2.0",
"devDependencies": {
"eslint": "^9.15.0",
"@antfu/eslint-config": "^3.9.1",
"eslint-plugin-format": "^0.1.2"
},
"scripts": { "scripts": {
"lint": "eslint .", "lint": "eslint .",
"lint:fix": "eslint . --fix" "lint:fix": "eslint . --fix"
},
"devDependencies": {
"@antfu/eslint-config": "^3.9.1",
"eslint": "^9.15.0",
"eslint-plugin-format": "^0.1.2"
} }
} }

View File

@ -11,8 +11,8 @@
"google加速", "google加速",
"代理" "代理"
], ],
"bin": "./cli.js",
"main": "src/index.js", "main": "src/index.js",
"bin": "./cli.js",
"scripts": { "scripts": {
"start": "node ./src" "start": "node ./src"
}, },

View File

@ -1,6 +1,6 @@
const fs = require('fs') const fs = require('node:fs')
const jsonApi = require('@docmirror/mitmproxy/src/json')
const DevSidecar = require('@docmirror/dev-sidecar') const DevSidecar = require('@docmirror/dev-sidecar')
const jsonApi = require('@docmirror/mitmproxy/src/json')
// 启动服务 // 启动服务
const mitmproxyPath = './src/mitmproxy' const mitmproxyPath = './src/mitmproxy'

View File

@ -1,5 +1,5 @@
const fs = require('fs') const fs = require('node:fs')
const path = require('path') const path = require('node:path')
const server = require('@docmirror/mitmproxy') const server = require('@docmirror/mitmproxy')
const jsonApi = require('@docmirror/mitmproxy/src/json') const jsonApi = require('@docmirror/mitmproxy/src/json')
const log = require('../src/utils/util.log') const log = require('../src/utils/util.log')
@ -9,7 +9,8 @@ const home = process.env.USER_HOME || process.env.HOME || 'C:/Users/Administrato
let configPath let configPath
if (process.argv && process.argv.length > 3) { if (process.argv && process.argv.length > 3) {
configPath = process.argv[2] configPath = process.argv[2]
} else { }
else {
configPath = path.join(home, '.dev-sidecar/running.json') configPath = path.join(home, '.dev-sidecar/running.json')
} }

View File

@ -16,12 +16,12 @@
"test": "mocha" "test": "mocha"
}, },
"dependencies": { "dependencies": {
"spawn-sync": "^2.0.0",
"fix-path": "^3.0.0", "fix-path": "^3.0.0",
"iconv-lite": "^0.6.3", "iconv-lite": "^0.6.3",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"log4js": "^6.9.1", "log4js": "^6.9.1",
"node-powershell": "^4.0.0", "node-powershell": "^4.0.0",
"spawn-sync": "^2.0.0",
"winreg": "^1.2.5" "winreg": "^1.2.5"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,5 +1,5 @@
const fs = require('fs') const fs = require('node:fs')
const path = require('path') const path = require('node:path')
const jsonApi = require('@docmirror/mitmproxy/src/json') const jsonApi = require('@docmirror/mitmproxy/src/json')
const lodash = require('lodash') const lodash = require('lodash')
const request = require('request') const request = require('request')
@ -30,7 +30,8 @@ function _getConfigPath () {
const dir = getDefaultConfigBasePath() const dir = getDefaultConfigBasePath()
if (!fs.existsSync(dir)) { if (!fs.existsSync(dir)) {
fs.mkdirSync(dir) fs.mkdirSync(dir)
} else { }
else {
// 兼容1.7.3及以下版本的配置文件处理逻辑 // 兼容1.7.3及以下版本的配置文件处理逻辑
const newFilePath = path.join(dir, '/config.json') const newFilePath = path.join(dir, '/config.json')
const oldFilePath = path.join(dir, '/config.json5') const oldFilePath = path.join(dir, '/config.json5')
@ -52,7 +53,8 @@ const configApi = {
try { try {
await configApi.downloadRemoteConfig() await configApi.downloadRemoteConfig()
configApi.reload() configApi.reload()
} catch (e) { }
catch (e) {
log.error('定时下载远程配置并重载配置失败', e) log.error('定时下载远程配置并重载配置失败', e)
} }
} }
@ -102,7 +104,8 @@ const configApi = {
log.warn('下载远程配置成功,但内容为空:', remoteConfigUrl) log.warn('下载远程配置成功,但内容为空:', remoteConfigUrl)
resolve() resolve()
return return
} else { }
else {
log.info('下载远程配置成功:', remoteConfigUrl) log.info('下载远程配置成功:', remoteConfigUrl)
} }
@ -110,7 +113,8 @@ const configApi = {
let remoteConfig let remoteConfig
try { try {
remoteConfig = jsonApi.parse(body) remoteConfig = jsonApi.parse(body)
} catch (e) { }
catch (e) {
log.error(`远程配置内容格式不正确, url: ${remoteConfigUrl}, body: ${body}`) log.error(`远程配置内容格式不正确, url: ${remoteConfigUrl}, body: ${body}`)
remoteConfig = null remoteConfig = null
} }
@ -119,18 +123,21 @@ const configApi = {
const remoteSavePath = _getRemoteSavePath(suffix) const remoteSavePath = _getRemoteSavePath(suffix)
fs.writeFileSync(remoteSavePath, body) fs.writeFileSync(remoteSavePath, body)
log.info('保存远程配置文件成功:', remoteSavePath) log.info('保存远程配置文件成功:', remoteSavePath)
} else { }
else {
log.warn('远程配置对象为空:', remoteConfigUrl) log.warn('远程配置对象为空:', remoteConfigUrl)
} }
resolve() resolve()
} else { }
else {
log.error(`下载远程配置失败: ${remoteConfigUrl}, response:`, response, ', body:', body) log.error(`下载远程配置失败: ${remoteConfigUrl}, response:`, response, ', body:', body)
let message let message
if (response) { if (response) {
message = `下载远程配置失败: ${remoteConfigUrl}, message: ${response.message}, code: ${response.statusCode}` message = `下载远程配置失败: ${remoteConfigUrl}, message: ${response.message}, code: ${response.statusCode}`
} else { }
else {
message = `下载远程配置失败: response: ${response}` message = `下载远程配置失败: response: ${response}`
} }
reject(new Error(message)) reject(new Error(message))
@ -154,7 +161,8 @@ const configApi = {
if (!get().app.remoteConfig.personalUrl) { if (!get().app.remoteConfig.personalUrl) {
return '{}' return '{}'
} }
} else if (suffix === '') { }
else if (suffix === '') {
if (!get().app.remoteConfig.url) { if (!get().app.remoteConfig.url) {
return '{}' return '{}'
} }
@ -167,10 +175,12 @@ const configApi = {
const file = fs.readFileSync(path) const file = fs.readFileSync(path)
log.info('读取远程配置文件内容成功:', path) log.info('读取远程配置文件内容成功:', path)
return file.toString() return file.toString()
} else { }
else {
log.warn('远程配置文件不存在:', path) log.warn('远程配置文件不存在:', path)
} }
} catch (e) { }
catch (e) {
log.error('读取远程配置文件内容失败:', e) log.error('读取远程配置文件内容失败:', e)
} }
@ -220,7 +230,8 @@ const configApi = {
if (!fs.existsSync(configPath)) { if (!fs.existsSync(configPath)) {
userConfig = {} userConfig = {}
log.info('config.json 文件不存在:', configPath) log.info('config.json 文件不存在:', configPath)
} else { }
else {
const file = fs.readFileSync(configPath) const file = fs.readFileSync(configPath)
log.info('读取 config.json 成功:', configPath) log.info('读取 config.json 成功:', configPath)
const fileStr = file.toString() const fileStr = file.toString()
@ -265,7 +276,8 @@ const configApi = {
if (get().app.remoteConfig.personalUrl) { if (get().app.remoteConfig.personalUrl) {
mergeApi.doMerge(merged, personalRemoteConfig) // 再合并一次个人远程配置,使配置生效 mergeApi.doMerge(merged, personalRemoteConfig) // 再合并一次个人远程配置,使配置生效
} }
} else { }
else {
mergeApi.doMerge(merged, defConfig) // 合并默认配置 mergeApi.doMerge(merged, defConfig) // 合并默认配置
} }
if (newConfig != null) { if (newConfig != null) {
@ -306,7 +318,8 @@ const configApi = {
configApi.load(null) configApi.load(null)
return true // 删除并重新加载配置成功 return true // 删除并重新加载配置成功
} else { }
else {
return false // config.json 文件不存在 return false // config.json 文件不存在
} }
}, },
@ -315,7 +328,8 @@ const configApi = {
let value = lodash.get(defConfig, key) let value = lodash.get(defConfig, key)
value = lodash.cloneDeep(value) value = lodash.cloneDeep(value)
lodash.set(configTarget, key, value) lodash.set(configTarget, key, value)
} else { }
else {
configTarget = lodash.cloneDeep(defConfig) configTarget = lodash.cloneDeep(defConfig)
} }
return configTarget return configTarget

View File

@ -1,4 +1,4 @@
const path = require('path') const path = require('node:path')
function getUserBasePath () { function getUserBasePath () {
const userHome = process.env.USERPROFILE || process.env.HOME || '/' const userHome = process.env.USERPROFILE || process.env.HOME || '/'

View File

@ -1,226 +1,226 @@
{ {
"server": { "server": {
"compatible": { "compatible": {
"connect": { "connect": {
"218.18.106.132:443": { "218.18.106.132:443": {
"ssl": true "ssl": true
} }
}, },
"request": { "request": {
"218.18.106.132:443": { "218.18.106.132:443": {
"rejectUnauthorized": false "rejectUnauthorized": false
} }
} }
}, },
"intercepts": { "intercepts": {
"github.com": { "github.com": {
"^(/[\\w-.]+){2,}/?(\\?.*)?$": { "^(/[\\w-.]+){2,}/?(\\?.*)?$": {
"tampermonkeyScript": "https://gitee.com/wangliang181230/dev-sidecar/raw/scripts/tampermonkey.js", "tampermonkeyScript": "https://gitee.com/wangliang181230/dev-sidecar/raw/scripts/tampermonkey.js",
"script": "https://gitee.com/wangliang181230/dev-sidecar/raw/scripts/GithubEnhanced-High-Speed-Download.user.js" "script": "https://gitee.com/wangliang181230/dev-sidecar/raw/scripts/GithubEnhanced-High-Speed-Download.user.js"
}, },
"^(/[^/]+){2}/releases/download/.*$": { "^(/[^/]+){2}/releases/download/.*$": {
"redirect": "ghp.ci/https://github.com", "redirect": "ghp.ci/https://github.com",
"desc": "release文件加速下载重定向地址" "desc": "release文件加速下载重定向地址"
}, },
"^(/[^/]+){2}/archive/.*\\.(zip|tar.gz)$": { "^(/[^/]+){2}/archive/.*\\.(zip|tar.gz)$": {
"redirect": "ghp.ci/https://github.com", "redirect": "ghp.ci/https://github.com",
"desc": "release源代码加速下载重定向地址" "desc": "release源代码加速下载重定向地址"
}, },
"^((/[^/]+){2,})/raw((/[^/]+)+\\.(jpg|jpeg|png|gif))(\\?.*)?$": { "^((/[^/]+){2,})/raw((/[^/]+)+\\.(jpg|jpeg|png|gif))(\\?.*)?$": {
"sni": "baidu.com" // proxy拦截器不会使用 .* 中的sni配置故补充此配置 "sni": "baidu.com" // proxy拦截器不会使用 .* 中的sni配置故补充此配置
}, },
"^((/[^/]+){2,})/raw((/[^/]+)+\\.js)(\\?.*)?$": { "^((/[^/]+){2,})/raw((/[^/]+)+\\.js)(\\?.*)?$": {
"sni": "baidu.com" // proxy拦截器不会使用 .* 中的sni配置故补充此配置 "sni": "baidu.com" // proxy拦截器不会使用 .* 中的sni配置故补充此配置
} }
}, },
"api.github.com": { "api.github.com": {
".*": { ".*": {
"sni": "baidu.com" "sni": "baidu.com"
} }
}, },
"github.githubassets.com": { "github.githubassets.com": {
".*": { ".*": {
"sni": "baidu.com" "sni": "baidu.com"
} }
}, },
"avatars.githubusercontent.com": { "avatars.githubusercontent.com": {
".*": { ".*": {
"sni": "baidu.com" "sni": "baidu.com"
} }
}, },
"camo.githubusercontent.com": { "camo.githubusercontent.com": {
".*": { ".*": {
"sni": "baidu.com" "sni": "baidu.com"
} }
}, },
"collector.github.com": { "collector.github.com": {
".*": { ".*": {
"sni": "baidu.com" "sni": "baidu.com"
} }
}, },
"www.gstatic.com": { "www.gstatic.com": {
"/recaptcha/.*": { "/recaptcha/.*": {
"proxy": "www.recaptcha.net" "proxy": "www.recaptcha.net"
} }
} }
}, },
"preSetIpList": { "preSetIpList": {
"github.com": [ "github.com": [
"4.237.22.38", "4.237.22.38",
"20.26.156.215", "20.26.156.215",
"20.27.177.113", "20.27.177.113",
"20.87.245.0", "20.87.245.0",
"20.200.245.247", "20.200.245.247",
"20.201.28.151", "20.201.28.151",
"20.205.243.166", "20.205.243.166",
"140.82.113.3", "140.82.113.3",
"140.82.114.4", "140.82.114.4",
"140.82.116.3", "140.82.116.3",
"140.82.116.4", "140.82.116.4",
"140.82.121.3", "140.82.121.3",
"140.82.121.4" "140.82.121.4"
], ],
"hub.docker.com": null // 1.8.2版本中该域名的预设IP有问题现在远程配置中删除 "hub.docker.com": null // 1.8.2版本中该域名的预设IP有问题现在远程配置中删除
}, },
"dns": { "dns": {
"mapping": { "mapping": {
"*.jetbrains.com": "quad9", "*.jetbrains.com": "quad9",
"*.azureedge.net": "quad9", "*.azureedge.net": "quad9",
"*.stackoverflow.com": "quad9" "*.stackoverflow.com": "quad9"
}, },
"speedTest": { "speedTest": {
"interval": 300000 "interval": 300000
} }
}, },
"whiteList": { "whiteList": {
"*.icloud.com": true, "*.icloud.com": true,
"*.lenovo.net": true "*.lenovo.net": true
} }
}, },
"proxy": { "proxy": {
"remoteDomesticDomainAllowListFileUrl": "https://raw.kkgithub.com/pluwen/china-domain-allowlist/main/allow-list.sorl", "remoteDomesticDomainAllowListFileUrl": "https://raw.kkgithub.com/pluwen/china-domain-allowlist/main/allow-list.sorl",
"excludeIpList": { "excludeIpList": {
// Github文件上传所使用的域名被DS代理会导致文件上传经常失败从系统代理中排除掉 // Github文件上传所使用的域名被DS代理会导致文件上传经常失败从系统代理中排除掉
"objects-origin.githubusercontent.com": true, "objects-origin.githubusercontent.com": true,
// Github通过Actions上传的文件下载时所需的域名从系统代理中排除掉否则下载会失败 // Github通过Actions上传的文件下载时所需的域名从系统代理中排除掉否则下载会失败
"*.windows.net": true, "*.windows.net": true,
// Github下载release文件的高速镜像地址 // Github下载release文件的高速镜像地址
"*.ghproxy.net": true, "*.ghproxy.net": true,
"*.ghp.ci": true, "*.ghp.ci": true,
"*.kkgithub.com": true, "*.kkgithub.com": true,
// Github建站域名 // Github建站域名
"*.github.io": true, "*.github.io": true,
// bilibili相关 // bilibili相关
"*.bilicomic.com": true, "*.bilicomic.com": true,
// 中国移动云盘登录API // 中国移动云盘登录API
"[2049:8c54:813:10c::140]": true, "[2049:8c54:813:10c::140]": true,
"[2409:8a0c:a442:ff40:a51f:4b9c:8b41:25ea]": true, "[2409:8a0c:a442:ff40:a51f:4b9c:8b41:25ea]": true,
"[2606:2800:147:120f:30c:1ba0:fc6:265a]": true, "[2606:2800:147:120f:30c:1ba0:fc6:265a]": true,
// 移动云盘相关 // 移动云盘相关
"*.cmicapm.com": true, "*.cmicapm.com": true,
// cloudflare排除以下域名cloudflare的人机校验会更快成功率更高。 // cloudflare排除以下域名cloudflare的人机校验会更快成功率更高。
"*.cloudflare.com": true, "*.cloudflare.com": true,
"*.cloudflare-cn.com": true, "*.cloudflare-cn.com": true,
// VS相关 // VS相关
"*.microsoftonline.com": true, // 此域名不排除的话,部分功能将出现异常 "*.microsoftonline.com": true, // 此域名不排除的话,部分功能将出现异常
"*.msecnd.net": true, "*.msecnd.net": true,
"*.msedge.net": true, "*.msedge.net": true,
// 卡巴斯基升级域名 // 卡巴斯基升级域名
"*kaspersky*.com": true, "*kaspersky*.com": true,
"*.upd.kaspersky.com": true, "*.upd.kaspersky.com": true,
// sandbox沙盒域名 // sandbox沙盒域名
"*.sandboxie-plus.com": true, "*.sandboxie-plus.com": true,
// 无忧论坛 // 无忧论坛
"*.wuyou.net": true, "*.wuyou.net": true,
// python建图包域名浏览器 // python建图包域名浏览器
"*.pyecharts.org": true, "*.pyecharts.org": true,
// 教育网站 // 教育网站
"*.bcloudlink.com": true, "*.bcloudlink.com": true,
// 奇迹秀(资源) // 奇迹秀(资源)
"*.qijishow.com": true, "*.qijishow.com": true,
// Z-Library // Z-Library
"*.z-lib.fo": true, "*.z-lib.fo": true,
// FinalshellLinux学习网 // FinalshellLinux学习网
"*.finalshell.com": true, "*.finalshell.com": true,
// MineBBS我的世界中文论坛 // MineBBS我的世界中文论坛
"*.minebbs.com": true, "*.minebbs.com": true,
// 我的世界插件网 // 我的世界插件网
"*.spigotmc.org": true, "*.spigotmc.org": true,
// bd测试 // bd测试
"*.virustotal.com": true, "*.virustotal.com": true,
// 未知 // 未知
"*.youdemai.com": true, "*.youdemai.com": true,
"*.casualthink.com": true, "*.casualthink.com": true,
"44.239.165.12": true, "44.239.165.12": true,
"3.164.110.117": true "3.164.110.117": true
} }
}, },
"plugin": { "plugin": {
"overwall": { "overwall": {
"targets": { "targets": {
"*.github.com": true, "*.github.com": true,
"*github*.com": true, "*github*.com": true,
"*.nodejs.org": true, "*.nodejs.org": true,
"*.npmjs.com": true, "*.npmjs.com": true,
"*.wikimedia.org": true, "*.wikimedia.org": true,
"*.v2ex.com": true, "*.v2ex.com": true,
"*.azureedge.net": true, "*.azureedge.net": true,
"*.cloudfront.net": true, "*.cloudfront.net": true,
"*.bing.com": true, "*.bing.com": true,
"*.discourse-cdn.com": true, "*.discourse-cdn.com": true,
"*.gravatar.com": true, "*.gravatar.com": true,
"*.docker.com": true, "*.docker.com": true,
"*.vueuse.org": true, "*.vueuse.org": true,
"*.elastic.co": true, "*.elastic.co": true,
"*.optimizely.com": true, "*.optimizely.com": true,
"*.stackpathcdn.com": true, "*.stackpathcdn.com": true,
"*.fastly.net": true, "*.fastly.net": true,
"*.cloudflare.com": true, "*.cloudflare.com": true,
"*.233v2.com": true, "*.233v2.com": true,
"*.v2fly.org": true, "*.v2fly.org": true,
"*.telegram.org": true, "*.telegram.org": true,
"*.amazon.com": true, "*.amazon.com": true,
"*.googleapis.com": true, "*.googleapis.com": true,
"*.google-analytics.com": true, "*.google-analytics.com": true,
"*.cloudflareinsights.com": true, "*.cloudflareinsights.com": true,
"*.intlify.dev": true, "*.intlify.dev": true,
"*.segment.io": true, "*.segment.io": true,
"*.shields.io": true, "*.shields.io": true,
"*.jsdelivr.net": true, "*.jsdelivr.net": true,
"*.z-library.sk": true, "*.z-library.sk": true,
"*.zlibrary*.se": true, "*.zlibrary*.se": true,
// 维基百科 // 维基百科
"*.wikipedia-on-ipfs.org": true, "*.wikipedia-on-ipfs.org": true,
// ChatGPT // ChatGPT
"*.oaiusercontent.com": true, // 在ChatGPT中生成文件并下载所需的域名 "*.oaiusercontent.com": true, // 在ChatGPT中生成文件并下载所需的域名
// Pixiv相关 // Pixiv相关
"*.pixiv.org": true, "*.pixiv.org": true,
"*.fanbox.cc": true, "*.fanbox.cc": true,
"*.onesignal.com": true // pixiv站点会加载该域名下的js脚本 "*.onesignal.com": true // pixiv站点会加载该域名下的js脚本
}, },
"pac": { "pac": {
"pacFileUpdateUrl": "https://raw.kkgithub.com/gfwlist/gfwlist/master/gfwlist.txt" "pacFileUpdateUrl": "https://raw.kkgithub.com/gfwlist/gfwlist/master/gfwlist.txt"
} }
} }
} }
} }

View File

@ -46,14 +46,16 @@ async function startup ({ mitmproxyPath }) {
if (conf.server.enabled) { if (conf.server.enabled) {
try { try {
await server.start({ mitmproxyPath }) await server.start({ mitmproxyPath })
} catch (err) { }
catch (err) {
log.error('代理服务启动失败:', err) log.error('代理服务启动失败:', err)
} }
} }
if (conf.proxy.enabled) { if (conf.proxy.enabled) {
try { try {
await proxy.start() await proxy.start()
} catch (err) { }
catch (err) {
log.error('开启系统代理失败:', err) log.error('开启系统代理失败:', err)
} }
} }
@ -65,7 +67,8 @@ async function startup ({ mitmproxyPath }) {
try { try {
await plugin[key].start() await plugin[key].start()
log.info(`插件【${key}】已启动`) log.info(`插件【${key}】已启动`)
} catch (err) { }
catch (err) {
log.error(`插件【${key}】启动失败:`, err) log.error(`插件【${key}】启动失败:`, err)
} }
} }
@ -75,7 +78,8 @@ async function startup ({ mitmproxyPath }) {
if (plugins && plugins.length > 0) { if (plugins && plugins.length > 0) {
await Promise.all(plugins) await Promise.all(plugins)
} }
} catch (err) { }
catch (err) {
log.error('开启插件失败:', err) log.error('开启插件失败:', err)
} }
} }
@ -89,7 +93,8 @@ async function shutdown () {
try { try {
await plugin[key].close() await plugin[key].close()
log.info(`插件【${key}】已关闭`) log.info(`插件【${key}】已关闭`)
} catch (err) { }
catch (err) {
log.error(`插件【${key}】关闭失败:`, err) log.error(`插件【${key}】关闭失败:`, err)
} }
} }
@ -99,7 +104,8 @@ async function shutdown () {
if (plugins.length > 0) { if (plugins.length > 0) {
await Promise.all(plugins) await Promise.all(plugins)
} }
} catch (error) { }
catch (error) {
log.error('插件关闭失败:', error) log.error('插件关闭失败:', error)
} }
@ -107,7 +113,8 @@ async function shutdown () {
try { try {
await proxy.close() await proxy.close()
log.info('系统代理已关闭') log.info('系统代理已关闭')
} catch (err) { }
catch (err) {
log.error('系统代理关闭失败:', err) log.error('系统代理关闭失败:', err)
} }
} }
@ -115,7 +122,8 @@ async function shutdown () {
try { try {
await server.close() await server.close()
log.info('代理服务已关闭') log.info('代理服务已关闭')
} catch (err) { }
catch (err) {
log.error('代理服务关闭失败:', err) log.error('代理服务关闭失败:', err)
} }
} }

View File

@ -56,13 +56,15 @@ const Plugin = function (context) {
try { try {
await shell.exec(['git config --global --unset https.proxy '], { type: 'cmd' }) await shell.exec(['git config --global --unset https.proxy '], { type: 'cmd' })
} catch (ignore) { }
catch (ignore) {
} }
if (config.get().plugin.git.setting.sslVerify === true) { if (config.get().plugin.git.setting.sslVerify === true) {
try { try {
await shell.exec(['git config --global --unset http.sslVerify '], { type: 'cmd' }) await shell.exec(['git config --global --unset http.sslVerify '], { type: 'cmd' })
} catch (ignore) { }
catch (ignore) {
} }
} }
@ -70,7 +72,8 @@ const Plugin = function (context) {
for (const url in config.get().plugin.git.setting.noProxyUrls) { for (const url in config.get().plugin.git.setting.noProxyUrls) {
try { try {
await shell.exec([`git config --global --unset http."${url}".proxy `], { type: 'cmd' }) await shell.exec([`git config --global --unset http."${url}".proxy `], { type: 'cmd' })
} catch (ignore) { }
catch (ignore) {
} }
} }
} }

View File

@ -7,7 +7,8 @@ const NodePlugin = function (context) {
async start () { async start () {
try { try {
await nodeApi.setVariables() await nodeApi.setVariables()
} catch (err) { }
catch (err) {
log.warn('set variables error:', err) log.warn('set variables error:', err)
} }
@ -47,7 +48,8 @@ const NodePlugin = function (context) {
for (const item of list) { for (const item of list) {
if (item.value != null && item.value.length > 0 && item.value !== 'default' && item.value !== 'null') { if (item.value != null && item.value.length > 0 && item.value !== 'default' && item.value !== 'null') {
cmds.push(`${command} config set ${item.key} ${item.value}`) cmds.push(`${command} config set ${item.key} ${item.value}`)
} else { }
else {
cmds.push(`${command} config delete ${item.key}`) cmds.push(`${command} config delete ${item.key}`)
} }
} }
@ -70,7 +72,8 @@ const NodePlugin = function (context) {
for (const item of list) { for (const item of list) {
if (item.value != null && item.value.length > 0 && item.value !== 'default' && item.value !== 'null') { if (item.value != null && item.value.length > 0 && item.value !== 'default' && item.value !== 'null') {
cmds.push(`yarn config set ${item.key} ${item.value}`) cmds.push(`yarn config set ${item.key} ${item.value}`)
} else { }
else {
cmds.push(`yarn config delete ${item.key}`) cmds.push(`yarn config delete ${item.key}`)
} }
} }
@ -115,7 +118,8 @@ const NodePlugin = function (context) {
async setRegistry ({ registry, type }) { async setRegistry ({ registry, type }) {
if (type === 'npm') { if (type === 'npm') {
await nodeApi.setNpmEnv([{ key: 'registry', value: registry }]) await nodeApi.setNpmEnv([{ key: 'registry', value: registry }])
} else { }
else {
await nodeApi.setYarnEnv([{ key: 'registry', value: registry }]) await nodeApi.setYarnEnv([{ key: 'registry', value: registry }])
} }
return true return true

View File

@ -28,7 +28,8 @@ const Plugin = function (context) {
for (const key in server) { for (const key in server) {
if (i === 0) { if (i === 0) {
main = key main = key
} else { }
else {
backup.push(key) backup.push(key)
} }
i++ i++

View File

@ -48,7 +48,8 @@ const PipPlugin = function (context) {
for (const item of list) { for (const item of list) {
if (item.value != null) { if (item.value != null) {
cmds.push(`${command} config set global.${item.key} ${item.value}`) cmds.push(`${command} config set global.${item.key} ${item.value}`)
} else { }
else {
cmds.push(`${command} config unset global.${item.key}`) cmds.push(`${command} config unset global.${item.key}`)
} }
} }

View File

@ -33,7 +33,8 @@ const ProxyPlugin = function (context) {
event.fire('status', { key: 'proxy.enabled', value: false }) event.fire('status', { key: 'proxy.enabled', value: false })
log.info('关闭系统代理成功') log.info('关闭系统代理成功')
return true return true
} catch (err) { }
catch (err) {
log.error('关闭系统代理失败:', err) log.error('关闭系统代理失败:', err)
return false return false
} }

View File

@ -2,9 +2,9 @@ const lodash = require('lodash')
const config = require('../../config') const config = require('../../config')
const event = require('../../event') const event = require('../../event')
const status = require('../../status') const status = require('../../status')
const fork = require('child_process').fork const fork = require('node:child_process').fork
const fs = require('fs') const fs = require('node:fs')
const path = require('path') const path = require('node:path')
const jsonApi = require('@docmirror/mitmproxy/src/json') const jsonApi = require('@docmirror/mitmproxy/src/json')
const log = require('../../utils/util.log') const log = require('../../utils/util.log')
@ -102,14 +102,16 @@ const serverApi = {
log.info('收到子进程消息:', JSON.stringify(msg)) log.info('收到子进程消息:', JSON.stringify(msg))
if (msg.type === 'status') { if (msg.type === 'status') {
fireStatus(msg.event) fireStatus(msg.event)
} else if (msg.type === 'error') { }
else if (msg.type === 'error') {
let code = '' let code = ''
if (msg.event.code) { if (msg.event.code) {
code = msg.event.code code = msg.event.code
} }
fireStatus(false) // 启动失败 fireStatus(false) // 启动失败
event.fire('error', { key: 'server', value: code, error: msg.event, message: msg.message }) event.fire('error', { key: 'server', value: code, error: msg.event, message: msg.message })
} else if (msg.type === 'speed') { }
else if (msg.type === 'speed') {
event.fire('speed', msg.event) event.fire('speed', msg.event)
} }
}) })
@ -139,12 +141,14 @@ const serverApi = {
} }
log.warn('代理服务关闭失败:', err) log.warn('代理服务关闭失败:', err)
reject(err) reject(err)
} else { }
else {
log.info('代理服务关闭成功') log.info('代理服务关闭成功')
resolve() resolve()
} }
}) })
} else { }
else {
log.info('server is null') log.info('server is null')
resolve() resolve()
} }

View File

@ -1,4 +1,4 @@
const path = require('path') const path = require('node:path')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
function getExtraPath () { function getExtraPath () {

View File

@ -1,12 +1,12 @@
const fs = require('node:fs')
const path = require('node:path')
const request = require('request')
/** /**
* 获取环境变量 * 获取环境变量
*/ */
const Registry = require('winreg') const Registry = require('winreg')
const Shell = require('../../shell')
const fs = require('fs')
const path = require('path')
const request = require('request')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const Shell = require('../../shell')
const extraPath = require('../extra-path/index') const extraPath = require('../extra-path/index')
const execute = Shell.execute const execute = Shell.execute
@ -44,7 +44,8 @@ async function _winUnsetProxy (exec, setEnv) {
}) })
} }
}) })
} catch (e) { }
catch (e) {
log.error('删除环境变量 HTTPS_PROXY、HTTP_PROXY 失败:', e) log.error('删除环境变量 HTTPS_PROXY、HTTP_PROXY 失败:', e)
} }
} }
@ -67,7 +68,8 @@ async function downloadDomesticDomainAllowListAsync () {
if (body == null || body.length < 100) { if (body == null || body.length < 100) {
log.warn('下载远程 domestic-domain-allowlist.txt 文件成功,但内容为空或内容太短,判断为无效的 domestic-domain-allowlist.txt 文件:', remoteFileUrl, ', body:', body) log.warn('下载远程 domestic-domain-allowlist.txt 文件成功,但内容为空或内容太短,判断为无效的 domestic-domain-allowlist.txt 文件:', remoteFileUrl, ', body:', body)
return return
} else { }
else {
log.info('下载远程 domestic-domain-allowlist.txt 文件成功:', remoteFileUrl) log.info('下载远程 domestic-domain-allowlist.txt 文件成功:', remoteFileUrl)
} }
@ -77,7 +79,8 @@ async function downloadDomesticDomainAllowListAsync () {
fileTxt = Buffer.from(fileTxt, 'base64').toString('utf8') fileTxt = Buffer.from(fileTxt, 'base64').toString('utf8')
// log.debug('解析 base64 后的 domestic-domain-allowlist:', fileTxt) // log.debug('解析 base64 后的 domestic-domain-allowlist:', fileTxt)
} }
} catch (e) { }
catch (e) {
if (!fileTxt.includes('*.')) { if (!fileTxt.includes('*.')) {
log.error(`远程 domestic-domain-allowlist.txt 文件内容即不是base64格式也不是要求的格式url: ${remoteFileUrl}body: ${body}`) log.error(`远程 domestic-domain-allowlist.txt 文件内容即不是base64格式也不是要求的格式url: ${remoteFileUrl}body: ${body}`)
return return
@ -86,7 +89,8 @@ async function downloadDomesticDomainAllowListAsync () {
// 保存到本地 // 保存到本地
saveDomesticDomainAllowListFile(fileTxt) saveDomesticDomainAllowListFile(fileTxt)
} else { }
else {
log.error(`下载远程 domestic-domain-allowlist.txt 文件失败: ${remoteFileUrl}, response:`, response, ', body:', body) log.error(`下载远程 domestic-domain-allowlist.txt 文件失败: ${remoteFileUrl}, response:`, response, ', body:', body)
} }
}) })
@ -97,7 +101,8 @@ function loadLastModifiedTimeFromTxt (fileTxt) {
if (matched && matched.length > 0) { if (matched && matched.length > 0) {
try { try {
return new Date(matched[0]) return new Date(matched[0])
} catch (ignore) { }
catch (ignore) {
return null return null
} }
} }
@ -122,7 +127,8 @@ function saveDomesticDomainAllowListFile (fileTxt) {
fs.utimes(filePath, lastModifiedTime, lastModifiedTime, (utimesErr) => { fs.utimes(filePath, lastModifiedTime, lastModifiedTime, (utimesErr) => {
if (utimesErr) { if (utimesErr) {
log.error('修改 domestic-domain-allowlist.txt 文件时间失败:', utimesErr) log.error('修改 domestic-domain-allowlist.txt 文件时间失败:', utimesErr)
} else { }
else {
log.info(`'${filePath}' 文件的修改时间已更新为其最近更新时间 '${formatDate(lastModifiedTime)}'`) log.info(`'${filePath}' 文件的修改时间已更新为其最近更新时间 '${formatDate(lastModifiedTime)}'`)
} }
}) })
@ -163,19 +169,22 @@ function getDomesticDomainAllowList () {
// 如果临时文件已存在,则使用临时文件 // 如果临时文件已存在,则使用临时文件
fileAbsolutePath = tmpFilePath fileAbsolutePath = tmpFilePath
log.info('读取已下载的 domestic-domain-allowlist.txt 文件:', fileAbsolutePath) log.info('读取已下载的 domestic-domain-allowlist.txt 文件:', fileAbsolutePath)
} else { }
else {
// 如果临时文件不存在,则使用内置文件 // 如果临时文件不存在,则使用内置文件
log.info('__dirname:', __dirname) log.info('__dirname:', __dirname)
fileAbsolutePath = path.join(__dirname, '../', config.get().proxy.domesticDomainAllowListFilePath) fileAbsolutePath = path.join(__dirname, '../', config.get().proxy.domesticDomainAllowListFilePath)
log.info('读取内置的 domestic-domain-allowlist.txt 文件:', fileAbsolutePath) log.info('读取内置的 domestic-domain-allowlist.txt 文件:', fileAbsolutePath)
} }
} else { }
else {
log.info('读取自定义路径的 domestic-domain-allowlist.txt 文件:', fileAbsolutePath) log.info('读取自定义路径的 domestic-domain-allowlist.txt 文件:', fileAbsolutePath)
} }
try { try {
return fs.readFileSync(fileAbsolutePath).toString() return fs.readFileSync(fileAbsolutePath).toString()
} catch (e) { }
catch (e) {
log.error(`读取 domestic-domain-allowlist.txt 文件失败: ${fileAbsolutePath}, error:`, e) log.error(`读取 domestic-domain-allowlist.txt 文件失败: ${fileAbsolutePath}, error:`, e)
return null return null
} }
@ -198,11 +207,13 @@ function getProxyExcludeIpStr (split) {
if (domesticDomainAllowList) { if (domesticDomainAllowList) {
excludeIpStr += domesticDomainAllowList excludeIpStr += domesticDomainAllowList
log.info('系统代理排除列表拼接国内域名') log.info('系统代理排除列表拼接国内域名')
} else { }
else {
log.info('国内域名为空,不进行系统代理排除列表拼接国内域名') log.info('国内域名为空,不进行系统代理排除列表拼接国内域名')
} }
} }
} catch (e) { }
catch (e) {
log.error('系统代理排除列表拼接国内域名失败:', e) log.error('系统代理排除列表拼接国内域名失败:', e)
} }
} }
@ -246,7 +257,8 @@ async function _winSetProxy (exec, ip, port, setEnv) {
} }
// await addClearScriptIni() // await addClearScriptIni()
} catch (e) { }
catch (e) {
log.error('设置环境变量 HTTPS_PROXY、HTTP_PROXY 失败:', e) log.error('设置环境变量 HTTPS_PROXY、HTTP_PROXY 失败:', e)
} }
} }
@ -260,7 +272,8 @@ const executor = {
if (ip != null) { // 设置代理 if (ip != null) { // 设置代理
log.info('设置windows系统代理:', ip, port, setEnv) log.info('设置windows系统代理:', ip, port, setEnv)
return _winSetProxy(exec, ip, port, setEnv) return _winSetProxy(exec, ip, port, setEnv)
} else { // 关闭代理 }
else { // 关闭代理
log.info('关闭windows系统代理') log.info('关闭windows系统代理')
return _winUnsetProxy(exec, setEnv) return _winUnsetProxy(exec, setEnv)
} }
@ -281,7 +294,8 @@ const executor = {
if (config.get().proxy.proxyHttp) { if (config.get().proxy.proxyHttp) {
setProxyCmd.push(`gsettings set org.gnome.system.proxy.http host ${ip}`) setProxyCmd.push(`gsettings set org.gnome.system.proxy.http host ${ip}`)
setProxyCmd.push(`gsettings set org.gnome.system.proxy.http port ${port - 1}`) setProxyCmd.push(`gsettings set org.gnome.system.proxy.http port ${port - 1}`)
} else { }
else {
setProxyCmd.push('gsettings set org.gnome.system.proxy.http host \'\'') setProxyCmd.push('gsettings set org.gnome.system.proxy.http host \'\'')
setProxyCmd.push('gsettings set org.gnome.system.proxy.http port 0') setProxyCmd.push('gsettings set org.gnome.system.proxy.http port 0')
} }
@ -291,7 +305,8 @@ const executor = {
setProxyCmd.push(`gsettings set org.gnome.system.proxy ignore-hosts "['${excludeIpStr}']"`) setProxyCmd.push(`gsettings set org.gnome.system.proxy ignore-hosts "['${excludeIpStr}']"`)
await exec(setProxyCmd) await exec(setProxyCmd)
} else { // 关闭代理 }
else { // 关闭代理
const setProxyCmd = [ const setProxyCmd = [
'gsettings set org.gnome.system.proxy mode none', 'gsettings set org.gnome.system.proxy mode none',
] ]
@ -313,7 +328,8 @@ const executor = {
// http // http
if (config.get().proxy.proxyHttp) { if (config.get().proxy.proxyHttp) {
await exec(`networksetup -setwebproxy "${wifiAdaptor}" ${ip} ${port - 1}`) await exec(`networksetup -setwebproxy "${wifiAdaptor}" ${ip} ${port - 1}`)
} else { }
else {
await exec(`networksetup -setwebproxystate "${wifiAdaptor}" off`) await exec(`networksetup -setwebproxystate "${wifiAdaptor}" off`)
} }
@ -328,7 +344,8 @@ const executor = {
// source ~/.zshrc // source ~/.zshrc
// ` // `
// await exec(setEnv) // await exec(setEnv)
} else { // 关闭代理 }
else { // 关闭代理
// https // https
await exec(`networksetup -setsecurewebproxystate "${wifiAdaptor}" off`) await exec(`networksetup -setsecurewebproxystate "${wifiAdaptor}" off`)
// http // http

View File

@ -1,5 +1,5 @@
const childProcess = require('child_process') const childProcess = require('node:child_process')
const os = require('os') const os = require('node:os')
const fixPath = require('fix-path') const fixPath = require('fix-path')
const iconv = require('iconv-lite') const iconv = require('iconv-lite')
const PowerShell = require('node-powershell') const PowerShell = require('node-powershell')
@ -60,10 +60,12 @@ class WindowsSystemShell extends SystemShell {
const ret = await ps.invoke() const ret = await ps.invoke()
// log.info('ps complete', cmds) // log.info('ps complete', cmds)
return ret return ret
} finally { }
finally {
ps.dispose() ps.dispose()
} }
} else { }
else {
let compose = 'echo "test" ' // 'chcp 65001 ' let compose = 'echo "test" ' // 'chcp 65001 '
for (const cmd of cmds) { for (const cmd of cmds) {
compose += ` && ${cmd}` compose += ` && ${cmd}`
@ -78,7 +80,7 @@ class WindowsSystemShell extends SystemShell {
function _childExec (composeCmds, options = {}) { function _childExec (composeCmds, options = {}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const childProcess = require('child_process') const childProcess = require('node:child_process')
log.info('shell:', composeCmds) log.info('shell:', composeCmds)
childProcess.exec(composeCmds, options, (error, stdout, stderr) => { childProcess.exec(composeCmds, options, (error, stdout, stderr) => {
if (error) { if (error) {
@ -86,7 +88,8 @@ function _childExec (composeCmds, options = {}) {
log.error('cmd 命令执行错误:\n===>\ncommands:', composeCmds, '\n error:', error, '\n<===') log.error('cmd 命令执行错误:\n===>\ncommands:', composeCmds, '\n error:', error, '\n<===')
} }
reject(new Error(stderr)) reject(new Error(stderr))
} else { }
else {
// log.info('cmd 命令完成:', stdout) // log.info('cmd 命令完成:', stdout)
resolve(stdout) resolve(stdout)
} }
@ -101,7 +104,7 @@ function childExec (composeCmds, options = {}) {
const encoding = 'cp936' const encoding = 'cp936'
const binaryEncoding = 'binary' const binaryEncoding = 'binary'
const childProcess = require('child_process') const childProcess = require('node:child_process')
log.info('shell:', composeCmds) log.info('shell:', composeCmds)
childProcess.exec(composeCmds, { encoding: binaryEncoding }, (error, stdout, stderr) => { childProcess.exec(composeCmds, { encoding: binaryEncoding }, (error, stdout, stderr) => {
if (error) { if (error) {
@ -111,7 +114,8 @@ function childExec (composeCmds, options = {}) {
log.error('cmd 命令执行错误:\n------------------------------\ncommands:', composeCmds, '\n message:', message, '\n error:', error, '\n------------------------------') log.error('cmd 命令执行错误:\n------------------------------\ncommands:', composeCmds, '\n message:', message, '\n error:', error, '\n------------------------------')
} }
reject(new Error(message)) reject(new Error(message))
} else { }
else {
// log.info('cmd 命令完成:', stdout) // log.info('cmd 命令完成:', stdout)
const message = iconv.decode(Buffer.from(stdout, binaryEncoding), encoding) const message = iconv.decode(Buffer.from(stdout, binaryEncoding), encoding)
resolve(message) resolve(message)
@ -167,7 +171,8 @@ async function execFile (file, args, options) {
log.debug('文件执行成功:', file) log.debug('文件执行成功:', file)
resolve(stdout) resolve(stdout)
}) })
} catch (e) { }
catch (e) {
log.error('文件执行出错:', file, e) log.error('文件执行出错:', file, e)
reject(e) reject(e)
} }

View File

@ -34,7 +34,7 @@
// console.error(e) // console.error(e)
// }) // })
const fs = require('fs') const fs = require('node:fs')
const request = require('request') const request = require('request')
request({ request({

View File

@ -1,4 +1,4 @@
const path = require('path') const path = require('node:path')
const log4js = require('log4js') const log4js = require('log4js')
const config = require('../config/index') const config = require('../config/index')
@ -16,14 +16,14 @@ log4js.configure({
appenders: { appenders: {
std: { type: 'stdout' }, std: { type: 'stdout' },
core: { type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename: coreLogFilename }, core: { type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename: coreLogFilename },
gui: { type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename: guiLogFilename }, gui: { type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename: guiLogFilename },
server: { level: 'debug', type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename: serverLogFilename } server: { level: 'debug', type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename: serverLogFilename },
}, },
categories: { categories: {
default: { appenders: ['std'], level }, default: { appenders: ['std'], level },
core: { appenders: ['core', 'std'], level }, core: { appenders: ['core', 'std'], level },
gui: { appenders: ['gui', 'std'], level }, gui: { appenders: ['gui', 'std'], level },
server: { appenders: ['server', 'std'], level } server: { appenders: ['server', 'std'], level },
}, },
}) })

View File

@ -1,4 +1,4 @@
const https = require('https') const https = require('node:https')
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1' process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'

View File

@ -1,24 +1,29 @@
# dev-sidecar-gui # dev-sidecar-gui
## Project setup ## Project setup
``` ```
yarn install yarn install
``` ```
### Compiles and hot-reloads for development ### Compiles and hot-reloads for development
``` ```
yarn serve yarn serve
``` ```
### Compiles and minifies for production ### Compiles and minifies for production
``` ```
yarn build yarn build
``` ```
### Lints and fixes files ### Lints and fixes files
``` ```
yarn lint yarn lint
``` ```
### Customize configuration ### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/). See [Configuration Reference](https://cli.vuejs.org/config/).

View File

@ -1,5 +1,5 @@
module.exports = { module.exports = {
presets: [ presets: [
'@vue/babel-preset-jsx' '@vue/babel-preset-jsx',
] ],
} }

View File

@ -1,5 +1,5 @@
const fs = require('fs') const fs = require('node:fs')
const path = require('path') const path = require('node:path')
const pkg = require('../package.json') const pkg = require('../package.json')
function appendIntro (context, systemType, latest) { function appendIntro (context, systemType, latest) {

View File

@ -1,5 +1,5 @@
const fs = require('fs') const fs = require('node:fs')
const path = require('path') const path = require('node:path')
const AdmZip = require('adm-zip') const AdmZip = require('adm-zip')
const pkg = require('../package.json') const pkg = require('../package.json')
@ -24,11 +24,13 @@ exports.default = async function (context) {
if (context.packager.platform.nodeName === 'darwin') { if (context.packager.platform.nodeName === 'darwin') {
targetPath = path.join(context.appOutDir, `${context.packager.appInfo.productName}.app/Contents/Resources`) targetPath = path.join(context.appOutDir, `${context.packager.appInfo.productName}.app/Contents/Resources`)
systemType = 'mac' systemType = 'mac'
} else if (context.packager.platform.nodeName === 'linux') { }
else if (context.packager.platform.nodeName === 'linux') {
targetPath = path.join(context.appOutDir, './resources') targetPath = path.join(context.appOutDir, './resources')
systemType = 'linux' systemType = 'linux'
writeAppUpdateYmlForLinux() writeAppUpdateYmlForLinux()
} else { }
else {
targetPath = path.join(context.appOutDir, './resources') targetPath = path.join(context.appOutDir, './resources')
systemType = 'win' systemType = 'win'
} }

View File

@ -1,16 +1,20 @@
<!DOCTYPE html> <!doctype html>
<html lang="en" style="height:100%"> <html lang="en" style="height: 100%">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title><%= htmlWebpackPlugin.options.title %></title> <title><%= htmlWebpackPlugin.options.title %></title>
<script type="application/javascript">window.config = {}</script> <script type="application/javascript">
window.config = {}
</script>
</head> </head>
<body style="height:100%"> <body style="height: 100%">
<div id="app" style="height:100%"> <div id="app" style="height: 100%">
<div style="display: flex;align-items: center;justify-content: center;height:100%;width:100%"><img src="loading-spin.svg"></div> <div style="display: flex; align-items: center; justify-content: center; height: 100%; width: 100%">
<img src="loading-spin.svg" />
</div>
</div> </div>
<!-- built files will be auto injected --> <!-- built files will be auto injected -->
</body> </body>

View File

@ -1,6 +1,6 @@
'use strict' 'use strict'
/* global __static */ /* global __static */
import path from 'path' import path from 'node:path'
import DevSidecar from '@docmirror/dev-sidecar' import DevSidecar from '@docmirror/dev-sidecar'
import { app, BrowserWindow, dialog, globalShortcut, ipcMain, Menu, nativeImage, nativeTheme, powerMonitor, protocol, Tray } from 'electron' import { app, BrowserWindow, dialog, globalShortcut, ipcMain, Menu, nativeImage, nativeTheme, powerMonitor, protocol, Tray } from 'electron'
import minimist from 'minimist' import minimist from 'minimist'
@ -34,7 +34,8 @@ function openDevTools () {
log.debug('尝试打开 `开发者工具`') log.debug('尝试打开 `开发者工具`')
win.webContents.openDevTools() win.webContents.openDevTools()
log.debug('打开 `开发者工具` 成功') log.debug('打开 `开发者工具` 成功')
} catch (e) { }
catch (e) {
log.error('打开 `开发者工具` 失败:', e) log.error('打开 `开发者工具` 失败:', e)
} }
} }
@ -44,7 +45,8 @@ function closeDevTools () {
log.debug('尝试关闭 `开发者工具`') log.debug('尝试关闭 `开发者工具`')
win.webContents.closeDevTools() win.webContents.closeDevTools()
log.debug('关闭 `开发者工具` 成功') log.debug('关闭 `开发者工具` 成功')
} catch (e) { }
catch (e) {
log.error('关闭 `开发者工具` 失败:', e) log.error('关闭 `开发者工具` 失败:', e)
} }
} }
@ -55,7 +57,8 @@ function switchDevTools () {
} }
if (win.webContents.isDevToolsOpened()) { if (win.webContents.isDevToolsOpened()) {
closeDevTools() closeDevTools()
} else { }
else {
openDevTools() openDevTools()
} }
} }
@ -102,7 +105,8 @@ function setTray () {
if (nativeTheme.shouldUseDarkColors) { if (nativeTheme.shouldUseDarkColors) {
console.log('i am dark.') console.log('i am dark.')
tray.setImage(iconWhitePath) tray.setImage(iconWhitePath)
} else { }
else {
console.log('i am light.') console.log('i am light.')
tray.setImage(iconBlackPath) tray.setImage(iconBlackPath)
// tray.setPressedImage(iconWhitePath) // tray.setPressedImage(iconWhitePath)
@ -200,7 +204,8 @@ function createWindow (startHideWindow) {
if (!process.env.IS_TEST) { if (!process.env.IS_TEST) {
setTimeout(openDevTools, 2000) setTimeout(openDevTools, 2000)
} }
} else { }
else {
createProtocol('app') createProtocol('app')
// Load the index.html when not in development // Load the index.html when not in development
win.loadURL('app://./index.html') win.loadURL('app://./index.html')
@ -219,7 +224,8 @@ function createWindow (startHideWindow) {
ipcMain.on('close', async (event, message) => { ipcMain.on('close', async (event, message) => {
if (message.value === 1) { if (message.value === 1) {
quit() quit()
} else { }
else {
hideWin() hideWin()
} }
}) })
@ -239,10 +245,12 @@ function createWindow (startHideWindow) {
if (closeStrategy === 0) { if (closeStrategy === 0) {
// 弹窗提示,选择关闭策略 // 弹窗提示,选择关闭策略
win.webContents.send('close.showTip', closeStrategy) win.webContents.send('close.showTip', closeStrategy)
} else if (closeStrategy === 1) { }
else if (closeStrategy === 1) {
// 直接退出 // 直接退出
quit() quit()
} else if (closeStrategy === 2) { }
else if (closeStrategy === 2) {
// 隐藏窗口 // 隐藏窗口
hideWin() hideWin()
} }
@ -320,7 +328,8 @@ function registerShowHideShortcut (showHideShortcut) {
if (winIsHidden) { if (winIsHidden) {
showWin() showWin()
} }
} else { }
else {
// linux快捷键不关闭窗口 // linux快捷键不关闭窗口
if (!isLinux()) { if (!isLinux()) {
hideWin() hideWin()
@ -330,10 +339,12 @@ function registerShowHideShortcut (showHideShortcut) {
if (registerSuccess) { if (registerSuccess) {
log.info('注册快捷键成功:', DevSidecar.api.config.get().app.showHideShortcut) log.info('注册快捷键成功:', DevSidecar.api.config.get().app.showHideShortcut)
} else { }
else {
log.error('注册快捷键失败:', DevSidecar.api.config.get().app.showHideShortcut) log.error('注册快捷键失败:', DevSidecar.api.config.get().app.showHideShortcut)
} }
} catch (e) { }
catch (e) {
log.error('注册快捷键异常:', DevSidecar.api.config.get().app.showHideShortcut, ', error:', e) log.error('注册快捷键异常:', DevSidecar.api.config.get().app.showHideShortcut, ', error:', e)
} }
} }
@ -359,7 +370,8 @@ app.disableHardwareAcceleration() // 禁用gpu
let startHideWindow = !DevSidecar.api.config.get().app.startShowWindow let startHideWindow = !DevSidecar.api.config.get().app.startShowWindow
if (app.getLoginItemSettings().wasOpenedAsHidden) { if (app.getLoginItemSettings().wasOpenedAsHidden) {
startHideWindow = true startHideWindow = true
} else if (process.argv) { }
else if (process.argv) {
const args = minimist(process.argv) const args = minimist(process.argv)
log.info('start args:', args) log.info('start args:', args)
@ -367,7 +379,8 @@ if (app.getLoginItemSettings().wasOpenedAsHidden) {
const hideWindowArg = `${args.hideWindow}` const hideWindowArg = `${args.hideWindow}`
if (hideWindowArg === 'true' || hideWindowArg === '1') { if (hideWindowArg === 'true' || hideWindowArg === '1') {
startHideWindow = true startHideWindow = true
} else if (hideWindowArg === 'false' || hideWindowArg === '0') { }
else if (hideWindowArg === 'false' || hideWindowArg === '0') {
startHideWindow = false startHideWindow = false
} }
} }
@ -380,7 +393,8 @@ if (!isFirstInstance) {
setTimeout(() => { setTimeout(() => {
app.quit() app.quit()
}, 1000) }, 1000)
} else { }
else {
app.on('before-quit', async () => { app.on('before-quit', async () => {
log.info('before-quit') log.info('before-quit')
if (process.platform === 'darwin') { if (process.platform === 'darwin') {
@ -414,7 +428,8 @@ if (!isFirstInstance) {
// dock icon is clicked and there are no other windows open. // dock icon is clicked and there are no other windows open.
if (win == null) { if (win == null) {
createWindow(false) createWindow(false)
} else { }
else {
showWin() showWin()
} }
}) })
@ -437,14 +452,16 @@ if (!isFirstInstance) {
createWindow(startHideWindow) createWindow(startHideWindow)
const context = { win, app, beforeQuit, quit, ipcMain, dialog, log, api: DevSidecar.api, changeAppConfig } const context = { win, app, beforeQuit, quit, ipcMain, dialog, log, api: DevSidecar.api, changeAppConfig }
backend.install(context) // 模块安装 backend.install(context) // 模块安装
} catch (err) { }
catch (err) {
log.info('error:', err) log.info('error:', err)
} }
try { try {
// 最小化到托盘 // 最小化到托盘
tray = setTray() tray = setTray()
} catch (err) { }
catch (err) {
log.info('error:', err) log.info('error:', err)
} }
@ -472,7 +489,8 @@ if (isDevelopment) {
quit() quit()
} }
}) })
} else { }
else {
process.on('SIGINT', () => { process.on('SIGINT', () => {
quit() quit()
}) })

View File

@ -34,7 +34,8 @@ class PowerMonitor {
releaseShutdownBlock() releaseShutdownBlock()
this._shutdownCallback = null this._shutdownCallback = null
} }
} else { }
else {
return _powerMonitor.removeAllListeners(event) return _powerMonitor.removeAllListeners(event)
} }
} }
@ -50,7 +51,8 @@ class PowerMonitor {
acquireShutdownBlock('正在停止 DevSidecar 代理') acquireShutdownBlock('正在停止 DevSidecar 代理')
} }
this._listeners.push(listener) this._listeners.push(listener)
} else { }
else {
return _powerMonitor.on(event, listener) return _powerMonitor.on(event, listener)
} }
} }
@ -58,7 +60,8 @@ class PowerMonitor {
off (event, listener) { off (event, listener) {
if (event === 'shutdown' && process.platform === 'win32') { if (event === 'shutdown' && process.platform === 'win32') {
this._listeners = this._listeners.filter(fn => fn !== listener) this._listeners = this._listeners.filter(fn => fn !== listener)
} else { }
else {
return _powerMonitor.off(event, listener) return _powerMonitor.off(event, listener)
} }
} }
@ -66,7 +69,8 @@ class PowerMonitor {
once (event, listener) { once (event, listener) {
if (event === 'shutdown' && process.platform === 'win32') { if (event === 'shutdown' && process.platform === 'win32') {
return this.on(event, listener) return this.on(event, listener)
} else { }
else {
return _powerMonitor.once(event, listener) return _powerMonitor.once(event, listener)
} }
} }

View File

@ -4,8 +4,8 @@ import DevSidecar from '@docmirror/dev-sidecar'
import { ipcMain } from 'electron' import { ipcMain } from 'electron'
import lodash from 'lodash' import lodash from 'lodash'
const pk = require('../../../package.json')
const jsonApi = require('@docmirror/mitmproxy/src/json') const jsonApi = require('@docmirror/mitmproxy/src/json')
const pk = require('../../../package.json')
const log = require('../../utils/util.log') const log = require('../../utils/util.log')
const mitmproxyPath = path.join(__dirname, 'mitmproxy.js') const mitmproxyPath = path.join(__dirname, 'mitmproxy.js')
@ -66,7 +66,8 @@ const localApi = {
try { try {
setting = jsonApi.parse(file.toString()) setting = jsonApi.parse(file.toString())
log.info('读取 setting.json 成功:', settingPath) log.info('读取 setting.json 成功:', settingPath)
} catch (e) { }
catch (e) {
log.error('读取 setting.json 失败:', settingPath, ', error:', e) log.error('读取 setting.json 失败:', settingPath, ', error:', e)
} }
if (setting == null) { if (setting == null) {
@ -130,7 +131,8 @@ function _deepFindFunction (list, parent, parentKey) {
const item = parent[key] const item = parent[key]
if (item instanceof Function) { if (item instanceof Function) {
list.push(parentKey + key) list.push(parentKey + key)
} else if (item instanceof Object) { }
else if (item instanceof Object) {
_deepFindFunction(list, item, `${parentKey + key}.`) _deepFindFunction(list, item, `${parentKey + key}.`)
} }
} }
@ -140,7 +142,8 @@ function _getSettingsPath () {
const dir = getDefaultConfigBasePath() const dir = getDefaultConfigBasePath()
if (!fs.existsSync(dir)) { if (!fs.existsSync(dir)) {
fs.mkdirSync(dir) fs.mkdirSync(dir)
} else { }
else {
// 兼容1.7.3及以下版本的配置文件处理逻辑 // 兼容1.7.3及以下版本的配置文件处理逻辑
const newFilePath = path.join(dir, '/setting.json') const newFilePath = path.join(dir, '/setting.json')
const oldFilePath = path.join(dir, '/setting.json5') const oldFilePath = path.join(dir, '/setting.json5')

View File

@ -19,7 +19,8 @@ Comment=
EOF EOF
` `
await DevSidecar.api.shell.exec(cmd) await DevSidecar.api.shell.exec(cmd)
} else { }
else {
const removeStart = 'sudo rm ~/.config/autostart/dev-sidecar.desktop -rf' const removeStart = 'sudo rm ~/.config/autostart/dev-sidecar.desktop -rf'
await DevSidecar.api.shell.exec(removeStart) await DevSidecar.api.shell.exec(removeStart)
} }
@ -39,7 +40,8 @@ export default {
if (message.value) { if (message.value) {
if (isLinux) { if (isLinux) {
await setAutoStartForLinux(app, true) await setAutoStartForLinux(app, true)
} else { }
else {
app.setLoginItemSettings({ app.setLoginItemSettings({
openAtLogin: true, openAtLogin: true,
openAsHidden: true, openAsHidden: true,
@ -51,10 +53,12 @@ export default {
} }
event.sender.send('auto-start', { key: 'enabled', value: true }) event.sender.send('auto-start', { key: 'enabled', value: true })
} else { }
else {
if (isLinux) { if (isLinux) {
await setAutoStartForLinux(app, false) await setAutoStartForLinux(app, false)
} else { }
else {
app.setLoginItemSettings({ app.setLoginItemSettings({
openAtLogin: false, openAtLogin: false,
openAsHidden: false, openAsHidden: false,

View File

@ -2,7 +2,8 @@ function install (app, api) {
api.ipc.on('auto-start', (event, message) => { api.ipc.on('auto-start', (event, message) => {
if (message.value === true) { if (message.value === true) {
app.$message.info('已添加开机自启') app.$message.info('已添加开机自启')
} else { }
else {
app.$message.info('已取消开机自启') app.$message.info('已取消开机自启')
} }
}) })

View File

@ -29,7 +29,8 @@ function handleServerStartError (message, err, app, api) {
console.log('Cancel') console.log('Cancel')
}, },
}) })
} else { }
else {
app.$message.error(`加速服务启动失败:${message.message}`) app.$message.error(`加速服务启动失败:${message.message}`)
} }
} }

View File

@ -9,7 +9,8 @@ export default {
}).then((result) => { }).then((result) => {
if (result.canceled) { if (result.canceled) {
event.sender.send('file-selector', { key: 'canceled' }) event.sender.send('file-selector', { key: 'canceled' })
} else { }
else {
event.sender.send('file-selector', { key: 'selected', value: result.filePaths }) event.sender.send('file-selector', { key: 'selected', value: result.filePaths })
} }
}).catch((err) => { }).catch((err) => {

View File

@ -7,7 +7,8 @@ function install (app, api) {
console.log('selector', message) console.log('selector', message)
if (message.key === 'selected') { if (message.key === 'selected') {
resolve(message.value) resolve(message.value)
} else { }
else {
reject(new Error('没有选择文件')) reject(new Error('没有选择文件'))
} }
api.ipc.on('file-selector', () => {}) api.ipc.on('file-selector', () => {})

View File

@ -1,5 +1,5 @@
const fs = require('fs') const fs = require('node:fs')
const path = require('path') const path = require('node:path')
const server = require('@docmirror/mitmproxy') const server = require('@docmirror/mitmproxy')
const jsonApi = require('@docmirror/mitmproxy/src/json') const jsonApi = require('@docmirror/mitmproxy/src/json')
const log = require('../utils/util.log') const log = require('../utils/util.log')

View File

@ -1,5 +1,5 @@
import fs from 'fs' import fs from 'node:fs'
import path from 'path' import path from 'node:path'
import DevSidecar from '@docmirror/dev-sidecar' import DevSidecar from '@docmirror/dev-sidecar'
import AdmZip from 'adm-zip' import AdmZip from 'adm-zip'
import { ipcMain } from 'electron' import { ipcMain } from 'electron'
@ -85,14 +85,16 @@ function isNewVersion (version, curVersion) {
if (versionObj.suffix > curVersionObj.suffix) { if (versionObj.suffix > curVersionObj.suffix) {
return 41 return 41
} }
} else if (!versionObj.suffix && curVersionObj.suffix) { }
else if (!versionObj.suffix && curVersionObj.suffix) {
// 线上版本号没有后缀版本号,说明为正式版本,为更新版本 // 线上版本号没有后缀版本号,说明为正式版本,为更新版本
return 42 return 42
} }
} }
} }
} }
} catch (e) { }
catch (e) {
log.error(`比对版本失败,当前版本号:${curVersion},比对版本号:${version}, error:`, e) log.error(`比对版本失败,当前版本号:${curVersion},比对版本号:${version}, error:`, e)
return -99 return -99
} }
@ -125,9 +127,11 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
// }) // })
if (isMac) { if (isMac) {
autoUpdater.updateConfigPath = path.join(__dirname, 'mac/dev-sidecar.app/Contents/Resources/app-update.yml') autoUpdater.updateConfigPath = path.join(__dirname, 'mac/dev-sidecar.app/Contents/Resources/app-update.yml')
} else if (isLinux) { }
else if (isLinux) {
autoUpdater.updateConfigPath = path.join(__dirname, 'linux-unpacked/resources/app-update.yml') autoUpdater.updateConfigPath = path.join(__dirname, 'linux-unpacked/resources/app-update.yml')
} else { }
else {
autoUpdater.updateConfigPath = path.join(__dirname, 'win-unpacked/resources/app-update.yml') autoUpdater.updateConfigPath = path.join(__dirname, 'win-unpacked/resources/app-update.yml')
} }
} }
@ -159,7 +163,8 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
let data let data
try { try {
data = JSON.parse(body) data = JSON.parse(body)
} catch (e) { }
catch (e) {
log.error('检查更新失败github API返回数据格式不正确:', body) log.error('检查更新失败github API返回数据格式不正确:', body)
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: '检查更新失败github API返回数据格式不正确' }) win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: '检查更新失败github API返回数据格式不正确' })
return return
@ -206,7 +211,8 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
: '无', : '无',
}, },
}) })
} else { }
else {
log.info(`检查更新:没有新版本,最近发布的版本号为 '${version}',而当前版本号为 '${curVersion}'`) log.info(`检查更新:没有新版本,最近发布的版本号为 '${version}',而当前版本号为 '${curVersion}'`)
win.webContents.send('update', { key: 'notAvailable' }) win.webContents.send('update', { key: 'notAvailable' })
} }
@ -216,25 +222,29 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
log.info('检查更新-没有正式版本数据') log.info('检查更新-没有正式版本数据')
win.webContents.send('update', { key: 'notAvailable' }) win.webContents.send('update', { key: 'notAvailable' })
} else { }
else {
log.error('检查更新失败, status:', response.statusCode, ', body:', body) log.error('检查更新失败, status:', response.statusCode, ', body:', body)
let bodyObj let bodyObj
try { try {
bodyObj = JSON.parse(body) bodyObj = JSON.parse(body)
} catch (e) { }
catch (e) {
bodyObj = null bodyObj = null
} }
let message let message
if (response) { if (response) {
message = `检查更新失败: ${bodyObj && bodyObj.message ? bodyObj.message : response.message}, code: ${response.statusCode}` message = `检查更新失败: ${bodyObj && bodyObj.message ? bodyObj.message : response.message}, code: ${response.statusCode}`
} else { }
else {
message = `检查更新失败: ${bodyObj && bodyObj.message ? bodyObj.message : body}` message = `检查更新失败: ${bodyObj && bodyObj.message ? bodyObj.message : body}`
} }
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: message }) win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: message })
} }
} catch (e) { }
catch (e) {
log.error('检查更新失败:', e) log.error('检查更新失败:', e)
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: `检查更新失败:${e.message}` }) win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: `检查更新失败:${e.message}` })
} }
@ -248,7 +258,8 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
log.info('download dir:', fileDir) log.info('download dir:', fileDir)
try { try {
fs.accessSync(fileDir, fs.constants.F_OK) fs.accessSync(fileDir, fs.constants.F_OK)
} catch (e) { }
catch (e) {
fs.mkdirSync(fileDir) fs.mkdirSync(fileDir)
} }
const filePath = path.join(fileDir, `${value.version}.zip`) const filePath = path.join(fileDir, `${value.version}.zip`)
@ -288,7 +299,8 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
const zip = new AdmZip(partPackagePath) const zip = new AdmZip(partPackagePath)
zip.extractAllTo(target, true) zip.extractAllTo(target, true)
log.info('安装完成重启app') log.info('安装完成重启app')
} finally { }
finally {
app.exit(0) app.exit(0)
} }
} }
@ -339,18 +351,21 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
}, 1000) }, 1000)
} }
}) })
} else if (arg.key === 'checkForUpdate') { }
else if (arg.key === 'checkForUpdate') {
// 执行自动更新检查 // 执行自动更新检查
log.info('autoUpdater checkForUpdates:', arg.fromUser) log.info('autoUpdater checkForUpdates:', arg.fromUser)
// 调用 github API获取release数据来检查更新 // 调用 github API获取release数据来检查更新
// autoUpdater.checkForUpdates() // autoUpdater.checkForUpdates()
checkForUpdatesFromGitHub() checkForUpdatesFromGitHub()
} else if (arg.key === 'downloadUpdate') { }
else if (arg.key === 'downloadUpdate') {
// 下载新版本 // 下载新版本
log.info('autoUpdater downloadUpdate') log.info('autoUpdater downloadUpdate')
autoUpdater.downloadUpdate() autoUpdater.downloadUpdate()
} else if (arg.key === 'downloadPart') { }
else if (arg.key === 'downloadPart') {
// 下载增量更新版本 // 下载增量更新版本
log.info('autoUpdater downloadPart') log.info('autoUpdater downloadPart')
downloadPart(app, arg.value) downloadPart(app, arg.value)

View File

@ -31,23 +31,28 @@ function install (app, api) {
updateParams.checking = false updateParams.checking = false
updateParams.newVersionData = message.value updateParams.newVersionData = message.value
foundNewVersion(message.value) foundNewVersion(message.value)
} else if (type === 'notAvailable') { }
else if (type === 'notAvailable') {
updateParams.checking = false updateParams.checking = false
noNewVersion() noNewVersion()
} else if (type === 'downloaded') { }
else if (type === 'downloaded') {
// 更新包已下载完成,让用户确认是否更新 // 更新包已下载完成,让用户确认是否更新
updateParams.downloading = false updateParams.downloading = false
console.log('updateParams', updateParams) console.log('updateParams', updateParams)
newUpdateIsReady(message.value) newUpdateIsReady(message.value)
} else if (type === 'progress') { }
else if (type === 'progress') {
progressUpdate(message.value) progressUpdate(message.value)
} else if (type === 'error') { }
else if (type === 'error') {
updateParams.checking = false updateParams.checking = false
updateParams.downloading = false updateParams.downloading = false
if (message.action === 'checkForUpdate' && updateParams.newVersionData) { if (message.action === 'checkForUpdate' && updateParams.newVersionData) {
// 如果检查更新报错了,但刚才成功拿到过一次数据,就拿之前的数据 // 如果检查更新报错了,但刚才成功拿到过一次数据,就拿之前的数据
foundNewVersion(updateParams.newVersionData) foundNewVersion(updateParams.newVersionData)
} else { }
else {
if (updateParams.fromUser === false && message.action === 'checkForUpdate') { if (updateParams.fromUser === false && message.action === 'checkForUpdate') {
return // 不是手动检查更新,不提示错误信息,避免打扰 return // 不是手动检查更新,不提示错误信息,避免打扰
} }
@ -83,7 +88,12 @@ function install (app, api) {
content: (h) => { content: (h) => {
return ( return (
<div> <div>
<div>请前往 <a onClick={openGithubUrl}>github项目release页面</a> </div> <div>
请前往
<a onClick={openGithubUrl}>github项目release页面</a>
{' '}
下载新版本手动安装
</div>
<div><a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div> <div><a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div>
</div> </div>
) )
@ -154,20 +164,27 @@ function install (app, api) {
const releaseNotes = value.releaseNotes.replace(/\r\n/g, '\n') const releaseNotes = value.releaseNotes.replace(/\r\n/g, '\n')
return ( return (
<div> <div>
<div>发布公告<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div> <div>
发布公告
<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a>
</div>
<hr /> <hr />
<pre style="max-height:350px;font-family:auto"> <pre style="max-height:350px;font-family:auto">
{releaseNotes} {releaseNotes}
</pre> </pre>
</div> </div>
) )
} else { }
else {
for (const note of value.releaseNotes) { for (const note of value.releaseNotes) {
notes.push(<li>{note}</li>) notes.push(<li>{note}</li>)
} }
return ( return (
<div> <div>
<div>发布公告<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div> <div>
发布公告
<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a>
</div>
<div>更新内容</div> <div>更新内容</div>
<ol>{notes}</ol> <ol>{notes}</ol>
</div> </div>
@ -200,20 +217,27 @@ function install (app, api) {
const releaseNotes = value.releaseNotes.replace(/\r\n/g, '\n') const releaseNotes = value.releaseNotes.replace(/\r\n/g, '\n')
return ( return (
<div> <div>
<div>发布公告<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div> <div>
发布公告
<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a>
</div>
<hr /> <hr />
<pre style="max-height:350px;font-family:auto"> <pre style="max-height:350px;font-family:auto">
{releaseNotes} {releaseNotes}
</pre> </pre>
</div> </div>
) )
} else { }
else {
for (const note of value.releaseNotes) { for (const note of value.releaseNotes) {
notes.push(<li>{note}</li>) notes.push(<li>{note}</li>)
} }
return ( return (
<div> <div>
<div>发布公告<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div> <div>
发布公告
<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a>
</div>
<div>更新内容</div> <div>更新内容</div>
<ol>{notes}</ol> <ol>{notes}</ol>
</div> </div>

View File

@ -1,5 +1,5 @@
import os from 'os' import os from 'node:os'
import path from 'path' import path from 'node:path'
function getSystemPlatform () { function getSystemPlatform () {
switch (os.platform()) { switch (os.platform()) {

View File

@ -88,17 +88,17 @@ export default {
</template> </template>
<style lang="scss"> <style lang="scss">
body{ body {
height: 100%; height: 100%;
} }
.mt10{ .mt10 {
margin-top:10px; margin-top: 10px;
} }
.mt5{ .mt5 {
margin-top:5px; margin-top: 5px;
} }
.mt20{ .mt20 {
margin-top:20px; margin-top: 20px;
} }
.ds_layout { .ds_layout {
font-family: Avenir, Helvetica, Arial, sans-serif; font-family: Avenir, Helvetica, Arial, sans-serif;
@ -106,31 +106,33 @@ body{
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
color: #2c3e50; color: #2c3e50;
height: 100%; height: 100%;
.ant-layout-has-sider{ .ant-layout-has-sider {
border:1px solid #eee; border: 1px solid #eee;
} }
.ant-layout-sider-children{ .ant-layout-sider-children {
border-right:1px solid #eee; border-right: 1px solid #eee;
} }
.ant-layout{ .ant-layout {
height:100% height: 100%;
} }
.logo{ .logo {
padding:5px; padding: 5px;
border-bottom: #eee solid 1px; border-bottom: #eee solid 1px;
height:60px; height: 60px;
background-image: url("../../public/logo/logo-lang.svg"); background-image: url('../../public/logo/logo-lang.svg');
background-size: auto 50px; background-size: auto 50px;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: 5px center; background-position: 5px center;
} }
.ant-layout-footer{ .ant-layout-footer {
padding:10px; padding: 10px;
text-align: center; text-align: center;
border-top:#d6d4d4 solid 1px; border-top: #d6d4d4 solid 1px;
} }
.ant-menu-inline, .ant-menu-vertical, .ant-menu-vertical-left{ .ant-menu-inline,
border:0; .ant-menu-vertical,
.ant-menu-vertical-left {
border: 0;
} }
} }
</style> </style>

View File

@ -7,21 +7,27 @@ export default {
<template> <template>
<div class="ds-container"> <div class="ds-container">
<div class="body-wrapper"> <div class="body-wrapper">
<div v-if="$slots.header" class="container-header"><slot name="header" /></div> <div v-if="$slots.header" class="container-header">
<div class="container-body"><slot /></div> <slot name="header" />
<div class="container-footer"><slot name="footer" /></div> </div>
<div class="container-body">
<slot />
</div>
<div class="container-footer">
<slot name="footer" />
</div>
</div> </div>
</div> </div>
</template> </template>
<style lang="scss"> <style lang="scss">
.ds-container{ .ds-container {
height:100%; height: 100%;
background: #fff; background: #fff;
display: flex; display: flex;
position: relative; position: relative;
.body-wrapper{ .body-wrapper {
position: absolute; position: absolute;
top: 0px; top: 0px;
right: 0px; right: 0px;
@ -32,21 +38,21 @@ export default {
overflow: hidden; overflow: hidden;
} }
.container-header{ .container-header {
padding:15px; padding: 15px;
border-bottom: 1px solid #EEE; border-bottom: 1px solid #eee;
background: #FFF; background: #fff;
height:60px; height: 60px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.container-body{ .container-body {
flex: 1; flex: 1;
height: 0; height: 0;
overflow: auto; overflow: auto;
position: relative; position: relative;
padding:15px; padding: 15px;
} }
} }
</style> </style>

View File

@ -22,9 +22,11 @@ export default {
setupImage () { setupImage () {
if (this.systemPlatform === 'mac') { if (this.systemPlatform === 'mac') {
return '/setup-mac.png' return '/setup-mac.png'
} else if (this.systemPlatform === 'linux') { }
else if (this.systemPlatform === 'linux') {
return '/setup-linux.png' return '/setup-linux.png'
} else { }
else {
return '/setup.png' return '/setup.png'
} }
}, },

View File

@ -48,7 +48,8 @@ export default {
await this.applyBefore() await this.applyBefore()
await this.saveConfig() await this.saveConfig()
await this.applyAfter() await this.applyAfter()
} finally { }
finally {
this.applyLoading = false this.applyLoading = false
} }
}, },
@ -73,7 +74,8 @@ export default {
await this.ready(this.config) await this.ready(this.config)
} }
await this.apply() await this.apply()
} finally { }
finally {
this.resetDefaultLoading = false this.resetDefaultLoading = false
} }
}, },
@ -125,7 +127,8 @@ export default {
await this.$api.plugin.git.start() await this.$api.plugin.git.start()
} }
this.$message.success('代理服务和系统代理重启成功') this.$message.success('代理服务和系统代理重启成功')
} else { }
else {
this.$message.info('代理服务和系统代理未启动,无需重启') this.$message.info('代理服务和系统代理未启动,无需重启')
} }
}, },

View File

@ -21,7 +21,8 @@ export default {
doClick: () => { doClick: () => {
if (this.status.server.enabled) { if (this.status.server.enabled) {
this.apiCall(this.startup, this.$api.shutdown) this.apiCall(this.startup, this.$api.shutdown)
} else { }
else {
this.apiCall(this.startup, this.$api.startup) this.apiCall(this.startup, this.$api.startup)
} }
}, },
@ -75,11 +76,13 @@ export default {
this.config.server.intercept.enabled = false this.config.server.intercept.enabled = false
this.config.server.dns.speedTest.enabled = true this.config.server.dns.speedTest.enabled = true
this.config.plugin.overwall.enabled = false this.config.plugin.overwall.enabled = false
} else if (mode === 'default') { }
else if (mode === 'default') {
this.config.server.intercept.enabled = true this.config.server.intercept.enabled = true
this.config.server.dns.speedTest.enabled = true this.config.server.dns.speedTest.enabled = true
this.config.plugin.overwall.enabled = false this.config.plugin.overwall.enabled = false
} else if (mode === 'ow') { }
else if (mode === 'ow') {
console.log('event', event) console.log('event', event)
if (!this.setting.overwall) { if (!this.setting.overwall) {
this.wantOW() this.wantOW()
@ -201,10 +204,12 @@ export default {
const ret = await api(param) const ret = await api(param)
console.log('this status', this.status) console.log('this status', this.status)
return ret return ret
} catch (err) { }
catch (err) {
btn.loading = false // false btn.loading = false // false
console.log('api invoke error:', err) console.log('api invoke error:', err)
} finally { }
finally {
btn.loading = false btn.loading = false
} }
}, },
@ -212,7 +217,8 @@ export default {
onSwitchClick (btn, openApi, closeApi, checked) { onSwitchClick (btn, openApi, closeApi, checked) {
if (checked) { if (checked) {
return this.apiCall(btn, openApi) return this.apiCall(btn, openApi)
} else { }
else {
return this.apiCall(btn, closeApi) return this.apiCall(btn, closeApi)
} }
}, },
@ -386,7 +392,7 @@ export default {
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding:10px; padding: 10px;
.donate { .donate {
cursor: pointer; cursor: pointer;
} }

View File

@ -24,7 +24,8 @@ export default {
if (this.status.plugin.git.enabled) { if (this.status.plugin.git.enabled) {
await this.$api.plugin.git.close() await this.$api.plugin.git.close()
this.needRestart = true this.needRestart = true
} else { }
else {
this.needRestart = false this.needRestart = false
} }
this.submitNoProxyUrls() this.submitNoProxyUrls()
@ -115,8 +116,12 @@ export default {
</div> </div>
<template slot="footer"> <template slot="footer">
<div class="footer-bar"> <div class="footer-bar">
<a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()"></a-button> <a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()">
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()"></a-button> 恢复默认
</a-button>
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()">
应用
</a-button>
</div> </div>
</template> </template>
</ds-container> </ds-container>

View File

@ -136,8 +136,12 @@ export default {
</div> </div>
<template slot="footer"> <template slot="footer">
<div class="footer-bar"> <div class="footer-bar">
<a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()"></a-button> <a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()">
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()"></a-button> 恢复默认
</a-button>
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()">
应用
</a-button>
</div> </div>
</template> </template>
</ds-container> </ds-container>

View File

@ -213,8 +213,12 @@ export default {
</div> </div>
<template slot="footer"> <template slot="footer">
<div class="footer-bar"> <div class="footer-bar">
<a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()"></a-button> <a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()">
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()"></a-button> 恢复默认
</a-button>
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()">
应用
</a-button>
</div> </div>
</template> </template>
</ds-container> </ds-container>

View File

@ -120,8 +120,12 @@ export default {
</div> </div>
<template slot="footer"> <template slot="footer">
<div class="footer-bar"> <div class="footer-bar">
<a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()"></a-button> <a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()">
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()"></a-button> 恢复默认
</a-button>
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()">
应用
</a-button>
</div> </div>
</template> </template>
</ds-container> </ds-container>

View File

@ -31,7 +31,8 @@ export default {
async openEnableLoopback () { async openEnableLoopback () {
try { try {
await this.$api.proxy.setEnableLoopback() await this.$api.proxy.setEnableLoopback()
} catch (e) { }
catch (e) {
if (e.message.includes('EACCES')) { if (e.message.includes('EACCES')) {
this.$message.error('请将DevSidecar关闭后以管理员身份重新打开再尝试此操作') this.$message.error('请将DevSidecar关闭后以管理员身份重新打开再尝试此操作')
return return
@ -113,7 +114,9 @@ export default {
</div> </div>
</a-form-item> </a-form-item>
<a-form-item v-if="isWindows()" label="设置loopback" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item v-if="isWindows()" label="设置loopback" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-button @click="loopbackVisible = true">去设置</a-button> <a-button @click="loopbackVisible = true">
去设置
</a-button>
<div class="form-help"> <div class="form-help">
解决<code>OneNote</code><code>MicrosoftStore</code><code>Outlook</code><code>UWP应用</code>开启代理后无法访问网络的问题 解决<code>OneNote</code><code>MicrosoftStore</code><code>Outlook</code><code>UWP应用</code>开启代理后无法访问网络的问题
</div> </div>
@ -162,8 +165,12 @@ export default {
</div> </div>
<template slot="footer"> <template slot="footer">
<div class="footer-bar"> <div class="footer-bar">
<a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()"></a-button> <a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()">
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()"></a-button> 恢复默认
</a-button>
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()">
应用
</a-button>
</div> </div>
</template> </template>
@ -179,7 +186,9 @@ export default {
> >
<template slot="title"> <template slot="title">
设置Loopback 设置Loopback
<a-button style="float:right;margin-right:10px;" @click="openEnableLoopback()">EnableLoopback</a-button> <a-button style="float:right;margin-right:10px;" @click="openEnableLoopback()">
打开EnableLoopback
</a-button>
</template> </template>
<div> <div>
<div>1此设置用于解决OneNoteMicrosoftStoreOutlook等UWP应用无法访问网络的问题</div> <div>1此设置用于解决OneNoteMicrosoftStoreOutlook等UWP应用无法访问网络的问题</div>

View File

@ -407,8 +407,12 @@ export default {
<a-divider /> <a-divider />
<a-row :gutter="10" class="mt10"> <a-row :gutter="10" class="mt10">
<a-col span="24"> <a-col span="24">
<a-button type="primary" icon="plus" @click="reSpeedTest()"></a-button> <a-button type="primary" icon="plus" @click="reSpeedTest()">
<a-button class="md-ml-10" type="primary" icon="reload" @click="reloadAllSpeedTester()"></a-button> 立即重新测速
</a-button>
<a-button class="md-ml-10" type="primary" icon="reload" @click="reloadAllSpeedTester()">
刷新
</a-button>
</a-col> </a-col>
</a-row> </a-row>
@ -434,8 +438,12 @@ export default {
</div> </div>
<template slot="footer"> <template slot="footer">
<div class="footer-bar"> <div class="footer-bar">
<a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()"></a-button> <a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()">
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()"></a-button> 恢复默认
</a-button>
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()">
应用
</a-button>
</div> </div>
</template> </template>
</ds-container> </ds-container>
@ -454,7 +462,7 @@ export default {
} }
.jsoneditor-vue { .jsoneditor-vue {
height: 100% height: 100%;
} }
.ant-tabs { .ant-tabs {

View File

@ -218,10 +218,12 @@ export default {
await this.$api.config.downloadRemoteConfig() await this.$api.config.downloadRemoteConfig()
this.$message.info('下载远程配置成功,开始重启代理服务和系统代理') this.$message.info('下载远程配置成功,开始重启代理服务和系统代理')
await this.reloadConfigAndRestart() await this.reloadConfigAndRestart()
} finally { }
finally {
this.reloadLoading = false this.reloadLoading = false
} }
} else { }
else {
this.$message.info('远程配置已关闭,开始重启代理服务和系统代理') this.$message.info('远程配置已关闭,开始重启代理服务和系统代理')
await this.reloadConfigAndRestart() await this.reloadConfigAndRestart()
} }
@ -244,11 +246,13 @@ export default {
if (remoteConfig.old1 === remoteConfig.new1 && remoteConfig.old2 === remoteConfig.new2) { if (remoteConfig.old1 === remoteConfig.new1 && remoteConfig.old2 === remoteConfig.new2) {
this.$message.info('远程配置没有变化,不做任何处理。') this.$message.info('远程配置没有变化,不做任何处理。')
this.$message.warn('如果您确实修改了远程配置,请稍等片刻再重试!') this.$message.warn('如果您确实修改了远程配置,请稍等片刻再重试!')
} else { }
else {
this.$message.success('获取到了最新的远程配置,开始重启代理服务和系统代理') this.$message.success('获取到了最新的远程配置,开始重启代理服务和系统代理')
await this.reloadConfigAndRestart() await this.reloadConfigAndRestart()
} }
} finally { }
finally {
this.reloadLoading = false this.reloadLoading = false
} }
}, },
@ -256,7 +260,7 @@ export default {
this.$confirm({ this.$confirm({
title: '确定要恢复出厂设置吗?', title: '确定要恢复出厂设置吗?',
width: 610, width: 610,
content: (h) => ( content: h => (
<div class="restore-factory-settings"> <div class="restore-factory-settings">
<hr /> <hr />
<p> <p>
@ -276,7 +280,9 @@ export default {
1. 找到备份文件路径 1. 找到备份文件路径
<span>~/.dev-sidecar/config.json..bak.json</span> <span>~/.dev-sidecar/config.json..bak.json</span>
<br /> <br />
2. 将该备份文件重命名为<span>config.json</span>再重启软件即可恢复个性化配置 2. 将该备份文件重命名为
<span>config.json</span>
再重启软件即可恢复个性化配置
</div> </div>
</p> </p>
</div> </div>
@ -291,10 +297,12 @@ export default {
this.config = await this.$api.config.get() this.config = await this.$api.config.get()
this.$message.success('恢复出厂设置成功,开始重启代理服务和系统代理') this.$message.success('恢复出厂设置成功,开始重启代理服务和系统代理')
await this.reloadConfigAndRestart() await this.reloadConfigAndRestart()
} else { }
else {
this.$message.info('已是出厂设置,无需恢复') this.$message.info('已是出厂设置,无需恢复')
} }
} finally { }
finally {
this.removeUserConfigLoading = false this.removeUserConfigLoading = false
} }
}, },
@ -316,7 +324,9 @@ export default {
<a-checkbox v-model="config.app.autoStart.enabled" @change="onAutoStartChange"> <a-checkbox v-model="config.app.autoStart.enabled" @change="onAutoStartChange">
本应用开机自启 本应用开机自启
</a-checkbox> </a-checkbox>
<a-button class="md-mr-10" icon="profile" @click="openLog()"></a-button> <a-button class="md-mr-10" icon="profile" @click="openLog()">
日志
</a-button>
<div class="form-help"> <div class="form-help">
windows下建议开启开机自启<a @click="openExternal('https://github.com/docmirror/dev-sidecar/blob/master/doc/recover.md')"></a> windows下建议开启开机自启<a @click="openExternal('https://github.com/docmirror/dev-sidecar/blob/master/doc/recover.md')"></a>
</div> </div>

View File

@ -1,62 +1,93 @@
.footer-bar{ .footer-bar {
padding:10px; padding: 10px;
text-align: right; text-align: right;
border-top:#eee 1px solid; border-top: #eee 1px solid;
} }
.flex-l-r{ .flex-l-r {
align-content: center; align-content: center;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;
&>a{ & > a {
align-content: center; align-content: center;
display: flex; display: flex;
align-items: center; align-items: center;
} }
} }
.md-mr-5{margin-right: 5px;} .md-mr-5 {
.md-mr-10{margin-right: 10px;} margin-right: 5px;
.md-mr-15{margin-right: 15px;} }
.md-mr-20{margin-right: 20px;} .md-mr-10 {
margin-right: 10px;
}
.md-mr-15 {
margin-right: 15px;
}
.md-mr-20 {
margin-right: 20px;
}
.md-mt-5{margin-top: 5px;} .md-mt-5 {
.md-mt-10{margin-top: 10px;} margin-top: 5px;
.md-mt-15{margin-top: 15px;} }
.md-mt-20{margin-top: 20px;} .md-mt-10 {
margin-top: 10px;
}
.md-mt-15 {
margin-top: 15px;
}
.md-mt-20 {
margin-top: 20px;
}
.md-ml-5 {
margin-left: 5px;
}
.md-ml-10 {
margin-left: 10px;
}
.md-ml-15 {
margin-left: 15px;
}
.md-ml-20 {
margin-left: 20px;
}
.md-ml-5{margin-left: 5px;} .md-mb-5 {
.md-ml-10{margin-left: 10px;} margin-bottom: 5px;
.md-ml-15{margin-left: 15px;} }
.md-ml-20{margin-left: 20px;} .md-mb-10 {
margin-bottom: 10px;
}
.md-mb-15 {
margin-bottom: 15px;
}
.md-mb-20 {
margin-bottom: 20px;
}
.md-mb-5{margin-bottom: 5px;} ol {
.md-mb-10{margin-bottom: 10px;}
.md-mb-15{margin-bottom: 15px;}
.md-mb-20{margin-bottom: 20px;}
ol{
margin-block-start: 0em; margin-block-start: 0em;
margin-block-end: 0em; margin-block-end: 0em;
padding-inline-start: 20px; padding-inline-start: 20px;
} }
.form-help{ .form-help {
font-size:12px; font-size: 12px;
line-height: 15px; line-height: 15px;
color: #a1a1a1; color: #a1a1a1;
i{ i {
font-family: "Microsoft YaHei", serif; font-family: 'Microsoft YaHei', serif;
font-style: normal; font-style: normal;
font-weight: bold; font-weight: bold;
} }
code { code {
padding: 0 .4em; padding: 0 0.4em;
} }
} }
@ -66,13 +97,13 @@ code {
border-radius: 6px; border-radius: 6px;
color: #888; color: #888;
background-color: #f1f1f1; background-color: #f1f1f1;
margin-left: .2em; margin-left: 0.2em;
margin-right: .2em; margin-right: 0.2em;
padding: .2em .4em; padding: 0.2em 0.4em;
white-space: break-spaces; white-space: break-spaces;
} }
.ace_search_form .ace_searchbtn{ .ace_search_form .ace_searchbtn {
width: auto; width: auto;
min-width: 27px; min-width: 27px;
} }

View File

@ -1,24 +1,28 @@
/* 暗色主题 */ /* 暗色主题 */
$dark-logo: url("../../../../public/logo/logo-lang-light.svg"); $dark-logo: url('../../../../public/logo/logo-lang-light.svg');
$dark-bg: #1e1f22; // $dark-bg: #1e1f22; //
$dark-bg-highlight: #333; // $dark-bg-highlight: #333; //
$dark-text: #ddd; // $dark-text: #ddd; //
$dark-bd: #333; //线 $dark-bd: #333; //线
$dark-btn: #444; // $dark-btn: #444; //
$dark-input: #777; // $dark-input: #777; //
.theme-dark{ .theme-dark {
hr { hr {
border-color: $dark-bd; border-color: $dark-bd;
} }
/* 背景色和字体颜色 */ /* 背景色和字体颜色 */
.ds_layout, .ant-layout, .ds_layout,
.ds-container, .ds-container .container-header, .ant-layout,
.ant-layout-footer{ .ds-container,
.ds-container .container-header,
.ant-layout-footer {
background: $dark-bg; background: $dark-bg;
color: $dark-text; color: $dark-text;
} }
div, span, label { div,
span,
label {
color: $dark-text; color: $dark-text;
} }
.form-help { .form-help {
@ -31,7 +35,7 @@ $dark-input: #777; //输入框:背景色
/* 高亮块:背景色和字体颜色 */ /* 高亮块:背景色和字体颜色 */
/* 警告类型 */ /* 警告类型 */
.ant-alert-warning{ .ant-alert-warning {
background: $dark-bg-highlight; background: $dark-bg-highlight;
border-color: $dark-bg-highlight; border-color: $dark-bg-highlight;
color: $dark-text; color: $dark-text;
@ -41,7 +45,7 @@ $dark-input: #777; //输入框:背景色
} }
} }
/* 消息类型 */ /* 消息类型 */
.ant-alert-info{ .ant-alert-info {
background: $dark-bg-highlight; background: $dark-bg-highlight;
border-color: $dark-bg-highlight; border-color: $dark-bg-highlight;
color: $dark-text; color: $dark-text;
@ -55,7 +59,7 @@ $dark-input: #777; //输入框:背景色
.footer-bar, .footer-bar,
.ant-layout-footer, .ant-layout-footer,
.ant-tabs .ant-tabs-left-bar, .ant-tabs .ant-tabs-left-bar,
.ant-tabs .ant-tabs-left-content{ .ant-tabs .ant-tabs-left-content {
border-color: $dark-bd; border-color: $dark-bd;
} }
.ant-radio-button-wrapper:not(:first-child)::before { .ant-radio-button-wrapper:not(:first-child)::before {
@ -67,138 +71,146 @@ $dark-input: #777; //输入框:背景色
/* 左侧 */ /* 左侧 */
/** 背景色 **/ /** 背景色 **/
.ant-layout-sider{ .ant-layout-sider {
background: $dark-bg; background: $dark-bg;
} }
/** Logo **/ /** Logo **/
.logo{ .logo {
background-image: $dark-logo; /* logo使用亮色的 */ background-image: $dark-logo; /* logo使用亮色的 */
} }
/** 菜单 **/ /** 菜单 **/
.ant-menu{ .ant-menu {
background: $dark-bg; background: $dark-bg;
color: $dark-text; color: $dark-text;
} }
/* 菜单选中时,或鼠标移到菜单上时的样式 */ /* 菜单选中时,或鼠标移到菜单上时的样式 */
.ant-menu-item:hover, .ant-menu-item:hover,
.ant-menu-submenu .ant-menu-submenu-title:hover, .ant-menu-submenu .ant-menu-submenu-title:hover,
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected{ .ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
background: $dark-bg-highlight; background: $dark-bg-highlight;
color: #1890ff; color: #1890ff;
span{ color: #1890ff; } span {
color: #1890ff;
}
} }
/* 输入框、下拉框 */ /* 输入框、下拉框 */
.ant-input, .ant-input,
.ant-input-number-input, .ant-input-number, .ant-input-number-input,
.ant-input-number,
.ant-select-selection, .ant-select-selection,
.ant-input-group-addon{ .ant-input-group-addon {
background: $dark-input; background: $dark-input;
border-color: #aaa; border-color: #aaa;
color: $dark-text; color: $dark-text;
&:hover, &:focus{ &:hover,
&:focus {
border-color: #fff; border-color: #fff;
} }
} }
/* 卡片消息IP测速 */ /* 卡片消息IP测速 */
.ant-card{ .ant-card {
background: $dark-input; background: $dark-input;
border-color: $dark-input; border-color: $dark-input;
.ant-card-head{ .ant-card-head {
border-bottom-color: #929292; border-bottom-color: #929292;
} }
} }
/* 标签:未启用 */ /* 标签:未启用 */
.ant-tag-red{ .ant-tag-red {
background: #4f4749; background: #4f4749;
border-color: #4f4749; border-color: #4f4749;
color: #bf8285; color: #bf8285;
} }
/* 标签:已启用 */ /* 标签:已启用 */
.ant-tag-green{ .ant-tag-green {
background: #505f5f; background: #505f5f;
border-color: #505f5f; border-color: #505f5f;
color: #90cb9f; color: #90cb9f;
} }
/* 标签:警告 */ /* 标签:警告 */
.ant-tag-orange{ .ant-tag-orange {
background: #5a5750; background: #5a5750;
border-color: #5a5750; border-color: #5a5750;
color: #cfa572; color: #cfa572;
} }
/* 按钮 */ /* 按钮 */
.ant-btn:not(.ant-btn-danger, .ant-btn-primary){ .ant-btn:not(.ant-btn-danger, .ant-btn-primary) {
background: $dark-btn; background: $dark-btn;
border-color: $dark-btn; border-color: $dark-btn;
color: $dark-text; color: $dark-text;
&:hover{ &:hover {
opacity: 0.8; opacity: 0.8;
} }
} }
/* 单选框:开关式 */ /* 单选框:开关式 */
.ant-switch:not(.ant-switch-checked){ .ant-switch:not(.ant-switch-checked) {
background: $dark-btn; background: $dark-btn;
border-color: $dark-btn; border-color: $dark-btn;
&:hover{ &:hover {
opacity: 0.8; opacity: 0.8;
} }
} }
/* 单选框:按钮式 */ /* 单选框:按钮式 */
.ant-radio-button-wrapper{ .ant-radio-button-wrapper {
background: $dark-btn; background: $dark-btn;
border-color: $dark-btn; border-color: $dark-btn;
color: $dark-text; color: $dark-text;
&:hover{ &:hover {
opacity: 0.8; opacity: 0.8;
} }
} }
/* JSON编辑器应用于拦截设置 */ /* JSON编辑器应用于拦截设置 */
.jsoneditor-vue{ .jsoneditor-vue {
/*整个编辑框:背景色和边框*/ /*整个编辑框:背景色和边框*/
div.jsoneditor{ div.jsoneditor {
background: $dark-bg-highlight; background: $dark-bg-highlight;
border: none; border: none;
} }
/* 头部菜单栏:边框 */ /* 头部菜单栏:边框 */
div.jsoneditor-menu{ div.jsoneditor-menu {
background: $dark-bg-highlight; background: $dark-bg-highlight;
border-color: $dark-bg-highlight; border-color: $dark-bg-highlight;
} }
/* 内容区域左边:行号 */ /* 内容区域左边:行号 */
.ace_gutter{ .ace_gutter {
background: #444; background: #444;
.ace_gutter-cell { color: #aaa; } .ace_gutter-cell {
color: #aaa;
}
} }
/* 内容区域右边JSON内容 */ /* 内容区域右边JSON内容 */
.ace_scroller{ .ace_scroller {
background: #555; background: #555;
} }
/* key的颜色 */ /* key的颜色 */
.ace_variable, .ace_text-layer{ .ace_variable,
.ace_text-layer {
color: #eee; color: #eee;
} }
/* 字符串值的颜色 */ /* 字符串值的颜色 */
.ace_string, .ace_cjk{ .ace_string,
.ace_cjk {
color: #a6eaa6; color: #a6eaa6;
} }
.ace_constant{ .ace_constant {
/* 数字的颜色 */ /* 数字的颜色 */
&.ace_numeric{ &.ace_numeric {
color: #ec9999; color: #ec9999;
} }
/* 布尔值的颜色 */ /* 布尔值的颜色 */
&.ace_language{ &.ace_language {
color: #f4c995; color: #f4c995;
} }
} }
/* 当前行高亮样式 */ /* 当前行高亮样式 */
.ace_gutter-active-line, .ace_gutter-active-line,
.ace_marker-layer .ace_active-line{ .ace_marker-layer .ace_active-line {
background: #838774; background: #838774;
} }
/* 选中行高亮样式 */ /* 选中行高亮样式 */
@ -213,7 +225,9 @@ $dark-input: #777; //输入框:背景色
} }
} }
/* 搜索框 */ /* 搜索框 */
.ace_button, button, .ace_search_field { .ace_button,
button,
.ace_search_field {
color: #000; color: #000;
} }
/* 搜索结果 */ /* 搜索结果 */

View File

@ -1,6 +1,6 @@
const path = require('path') const path = require('node:path')
const webpack = require('webpack')
const { defineConfig } = require('@vue/cli-service') const { defineConfig } = require('@vue/cli-service')
const webpack = require('webpack')
const publishUrl = process.env.VUE_APP_PUBLISH_URL const publishUrl = process.env.VUE_APP_PUBLISH_URL
const publishProvider = process.env.VUE_APP_PUBLISH_PROVIDER const publishProvider = process.env.VUE_APP_PUBLISH_PROVIDER
@ -33,7 +33,7 @@ module.exports = defineConfig({
}, },
pluginOptions: { pluginOptions: {
electronBuilder: { electronBuilder: {
mainProcessFile: "./src/background.js", mainProcessFile: './src/background.js',
// Ref: https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/1891 // Ref: https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/1891
customFileProtocol: './', customFileProtocol: './',
externals: [ externals: [

View File

@ -12,7 +12,8 @@ function registerProcessListener () {
log.info('child get msg:', JSON.stringify(msg)) log.info('child get msg:', JSON.stringify(msg))
if (msg.type === 'action') { if (msg.type === 'action') {
api[msg.event.key](msg.event.params) api[msg.event.key](msg.event.params)
} else if (msg.type === 'speed') { }
else if (msg.type === 'speed') {
speedTest.action(msg.event) speedTest.action(msg.event)
} }
}) })
@ -61,7 +62,8 @@ const api = {
if (proxyOptions.setting && proxyOptions.setting.NODE_TLS_REJECT_UNAUTHORIZED === false) { if (proxyOptions.setting && proxyOptions.setting.NODE_TLS_REJECT_UNAUTHORIZED === false) {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
} else { }
else {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1' process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'
} }
// log.info('启动代理服务时的配置:', JSON.stringify(proxyOptions, null, '\t')) // log.info('启动代理服务时的配置:', JSON.stringify(proxyOptions, null, '\t'))
@ -98,7 +100,8 @@ const api = {
if (err.code === 'ERR_SERVER_NOT_RUNNING') { if (err.code === 'ERR_SERVER_NOT_RUNNING') {
log.info('代理服务未运行,无需关闭') log.info('代理服务未运行,无需关闭')
resolve() resolve()
} else { }
else {
log.error('代理服务关闭失败:', err) log.error('代理服务关闭失败:', err)
reject(err) reject(err)
} }
@ -110,7 +113,8 @@ const api = {
}) })
} }
servers = [] servers = []
} else { }
else {
log.info('server is null, no need to close.') log.info('server is null, no need to close.')
fireStatus(false) fireStatus(false)
resolve() resolve()

View File

@ -1,5 +1,6 @@
const log = require('./utils/util.log')
let JSON5 = require('json5') let JSON5 = require('json5')
const log = require('./utils/util.log')
if (JSON5.default) { if (JSON5.default) {
JSON5 = JSON5.default JSON5 = JSON5.default
} }
@ -16,10 +17,12 @@ module.exports = {
stringify2 (obj) { stringify2 (obj) {
try { try {
return JSON.stringify(obj) return JSON.stringify(obj)
} catch (e) { }
catch (e) {
try { try {
return JSON5.stringify(obj) return JSON5.stringify(obj)
} catch (e2) { }
catch (e2) {
log.debug('转换为JSON字符串失败, error:', e, ', obj:', obj) log.debug('转换为JSON字符串失败, error:', e, ', obj:', obj)
return obj return obj
} }

View File

@ -88,7 +88,8 @@ class DynamicChoice {
if (this.backupList.length > 0) { if (this.backupList.length > 0) {
this.value = this.backupList.shift() this.value = this.backupList.shift()
log.info(`切换backup完成: ${this.key}, ip: ${valueBackup}${this.value}, this:`, this) log.info(`切换backup完成: ${this.key}, ip: ${valueBackup}${this.value}, this:`, this)
} else { }
else {
this.value = null this.value = null
log.info(`切换backup完成: ${this.key}, backupList为空了设置this.value: from '${valueBackup}' to null. this:`, this) log.info(`切换backup完成: ${this.key}, backupList为空了设置this.value: from '${valueBackup}' to null. this:`, this)
} }
@ -109,7 +110,8 @@ class DynamicChoice {
// 失败次数+1累计连续失败次数+1 // 失败次数+1累计连续失败次数+1
count.error++ count.error++
count.keepErrorCount++ count.keepErrorCount++
} else { }
else {
// 总次数+1 // 总次数+1
count.total++ count.total++
} }

View File

@ -43,7 +43,8 @@ module.exports = class BaseDNS {
ipCache.doCount(ipCache.value, false) ipCache.doCount(ipCache.value, false)
return ipCache.value return ipCache.value
} }
} else { }
else {
ipCache = new IpCache(hostname) ipCache = new IpCache(hostname)
this.cache.set(hostname, ipCache) this.cache.set(hostname, ipCache)
} }
@ -60,7 +61,8 @@ module.exports = class BaseDNS {
log.info(`[DNS]: ${hostname}${ipCache.value} (${new Date() - t} ms), ipList: ${JSON.stringify(ipList)}, ipCache:`, JSON.stringify(ipCache)) log.info(`[DNS]: ${hostname}${ipCache.value} (${new Date() - t} ms), ipList: ${JSON.stringify(ipList)}, ipCache:`, JSON.stringify(ipCache))
return ipCache.value return ipCache.value
} catch (error) { }
catch (error) {
log.error(`[DNS] cannot resolve hostname ${hostname} (${error})`, error) log.error(`[DNS] cannot resolve hostname ${hostname} (${error})`, error)
return hostname return hostname
} }

View File

@ -1,4 +1,4 @@
const { promisify } = require('util') const { promisify } = require('node:util')
const doh = require('dns-over-http') const doh = require('dns-over-http')
const log = require('../../utils/util.log') const log = require('../../utils/util.log')
const matchUtil = require('../../utils/util.match') const matchUtil = require('../../utils/util.match')
@ -30,7 +30,8 @@ module.exports = class DNSOverHTTPS extends BaseDNS {
if (hostnamePreSetIpList && (hostnamePreSetIpList.length > 0 || hostnamePreSetIpList.length === undefined)) { if (hostnamePreSetIpList && (hostnamePreSetIpList.length > 0 || hostnamePreSetIpList.length === undefined)) {
if (hostnamePreSetIpList.length > 0) { if (hostnamePreSetIpList.length > 0) {
hostnamePreSetIpList = hostnamePreSetIpList.slice() hostnamePreSetIpList = hostnamePreSetIpList.slice()
} else { }
else {
hostnamePreSetIpList = mapToList(hostnamePreSetIpList) hostnamePreSetIpList = mapToList(hostnamePreSetIpList)
} }
@ -52,11 +53,13 @@ module.exports = class DNSOverHTTPS extends BaseDNS {
const ret = result.answers.filter(item => item.type === 'A').map(item => item.data) const ret = result.answers.filter(item => item.type === 'A').map(item => item.data)
if (ret.length === 0) { if (ret.length === 0) {
log.info('该域名没有IPv4地址解析:', hostname, ', cost:', (new Date() - start), 'ms') log.info('该域名没有IPv4地址解析:', hostname, ', cost:', (new Date() - start), 'ms')
} else { }
else {
log.info('获取到域名地址:', hostname, JSON.stringify(ret), ', cost:', (new Date() - start), 'ms') log.info('获取到域名地址:', hostname, JSON.stringify(ret), ', cost:', (new Date() - start), 'ms')
} }
return ret return ret
} catch (e) { }
catch (e) {
log.warn('DNS query error:', hostname, ', dns:', this.dnsServer, ', cost:', (new Date() - start), 'ms, error:', e) log.warn('DNS query error:', hostname, ', dns:', this.dnsServer, ', cost:', (new Date() - start), 'ms, error:', e)
return [] return []
} }

View File

@ -14,9 +14,11 @@ module.exports = {
if (conf.type === 'ipaddress') { if (conf.type === 'ipaddress') {
dnsMap[provider] = new DNSOverIpAddress(conf.server) dnsMap[provider] = new DNSOverIpAddress(conf.server)
} else if (conf.type === 'https') { }
else if (conf.type === 'https') {
dnsMap[provider] = new DNSOverHTTPS(conf.server, preSetIpList) dnsMap[provider] = new DNSOverHTTPS(conf.server, preSetIpList)
} else { }
else {
dnsMap[provider] = new DNSOverTLS(conf.server) dnsMap[provider] = new DNSOverTLS(conf.server)
} }

View File

@ -14,7 +14,7 @@ module.exports = class DNSOverIpAddress extends BaseDNS {
} }
const ret = res.data const ret = res.data
const regexp = /<tr><th>IP Address<\/th><td><ul class="comma-separated"><li>([^<]*)<\/li><\/ul><\/td><\/tr>/gm const regexp = /<tr><th>IP Address<\/th><td><ul class="comma-separated"><li>([^<]*)<\/li><\/ul><\/td><\/tr>/g
const matched = regexp.exec(ret) const matched = regexp.exec(ret)
let ip = null let ip = null

View File

@ -26,7 +26,8 @@ module.exports = class DNSOverPreSetIpList extends BaseDNS {
if (hostnamePreSetIpList && (hostnamePreSetIpList.length > 0 || hostnamePreSetIpList.length === undefined)) { if (hostnamePreSetIpList && (hostnamePreSetIpList.length > 0 || hostnamePreSetIpList.length === undefined)) {
if (hostnamePreSetIpList.length > 0) { if (hostnamePreSetIpList.length > 0) {
hostnamePreSetIpList = hostnamePreSetIpList.slice() hostnamePreSetIpList = hostnamePreSetIpList.slice()
} else { }
else {
hostnamePreSetIpList = mapToList(hostnamePreSetIpList) hostnamePreSetIpList = mapToList(hostnamePreSetIpList)
} }

View File

@ -6,7 +6,8 @@ function readConfig (config, defaultConfig) {
if (Object.isArray(config)) { if (Object.isArray(config)) {
config = config.join(',') config = config.join(',')
} }
} else { }
else {
config = defaultConfig config = defaultConfig
} }
return config return config

View File

@ -60,7 +60,8 @@ function getConfig (interceptOpt, tryCount, log) {
if (count >= 100000) { if (count >= 100000) {
count = 0 count = 0
} }
} else { }
else {
config = interceptOpt.baiduOcr config = interceptOpt.baiduOcr
tryCount = null // 将tryCount设置为null代表只有一个配置 tryCount = null // 将tryCount设置为null代表只有一个配置
} }
@ -83,11 +84,13 @@ function getConfig (interceptOpt, tryCount, log) {
if (config.api == null) { if (config.api == null) {
if (tryCount == null) { if (tryCount == null) {
return null // 只配置了一个账号没有更多账号可以选择了直接返回null return null // 只配置了一个账号没有更多账号可以选择了直接返回null
} else { }
else {
if (tryCount < interceptOpt.baiduOcr.length) { if (tryCount < interceptOpt.baiduOcr.length) {
// 递归找到有效的配置 // 递归找到有效的配置
return getConfig(interceptOpt, tryCount + 1, log) return getConfig(interceptOpt, tryCount + 1, log)
} else { }
else {
return null return null
} }
} }
@ -164,7 +167,8 @@ module.exports = {
limitConfig(config.id, config.api) limitConfig(config.id, config.api)
log.error(`当前百度云账号的接口 ${config.api},已达到当日调用次数上限,暂时禁用它,明天会自动放开:`, config) log.error(`当前百度云账号的接口 ${config.api},已达到当日调用次数上限,暂时禁用它,明天会自动放开:`, config)
} }
} else { }
else {
log.info('baiduOcr success:', result) log.info('baiduOcr success:', result)
} }

View File

@ -42,7 +42,8 @@ function getLastModifiedTimeFromIfModifiedSince (rOptions, log) {
try { try {
// 尝试解析 lastModified并获取time // 尝试解析 lastModified并获取time
return new Date(lastModified).getTime() return new Date(lastModified).getTime()
} catch (e) { }
catch (e) {
// 为数字时,直接返回 // 为数字时,直接返回
if (/\\d+/.test(lastModified)) { if (/\\d+/.test(lastModified)) {
return lastModified - 0 return lastModified - 0

View File

@ -1,4 +1,4 @@
const url = require('url') const url = require('node:url')
const lodash = require('lodash') const lodash = require('lodash')
// 替换占位符 // 替换占位符
@ -27,9 +27,11 @@ function buildTargetUrl (rOptions, urlConf, interceptOpt, matched) {
if (interceptOpt && interceptOpt.replace) { if (interceptOpt && interceptOpt.replace) {
const regexp = new RegExp(interceptOpt.replace) const regexp = new RegExp(interceptOpt.replace)
targetUrl = rOptions.path.replace(regexp, urlConf) targetUrl = rOptions.path.replace(regexp, urlConf)
} else if (urlConf.indexOf('http:') === 0 || urlConf.indexOf('https:') === 0) { }
else if (urlConf.indexOf('http:') === 0 || urlConf.indexOf('https:') === 0) {
targetUrl = urlConf targetUrl = urlConf
} else { }
else {
let uri = rOptions.path let uri = rOptions.path
if (uri.indexOf('http:') === 0 || uri.indexOf('https:') === 0) { if (uri.indexOf('http:') === 0 || uri.indexOf('https:') === 0) {
// eslint-disable-next-line node/no-deprecated-api // eslint-disable-next-line node/no-deprecated-api
@ -95,7 +97,8 @@ module.exports = {
} }
if (count.value == null) { if (count.value == null) {
log.error('`count.value` is null, the count:', count) log.error('`count.value` is null, the count:', count)
} else { }
else {
count.doCount(count.value) count.doCount(count.value)
proxyConf = count.value proxyConf = count.value
context.requestCount = { context.requestCount = {
@ -124,7 +127,8 @@ module.exports = {
} }
res.setHeader('DS-Interceptor', `proxy: ${proxyTarget}, sni: ${interceptOpt.sni}${unVerifySsl ? ', unVerifySsl' : ''}`) res.setHeader('DS-Interceptor', `proxy: ${proxyTarget}, sni: ${interceptOpt.sni}${unVerifySsl ? ', unVerifySsl' : ''}`)
log.info('proxy intercept: hostname:', originHostname, ', target', proxyTarget, ', sni replace servername:', rOptions.servername, (unVerifySsl ? ', unVerifySsl' : '')) log.info('proxy intercept: hostname:', originHostname, ', target', proxyTarget, ', sni replace servername:', rOptions.servername, (unVerifySsl ? ', unVerifySsl' : ''))
} else { }
else {
res.setHeader('DS-Interceptor', `proxy: ${proxyTarget}`) res.setHeader('DS-Interceptor', `proxy: ${proxyTarget}`)
log.info('proxy intercept: hostname:', originHostname, ', target', proxyTarget) log.info('proxy intercept: hostname:', originHostname, ', target', proxyTarget)
} }

View File

@ -10,7 +10,8 @@ function replaceRequestHeaders (rOptions, headers, log) {
if (value) { if (value) {
log.debug(`[DS-RequestReplace-Interceptor] replace '${key}': '${rOptions.headers[key.toLowerCase()]}' -> '${value}'`) log.debug(`[DS-RequestReplace-Interceptor] replace '${key}': '${rOptions.headers[key.toLowerCase()]}' -> '${value}'`)
rOptions.headers[key.toLowerCase()] = value rOptions.headers[key.toLowerCase()] = value
} else if (rOptions.headers[key.toLowerCase()]) { }
else if (rOptions.headers[key.toLowerCase()]) {
log.debug(`[DS-RequestReplace-Interceptor] remove '${key}': '${rOptions.headers[key.toLowerCase()]}'`) log.debug(`[DS-RequestReplace-Interceptor] remove '${key}': '${rOptions.headers[key.toLowerCase()]}'`)
delete rOptions.headers[key.toLowerCase()] delete rOptions.headers[key.toLowerCase()]
} }

View File

@ -47,11 +47,14 @@ module.exports = {
// 尝试修改rawHeaders中的cache-control、last-modified、expires // 尝试修改rawHeaders中的cache-control、last-modified、expires
if (proxyRes.rawHeaders[i].toLowerCase() === 'cache-control') { if (proxyRes.rawHeaders[i].toLowerCase() === 'cache-control') {
originalHeaders.cacheControl = { value: proxyRes.rawHeaders[i + 1], valueIndex: i + 1 } originalHeaders.cacheControl = { value: proxyRes.rawHeaders[i + 1], valueIndex: i + 1 }
} else if (proxyRes.rawHeaders[i].toLowerCase() === 'last-modified') { }
else if (proxyRes.rawHeaders[i].toLowerCase() === 'last-modified') {
originalHeaders.lastModified = { value: proxyRes.rawHeaders[i + 1], valueIndex: i + 1 } originalHeaders.lastModified = { value: proxyRes.rawHeaders[i + 1], valueIndex: i + 1 }
} else if (proxyRes.rawHeaders[i].toLowerCase() === 'expires') { }
else if (proxyRes.rawHeaders[i].toLowerCase() === 'expires') {
originalHeaders.expires = { value: proxyRes.rawHeaders[i + 1], valueIndex: i + 1 } originalHeaders.expires = { value: proxyRes.rawHeaders[i + 1], valueIndex: i + 1 }
} else if (proxyRes.rawHeaders[i].toLowerCase() === 'etag') { }
else if (proxyRes.rawHeaders[i].toLowerCase() === 'etag') {
originalHeaders.etag = { value: proxyRes.rawHeaders[i + 1], valueIndex: i + 1 } originalHeaders.etag = { value: proxyRes.rawHeaders[i + 1], valueIndex: i + 1 }
} }
@ -67,7 +70,8 @@ module.exports = {
if (maxAgeMatch && maxAgeMatch[1] > maxAge) { if (maxAgeMatch && maxAgeMatch[1] > maxAge) {
if (interceptOpt.cacheImmutable !== false && !originalHeaders.cacheControl.value.includes('immutable')) { if (interceptOpt.cacheImmutable !== false && !originalHeaders.cacheControl.value.includes('immutable')) {
maxAge = maxAgeMatch[1] maxAge = maxAgeMatch[1]
} else { }
else {
const url = `${rOptions.method}${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${req.url}` const url = `${rOptions.method}${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${req.url}`
res.setHeader('DS-Cache-Response-Interceptor', `skip: ${maxAgeMatch[1]} > ${maxAge}`) res.setHeader('DS-Cache-Response-Interceptor', `skip: ${maxAgeMatch[1]} > ${maxAge}`)
log.info(`cache response intercept: skip: ${maxAgeMatch[1]} > ${maxAge}, url: ${url}`) log.info(`cache response intercept: skip: ${maxAgeMatch[1]} > ${maxAge}, url: ${url}`)
@ -87,19 +91,22 @@ module.exports = {
// 替换cache-control // 替换cache-control
if (originalHeaders.cacheControl) { if (originalHeaders.cacheControl) {
proxyRes.rawHeaders[originalHeaders.cacheControl.valueIndex] = replaceHeaders.cacheControl proxyRes.rawHeaders[originalHeaders.cacheControl.valueIndex] = replaceHeaders.cacheControl
} else { }
else {
res.setHeader('Cache-Control', replaceHeaders.cacheControl) res.setHeader('Cache-Control', replaceHeaders.cacheControl)
} }
// 替换last-modified // 替换last-modified
if (originalHeaders.lastModified) { if (originalHeaders.lastModified) {
proxyRes.rawHeaders[originalHeaders.lastModified.valueIndex] = replaceHeaders.lastModified proxyRes.rawHeaders[originalHeaders.lastModified.valueIndex] = replaceHeaders.lastModified
} else { }
else {
res.setHeader('Last-Modified', replaceHeaders.lastModified) res.setHeader('Last-Modified', replaceHeaders.lastModified)
} }
// 替换expires // 替换expires
if (originalHeaders.expires) { if (originalHeaders.expires) {
proxyRes.rawHeaders[originalHeaders.expires.valueIndex] = replaceHeaders.expires proxyRes.rawHeaders[originalHeaders.expires.valueIndex] = replaceHeaders.expires
} else { }
else {
res.setHeader('Expires', replaceHeaders.expires) res.setHeader('Expires', replaceHeaders.expires)
} }

View File

@ -31,7 +31,8 @@ function replaceResponseHeaders (newHeaders, res, proxyRes) {
preHeaders[headerKey] = proxyRes.rawHeaders[i + 1] // 先保存原先响应头 preHeaders[headerKey] = proxyRes.rawHeaders[i + 1] // 先保存原先响应头
if (newHeaderValue === REMOVE) { // 由于拦截配置中不允许配置null会被删所以配置一个 "[remove]",当作删除响应头的意思 if (newHeaderValue === REMOVE) { // 由于拦截配置中不允许配置null会被删所以配置一个 "[remove]",当作删除响应头的意思
proxyRes.rawHeaders[i + 1] = '' proxyRes.rawHeaders[i + 1] = ''
} else { }
else {
proxyRes.rawHeaders[i + 1] = newHeaderValue proxyRes.rawHeaders[i + 1] = newHeaderValue
} }
} }

View File

@ -52,7 +52,8 @@ module.exports = {
if (key.includes('/')) { if (key.includes('/')) {
scriptTag = getScriptByUrlOrPath(key) // 1.绝对地址或相对地址注意当目标站点限制跨域脚本时可使用相对地址再结合proxy拦截器进行代理可规避掉限制跨域脚本问题。 scriptTag = getScriptByUrlOrPath(key) // 1.绝对地址或相对地址注意当目标站点限制跨域脚本时可使用相对地址再结合proxy拦截器进行代理可规避掉限制跨域脚本问题。
} else { }
else {
const script = scripts[key] const script = scripts[key]
if (script == null) { if (script == null) {
continue continue
@ -71,7 +72,8 @@ module.exports = {
// 插入油猴脚本浏览器扩展 // 插入油猴脚本浏览器扩展
if (typeof interceptOpt.tampermonkeyScript === 'string') { if (typeof interceptOpt.tampermonkeyScript === 'string') {
tags = `\r\n\t${getScriptByUrlOrPath(interceptOpt.tampermonkeyScript)}${tags}` tags = `\r\n\t${getScriptByUrlOrPath(interceptOpt.tampermonkeyScript)}${tags}`
} else { }
else {
tags = `\r\n\t${getScript('tampermonkey', scripts.tampermonkey.script)}${tags}` tags = `\r\n\t${getScript('tampermonkey', scripts.tampermonkey.script)}${tags}`
} }
@ -80,10 +82,12 @@ module.exports = {
return { return {
head: `${tags}\r\n`, head: `${tags}\r\n`,
} }
} catch (err) { }
catch (err) {
try { try {
res.setHeader('DS-Script-Interceptor', 'error') res.setHeader('DS-Script-Interceptor', 'error')
} catch (e) { }
catch (e) {
// ignore // ignore
} }
log.error('load monkey script error', err) log.error('load monkey script error', err)
@ -108,7 +112,8 @@ module.exports = {
if (typeof replaceScriptUrlFun === 'function') { if (typeof replaceScriptUrlFun === 'function') {
replaceScriptUrlFun(scriptKey) replaceScriptUrlFun(scriptKey)
} }
} else if (scriptUrl.indexOf('/') === 0) { }
else if (scriptUrl.indexOf('/') === 0) {
// 相对地址 // 相对地址
scriptProxy[scriptUrl] = scriptUrl scriptProxy[scriptUrl] = scriptUrl
} }
@ -124,7 +129,8 @@ module.exports = {
pathConfig.script[i] = scriptKey pathConfig.script[i] = scriptKey
}) })
} }
} else if (typeof pathConfig.script === 'string') { }
else if (typeof pathConfig.script === 'string') {
handleScriptUrl(pathConfig.script, 'script', (scriptKey) => { handleScriptUrl(pathConfig.script, 'script', (scriptKey) => {
pathConfig.script = scriptKey pathConfig.script = scriptKey
}) })
@ -174,7 +180,8 @@ module.exports = {
const obj = {} const obj = {}
obj[pathPattern] = hostnameConfig[pathPattern] obj[pathPattern] = hostnameConfig[pathPattern]
log.debug(`域名 '${hostnamePattern}' 拦截配置中,新增伪脚本地址的代理配置:`, JSON.stringify(obj, null, '\t')) log.debug(`域名 '${hostnamePattern}' 拦截配置中,新增伪脚本地址的代理配置:`, JSON.stringify(obj, null, '\t'))
} else { }
else {
// 相对地址新增响应头Content-Type替换配置 // 相对地址新增响应头Content-Type替换配置
if (hostnameConfig[scriptKey]) { if (hostnameConfig[scriptKey]) {
continue // 配置已经存在,按自定义配置优先 continue // 配置已经存在,按自定义配置优先

View File

@ -1,17 +1,17 @@
// request interceptor impls
const OPTIONS = require('./impl/req/OPTIONS.js')
const success = require('./impl/req/success')
const redirect = require('./impl/req/redirect')
const abort = require('./impl/req/abort') const abort = require('./impl/req/abort')
const cacheReq = require('./impl/req/cacheReq')
const requestReplace = require('./impl/req/requestReplace')
const proxy = require('./impl/req/proxy')
const sni = require('./impl/req/sni')
const baiduOcr = require('./impl/req/baiduOcr') const baiduOcr = require('./impl/req/baiduOcr')
const cacheReq = require('./impl/req/cacheReq')
// request interceptor impls
const OPTIONS = require('./impl/req/OPTIONS.js')
const proxy = require('./impl/req/proxy')
const redirect = require('./impl/req/redirect')
const requestReplace = require('./impl/req/requestReplace')
const sni = require('./impl/req/sni')
const success = require('./impl/req/success')
// response interceptor impls // response interceptor impls
const OPTIONSHeaders = require('./impl/res/AfterOPTIONSHeaders') const OPTIONSHeaders = require('./impl/res/AfterOPTIONSHeaders')
@ -23,12 +23,18 @@ const script = require('./impl/res/script')
module.exports = [ module.exports = [
// request interceptor impls // request interceptor impls
OPTIONS, OPTIONS,
success, redirect, abort, cacheReq, success,
redirect,
abort,
cacheReq,
requestReplace, requestReplace,
proxy, sni, proxy,
sni,
baiduOcr, baiduOcr,
// response interceptor impls // response interceptor impls
OPTIONSHeaders, cacheRes, responseReplace, OPTIONSHeaders,
cacheRes,
responseReplace,
script, script,
] ]

View File

@ -1,5 +1,5 @@
const fs = require('fs') const fs = require('node:fs')
const path = require('path') const path = require('node:path')
const log = require('../../utils/util.log') const log = require('../../utils/util.log')
let scripts let scripts
@ -12,7 +12,8 @@ function buildScript (sc, content, scriptName) {
let eventStr let eventStr
if (runAt === 'document-end') { if (runAt === 'document-end') {
eventStr = 'document.addEventListener("DOMContentLoaded"' eventStr = 'document.addEventListener("DOMContentLoaded"'
} else { }
else {
eventStr = 'window.addEventListener("load"' eventStr = 'window.addEventListener("load"'
} }
@ -47,7 +48,8 @@ if (!((window.__ds_global__ || {}).GM_getValue || (() => true))("ds_enabled", tr
if (item.indexOf('.') > 0) { if (item.indexOf('.') > 0) {
grantStr += `${item} = (window.__ds_global__ || {})['${item}'];` grantStr += `${item} = (window.__ds_global__ || {})['${item}'];`
} else { }
else {
grantStr += `const ${item} = (window.__ds_global__ || {})['${item}'] || (() => {});` grantStr += `const ${item} = (window.__ds_global__ || {})['${item}'] || (() => {});`
} }
} }
@ -57,10 +59,10 @@ if (!((window.__ds_global__ || {}).GM_getValue || (() => true))("ds_enabled", tr
initStr}\r\n${ initStr}\r\n${
checkEnabledStr}\r\n\r\n${ checkEnabledStr}\r\n\r\n${
grantStr ? (`${grantStr}\r\n\r\n`) : '' grantStr ? (`${grantStr}\r\n\r\n`) : ''
}${content }${content
}\r\nconsole.log("${scriptKey} completed")` }\r\nconsole.log("${scriptKey} completed")`
+ `\r\n})` + `\r\n})`
+ `\r\nconsole.log("${scriptKey} loaded")` + `\r\nconsole.log("${scriptKey} loaded")`
} }
function loadScript (content, scriptName) { function loadScript (content, scriptName) {
@ -89,9 +91,11 @@ function loadScript (content, scriptName) {
const value = ret[2].trim() const value = ret[2].trim()
if (key === 'grant') { if (key === 'grant') {
sc.grant.push(value) sc.grant.push(value)
} else if (key === 'match') { }
else if (key === 'match') {
sc.match.push(value) sc.match.push(value)
} else { }
else {
sc[key] = value sc[key] = value
} }
} }

View File

@ -1,4 +1,4 @@
const path = require('path') const path = require('node:path')
const config = exports const config = exports

View File

@ -1,4 +1,4 @@
const url = require('url') const url = require('node:url')
const tunnelAgent = require('tunnel-agent') const tunnelAgent = require('tunnel-agent')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const matchUtil = require('../../../utils/util.match') const matchUtil = require('../../../utils/util.match')
@ -83,7 +83,8 @@ util.parseHostnameAndPort = (host, defaultPort) => {
if (arr[1]) { if (arr[1]) {
arr[1] = Number.parseInt(arr[1], 10) arr[1] = Number.parseInt(arr[1], 10)
} }
} else { }
else {
arr = host.split(':') arr = host.split(':')
if (arr.length > 1) { if (arr.length > 1) {
arr[1] = Number.parseInt(arr[1], 10) arr[1] = Number.parseInt(arr[1], 10)
@ -92,7 +93,8 @@ util.parseHostnameAndPort = (host, defaultPort) => {
if (defaultPort > 0 && (arr.length === 1 || arr[1] === undefined)) { if (defaultPort > 0 && (arr.length === 1 || arr[1] === undefined)) {
arr[1] = defaultPort arr[1] = defaultPort
} else if (arr.length === 2 && arr[1] === undefined) { }
else if (arr.length === 2 && arr[1] === undefined) {
arr.pop() arr.pop()
} }
@ -110,10 +112,12 @@ util.getOptionsFromRequest = (req, ssl, externalProxy = null, serverSetting, com
if (externalProxy) { if (externalProxy) {
if (typeof externalProxy === 'string') { if (typeof externalProxy === 'string') {
externalProxyUrl = externalProxy externalProxyUrl = externalProxy
} else if (typeof externalProxy === 'function') { }
else if (typeof externalProxy === 'function') {
try { try {
externalProxyUrl = externalProxy(req, ssl) externalProxyUrl = externalProxy(req, ssl)
} catch (e) { }
catch (e) {
log.error('externalProxy error:', e) log.error('externalProxy error:', e)
} }
} }
@ -133,10 +137,12 @@ util.getOptionsFromRequest = (req, ssl, externalProxy = null, serverSetting, com
// log.info(`get timeoutConfig '${hostname}':`, timeoutConfig) // log.info(`get timeoutConfig '${hostname}':`, timeoutConfig)
agent = createAgent(protocol, timeoutConfig, serverSetting.verifySsl) agent = createAgent(protocol, timeoutConfig, serverSetting.verifySsl)
headers.connection = 'keep-alive' headers.connection = 'keep-alive'
} else { }
else {
agent = false agent = false
} }
} else { }
else {
agent = util.getTunnelAgent(protocol === 'https:', externalProxyUrl) agent = util.getTunnelAgent(protocol === 'https:', externalProxyUrl)
} }
@ -166,7 +172,8 @@ util.getOptionsFromRequest = (req, ssl, externalProxy = null, serverSetting, com
// mark a socketId for Agent to bind socket for NTLM // mark a socketId for Agent to bind socket for NTLM
if (req.socket.customSocketId) { if (req.socket.customSocketId) {
options.customSocketId = req.socket.customSocketId options.customSocketId = req.socket.customSocketId
} else if (headers.authorization) { }
else if (headers.authorization) {
options.customSocketId = req.socket.customSocketId = socketId++ options.customSocketId = req.socket.customSocketId = socketId++
} }
@ -194,7 +201,8 @@ util.getTunnelAgent = (requestIsSSL, externalProxyUrl) => {
}) })
} }
return httpsOverHttpAgent return httpsOverHttpAgent
} else { }
else {
if (!httpsOverHttpsAgent) { if (!httpsOverHttpsAgent) {
httpsOverHttpsAgent = tunnelAgent.httpsOverHttps({ httpsOverHttpsAgent = tunnelAgent.httpsOverHttps({
proxy: { proxy: {
@ -205,7 +213,8 @@ util.getTunnelAgent = (requestIsSSL, externalProxyUrl) => {
} }
return httpsOverHttpsAgent return httpsOverHttpsAgent
} }
} else { }
else {
if (protocol === 'http:') { if (protocol === 'http:') {
// if (!httpOverHttpAgent) { // if (!httpOverHttpAgent) {
// httpOverHttpAgent = tunnelAgent.httpOverHttp({ // httpOverHttpAgent = tunnelAgent.httpOverHttp({
@ -216,7 +225,8 @@ util.getTunnelAgent = (requestIsSSL, externalProxyUrl) => {
// }) // })
// } // }
return false return false
} else { }
else {
if (!httpOverHttpsAgent) { if (!httpOverHttpsAgent) {
httpOverHttpsAgent = tunnelAgent.httpOverHttps({ httpOverHttpsAgent = tunnelAgent.httpOverHttps({
proxy: { proxy: {

View File

@ -5,8 +5,8 @@
* *
* @author WangLiang * @author WangLiang
*/ */
const fs = require('fs') const fs = require('node:fs')
const path = require('path') const path = require('node:path')
const jsonApi = require('../../../json') const jsonApi = require('../../../json')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const matchUtil = require('../../../utils/util.match') const matchUtil = require('../../../utils/util.match')
@ -58,7 +58,8 @@ function _loadFromFile (defaultConfig) {
if (!fs.existsSync(configPath)) { if (!fs.existsSync(configPath)) {
config = defaultConfig config = defaultConfig
log.info(`本地未保存过 ${configPath} 文件,使用默认配置`) log.info(`本地未保存过 ${configPath} 文件,使用默认配置`)
} else { }
else {
const file = fs.readFileSync(configPath) const file = fs.readFileSync(configPath)
log.info('读取 automaticCompatibleConfig.json 成功:', configPath) log.info('读取 automaticCompatibleConfig.json 成功:', configPath)
const fileStr = file.toString() const fileStr = file.toString()
@ -79,7 +80,8 @@ function _saveConfigToFile () {
try { try {
fs.writeFileSync(filePath, jsonApi.stringify(config)) fs.writeFileSync(filePath, jsonApi.stringify(config))
log.info('保存 automaticCompatibleConfig.json 成功:', filePath) log.info('保存 automaticCompatibleConfig.json 成功:', filePath)
} catch (e) { }
catch (e) {
log.error('保存 automaticCompatibleConfig.json 失败:', filePath, e) log.error('保存 automaticCompatibleConfig.json 失败:', filePath, e)
} }
} }
@ -107,7 +109,8 @@ module.exports = {
const connectCompatibleConfig = this.getConnectCompatibleConfig(hostname, port) const connectCompatibleConfig = this.getConnectCompatibleConfig(hostname, port)
if (connectCompatibleConfig) { if (connectCompatibleConfig) {
connectCompatibleConfig.ssl = ssl connectCompatibleConfig.ssl = ssl
} else { }
else {
config.connect[`${hostname}:${port}`] = { ssl } config.connect[`${hostname}:${port}`] = { ssl }
} }
@ -139,7 +142,8 @@ module.exports = {
const requestCompatibleConfig = this.getRequestCompatibleConfig(rOptions.hostname, rOptions.port) const requestCompatibleConfig = this.getRequestCompatibleConfig(rOptions.hostname, rOptions.port)
if (requestCompatibleConfig) { if (requestCompatibleConfig) {
requestCompatibleConfig.rejectUnauthorized = rejectUnauthorized requestCompatibleConfig.rejectUnauthorized = rejectUnauthorized
} else { }
else {
config.request[`${rOptions.hostname}:${rOptions.port}`] = { rejectUnauthorized } config.request[`${rOptions.hostname}:${rOptions.port}`] = { rejectUnauthorized }
} }

View File

@ -1,4 +1,4 @@
const zlib = require('zlib') const zlib = require('node:zlib')
const through = require('through2') const through = require('through2')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
@ -181,10 +181,12 @@ module.exports = {
})) }))
.pipe(codec.createCompressor()) // 编码 .pipe(codec.createCompressor()) // 编码
.pipe(res) .pipe(res)
} else { }
else {
log.error(`InsertScriptMiddleware.responseInterceptor(): 暂不支持编码方式 ${encoding}, 目前支持:`, httpUtil.supportedEncodingsStr()) log.error(`InsertScriptMiddleware.responseInterceptor(): 暂不支持编码方式 ${encoding}, 目前支持:`, httpUtil.supportedEncodingsStr())
} }
} else { }
else {
proxyRes proxyRes
.pipe(through(function (chunk, enc, callback) { .pipe(through(function (chunk, enc, callback) {
chunkByteReplace(this, chunk, enc, callback, append) chunkByteReplace(this, chunk, enc, callback, append)

View File

@ -1,7 +1,7 @@
const { Buffer } = require('buffer') const { Buffer } = require('node:buffer')
const fs = require('fs') const fs = require('node:fs')
const path = require('path') const path = require('node:path')
const url = require('url') const url = require('node:url')
const lodash = require('lodash') const lodash = require('lodash')
const request = require('request') const request = require('request')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
@ -15,7 +15,8 @@ function matched (hostname, overWallTargetMap) {
const ret1 = matchUtil.matchHostname(overWallTargetMap, hostname, 'matched overwall') const ret1 = matchUtil.matchHostname(overWallTargetMap, hostname, 'matched overwall')
if (ret1) { if (ret1) {
return 'in config' return 'in config'
} else if (ret1 === false || ret1 === 'false') { }
else if (ret1 === false || ret1 === 'false') {
log.debug(`域名 ${hostname} 的overwall配置为 false跳过增强功能即使它在 pac.txt 里`) log.debug(`域名 ${hostname} 的overwall配置为 false跳过增强功能即使它在 pac.txt 里`)
return null return null
} }
@ -28,7 +29,8 @@ function matched (hostname, overWallTargetMap) {
if (ret && ret.indexOf('PROXY ') === 0) { if (ret && ret.indexOf('PROXY ') === 0) {
log.info(`matchHostname: matched overwall: '${hostname}' -> '${ret}' in pac.txt`) log.info(`matchHostname: matched overwall: '${hostname}' -> '${ret}' in pac.txt`)
return 'in pac.txt' return 'in pac.txt'
} else { }
else {
log.debug(`matchHostname: matched overwall: Not-Matched '${hostname}' -> '${ret}' in pac.txt`) log.debug(`matchHostname: matched overwall: Not-Matched '${hostname}' -> '${ret}' in pac.txt`)
return null return null
} }
@ -49,7 +51,8 @@ function loadPacLastModifiedTime (pacTxt) {
if (matched && matched.length > 0) { if (matched && matched.length > 0) {
try { try {
return new Date(matched[0]) return new Date(matched[0])
} catch (ignore) { }
catch {
return null return null
} }
} }
@ -74,7 +77,7 @@ function savePacFile (pacTxt) {
// 尝试解析和修改 pac.txt 文件时间 // 尝试解析和修改 pac.txt 文件时间
const lastModifiedTime = loadPacLastModifiedTime(pacTxt) const lastModifiedTime = loadPacLastModifiedTime(pacTxt)
if (lastModifiedTime) { if (lastModifiedTime) {
fs.stat(pacFilePath, (err, stats) => { fs.stat(pacFilePath, (err, _stats) => {
if (err) { if (err) {
log.error('修改 pac.txt 文件时间失败:', err) log.error('修改 pac.txt 文件时间失败:', err)
return return
@ -84,7 +87,8 @@ function savePacFile (pacTxt) {
fs.utimes(pacFilePath, lastModifiedTime, lastModifiedTime, (utimesErr) => { fs.utimes(pacFilePath, lastModifiedTime, lastModifiedTime, (utimesErr) => {
if (utimesErr) { if (utimesErr) {
log.error('修改 pac.txt 文件时间失败:', utimesErr) log.error('修改 pac.txt 文件时间失败:', utimesErr)
} else { }
else {
log.info(`'${pacFilePath}' 文件的修改时间已更新为其最近更新时间 '${formatDate(lastModifiedTime)}'`) log.info(`'${pacFilePath}' 文件的修改时间已更新为其最近更新时间 '${formatDate(lastModifiedTime)}'`)
} }
}) })
@ -107,7 +111,8 @@ async function downloadPacAsync (pacConfig) {
if (body == null || body.length < 100) { if (body == null || body.length < 100) {
log.warn('下载远程 pac.txt 文件成功,但内容为空或内容太短,判断为无效的 pax.txt 文件:', remotePacFileUrl, ', body:', body) log.warn('下载远程 pac.txt 文件成功,但内容为空或内容太短,判断为无效的 pax.txt 文件:', remotePacFileUrl, ', body:', body)
return return
} else { }
else {
log.info('下载远程 pac.txt 文件成功:', remotePacFileUrl) log.info('下载远程 pac.txt 文件成功:', remotePacFileUrl)
} }
@ -118,7 +123,8 @@ async function downloadPacAsync (pacConfig) {
pacTxt = Buffer.from(pacTxt, 'base64').toString('utf8') pacTxt = Buffer.from(pacTxt, 'base64').toString('utf8')
// log.debug('解析 base64 后的 pax:', pacTxt) // log.debug('解析 base64 后的 pax:', pacTxt)
} }
} catch (e) { }
catch {
if (!pacTxt.includes('!---------------------EOF')) { if (!pacTxt.includes('!---------------------EOF')) {
log.error(`远程 pac.txt 文件内容即不是base64格式也不是要求的格式url: ${remotePacFileUrl}body: ${body}`) log.error(`远程 pac.txt 文件内容即不是base64格式也不是要求的格式url: ${remotePacFileUrl}body: ${body}`)
return return
@ -127,7 +133,8 @@ async function downloadPacAsync (pacConfig) {
// 保存到本地 // 保存到本地
savePacFile(pacTxt) savePacFile(pacTxt)
} else { }
else {
log.error(`下载远程 pac.txt 文件失败: ${remotePacFileUrl}, response:`, response, ', body:', body) log.error(`下载远程 pac.txt 文件失败: ${remotePacFileUrl}, response:`, response, ', body:', body)
} }
}) })
@ -153,11 +160,11 @@ function createOverwallMiddleware (overWallConfig) {
} }
const overWallTargetMap = matchUtil.domainMapRegexply(overWallConfig.targets) const overWallTargetMap = matchUtil.domainMapRegexply(overWallConfig.targets)
return { return {
sslConnectInterceptor: (req, cltSocket, head) => { sslConnectInterceptor: (req, _cltSocket, _head) => {
const hostname = req.url.split(':')[0] const hostname = req.url.split(':')[0]
return matched(hostname, overWallTargetMap) return matched(hostname, overWallTargetMap)
}, },
requestIntercept (context, req, res, ssl, next) { requestIntercept (context, req, res, _ssl, _next) {
const { rOptions, log, RequestCounter } = context const { rOptions, log, RequestCounter } = context
if (rOptions.protocol === 'http:') { if (rOptions.protocol === 'http:') {
return return
@ -176,7 +183,8 @@ function createOverwallMiddleware (overWallConfig) {
} }
if (count.value == null) { if (count.value == null) {
log.error('`count.value` is null, the count:', count) log.error('`count.value` is null, the count:', count)
} else { }
else {
count.doCount(count.value) count.doCount(count.value)
proxyServer = count.value proxyServer = count.value
context.requestCount = { context.requestCount = {

View File

@ -1,5 +1,5 @@
const fs = require('fs') const fs = require('node:fs')
const path = require('path') const path = require('node:path')
const log = require('../../../../utils/util.log') const log = require('../../../../utils/util.log')
function createPacClient (pacFilePath) { function createPacClient (pacFilePath) {
@ -12,7 +12,8 @@ function createPacClient (pacFilePath) {
const filePath = path.resolve(location) const filePath = path.resolve(location)
log.info('read pac path:', filePath) log.info('read pac path:', filePath)
return fs.readFileSync(location).toString() return fs.readFileSync(location).toString()
} catch (e) { }
catch (e) {
log.error('读取pac失败:', e) log.error('读取pac失败:', e)
return '' return ''
} }

View File

@ -1,5 +1,5 @@
const net = require('net') const net = require('node:net')
const url = require('url') const url = require('node:url')
const jsonApi = require('../../../json') const jsonApi = require('../../../json')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const DnsUtil = require('../../dns/index') const DnsUtil = require('../../dns/index')
@ -45,7 +45,8 @@ module.exports = function createConnectHandler (sslConnectInterceptor, middlewar
}).catch((e) => { }).catch((e) => {
log.error(`----- fakeServer getServerPromise error: ${hostname}:${port}, error:`, e) log.error(`----- fakeServer getServerPromise error: ${hostname}:${port}, error:`, e)
}) })
} else { }
else {
log.info(`不拦截请求,直连目标服务器: ${hostname}:${port}, headers:`, jsonApi.stringify2(req.headers)) log.info(`不拦截请求,直连目标服务器: ${hostname}:${port}, headers:`, jsonApi.stringify2(req.headers))
connect(req, cltSocket, head, hostname, port, dnsConfig, true) connect(req, cltSocket, head, hostname, port, dnsConfig, true)
} }
@ -117,7 +118,8 @@ function connect (req, cltSocket, head, hostname, port, dnsConfig = null, isDire
const proxySocket = net.connect(options, () => { const proxySocket = net.connect(options, () => {
if (!isDirect) { if (!isDirect) {
log.info('Proxy connect start:', hostport) log.info('Proxy connect start:', hostport)
} else { }
else {
log.debug('Direct connect start:', hostport) log.debug('Direct connect start:', hostport)
} }
@ -190,7 +192,8 @@ function connect (req, cltSocket, head, hostname, port, dnsConfig = null, isDire
} }
return proxySocket return proxySocket
} catch (e) { }
catch (e) {
log.error(`${isDirect ? '直连' : '代理连接'}错误: ${hostport}, error:`, e) log.error(`${isDirect ? '直连' : '代理连接'}错误: ${hostport}, error:`, e)
} }
} }

View File

@ -1,4 +1,4 @@
const fs = require('fs') const fs = require('node:fs')
const forge = require('node-forge') const forge = require('node-forge')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const FakeServersCenter = require('../tls/FakeServersCenter') const FakeServersCenter = require('../tls/FakeServersCenter')
@ -20,7 +20,8 @@ module.exports = function createFakeServerCenter ({
const caKeyPem = fs.readFileSync(caKeyPath) const caKeyPem = fs.readFileSync(caKeyPath)
caCert = forge.pki.certificateFromPem(caCertPem) caCert = forge.pki.certificateFromPem(caCertPem)
caKey = forge.pki.privateKeyFromPem(caKeyPem) caKey = forge.pki.privateKeyFromPem(caKeyPem)
} catch (e) { }
catch (e) {
log.error('Can not find `CA certificate` or `CA key`:', e) log.error('Can not find `CA certificate` or `CA key`:', e)
process.exit(1) process.exit(1)
} }

View File

@ -1,5 +1,5 @@
const http = require('http') const http = require('node:http')
const https = require('https') const https = require('node:https')
const jsonApi = require('../../../json') const jsonApi = require('../../../json')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const RequestCounter = require('../../choice/RequestCounter') const RequestCounter = require('../../choice/RequestCounter')
@ -23,9 +23,11 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
if (rOptions.headers.connection === 'close') { if (rOptions.headers.connection === 'close') {
req.socket.setKeepAlive(false) req.socket.setKeepAlive(false)
} else if (rOptions.customSocketId != null) { // for NTLM }
else if (rOptions.customSocketId != null) { // for NTLM
req.socket.setKeepAlive(true, 60 * 60 * 1000) req.socket.setKeepAlive(true, 60 * 60 * 1000)
} else { }
else {
req.socket.setKeepAlive(true, 30000) req.socket.setKeepAlive(true, 30000)
} }
const context = { const context = {
@ -71,10 +73,12 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
} }
} }
next() next()
} else { }
else {
next() next()
} }
} catch (e) { }
catch (e) {
reject(e) reject(e)
} }
}) })
@ -125,10 +129,12 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
rOptions.lookup = dnsLookup.createLookupFunc(res, dns, 'request url', url, isDnsIntercept) rOptions.lookup = dnsLookup.createLookupFunc(res, dns, 'request url', url, isDnsIntercept)
log.debug(`域名 ${rOptions.hostname} DNS: ${dns.name}`) log.debug(`域名 ${rOptions.hostname} DNS: ${dns.name}`)
res.setHeader('DS-DNS', dns.name) res.setHeader('DS-DNS', dns.name)
} else { }
else {
log.info(`域名 ${rOptions.hostname} 在DNS中未配置`) log.info(`域名 ${rOptions.hostname} 在DNS中未配置`)
} }
} else { }
else {
log.info(`域名 ${rOptions.hostname} DNS配置不存在`) log.info(`域名 ${rOptions.hostname} DNS配置不存在`)
} }
@ -157,7 +163,8 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
const cost = new Date() - start const cost = new Date() - start
if (rOptions.protocol === 'https:') { if (rOptions.protocol === 'https:') {
log.info(`代理请求返回: 【${proxyRes.statusCode}${url}, cost: ${cost} ms`) log.info(`代理请求返回: 【${proxyRes.statusCode}${url}, cost: ${cost} ms`)
} else { }
else {
log.info(`请求返回: 【${proxyRes.statusCode}${url}, cost: ${cost} ms`) log.info(`请求返回: 【${proxyRes.statusCode}${url}, cost: ${cost} ms`)
} }
// console.log('request:', proxyReq, proxyReq.socket) // console.log('request:', proxyReq, proxyReq.socket)
@ -284,7 +291,8 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
if (append.body) { if (append.body) {
body += append.body body += append.body
} }
} else if (append === false) { }
else if (append === false) {
break // 返回false表示终止拦截器跳出循环 break // 返回false表示终止拦截器跳出循环
} }
} }
@ -292,10 +300,12 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
head, head,
body, body,
}) })
} else { }
else {
next() next()
} }
} catch (e) { }
catch (e) {
reject(e) reject(e)
} }
}) })
@ -331,13 +341,15 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
目标网站请求错误${e.code} ${e.message}<br/> 目标网站请求错误${e.code} ${e.message}<br/>
目标地址${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`, 目标地址${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`,
) )
} catch (e) { }
catch (e) {
// do nothing // do nothing
} }
try { try {
res.end() res.end()
} catch (e) { }
catch (e) {
// do nothing // do nothing
} }

View File

@ -1,5 +1,5 @@
const http = require('http') const http = require('node:http')
const https = require('https') const https = require('node:https')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const util = require('../common/util') const util = require('../common/util')

View File

@ -1,4 +1,4 @@
const defaultDns = require('dns') const defaultDns = require('node:dns')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const speedTest = require('../../speed') const speedTest = require('../../speed')
@ -17,7 +17,8 @@ module.exports = {
} }
callback(null, aliveIpObj.host, 4) callback(null, aliveIpObj.host, 4)
return return
} else { }
else {
log.info(`----- ${action}: ${hostname}, no alive ip${target}, tester: { "ready": ${tester.ready}, "backupList": ${JSON.stringify(tester.backupList)} }`) log.info(`----- ${action}: ${hostname}, no alive ip${target}, tester: { "ready": ${tester.ready}, "backupList": ${JSON.stringify(tester.backupList)} }`)
} }
} }
@ -49,11 +50,13 @@ module.exports = {
} }
callback(null, ip, 4) callback(null, ip, 4)
return return
} else { }
else {
// 使用默认dns // 使用默认dns
log.info(`----- ${action}: ${hostname}, use hostname by default DNS: ${hostname}, skip test failed ip from dns '${dns.name}: ${ip}'${target}, options:`, options) log.info(`----- ${action}: ${hostname}, use hostname by default DNS: ${hostname}, skip test failed ip from dns '${dns.name}: ${ip}'${target}, options:`, options)
} }
} else { }
else {
// 使用默认dns // 使用默认dns
log.info(`----- ${action}: ${hostname}, use hostname by default DNS: ${hostname}${target}, options:`, options, ', dns:', dns) log.info(`----- ${action}: ${hostname}, use hostname by default DNS: ${hostname}${target}, options:`, options, ', dns:', dns)
} }

View File

@ -1,4 +1,4 @@
const http = require('http') const http = require('node:http')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const speedTest = require('../../speed/index.js') const speedTest = require('../../speed/index.js')
const config = require('../common/config') const config = require('../common/config')
@ -104,7 +104,8 @@ module.exports = {
server.on('upgrade', (req, cltSocket, head) => { server.on('upgrade', (req, cltSocket, head) => {
if (printDebugLog) { if (printDebugLog) {
log.debug(`【server upgrade, ssl: ${ssl}\r\n----- req -----\r\n`, req) log.debug(`【server upgrade, ssl: ${ssl}\r\n----- req -----\r\n`, req)
} else { }
else {
log.info(`【server upgrade, ssl: ${ssl}`, req.url) log.info(`【server upgrade, ssl: ${ssl}`, req.url)
} }
upgradeHandler(req, cltSocket, head, ssl) upgradeHandler(req, cltSocket, head, ssl)

View File

@ -73,7 +73,8 @@ module.exports = class CertAndKeyContainer {
if (fast) { if (fast) {
certObj = tlsUtils.createFakeCertificateByDomain(this.caKey, this.caCert, hostname) certObj = tlsUtils.createFakeCertificateByDomain(this.caKey, this.caCert, hostname)
_resolve(certObj) _resolve(certObj)
} else { }
else {
// 这个太慢了 // 这个太慢了
// const preReq = https.request({ // const preReq = https.request({
// port: port, // port: port,

View File

@ -1,12 +1,12 @@
const http = require('http') const http = require('node:http')
const https = require('https') const https = require('node:https')
const forge = require('node-forge') const forge = require('node-forge')
const CertAndKeyContainer = require('./CertAndKeyContainer') const CertAndKeyContainer = require('./CertAndKeyContainer')
const tlsUtils = require('./tlsUtils') const tlsUtils = require('./tlsUtils')
const pki = forge.pki const pki = forge.pki
// const colors = require('colors') // const colors = require('colors')
const tls = require('tls') const tls = require('node:tls')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const compatible = require('../compatible/compatible') const compatible = require('../compatible/compatible')
@ -38,7 +38,8 @@ module.exports = class FakeServersCenter {
try { try {
log.info('超过最大服务数量删除旧服务。delServerObj:', delServerObj) log.info('超过最大服务数量删除旧服务。delServerObj:', delServerObj)
delServerObj.serverObj.server.close() delServerObj.serverObj.server.close()
} catch (e) { }
catch (e) {
log.error('`delServerObj.serverObj.server.close()` error:', e) log.error('`delServerObj.serverObj.server.close()` error:', e)
} }
} }
@ -49,7 +50,8 @@ module.exports = class FakeServersCenter {
getServerPromise (hostname, port, ssl, manualCompatibleConfig) { getServerPromise (hostname, port, ssl, manualCompatibleConfig) {
if (port === 443 || port === 80) { if (port === 443 || port === 80) {
ssl = port === 443 ssl = port === 443
} else if (ssl) { }
else if (ssl) {
// 自动兼容程序1 // 自动兼容程序1
const compatibleConfig = compatible.getConnectCompatibleConfig(hostname, port, manualCompatibleConfig) const compatibleConfig = compatible.getConnectCompatibleConfig(hostname, port, manualCompatibleConfig)
if (compatibleConfig && compatibleConfig.ssl != null) { if (compatibleConfig && compatibleConfig.ssl != null) {
@ -105,7 +107,8 @@ module.exports = class FakeServersCenter {
})() })()
}, },
}) })
} else { }
else {
fakeServer = new http.Server() fakeServer = new http.Server()
} }
const serverObj = { const serverObj = {
@ -146,7 +149,8 @@ module.exports = class FakeServersCenter {
fakeServer.on('upgrade', (req, socket, head) => { fakeServer.on('upgrade', (req, socket, head) => {
if (printDebugLog) { if (printDebugLog) {
log.debug(`【fakeServer upgrade - ${hostname}:${port}\r\n----- req -----\r\n`, req, '\r\n----- socket -----\r\n', socket, '\r\n----- head -----\r\n', head) log.debug(`【fakeServer upgrade - ${hostname}:${port}\r\n----- req -----\r\n`, req, '\r\n----- socket -----\r\n', socket, '\r\n----- head -----\r\n', head)
} else { }
else {
log.info(`【fakeServer upgrade - ${hostname}:${port}`, req.url) log.info(`【fakeServer upgrade - ${hostname}:${port}`, req.url)
} }
this.upgradeHandler(req, socket, head, ssl) this.upgradeHandler(req, socket, head, ssl)
@ -165,7 +169,8 @@ module.exports = class FakeServersCenter {
if (ssl === true && err.code.indexOf('ERR_SSL_') === 0) { if (ssl === true && err.code.indexOf('ERR_SSL_') === 0) {
compatible.setConnectSsl(hostname, port, false) compatible.setConnectSsl(hostname, port, false)
log.error(`自动兼容程序SSL异常现设置为禁用ssl: ${hostname}:${port}, ssl = false`) log.error(`自动兼容程序SSL异常现设置为禁用ssl: ${hostname}:${port}, ssl = false`)
} else if (ssl === false && err.code === 'HPE_INVALID_METHOD') { }
else if (ssl === false && err.code === 'HPE_INVALID_METHOD') {
compatible.setConnectSsl(hostname, port, true) compatible.setConnectSsl(hostname, port, true)
log.error(`自动兼容程序:${err.code}现设置为启用ssl: ${hostname}:${port}, ssl = true`) log.error(`自动兼容程序:${err.code}现设置为启用ssl: ${hostname}:${port}, ssl = true`)
} }

View File

@ -172,11 +172,13 @@ module.exports = function extractSNI (data) {
end: n + nameLength, end: n + nameLength,
length: nameLength, length: nameLength,
} }
} else { }
else {
n += nameLength n += nameLength
} }
} }
} else { // ExtensionType was something we are not interested in }
else { // ExtensionType was something we are not interested in
pos += extensionSize pos += extensionSize
} }
} }

View File

@ -1,5 +1,5 @@
const fs = require('fs') const fs = require('node:fs')
const path = require('path') const path = require('node:path')
const _ = require('lodash') const _ = require('lodash')
const forge = require('node-forge') const forge = require('node-forge')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
@ -244,7 +244,8 @@ utils.initCA = function ({ caCertPath, caKeyPath }) {
caKeyPath, caKeyPath,
create: false, create: false,
} }
} catch (e) { }
catch (e) {
const caObj = utils.createCA(config.caName) const caObj = utils.createCA(config.caName)
const caCert = caObj.cert const caCert = caObj.cert

Some files were not shown because too many files have changed in this diff Show More