├── .github ├── ISSUE_TEMPLATE │ ├── 1_BUG_REPORT.md │ ├── 2_STYLE_ISSUE.md │ ├── 3_CONFIG_ISSUES.md │ ├── 4_FEATURE_REQUEST.md │ └── 5_OTHERS.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── build-and-release.yml │ ├── npm-run-electron.yml │ └── test-and-upload.yml ├── .gitignore ├── .npmrc ├── LICENSE ├── README.md ├── _script ├── 0、updateDependencies.bat ├── 1、setupEnv.bat ├── 2、installProject.bat ├── 3、buildAndRun.bat ├── 4.1、runTestCore.bat ├── 4.2、runTestMitmproxy.bat └── 5、generateSetupFile.bat ├── doc ├── Firefox │ ├── 1.png │ ├── 2.png │ └── 3.png ├── avatar1.png ├── avatar2.png ├── caroot.md ├── chatgpt2.png ├── clone-before.png ├── clone.png ├── crt-error.png ├── download-before.png ├── download.png ├── flow.jpg ├── gitee.png ├── index.png ├── linux.md ├── log.png ├── mac-proxy.png ├── me.png ├── other.md ├── proxy.png ├── qq_group.png ├── recover.md ├── setup.png ├── speed.png └── wiki │ ├── Home.md │ ├── 加速服务使用说明.md │ ├── 各平台安装说明.md │ └── 解决Github访问不了或速度很慢的问题.md ├── eslint.config.js ├── package.json ├── packages ├── cli │ ├── LICENSE │ ├── cli.js │ ├── package.json │ └── src │ │ ├── banner.txt │ │ ├── index.js │ │ ├── mitmproxy.js │ │ └── user_config.json5 ├── core │ ├── LICENSE │ ├── index.js │ ├── package.json │ ├── src │ │ ├── config-api.js │ │ ├── config │ │ │ ├── index.js │ │ │ ├── local-config-loader.js │ │ │ └── remote_config.json5 │ │ ├── event.js │ │ ├── expose.js │ │ ├── index.js │ │ ├── merge.js │ │ ├── modules │ │ │ ├── index.js │ │ │ ├── plugin │ │ │ │ ├── git │ │ │ │ │ ├── config.js │ │ │ │ │ └── index.js │ │ │ │ ├── index.js │ │ │ │ ├── node │ │ │ │ │ ├── config.js │ │ │ │ │ └── index.js │ │ │ │ ├── overwall │ │ │ │ │ ├── config.js │ │ │ │ │ └── index.js │ │ │ │ └── pip │ │ │ │ │ ├── config.js │ │ │ │ │ └── index.js │ │ │ ├── proxy │ │ │ │ └── index.js │ │ │ └── server │ │ │ │ └── index.js │ │ ├── shell │ │ │ ├── index.js │ │ │ ├── scripts │ │ │ │ ├── enable-loopback.js │ │ │ │ ├── extra-path │ │ │ │ │ ├── EnableLoopback.exe │ │ │ │ │ ├── index.js │ │ │ │ │ └── sysproxy.exe │ │ │ │ ├── get-npm-env.js │ │ │ │ ├── get-system-env.js │ │ │ │ ├── kill-by-port.js │ │ │ │ ├── set-npm-env.js │ │ │ │ ├── set-system-env.js │ │ │ │ ├── set-system-proxy │ │ │ │ │ ├── index.js │ │ │ │ │ └── refresh-internet.js │ │ │ │ └── setup-ca.js │ │ │ └── shell.js │ │ ├── status.js │ │ └── utils │ │ │ ├── util.date.js │ │ │ ├── util.log-or-console.js │ │ │ ├── util.log.core.js │ │ │ ├── util.logger.js │ │ │ └── util.version.js │ └── test │ │ ├── configTest.js │ │ ├── httpsVerifyTest.js │ │ ├── macProxyTest.js │ │ ├── mergeTest.js │ │ ├── regex.test.js │ │ ├── requestTest.js │ │ └── versionTest.js ├── gui │ ├── .editorconfig │ ├── .env │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── babel.config.js │ ├── build │ │ ├── icons │ │ │ ├── 0x0.png │ │ │ ├── 1024x1024.png │ │ │ ├── 128x128.png │ │ │ ├── 16x16.png │ │ │ ├── 24x24.png │ │ │ ├── 256x256.png │ │ │ ├── 32x32.png │ │ │ ├── 32x32@2x.png │ │ │ ├── 48x48.png │ │ │ ├── 512x512.png │ │ │ ├── 64x64.png │ │ │ ├── icon.icns │ │ │ └── icon.ico │ │ └── mac │ │ │ ├── 0x0.png │ │ │ ├── 1024x1024.png │ │ │ ├── 128x128.png │ │ │ ├── 16x16.png │ │ │ ├── 24x24.png │ │ │ ├── 256x256.png │ │ │ ├── 32x32.png │ │ │ ├── 48x48.png │ │ │ ├── 512x512.png │ │ │ ├── 64x64.png │ │ │ ├── icon.icns │ │ │ └── icon.ico │ ├── extra │ │ ├── EnableLoopback.exe │ │ ├── favicon.ico │ │ ├── icons │ │ │ ├── 1024x1024.png │ │ │ ├── 128x128.png │ │ │ ├── 16x16-black.png │ │ │ ├── 16x16.png │ │ │ ├── 24x24.png │ │ │ ├── 256x256.png │ │ │ ├── 32x32.png │ │ │ ├── 48x48.png │ │ │ ├── 512x512.png │ │ │ ├── 64x64.png │ │ │ ├── icon.icns │ │ │ ├── icon.ico │ │ │ ├── tray-icon.png │ │ │ └── tray │ │ │ │ ├── icon-black.png │ │ │ │ ├── icon-black@2x.png │ │ │ │ ├── icon-black@3x.png │ │ │ │ ├── icon-white.png │ │ │ │ ├── icon-white@2x.png │ │ │ │ ├── icon-white@3x.png │ │ │ │ ├── icon.png │ │ │ │ ├── icon@2x.png │ │ │ │ └── icon@3x.png │ │ ├── pac │ │ │ └── pac.txt │ │ ├── proxy │ │ │ └── domestic-domain-allowlist.txt │ │ ├── scripts │ │ │ ├── github.script │ │ │ ├── google.js │ │ │ └── tampermonkey.script │ │ └── sysproxy.exe │ ├── package.json │ ├── pkg │ │ ├── after-all-artifact-build.js │ │ └── after-pack.js │ ├── public │ │ ├── 256x256.png │ │ ├── favicon.ico │ │ ├── icon-1.png │ │ ├── icon.png │ │ ├── icon2.png │ │ ├── index.html │ │ ├── loading-spin.svg │ │ ├── logo │ │ │ ├── logo-1.svg │ │ │ ├── logo-fff.svg │ │ │ ├── logo-lang-light.svg │ │ │ ├── logo-lang.svg │ │ │ ├── logo-only.png │ │ │ ├── logo-only.svg │ │ │ ├── logo-only2.png │ │ │ ├── logo-only4.png │ │ │ ├── logo-simple-fan.svg │ │ │ ├── logo-simple.svg │ │ │ ├── logo-simple2.png │ │ │ ├── logo-text.svg │ │ │ ├── logo.svg │ │ │ ├── mac.png │ │ │ ├── mac.svg │ │ │ ├── win-16.svg │ │ │ ├── win-black.png │ │ │ ├── win.png │ │ │ └── win.svg │ │ ├── loopback.png │ │ ├── setup-linux.png │ │ ├── setup-mac.png │ │ └── setup.png │ ├── src │ │ ├── background.js │ │ ├── background │ │ │ └── powerMonitor.js │ │ ├── bridge │ │ │ ├── api │ │ │ │ ├── backend.js │ │ │ │ └── open-enable-loopback.js │ │ │ ├── auto-start │ │ │ │ ├── backend.js │ │ │ │ └── front.js │ │ │ ├── backend.js │ │ │ ├── error │ │ │ │ └── front.js │ │ │ ├── file-selector │ │ │ │ ├── backend.js │ │ │ │ └── front.js │ │ │ ├── front.js │ │ │ ├── mitmproxy.js │ │ │ ├── on-close │ │ │ │ └── front.js │ │ │ ├── tongji │ │ │ │ ├── backend.js │ │ │ │ └── front.js │ │ │ └── update │ │ │ │ ├── backend.js │ │ │ │ └── front.js │ │ ├── main.js │ │ ├── utils │ │ │ ├── util.apppath.js │ │ │ └── util.log.gui.js │ │ └── view │ │ │ ├── App.vue │ │ │ ├── api.js │ │ │ ├── components │ │ │ ├── container.vue │ │ │ ├── mock-input.vue │ │ │ ├── setup-ca.vue │ │ │ └── tree-node.vue │ │ │ ├── composables │ │ │ └── theme.js │ │ │ ├── index.js │ │ │ ├── mixins │ │ │ └── plugin.js │ │ │ ├── pages │ │ │ ├── help.vue │ │ │ ├── index.vue │ │ │ ├── plugin │ │ │ │ ├── git.vue │ │ │ │ ├── node.vue │ │ │ │ ├── overwall.vue │ │ │ │ └── pip.vue │ │ │ ├── proxy.vue │ │ │ ├── server.vue │ │ │ └── setting.vue │ │ │ ├── router │ │ │ ├── index.js │ │ │ └── menu.js │ │ │ ├── status.js │ │ │ └── style │ │ │ ├── index.scss │ │ │ └── theme │ │ │ └── dark.scss │ └── vue.config.js └── mitmproxy │ ├── LICENSE │ ├── index.js │ ├── package.json │ ├── src │ ├── index.js │ ├── json.js │ ├── lib │ │ ├── choice │ │ │ ├── RequestCounter.js │ │ │ └── index.js │ │ ├── dns │ │ │ ├── base.js │ │ │ ├── https.js │ │ │ ├── index.js │ │ │ ├── preset.js │ │ │ ├── tcp.js │ │ │ ├── tls.js │ │ │ └── udp.js │ │ ├── interceptor │ │ │ ├── impl │ │ │ │ ├── req │ │ │ │ │ ├── OPTIONS.js │ │ │ │ │ ├── abort.js │ │ │ │ │ ├── baiduOcr.js │ │ │ │ │ ├── cacheRequest.js │ │ │ │ │ ├── proxy.js │ │ │ │ │ ├── redirect.js │ │ │ │ │ ├── requestReplace.js │ │ │ │ │ ├── sni.js │ │ │ │ │ ├── success.js │ │ │ │ │ └── unVerifySsl.js │ │ │ │ └── res │ │ │ │ │ ├── AfterOPTIONSHeaders.js │ │ │ │ │ ├── cacheResponse.js │ │ │ │ │ ├── responseReplace.js │ │ │ │ │ └── script.js │ │ │ └── index.js │ │ ├── monkey │ │ │ └── index.js │ │ ├── proxy │ │ │ ├── common │ │ │ │ ├── ProxyHttpAgent.js │ │ │ │ ├── ProxyHttpsAgent.js │ │ │ │ ├── config.js │ │ │ │ └── util.js │ │ │ ├── compatible │ │ │ │ └── compatible.js │ │ │ ├── index.js │ │ │ ├── middleware │ │ │ │ ├── InsertScriptMiddleware.js │ │ │ │ ├── overwall.js │ │ │ │ └── source │ │ │ │ │ └── pac.js │ │ │ ├── mitmproxy │ │ │ │ ├── createConnectHandler.js │ │ │ │ ├── createFakeServerCenter.js │ │ │ │ ├── createRequestHandler.js │ │ │ │ ├── createUpgradeHandler.js │ │ │ │ ├── dnsLookup.js │ │ │ │ └── index.js │ │ │ └── tls │ │ │ │ ├── CertAndKeyContainer.js │ │ │ │ ├── FakeServersCenter.js │ │ │ │ ├── sniUtil.js │ │ │ │ └── tlsUtils.js │ │ └── speed │ │ │ ├── SpeedTester.js │ │ │ ├── config.js │ │ │ └── index.js │ ├── options.js │ └── utils │ │ ├── util.js │ │ ├── util.log.server.js │ │ ├── util.match.js │ │ └── util.process.js │ └── test │ ├── baiduOcrTest.js │ ├── dnsSpeedTest.js │ ├── dnsTest.mjs │ ├── lodashTest.js │ ├── matchTest.js │ ├── matchUtilTest.js │ ├── monkeyTest.js │ ├── pacTest.js │ ├── proxyTest.js │ ├── responseReplaceTest.js │ ├── sha256Test.js │ └── utilTest.js ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── test ├── test.js └── testDns.js /.github/ISSUE_TEMPLATE/1_BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 问题上报 3 | about: 如果你在使用过程中发现问题,请使用此模板。 4 | labels: Bug 5 | --- 6 | 7 | 8 | 9 | - [ ] 你是否在现有 [Issue列表](/docmirror/dev-sidecar/issues) 中搜索过相同问题,但未找到? 10 | 11 | ### Ⅰ. 请说明操作系统及DS的版本号: 12 | 13 | 1. 操作系统:? 14 | 2. DS版本号:? 15 | 16 | ### Ⅱ. 问题描述: 17 | 18 | ### Ⅲ. 期望的结果: 19 | 20 | ### Ⅳ. 如何复现问题? 21 | 22 | 1. xxx 23 | 2. xxx 24 | 3. xxx 25 | 26 | ### Ⅴ. 请提供相关的错误日志,尽可能的详细:(日志文件在 `${user.home}/.dev-sidecar/logs/` 目录下) 27 | 28 |
29 | 点击查看日志 30 | 31 | ```log 32 | 33 | ``` 34 |
35 | 36 | ### Ⅵ. 有必要时,请提供 `${user.home}/.dev-sidecar/running.json` 文件内容: 37 | 38 | 39 | 40 |
41 | 点击查看运行参数 42 | 43 | ```json 44 | 45 | ``` 46 |
47 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2_STYLE_ISSUE.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 样式问题 3 | about: 如果你发现了一些页面样式问题,请使用此模板。 4 | labels: Style Issue 5 | --- 6 | 7 | 8 | 9 | - [ ] 你是否在现有 [Issue列表](/docmirror/dev-sidecar/issues) 中搜索过相同问题,但未找到? 10 | 11 | ### Ⅰ. 请说明操作系统及DS的版本号: 12 | 13 | 1. 操作系统:? 14 | 2. DS版本号:? 15 | 16 | ### Ⅱ. 样式问题描述: 17 | 18 | ### Ⅲ. 样式问题截图: 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3_CONFIG_ISSUES.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 配置问题 3 | about: 如果你不知道如何配置DS来访问某个网站,请使用这个模板。 4 | labels: Config Issue 5 | --- 6 | 7 | ### Ⅰ. 你对哪个功能的配置不了解? 8 | 9 | 10 | 11 | - [ ] 拦截设置: 12 | - [ ] redirect 13 | - [ ] proxy 14 | - [ ] sni 15 | - [ ] success 16 | - [ ] abort 17 | - [ ] cache 18 | - [ ] options 19 | - [ ] script 20 | - [ ] requestReplace 21 | - [ ] responseReplace 22 | - [ ] DNS设置和IP测速 23 | - [ ] 系统代理 24 | - [ ] 远程配置 25 | - [ ] 应用: 26 | - [ ] NPM加速 27 | - [ ] Git代理 28 | - [ ] PIP加速 29 | - [ ] 增强功能 30 | 31 | ### Ⅱ. 请详细描述你的问题: 32 | 33 | ### Ⅲ. 有必要时,请提供 `${user.home}/.dev-sidecar/running.json` 文件内容: 34 | 35 | 36 | 37 |
38 | 点击查看运行参数 39 | 40 | ```json 41 | 42 | ``` 43 |
44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/4_FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 提新需求 3 | about: 如果你想提出一个新需求,请使用此模板。 4 | labels: Feature Request 5 | --- 6 | 7 | ### Ⅰ. 请描述你想要的新功能: 8 | 9 | 10 | 11 | ### Ⅱ. 请描述你心目中新功能的样子: 12 | 13 | 14 | 15 | ### Ⅲ. 你希望该新功能修复哪个issue? 16 | 17 | 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/5_OTHERS.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 其他问题 3 | about: 如果不是以上问题,请使用此模板。 4 | --- 5 | 6 | ### 请详细描述你的问题、需求或建议: 7 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Ⅰ. 描述此PR的作用: 2 | 3 | ### Ⅱ. 此PR修复了哪个issue吗? 4 | 5 | 6 | 7 | ### Ⅲ. 界面变化截屏 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliJ project files 2 | .idea 3 | *.iml 4 | 5 | # vscode settings files 6 | .vscode 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # Node files 12 | node_modules/ 13 | *.lock 14 | package-lock.json 15 | 16 | # Other files 17 | out 18 | gen 19 | *.log 20 | *.lnk 21 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | -------------------------------------------------------------------------------- /_script/0、updateDependencies.bat: -------------------------------------------------------------------------------- 1 | node -v 2 | 3 | # 安装ncu 4 | # npm install -g npm-check-updates 5 | 6 | cd ../packages/core 7 | ncu -u 8 | 9 | # cd ../packages/gui 10 | # ncu -u 11 | 12 | # cd ../packages/mitmproxy 13 | # ncu -u 14 | -------------------------------------------------------------------------------- /_script/1、setupEnv.bat: -------------------------------------------------------------------------------- 1 | node -v 2 | 3 | cd ../ 4 | npm install -g pnpm --registry=https://registry.npmmirror.com 5 | -------------------------------------------------------------------------------- /_script/2、installProject.bat: -------------------------------------------------------------------------------- 1 | node -v 2 | 3 | cd ../ 4 | chcp 65001 5 | pnpm install 6 | -------------------------------------------------------------------------------- /_script/3、buildAndRun.bat: -------------------------------------------------------------------------------- 1 | node -v 2 | 3 | cd ../packages/gui 4 | chcp 65001 5 | npm run electron 6 | -------------------------------------------------------------------------------- /_script/4.1、runTestCore.bat: -------------------------------------------------------------------------------- 1 | node -v 2 | 3 | cd ../packages/core 4 | pnpm run test 5 | -------------------------------------------------------------------------------- /_script/4.2、runTestMitmproxy.bat: -------------------------------------------------------------------------------- 1 | node -v 2 | 3 | cd ../packages/mitmproxy 4 | pnpm run test 5 | -------------------------------------------------------------------------------- /_script/5、generateSetupFile.bat: -------------------------------------------------------------------------------- 1 | node -v 2 | 3 | cd ../packages/gui 4 | 5 | if not exist "dist_electron" mkdir "dist_electron" 6 | start dist_electron 7 | 8 | npm run electron:build 9 | -------------------------------------------------------------------------------- /doc/Firefox/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/Firefox/1.png -------------------------------------------------------------------------------- /doc/Firefox/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/Firefox/2.png -------------------------------------------------------------------------------- /doc/Firefox/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/Firefox/3.png -------------------------------------------------------------------------------- /doc/avatar1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/avatar1.png -------------------------------------------------------------------------------- /doc/avatar2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/avatar2.png -------------------------------------------------------------------------------- /doc/caroot.md: -------------------------------------------------------------------------------- 1 | # 关于信任根证书的说明 2 | 3 | ## 一、为什么要信任根证书。 4 | 5 | 要回答这个问题需要先掌握下面两个知识点 6 | 7 | ### 知识点1:什么是根证书 8 | 9 | [百度百科-什么是根证书](https://baike.baidu.com/item/%E6%A0%B9%E8%AF%81%E4%B9%A6/9874620?fr=aladdin) 10 | 11 | 当访问目标网站是https协议时,服务器会发送一个由根证书签发的网站ssl证书给浏览器,让浏览器用这个ssl证书给数据加密。 12 | 浏览器需要先验证这个证书的真伪,之后才会使用证书加密。 13 | 证书的真伪是通过验证证书的签发机构的证书是否可信,一直追溯到最初始的签发机构的证书(根证书)。 14 | 浏览器只需信任根证书,间接的就信任了这条证书链下签发的所有证书。 15 | 16 | windows、mac、linux或者浏览器他们都内置了市面上可信的大型证书颁发机构的根证书。 17 | 18 | ### 知识点2:中间人攻击 19 | 20 | 本应用的实现原理如下图: 21 | 22 | ![](./flow.jpg) 23 | 24 | > 简单来说就是DevSidecar在本地启动了一个代理服务器帮你访问目标网站。 25 | > 实际上就是 [中间人攻击](https://baike.baidu.com/item/%E4%B8%AD%E9%97%B4%E4%BA%BA%E6%94%BB%E5%87%BB/1739730?fr=aladdin) 的原理,只是本应用没有用它来干坏事,而是帮助开发者加速目标网站的访问。 26 | 27 | ### 现在可以回答为什么要信任根证书 28 | 29 | 当目标网站不需要加速拦截时,直接走TCP转发,不需要中间人攻击,没有安全风险,在此不多做讨论。 30 | 31 | 当目标网站需要拦截时(例如github),就需要通过中间人攻击修改请求或者请求其他替代网站,从而达到加速的目的。 32 | 33 | 例如加速github就需要修改如下几处 34 | 35 | 1. 直连访问github需要修改tls握手时的sni域名,规避\*\*\*的sni阻断问题。 36 | 2. asserts.github.com等静态资源拦截替换成fastgit.org的镜像地址 37 | 38 | DevSidecar在第一次启动时会在本地随机生成一份根证书,当有用户访问github时,就用这份根证书来签发一份假的叫github.com的证书。 39 | 如果浏览器事先信任了这份根证书,那么就可以正常访问DevSidecar返回的网页内容了。 40 | 41 | ## 二、信任根证书有安全风险吗 42 | 43 | 1. 根证书是DevSidecar第一次启动时本地随机生成的,除了你这台电脑没人知道这份根证书的内容。 44 | 2. 代理请求目标网站时会校验目标网站的证书(除非关闭了`代理校验ssl`)。 45 | 46 | > 两段链路都是安全的,所以信任根证书没有问题。 47 | > 但如果应用本身来源不明,或者`拦截配置`里的替代网站作恶,则有安全风险。 48 | 49 | > 对于应用来源风险: 50 | > 请勿从未知网站下载DevSidecar应用,认准官方版本发布地址 51 | > [Github Release](https://github.com/docmirror/dev-sidecar/releases) 52 | > 53 | > 或者从源码自行编译安装 54 | 55 | > 对于拦截配置里的替代网站风险: 56 | > 57 | > 1. 尽量缩小替代配置的范围 58 | > 2. 不使用来源不明的镜像地址,尽量使用知名度较高的镜像地址 59 | > 3. 你甚至可以将其他拦截配置全部删除,只保留github相关配置 60 | -------------------------------------------------------------------------------- /doc/chatgpt2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/chatgpt2.png -------------------------------------------------------------------------------- /doc/clone-before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/clone-before.png -------------------------------------------------------------------------------- /doc/clone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/clone.png -------------------------------------------------------------------------------- /doc/crt-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/crt-error.png -------------------------------------------------------------------------------- /doc/download-before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/download-before.png -------------------------------------------------------------------------------- /doc/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/download.png -------------------------------------------------------------------------------- /doc/flow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/flow.jpg -------------------------------------------------------------------------------- /doc/gitee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/gitee.png -------------------------------------------------------------------------------- /doc/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/index.png -------------------------------------------------------------------------------- /doc/linux.md: -------------------------------------------------------------------------------- 1 | # Linux 支持 2 | 3 | `Linux`使用说明,目前仅官方支持`Ubuntu x86_64 GNOME桌面版(原版)`,其他`Linux`未测试 4 | 5 | > 注意:需要开启 [sudo 免密支持](https://www.jianshu.com/p/5d02428f313d),否则请自行安装证书 6 | 7 | ## 一、安装 8 | 9 | ### 1.1. Ubuntu / Debian或其衍生版(未测试) 10 | 11 | - 下载`DevSidecar-x.x.x.deb` 12 | - 使用 root 执行命令安装 `dpkg -i DevSidecar-x.x.x.deb` 13 | - 去应用列表里面找到 dev-sidecar 应用,打开即可 14 | 15 | ### 1.2. 其他基于glibc的Linux系统(未测试) 16 | 17 | - 下载 `DevSidecar-x.x.x.AppImage` 18 | - 设置可执行权限 `chmod +x DevSidecar-x.x.x.AppImage` 19 | - 双击运行 20 | 21 | ### 1.3. 特殊的Linux系统(如Alpine和Chimera Linux) 22 | 23 | > 此处默认用户有较专业的Linux知识,故不详细描述,请参考并自行试验 24 | - 创建Debian(最方便且省空间)容器,可使用distrobox(推荐),接下来以此为例说明 25 | - 下载deb包并在容器内安装 26 | - 穿透系统设置: 27 | 在容器内 `/usr/bin/gsettings` 文件写入: 28 | 29 | ```bash 30 | #!/bin/sh 31 | distrobox-host-exec gsettings "$@" 32 | ``` 33 | 并设置可执行权限 34 | 35 | 简化版命令(请在容器内执行): 36 | ``` 37 | echo -e '#!/bin/sh\ndistrobox-host-exec gsettings "$@"' >/usr/bin/gsettings 38 | ``` 39 | - 使用命令启动应用,使用“自动安装证书”功能,回到终端,找到输出里含有 `sudo` 的两句命令,复制到主系统执行,如失败(或使用其他证书系统),请自行安装证书,可参考 [议题 #204](https://github.com/docmirror/dev-sidecar/issues/204) 40 | 41 | ### 1.4. 版本选择 42 | 43 | 不同CPU架构,选择对应的版本,如果安装失败,请下载 `universal` 版本 44 | 45 | 46 | ## 二、证书安装 47 | 48 | 默认模式和增强模式需要系统信任CA证书。 49 | 由于Linux上火狐和Chrome都不走系统证书,所以除了安装系统证书之外,还需要给浏览器安装证书 50 | 51 | ### 2.1. 系统证书安装 52 | 53 | 根据弹出的提示: 54 | 55 | - 点击首页右上角“安装根证书”按钮 56 | - 点击“点此去安装” 57 | - 提示安装成功即可 58 | 59 | ### 2.2. 火狐浏览器安装证书 60 | 61 | - 火狐浏览器->选项->隐私与安全->证书->查看证书 62 | - 证书颁发机构->导入 63 | - 选择证书文件在 `~/.dev-sidecar` 目录下 64 | - 勾选信任由此证书颁发机构来标识网站,确定即可 65 | 66 | ### 2.3. Chrome浏览器安装证书 67 | 68 | 证书文件目录为 `~/.dev-sidecar` 69 | 70 | ![](../packages/gui/public/setup-linux.png) 71 | -------------------------------------------------------------------------------- /doc/log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/log.png -------------------------------------------------------------------------------- /doc/mac-proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/mac-proxy.png -------------------------------------------------------------------------------- /doc/me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/me.png -------------------------------------------------------------------------------- /doc/other.md: -------------------------------------------------------------------------------- 1 | # 其他程序使用 2 | 3 | ## Java程序使用 4 | 5 | > 由 [Enaium](https://github.com/Enaium) 提供,未做验证,可供参考 6 | 7 | 1. 先通过keytool安装证书: 8 | 9 | ```shell 10 | keytool -import -alias dev-sidecar -keystore "jdk路径\security\cacerts" -file 用户目录\.dev-sidecar\dev-sidecar.ca.crt 11 | ``` 12 | 默认密码为 `changeit` 13 | 14 | 2. 启动时还需要设置参数,例: 15 | 16 | ```shell 17 | java -Dhttp.proxyHost=localhost -Dhttp.proxyPort=31181 -Dhttps.proxyHost=localhost -Dhttps.proxyPort=31181 -jar xxxx.jar 18 | ``` 19 | 20 | 3. Gradle还需在`用户目录/.gradle/gradle.properties`创建配置文件: 21 | 22 | ```properties 23 | systemProp.http.proxyHost=localhost 24 | systemProp.http.proxyPort=31181 25 | systemProp.https.proxyHost=localhost 26 | systemProp.https.proxyPort=31181 27 | ``` 28 | -------------------------------------------------------------------------------- /doc/proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/proxy.png -------------------------------------------------------------------------------- /doc/qq_group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/qq_group.png -------------------------------------------------------------------------------- /doc/recover.md: -------------------------------------------------------------------------------- 1 | # 卸载与恢复网络 2 | 3 | 由于应用启动后会自动设置系统代理,正常退出时会关闭系统代理。 4 | 当应用意外关闭,或者未正常退出后被卸载,此时会因为系统代理没有恢复从而导致完全上不了网。 5 | 目前electron在windows系统上无法监听系统重启事件。更多相关资料 [electron issues](https://github.com/electron/electron/pull/24261) 6 | 7 | ## 恢复代理设置 8 | 9 | ### 1、windows 代理关闭 10 | 11 | 如何打开查看windows代理设置: 12 | 13 | - win10: 开始->设置->网络和Internet->最下方代理 14 | - win7: 开始->控制面板->网络和Internet->网络和共享中心->左下角Internet选项->连接选项卡->局域网设置 15 | 16 | ![windows](./proxy.png) 17 | 18 | ### 2、mac 代理关闭 19 | 20 | 网络->网卡->代理->去掉http和https的两个勾 21 | 22 | ![](./mac-proxy.png) 23 | 24 | ### 3、Linux(Ubuntu) 25 | 26 | 网络->代理->选择禁用 27 | -------------------------------------------------------------------------------- /doc/setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/setup.png -------------------------------------------------------------------------------- /doc/speed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/doc/speed.png -------------------------------------------------------------------------------- /doc/wiki/Home.md: -------------------------------------------------------------------------------- 1 | > **给作者打个广告:**
2 | > [https://github.com/certd/certd](https://github.com/certd/certd) 我的开源证书管理工具项目,全自动申请和部署证书,有需求的可以去试试,帮忙点个star 3 | 4 | > 注:Wiki还在完善中,敬请期待更多内容。
5 | > 说明:以下文档均以最新版本进行编写,请下载最新版DS后,再参考以下文档使用!
6 | 7 | # 一、下载安装: 8 | 9 | 访问 https://github.com/docmirror/dev-sidecar/releases 页面,下载对应操作系统的安装程序进行安装。 10 | 11 | 如安装有问题,请查看 [各平台安装说明](https://github.com/docmirror/dev-sidecar/wiki/%E5%90%84%E5%B9%B3%E5%8F%B0%E5%AE%89%E8%A3%85%E8%AF%B4%E6%98%8E) 12 | 13 | # 二、功能使用说明: 14 | 15 | 1. [`加速服务`使用说明](https://github.com/docmirror/dev-sidecar/wiki/%E5%8A%A0%E9%80%9F%E6%9C%8D%E5%8A%A1%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E) 16 | 2. 系统代理使用说明: 17 | 3. 通用功能使用说明: 18 | 1. 开机自启动: 19 | 2. 远程配置: 20 | 3. 主题设置: 21 | 4. 窗口设置: 22 | 5. 检查更新: 23 | 4. 应用使用说明: 24 | 1. NPM加速: 25 | 2. Git.exe加速: 26 | 3. PIP加速: 27 | 4. 彩蛋(功能增强): 28 | 5. 帮助中心 29 | 6. 反馈问题 30 | 31 | # 三、解决问题: 32 | 33 | 1. [解决Github访问不了或速度很慢的问题](https://github.com/docmirror/dev-sidecar/wiki/%E8%A7%A3%E5%86%B3Github%E8%AE%BF%E9%97%AE%E4%B8%8D%E4%BA%86%E6%88%96%E9%80%9F%E5%BA%A6%E5%BE%88%E6%85%A2%E7%9A%84%E9%97%AE%E9%A2%98) 34 | 2. [Linux安装证书失败的避坑](https://github.com/docmirror/dev-sidecar/issues/238) 35 | 3. [解决Linux(deb)系统下无法安装根证书的问题](https://github.com/docmirror/dev-sidecar/issues/135) 36 | 4. [在Arch/Fedora下的证书安装](https://github.com/docmirror/dev-sidecar/issues/204) 37 | 5. [Mac安装:`无法打开“dev-sidecar”,因为无法验证开发者。` 的解决方案](https://github.com/docmirror/dev-sidecar/issues/147) 38 | 6. [在 WSL 中的使用方法](https://github.com/docmirror/dev-sidecar/issues/73) 39 | 40 | [> 点击前往Issue区查找更多帮助信息](https://github.com/docmirror/dev-sidecar/issues) 41 | 42 | # 四、DevSidecar技术交流群 43 | 44 | - QQ 1群:[390691483](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=hIG_VClE1CU2gHuLSSTaazMlo6M760iL&authKey=5VUMMwzH5FeabLDbZNZJbqmZk1gfmB%2B%2FlotO%2Brszz%2BW3E8xwKD2hTg2%2FV2LJEKL7&noverify=0&group_code=390691483),人数:496 / 500 45 | - 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),人数:488 / 500 46 | - QQ 3群:[419807815](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=zRkm0eHUhRmWWJA5O35C7BOKPZ4_gmrz&authKey=X9JHezR1BOalcEmvV6If04TN%2BIbzjAayBDaOSiuOg1SPpPguA7RqoLSHVEeo7A4e&noverify=0&group_code=419807815),人数:494 / 500 47 | - 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),人数:295 / 1000 48 | - 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),人数:068 / 200(new) 49 | 50 | # 五、版本更新日志 51 | 52 | https://github.com/docmirror/dev-sidecar/releases 53 | -------------------------------------------------------------------------------- /doc/wiki/各平台安装说明.md: -------------------------------------------------------------------------------- 1 | |平台|安装说明 | 2 | |---|---| 3 | | 【Windows】 | 下载后提示无法验证发行者时,选择保留即可
注意:开着ds重启电脑会导致无法上网,你可以再次打开ds,然后右键小图标退出ds即可。[更多说明](https://github.com/docmirror/dev-sidecar/issues/109)| 4 | | 【Mac】 |安装时提示无法验证开发者时,请先取消
然后去系统偏好设置->安全与隐私->下方已阻止使用DevSidecar
选择仍要打开 | 5 | | 【Ubuntu】 | [安装说明](https://github.com/docmirror/dev-sidecar/blob/master/doc/linux.md)| 6 | |【其他Linux】| | -------------------------------------------------------------------------------- /doc/wiki/解决Github访问不了或速度很慢的问题.md: -------------------------------------------------------------------------------- 1 | > 注:请使用 `v2.0.0-RC2` 及以上版本,下载地址:https://github.com/docmirror/dev-sidecar/releases 2 | 3 | 目前,Github通过预设置的IP来访问的,选取测速排在前的IP。 4 | 5 | 可是,虽然IP测速延迟很低,但是依然会存在不同地区访问部分预设IP不通或很慢的问题。 6 | 7 | 如果碰到此问题,可以通过将预设IP设置为 `false` 来禁用访问慢的IP,以此达到切换IP的目的,如下图: 8 | 如果访问还慢,再将测速排在第1的IP再禁用掉,以此循环,将访问慢的IP都禁掉,直到选取到的IP访问Github速度很快为止。 9 | 10 | > 假如:测速排第1的IP为 `20.27.177.113`,则将其配置为 `false`,或者删除该IP 11 | ![输入图片说明](https://foruda.gitee.com/images/1737713514504282222/96a679f9_1895865.png "屏幕截图") 12 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import antfu from '@antfu/eslint-config' 2 | 3 | export default antfu( 4 | { 5 | vue: { 6 | vueVersion: 2, 7 | }, 8 | rules: { 9 | 'style/brace-style': ['error', '1tbs'], 10 | 'style/space-before-function-paren': ['error', 'always'], 11 | 'import/newline-after-import': 'off', 12 | 'import/first': 'off', 13 | 'perfectionist/sort-imports': 'off', 14 | 'node/prefer-global/buffer': 'off', 15 | 'node/prefer-global/process': 'off', 16 | 'no-console': 'off', 17 | }, 18 | ignores: [ 19 | '**/build/*', 20 | '**/dist_electron', 21 | ], 22 | formatters: { 23 | css: true, 24 | html: true, 25 | markdown: 'prettier', 26 | }, 27 | }, 28 | ) 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dev-sidecar-parent", 3 | "type": "module", 4 | "private": false, 5 | "packageManager": "pnpm@9.13.2", 6 | "author": "Greper", 7 | "license": "MPL-2.0", 8 | "scripts": { 9 | "lint": "eslint .", 10 | "lint:fix": "eslint . --fix" 11 | }, 12 | "devDependencies": { 13 | "@antfu/eslint-config": "^3.9.1", 14 | "eslint": "^9.15.0", 15 | "eslint-plugin-format": "^0.1.2" 16 | }, 17 | "pnpm": { 18 | "supportedArchitectures": { 19 | "os": ["current"], 20 | "cpu": ["x64", "arm64", "ia32"] 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/cli/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('./src') 4 | -------------------------------------------------------------------------------- /packages/cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@docmirror/dev-sidecar-cli", 3 | "version": "2.0.0", 4 | "private": false, 5 | "description": "给开发者的加速代理工具", 6 | "author": "docmirror.cn", 7 | "license": "MPL-2.0", 8 | "keywords": [ 9 | "dev-sidecar", 10 | "github加速", 11 | "google加速", 12 | "代理" 13 | ], 14 | "main": "src/index.js", 15 | "bin": "./cli.js", 16 | "scripts": { 17 | "start": "node ./src" 18 | }, 19 | "dependencies": { 20 | "@docmirror/dev-sidecar": "workspace:*", 21 | "@docmirror/mitmproxy": "workspace:*" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/cli/src/banner.txt: -------------------------------------------------------------------------------- 1 | ____ _____ _ __ 2 | / __ \___ _ __ / ___/(_)___/ /__ _________ ______ 3 | / / / / _ \ | / /_____\__ \/ / __ / _ \/ ___/ __ `/ ___/ 4 | / /_/ / __/ |/ /_____/__/ / / /_/ / __/ /__/ /_/ / / 5 | /_____/\___/|___/ /____/_/\__,_/\___/\___/\__,_/_/ 6 | 7 | 8 | ==================== 开发者边车 ==================== 9 | -------------------------------------------------------------------------------- /packages/cli/src/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('node:fs') 2 | const DevSidecar = require('@docmirror/dev-sidecar') 3 | const jsonApi = require('@docmirror/mitmproxy/src/json') 4 | 5 | // 启动服务 6 | const mitmproxyPath = './mitmproxy' 7 | async function startup () { 8 | const banner = fs.readFileSync('./banner.txt') 9 | console.log(banner.toString()) 10 | 11 | const configPath = './user_config.json5' 12 | if (fs.existsSync(configPath)) { 13 | const file = fs.readFileSync(configPath) 14 | let userConfig 15 | try { 16 | userConfig = jsonApi.parse(file.toString()) 17 | console.info(`读取和解析 user_config.json5 成功:${configPath}`) 18 | } catch (e) { 19 | console.error(`读取或解析 user_config.json5 失败: ${configPath}, error:`, e) 20 | userConfig = {} 21 | } 22 | DevSidecar.api.config.set(userConfig) 23 | } 24 | 25 | await DevSidecar.api.startup({ mitmproxyPath }) 26 | console.log('dev-sidecar 已启动') 27 | } 28 | 29 | async function onClose () { 30 | console.log('on sigint ') 31 | await DevSidecar.api.shutdown() 32 | console.log('on closed ') 33 | process.exit(0) 34 | } 35 | process.on('SIGINT', onClose) 36 | 37 | startup() 38 | -------------------------------------------------------------------------------- /packages/cli/src/mitmproxy.js: -------------------------------------------------------------------------------- 1 | const fs = require('node:fs') 2 | const path = require('node:path') 3 | const server = require('@docmirror/mitmproxy') 4 | const jsonApi = require('@docmirror/mitmproxy/src/json') 5 | const log = require('@docmirror/mitmproxy/src/utils/util.log.server') // 当前脚本是在 server 的进程中执行的,所以使用 mitmproxy 中的logger 6 | 7 | const home = process.env.USER_HOME || process.env.HOME || 'C:/Users/Administrator/' 8 | 9 | let configPath 10 | if (process.argv && process.argv.length > 3) { 11 | configPath = process.argv[2] 12 | } else { 13 | configPath = path.join(home, '.dev-sidecar/running.json') 14 | } 15 | 16 | const configJson = fs.readFileSync(configPath) 17 | log.info('读取 running.json by cli 成功:', configPath) 18 | let config 19 | try { 20 | config = jsonApi.parse(configJson.toString()) 21 | } catch (e) { 22 | log.error(`running.json 文件内容格式不正确,文件路径:${configPath},文件内容: ${configJson.toString()}, error:`, e) 23 | config = {} 24 | } 25 | // const scriptDir = '../../gui/extra/scripts/' 26 | // config.setting.script.defaultDir = path.join(__dirname, scriptDir) 27 | // const pacFilePath = '../../gui/extra/pac/pac.txt' 28 | // config.plugin.overwall.pac.customPacFilePath = path.join(__dirname, pacFilePath) 29 | config.setting.rootDir = path.join(__dirname, '../../gui/') 30 | log.info(`start mitmproxy by cli, configPath: ${configPath}`) 31 | server.start(config) 32 | -------------------------------------------------------------------------------- /packages/cli/src/user_config.json5: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "autoStart": { 4 | "enabled": true 5 | }, 6 | "mode": "default" 7 | }, 8 | "plugin": { 9 | "node": { 10 | "setting": { 11 | "yarnRegistry": "null" 12 | } 13 | }, 14 | "git": { 15 | "enabled": true 16 | }, 17 | "overwall": { 18 | "enabled": false, 19 | "targets": { 20 | "*gagedigital.com": true, 21 | "*yonsz.net": true, 22 | "*bootstrapcdn.com": true, 23 | "*cloudflare.com": true, 24 | "help.yonsz.net": true 25 | } 26 | } 27 | }, 28 | "server": { 29 | "intercepts": { 30 | "dev-sidecar.docmirror.cn": { 31 | ".*": { 32 | "proxy": "dev-sidecar-preview.docmirror.cn" 33 | } 34 | }, 35 | "test1111.gagedigital.com": { 36 | ".*": { 37 | "proxy": "test1.gagedigital.com" 38 | } 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/core/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./src') 2 | 3 | // TODO 这是一个解谜游戏 ↓ ↓ ↓ ↓ ↓ ↓ ,如果你破解了它,请不要公开,好好用它来学习和查资料吧(特别注意:为了你的人身安全,请不要用它来查看和发表不当言论,你懂得)。 4 | /** 5 | \u0061\u0048\u0052\u0030\u0063\u0044\u006f\u0076\u004c\u0032\u0052\u006c\u0064\u0069\u0031\u007a\u0061\u0057\u0052\u006c\u0059\u0032\u0046\u0079\u004c\u006d\u0052\u0076\u0059\u0032\u0031\u0070\u0063\u006e\u004a\u0076\u0063\u0069\u0035\u006a\u0062\u0069\u0039\u0035\u0062\u0033\u0056\u006d\u0061\u0057\u0035\u006b\u0061\u0058\u0051\u0076\u0061\u0057\u0035\u006b\u005a\u0058\u0067\u0075\u0061\u0048\u0052\u0074\u0062\u0041\u003d\u003d 6 | */ 7 | // 这个项目里有一点点解谜提示: https://github.com/fast-crud/fast-crud (打开拉到最下面) 8 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@docmirror/dev-sidecar", 3 | "version": "2.0.0", 4 | "private": false, 5 | "description": "给开发者的加速代理工具", 6 | "author": "docmirror.cn", 7 | "license": "MPL-2.0", 8 | "keywords": [ 9 | "dev-sidecar", 10 | "github加速", 11 | "google加速", 12 | "代理" 13 | ], 14 | "main": "src/index.js", 15 | "scripts": { 16 | "test": "mocha" 17 | }, 18 | "dependencies": { 19 | "@starknt/sysproxy": "^0.0.3", 20 | "@vscode/sudo-prompt": "^9.3.1", 21 | "fix-path": "^3.0.0", 22 | "iconv-lite": "^0.6.3", 23 | "lodash": "^4.17.21", 24 | "log4js": "^6.9.1", 25 | "node-powershell": "^4.0.0", 26 | "spawn-sync": "^2.0.0", 27 | "winreg": "^1.2.5" 28 | }, 29 | "devDependencies": { 30 | "chai": "^4.3.4", 31 | "mocha": "^8.2.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/core/src/config/local-config-loader.js: -------------------------------------------------------------------------------- 1 | const fs = require('node:fs') 2 | const path = require('node:path') 3 | const lodash = require('lodash') 4 | const jsonApi = require('@docmirror/mitmproxy/src/json') 5 | const mergeApi = require('../merge') 6 | const logOrConsole = require('../utils/util.log-or-console') 7 | 8 | function getUserBasePath (autoCreate = true) { 9 | const userHome = process.env.USERPROFILE || process.env.HOME || '/' 10 | const dir = path.resolve(userHome, './.dev-sidecar') 11 | 12 | // 自动创建目录 13 | if (autoCreate && !fs.existsSync(dir)) { 14 | fs.mkdirSync(dir) 15 | } 16 | 17 | return dir 18 | } 19 | 20 | function loadConfigFromFile (configFilePath) { 21 | if (configFilePath == null) { 22 | logOrConsole.error('配置文件地址为空') 23 | return {} 24 | } 25 | 26 | if (!fs.existsSync(configFilePath)) { 27 | logOrConsole.info('配置文件不存在:', configFilePath) 28 | return {} // 文件不存在,返回空配置 29 | } 30 | 31 | // 读取配置文件 32 | let configStr 33 | try { 34 | configStr = fs.readFileSync(configFilePath) 35 | } catch (e) { 36 | logOrConsole.error('读取配置文件失败:', configFilePath, ', error:', e) 37 | return {} 38 | } 39 | 40 | // 解析配置文件 41 | try { 42 | const config = jsonApi.parse(configStr) 43 | logOrConsole.info('读取配置文件成功:', configFilePath) 44 | return config 45 | } catch (e) { 46 | logOrConsole.error(`解析配置文件失败,文件内容格式不正确,文件路径: ${configFilePath},文件内容:${configStr},error:`, e) 47 | return {} 48 | } 49 | } 50 | 51 | function getUserConfigPath () { 52 | const dir = getUserBasePath() 53 | 54 | // 兼容1.7.3及以下版本的配置文件处理逻辑 55 | const newFilePath = path.join(dir, '/config.json') 56 | const oldFilePath = path.join(dir, '/config.json5') 57 | if (!fs.existsSync(newFilePath) && fs.existsSync(oldFilePath)) { 58 | return oldFilePath // 如果新文件不存在,但旧文件存在,则返回旧文件路径 59 | } 60 | 61 | return newFilePath 62 | } 63 | 64 | function getUserConfig () { 65 | const configFilePath = getUserConfigPath() 66 | return loadConfigFromFile(configFilePath) 67 | } 68 | 69 | function getRemoteConfigPath (suffix = '') { 70 | const dir = getUserBasePath() 71 | return path.join(dir, `/remote_config${suffix}.json5`) 72 | } 73 | 74 | function getRemoteConfig (suffix = '') { 75 | const remoteConfigFilePath = getRemoteConfigPath(suffix) 76 | return loadConfigFromFile(remoteConfigFilePath) 77 | } 78 | 79 | function getAutomaticCompatibleConfigPath () { 80 | const dir = getUserBasePath() 81 | return path.join(dir, '/automaticCompatibleConfig.json') 82 | } 83 | 84 | /** 85 | * 从文件读取配置 86 | * 87 | * @param userConfig 用户配置 88 | * @param defaultConfig 默认配置 89 | */ 90 | function getConfigFromFiles (userConfig, defaultConfig) { 91 | const merged = userConfig != null ? lodash.cloneDeep(userConfig) : {} 92 | 93 | const personalRemoteConfig = getRemoteConfig('_personal') 94 | const shareRemoteConfig = getRemoteConfig() 95 | 96 | mergeApi.doMerge(merged, personalRemoteConfig) // 先合并一次个人远程配置,使配置顺序在前 97 | mergeApi.doMerge(merged, shareRemoteConfig) // 先合并一次共享远程配置,使配置顺序在前 98 | mergeApi.doMerge(merged, defaultConfig) // 合并默认配置,顺序排在最后 99 | mergeApi.doMerge(merged, shareRemoteConfig) // 再合并一次共享远程配置,使配置生效 100 | mergeApi.doMerge(merged, personalRemoteConfig) // 再合并一次个人远程配置,使配置生效 101 | 102 | if (userConfig != null) { 103 | mergeApi.doMerge(merged, userConfig) // 再合并一次用户配置,使用户配置重新生效 104 | } 105 | 106 | // 删除为null及[delete]的项 107 | mergeApi.deleteNullItems(merged) 108 | 109 | logOrConsole.info('加载及合并远程配置完成') 110 | return merged 111 | } 112 | 113 | module.exports = { 114 | getUserBasePath, 115 | 116 | loadConfigFromFile, 117 | 118 | getUserConfigPath, 119 | getUserConfig, 120 | 121 | getRemoteConfigPath, 122 | getRemoteConfig, 123 | 124 | getAutomaticCompatibleConfigPath, 125 | 126 | getConfigFromFiles, 127 | } 128 | -------------------------------------------------------------------------------- /packages/core/src/event.js: -------------------------------------------------------------------------------- 1 | const listener = {} 2 | let index = 1 3 | function register (channel, handle, order = 10) { 4 | let handles = listener[channel] 5 | if (handles == null) { 6 | handles = listener[channel] = [] 7 | } 8 | handles.push({ id: index, handle, order }) 9 | handles.sort((a, b) => { 10 | return a.order - b.order 11 | }) 12 | return index++ 13 | } 14 | function fire (channel, event) { 15 | const handles = listener[channel] 16 | if (handles == null) { 17 | return 18 | } 19 | for (const item of handles) { 20 | item.handle(event) 21 | } 22 | } 23 | 24 | function unregister (id) { 25 | for (const key in listener) { 26 | const handlers = listener[key] 27 | for (let i = 0; i < handlers.length; i++) { 28 | const handle = handlers[i] 29 | if (handle.id === id) { 30 | handlers.splice(i) 31 | return 32 | } 33 | } 34 | } 35 | } 36 | const EventHub = { 37 | register, 38 | fire, 39 | unregister, 40 | } 41 | module.exports = EventHub 42 | -------------------------------------------------------------------------------- /packages/core/src/expose.js: -------------------------------------------------------------------------------- 1 | const lodash = require('lodash') 2 | const config = require('./config-api') 3 | const event = require('./event') 4 | const modules = require('./modules') 5 | const shell = require('./shell') 6 | const status = require('./status') 7 | const log = require('./utils/util.log.core') 8 | 9 | const context = { 10 | config, 11 | shell, 12 | status, 13 | event, 14 | log, 15 | } 16 | 17 | function setupPlugin (key, plugin, context, config) { 18 | const pluginConfig = plugin.config 19 | const PluginClass = plugin.plugin 20 | const pluginStatus = plugin.status 21 | const api = PluginClass(context) 22 | config.addDefault(key, pluginConfig) 23 | if (pluginStatus) { 24 | lodash.set(status, key, pluginStatus) 25 | } 26 | return api 27 | } 28 | 29 | const proxy = setupPlugin('proxy', modules.proxy, context, config) 30 | const plugin = {} 31 | for (const key in modules.plugin) { 32 | const target = modules.plugin[key] 33 | const api = setupPlugin(`plugin.${key}`, target, context, config) 34 | plugin[key] = api 35 | } 36 | config.resetDefault() 37 | const server = modules.server 38 | const serverStart = server.start 39 | 40 | function newServerStart ({ mitmproxyPath }) { 41 | return serverStart({ mitmproxyPath, plugins: plugin }) 42 | } 43 | server.start = newServerStart 44 | async function startup ({ mitmproxyPath }) { 45 | const conf = config.get() 46 | if (conf.server.enabled) { 47 | try { 48 | await server.start({ mitmproxyPath }) 49 | } catch (err) { 50 | log.error('代理服务启动失败:', err) 51 | } 52 | } 53 | if (conf.proxy.enabled) { 54 | try { 55 | await proxy.start() 56 | } catch (err) { 57 | log.error('开启系统代理失败:', err) 58 | } 59 | } 60 | try { 61 | const plugins = [] 62 | for (const key in plugin) { 63 | if (conf.plugin[key].enabled) { 64 | const start = async () => { 65 | try { 66 | await plugin[key].start() 67 | log.info(`插件【${key}】已启动`) 68 | } catch (err) { 69 | log.error(`插件【${key}】启动失败:`, err) 70 | } 71 | } 72 | plugins.push(start()) 73 | } 74 | } 75 | if (plugins && plugins.length > 0) { 76 | await Promise.all(plugins) 77 | } 78 | } catch (err) { 79 | log.error('开启插件失败:', err) 80 | } 81 | } 82 | 83 | async function shutdown () { 84 | try { 85 | const plugins = [] 86 | for (const key in plugin) { 87 | if (status.plugin[key] && status.plugin[key].enabled && plugin[key].close) { 88 | const close = async () => { 89 | try { 90 | await plugin[key].close() 91 | log.info(`插件【${key}】已关闭`) 92 | } catch (err) { 93 | log.error(`插件【${key}】关闭失败:`, err) 94 | } 95 | } 96 | plugins.push(close()) 97 | } 98 | } 99 | if (plugins.length > 0) { 100 | await Promise.all(plugins) 101 | } 102 | } catch (error) { 103 | log.error('插件关闭失败:', error) 104 | } 105 | 106 | if (status.proxy.enabled) { 107 | try { 108 | await proxy.close() 109 | log.info('系统代理已关闭') 110 | } catch (err) { 111 | log.error('系统代理关闭失败:', err) 112 | } 113 | } 114 | if (status.server.enabled) { 115 | try { 116 | await server.close() 117 | log.info('代理服务已关闭') 118 | } catch (err) { 119 | log.error('代理服务关闭失败:', err) 120 | } 121 | } 122 | } 123 | 124 | const api = { 125 | startup, 126 | shutdown, 127 | status: { 128 | get () { 129 | return status 130 | }, 131 | }, 132 | config, 133 | event, 134 | shell, 135 | server, 136 | proxy, 137 | plugin, 138 | log, 139 | } 140 | module.exports = { 141 | status, 142 | api, 143 | } 144 | -------------------------------------------------------------------------------- /packages/core/src/index.js: -------------------------------------------------------------------------------- 1 | const expose = require('./expose.js') 2 | const log = require('./utils/util.log.core') 3 | // process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' 4 | 5 | // 避免异常崩溃 6 | process.on('uncaughtException', (err) => { 7 | log.error('Process Uncaught Exception:', err) 8 | }) 9 | 10 | process.on('unhandledRejection', (reason, p) => { 11 | log.error('Process Unhandled Rejection at: Promise:', p, ', reason:', reason) 12 | // application specific logging, throwing an error, or other logic here 13 | }) 14 | 15 | module.exports = expose 16 | -------------------------------------------------------------------------------- /packages/core/src/merge.js: -------------------------------------------------------------------------------- 1 | const lodash = require('lodash') 2 | 3 | /** 4 | * 找出 newObj 相对于 oldObj 有差异的部分 5 | * 6 | * @param oldObj 7 | * @param newObj 8 | * @returns {{}|*} 9 | */ 10 | function doDiff (oldObj, newObj) { 11 | if (newObj == null) { 12 | return oldObj 13 | } 14 | 15 | // 临时的对象,用于找出被删除的数据 16 | const tempObj = { ...oldObj } 17 | // 删除空项,使差异对象更干净一些,体现出用户自定义内容 18 | deleteNullItems(tempObj) 19 | 20 | // 保存差异的对象 21 | const diffObj = {} 22 | 23 | // 读取新对象,并解析 24 | for (const key in newObj) { 25 | const newValue = newObj[key] 26 | const oldValue = oldObj[key] 27 | 28 | // 新值不为空,旧值为空时,直接取新值 29 | if (newValue != null && oldValue == null) { 30 | diffObj[key] = newValue 31 | continue 32 | } 33 | // 新旧值相等时,忽略 34 | if (lodash.isEqual(newValue, oldValue)) { 35 | delete tempObj[key] 36 | continue 37 | } 38 | // 新的值为数组时,直接取新值 39 | if (lodash.isArray(newValue)) { 40 | diffObj[key] = newValue 41 | delete tempObj[key] 42 | continue 43 | } 44 | 45 | // 新的值为对象时,递归合并 46 | if (lodash.isObject(newValue)) { 47 | diffObj[key] = doDiff(oldValue, newValue) 48 | delete tempObj[key] 49 | continue 50 | } 51 | 52 | // 基础类型,直接覆盖 53 | delete tempObj[key] 54 | diffObj[key] = newValue 55 | } 56 | 57 | // tempObj 里面剩下的是被删掉的数据 58 | lodash.forEach(tempObj, (oldValue, key) => { 59 | // 将被删除的属性设置为null,目的是为了merge时,将被删掉的对象设置为null,达到删除的目的 60 | diffObj[key] = null 61 | }) 62 | 63 | return diffObj 64 | } 65 | 66 | function deleteNullItems (target) { 67 | lodash.forEach(target, (item, key) => { 68 | if (item == null || item === '[delete]') { 69 | delete target[key] 70 | } 71 | if (lodash.isObject(item)) { 72 | deleteNullItems(item) 73 | } 74 | }) 75 | } 76 | 77 | module.exports = { 78 | doMerge (oldObj, newObj) { 79 | return lodash.mergeWith(oldObj, newObj, (objValue, srcValue) => { 80 | if (lodash.isArray(objValue)) { 81 | return srcValue 82 | } 83 | }) 84 | }, 85 | doDiff, 86 | deleteNullItems, 87 | } 88 | -------------------------------------------------------------------------------- /packages/core/src/modules/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | server: require('./server'), 3 | proxy: require('./proxy'), 4 | plugin: require('./plugin'), 5 | } 6 | -------------------------------------------------------------------------------- /packages/core/src/modules/plugin/git/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'Git.exe代理', 3 | enabled: false, 4 | tip: '如果你没有安装git命令行则不需要启动它', 5 | setting: { 6 | sslVerify: true, // Git.exe 是否关闭sslVerify,true=关闭 false=开启 7 | noProxyUrls: { 8 | 'https://gitee.com': true, // 码云 9 | 'https://e.coding.net': true, // Coding(腾讯云) 10 | 'https://codeup.aliyun.com': true, // 云效 Codeup (阿里云) 11 | }, 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /packages/core/src/modules/plugin/git/index.js: -------------------------------------------------------------------------------- 1 | const pluginConfig = require('./config') 2 | 3 | const Plugin = function (context) { 4 | const { config, shell, event, log } = context 5 | const pluginApi = { 6 | async start () { 7 | const ip = '127.0.0.1' 8 | const port = config.get().server.port 9 | await pluginApi.setProxy(ip, port) 10 | return { ip, port } 11 | }, 12 | 13 | async close () { 14 | return pluginApi.unsetProxy() 15 | }, 16 | 17 | async restart () { 18 | await pluginApi.close() 19 | await pluginApi.start() 20 | }, 21 | 22 | isEnabled () { 23 | return config.get().plugin.git.enabled 24 | }, 25 | 26 | async save (newConfig) { 27 | 28 | }, 29 | 30 | async setProxy (ip, port) { 31 | const cmds = [ 32 | `git config --global http.proxy http://${ip}:${port - 1} `, 33 | `git config --global https.proxy http://${ip}:${port} `, 34 | ] 35 | 36 | if (config.get().plugin.git.setting.sslVerify === true) { 37 | cmds.push('git config --global http.sslVerify false ') 38 | } 39 | 40 | if (config.get().plugin.git.setting.noProxyUrls != null) { 41 | for (const url in config.get().plugin.git.setting.noProxyUrls) { 42 | cmds.push(`git config --global http."${url}".proxy "" `) 43 | } 44 | } 45 | 46 | const ret = await shell.exec(cmds, { type: 'cmd' }) 47 | event.fire('status', { key: 'plugin.git.enabled', value: true }) 48 | log.info('开启【Git】代理成功') 49 | 50 | return ret 51 | }, 52 | 53 | // 当手动修改过 `~/.gitconfig` 时,`unset` 可能会执行失败,所以除了第一条命令外,其他命令都添加了try-catch,防止关闭Git代理失败 54 | async unsetProxy () { 55 | const ret = await shell.exec(['git config --global --unset http.proxy '], { type: 'cmd' }) 56 | 57 | try { 58 | await shell.exec(['git config --global --unset https.proxy '], { type: 'cmd' }) 59 | } catch { 60 | } 61 | 62 | if (config.get().plugin.git.setting.sslVerify === true) { 63 | try { 64 | await shell.exec(['git config --global --unset http.sslVerify '], { type: 'cmd' }) 65 | } catch { 66 | } 67 | } 68 | 69 | if (config.get().plugin.git.setting.noProxyUrls != null) { 70 | for (const url in config.get().plugin.git.setting.noProxyUrls) { 71 | try { 72 | await shell.exec([`git config --global --unset http."${url}".proxy `], { type: 'cmd' }) 73 | } catch { 74 | } 75 | } 76 | } 77 | event.fire('status', { key: 'plugin.git.enabled', value: false }) 78 | log.info('关闭【Git】代理成功') 79 | return ret 80 | }, 81 | } 82 | return pluginApi 83 | } 84 | 85 | module.exports = { 86 | key: 'git', 87 | config: pluginConfig, 88 | status: { 89 | enabled: false, 90 | }, 91 | plugin: Plugin, 92 | } 93 | -------------------------------------------------------------------------------- /packages/core/src/modules/plugin/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | node: require('./node'), 3 | git: require('./git'), 4 | pip: require('./pip'), 5 | overwall: require('./overwall'), 6 | } 7 | -------------------------------------------------------------------------------- /packages/core/src/modules/plugin/node/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'NPM加速', 3 | enabled: false, 4 | tip: '如果你没有安装nodejs则不需要启动它', 5 | startup: { 6 | variables: true, 7 | }, 8 | setting: { 9 | 'command': 'npm', 10 | 'strict-ssl': true, 11 | 'cafile': false, 12 | 'NODE_EXTRA_CA_CERTS': false, 13 | 'NODE_TLS_REJECT_UNAUTHORIZED': false, 14 | 'yarnRegistry': 'default', 15 | 'registry': 'https://registry.npmjs.org', // 可以选择切换官方或者淘宝镜像 16 | }, 17 | variables: { 18 | phantomjs_cdnurl: 'https://npmmirror.com/mirrors/phantomjs', 19 | chromedriver_cdnurl: 'https://npmmirror.com/mirrors/chromedriver', 20 | sass_binary_site: 'https://npmmirror.com/mirrors/node-sass', 21 | ELECTRON_MIRROR: 'https://npmmirror.com/mirrors/electron/', 22 | NVM_NODEJS_ORG_MIRROR: 'https://npmmirror.com/mirrors/node', 23 | CHROMEDRIVER_CDNURL: 'https://npmmirror.com/mirrors/chromedriver', 24 | OPERADRIVER: 'https://npmmirror.com/mirrors/operadriver', 25 | ELECTRON_BUILDER_BINARIES_MIRROR: 'https://npmmirror.com/mirrors/electron-builder-binaries/', 26 | PYTHON_MIRROR: 'https://npmmirror.com/mirrors/python', 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /packages/core/src/modules/plugin/overwall/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: '梯子', 3 | enabled: false, // 默认关闭梯子 4 | server: {}, 5 | serverDefault: { 6 | 'ow-prod.docmirror.top': { 7 | port: 443, 8 | path: 'X2dvX292ZXJfd2FsbF8', 9 | password: 'dev_sidecar_is_666', 10 | }, 11 | }, 12 | targets: { 13 | '*.github.com': true, 14 | '*github*.com': true, 15 | '*.wikimedia.org': true, 16 | '*.v2ex.com': true, 17 | '*.azureedge.net': true, 18 | '*.cloudfront.net': true, 19 | '*.bing.com': true, 20 | '*.discourse-cdn.com': true, 21 | '*.gravatar.com': true, 22 | '*.docker.com': true, 23 | '*.vueuse.org': true, 24 | '*.elastic.co': true, 25 | '*.optimizely.com': true, 26 | '*.stackpathcdn.com': true, 27 | '*.fastly.net': true, 28 | '*.cloudflare.com': true, 29 | '*.233v2.com': true, 30 | '*.v2fly.org': true, 31 | '*.telegram.org': true, 32 | '*.amazon.com': true, 33 | '*.googleapis.com': true, 34 | '*.google-analytics.com': true, 35 | '*.cloudflareinsights.com': true, 36 | '*.intlify.dev': true, 37 | '*.segment.io': true, 38 | '*.shields.io': true, 39 | '*.jsdelivr.net': true, 40 | }, 41 | pac: { 42 | enabled: true, 43 | autoUpdate: true, 44 | pacFileUpdateUrl: 'https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt', 45 | pacFileAbsolutePath: null, // 自定义 pac.txt 文件位置,可以是本地文件路径 46 | pacFilePath: './extra/pac/pac.txt', // 内置 pac.txt 文件路径 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /packages/core/src/modules/plugin/overwall/index.js: -------------------------------------------------------------------------------- 1 | const pluginConfig = require('./config') 2 | 3 | const Plugin = function (context) { 4 | const { config, shell, event, log } = context 5 | const api = { 6 | async start () { 7 | // event.fire('status', { key: 'plugin.overwall.enabled', value: true }) 8 | }, 9 | 10 | async close () { 11 | // event.fire('status', { key: 'plugin.overwall.enabled', value: false }) 12 | }, 13 | 14 | async restart () { 15 | await api.close() 16 | await api.start() 17 | }, 18 | 19 | async overrideRunningConfig_bak (serverConfig) { 20 | const conf = config.get().plugin.overwall 21 | if (!conf || !conf.enabled || !conf.targets) { 22 | return 23 | } 24 | const server = conf.server 25 | let i = 0 26 | let main 27 | const backup = [] 28 | for (const key in server) { 29 | if (i === 0) { 30 | main = key 31 | } else { 32 | backup.push(key) 33 | } 34 | i++ 35 | } 36 | for (const key in conf.targets) { 37 | serverConfig.intercepts[key] = { 38 | '.*': { 39 | proxy: `${main}/\${host}`, 40 | backup, 41 | }, 42 | } 43 | } 44 | }, 45 | } 46 | return api 47 | } 48 | 49 | module.exports = { 50 | key: 'overwall', 51 | config: pluginConfig, 52 | plugin: Plugin, 53 | } 54 | -------------------------------------------------------------------------------- /packages/core/src/modules/plugin/pip/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'PIP加速', 3 | statusOff: true, 4 | enabled: null, // 没有开关 5 | tip: '如果你没有安装pip则不需要启动它', 6 | startup: { 7 | }, 8 | setting: { 9 | command: 'pip', 10 | trustedHost: 'pypi.org', 11 | registry: 'https://pypi.org/simple/', // 可以选择切换官方或者淘宝镜像 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /packages/core/src/modules/plugin/pip/index.js: -------------------------------------------------------------------------------- 1 | const pipConfig = require('./config') 2 | 3 | const PipPlugin = function (context) { 4 | const { config, shell, event, log } = context 5 | const api = { 6 | async start () { 7 | await api.setRegistry({ registry: config.get().plugin.pip.setting.registry }) 8 | await api.setTrustedHost(config.get().plugin.pip.setting.trustedHost) 9 | }, 10 | 11 | async close () { 12 | }, 13 | 14 | async restart () { 15 | await api.close() 16 | await api.start() 17 | }, 18 | 19 | async save (newConfig) { 20 | await api.setVariables() 21 | }, 22 | async getPipEnv () { 23 | const command = config.get().plugin.pip.setting.command 24 | let ret = await shell.exec([`${command} config list`], { type: 'cmd' }) 25 | if (ret != null) { 26 | ret = ret.trim() 27 | const lines = ret.split('\n') 28 | const vars = {} 29 | for (const line of lines) { 30 | if (!line.startsWith('global')) { 31 | continue 32 | } 33 | const key = line.substring(0, line.indexOf('=')) 34 | let value = line.substring(line.indexOf('=') + 1) 35 | if (value.startsWith('\'')) { 36 | value = value.startsWith(1, value.length - 1) 37 | } 38 | vars[key] = value 39 | } 40 | return vars 41 | } 42 | return {} 43 | }, 44 | 45 | async setPipEnv (list) { 46 | const command = config.get().plugin.pip.setting.command 47 | const cmds = [] 48 | for (const item of list) { 49 | if (item.value != null) { 50 | cmds.push(`${command} config set global.${item.key} ${item.value}`) 51 | } else { 52 | cmds.push(`${command} config unset global.${item.key}`) 53 | } 54 | } 55 | return await shell.exec(cmds, { type: 'cmd' }) 56 | }, 57 | 58 | async unsetPipEnv (list) { 59 | const command = config.get().plugin.pip.setting.command 60 | const cmds = [] 61 | for (const item of list) { 62 | cmds.push(`${command} config unset global.${item} `) 63 | } 64 | return await shell.exec(cmds, { type: 'cmd' }) 65 | }, 66 | 67 | async setRegistry ({ registry }) { 68 | await api.setPipEnv([{ key: 'index-url', value: registry }]) 69 | return true 70 | }, 71 | 72 | async setTrustedHost (host) { 73 | await api.setPipEnv([{ key: 'trusted-host', value: host }]) 74 | return true 75 | }, 76 | 77 | async setProxy (ip, port) { 78 | 79 | }, 80 | 81 | async unsetProxy () { 82 | 83 | }, 84 | } 85 | return api 86 | } 87 | 88 | module.exports = { 89 | key: 'pip', 90 | config: pipConfig, 91 | status: { 92 | enabled: false, 93 | }, 94 | plugin: PipPlugin, 95 | } 96 | -------------------------------------------------------------------------------- /packages/core/src/shell/index.js: -------------------------------------------------------------------------------- 1 | const enableLoopback = require('./scripts/enable-loopback') 2 | const extraPath = require('./scripts/extra-path') 3 | const getNpmEnv = require('./scripts/get-npm-env') 4 | const getSystemEnv = require('./scripts/get-system-env') 5 | const killByPort = require('./scripts/kill-by-port') 6 | const setNpmEnv = require('./scripts/set-npm-env') 7 | const setSystemEnv = require('./scripts/set-system-env') 8 | const setSystemProxy = require('./scripts/set-system-proxy') 9 | const setupCa = require('./scripts/setup-ca') 10 | const shell = require('./shell') 11 | 12 | module.exports = { 13 | killByPort, 14 | setupCa, 15 | getSystemEnv, 16 | setSystemEnv, 17 | getNpmEnv, 18 | setNpmEnv, 19 | setSystemProxy, 20 | enableLoopback, 21 | extraPath, 22 | async exec (cmds, args) { 23 | return shell.getSystemShell().exec(cmds, args) 24 | }, 25 | getSystemPlatform: shell.getSystemPlatform, 26 | } 27 | -------------------------------------------------------------------------------- /packages/core/src/shell/scripts/enable-loopback.js: -------------------------------------------------------------------------------- 1 | /** 2 | */ 3 | const Shell = require('../shell') 4 | const extraPath = require('./extra-path') 5 | const sudoPrompt = require('@vscode/sudo-prompt') 6 | const log = require('../../utils/util.log.core') 7 | const execute = Shell.execute 8 | 9 | const executor = { 10 | windows (exec) { 11 | const loopbackPath = extraPath.getEnableLoopbackPath() 12 | const sudoCommand = [`"${loopbackPath}"`] 13 | 14 | const options = { 15 | name: 'EnableLoopback', 16 | } 17 | return new Promise((resolve, reject) => { 18 | sudoPrompt.exec( 19 | sudoCommand.join(' '), 20 | options, 21 | (error, _, stderr) => { 22 | if (stderr) { 23 | log.error(`[sudo-prompt] 发生错误: ${stderr}`) 24 | } 25 | 26 | if (error) { 27 | reject(error) 28 | } else { 29 | resolve(undefined) 30 | } 31 | }, 32 | ) 33 | }) 34 | }, 35 | async linux (exec, { port }) { 36 | throw new Error('不支持此操作') 37 | }, 38 | async mac (exec, { port }) { 39 | throw new Error('不支持此操作') 40 | }, 41 | } 42 | 43 | module.exports = async function (args) { 44 | return execute(executor, args) 45 | } 46 | -------------------------------------------------------------------------------- /packages/core/src/shell/scripts/extra-path/EnableLoopback.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/core/src/shell/scripts/extra-path/EnableLoopback.exe -------------------------------------------------------------------------------- /packages/core/src/shell/scripts/extra-path/index.js: -------------------------------------------------------------------------------- 1 | const path = require('node:path') 2 | const log = require('../../../utils/util.log.core') 3 | 4 | function getExtraPath () { 5 | let extraPath = process.env.DS_EXTRA_PATH 6 | log.info('extraPath:', extraPath) 7 | if (!extraPath) { 8 | extraPath = __dirname 9 | } 10 | return extraPath 11 | } 12 | 13 | function getProxyExePath () { 14 | const extraPath = getExtraPath() 15 | return path.join(extraPath, 'sysproxy.exe') 16 | } 17 | 18 | function getEnableLoopbackPath () { 19 | const extraPath = getExtraPath() 20 | return path.join(extraPath, 'EnableLoopback.exe') 21 | } 22 | 23 | module.exports = { 24 | getProxyExePath, 25 | getEnableLoopbackPath, 26 | } 27 | -------------------------------------------------------------------------------- /packages/core/src/shell/scripts/extra-path/sysproxy.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/core/src/shell/scripts/extra-path/sysproxy.exe -------------------------------------------------------------------------------- /packages/core/src/shell/scripts/get-npm-env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 获取环境变量 3 | */ 4 | const jsonApi = require('@docmirror/mitmproxy/src/json') 5 | const Shell = require('../shell') 6 | 7 | const execute = Shell.execute 8 | 9 | const executor = { 10 | async windows (exec) { 11 | const ret = await exec(['npm config list --json'], { type: 'cmd' }) 12 | if (ret != null) { 13 | const json = ret.substring(ret.indexOf('{')) 14 | return jsonApi.parse(json) 15 | } 16 | return {} 17 | }, 18 | async linux (exec, { port }) { 19 | throw new Error('暂未实现此功能') 20 | }, 21 | async mac (exec, { port }) { 22 | throw new Error('暂未实现此功能') 23 | }, 24 | } 25 | 26 | module.exports = async function (args) { 27 | return execute(executor, args) 28 | } 29 | -------------------------------------------------------------------------------- /packages/core/src/shell/scripts/get-system-env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 获取环境变量 3 | */ 4 | const Shell = require('../shell') 5 | 6 | const execute = Shell.execute 7 | 8 | const executor = { 9 | async windows (exec) { 10 | const ret = await exec(['set'], { type: 'cmd' }) 11 | const map = {} 12 | if (ret != null) { 13 | const lines = ret.split('\r\n') 14 | for (const item of lines) { 15 | const kv = item.split('=') 16 | if (kv.length > 1) { 17 | map[kv[0].trim()] = kv[1].trim() 18 | } 19 | } 20 | } 21 | return map 22 | }, 23 | async linux (exec, { port }) { 24 | throw new Error('暂未实现此功能') 25 | }, 26 | async mac (exec, { port }) { 27 | throw new Error('暂未实现此功能') 28 | }, 29 | } 30 | 31 | module.exports = async function (args) { 32 | return execute(executor, args) 33 | } 34 | -------------------------------------------------------------------------------- /packages/core/src/shell/scripts/kill-by-port.js: -------------------------------------------------------------------------------- 1 | const Shell = require('../shell') 2 | 3 | const execute = Shell.execute 4 | 5 | const executor = { 6 | async windows (exec, { port }) { 7 | const cmds = [`for /f "tokens=5" %a in ('netstat -aon ^| find ":${port}" ^| find "LISTENING"') do (taskkill /f /pid %a & exit /B) `] 8 | await exec(cmds, { type: 'cmd' }) 9 | return true 10 | }, 11 | async linux (exec, { port }) { 12 | await exec(`kill \`lsof -i:${port} |grep 'dev-sidecar\\|electron\\|@docmirro' |awk '{print $2}'\``) 13 | return true 14 | }, 15 | async mac (exec, { port }) { 16 | await exec(`kill \`lsof -i:${port} |grep 'dev-side\\|Elect' |awk '{print $2}'\``) 17 | return true 18 | }, 19 | } 20 | 21 | module.exports = async function (args) { 22 | return execute(executor, args) 23 | } 24 | -------------------------------------------------------------------------------- /packages/core/src/shell/scripts/set-npm-env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 设置环境变量 3 | */ 4 | const Shell = require('../shell') 5 | 6 | const execute = Shell.execute 7 | 8 | const executor = { 9 | async windows (exec, { list }) { 10 | const cmds = [] 11 | for (const item of list) { 12 | cmds.push(`npm config set ${item.key} ${item.value}`) 13 | } 14 | return await exec(cmds, { type: 'cmd' }) 15 | }, 16 | async linux (exec, { port }) { 17 | throw new Error('暂未实现此功能') 18 | }, 19 | async mac (exec, { port }) { 20 | throw new Error('暂未实现此功能') 21 | }, 22 | } 23 | 24 | module.exports = async function (args) { 25 | return execute(executor, args) 26 | } 27 | -------------------------------------------------------------------------------- /packages/core/src/shell/scripts/set-system-env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 设置环境变量 3 | */ 4 | const Shell = require('../shell') 5 | 6 | const execute = Shell.execute 7 | 8 | const executor = { 9 | async windows (exec, { list }) { 10 | const cmds = [] 11 | for (const item of list) { 12 | // [Environment]::SetEnvironmentVariable('FOO', 'bar', 'Machine') 13 | cmds.push(`[Environment]::SetEnvironmentVariable('${item.key}', '${item.value}', 'Machine')`) 14 | } 15 | const ret = await exec(cmds, { type: 'ps' }) 16 | 17 | const cmds2 = [] 18 | for (const item of list) { 19 | // [Environment]::SetEnvironmentVariable('FOO', 'bar', 'Machine') 20 | cmds2.push(`set ${item.key}=""`) 21 | } 22 | await exec(cmds2, { type: 'cmd' }) 23 | return ret 24 | }, 25 | async linux (exec, { port }) { 26 | throw new Error('暂未实现此功能') 27 | }, 28 | async mac (exec, { port }) { 29 | throw new Error('暂未实现此功能') 30 | }, 31 | } 32 | 33 | module.exports = async function (args) { 34 | return execute(executor, args) 35 | } 36 | -------------------------------------------------------------------------------- /packages/core/src/shell/scripts/set-system-proxy/refresh-internet.js: -------------------------------------------------------------------------------- 1 | const script = ` 2 | $signature = @' 3 | [DllImport("wininet.dll", SetLastError = true, CharSet=CharSet.Auto)] 4 | public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); 5 | '@ 6 | 7 | $INTERNET_OPTION_SETTINGS_CHANGED = 39 8 | $INTERNET_OPTION_REFRESH = 37 9 | $type = Add-Type -MemberDefinition $signature -Name wininet -Namespace pinvoke -PassThru 10 | $a = $type::InternetSetOption(0, $INTERNET_OPTION_SETTINGS_CHANGED, 0, 0) 11 | $b = $type::InternetSetOption(0, $INTERNET_OPTION_REFRESH, 0, 0) 12 | $a -and $b 13 | ` 14 | module.exports = script 15 | -------------------------------------------------------------------------------- /packages/core/src/shell/scripts/setup-ca.js: -------------------------------------------------------------------------------- 1 | const Shell = require('../shell') 2 | 3 | const execute = Shell.execute 4 | 5 | const executor = { 6 | async windows (exec, { certPath }) { 7 | const cmds = [`start "" "${certPath}"`] 8 | await exec(cmds, { type: 'cmd' }) 9 | return true 10 | }, 11 | async linux (exec, { certPath }) { 12 | const cmds = [`sudo cp ${certPath} /usr/local/share/ca-certificates`, 'sudo update-ca-certificates '] 13 | await exec(cmds) 14 | return true 15 | }, 16 | async mac (exec, { certPath }) { 17 | const cmds = [`open "${certPath}"`] 18 | await exec(cmds, { type: 'cmd' }) 19 | return true 20 | }, 21 | } 22 | 23 | module.exports = async function (args) { 24 | return execute(executor, args) 25 | } 26 | -------------------------------------------------------------------------------- /packages/core/src/status.js: -------------------------------------------------------------------------------- 1 | const lodash = require('lodash') 2 | const event = require('./event') 3 | const log = require('./utils/util.log.core') 4 | 5 | const status = { 6 | server: { enabled: false }, 7 | proxy: {}, 8 | plugin: {}, 9 | } 10 | 11 | event.register('status', (event) => { 12 | lodash.set(status, event.key, event.value) 13 | log.info('status changed:', event) 14 | }, -999) 15 | 16 | module.exports = status 17 | -------------------------------------------------------------------------------- /packages/core/src/utils/util.date.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | format (date, needMill = true) { 4 | if (date == null) { 5 | return 'null' 6 | } 7 | 8 | const year = date.getFullYear() // 获取年份 9 | const month = (date.getMonth() + 1).toString().padStart(2, '0') // 获取月份(注意月份从 0 开始计数) 10 | const day = date.getDate().toString().padStart(2, '0') // 获取天数 11 | const hours = date.getHours().toString().padStart(2, '0') // 获取小时 12 | const minutes = date.getMinutes().toString().padStart(2, '0') // 获取分钟 13 | const seconds = date.getSeconds().toString().padStart(2, '0') // 获取秒数 14 | const milliseconds = needMill ? `.${date.getMilliseconds().toString().padStart(3, '0')}` : '' // 获取毫秒 15 | 16 | return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}${milliseconds}` 17 | }, 18 | 19 | now (needMill = true) { 20 | return this.format(new Date(), needMill) 21 | }, 22 | 23 | } 24 | -------------------------------------------------------------------------------- /packages/core/src/utils/util.log-or-console.js: -------------------------------------------------------------------------------- 1 | const dateUtil = require('./util.date') 2 | 3 | let log = console 4 | 5 | // 将console中的日志缓存起来,当setLogger时,将控制台的日志写入日志文件 6 | let backupLogs = [] 7 | 8 | function backup (fun, args) { 9 | if (backupLogs === null) { 10 | return 11 | } 12 | 13 | try { 14 | backupLogs.push({ 15 | fun, 16 | args, 17 | time: dateUtil.format(new Date()), 18 | }) 19 | 20 | // 最多缓存 100 条 21 | if (backupLogs.length > 100) { 22 | backupLogs = backupLogs.slice(1) 23 | } 24 | } catch { 25 | } 26 | } 27 | 28 | function printBackups () { 29 | if (backupLogs === null || log === console) { 30 | return 31 | } 32 | 33 | try { 34 | const backups = backupLogs 35 | backupLogs = null // 先置空历史消息对象,再记录日志 36 | 37 | for (const item of backups) { 38 | log[item.fun](...[`[${item.time}] console -`, ...item.args]) 39 | } 40 | } catch { 41 | } 42 | } 43 | 44 | function _doLog (fun, args) { 45 | if (log === console) { 46 | log[fun](...[`[${fun.toUpperCase()}]`, ...args]) 47 | backup(fun, args) // 控制台日志备份起来 48 | } else { 49 | log[fun](...args) 50 | } 51 | } 52 | 53 | module.exports = { 54 | setLogger (logger) { 55 | if (logger == null) { 56 | log.error('logger 不能为空') 57 | return 58 | } 59 | 60 | if (logger === log) { 61 | return 62 | } 63 | 64 | log = logger 65 | 66 | if (log !== console) { 67 | try { 68 | if (backupLogs && backupLogs.length > 0) { 69 | log.info('[util.log-or-console.js] 日志系统已初始化完成,现开始将历史控制台信息记录到日志文件中:') 70 | printBackups() 71 | } 72 | } catch { 73 | } 74 | } 75 | }, 76 | 77 | debug (...args) { 78 | _doLog('debug', args) 79 | }, 80 | info (...args) { 81 | _doLog('info', args) 82 | }, 83 | warn (...args) { 84 | _doLog('warn', args) 85 | }, 86 | error (...args) { 87 | _doLog('error', args) 88 | }, 89 | } 90 | -------------------------------------------------------------------------------- /packages/core/src/utils/util.log.core.js: -------------------------------------------------------------------------------- 1 | const loggerFactory = require('./util.logger') 2 | 3 | const logger = loggerFactory.getLogger('core') 4 | 5 | module.exports = logger 6 | -------------------------------------------------------------------------------- /packages/core/src/utils/util.logger.js: -------------------------------------------------------------------------------- 1 | const path = require('node:path') 2 | const log4js = require('log4js') 3 | const logOrConsole = require('./util.log-or-console') 4 | const defaultConfig = require('../config/index.js') 5 | const configFromFiles = defaultConfig.configFromFiles 6 | 7 | // 日志级别 8 | const level = process.env.NODE_ENV === 'development' ? 'debug' : 'info' 9 | 10 | function getDefaultConfigBasePath () { 11 | if (configFromFiles.app.logFileSavePath) { 12 | let logFileSavePath = configFromFiles.app.logFileSavePath 13 | if (logFileSavePath.endsWith('/') || logFileSavePath.endsWith('\\')) { 14 | logFileSavePath = logFileSavePath.slice(0, -1) 15 | } 16 | // eslint-disable-next-line no-template-curly-in-string 17 | return logFileSavePath.replace('${userBasePath}', configFromFiles.server.setting.userBasePath) 18 | } else { 19 | return path.join(configFromFiles.server.setting.userBasePath, '/logs') 20 | } 21 | } 22 | 23 | // 日志文件目录 24 | const basePath = getDefaultConfigBasePath() 25 | 26 | // 通用日志配置 27 | const appenderConfig = { 28 | type: 'file', 29 | pattern: 'yyyy-MM-dd', 30 | compress: true, // 压缩日志文件 31 | keepFileExt: true, // 保留日志文件扩展名为 .log 32 | backups: Math.ceil(configFromFiles.app.keepLogFileCount) || defaultConfig.app.keepLogFileCount, // 保留日志文件数 33 | maxLogSize: Math.ceil((configFromFiles.app.maxLogFileSize || defaultConfig.app.maxLogFileSize) * 1024 * 1024 * (configFromFiles.app.maxLogFileSizeUnit === 'GB' ? 1024 : 1)), // 目前单位只有GB和MB 34 | } 35 | 36 | let log = null 37 | 38 | // 设置一组日志配置 39 | function log4jsConfigure (categories) { 40 | if (log != null) { 41 | log.error('当前进程已经设置过日志配置,无法再设置更多日志配置:', categories) 42 | return 43 | } 44 | 45 | const config = { 46 | appenders: { 47 | std: { type: 'stdout' }, 48 | }, 49 | categories: { 50 | default: { appenders: ['std'], level }, 51 | }, 52 | } 53 | 54 | for (const category of categories) { 55 | config.appenders[category] = { ...appenderConfig, filename: path.join(basePath, `/${category}.log`) } 56 | config.categories[category] = { appenders: [category, 'std'], level } 57 | } 58 | 59 | log4js.configure(config) 60 | 61 | // 拿第一个日志类型来logger并设置到log变量中 62 | log = log4js.getLogger(categories[0]) 63 | logOrConsole.setLogger(log) 64 | 65 | log.info(`设置日志配置完成,进程ID: ${process.pid},categories:[${categories}],config:`, JSON.stringify(config)) 66 | } 67 | 68 | module.exports = { 69 | getLogger (category) { 70 | if (!category) { 71 | if (log) { 72 | log.error('未指定日志类型,无法配置并获取日志对象!!!') 73 | } 74 | throw new Error('未指定日志类型,无法配置并获取日志对象!!!') 75 | } 76 | 77 | if (category === 'core' || category === 'gui') { 78 | // core 和 gui 的日志配置,因为它们在同一进程中,所以一起配置,且只能配置一次 79 | if (log == null) { 80 | log4jsConfigure(['core', 'gui']) 81 | } 82 | 83 | return log4js.getLogger(category) 84 | } else { 85 | if (log == null) { 86 | log4jsConfigure([category]) 87 | } else if (category !== log.category) { 88 | log.error(`当前进程已经设置过日志配置,无法再设置 "${category}" 的配置,先临时返回 "${log.category}" 的 log 进行日志记录。如果与其他类型的日志在同一进程中写入,请参照 core 和 gui 一起配置`) 89 | } 90 | 91 | return log 92 | } 93 | }, 94 | } 95 | -------------------------------------------------------------------------------- /packages/core/src/utils/util.version.js: -------------------------------------------------------------------------------- 1 | function parseVersion (version) { 2 | const matched = version.match(/^v?(\d{1,2}(?:\.\d{1,2})*)(.*)$/) 3 | return { 4 | versions: matched[1].split('.'), // 版本号数组 5 | pre: matched[2], // 预发布版本号 6 | } 7 | } 8 | 9 | /** 10 | * 比较版本号 11 | * 12 | * @param onlineVersion 线上版本号 13 | * @param currentVersion 当前版本号 14 | * @param log 日志对象 15 | * @returns {number} 比较线上版本号是否为更新的版本,大于0=是|0=相等|小于0=否|-999=出现异常,比较结果未知 16 | */ 17 | export function isNewVersion (onlineVersion, currentVersion, log = console) { 18 | if (onlineVersion === currentVersion) { 19 | return 0 20 | } 21 | 22 | try { 23 | const onlineVersionObj = parseVersion(onlineVersion) 24 | const curVersionObj = parseVersion(currentVersion) 25 | 26 | const { versions: versions1 } = onlineVersionObj 27 | const { versions: versions2 } = curVersionObj 28 | 29 | if (versions1.length !== versions2.length) { 30 | // 短的数组补0 31 | if (versions1.length < versions2.length) { 32 | for (let i = versions1.length; i < versions2.length; i++) { 33 | versions1.push('0') 34 | } 35 | } else if (versions1.length > versions2.length) { 36 | for (let i = versions2.length; i < versions1.length; i++) { 37 | versions2.push('0') 38 | } 39 | } 40 | } 41 | 42 | // 版本数组比对 43 | for (let i = 0; i < versions1.length; i++) { 44 | if (versions1[i] > versions2[i]) { 45 | return i + 1 // 为新版本,需要更新 46 | } else if (versions1[i] < versions2[i]) { 47 | return -(i + 1) // 为旧版本,无需更新 48 | } 49 | } 50 | 51 | // 版本号相同,继续比对预发布版本号 52 | if (onlineVersionObj.pre && curVersionObj.pre) { 53 | // 都为预发布版本时,直接比较预发布版本号字符串的大小 54 | if (onlineVersionObj.pre > curVersionObj.pre) { 55 | return 101 56 | } else if (onlineVersionObj.pre < curVersionObj.pre) { 57 | return -101 58 | } 59 | } else if (!onlineVersionObj.pre && curVersionObj.pre) { 60 | // 线上为正式版本,当前版本为预发布版本,需要更新 61 | return 102 62 | } else if (onlineVersionObj.pre && !curVersionObj.pre) { 63 | // 线上为预发布版本,当前版本为正式版本,无需更新 64 | return -102 65 | } 66 | 67 | return 0 // 相同版本,无需更新 68 | } catch (e) { 69 | (log || console).error(`比对版本失败,当前版本号:${currentVersion},线上版本号:${onlineVersion}, error:`, e) 70 | return -999 // 比对异常 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /packages/core/test/configTest.js: -------------------------------------------------------------------------------- 1 | // const config = require('../src/config-api') 2 | // 3 | // config.set({ 4 | // server: { 5 | // intercepts: { 6 | // 'github1.githubassets.com': { 7 | // '.*': { 8 | // redirect: 'assets.fastgit.org', 9 | // test: 'https://github.githubassets.com/favicons/favicon.svg', 10 | // desc: '静态资源加速' 11 | // } 12 | // }, 13 | // 'github.githubassets.com': null 14 | // } 15 | // } 16 | // }) 17 | // 18 | // console.log(config.get()) 19 | // 20 | // config.reload() 21 | -------------------------------------------------------------------------------- /packages/core/test/httpsVerifyTest.js: -------------------------------------------------------------------------------- 1 | // const https = require('node:https') 2 | // 3 | // process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1' 4 | // 5 | // function request () { 6 | // return new Promise((resolve, reject) => { 7 | // const options = { 8 | // hostname: 'test1.gagedigital.com', 9 | // port: 443, 10 | // path: '/ssltest.php', 11 | // method: 'GET', 12 | // rejectUnauthorized: true, 13 | // } 14 | // console.log('ssl test: gagedigital') 15 | // const req = https.request(options, (res) => { 16 | // console.log('statusCode:', res.statusCode) 17 | // console.log('headers:', res.headers) 18 | // 19 | // res.on('data', (d) => { 20 | // process.stdout.write(d) 21 | // resolve() 22 | // }) 23 | // }) 24 | // 25 | // req.on('error', (e) => { 26 | // console.error(e) 27 | // reject(e) 28 | // }) 29 | // req.end() 30 | // }) 31 | // } 32 | // // eslint-disable-next-line no-undef 33 | // describe('ssl.verify', () => { 34 | // // eslint-disable-next-line no-undef 35 | // it('regex.test.js', async () => { 36 | // // https.request('https://test1.gagedigital.com/ssltest.php') 37 | // await request() 38 | // 39 | // // expect(ret).be.ok 40 | // }) 41 | // }) 42 | -------------------------------------------------------------------------------- /packages/core/test/macProxyTest.js: -------------------------------------------------------------------------------- 1 | const assert = require('node:assert') 2 | 3 | // const childProcess = require('child_process') 4 | // const util = require('util') 5 | // const exec = util.promisify(childProcess.exec) 6 | // 7 | // async function test () { 8 | // const wifiAdaptor = (await exec('sh -c "networksetup -listnetworkserviceorder | grep `route -n get 0.0.0.0 | grep \'interface\' | cut -d \':\' -f2` -B 1 | head -n 1 | cut -d \' \' -f2"')).stdout.trim() 9 | // 10 | // await exec(`networksetup -setwebproxystate '${wifiAdaptor}' off`) 11 | // return await exec(`networksetup -setsecurewebproxystate '${wifiAdaptor}' off`) 12 | // } 13 | // test().then((ret) => { 14 | // console.log('haha', ret) 15 | // }) 16 | let wifiAdaptor = '(151) test' 17 | wifiAdaptor = wifiAdaptor.substring(wifiAdaptor.indexOf(' ')).trim() 18 | console.log(wifiAdaptor) 19 | assert.strictEqual(wifiAdaptor, 'test') 20 | -------------------------------------------------------------------------------- /packages/core/test/mergeTest.js: -------------------------------------------------------------------------------- 1 | const assert = require('node:assert') 2 | const lodash = require('lodash') 3 | const mergeApi = require('../src/merge.js') 4 | 5 | // 默认配置 6 | const defConfig = { 7 | a: { 8 | aa: { value: 1 }, 9 | bb: { value: 2 }, 10 | }, 11 | b: { c: 2 }, 12 | c: 1, 13 | d: [1, 2, 3], 14 | e: { 15 | aa: 2, 16 | ee: 5, 17 | }, 18 | f: { 19 | x: 1, 20 | }, 21 | g: [1, 2], 22 | h: null, 23 | i: null, 24 | } 25 | 26 | // 自定义配置 27 | const customConfig = { 28 | a: { 29 | bb: { value: 2 }, 30 | cc: { value: 3 }, 31 | }, 32 | b: { c: 2 }, 33 | c: null, 34 | d: [1, 2, 3, 4], 35 | e: { 36 | aa: 2, 37 | ee: 5, 38 | ff: 6, 39 | }, 40 | f: {}, 41 | g: [1, 2], 42 | h: null, 43 | } 44 | 45 | // doDiff 46 | const doDiffResult = mergeApi.doDiff(defConfig, customConfig) 47 | console.log('doDiffResult:', JSON.stringify(doDiffResult, null, 2)) 48 | console.log('\r') 49 | // 校验doDiff结果 50 | const doDiffExpect = { 51 | a: { 52 | aa: null, 53 | cc: { value: 3 }, 54 | }, 55 | c: null, 56 | d: [1, 2, 3, 4], 57 | e: { 58 | ff: 6, 59 | }, 60 | f: { 61 | x: null, 62 | }, 63 | } 64 | console.log('check diff result:', lodash.isEqual(doDiffResult, doDiffExpect)) 65 | console.log('\r') 66 | 67 | // doMerge 68 | const doMergeResult = mergeApi.doMerge(defConfig, doDiffResult) 69 | // delete null item 70 | mergeApi.deleteNullItems(doMergeResult) 71 | console.log('running:', JSON.stringify(doMergeResult, null, 2)) 72 | // 校验doMerge结果 73 | const doMergeExpect = { 74 | a: { 75 | bb: { value: 2 }, 76 | cc: { value: 3 }, 77 | }, 78 | b: { c: 2 }, 79 | d: [1, 2, 3, 4], 80 | e: { 81 | aa: 2, 82 | ee: 5, 83 | ff: 6, 84 | }, 85 | f: {}, 86 | g: [1, 2], 87 | } 88 | 89 | const result = lodash.isEqual(doMergeResult, doMergeExpect) 90 | console.log('check merge result:', result) 91 | console.log('\r') 92 | assert.strictEqual(result, true) 93 | -------------------------------------------------------------------------------- /packages/core/test/regex.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('node:assert') 2 | const expect = require('chai').expect 3 | // eslint-disable-next-line no-undef 4 | describe('test', () => { 5 | // eslint-disable-next-line no-undef 6 | it('regexp', () => { 7 | const test = '^/[^/]+/[^/]+(?:/releases(?:/.*)?)?$' 8 | const reg = new RegExp(test) 9 | 10 | const ret = reg.test('/docmirror/dev-sidecar/releases/tag') 11 | console.log(ret) 12 | assert.strictEqual(ret, true) 13 | 14 | expect(ret).be.ok 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /packages/core/test/requestTest.js: -------------------------------------------------------------------------------- 1 | const HttpsAgent = require('@docmirror/mitmproxy/src/lib/proxy/common/ProxyHttpsAgent') 2 | const request = require('request') 3 | 4 | const options = { 5 | url: 'https://raw.githubusercontent.com/docmirror/dev-sidecar/refs/heads/master/packages/core/src/config/remote_config.json5', 6 | // url: 'https://gitee.com/wangliang181230/dev-sidecar/raw/docmirror2.x/packages/core/src/config/remote_config.json', 7 | servername: 'baidu.com', 8 | agent: new HttpsAgent({ 9 | keepAlive: true, 10 | timeout: 20000, 11 | keepAliveTimeout: 30000, 12 | rejectUnauthorized: false, 13 | }), 14 | } 15 | if (options.agent.options) { 16 | options.agent.options.rejectUnauthorized = false 17 | console.info('options.agent.options.rejectUnauthorized = false') 18 | } 19 | 20 | request(options, (error, response, body) => { 21 | console.info('error:', error, '\n---------------------------------------------------------------------------\n' 22 | + 'response:', response, '\n---------------------------------------------------------------------------\n' 23 | + 'body:', body) 24 | }) 25 | -------------------------------------------------------------------------------- /packages/core/test/versionTest.js: -------------------------------------------------------------------------------- 1 | const assert = require('node:assert') 2 | const { isNewVersion } = require('../src/utils/util.version.js') 3 | 4 | function testIsNewVersion (onlineVersion, currentVersion, expected) { 5 | const ret = isNewVersion(onlineVersion, currentVersion) 6 | console.log(ret >= 0 ? ` ${ret}` : `${ret}`) 7 | assert.strictEqual(ret, expected) 8 | } 9 | 10 | testIsNewVersion('2.0.0', '2.0.0', 0) 11 | 12 | testIsNewVersion('2.0.0', '1.0.0', 1) 13 | testIsNewVersion('1.0.0', '2.0.0', -1) 14 | 15 | testIsNewVersion('2.1.0', '2.0.0', 2) 16 | testIsNewVersion('2.0.0', '2.1.0', -2) 17 | 18 | testIsNewVersion('2.0.1', '2.0.0', 3) 19 | testIsNewVersion('2.0.0', '2.0.1', -3) 20 | 21 | testIsNewVersion('2.0.0.1', '2.0.0', 4) 22 | testIsNewVersion('2.0.0', '2.0.0.1', -4) 23 | 24 | testIsNewVersion('2.0.0.9.1', '2.0.0.9', 5) 25 | testIsNewVersion('2.0.0.9', '2.0.0.9.1', -5) 26 | 27 | testIsNewVersion('2.0.0-RC2', '2.0.0-RC1', 101) 28 | testIsNewVersion('2.0.0-RC1', '2.0.0-RC2', -101) 29 | 30 | testIsNewVersion('2.0.0', '2.0.0-RC1', 102) 31 | testIsNewVersion('2.0.0-RC1', '2.0.0', -102) 32 | 33 | testIsNewVersion('2.0.0.0', '2.0.0', 0) 34 | 35 | testIsNewVersion('x', 'v', -999) 36 | -------------------------------------------------------------------------------- /packages/gui/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /packages/gui/.env: -------------------------------------------------------------------------------- 1 | VUE_APP_PUBLISH_URL=http://dev-sidecar.docmirror.cn/update/ 2 | VUE_APP_PUBLISH_PROVIDER=generic 3 | -------------------------------------------------------------------------------- /packages/gui/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | *.lock 25 | *.log 26 | #Electron-builder output 27 | /dist_electron 28 | /config 29 | -------------------------------------------------------------------------------- /packages/gui/README.md: -------------------------------------------------------------------------------- 1 | # dev-sidecar-gui 2 | 3 | ## Project setup 4 | 5 | ``` 6 | yarn install 7 | ``` 8 | 9 | ### Compiles and hot-reloads for development 10 | 11 | ``` 12 | yarn serve 13 | ``` 14 | 15 | ### Compiles and minifies for production 16 | 17 | ``` 18 | yarn build 19 | ``` 20 | 21 | ### Lints and fixes files 22 | 23 | ``` 24 | yarn lint 25 | ``` 26 | 27 | ### Customize configuration 28 | 29 | See [Configuration Reference](https://cli.vuejs.org/config/). 30 | -------------------------------------------------------------------------------- /packages/gui/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/babel-preset-jsx', 4 | ], 5 | } 6 | -------------------------------------------------------------------------------- /packages/gui/build/icons/0x0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/0x0.png -------------------------------------------------------------------------------- /packages/gui/build/icons/1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/1024x1024.png -------------------------------------------------------------------------------- /packages/gui/build/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/128x128.png -------------------------------------------------------------------------------- /packages/gui/build/icons/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/16x16.png -------------------------------------------------------------------------------- /packages/gui/build/icons/24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/24x24.png -------------------------------------------------------------------------------- /packages/gui/build/icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/256x256.png -------------------------------------------------------------------------------- /packages/gui/build/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/32x32.png -------------------------------------------------------------------------------- /packages/gui/build/icons/32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/32x32@2x.png -------------------------------------------------------------------------------- /packages/gui/build/icons/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/48x48.png -------------------------------------------------------------------------------- /packages/gui/build/icons/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/512x512.png -------------------------------------------------------------------------------- /packages/gui/build/icons/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/64x64.png -------------------------------------------------------------------------------- /packages/gui/build/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/icon.icns -------------------------------------------------------------------------------- /packages/gui/build/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/icons/icon.ico -------------------------------------------------------------------------------- /packages/gui/build/mac/0x0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/mac/0x0.png -------------------------------------------------------------------------------- /packages/gui/build/mac/1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/mac/1024x1024.png -------------------------------------------------------------------------------- /packages/gui/build/mac/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/mac/128x128.png -------------------------------------------------------------------------------- /packages/gui/build/mac/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/mac/16x16.png -------------------------------------------------------------------------------- /packages/gui/build/mac/24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/mac/24x24.png -------------------------------------------------------------------------------- /packages/gui/build/mac/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/mac/256x256.png -------------------------------------------------------------------------------- /packages/gui/build/mac/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/mac/32x32.png -------------------------------------------------------------------------------- /packages/gui/build/mac/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/mac/48x48.png -------------------------------------------------------------------------------- /packages/gui/build/mac/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/mac/512x512.png -------------------------------------------------------------------------------- /packages/gui/build/mac/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/mac/64x64.png -------------------------------------------------------------------------------- /packages/gui/build/mac/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/mac/icon.icns -------------------------------------------------------------------------------- /packages/gui/build/mac/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/build/mac/icon.ico -------------------------------------------------------------------------------- /packages/gui/extra/EnableLoopback.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/EnableLoopback.exe -------------------------------------------------------------------------------- /packages/gui/extra/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/favicon.ico -------------------------------------------------------------------------------- /packages/gui/extra/icons/1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/1024x1024.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/128x128.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/16x16-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/16x16-black.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/16x16.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/24x24.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/256x256.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/32x32.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/48x48.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/512x512.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/64x64.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/icon.icns -------------------------------------------------------------------------------- /packages/gui/extra/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/icon.ico -------------------------------------------------------------------------------- /packages/gui/extra/icons/tray-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/tray-icon.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/tray/icon-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/tray/icon-black.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/tray/icon-black@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/tray/icon-black@2x.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/tray/icon-black@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/tray/icon-black@3x.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/tray/icon-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/tray/icon-white.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/tray/icon-white@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/tray/icon-white@2x.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/tray/icon-white@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/tray/icon-white@3x.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/tray/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/tray/icon.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/tray/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/tray/icon@2x.png -------------------------------------------------------------------------------- /packages/gui/extra/icons/tray/icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/icons/tray/icon@3x.png -------------------------------------------------------------------------------- /packages/gui/extra/scripts/google.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name google增强 3 | // @version 1.2.4 4 | // @author Greper 5 | // @description 去除ping链接 6 | // @match https://www.google.com/*/* 7 | // @icon https://www.google.com/favicon.ico 8 | // @license GPL-3.0 License 9 | // @run-at document-end 10 | // @namespace 11 | // ==/UserScript== 12 | 13 | (function () { 14 | console.log('google script loaded') 15 | const aList = document.getElementsByTagName('a') 16 | for (let i = 0; i <= aList.length; i++) { 17 | console.log(aList[i].href) 18 | aList[i].ping = undefined 19 | } 20 | })() 21 | -------------------------------------------------------------------------------- /packages/gui/extra/sysproxy.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/extra/sysproxy.exe -------------------------------------------------------------------------------- /packages/gui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@docmirror/dev-sidecar-gui", 3 | "version": "2.0.0", 4 | "private": false, 5 | "author": { 6 | "email": "xiaojunnuo@qq.com", 7 | "name": "Greper" 8 | }, 9 | "license": "MPL-2.0", 10 | "homepage": "https://github.com/docmirror/dev-sidecar", 11 | "scripts": { 12 | "serve": "vue-cli-service serve", 13 | "lint": "vue-cli-service lint", 14 | "electron:build": "vue-cli-service electron:build", 15 | "electron": "vue-cli-service electron:serve", 16 | "postinstall": "electron-builder install-app-deps", 17 | "postuninstall": "electron-builder install-app-deps", 18 | "electron:icons": "electron-icon-builder --input=./public/logo/win.png --output=build --flatten", 19 | "electron:icons-mac": "electron-icon-builder --input=./public/logo/mac.png --output=build --flatten", 20 | "electron:icons-black": "electron-icon-builder --input=./public/logo/win-black.png --output=build/black --flatten" 21 | }, 22 | "dependencies": { 23 | "@docmirror/dev-sidecar": "workspace:*", 24 | "@docmirror/mitmproxy": "workspace:*", 25 | "@starknt/shutdown-handler-napi": "^0.0.3", 26 | "@starknt/sysproxy": "^0.0.3", 27 | "@vscode/sudo-prompt": "^9.3.1", 28 | "adm-zip": "^0.5.16", 29 | "ant-design-vue": "^1.7.8", 30 | "electron-baidu-tongji": "^1.0.5", 31 | "electron-updater": "^6.3.9", 32 | "json5": "^2.2.3", 33 | "lodash": "^4.17.21", 34 | "request-progress": "^3.0.0", 35 | "sass": "^1.81.0", 36 | "sass-loader": "^16.0.3", 37 | "search-bar-vue2": "^1.0.0", 38 | "vue": "^2.7.16", 39 | "vue-json-editor-fix-cn": "^1.4.3", 40 | "vue-router": "^3.6.5" 41 | }, 42 | "devDependencies": { 43 | "@babel/plugin-syntax-jsx": "^7.25.9", 44 | "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", 45 | "@vue/babel-preset-jsx": "^1.4.0", 46 | "@vue/cli-plugin-babel": "^5.0.8", 47 | "@vue/cli-service": "^5.0.8", 48 | "electron": "^19.1.9", 49 | "electron-builder": "^25.1.8", 50 | "electron-icon-builder": "^2.0.1", 51 | "json5-loader": "^4.0.1", 52 | "vue-cli-plugin-electron-builder": "^3.0.0-alpha.4" 53 | }, 54 | "browserslist": [ 55 | "> 1%", 56 | "last 2 versions", 57 | "not dead" 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /packages/gui/pkg/after-all-artifact-build.js: -------------------------------------------------------------------------------- 1 | const fs = require('node:fs') 2 | const path = require('node:path') 3 | const pkg = require('../package.json') 4 | 5 | function appendIntro (context, systemType, latest) { 6 | const version = pkg.version 7 | const partUpdateFile = `update-${systemType}-${version}.zip` 8 | 9 | const partUpdateUrl = context.configuration.publish.url + partUpdateFile 10 | 11 | const latestFilePath = path.join(context.outDir, latest) 12 | fs.appendFile(latestFilePath, `partPackage: ${partUpdateUrl} 13 | partMiniVersion: 1.7.0 14 | releaseNotes: 15 | - 升级日志 16 | - https://download.fastgit.org/docmirror/dev-sidecar/releases/download/v${version}/DevSidecar-${version}.exe 17 | `, (err) => { 18 | if (err) { 19 | console.log('修改latest 失败') 20 | } 21 | }) 22 | } 23 | exports.default = async function (context) { 24 | console.log('after-all-artifact-build') 25 | appendIntro(context, 'mac', 'latest-mac.yml') 26 | appendIntro(context, 'win', 'latest.yml') 27 | appendIntro(context, 'linux', 'latest-linux.yml') 28 | } 29 | -------------------------------------------------------------------------------- /packages/gui/pkg/after-pack.js: -------------------------------------------------------------------------------- 1 | const fs = require('node:fs') 2 | const path = require('node:path') 3 | const AdmZip = require('adm-zip') 4 | const pkg = require('../package.json') 5 | 6 | function writeAppUpdateYmlForLinux () { 7 | const publishUrl = process.env.VUE_APP_PUBLISH_URL 8 | const publishProvider = process.env.VUE_APP_PUBLISH_PROVIDER 9 | // provider: generic 10 | // url: 'http://dev-sidecar.docmirror.cn/update/preview/' 11 | // updaterCacheDirName: '@docmirrordev-sidecar-gui-updater' 12 | const fileContent = `provider: ${publishProvider} 13 | url: '${publishUrl}' 14 | updaterCacheDirName: '@docmirrordev-sidecar-gui-updater' 15 | ` 16 | console.log('write linux app-update.yml,updateUrl:', publishUrl) 17 | const filePath = path.resolve('./dist_electron/linux-unpacked/resources/app-update.yml') 18 | fs.writeFileSync(filePath, fileContent) 19 | } 20 | exports.default = async function (context) { 21 | let targetPath 22 | let systemType 23 | if (context.packager.platform.nodeName === 'darwin') { 24 | targetPath = path.join(context.appOutDir, `${context.packager.appInfo.productName}.app/Contents/Resources`) 25 | systemType = 'mac' 26 | } else if (context.packager.platform.nodeName === 'linux') { 27 | targetPath = path.join(context.appOutDir, './resources') 28 | systemType = 'linux' 29 | writeAppUpdateYmlForLinux() 30 | } else { 31 | targetPath = path.join(context.appOutDir, './resources') 32 | systemType = 'win' 33 | } 34 | const zip = new AdmZip() 35 | zip.addLocalFolder(targetPath) 36 | const partUpdateFile = `update-${systemType}-${pkg.version}.zip` 37 | zip.writeZip(path.join(context.outDir, partUpdateFile)) 38 | } 39 | -------------------------------------------------------------------------------- /packages/gui/public/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/256x256.png -------------------------------------------------------------------------------- /packages/gui/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/favicon.ico -------------------------------------------------------------------------------- /packages/gui/public/icon-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/icon-1.png -------------------------------------------------------------------------------- /packages/gui/public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/icon.png -------------------------------------------------------------------------------- /packages/gui/public/icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/icon2.png -------------------------------------------------------------------------------- /packages/gui/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /packages/gui/public/loading-spin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/gui/public/logo/logo-fff.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/gui/public/logo/logo-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/logo/logo-only.png -------------------------------------------------------------------------------- /packages/gui/public/logo/logo-only.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/gui/public/logo/logo-only2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/logo/logo-only2.png -------------------------------------------------------------------------------- /packages/gui/public/logo/logo-only4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/logo/logo-only4.png -------------------------------------------------------------------------------- /packages/gui/public/logo/logo-simple-fan.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/gui/public/logo/logo-simple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/gui/public/logo/logo-simple2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/logo/logo-simple2.png -------------------------------------------------------------------------------- /packages/gui/public/logo/mac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/logo/mac.png -------------------------------------------------------------------------------- /packages/gui/public/logo/win-16.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | window 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/gui/public/logo/win-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/logo/win-black.png -------------------------------------------------------------------------------- /packages/gui/public/logo/win.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/logo/win.png -------------------------------------------------------------------------------- /packages/gui/public/logo/win.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | window 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /packages/gui/public/loopback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/loopback.png -------------------------------------------------------------------------------- /packages/gui/public/setup-linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/setup-linux.png -------------------------------------------------------------------------------- /packages/gui/public/setup-mac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/setup-mac.png -------------------------------------------------------------------------------- /packages/gui/public/setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docmirror/dev-sidecar/4d6be465c7c56ddfc5cbf25349ec95c003c7b001/packages/gui/public/setup.png -------------------------------------------------------------------------------- /packages/gui/src/background/powerMonitor.js: -------------------------------------------------------------------------------- 1 | import { acquireShutdownBlock, insertWndProcHook, releaseShutdownBlock, removeWndProcHook, setMainWindowHandle } from '@starknt/shutdown-handler-napi' 2 | import { powerMonitor as _powerMonitor } from 'electron' 3 | 4 | class PowerMonitor { 5 | constructor () { 6 | this.setup = false 7 | this._listeners = [] 8 | this._shutdownCallback = null 9 | } 10 | 11 | /** 12 | * @param {import('electron').BrowserWindow} window 13 | */ 14 | setupMainWindow (window) { 15 | if (!this.setup) { 16 | setMainWindowHandle(window.getNativeWindowHandle()) 17 | this.setup = true 18 | } 19 | } 20 | 21 | addListener (event, listener) { 22 | return this.on(event, listener) 23 | } 24 | 25 | removeListener (event, listener) { 26 | return this.off(event, listener) 27 | } 28 | 29 | removeAllListeners (event) { 30 | if (event === 'shutdown' && process.platform === 'win32') { 31 | this._listeners = [] 32 | if (this._shutdownCallback) { 33 | removeWndProcHook() 34 | releaseShutdownBlock() 35 | this._shutdownCallback = null 36 | } 37 | } else { 38 | return _powerMonitor.removeAllListeners(event) 39 | } 40 | } 41 | 42 | on (event, listener) { 43 | if (event === 'shutdown' && process.platform === 'win32') { 44 | if (!this._shutdownCallback) { 45 | this._shutdownCallback = async () => { 46 | await Promise.all(this._listeners.map(fn => fn())) 47 | releaseShutdownBlock() 48 | } 49 | insertWndProcHook(this._shutdownCallback) 50 | acquireShutdownBlock('正在停止 DevSidecar 代理') 51 | } 52 | this._listeners.push(listener) 53 | } else { 54 | return _powerMonitor.on(event, listener) 55 | } 56 | } 57 | 58 | off (event, listener) { 59 | if (event === 'shutdown' && process.platform === 'win32') { 60 | this._listeners = this._listeners.filter(fn => fn !== listener) 61 | } else { 62 | return _powerMonitor.off(event, listener) 63 | } 64 | } 65 | 66 | once (event, listener) { 67 | if (event === 'shutdown' && process.platform === 'win32') { 68 | return this.on(event, listener) 69 | } else { 70 | return _powerMonitor.once(event, listener) 71 | } 72 | } 73 | 74 | emit (event, ...args) { 75 | return _powerMonitor.emit(event, ...args) 76 | } 77 | 78 | eventNames () { 79 | return _powerMonitor.eventNames() 80 | } 81 | 82 | getMaxListeners () { 83 | return _powerMonitor.getMaxListeners() 84 | } 85 | 86 | listeners (event) { 87 | return _powerMonitor.listeners(event) 88 | } 89 | 90 | rawListeners (event) { 91 | return _powerMonitor.rawListeners(event) 92 | } 93 | 94 | listenerCount (event, listener) { 95 | return _powerMonitor.listenerCount(event, listener) 96 | } 97 | 98 | /** 99 | * @returns {boolean} 100 | */ 101 | get onBatteryPower () { 102 | return _powerMonitor.onBatteryPower 103 | } 104 | 105 | /** 106 | * @param {number} idleThreshold 107 | * @returns {'active'|'idle'|'locked'|'unknown'} 108 | */ 109 | getSystemIdleState (idleThreshold) { 110 | return _powerMonitor.getSystemIdleState(idleThreshold) 111 | } 112 | 113 | /** 114 | * @returns {number} 115 | */ 116 | getSystemIdleTime () { 117 | return _powerMonitor.getSystemIdleTime() 118 | } 119 | 120 | /** 121 | * @returns {'unknown'|'nominal'|'fair'|'serious'|'critical'} 122 | */ 123 | getCurrentThermalState () { 124 | return _powerMonitor.getCurrentThermalState() 125 | } 126 | 127 | /** 128 | * @returns {boolean} 129 | */ 130 | isOnBatteryPower () { 131 | return _powerMonitor.isOnBatteryPower() 132 | } 133 | } 134 | 135 | export const powerMonitor = new PowerMonitor() 136 | -------------------------------------------------------------------------------- /packages/gui/src/bridge/api/open-enable-loopback.js: -------------------------------------------------------------------------------- 1 | /* global __static */ 2 | import DevSidecar from '@docmirror/dev-sidecar' 3 | import sudoPrompt from '@vscode/sudo-prompt' 4 | import { join } from 'node:path' 5 | import log from '../../utils/util.log.gui' 6 | 7 | export default { 8 | open () { 9 | const options = { 10 | name: 'EnableLoopback', 11 | icns: process.platform === 'darwin' ? join(__static, 'icon.icns') : undefined, 12 | env: { PARAM: 'VALUE' }, 13 | } 14 | const exeFile = DevSidecar.api.shell.extraPath.getEnableLoopbackPath() 15 | const sudoCommand = [`"${exeFile}"`] 16 | 17 | return new Promise((resolve, reject) => { 18 | sudoPrompt.exec( 19 | sudoCommand.join(' '), 20 | options, 21 | (error, _, stderr) => { 22 | if (stderr) { 23 | log.error(`[sudo-prompt] 发生错误: ${stderr}`) 24 | } 25 | 26 | if (error) { 27 | reject(error) 28 | } else { 29 | resolve(undefined) 30 | } 31 | }, 32 | ) 33 | }) 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /packages/gui/src/bridge/auto-start/backend.js: -------------------------------------------------------------------------------- 1 | import DevSidecar from '@docmirror/dev-sidecar' 2 | 3 | async function setAutoStartForLinux (app, enable = true) { 4 | const path = app.getPath('exe') 5 | if (enable) { 6 | const cmd = ` 7 | mkdir -p ~/.config/autostart/ 8 | cat >> ~/.config/autostart/dev-sidecar.desktop <