Merge remote-tracking branch 'origin/master' into master
# Conflicts: # packages/mitmproxy/src/lib/proxy/mitmproxy/createRequestHandler.jspull/67/head
147
README.md
|
@ -1,58 +1,88 @@
|
|||
# dev-sidecar
|
||||
开发者边车,命名取自service-mesh的service-sidecar,意为为开发者打辅助的边车工具
|
||||
通过本地代理的方式将http请求代理到一些国内的加速通道上
|
||||
不用`ss小飞机`也能解决一些网站和库无法访问或访问速度慢的问题
|
||||
|
||||
不用`fan qiang`也能解决一些网站和库无法访问或访问速度慢的问题
|
||||
|
||||
<a href='https://gitee.com/docmirror/dev-sidecar'><img src='https://gitee.com/docmirror/dev-sidecar/badge/star.svg?theme=dark' alt='star'/></a>
|
||||
<a href='https://github.com/docmirror/dev-sidecar'><img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"></a>
|
||||
|
||||
|
||||
|
||||
## 特性
|
||||
|
||||
### 1、 github的release、source、zip下载加速
|
||||
可解决npm install 时某些安装包下载不下来的问题
|
||||
### 1、 dns优选
|
||||
根据网络状况智能解析最佳域名ip地址,获取最佳网络速度
|
||||
|
||||
### 2、 dns优选
|
||||
根据网络状况智能解析域名ip地址,获取最佳网络速度
|
||||
比如:
|
||||
1. 解决git push 偶尔失败需要输入账号密码的问题(fatal: TaskCanceledException encountered)
|
||||
2. 解决github头像加载不出来的问题
|
||||
3. 解决gist.github.com访问不到的问题
|
||||
建议遇到打开比较慢的国外网站,可以优先尝试将该域名添加到dns设置中(注意:被GFW封杀的无效)
|
||||
|
||||
### 3、 github的源代码查看(raw/blame查看)
|
||||
通过跳转到国内加速链接上
|
||||
### 2、 请求拦截
|
||||
拦截打不开的网站,代理到加速镜像站点上去。
|
||||
可配置多个镜像站作为备份
|
||||
具备测速机制,当访问失败或超时之后,自动切换到备用站点。
|
||||
使得目标服务高可用
|
||||
|
||||
### 3、 github加速
|
||||
* release、source、zip下载加速
|
||||
* clone 加速
|
||||
* 头像加速
|
||||
* 解决readme中图片引用无法加载的问题
|
||||
* gist.github.com 加速
|
||||
* 解决git push 偶尔失败需要输入账号密码的问题(fatal: TaskCanceledException encountered / fatal: HttpRequestException encountered)
|
||||
* raw/blame加速
|
||||
|
||||
### 4、 Stack Overflow 加速
|
||||
* 将ajax.google.com代理到加速CDN上
|
||||
* recaptcha 图片验证码加速
|
||||
|
||||
将ajax.google.com代理到加速CDN上
|
||||
recaptcha 图片验证码加速
|
||||
|
||||
|
||||
### 5、 google cdn 加速
|
||||
通过代理到加速链接上
|
||||
### 5、 npm加速
|
||||
* 支持开启npm代理
|
||||
* 官方与淘宝npm registry一键切换,
|
||||
* 某些npm install的时候,并且使用cnpm也无法安装时,可以尝试开启npm代理再试
|
||||
|
||||
### 6、 更多加速配置
|
||||
等你来提issue
|
||||
|
||||
## 快速开始
|
||||
目前仅支持windows
|
||||
### 1、 DevSidecar桌面应用发布啦
|
||||
暂时只支持windows
|
||||
|
||||
### DevSidecar桌面应用
|
||||
|
||||
#### 1.1 下载安装包
|
||||
[点此去下载](https://dev-sidecar.docmirror.cn/update/DevSidecar-1.0.2.exe)
|
||||
安装后打开:
|
||||
#### 1 下载安装包
|
||||
下载安装包:
|
||||
|
||||
[阿里云](https://dev-sidecar.docmirror.cn/update/DevSidecar-1.2.1.exe)
|
||||
|
||||
[Gitee Release](https://gitee.com/docmirror/dev-sidecar/releases)
|
||||
[Github Release](https://github.com/docmirror/dev-sidecar/releases)
|
||||
|
||||
安装后打开
|
||||
|
||||
|
||||
![](./doc/index.png)
|
||||
#### 1.2 安装根证书
|
||||
第一次打开会提示安装根证书
|
||||
#### 1.3 开始加速吧
|
||||
去试试打开github
|
||||
`Download ZIP`、`Release` 下载试试,体验秒下的感觉
|
||||
比如去下载它: https://github.com/greper/d2-crud-plus/archive/master.zip
|
||||
|
||||
#### 2 安装根证书
|
||||
|
||||
第一次打开会提示安装证书,根据提示操作即可
|
||||
|
||||
|
||||
>根证书是本地随机生成的,所以不用担心根证书的安全问题
|
||||
|
||||
|
||||
#### 3 开始加速吧
|
||||
去试试打开github
|
||||
|
||||
---------
|
||||
>第一次访问会去国外的dns服务器上获取ip,会比较慢一点,后面就快了
|
||||
---------
|
||||
|
||||
### 开启前 vs 开启后
|
||||
|
||||
| | 开启前 | 开启后 |
|
||||
| ---- | ---- | ---- |
|
||||
|头像| ![](./doc/avatar2.png) |![](./doc/avatar1.png) |
|
||||
|clone |![](./doc/clone-before.png) |![](./doc/clone.png) |
|
||||
|zip 下载 |![](./doc/download-before.png) |![](./doc/download.png)秒下的,实在截不到速度的图 |
|
||||
|
||||
#### 开启前vs 开启后
|
||||
![](./doc/avatar2.png)
|
||||
![](./doc/avatar1.png)
|
||||
|
||||
## 最佳实践
|
||||
|
||||
|
@ -60,17 +90,18 @@ recaptcha 图片验证码加速
|
|||
建议遇到打开比较慢的国外网站,可以优先尝试将该域名添加到dns设置中(注意:被GFW封杀的无效)
|
||||
如果还访问不了,就需要寻找镜像cdn进行拦截代理
|
||||
|
||||
### npm加速
|
||||
1. yarn 设置淘宝镜像registry
|
||||
2. npm设置官方registry。
|
||||
3. 项目install使用yarn,发布包publish用npm,互不影响
|
||||
4. 某些库用cnpm也下载不下来的话,可以试试打开dev-sidecar的npm加速
|
||||
### 其他加速
|
||||
1. git clone 加速
|
||||
1. git clone 加速
|
||||
|
||||
方式1:快捷复制:
|
||||
> 开启脚本支持,然后在复制clone链接下方,即可复制到加速链接
|
||||
|
||||
方式2:
|
||||
> 使用方式用实际的名称替换{}的内容,即可加速clone
|
||||
> https://hub.fastgit.org/{username}/{reponame}.git
|
||||
> clone 出来的 remote "origin" 为fastgit的地址,需要手动改回来
|
||||
> 你也可以直接使用他们的clone加速工具 [fgit-go](https://github.com/FastGitORG/fgit-go)
|
||||
|
||||
2. github.com的镜像网站(注意:不能登录)
|
||||
>1. [hub.fastgit.org](https://hub.fastgit.org/)
|
||||
>2. [github.com.cnpmjs.org](https://github.com.cnpmjs.org/) 这个很容易超限
|
||||
|
@ -90,14 +121,16 @@ const intercepts = {
|
|||
// redirect:url, 临时重定向(url会变,一些下载资源可以通过此方式配置)
|
||||
// proxy:url, 代理(url不会变,没有跨域问题)
|
||||
// abort:true, 取消请求(适用于被GFW封锁的资源,找不到替代,直接取消请求,快速失败,节省时间)
|
||||
// success:true, 直接返回成功请求(某些请求不想发出去,可以伪装成功返回)
|
||||
redirect: 'download.fastgit.org'
|
||||
},
|
||||
},
|
||||
'ajax.googleapis.com': {
|
||||
'.*': {
|
||||
proxy: 'ajax.loli.net', //代理请求,url不会变
|
||||
backup: ['ajax.proxy.ustclug.org'],
|
||||
test: 'ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js'
|
||||
backup: ['ajax.proxy.ustclug.org'], //备份,当前代理请求失败后,将会切换到备用地址
|
||||
test: 'ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js',
|
||||
replace:'/(.*)/xxx'//当加速地址的链接和原链接不是完全相同时,可以通过正则表达式replace,此时proxy通过$1$2来重组url, proxy:'ajax.loli.net/xxx/$1'
|
||||
}
|
||||
},
|
||||
'clients*.google.com': {
|
||||
|
@ -108,11 +141,9 @@ const intercepts = {
|
|||
}
|
||||
```
|
||||
|
||||
### DNS优选
|
||||
某些域名(比如api.github.com)会被解析到新加坡的ip上,新加坡的服务器在上午挺好,到了晚上就卡死,基本不可用。
|
||||
所以将这些域名解析到美国服务器上就可以正常访问
|
||||
|
||||
另外,配置了dns mapping的域名,将会从dns获取到的ip列表中选择相对快一点的服务器进行访问
|
||||
### DNS优选配置
|
||||
某些域名解析出来的ip会无法访问,(比如api.github.com会被解析到新加坡的ip上,新加坡的服务器在上午挺好,到了晚上就卡死,基本不可用)
|
||||
通过从dns上获取ip列表,切换不同的ip进行尝试,最终会挑选到一个最快的ip
|
||||
|
||||
```js
|
||||
dns: {
|
||||
|
@ -126,6 +157,31 @@ const intercepts = {
|
|||
```
|
||||
注意:暂时只支持IPv4的解析
|
||||
|
||||
## 问题排查
|
||||
如果没有加速效果,请根据以下步骤进行排查
|
||||
|
||||
#### 1、请确认windows的代理设置处于勾选状态
|
||||
如何打开查看windows代理设置:
|
||||
* win10: 开始->设置->网络和Internet->最下方代理
|
||||
* win7: 开始->控制面板->网络和Internet->网络和共享中心->左下角Internet选项->连接选项卡->局域网设置
|
||||
|
||||
![](./doc/proxy.png)
|
||||
|
||||
#### 2. 360软件会严重拖慢设置代理命令的执行时间
|
||||
如果开启了360,那么软件开启windows代理的时间会特别长,需要耐心等待。
|
||||
|
||||
#### 3.如果还是不行,请在下方加作者好友,将服务日志发送给作者进行分析
|
||||
日志打开方式:加速服务->右边日志按钮->另存为
|
||||
|
||||
![](./doc/log.png)
|
||||
|
||||
## 联系作者
|
||||
|
||||
欢迎bug反馈,需求建议,技术交流等(请备注dev-sidecar,或简称DS)
|
||||
|
||||
![](./doc/contact.png)
|
||||
|
||||
|
||||
## 感谢
|
||||
本项目使用lerna包管理工具
|
||||
|
||||
|
@ -134,6 +190,7 @@ const intercepts = {
|
|||
本项目参考如下开源项目
|
||||
* [node-mitmproxy](https://github.com/wuchangming/node-mitmproxy)
|
||||
* [ReplaceGoogleCDN](https://github.com/justjavac/ReplaceGoogleCDN)
|
||||
* [github增强油猴脚本](https://greasyfork.org/zh-CN/scripts/412245-github-%E5%A2%9E%E5%BC%BA-%E9%AB%98%E9%80%9F%E4%B8%8B%E8%BD%BD)
|
||||
|
||||
本项目加速资源由如下组织提供
|
||||
* [fastgit](https://fastgit.org/)
|
||||
|
|
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 615 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 6.2 KiB |
BIN
doc/index.png
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 173 KiB |
|
@ -14,5 +14,5 @@
|
|||
"ignore": []
|
||||
}
|
||||
},
|
||||
"version": "1.1.0"
|
||||
"version": "1.2.1"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docmirror/dev-sidecar",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docmirror/dev-sidecar",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.1",
|
||||
"description": "给开发者的加速代理工具",
|
||||
"main": "src/index.js",
|
||||
"keywords": [
|
||||
|
@ -16,7 +16,7 @@
|
|||
"start": "node ./start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docmirror/mitmproxy": "^1.1.0",
|
||||
"@docmirror/mitmproxy": "^1.2.1",
|
||||
"agentkeepalive": "^2.1.1",
|
||||
"charset": "^1.0.0",
|
||||
"child_process": "^1.0.2",
|
||||
|
@ -30,6 +30,7 @@
|
|||
"jschardet": "^1.4.1",
|
||||
"json5": "^2.1.3",
|
||||
"lodash": "^4.7.0",
|
||||
"log4js": "^6.3.0",
|
||||
"lru-cache": "^6.0.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"node-cmd": "^3.0.0",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const Shell = require('./shell')
|
||||
const lodash = require('lodash')
|
||||
const defConfig = require('./config/index.js')
|
||||
const proxyServer = require('@docmirror/mitmproxy')
|
||||
|
||||
let configTarget = lodash.cloneDeep(defConfig)
|
||||
function _deleteDisabledItem (target) {
|
||||
lodash.forEach(target, (item, key) => {
|
||||
|
@ -13,6 +13,7 @@ function _deleteDisabledItem (target) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
const configApi = {
|
||||
get () {
|
||||
return configTarget
|
||||
|
@ -68,7 +69,7 @@ const configApi = {
|
|||
})
|
||||
if (list.length > 0) {
|
||||
const context = {
|
||||
ca_cert_path: proxyServer.config.getDefaultCACertPath()
|
||||
root_ca_cert_path: configApi.get().server.setting.rootCaFile.certPath
|
||||
}
|
||||
for (const item of noSetList) {
|
||||
if (item.value.indexOf('${') >= 0) {
|
||||
|
|
|
@ -1,30 +1,73 @@
|
|||
const path = require('path')
|
||||
function getUserBasePath () {
|
||||
const userHome = process.env.USERPROFILE
|
||||
return path.resolve(userHome, './.dev-sidecar')
|
||||
}
|
||||
function getRootCaCertPath () {
|
||||
return getUserBasePath() + '/dev-sidecar.ca.crt'
|
||||
}
|
||||
function getRootCaKeyPath () {
|
||||
return getUserBasePath() + '/dev-sidecar.ca.key.pem'
|
||||
}
|
||||
module.exports = {
|
||||
server: {
|
||||
enabled: true,
|
||||
port: 1181,
|
||||
setting: {
|
||||
NODE_TLS_REJECT_UNAUTHORIZED: true
|
||||
NODE_TLS_REJECT_UNAUTHORIZED: true,
|
||||
script: {
|
||||
enabled: true,
|
||||
defaultDir: '../../../scripts/'
|
||||
},
|
||||
userBasePath: getUserBasePath(),
|
||||
rootCaFile: {
|
||||
certPath: getRootCaCertPath(),
|
||||
keyPath: getRootCaKeyPath()
|
||||
}
|
||||
},
|
||||
intercepts: {
|
||||
'github.com': {
|
||||
'/.*/.*/releases/download/': {
|
||||
redirect: 'download.fastgit.org'
|
||||
redirect: 'download.fastgit.org',
|
||||
desc: 'release文件加速下载跳转地址'
|
||||
},
|
||||
'/.*/.*/archive/': {
|
||||
redirect: 'download.fastgit.org'
|
||||
},
|
||||
'/.*/.*/raw/': {
|
||||
redirect: 'hub.fastgit.org'
|
||||
replace: '(.+)\\/raw\\/(.+)',
|
||||
proxy: 'raw.fastgit.org$1/$2'
|
||||
},
|
||||
'/.*/.*/blame/': {
|
||||
redirect: 'hub.fastgit.org'
|
||||
},
|
||||
'^/[^/]+/[^/]+$': {
|
||||
script: [
|
||||
'jquery',
|
||||
'github'
|
||||
],
|
||||
desc: 'clone加速复制链接脚本'
|
||||
},
|
||||
'/.*': {
|
||||
proxy: 'github.com',
|
||||
backup: [
|
||||
'gh.docmirror.top/_proxy'
|
||||
],
|
||||
desc: '如果出现dev-sidecar报错,可能是备用加速地址dns被污染了,需要将本条配置删除'
|
||||
}
|
||||
},
|
||||
'api.github.com': {
|
||||
'^/_private/browser/stats$': {
|
||||
success: true,
|
||||
desc: 'github的访问速度分析上传,没有必要,直接返回成功'
|
||||
}
|
||||
},
|
||||
'raw.githubusercontent.com': {
|
||||
'.*': { proxy: 'raw.fastgit.org' }
|
||||
},
|
||||
'github11.githubassets.com': {
|
||||
'.*': { proxy: 'assets.fastgit.org', test: 'https://github.githubassets.com/favicons/favicon.svg' }
|
||||
'github.githubassets.com': {
|
||||
'.*': { proxy: 'assets.fastgit.org', test: 'https://github.githubassets.com/favicons/favicon.svg', desc: '静态资源加速' }
|
||||
|
||||
},
|
||||
'customer-stories-feed.github.com': {
|
||||
'.*': { proxy: 'customer-stories-feed.fastgit.org' }
|
||||
|
@ -78,7 +121,13 @@ module.exports = {
|
|||
'archive.cloudera.com': { '.*': { regexp: '/cdh5/.*', proxy: 'cloudera.proxy.ustclug.org' } },
|
||||
'downloads.lede-project.org': { '.*': { proxy: 'lede.proxy.ustclug.org' } },
|
||||
'downloads.openwrt.org': { '.*': { proxy: 'openwrt.proxy.ustclug.org' } },
|
||||
'secure.gravatar.com': { '.*': { proxy: 'gravatar.proxy.ustclug.org' } }
|
||||
'secure.gravatar.com': { '.*': { proxy: 'gravatar.proxy.ustclug.org' } },
|
||||
'*.carbonads.com': {
|
||||
'/carbon.*': {
|
||||
abort: true,
|
||||
desc: '广告拦截'
|
||||
}
|
||||
}
|
||||
},
|
||||
whiteList: {
|
||||
'alipay.com': true,
|
||||
|
@ -100,11 +149,16 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
mapping: {
|
||||
'*github.io': 'usa',
|
||||
'img.shields.io': 'usa',
|
||||
'*.github.com': 'usa',
|
||||
'*.githubusercontent.com': 'usa',
|
||||
'*.githubassets.com': 'usa',
|
||||
// "解决push的时候需要输入密码的问题",
|
||||
'github.com': 'usa'
|
||||
'github.com': 'usa',
|
||||
'*.vuepress.vuejs.org': 'usa',
|
||||
'github.docmirror.cn': 'usa',
|
||||
'gh.docmirror.top': 'usa'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -4,14 +4,13 @@ const event = require('./event')
|
|||
const shell = require('./shell')
|
||||
const modules = require('./modules')
|
||||
const lodash = require('lodash')
|
||||
const proxyServer = require('@docmirror/mitmproxy')
|
||||
const proxyConfig = proxyServer.config
|
||||
const log = require('./utils/util.log')
|
||||
const context = {
|
||||
config,
|
||||
shell,
|
||||
status,
|
||||
event,
|
||||
rootCaFile: proxyConfig.getDefaultCACertPath()
|
||||
log
|
||||
}
|
||||
|
||||
function setupPlugin (key, plugin, context, config) {
|
||||
|
@ -43,14 +42,14 @@ module.exports = {
|
|||
try {
|
||||
await server.start({ mitmproxyPath })
|
||||
} catch (err) {
|
||||
console.error('代理服务启动失败:', err)
|
||||
log.error('代理服务启动失败:', err)
|
||||
}
|
||||
}
|
||||
if (conf.proxy.enabled) {
|
||||
try {
|
||||
await proxy.start()
|
||||
} catch (err) {
|
||||
console.error('开启系统代理失败:', err)
|
||||
log.error('开启系统代理失败:', err)
|
||||
}
|
||||
}
|
||||
try {
|
||||
|
@ -60,9 +59,9 @@ module.exports = {
|
|||
const start = async () => {
|
||||
try {
|
||||
await plugin[key].start()
|
||||
console.log(`插件【${key}】已启动`)
|
||||
log.info(`插件【${key}】已启动`)
|
||||
} catch (err) {
|
||||
console.log(`插件【${key}】启动失败`, err)
|
||||
log.error(`插件【${key}】启动失败`, err)
|
||||
}
|
||||
}
|
||||
plugins.push(start())
|
||||
|
@ -72,7 +71,7 @@ module.exports = {
|
|||
await Promise.all(plugins)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('开启插件失败:', err)
|
||||
log.error('开启插件失败:', err)
|
||||
}
|
||||
},
|
||||
shutdown: async () => {
|
||||
|
@ -83,9 +82,9 @@ module.exports = {
|
|||
const close = async () => {
|
||||
try {
|
||||
await plugin[key].close()
|
||||
console.log(`插件【${key}】已关闭`)
|
||||
log.info(`插件【${key}】已关闭`)
|
||||
} catch (err) {
|
||||
console.log(`插件【${key}】关闭失败`, err)
|
||||
log.info(`插件【${key}】关闭失败`, err)
|
||||
}
|
||||
}
|
||||
plugins.push(close())
|
||||
|
@ -95,23 +94,23 @@ module.exports = {
|
|||
await Promise.all(plugins)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('插件关闭失败'.error)
|
||||
log.error('插件关闭失败'.error)
|
||||
}
|
||||
|
||||
if (status.proxy.enabled) {
|
||||
try {
|
||||
await proxy.close()
|
||||
console.log('系统代理已关闭')
|
||||
log.info('系统代理已关闭')
|
||||
} catch (err) {
|
||||
console.error('系统代理关闭失败', err)
|
||||
log.error('系统代理关闭失败', err)
|
||||
}
|
||||
}
|
||||
if (status.server.enabled) {
|
||||
try {
|
||||
await server.close()
|
||||
console.log('代理服务已关闭')
|
||||
log.info('代理服务已关闭')
|
||||
} catch (err) {
|
||||
console.error('代理服务关闭失败', err)
|
||||
log.error('代理服务关闭失败', err)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -125,6 +124,7 @@ module.exports = {
|
|||
shell,
|
||||
server,
|
||||
proxy,
|
||||
plugin
|
||||
plugin,
|
||||
log
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const expose = require('./expose.js')
|
||||
|
||||
const log = require('./utils/util.log')
|
||||
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
||||
|
||||
// 避免异常崩溃
|
||||
|
@ -8,11 +8,11 @@ process.on('uncaughtException', function (err) {
|
|||
// console.error(err.errno)
|
||||
return
|
||||
}
|
||||
console.error('uncaughtException', err)
|
||||
log.error('uncaughtException', err)
|
||||
})
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason)
|
||||
log.error('Unhandled Rejection at: Promise', p, 'reason:', reason)
|
||||
// application specific logging, throwing an error, or other logic here
|
||||
})
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
const nodeConfig = require('./config')
|
||||
const NodePlugin = function (context) {
|
||||
const { config, shell, event, rootCaFile } = context
|
||||
const { config, shell, event, log } = context
|
||||
const nodeApi = {
|
||||
async start () {
|
||||
try {
|
||||
await nodeApi.setVariables()
|
||||
} catch (err) {
|
||||
console.warn('set variables error', err)
|
||||
log.warn('set variables error', err)
|
||||
}
|
||||
|
||||
const ip = '127.0.0.1'
|
||||
|
@ -101,16 +101,17 @@ const NodePlugin = function (context) {
|
|||
NODE_TLS_REJECT_UNAUTHORIZED: false
|
||||
*/
|
||||
const nodeConfig = config.get().plugin.node
|
||||
const rootCaCertFile = config.get().server.setting.rootCaFile.certPath
|
||||
if (nodeConfig.setting['strict-ssl']) {
|
||||
cmds.push('npm config set strict-ssl false')
|
||||
}
|
||||
if (nodeConfig.setting.cafile) {
|
||||
cmds.push(`npm config set cafile "${rootCaFile}"`)
|
||||
cmds.push(`npm config set cafile "${rootCaCertFile}"`)
|
||||
}
|
||||
|
||||
if (nodeConfig.setting.NODE_EXTRA_CA_CERTS) {
|
||||
cmds.push(`npm config set NODE_EXTRA_CA_CERTS "${rootCaFile}"`)
|
||||
env.push({ key: 'NODE_EXTRA_CA_CERTS', value: rootCaFile })
|
||||
cmds.push(`npm config set NODE_EXTRA_CA_CERTS "${rootCaCertFile}"`)
|
||||
env.push({ key: 'NODE_EXTRA_CA_CERTS', value: rootCaCertFile })
|
||||
}
|
||||
|
||||
if (nodeConfig.setting.NODE_TLS_REJECT_UNAUTHORIZED) {
|
||||
|
@ -123,7 +124,7 @@ const NodePlugin = function (context) {
|
|||
await shell.setSystemEnv({ list: env })
|
||||
}
|
||||
event.fire('status', { key: 'plugin.node.enabled', value: true })
|
||||
console.info('开启【NPM】代理成功')
|
||||
log.info('开启【NPM】代理成功')
|
||||
|
||||
return ret
|
||||
},
|
||||
|
@ -137,7 +138,7 @@ const NodePlugin = function (context) {
|
|||
]
|
||||
const ret = await shell.exec(cmds, { type: 'cmd' })
|
||||
event.fire('status', { key: 'plugin.node.enabled', value: false })
|
||||
console.info('关闭【NPM】代理成功')
|
||||
log.info('关闭【NPM】代理成功')
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const ProxyPlugin = function (context) {
|
||||
const { config, event, shell } = context
|
||||
const { config, event, shell, log } = context
|
||||
const api = {
|
||||
async start () {
|
||||
return api.setProxy()
|
||||
|
@ -13,7 +13,7 @@ const ProxyPlugin = function (context) {
|
|||
const ip = '127.0.0.1'
|
||||
const port = config.get().server.port
|
||||
await shell.setSystemProxy({ ip, port })
|
||||
console.log(`开启系统代理成功:${ip}:${port}`)
|
||||
log.info(`开启系统代理成功:${ip}:${port}`)
|
||||
event.fire('status', { key: 'proxy.enabled', value: true })
|
||||
return { ip, port }
|
||||
},
|
||||
|
@ -21,11 +21,11 @@ const ProxyPlugin = function (context) {
|
|||
async unsetProxy () {
|
||||
try {
|
||||
await shell.setSystemProxy()
|
||||
event.fire('status', { key: 'proxy.enabled', vlaue: false })
|
||||
console.log('关闭系统代理成功')
|
||||
event.fire('status', { key: 'proxy.enabled', value: false })
|
||||
log.info('关闭系统代理成功')
|
||||
return true
|
||||
} catch (err) {
|
||||
console.error('关闭系统代理失败', err)
|
||||
log.error('关闭系统代理失败', err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ const event = require('../../event')
|
|||
const status = require('../../status')
|
||||
const lodash = require('lodash')
|
||||
const fork = require('child_process').fork
|
||||
const log = require('../../utils/util.log')
|
||||
const fs = require('fs')
|
||||
let server
|
||||
function fireStatus (status) {
|
||||
event.fire('status', { key: 'server.enabled', value: status })
|
||||
|
@ -44,7 +46,10 @@ const serverApi = {
|
|||
})
|
||||
}
|
||||
// fireStatus('ing') // 启动中
|
||||
const serverProcess = fork(mitmproxyPath, [JSON.stringify(serverConfig)])
|
||||
const basePath = serverConfig.setting.userBasePath
|
||||
const runningConfig = basePath + '/running.json'
|
||||
fs.writeFileSync(runningConfig, JSON.stringify(serverConfig))
|
||||
const serverProcess = fork(mitmproxyPath, [runningConfig])
|
||||
server = {
|
||||
id: serverProcess.pid,
|
||||
process: serverProcess,
|
||||
|
@ -53,7 +58,7 @@ const serverApi = {
|
|||
}
|
||||
}
|
||||
serverProcess.on('message', function (msg) {
|
||||
console.log('收到子进程消息', msg)
|
||||
log.info('收到子进程消息', msg)
|
||||
if (msg.type === 'status') {
|
||||
fireStatus(msg.event)
|
||||
} else if (msg.type === 'error') {
|
||||
|
@ -63,7 +68,7 @@ const serverApi = {
|
|||
event.fire('error', { key: 'server', value: 'EADDRINUSE', error: msg.event })
|
||||
}
|
||||
})
|
||||
return { port: config.port }
|
||||
return { port: runningConfig.port }
|
||||
},
|
||||
async kill () {
|
||||
if (server) {
|
||||
|
@ -81,21 +86,21 @@ const serverApi = {
|
|||
// fireStatus('ing')// 关闭中
|
||||
server.close((err) => {
|
||||
if (err) {
|
||||
console.log('close error', err, ',', err.code, ',', err.message, ',', err.errno)
|
||||
log.info('close error', err, ',', err.code, ',', err.message, ',', err.errno)
|
||||
if (err.code === 'ERR_SERVER_NOT_RUNNING') {
|
||||
console.log('代理服务关闭成功')
|
||||
log.info('代理服务关闭成功')
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
console.log('代理服务关闭失败', err)
|
||||
log.info('代理服务关闭失败', err)
|
||||
reject(err)
|
||||
} else {
|
||||
console.log('代理服务关闭成功')
|
||||
log.info('代理服务关闭成功')
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
console.log('server is null')
|
||||
log.info('server is null')
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
|
|
|
@ -7,7 +7,7 @@ const Registry = require('winreg')
|
|||
// const cmd = require('node-cmd')
|
||||
const refreshInternetPs = require('./refresh-internet')
|
||||
const PowerShell = require('node-powershell')
|
||||
|
||||
const log = require('../../../utils/util.log')
|
||||
const _lanIP = [
|
||||
'localhost',
|
||||
'127.*',
|
||||
|
@ -42,9 +42,9 @@ async function _winUnsetProxy (exec) {
|
|||
_winAsyncRegSet(regKey, 'ProxyEnable', Registry.REG_DWORD, 0),
|
||||
_winAsyncRegSet(regKey, 'ProxyServer', Registry.REG_SZ, '')
|
||||
])
|
||||
console.log('代理关闭成功,等待refresh')
|
||||
log.info('代理关闭成功,等待refresh')
|
||||
await exec(refreshInternetPs, { type: 'ps' })
|
||||
console.log('代理关闭refresh完成')
|
||||
log.info('代理关闭refresh完成')
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ async function _winSetProxy (exec, ip, port) {
|
|||
for (const string of _lanIP) {
|
||||
lanIpStr += string + ';'
|
||||
}
|
||||
// console.log('lanIps:', lanIpStr, ip, port)
|
||||
// log.info('lanIps:', lanIpStr, ip, port)
|
||||
await Promise.all([
|
||||
_winAsyncRegSet(regKey, 'MigrateProxy', Registry.REG_DWORD, 1),
|
||||
_winAsyncRegSet(regKey, 'ProxyEnable', Registry.REG_DWORD, 1),
|
||||
|
@ -66,9 +66,9 @@ async function _winSetProxy (exec, ip, port) {
|
|||
_winAsyncRegSet(regKey, 'ProxyServer', Registry.REG_SZ, `${ip}:${port}`),
|
||||
_winAsyncRegSet(regKey, 'ProxyOverride', Registry.REG_SZ, lanIpStr)
|
||||
])
|
||||
console.log('代理设置成功,等待refresh')
|
||||
log.info('代理设置成功,等待refresh')
|
||||
await exec(refreshInternetPs)
|
||||
console.log('代理设置refresh完成')
|
||||
log.info('代理设置refresh完成')
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -84,32 +84,16 @@ function _winAsyncRegSet (regKey, name, type, value) {
|
|||
})
|
||||
}
|
||||
|
||||
async function _winResetWininetProxySettings (script) {
|
||||
const ps = new PowerShell({
|
||||
executionPolicy: 'Bypass',
|
||||
noProfile: true
|
||||
})
|
||||
ps.addCommand(script)
|
||||
|
||||
try {
|
||||
const ret = await ps.invoke()
|
||||
console.log('ps complete', script)
|
||||
return ret
|
||||
} finally {
|
||||
ps.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
const executor = {
|
||||
async windows (exec, params) {
|
||||
if (params == null) {
|
||||
// 清空代理
|
||||
console.log('关闭代理')
|
||||
log.info('关闭代理')
|
||||
return _winUnsetProxy(exec)
|
||||
} else {
|
||||
// 设置代理
|
||||
const { ip, port } = params
|
||||
console.log('设置代理', ip, port)
|
||||
log.info('设置代理', ip, port)
|
||||
return _winSetProxy(exec, ip, port)
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
const Shell = require('../shell')
|
||||
const execute = Shell.execute
|
||||
const proxyServer = require('@docmirror/mitmproxy')
|
||||
const executor = {
|
||||
async windows (exec) {
|
||||
const cmds = ['start ' + proxyServer.config.getDefaultCACertPath()]
|
||||
async windows (exec, { certPath }) {
|
||||
const cmds = ['start "" "' + certPath + '"']
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const ret = await exec(cmds, { type: 'cmd' })
|
||||
return true
|
||||
},
|
||||
async linux (exec, { port }) {
|
||||
async linux (exec, { certPath }) {
|
||||
throw Error('暂未实现此功能')
|
||||
},
|
||||
async mac (exec, { port }) {
|
||||
async mac (exec, { certPath }) {
|
||||
throw Error('暂未实现此功能')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ const childProcess = require('child_process')
|
|||
const _exec = childProcess.exec
|
||||
const exec = util.promisify(_exec)
|
||||
const PowerShell = require('node-powershell')
|
||||
|
||||
const log = require('../utils/util.log')
|
||||
class SystemShell {
|
||||
static async exec (cmds, args) {
|
||||
throw new Error('You have to implement the method exec!')
|
||||
|
@ -52,7 +52,7 @@ class WindowsSystemShell extends SystemShell {
|
|||
|
||||
try {
|
||||
const ret = await ps.invoke()
|
||||
// console.log('ps complete', cmds)
|
||||
// log.info('ps complete', cmds)
|
||||
return ret
|
||||
} finally {
|
||||
ps.dispose()
|
||||
|
@ -64,7 +64,7 @@ class WindowsSystemShell extends SystemShell {
|
|||
}
|
||||
// compose += '&& exit'
|
||||
const ret = await childExec(compose)
|
||||
// console.log('cmd complete:', compose)
|
||||
// log.info('cmd complete:', compose)
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
@ -75,13 +75,13 @@ function childExec (composeCmds) {
|
|||
const childProcess = require('child_process')
|
||||
childProcess.exec(composeCmds, function (error, stdout, stderr) {
|
||||
if (error) {
|
||||
console.error('cmd 命令执行错误:', composeCmds, error, stderr)
|
||||
log.error('cmd 命令执行错误:', composeCmds, error, stderr)
|
||||
reject(error)
|
||||
} else {
|
||||
// console.log('cmd 命令完成:', stdout)
|
||||
// log.info('cmd 命令完成:', stdout)
|
||||
resolve(stdout)
|
||||
}
|
||||
// console.log('关闭 cmd')
|
||||
// log.info('关闭 cmd')
|
||||
// ps.kill('SIGINT')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const event = require('./event')
|
||||
const lodash = require('lodash')
|
||||
const log = require('./utils/util.log')
|
||||
const status = {
|
||||
server: { enabled: false },
|
||||
proxy: {},
|
||||
|
@ -8,7 +9,7 @@ const status = {
|
|||
|
||||
event.register('status', (event) => {
|
||||
lodash.set(status, event.key, event.value)
|
||||
console.log('status changed:', event)
|
||||
log.info('status changed:', event)
|
||||
}, -999)
|
||||
|
||||
module.exports = status
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
const os = require('os')
|
||||
module.exports = {
|
||||
isWindows7 () {
|
||||
const version = os.release()
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
const os = require('os')
|
||||
const util = {
|
||||
getNodeVersion () {
|
||||
const version = process.version
|
||||
console.log(version)
|
||||
}
|
||||
}
|
||||
util.getNodeVersion()
|
||||
module.exports = util
|
|
@ -0,0 +1,11 @@
|
|||
const log4js = require('log4js')
|
||||
const config = require('../config/index')
|
||||
function getDefaultConfigBasePath () {
|
||||
return config.server.setting.userBasePath
|
||||
}
|
||||
log4js.configure({
|
||||
appenders: { std: { type: 'stdout' }, file: { type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename: getDefaultConfigBasePath() + '/logs/core.log' } },
|
||||
categories: { default: { appenders: ['file', 'std'], level: 'info' } }
|
||||
})
|
||||
const logger = log4js.getLogger('server')
|
||||
module.exports = logger
|
|
@ -0,0 +1,3 @@
|
|||
const proxyConfig = require('@docmirror/mitmproxy/config.js')
|
||||
module.exports = {
|
||||
}
|
|
@ -1,4 +1,10 @@
|
|||
// eslint-disable-next-line no-unused-vars
|
||||
const server = require('@docmirror/mitmproxy')
|
||||
const config = JSON.parse(process.argv[2])
|
||||
const configPath = process.argv[2]
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const configJson = fs.readFileSync(configPath)
|
||||
const config = JSON.parse(configJson)
|
||||
const scriptDir = '../../gui/extra/scripts/'
|
||||
config.setting.script.defaultDir = path.join(__dirname, scriptDir)
|
||||
server.start(config)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
abort: true
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
plugin: {
|
||||
node: {
|
||||
|
|
|
@ -0,0 +1,288 @@
|
|||
// ==UserScript==
|
||||
// @name Github 增强 - 高速下载
|
||||
// @version 1.2.4
|
||||
// @author X.I.U
|
||||
// @description 高速下载 Clone、Release、Raw、Code(ZIP) 等文件、项目列表单文件快捷下载 (☁)
|
||||
// @match https://github.com/*/*
|
||||
// @match https://github.com/*/*/releases
|
||||
// @match https://github.com/*/*/releases/*
|
||||
// @icon https://github.githubassets.com/favicon.ico
|
||||
// @require https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js
|
||||
// @grant GM_registerMenuCommand
|
||||
// @grant GM_unregisterMenuCommand
|
||||
// @grant GM_openInTab
|
||||
// @grant GM_getValue
|
||||
// @grant GM_setValue
|
||||
// @grant GM_notification
|
||||
// @license GPL-3.0 License
|
||||
// @run-at document-end
|
||||
// @namespace https://greasyfork.org/scripts/412245
|
||||
// ==/UserScript==
|
||||
|
||||
(function () {
|
||||
console.log('github script loaded')
|
||||
var download_url = [
|
||||
'https://gh.con.sh',
|
||||
'https://gh.api.99988866.xyz',
|
||||
'https://download.fastgit.org',
|
||||
'https://pd.zwc365.com/seturl',
|
||||
'https://g.ioiox.com',
|
||||
'https://git.yumenaka.net'
|
||||
]
|
||||
var download_url_name = ['美国', '美国', '日本东京', '中国香港', '中国香港', '美国洛杉矶']
|
||||
var clone_url = [
|
||||
'https://hub.fastgit.org',
|
||||
'https://gitclone.com',
|
||||
'https://github.com.cnpmjs.org'
|
||||
]
|
||||
var raw_url = [
|
||||
'https://raw.githubusercontent.com',
|
||||
'https://cdn.jsdelivr.net',
|
||||
'https://raw.fastgit.org'
|
||||
]
|
||||
var raw_url_name = ['Github 原生', '中国国内', '中国香港', '美国洛杉矶']
|
||||
var raw_url_tip = [
|
||||
'',
|
||||
'注意:该加速源存在缓存机制(24小时),所以文件可能不是最新。 注意:当前分支所有文件总文件大小超过 50MB 时,该加速源不可用。 注意:当前分支名为版本号格式时(如 v1.2.3),该高速下载链接因格式限制不可用。 ',
|
||||
'注意:单个文件太大时可能会提示超时(实时获取中),请重试。 ',
|
||||
'注意:经过测试,该加速源存在文件格式限制,如果无法下载说明不支持该文件格式。 '
|
||||
]
|
||||
var svg = [
|
||||
'<svg class="octicon octicon-file-zip mr-3" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M3.5 1.75a.25.25 0 01.25-.25h3a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h2.086a.25.25 0 01.177.073l2.914 2.914a.25.25 0 01.073.177v8.586a.25.25 0 01-.25.25h-.5a.75.75 0 000 1.5h.5A1.75 1.75 0 0014 13.25V4.664c0-.464-.184-.909-.513-1.237L10.573.513A1.75 1.75 0 009.336 0H3.75A1.75 1.75 0 002 1.75v11.5c0 .649.353 1.214.874 1.515a.75.75 0 10.752-1.298.25.25 0 01-.126-.217V1.75zM8.75 3a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5zM6 5.25a.75.75 0 01.75-.75h.5a.75.75 0 010 1.5h-.5A.75.75 0 016 5.25zm2 1.5A.75.75 0 018.75 6h.5a.75.75 0 010 1.5h-.5A.75.75 0 018 6.75zm-1.25.75a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5zM8 9.75A.75.75 0 018.75 9h.5a.75.75 0 010 1.5h-.5A.75.75 0 018 9.75zm-.75.75a1.75 1.75 0 00-1.75 1.75v3c0 .414.336.75.75.75h2.5a.75.75 0 00.75-.75v-3a1.75 1.75 0 00-1.75-1.75h-.5zM7 12.25a.25.25 0 01.25-.25h.5a.25.25 0 01.25.25v2.25H7v-2.25z"></path></svg>',
|
||||
'<svg class="octicon octicon-clippy" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg>',
|
||||
'<svg class="octicon octicon-cloud-download" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M9 12h2l-3 3-3-3h2V7h2v5zm3-8c0-.44-.91-3-4.5-3C5.08 1 3 2.92 3 5 1.02 5 0 6.52 0 8c0 1.53 1 3 3 3h3V9.7H3C1.38 9.7 1.3 8.28 1.3 8c0-.17.05-1.7 1.7-1.7h1.3V5c0-1.39 1.56-2.7 3.2-2.7 2.55 0 3.13 1.55 3.2 1.8v1.2H12c.81 0 2.7.22 2.7 2.2 0 2.09-2.25 2.2-2.7 2.2h-2V11h2c2.08 0 4-1.16 4-3.5C16 5.06 14.08 4 12 4z"></path></svg>'
|
||||
]
|
||||
var style = ['padding:0 6px;margin-right: -1px;border-radius: 2px;background-color: #ffffff;border-color: rgba(27, 31, 35, 0.1);font-size: 11px;color: #888888;']
|
||||
|
||||
var menu_raw_fast = GM_getValue('xiu2_menu_raw_fast')
|
||||
var menu_menu_raw_fast_ID; var menu_feedBack_ID
|
||||
if (menu_raw_fast == null || menu_raw_fast == '中国国内') { menu_raw_fast = 1; GM_setValue('xiu2_menu_raw_fast', 1) }; // 调整上个版本的设置存储变量内容
|
||||
|
||||
registerMenuCommand()
|
||||
// 注册脚本菜单
|
||||
function registerMenuCommand () {
|
||||
if (menu_feedBack_ID) { // 如果反馈菜单ID不是 null,则删除所有脚本菜单
|
||||
GM_unregisterMenuCommand(menu_menu_raw_fast_ID)
|
||||
GM_unregisterMenuCommand(menu_feedBack_ID)
|
||||
menu_raw_fast = GM_getValue('xiu2_menu_raw_fast')
|
||||
}
|
||||
menu_menu_raw_fast_ID = GM_registerMenuCommand(`🔄 [ ${raw_url_name[menu_raw_fast]} ] 加速源 (☁) - 点击切换`, menu_toggle_raw_fast)
|
||||
menu_feedBack_ID = GM_registerMenuCommand('💬 反馈 & 建议 [Github]', function () { window.GM_openInTab('https://github.com/XIU2/UserScript', { active: true, insert: true, setParent: true }) })
|
||||
}
|
||||
|
||||
// 切换加速源
|
||||
function menu_toggle_raw_fast () {
|
||||
if (menu_raw_fast >= raw_url_name.length - 1) { // 如果当前加速源位置大于等于加速源总数,则改为第一个加速源,反之递增下一个加速源
|
||||
menu_raw_fast = 0
|
||||
} else {
|
||||
menu_raw_fast += 1
|
||||
}
|
||||
GM_setValue('xiu2_menu_raw_fast', menu_raw_fast)
|
||||
console.log(11111)
|
||||
delDownLink() // 删除旧加速源
|
||||
console.log(22222)
|
||||
addDownLink() // 添加新加速源
|
||||
console.log(33333)
|
||||
GM_notification(`已切换加速源为:${raw_url_name[menu_raw_fast]}`) // 提示消息
|
||||
registerMenuCommand() // 重新注册脚本菜单
|
||||
};
|
||||
|
||||
addRelease() // Release 加速
|
||||
addDownloadZIP() // Source Code 加速
|
||||
addGitClone() // Download ZIP/Code(ZIP) 加速
|
||||
addRawFile() // Raw 加速
|
||||
setTimeout(addDownLink, 2000) // 添加 Raw 下载链接(☁),延迟 2 秒执行,避免被 pjax 刷掉
|
||||
|
||||
document.addEventListener('pjax:success', function () { // pjax 事件发生后
|
||||
addRelease() // Release 加速
|
||||
addDownloadZIP() // Source Code 加速
|
||||
addGitClone() // Download ZIP/Code(ZIP) 加速
|
||||
addRawFile() // 添加 Raw 加速按钮
|
||||
setTimeout(addDownLink, 2000) // 添加 Raw 下载链接(☁),延迟 2 秒执行,避免被 pjax 刷掉
|
||||
})
|
||||
|
||||
// Release
|
||||
function addRelease () {
|
||||
$('.Box.Box--condensed').each(function () {
|
||||
$(this).find('.d-flex.Box-body>a').each(function () {
|
||||
var href = $(this).attr('href')
|
||||
var url = [
|
||||
download_url[0] + '/https://github.com' + href,
|
||||
download_url[1] + '/https://github.com' + href,
|
||||
download_url[2] + href,
|
||||
download_url[3] + '/https://github.com' + href,
|
||||
download_url[4] + '/https://github.com' + href,
|
||||
download_url[5] + '/https://github.com' + href
|
||||
]
|
||||
var html = `<div style="display: flex;justify-content: flex-end;">
|
||||
<div><a style="${style[0]}" class="btn" href="${url[0]}" rel="noreferrer noopener nofollow">${download_url_name[0]}</a></div>
|
||||
<div><a style="${style[0]}" class="btn" href="${url[1]}" rel="noreferrer noopener nofollow">${download_url_name[1]}</a></div>
|
||||
<div><a style="${style[0]}" class="btn" href="${url[2]}" rel="noreferrer noopener nofollow">${download_url_name[2]}</a></div>
|
||||
<div><a style="${style[0]}" class="btn" href="${url[3]}" rel="noreferrer noopener nofollow">${download_url_name[3]}</a></div>
|
||||
<div><a style="${style[0]}" class="btn" href="${url[4]}" rel="noreferrer noopener nofollow">${download_url_name[4]}</a></div>
|
||||
<div><a style="${style[0]}" class="btn" href="${url[5]}" rel="noreferrer noopener nofollow">${download_url_name[5]}</a></div>
|
||||
</div>`
|
||||
$(this).next().after(html)
|
||||
})
|
||||
// 修改[文件大小]元素样式
|
||||
document.querySelectorAll('small.pl-2.text-gray.flex-shrink-0').forEach(el => el.style.cssText = 'display: flex; justify-content: flex-end; flex-grow: 1; margin-right: 8px;')
|
||||
|
||||
// Source Code
|
||||
$(this).find('.d-block.Box-body>a').each(function () {
|
||||
var href = $(this).attr('href')
|
||||
var url = [
|
||||
download_url[0] + '/https://github.com' + href,
|
||||
download_url[1] + '/https://github.com' + href,
|
||||
download_url[2] + href,
|
||||
download_url[3] + '/https://github.com' + href,
|
||||
download_url[4] + '/https://github.com' + href,
|
||||
download_url[5] + '/https://github.com' + href
|
||||
]
|
||||
var html = `<div style="display: flex;justify-content: flex-end;flex-grow: 1;">
|
||||
<div><a style="${style[0]}" class="btn" href="${url[0]}" rel="noreferrer noopener nofollow">${download_url_name[0]}</a></div>
|
||||
<div><a style="${style[0]}" class="btn" href="${url[1]}" rel="noreferrer noopener nofollow">${download_url_name[1]}</a></div>
|
||||
<div><a style="${style[0]}" class="btn" href="${url[2]}" rel="noreferrer noopener nofollow">${download_url_name[2]}</a></div>
|
||||
<div><a style="${style[0]}" class="btn" href="${url[3]}" rel="noreferrer noopener nofollow">${download_url_name[3]}</a></div>
|
||||
<div><a style="${style[0]}" class="btn" href="${url[4]}" rel="noreferrer noopener nofollow">${download_url_name[4]}</a></div>
|
||||
<div><a style="${style[0]}" class="btn" href="${url[5]}" rel="noreferrer noopener nofollow">${download_url_name[5]}</a></div>
|
||||
</div>`
|
||||
$(this).after(html)
|
||||
})
|
||||
})
|
||||
// 修改 Source code 样式,使其和加速按钮并列一排
|
||||
document.querySelectorAll('div.d-block.py-1.py-md-2.Box-body.px-2').forEach(el => el.className = 'd-flex py-1 py-md-2 Box-body px-2')
|
||||
}
|
||||
|
||||
// Download ZIP
|
||||
function addDownloadZIP () {
|
||||
$('.dropdown-menu.dropdown-menu-sw.p-0 ul li:last-child').each(function () {
|
||||
var href = $(this).children('a').attr('href')
|
||||
var url = [
|
||||
download_url[0] + '/https://github.com' + href,
|
||||
download_url[1] + '/https://github.com' + href,
|
||||
download_url[2] + href,
|
||||
download_url[3] + '/https://github.com' + href,
|
||||
download_url[4] + '/https://github.com' + href,
|
||||
download_url[5] + '/https://github.com' + href
|
||||
]
|
||||
var html = `
|
||||
<li class="Box-row Box-row--hover-gray p-0"><a class="d-flex flex-items-center text-gray-dark text-bold no-underline p-3" rel="noreferrer noopener nofollow" href="${url[0]}">${svg[0]}Download ZIP ${download_url_name[0]}</a></li>
|
||||
<li class="Box-row Box-row--hover-gray p-0"><a class="d-flex flex-items-center text-gray-dark text-bold no-underline p-3" rel="noreferrer noopener nofollow" href="${url[1]}">${svg[0]}Download ZIP ${download_url_name[1]}</a></li>
|
||||
<li class="Box-row Box-row--hover-gray p-0"><a class="d-flex flex-items-center text-gray-dark text-bold no-underline p-3" rel="noreferrer noopener nofollow" href="${url[2]}">${svg[0]}Download ZIP ${download_url_name[2]}</a></li>
|
||||
<li class="Box-row Box-row--hover-gray p-0"><a class="d-flex flex-items-center text-gray-dark text-bold no-underline p-3" rel="noreferrer noopener nofollow" href="${url[3]}">${svg[0]}Download ZIP ${download_url_name[3]}</a></li>
|
||||
<li class="Box-row Box-row--hover-gray p-0"><a class="d-flex flex-items-center text-gray-dark text-bold no-underline p-3" rel="noreferrer noopener nofollow" href="${url[4]}">${svg[0]}Download ZIP ${download_url_name[4]}</a></li>
|
||||
<li class="Box-row Box-row--hover-gray p-0"><a class="d-flex flex-items-center text-gray-dark text-bold no-underline p-3" rel="noreferrer noopener nofollow" href="${url[5]}">${svg[0]}Download ZIP ${download_url_name[5]}</a></li>
|
||||
`
|
||||
$(this).after(html)
|
||||
})
|
||||
}
|
||||
|
||||
// Git Clone
|
||||
function addGitClone () {
|
||||
$("[role='tabpanel'] div.input-group").first().each(function () {
|
||||
var href_split = location.href.split('/')
|
||||
var url = [
|
||||
clone_url[0] + '/' + href_split[3] + '/' + href_split[4] + '.git',
|
||||
clone_url[1] + '/github.com/' + href_split[3] + '/' + href_split[4] + '.git',
|
||||
clone_url[2] + '/' + href_split[3] + '/' + href_split[4] + '.git'
|
||||
]
|
||||
var html = `
|
||||
<div class="input-group" style="margin-top: 4px;"><input value="${url[0]}" aria-label="${url[0]}" type="text" class="form-control input-monospace input-sm bg-gray-light" data-autoselect="" readonly=""><div class="input-group-button"><clipboard-copy value="${url[0]}" aria-label="Copy to clipboard" class="btn btn-sm" tabindex="0" role="button">${svg[1]}</clipboard-copy></div></div>
|
||||
<div class="input-group" style="margin-top: 4px;"><input value="${url[1]}" aria-label="${url[1]}" type="text" class="form-control input-monospace input-sm bg-gray-light" data-autoselect="" readonly=""><div class="input-group-button"><clipboard-copy value="${url[1]}" aria-label="Copy to clipboard" class="btn btn-sm" tabindex="0" role="button">${svg[1]}</clipboard-copy></div></div>
|
||||
<div class="input-group" style="margin-top: 4px;"><input value="${url[2]}" aria-label="${url[2]}" type="text" class="form-control input-monospace input-sm bg-gray-light" data-autoselect="" readonly=""><div class="input-group-button"><clipboard-copy value="${url[2]}" aria-label="Copy to clipboard" class="btn btn-sm" tabindex="0" role="button">${svg[1]}</clipboard-copy></div></div>
|
||||
`
|
||||
$(this).after(html)
|
||||
})
|
||||
}
|
||||
|
||||
// Raw
|
||||
function addRawFile () {
|
||||
$('#raw-url').each(function () {
|
||||
var href = location.href.replace('https://github.com', '')
|
||||
var href2 = href.replace('/blob/', '/')
|
||||
var url = [
|
||||
raw_url[1] + '/gh' + href.replace('/blob/', '@'),
|
||||
raw_url[2] + href2,
|
||||
download_url[5] + '/' + raw_url[0] + href2
|
||||
]
|
||||
var html = `
|
||||
<a href="${url[0]}" title="${raw_url_tip[1]}" role="button" rel="noreferrer noopener nofollow" class="btn btn-sm BtnGroup-item">${raw_url_name[1]}</a>
|
||||
<a href="${url[1]}" title="${raw_url_tip[2]}" role="button" rel="noreferrer noopener nofollow" class="btn btn-sm BtnGroup-item">${raw_url_name[2]}</a>
|
||||
<a href="${url[2]}" title="${raw_url_tip[3]}" role="button" rel="noreferrer noopener nofollow" class="btn btn-sm BtnGroup-item">${raw_url_name[3]}</a>
|
||||
`
|
||||
$(this).after(html)
|
||||
})
|
||||
}
|
||||
|
||||
// 添加 Raw 下载链接(☁)
|
||||
function addDownLink () {
|
||||
// 如果不是项目文件页面,就返回
|
||||
var files = $('div.Box-row svg.octicon.octicon-file')
|
||||
if (files.length === 0) return
|
||||
var files1 = $('a.fileDownLink')
|
||||
if (files1.length > 0) return
|
||||
|
||||
// 鼠标指向则显示
|
||||
var mouseOverHandler = function (evt) {
|
||||
var elem = evt.currentTarget
|
||||
var aElm_new = elem.querySelectorAll('.fileDownLink')
|
||||
var aElm_now = elem.querySelectorAll('svg.octicon.octicon-file.text-gray-light')
|
||||
aElm_new.forEach(el => el.style.cssText = 'display: inline')
|
||||
aElm_now.forEach(el => el.style.cssText = 'display: none')
|
||||
}
|
||||
|
||||
// 鼠标离开则隐藏
|
||||
var mouseOutHandler = function (evt) {
|
||||
var elem = evt.currentTarget
|
||||
var aElm_new = elem.querySelectorAll('.fileDownLink')
|
||||
var aElm_now = elem.querySelectorAll('svg.octicon.octicon-file.text-gray-light')
|
||||
aElm_new.forEach(el => el.style.cssText = 'display: none')
|
||||
aElm_now.forEach(el => el.style.cssText = 'display: inline')
|
||||
}
|
||||
|
||||
// 循环添加
|
||||
files.each(function (i, fileElm) {
|
||||
var trElm = fileElm.parentNode.parentNode
|
||||
var cntElm_a = trElm.querySelector('.css-truncate.css-truncate-target.d-block.width-fit a')
|
||||
var cntElm_svg = trElm.querySelector('.mr-3.flex-shrink-0 svg.octicon.octicon-file.text-gray-light')
|
||||
var Name = cntElm_a.innerText
|
||||
var href = cntElm_a.attributes.href.nodeValue.replace('https://github.com', '')
|
||||
var href2 = href.replace('/blob/', '/'); var url; var url_name; var url_tip = ''
|
||||
switch (menu_raw_fast) {
|
||||
case 0:
|
||||
url = raw_url[0] + href2
|
||||
url_name = raw_url_name[0]
|
||||
url_tip = raw_url_tip[0]
|
||||
break
|
||||
case 1:
|
||||
url = raw_url[1] + '/gh' + href.replace('/blob/', '@')
|
||||
url_name = raw_url_name[1]
|
||||
url_tip = raw_url_tip[1]
|
||||
break
|
||||
case 2:
|
||||
url = raw_url[2] + href2
|
||||
url_name = raw_url_name[2]
|
||||
url_tip = raw_url_tip[2]
|
||||
break
|
||||
case 3:
|
||||
url = download_url[5] + '/' + raw_url[0] + href2
|
||||
url_name = download_url_name[5]
|
||||
url_tip = raw_url_tip[3]
|
||||
break
|
||||
}
|
||||
var html = ` <a href="${url}" download="${Name}" target="_blank" rel="noreferrer noopener nofollow" class="fileDownLink" style="display: none;" title="「${url_name}」 [Alt + 左键] 或 [右键 - 另存为...] 下载文件。 注意:鼠标点击 [☁] 图标,而不是左侧的文件名! ${url_tip}提示:点击浏览器右上角 Tampermonkey 扩展图标 - [ ${raw_url_name[menu_raw_fast]} ] 加速源 (☁) 即可切换。">${svg[2]}</a>`
|
||||
$(cntElm_svg).after(html)
|
||||
// 绑定鼠标事件
|
||||
trElm.onmouseover = mouseOverHandler
|
||||
trElm.onmouseout = mouseOutHandler
|
||||
})
|
||||
}
|
||||
|
||||
// 删除 Raw 快捷下载(☁)
|
||||
function delDownLink () {
|
||||
var aElm = document.querySelectorAll('.fileDownLink')
|
||||
for (var num = 0; num < aElm.length; num++) {
|
||||
aElm[num].remove()
|
||||
};
|
||||
}
|
||||
})()
|
|
@ -0,0 +1,9 @@
|
|||
window.__ds_global__={
|
||||
GM_registerMenuCommand: () => {},
|
||||
GM_unregisterMenuCommand: () => {},
|
||||
GM_openInTab: () => {},
|
||||
GM_getValue: () => {},
|
||||
GM_setValue: () => {},
|
||||
GM_notification: () => {}
|
||||
}
|
||||
console.log('ds_global loaded')
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docmirror/dev-sidecar-gui",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.1",
|
||||
"private": false,
|
||||
"license": "MPL-2.0",
|
||||
"scripts": {
|
||||
|
@ -14,8 +14,8 @@
|
|||
},
|
||||
"main": "background.js",
|
||||
"dependencies": {
|
||||
"@docmirror/dev-sidecar": "^1.1.0",
|
||||
"@docmirror/mitmproxy": "^1.1.0",
|
||||
"@docmirror/dev-sidecar": "^1.2.1",
|
||||
"@docmirror/mitmproxy": "^1.2.1",
|
||||
"ant-design-vue": "^1.6.5",
|
||||
"core-js": "^3.6.5",
|
||||
"electron-baidu-tongji": "^1.0.5",
|
||||
|
@ -24,16 +24,13 @@
|
|||
"es-abstract": "^1.17.7",
|
||||
"json5": "^2.1.3",
|
||||
"lodash": "^4.17.20",
|
||||
"log4js": "^6.3.0",
|
||||
"sass": "^1.27.1",
|
||||
"sass-loader": "^10.0.4",
|
||||
"vue": "^2.6.11",
|
||||
"vue-json-editor": "^1.4.2",
|
||||
"vue-router": "^3.4.8"
|
||||
},
|
||||
"resolutions": {
|
||||
"hexoid": "^1.0.0",
|
||||
"formidable": "2.0.0-canary.20200504.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
|
|
|
@ -6,7 +6,7 @@ import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
|
|||
import bridge from './bridge/index'
|
||||
import updateHandle from './bridge/update-handle'
|
||||
import { ebtMain } from './tongji'
|
||||
|
||||
import log from './utils/util.log'
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const isMac = process.platform === 'darwin'
|
||||
|
||||
|
@ -60,7 +60,7 @@ function setTray (app) {
|
|||
// appTray.setContextMenu(contextMenu)
|
||||
|
||||
// appTray.on('double-click', function () {
|
||||
// console.log('double click')
|
||||
// log.info('double click')
|
||||
// win.show()
|
||||
// })
|
||||
appTray.on('right-click', function (event, bounds) {
|
||||
|
@ -112,7 +112,14 @@ function createWindow () {
|
|||
})
|
||||
}
|
||||
|
||||
function quit (app) {
|
||||
async function beforeQuit () {
|
||||
return bridge.devSidecar.api.shutdown()
|
||||
}
|
||||
async function quit (app, callback) {
|
||||
if (tray) {
|
||||
tray.displayBalloon({ title: '正在关闭', content: '关闭中,请稍候。。。' })
|
||||
}
|
||||
await beforeQuit()
|
||||
app.quit()
|
||||
}
|
||||
|
||||
|
@ -122,22 +129,22 @@ app.disableHardwareAcceleration() // 禁用gpu
|
|||
// 禁止双开
|
||||
const isFirstInstance = app.requestSingleInstanceLock()
|
||||
if (!isFirstInstance) {
|
||||
console.log('is second instance')
|
||||
log.info('is second instance')
|
||||
setTimeout(() => {
|
||||
app.quit()
|
||||
}, 1000)
|
||||
} else {
|
||||
app.on('before-quit', async (event) => {
|
||||
console.log('before-quit')
|
||||
event.preventDefault()
|
||||
// if (tray) {
|
||||
// tray.displayBalloon({ title: '正在关闭,请稍候...', content: '正在关闭中,请稍候。。。' })
|
||||
// }
|
||||
await bridge.devSidecar.api.shutdown()
|
||||
app.exit()
|
||||
log.info('before-quit')
|
||||
// event.preventDefault()
|
||||
// // if (tray) {
|
||||
// // tray.displayBalloon({ title: '正在关闭,请稍候...', content: '正在关闭中,请稍候。。。' })
|
||||
// // }
|
||||
// await bridge.devSidecar.api.shutdown()
|
||||
// app.exit()
|
||||
})
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
console.log('new app started', commandLine)
|
||||
log.info('new app started', commandLine)
|
||||
if (win) {
|
||||
win.show()
|
||||
win.focus()
|
||||
|
@ -170,7 +177,7 @@ if (!isFirstInstance) {
|
|||
// try {
|
||||
// await installExtension(VUEJS_DEVTOOLS)
|
||||
// } catch (e) {
|
||||
// console.error('Vue Devtools failed to install:', e.toString())
|
||||
// log.error('Vue Devtools failed to install:', e.toString())
|
||||
// }
|
||||
}
|
||||
createWindow()
|
||||
|
@ -183,11 +190,11 @@ if (!isFirstInstance) {
|
|||
return true
|
||||
}
|
||||
})
|
||||
// updateUrl = 'https://dev-sidecar.docmirror.cn/update/'
|
||||
updateUrl = 'http://localhost/dev-sidecar/'
|
||||
updateUrl = 'https://dev-sidecar.docmirror.cn/update/'
|
||||
// updateUrl = 'http://localhost/dev-sidecar/'
|
||||
}
|
||||
// 自动更新
|
||||
updateHandle(win, updateUrl)
|
||||
updateHandle(app, win, beforeQuit, updateUrl)
|
||||
|
||||
// 百度分析
|
||||
ebtMain(ipcMain, isDevelopment)
|
||||
|
@ -196,7 +203,7 @@ if (!isFirstInstance) {
|
|||
// 最小化到托盘
|
||||
tray = setTray(app)
|
||||
} catch (err) {
|
||||
console.log('err', err)
|
||||
log.info('err', err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -6,10 +6,9 @@ import JSON5 from 'json5'
|
|||
import path from 'path'
|
||||
const pk = require('../../package.json')
|
||||
const mitmproxyPath = path.join(__dirname, 'mitmproxy.js')
|
||||
|
||||
const log = require('../utils/util.log')
|
||||
const getDefaultConfigBasePath = function () {
|
||||
const userHome = process.env.HOME || process.env.USERPROFILE
|
||||
return path.resolve(userHome, './.dev-sidecar')
|
||||
return DevSidecar.api.config.get().server.setting.userBasePath
|
||||
}
|
||||
const localApi = {
|
||||
/**
|
||||
|
@ -22,15 +21,17 @@ const localApi = {
|
|||
lodash.merge(core, local)
|
||||
const list = []
|
||||
_deepFindFunction(list, core, '')
|
||||
// console.log('api list:', list)
|
||||
// log.info('api list:', list)
|
||||
return list
|
||||
},
|
||||
info: {
|
||||
get () {
|
||||
console.log(pk)
|
||||
return {
|
||||
version: pk.version
|
||||
}
|
||||
},
|
||||
getConfigDir () {
|
||||
return getDefaultConfigBasePath()
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
@ -81,6 +82,7 @@ const localApi = {
|
|||
*/
|
||||
save (newConfig) {
|
||||
// 对比默认config的异同
|
||||
DevSidecar.api.config.set(newConfig)
|
||||
const defConfig = DevSidecar.api.config.getDefault()
|
||||
const saveConfig = doMerge(defConfig, newConfig)
|
||||
fs.writeFileSync(_getConfigPath(), JSON5.stringify(saveConfig, null, 2))
|
||||
|
@ -178,23 +180,23 @@ export default {
|
|||
target = lodash.get(DevSidecar.api, api)
|
||||
}
|
||||
if (target == null) {
|
||||
console.log('找不到此接口方法:', api)
|
||||
log.info('找不到此接口方法:', api)
|
||||
}
|
||||
let param
|
||||
if (args.length >= 2) {
|
||||
param = args[1]
|
||||
}
|
||||
const ret = target(param)
|
||||
// console.log('api:', api, 'ret:', ret)
|
||||
// log.info('api:', api, 'ret:', ret)
|
||||
return ret
|
||||
})
|
||||
// 注册从core里来的事件,并转发给view
|
||||
DevSidecar.api.event.register('status', (event) => {
|
||||
console.log('bridge on status', event)
|
||||
log.info('bridge on status', event)
|
||||
win.webContents.send('status', { ...event })
|
||||
})
|
||||
DevSidecar.api.event.register('error', (event) => {
|
||||
console.error('bridge on error', event)
|
||||
log.error('bridge on error', event)
|
||||
win.webContents.send('error.core', event)
|
||||
})
|
||||
|
||||
|
|
|
@ -1,4 +1,15 @@
|
|||
// eslint-disable-next-line no-unused-vars
|
||||
const server = require('@docmirror/mitmproxy')
|
||||
const config = JSON.parse(process.argv[2])
|
||||
const configPath = process.argv[2]
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const configJson = fs.readFileSync(configPath)
|
||||
const config = JSON.parse(configJson)
|
||||
|
||||
let scriptDir = '../extra/scripts/'
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
scriptDir = '../extra/scripts/'
|
||||
}
|
||||
config.setting.script.defaultDir = path.join(__dirname, scriptDir)
|
||||
server.start(config)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { ipcMain, dialog } from 'electron'
|
||||
import { autoUpdater } from 'electron-updater'
|
||||
import log from '../utils/util.log'
|
||||
import path from 'path'
|
||||
// win是所有窗口的引用
|
||||
// const path = require('path') // 引入path模块
|
||||
|
@ -7,7 +8,7 @@ import path from 'path'
|
|||
// eslint-disable-next-line no-unused-vars
|
||||
const isMac = process.platform === 'darwin'
|
||||
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
|
||||
function updateHandle (win, updateUrl) {
|
||||
function updateHandle (app, win, beforeQuit, updateUrl) {
|
||||
// // 更新前,删除本地安装包 ↓
|
||||
// const updaterCacheDirName = 'dev-sidecar-updater'
|
||||
// const updatePendingPath = path.join(autoUpdater.app.baseCachePath, updaterCacheDirName, 'pending')
|
||||
|
@ -31,30 +32,30 @@ function updateHandle (win, updateUrl) {
|
|||
url: updateUrl
|
||||
})
|
||||
autoUpdater.on('error', function (error) {
|
||||
console.log('autoUpdater error', error)
|
||||
log.info('autoUpdater error', error)
|
||||
sendUpdateMessage({ key: 'error', value: error, error: error })
|
||||
// dialog.showErrorBox('Error: ', error == null ? 'unknown' : (error.stack || error).toString())
|
||||
})
|
||||
autoUpdater.on('checking-for-update', function () {
|
||||
console.log('autoUpdater checking-for-update')
|
||||
log.info('autoUpdater checking-for-update')
|
||||
sendUpdateMessage({ key: 'checking', value: message.checking })
|
||||
})
|
||||
autoUpdater.on('update-available', function (info) {
|
||||
console.log('autoUpdater update-available')
|
||||
log.info('autoUpdater update-available')
|
||||
sendUpdateMessage({ key: 'available', value: info })
|
||||
})
|
||||
autoUpdater.on('update-not-available', function (info) {
|
||||
console.log('autoUpdater update-not-available')
|
||||
log.info('autoUpdater update-not-available')
|
||||
sendUpdateMessage({ key: 'notAvailable', value: message.updateNotAva })
|
||||
})
|
||||
// 更新下载进度
|
||||
autoUpdater.on('download-progress', function (progressObj) {
|
||||
console.log('autoUpdater download-progress')
|
||||
log.info('autoUpdater download-progress')
|
||||
win.webContents.send('update', { key: 'progress', value: parseInt(progressObj.percent) })
|
||||
})
|
||||
// 更新完成,重启应用
|
||||
autoUpdater.on('update-downloaded', function (info) {
|
||||
console.log('download complete', info.version)
|
||||
log.info('download complete', info.version)
|
||||
win.webContents.send('update', {
|
||||
key: 'downloaded',
|
||||
value: {
|
||||
|
@ -67,24 +68,31 @@ function updateHandle (win, updateUrl) {
|
|||
ipcMain.on('update', (e, arg) => {
|
||||
if (arg.key === 'doUpdateNow') {
|
||||
// some code here to handle event
|
||||
autoUpdater.quitAndInstall()
|
||||
beforeQuit().then(() => {
|
||||
autoUpdater.quitAndInstall()
|
||||
if (app) {
|
||||
setTimeout(() => {
|
||||
app.exit()
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
} else if (arg.key === 'checkForUpdate') {
|
||||
// 执行自动更新检查
|
||||
console.log('autoUpdater checkForUpdates')
|
||||
log.info('autoUpdater checkForUpdates')
|
||||
autoUpdater.checkForUpdates()
|
||||
} else if (arg.key === 'downloadUpdate') {
|
||||
// 下载新版本
|
||||
console.log('autoUpdater downloadUpdate')
|
||||
log.info('autoUpdater downloadUpdate')
|
||||
autoUpdater.downloadUpdate()
|
||||
}
|
||||
})
|
||||
// 通过main进程发送事件给renderer进程,提示更新信息
|
||||
function sendUpdateMessage (message) {
|
||||
console.log('autoUpdater sendUpdateMessage')
|
||||
log.info('autoUpdater sendUpdateMessage')
|
||||
win.webContents.send('update', message)
|
||||
}
|
||||
|
||||
console.log('auto update inited')
|
||||
log.info('auto update inited')
|
||||
return autoUpdater
|
||||
}
|
||||
export default updateHandle
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
const log4js = require('log4js')
|
||||
const DevSidecar = require('@docmirror/dev-sidecar')
|
||||
const getDefaultConfigBasePath = function () {
|
||||
return DevSidecar.api.config.get().server.setting.userBasePath
|
||||
}
|
||||
log4js.configure({
|
||||
appenders: { std: { type: 'stdout' }, file: { type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename: getDefaultConfigBasePath() + '/logs/gui.log' } },
|
||||
categories: { default: { appenders: ['file', 'std'], level: 'info' } }
|
||||
})
|
||||
const logger = log4js.getLogger('server')
|
||||
module.exports = logger
|
|
@ -17,13 +17,18 @@ const bindApi = (api, param1) => {
|
|||
})
|
||||
}
|
||||
const apiObj = {
|
||||
on (channel, callback) {
|
||||
ipcRenderer.on(channel, callback)
|
||||
},
|
||||
invoke,
|
||||
send,
|
||||
openExternal (href) {
|
||||
shell.openExternal(href)
|
||||
ipc: {
|
||||
on (channel, callback) {
|
||||
ipcRenderer.on(channel, callback)
|
||||
},
|
||||
invoke,
|
||||
send,
|
||||
openExternal (href) {
|
||||
shell.openExternal(href)
|
||||
},
|
||||
openPath (file) {
|
||||
shell.openPath(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
let inited = false
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import api from '../api'
|
||||
export default {
|
||||
name: 'setup-ca',
|
||||
components: {
|
||||
|
@ -55,7 +54,6 @@ export default {
|
|||
this.$emit('update:visible', false)
|
||||
},
|
||||
async doSetup () {
|
||||
await api.shell.setupCa()
|
||||
this.$emit('setup')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
this.status = this.$status
|
||||
return this.$api.config.reload().then(ret => {
|
||||
this.config = ret
|
||||
console.log('config', this.config)
|
||||
if (this.ready) {
|
||||
return this.ready(this.config)
|
||||
}
|
||||
|
@ -39,13 +40,14 @@ export default {
|
|||
this.applyLoading = true
|
||||
await this.applyBefore()
|
||||
await this.saveConfig()
|
||||
if (this.applyAfter) {
|
||||
await this.applyAfter()
|
||||
}
|
||||
await this.applyAfter()
|
||||
this.applyLoading = false
|
||||
},
|
||||
async applyBefore () {
|
||||
|
||||
},
|
||||
async applyAfter () {
|
||||
|
||||
},
|
||||
resetDefault () {
|
||||
const key = this.getKey()
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
function install (app, api) {
|
||||
api.on('error.core', (event, message) => {
|
||||
api.ipc.on('error.core', (event, message) => {
|
||||
console.error('view on error', message)
|
||||
const key = message.key
|
||||
if (key === 'server') {
|
||||
handleServerStartError(message, message.error, app, api)
|
||||
}
|
||||
})
|
||||
api.on('error', (event, message) => {
|
||||
api.ipc.on('error', (event, message) => {
|
||||
console.error('error', event, message)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
let updateParams = { }
|
||||
|
||||
function install (app, api) {
|
||||
api.on('update', (event, message) => {
|
||||
const updateParams = app.$global.update = { fromUser: false, autoDownload: true, progress: 0, downloading: false, newVersion: false }
|
||||
api.ipc.on('update', (event, message) => {
|
||||
console.log('on message', event, message)
|
||||
handleUpdateMessage(message, app)
|
||||
})
|
||||
|
||||
api.update = {
|
||||
checkForUpdate (params) {
|
||||
updateParams = params || { fromUser: false, autoDownload: true, progress: 0 }
|
||||
api.send('update', { key: 'checkForUpdate' })
|
||||
checkForUpdate (fromUser) {
|
||||
if (fromUser != null) {
|
||||
updateParams.fromUser = fromUser
|
||||
}
|
||||
api.ipc.send('update', { key: 'checkForUpdate' })
|
||||
},
|
||||
downloadUpdate () {
|
||||
api.send('update', { key: 'downloadUpdate' })
|
||||
api.ipc.send('update', { key: 'downloadUpdate' })
|
||||
},
|
||||
doUpdateNow () {
|
||||
api.send('update', { key: 'doUpdateNow' })
|
||||
api.ipc.send('update', { key: 'doUpdateNow' })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +29,8 @@ function install (app, api) {
|
|||
noNewVersion()
|
||||
} else if (type === 'downloaded') {
|
||||
// 更新包已下载完成,让用户确认是否更新
|
||||
updateParams.downloading = false
|
||||
console.log('updateParams', updateParams)
|
||||
newUpdateIsReady(message.value)
|
||||
} else if (type === 'progress') {
|
||||
progressUpdate(message.value)
|
||||
|
@ -49,6 +54,8 @@ function install (app, api) {
|
|||
updateParams.newVersion = true
|
||||
|
||||
if (updateParams.autoDownload !== false) {
|
||||
app.$message.info('发现新版本,正在下载中...')
|
||||
updateParams.downloading = true
|
||||
api.update.downloadUpdate()
|
||||
return
|
||||
}
|
||||
|
@ -69,6 +76,7 @@ function install (app, api) {
|
|||
}
|
||||
|
||||
function newUpdateIsReady (value) {
|
||||
updateParams.downloading = false
|
||||
app.$confirm({
|
||||
title: '新版本已准备好',
|
||||
content: `是否立即升级安装v${value.version}?`,
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
<a-badge :count="_rootCaSetuped?0:1" dot>安装根证书 </a-badge>
|
||||
</a-button>
|
||||
|
||||
<a-button style="margin-right:10px" @click="doCheckUpdate">
|
||||
<a-button style="margin-right:10px" @click="doCheckUpdate(true)" :loading="update.downloading" :title="'当前版本:'+info.version">
|
||||
<a-badge :count="update.newVersion?1:0" dot>
|
||||
检查更新
|
||||
<span v-if="update.downloading">{{update.progress}}%</span>{{update.downloading?'新版本下载中':'检查更新'}}
|
||||
</a-badge>
|
||||
</a-button>
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
|||
<a-form style="margin-top:20px" :label-col="{ span: 12 }" :wrapper-col="{ span: 12 }">
|
||||
|
||||
<a-form-item v-for=" (item, key) in switchBtns" :key="key" :label="item.label">
|
||||
<a-switch style="margin-left:10px" :loading="item.loading" v-model="item.status[key].enabled" default-checked v-on:click="item.doClick">
|
||||
<a-switch style="margin-left:10px" :loading="item.loading" :checked="item.status()" default-checked @change="item.doClick">
|
||||
<a-icon slot="checkedChildren" type="check"/>
|
||||
<a-icon slot="unCheckedChildren" type="close"/>
|
||||
</a-switch>
|
||||
|
@ -45,7 +45,7 @@
|
|||
<div class="flex-l-r star" style="padding:10px;">
|
||||
<div>如果它解决了你的问题,请不要吝啬你的star哟! <a-icon type="smile" theme="outlined" /></div>
|
||||
<a @click="openExternal('https://gitee.com/docmirror/dev-sidecar')"><img src='https://gitee.com/docmirror/dev-sidecar/badge/star.svg?theme=dark' alt='star'/></a>
|
||||
<a @click="openExternal('https://github.com/docmirror/dev-sidecar')"><img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"></a>
|
||||
<a @click="openExternal('https://github.com/docmirror/dev-sidecar')"><img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -57,7 +57,6 @@
|
|||
import lodash from 'lodash'
|
||||
import setupCa from '../components/setup-ca'
|
||||
import DsContainer from '../components/container'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
|
@ -88,6 +87,8 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
info: {},
|
||||
newVersionDownloading: false,
|
||||
setting: undefined,
|
||||
server: {
|
||||
key: '代理服务',
|
||||
|
@ -101,29 +102,23 @@ export default {
|
|||
setupCa: {
|
||||
visible: false
|
||||
},
|
||||
update: {}
|
||||
update: { downloading: false, progress: 0, newVersion: false }
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
this.doCheckRootCa()
|
||||
console.log('index created', this.status, this.$status)
|
||||
await this.reloadConfig()
|
||||
const status = await this.$api.status.get()
|
||||
console.log('status', status)
|
||||
this.$set(this, 'status', status)
|
||||
this.$set(this, 'status', this.$status)
|
||||
this.switchBtns = this.createSwitchBtns()
|
||||
console.log('switchBtns', this.switchBtns)
|
||||
if (this.$global.update == null) {
|
||||
this.$global.update = {
|
||||
fromUser: false,
|
||||
autoDownload: true,
|
||||
progress: 0,
|
||||
newVersion: false
|
||||
}
|
||||
this.update = this.$global.update
|
||||
this.$set(this, 'update', this.$global.update)
|
||||
if (!this.update.autoChecked) {
|
||||
this.update.autoChecked = true
|
||||
this.doCheckUpdate(false)
|
||||
}
|
||||
this.update = this.$global.update
|
||||
this.$api.info.get().then(ret => {
|
||||
this.info = ret
|
||||
})
|
||||
},
|
||||
mounted () {
|
||||
console.log('index mounted')
|
||||
|
@ -156,7 +151,9 @@ export default {
|
|||
openSetupCa () {
|
||||
this.setupCa.visible = true
|
||||
},
|
||||
handleCaSetuped () {
|
||||
async handleCaSetuped () {
|
||||
console.log('this.config.server.setting.rootCaFile.certPath', this.config.server.setting.rootCaFile.certPath)
|
||||
await this.$api.shell.setupCa({ certPath: this.config.server.setting.rootCaFile.certPath })
|
||||
this.setting.rootCa = this.setting.rootCa || {}
|
||||
const rootCa = this.setting.rootCa
|
||||
rootCa.setuped = true
|
||||
|
@ -185,7 +182,9 @@ export default {
|
|||
loading: false,
|
||||
key: key,
|
||||
label: label,
|
||||
status: statusParent,
|
||||
status: () => {
|
||||
return statusParent[key].enabled
|
||||
},
|
||||
doClick: (checked) => {
|
||||
this.onSwitchClick(this.switchBtns[key], apiTarget.start, apiTarget.close, checked)
|
||||
}
|
||||
|
@ -229,11 +228,10 @@ export default {
|
|||
})
|
||||
},
|
||||
doCheckUpdate (fromUser = true) {
|
||||
this.update.fromUser = fromUser
|
||||
this.$api.update.checkForUpdate(this.update)
|
||||
this.$api.update.checkForUpdate(fromUser)
|
||||
},
|
||||
openExternal (url) {
|
||||
this.$api.openExternal(url)
|
||||
this.$api.ipc.openExternal(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
>
|
||||
<a-tab-pane tab="基本设置" key="1" >
|
||||
<a-form-item label="代理服务:" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-checkbox :checked="config.server.enabled" @change="config.server.enabled = $event">
|
||||
<a-checkbox v-model="config.server.enabled" >
|
||||
随应用启动
|
||||
</a-checkbox>
|
||||
<a-tag v-if="status.proxy.enabled" color="green">
|
||||
|
@ -25,16 +25,29 @@
|
|||
<a-tag v-else color="red">
|
||||
当前未启动
|
||||
</a-tag>
|
||||
|
||||
<a-button class="md-mr-10" icon="profile" @click="openLog()">日志</a-button>
|
||||
</a-form-item>
|
||||
<a-form-item label="代理端口" :label-col="labelCol" :wrapper-col="wrapperCol" >
|
||||
<a-input v-model="config.server.port"/>
|
||||
</a-form-item>
|
||||
<a-form-item label="校验SSL" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-checkbox :checked="config.server.setting.NODE_TLS_REJECT_UNAUTHORIZED" @change="config.server.setting.NODE_TLS_REJECT_UNAUTHORIZED = $event">
|
||||
<a-checkbox v-model="config.server.setting.NODE_TLS_REJECT_UNAUTHORIZED">
|
||||
NODE_TLS_REJECT_UNAUTHORIZED
|
||||
</a-checkbox>
|
||||
<div>开启此项之后,被代理应用关闭SSL校验也问题不大了</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="根证书:" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-input addon-before="Cert" addon-after="选择" v-model="config.server.setting.rootCaFile.certPath" ></a-input>
|
||||
<a-input addon-before="Key" addon-after="选择" v-model="config.server.setting.rootCaFile.keyPath" ></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="启用脚本" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-tooltip title="关闭后,github的clone加速链接复制也将关闭">
|
||||
<a-checkbox v-model="config.server.setting.script.enabled" >
|
||||
允许插入并运行脚本
|
||||
</a-checkbox>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="拦截设置" key="2" >
|
||||
<vue-json-editor style="height:100%;" ref="editor" v-model="config.server.intercepts" mode="code" :show-btns="false" :expandedOnStart="true" @json-change="onJsonChange" ></vue-json-editor>
|
||||
|
@ -132,6 +145,10 @@ export default {
|
|||
},
|
||||
addDnsMapping () {
|
||||
this.dnsMappings.unshift({ key: '', value: 'usa' })
|
||||
},
|
||||
async openLog () {
|
||||
const dir = await this.$api.info.getConfigDir()
|
||||
this.$api.ipc.openPath(dir + '/logs/server.log')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ const status = {
|
|||
}
|
||||
}
|
||||
async function install (api) {
|
||||
api.on('status', (event, message) => {
|
||||
api.ipc.on('status', (event, message) => {
|
||||
console.log('view on status', event, message)
|
||||
const value = message.value
|
||||
const key = message.key
|
||||
|
|
|
@ -901,12 +901,12 @@
|
|||
ajv "^6.12.0"
|
||||
ajv-keywords "^3.4.1"
|
||||
|
||||
"@docmirror/dev-sidecar@1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@docmirror/dev-sidecar/-/dev-sidecar-1.0.2.tgz#9cb617a5a604a375d6059cf4669d5b2f4bd731df"
|
||||
integrity sha512-VOo2VYau6eAMbFT+Ymne7tMzrKh4hveNbXmCUmH8Zt5ynbGZXujXozzoVEYOVDXH5T0n+K7qsPh+Cw959LQi9w==
|
||||
"@docmirror/dev-sidecar@^1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@docmirror/dev-sidecar/-/dev-sidecar-1.2.0.tgz#2320c31f786afd495b8e12557bea396cb96e0985"
|
||||
integrity sha512-i96YlPjQtrrAgDW52YOpuVFmQDl1A0Nx3x6/riv2yKVN4nGqAugdJvcAuhNi7BDrJfdLyls2jI35uzN5+bpYfQ==
|
||||
dependencies:
|
||||
"@docmirror/mitmproxy" "1.0.2"
|
||||
"@docmirror/mitmproxy" "^1.2.0"
|
||||
agentkeepalive "^2.1.1"
|
||||
charset "^1.0.0"
|
||||
child_process "^1.0.2"
|
||||
|
@ -920,6 +920,7 @@
|
|||
jschardet "^1.4.1"
|
||||
json5 "^2.1.3"
|
||||
lodash "^4.7.0"
|
||||
log4js "^6.3.0"
|
||||
lru-cache "^6.0.0"
|
||||
mkdirp "^0.5.1"
|
||||
node-cmd "^3.0.0"
|
||||
|
@ -932,18 +933,20 @@
|
|||
validator "^13.1.17"
|
||||
winreg "^1.2.4"
|
||||
|
||||
"@docmirror/mitmproxy@1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@docmirror/mitmproxy/-/mitmproxy-1.0.2.tgz#ee25d4205dca58372aa7c9a34d2789d39dda3dc4"
|
||||
integrity sha512-bDAIIp5aDQhgBnQfvtkYMzRVHIMAWFO9WtgWEBPLwLenXycU4vSMqt2c9Y/ArWlU4Ku+PQpjk2WZHYjmKzlmLA==
|
||||
"@docmirror/mitmproxy@^1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@docmirror/mitmproxy/-/mitmproxy-1.2.0.tgz#ab9910031272d8e16fe0e38d434f7b42971bc74e"
|
||||
integrity sha512-DlzquSNVZOC/p5GwAdDwSiI4KCb3HlUY4A44pGGOBehsNThBoRU8ESKJjbyay9ah4RPSAWTSVYgMEiPZctR+wg==
|
||||
dependencies:
|
||||
agentkeepalive "^2.1.1"
|
||||
child_process "^1.0.2"
|
||||
colors "^1.1.2"
|
||||
commander "^2.9.0"
|
||||
crypto-js "^4.0.0"
|
||||
debug "^4.1.1"
|
||||
dns-over-http "^0.2.0"
|
||||
dns-over-tls "^0.0.8"
|
||||
is-browser "^2.1.0"
|
||||
json5 "^2.1.3"
|
||||
lodash "^4.7.0"
|
||||
log4js "^6.3.0"
|
||||
|
@ -2019,8 +2022,8 @@
|
|||
|
||||
accept@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.npm.taobao.org/accept/download/accept-3.1.3.tgz#29c3e2b3a8f4eedbc2b690e472b9ebbdc7385e87"
|
||||
integrity sha1-KcPis6j07tvCtpDkcrnrvcc4Xoc=
|
||||
resolved "https://registry.yarnpkg.com/accept/-/accept-3.1.3.tgz#29c3e2b3a8f4eedbc2b690e472b9ebbdc7385e87"
|
||||
integrity sha512-OgOEAidVEOKPup+Gv2+2wdH2AgVKI9LxsJ4hicdJ6cY0faUuZdZoi56kkXWlHp9qicN1nWQLmW5ZRGk+SBS5xg==
|
||||
dependencies:
|
||||
boom "7.x.x"
|
||||
hoek "6.x.x"
|
||||
|
@ -2067,7 +2070,7 @@ address@^1.1.2:
|
|||
|
||||
agentkeepalive@^2.1.1:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npm.taobao.org/agentkeepalive/download/agentkeepalive-2.2.0.tgz#c5d1bd4b129008f1163f236f86e5faea2026e2ef"
|
||||
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-2.2.0.tgz#c5d1bd4b129008f1163f236f86e5faea2026e2ef"
|
||||
integrity sha1-xdG9SxKQCPEWPyNvhuX66iAm4u8=
|
||||
|
||||
aggregate-error@^3.0.0:
|
||||
|
@ -2305,7 +2308,7 @@ arr-union@^3.1.0:
|
|||
|
||||
array-filter@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npm.taobao.org/array-filter/download/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83"
|
||||
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83"
|
||||
integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=
|
||||
|
||||
array-find@^1.0.0:
|
||||
|
@ -2362,11 +2365,6 @@ array.prototype.flat@^1.2.3:
|
|||
define-properties "^1.1.3"
|
||||
es-abstract "^1.17.0-next.1"
|
||||
|
||||
asap@^2.0.0:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
|
||||
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
|
||||
|
||||
asn1.js@^5.2.0:
|
||||
version "5.4.1"
|
||||
resolved "https://registry.npm.taobao.org/asn1.js/download/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07"
|
||||
|
@ -2474,8 +2472,8 @@ autoprefixer@^9.8.6:
|
|||
|
||||
available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npm.taobao.org/available-typed-arrays/download/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5"
|
||||
integrity sha1-awmMqdgDkHnuP3f3t4PESAulE/U=
|
||||
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5"
|
||||
integrity sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==
|
||||
dependencies:
|
||||
array-filter "^1.0.0"
|
||||
|
||||
|
@ -2671,8 +2669,8 @@ boolean@^3.0.1:
|
|||
|
||||
boom@7.x.x:
|
||||
version "7.3.0"
|
||||
resolved "https://registry.npm.taobao.org/boom/download/boom-7.3.0.tgz#733a6d956d33b0b1999da3fe6c12996950d017b9"
|
||||
integrity sha1-czptlW0zsLGZnaP+bBKZaVDQF7k=
|
||||
resolved "https://registry.yarnpkg.com/boom/-/boom-7.3.0.tgz#733a6d956d33b0b1999da3fe6c12996950d017b9"
|
||||
integrity sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==
|
||||
dependencies:
|
||||
hoek "6.x.x"
|
||||
|
||||
|
@ -3120,8 +3118,8 @@ chardet@^0.7.0:
|
|||
|
||||
charset@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npm.taobao.org/charset/download/charset-1.0.1.tgz#8d59546c355be61049a8fa9164747793319852bd"
|
||||
integrity sha1-jVlUbDVb5hBJqPqRZHR3kzGYUr0=
|
||||
resolved "https://registry.yarnpkg.com/charset/-/charset-1.0.1.tgz#8d59546c355be61049a8fa9164747793319852bd"
|
||||
integrity sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==
|
||||
|
||||
check-types@^8.0.3:
|
||||
version "8.0.3"
|
||||
|
@ -3130,7 +3128,7 @@ check-types@^8.0.3:
|
|||
|
||||
child_process@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npm.taobao.org/child_process/download/child_process-1.0.2.tgz#b1f7e7fc73d25e7fd1d455adc94e143830182b5a"
|
||||
resolved "https://registry.yarnpkg.com/child_process/-/child_process-1.0.2.tgz#b1f7e7fc73d25e7fd1d455adc94e143830182b5a"
|
||||
integrity sha1-sffn/HPSXn/R1FWtyU4UODAYK1o=
|
||||
|
||||
"chokidar@>=2.0.0 <4.0.0", chokidar@^3.0.2, chokidar@^3.4.1:
|
||||
|
@ -3401,8 +3399,8 @@ colorette@^1.2.1:
|
|||
|
||||
colors@^1.1.2:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.npm.taobao.org/colors/download/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
|
||||
integrity sha1-xQSRR51MG9rtLJztMs98fcI2D3g=
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
|
||||
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
|
||||
|
||||
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
|
||||
version "1.0.8"
|
||||
|
@ -3418,8 +3416,8 @@ commander@2.17.x:
|
|||
|
||||
commander@^2.18.0, commander@^2.20.0, commander@^2.9.0:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.npm.taobao.org/commander/download/commander-2.20.3.tgz?cache=0&sync_timestamp=1598576116597&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
|
||||
commander@~2.19.0:
|
||||
version "2.19.0"
|
||||
|
@ -3640,8 +3638,8 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
|
|||
|
||||
cors@^2.8.5:
|
||||
version "2.8.5"
|
||||
resolved "https://registry.npm.taobao.org/cors/download/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
|
||||
integrity sha1-6sEdpRWS3Ya58G9uesKTs9+HXSk=
|
||||
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
|
||||
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
|
||||
dependencies:
|
||||
object-assign "^4"
|
||||
vary "^1"
|
||||
|
@ -3733,6 +3731,11 @@ crypto-browserify@^3.11.0:
|
|||
randombytes "^2.0.0"
|
||||
randomfill "^1.0.3"
|
||||
|
||||
crypto-js@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.0.0.tgz#2904ab2677a9d042856a2ea2ef80de92e4a36dcc"
|
||||
integrity sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==
|
||||
|
||||
crypto-random-string@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npm.taobao.org/crypto-random-string/download/crypto-random-string-2.0.0.tgz?cache=0&sync_timestamp=1599139352103&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcrypto-random-string%2Fdownload%2Fcrypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
|
||||
|
@ -3944,8 +3947,8 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
|
|||
|
||||
debug@^3.1.0, debug@^3.1.1, debug@^3.2.5:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz?cache=0&sync_timestamp=1600502894812&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
integrity sha1-6D0X3hbYp++3cX7b5fsQE17uYps=
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
|
@ -4116,14 +4119,6 @@ detect-node@^2.0.4:
|
|||
resolved "https://registry.npm.taobao.org/detect-node/download/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
|
||||
integrity sha1-AU7o+PZpxcWAI9pkuBecCDooxGw=
|
||||
|
||||
dezalgo@1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
|
||||
integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=
|
||||
dependencies:
|
||||
asap "^2.0.0"
|
||||
wrappy "1"
|
||||
|
||||
diffie-hellman@^5.0.0:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.npm.taobao.org/diffie-hellman/download/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
|
||||
|
@ -4159,8 +4154,8 @@ dns-equal@^1.0.0:
|
|||
|
||||
dns-over-http@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npm.taobao.org/dns-over-http/download/dns-over-http-0.2.0.tgz#1f2ead0752621668b67b8fbbfa85b10abd9f4768"
|
||||
integrity sha1-Hy6tB1JiFmi2e4+7+oWxCr2fR2g=
|
||||
resolved "https://registry.yarnpkg.com/dns-over-http/-/dns-over-http-0.2.0.tgz#1f2ead0752621668b67b8fbbfa85b10abd9f4768"
|
||||
integrity sha512-K+SyN2L3ljxJ2MFtOv/vRS+3/YEMLvOuH7MrmO5ejaubi4w02/DLqzoK1kBGKlQrT9ND57pbapeDf+ue8AElEA==
|
||||
dependencies:
|
||||
accept "^3.1.3"
|
||||
cors "^2.8.5"
|
||||
|
@ -4174,8 +4169,8 @@ dns-over-http@^0.2.0:
|
|||
|
||||
dns-over-tls@^0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.npm.taobao.org/dns-over-tls/download/dns-over-tls-0.0.8.tgz#0ea3af54c0073e153a989a616c500e79f9f3ac0e"
|
||||
integrity sha1-DqOvVMAHPhU6mJphbFAOefnzrA4=
|
||||
resolved "https://registry.yarnpkg.com/dns-over-tls/-/dns-over-tls-0.0.8.tgz#0ea3af54c0073e153a989a616c500e79f9f3ac0e"
|
||||
integrity sha512-2r1IBUEffIbhjuyOyKCsiMimXFCCEADY9Xfu9+p2NuUpSB6Si03+rPdLL9wxzkD6dI1d7gaJt+ekVIg3tW+ReQ==
|
||||
dependencies:
|
||||
dns-packet "^5.2.1"
|
||||
|
||||
|
@ -4189,23 +4184,23 @@ dns-packet@^1.3.1:
|
|||
|
||||
dns-packet@^4.1.0, dns-packet@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.npm.taobao.org/dns-packet/download/dns-packet-4.2.0.tgz#3fd6f5ff5a4ec3194ed0b15312693ffe8776b343"
|
||||
integrity sha1-P9b1/1pOwxlO0LFTEmk//od2s0M=
|
||||
resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-4.2.0.tgz#3fd6f5ff5a4ec3194ed0b15312693ffe8776b343"
|
||||
integrity sha512-bn1AKpfkFbm0MIioOMHZ5qJzl2uypdBwI4nYNsqvhjsegBhcKJUlCrMPWLx6JEezRjxZmxhtIz/FkBEur2l8Cw==
|
||||
dependencies:
|
||||
ip "^1.1.5"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
dns-packet@^5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.npm.taobao.org/dns-packet/download/dns-packet-5.2.1.tgz#26cec0be92252a1b97ed106482921192a7e08f72"
|
||||
integrity sha1-Js7AvpIlKhuX7RBkgpIRkqfgj3I=
|
||||
resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.2.1.tgz#26cec0be92252a1b97ed106482921192a7e08f72"
|
||||
integrity sha512-JHj2yJeKOqlxzeuYpN1d56GfhzivAxavNwHj9co3qptECel27B1rLY5PifJAvubsInX5pGLDjAHuCfCUc2Zv/w==
|
||||
dependencies:
|
||||
ip "^1.1.5"
|
||||
|
||||
dns-socket@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npm.taobao.org/dns-socket/download/dns-socket-3.0.0.tgz#3418a3c6309656ebdb3eb0a941811a4fb0b828c5"
|
||||
integrity sha1-NBijxjCWVuvbPrCpQYEaT7C4KMU=
|
||||
resolved "https://registry.yarnpkg.com/dns-socket/-/dns-socket-3.0.0.tgz#3418a3c6309656ebdb3eb0a941811a4fb0b828c5"
|
||||
integrity sha512-M0WkByoJ/mTm+HtwBQLsRJPe5uGIC/lYVOp+s6ZzhbZ5iq4GxjFyxYPQhB85dgCLvVb43aJQXHDC9aUgyKGc/Q==
|
||||
dependencies:
|
||||
dns-packet "^4.1.0"
|
||||
|
||||
|
@ -5055,8 +5050,8 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
|
|||
|
||||
extend@^3.0.1, extend@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz?cache=0&sync_timestamp=1589682707348&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fextend%2Fdownload%2Fextend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
|
||||
external-editor@^3.0.3:
|
||||
version "3.1.0"
|
||||
|
@ -5334,7 +5329,7 @@ for-in@^1.0.2:
|
|||
|
||||
foreach@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npm.taobao.org/foreach/download/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
|
||||
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
|
||||
integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k=
|
||||
|
||||
forever-agent@~0.6.1:
|
||||
|
@ -5360,15 +5355,10 @@ form-data@~2.3.2:
|
|||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
formidable@2.0.0-canary.20200504.1, formidable@^1.2.2:
|
||||
version "2.0.0-canary.20200504.1"
|
||||
resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.0.0-canary.20200504.1.tgz#8b060a43f77da82aa7ddc395e1bb4d845b65dc0b"
|
||||
integrity sha512-//FlGY4V1wl5+Q54Gfx8FHErl0tDrRatftGFOgis2IeH8JFs4Ve/r+hubMRfk3gjSyI8VYLg8dWfa1DqfhMdCg==
|
||||
dependencies:
|
||||
dezalgo "1.0.3"
|
||||
hexoid "1.0.0"
|
||||
once "1.4.0"
|
||||
qs "^6.9.3"
|
||||
formidable@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9"
|
||||
integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==
|
||||
|
||||
forwarded@~0.1.2:
|
||||
version "0.1.2"
|
||||
|
@ -5816,11 +5806,6 @@ hex-color-regex@^1.1.0:
|
|||
resolved "https://registry.npm.taobao.org/hex-color-regex/download/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
|
||||
integrity sha1-TAb8y0YC/iYCs8k9+C1+fb8aio4=
|
||||
|
||||
hexoid@1.0.0, hexoid@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18"
|
||||
integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==
|
||||
|
||||
highlight.js@^9.6.0:
|
||||
version "9.18.3"
|
||||
resolved "https://registry.npm.taobao.org/highlight.js/download/highlight.js-9.18.3.tgz#a1a0a2028d5e3149e2380f8a865ee8516703d634"
|
||||
|
@ -5837,8 +5822,8 @@ hmac-drbg@^1.0.0:
|
|||
|
||||
hoek@6.x.x:
|
||||
version "6.1.3"
|
||||
resolved "https://registry.npm.taobao.org/hoek/download/hoek-6.1.3.tgz#73b7d33952e01fe27a38b0457294b79dd8da242c"
|
||||
integrity sha1-c7fTOVLgH+J6OLBFcpS3ndjaJCw=
|
||||
resolved "https://registry.yarnpkg.com/hoek/-/hoek-6.1.3.tgz#73b7d33952e01fe27a38b0457294b79dd8da242c"
|
||||
integrity sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==
|
||||
|
||||
hoopy@^0.1.4:
|
||||
version "0.1.4"
|
||||
|
@ -6033,8 +6018,8 @@ icon-gen@^2.0.0:
|
|||
|
||||
iconv-lite@0.4.24, iconv-lite@^0.4.13, iconv-lite@^0.4.24:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
integrity sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
|
@ -6292,8 +6277,8 @@ is-binary-path@~2.1.0:
|
|||
|
||||
is-browser@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npm.taobao.org/is-browser/download/is-browser-2.1.0.tgz#fc084d59a5fced307d6708c59356bad7007371a9"
|
||||
integrity sha1-/AhNWaX87TB9ZwjFk1a61wBzcak=
|
||||
resolved "https://registry.yarnpkg.com/is-browser/-/is-browser-2.1.0.tgz#fc084d59a5fced307d6708c59356bad7007371a9"
|
||||
integrity sha512-F5rTJxDQ2sW81fcfOR1GnCXT6sVJC104fCyfj+mjpwNEwaPYSn5fte5jiHmBg3DHsIoL/l8Kvw5VN5SsTRcRFQ==
|
||||
|
||||
is-buffer@^1.1.5:
|
||||
version "1.1.6"
|
||||
|
@ -6419,8 +6404,8 @@ is-function@^1.0.1:
|
|||
|
||||
is-generator-function@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.npm.taobao.org/is-generator-function/download/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522"
|
||||
integrity sha1-0hMuUpuwAAp/gHlNS99c1eWBNSI=
|
||||
resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522"
|
||||
integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==
|
||||
|
||||
is-glob@^3.1.0:
|
||||
version "3.1.0"
|
||||
|
@ -6574,8 +6559,8 @@ is-symbol@^1.0.2:
|
|||
|
||||
is-typed-array@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npm.taobao.org/is-typed-array/download/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d"
|
||||
integrity sha1-pP9aXmcuGlX5nH9U5ZWXr1wd8E0=
|
||||
resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d"
|
||||
integrity sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ==
|
||||
dependencies:
|
||||
available-typed-arrays "^1.0.0"
|
||||
es-abstract "^1.17.4"
|
||||
|
@ -6732,8 +6717,8 @@ jsbn@~0.1.0:
|
|||
|
||||
jschardet@^1.4.1:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.npm.taobao.org/jschardet/download/jschardet-1.6.0.tgz#c7d1a71edcff2839db2f9ec30fc5d5ebd3c1a678"
|
||||
integrity sha1-x9GnHtz/KDnbL57DD8XV69PBpng=
|
||||
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.6.0.tgz#c7d1a71edcff2839db2f9ec30fc5d5ebd3c1a678"
|
||||
integrity sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ==
|
||||
|
||||
jsesc@^2.5.1:
|
||||
version "2.5.2"
|
||||
|
@ -7138,8 +7123,8 @@ lodash.uniq@^4.5.0:
|
|||
|
||||
lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.3, lodash@^4.17.5, lodash@^4.7.0:
|
||||
version "4.17.20"
|
||||
resolved "https://registry.npm.taobao.org/lodash/download/lodash-4.17.20.tgz?cache=0&sync_timestamp=1597335994883&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
|
||||
integrity sha1-tEqbYpe8tpjxxRo1RaKzs2jVnFI=
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
|
||||
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
|
||||
|
||||
log-symbols@^2.2.0:
|
||||
version "2.2.0"
|
||||
|
@ -7417,8 +7402,8 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
|
|||
|
||||
minimatch@^3.0.2, minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
|
@ -7575,8 +7560,8 @@ nan@^2.12.1:
|
|||
|
||||
nanoid@^2.1.0:
|
||||
version "2.1.11"
|
||||
resolved "https://registry.npm.taobao.org/nanoid/download/nanoid-2.1.11.tgz?cache=0&sync_timestamp=1603419433040&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnanoid%2Fdownload%2Fnanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
|
||||
integrity sha1-7CS4p1jVkVYVMbQXagHjq08PAoA=
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
|
||||
integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
|
||||
|
||||
nanomatch@^1.2.9:
|
||||
version "1.2.13"
|
||||
|
@ -7629,12 +7614,12 @@ no-case@^2.2.0:
|
|||
|
||||
node-cmd@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npm.taobao.org/node-cmd/download/node-cmd-3.0.0.tgz#38fff70a4aaa4f659d203eb57862737018e24f6f"
|
||||
resolved "https://registry.yarnpkg.com/node-cmd/-/node-cmd-3.0.0.tgz#38fff70a4aaa4f659d203eb57862737018e24f6f"
|
||||
integrity sha1-OP/3CkqqT2WdID61eGJzcBjiT28=
|
||||
|
||||
node-dir@^0.1.17:
|
||||
version "0.1.17"
|
||||
resolved "https://registry.npm.taobao.org/node-dir/download/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5"
|
||||
resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5"
|
||||
integrity sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=
|
||||
dependencies:
|
||||
minimatch "^3.0.2"
|
||||
|
@ -7653,8 +7638,8 @@ node-forge@^0.10.0:
|
|||
|
||||
node-forge@^0.8.2:
|
||||
version "0.8.5"
|
||||
resolved "https://registry.npm.taobao.org/node-forge/download/node-forge-0.8.5.tgz?cache=0&sync_timestamp=1599010773454&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-forge%2Fdownload%2Fnode-forge-0.8.5.tgz#57906f07614dc72762c84cef442f427c0e1b86ee"
|
||||
integrity sha1-V5BvB2FNxydiyEzvRC9CfA4bhu4=
|
||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.8.5.tgz#57906f07614dc72762c84cef442f427c0e1b86ee"
|
||||
integrity sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q==
|
||||
|
||||
node-ipc@^9.1.1:
|
||||
version "9.1.1"
|
||||
|
@ -7696,8 +7681,8 @@ node-ipc@^9.1.1:
|
|||
|
||||
node-powershell@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npm.taobao.org/node-powershell/download/node-powershell-4.0.0.tgz#f3a0b1ec4f5619b501b66005f8a663c8373e8da8"
|
||||
integrity sha1-86Cx7E9WGbUBtmAF+KZjyDc+jag=
|
||||
resolved "https://registry.yarnpkg.com/node-powershell/-/node-powershell-4.0.0.tgz#f3a0b1ec4f5619b501b66005f8a663c8373e8da8"
|
||||
integrity sha512-WCZMLgwkjW9G/DZsZwyCEAXhMMzShLRUlnYS+EETRqRLSdUMbuO4xiQxIOeAutwQgvj75NvC58CorHFlx0olIA==
|
||||
dependencies:
|
||||
chalk "^2.4.1"
|
||||
shortid "^2.2.14"
|
||||
|
@ -7805,7 +7790,7 @@ oauth-sign@~0.9.0:
|
|||
|
||||
object-assign@4.x, object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
object-copy@^0.1.0:
|
||||
|
@ -7911,7 +7896,7 @@ on-headers@~1.0.2:
|
|||
resolved "https://registry.npm.taobao.org/on-headers/download/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
|
||||
integrity sha1-dysK5qqlJcOZ5Imt+tkMQD6zwo8=
|
||||
|
||||
once@1.4.0, once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
|
@ -8947,10 +8932,10 @@ qs@6.7.0:
|
|||
resolved "https://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||
integrity sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=
|
||||
|
||||
qs@^6.6.0, qs@^6.9.3, qs@^6.9.4:
|
||||
qs@^6.6.0, qs@^6.9.4:
|
||||
version "6.9.4"
|
||||
resolved "https://registry.npm.taobao.org/qs/download/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
|
||||
integrity sha1-kJCykNH5FyjTwi5UhDykSupatoc=
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
|
||||
integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==
|
||||
|
||||
qs@~6.5.2:
|
||||
version "6.5.2"
|
||||
|
@ -8989,7 +8974,7 @@ raf@^3.4.0:
|
|||
|
||||
random-int@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npm.taobao.org/random-int/download/random-int-1.0.0.tgz#e6a2ed3448ac9c6646a0657443b1c1521592ed08"
|
||||
resolved "https://registry.yarnpkg.com/random-int/-/random-int-1.0.0.tgz#e6a2ed3448ac9c6646a0657443b1c1521592ed08"
|
||||
integrity sha1-5qLtNEisnGZGoGV0Q7HBUhWS7Qg=
|
||||
|
||||
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
|
||||
|
@ -9284,8 +9269,8 @@ request@^2.81.0, request@^2.88.2:
|
|||
|
||||
require-context@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npm.taobao.org/require-context/download/require-context-1.1.0.tgz#f77e60dddb0a296946e6915bf580c73dbe75ab4d"
|
||||
integrity sha1-935g3dsKKWlG5pFb9YDHPb51q00=
|
||||
resolved "https://registry.yarnpkg.com/require-context/-/require-context-1.1.0.tgz#f77e60dddb0a296946e6915bf580c73dbe75ab4d"
|
||||
integrity sha512-nfYSy3Q9W3W1fCo0nief19bDq216IGY9+wOUsmCWAJ5jssyak0r110rvqIj4KJYoUYDxLDaeA66ONOYy4PJEUw==
|
||||
dependencies:
|
||||
node-dir "^0.1.17"
|
||||
|
||||
|
@ -9719,8 +9704,8 @@ shell-quote@^1.6.1:
|
|||
|
||||
shortid@^2.2.14:
|
||||
version "2.2.16"
|
||||
resolved "https://registry.npm.taobao.org/shortid/download/shortid-2.2.16.tgz#b742b8f0cb96406fd391c76bfc18a67a57fe5608"
|
||||
integrity sha1-t0K48MuWQG/Tkcdr/Bimelf+Vgg=
|
||||
resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.16.tgz#b742b8f0cb96406fd391c76bfc18a67a57fe5608"
|
||||
integrity sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==
|
||||
dependencies:
|
||||
nanoid "^2.1.0"
|
||||
|
||||
|
@ -10419,8 +10404,8 @@ through2-map@^3.0.0:
|
|||
|
||||
through2@^2.0.0, through2@^2.0.1, through2@~2.0.0:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npm.taobao.org/through2/download/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
|
||||
integrity sha1-AcHjnrMdB8t9A6lqcIIyYLIxMs0=
|
||||
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
|
||||
integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
|
||||
dependencies:
|
||||
readable-stream "~2.3.6"
|
||||
xtend "~4.0.1"
|
||||
|
@ -10568,7 +10553,7 @@ tty-browserify@0.0.0:
|
|||
|
||||
tunnel-agent@^0.4.3:
|
||||
version "0.4.3"
|
||||
resolved "https://registry.npm.taobao.org/tunnel-agent/download/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb"
|
||||
integrity sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
|
@ -10887,8 +10872,8 @@ util@^0.11.0:
|
|||
|
||||
util@^0.12.3:
|
||||
version "0.12.3"
|
||||
resolved "https://registry.npm.taobao.org/util/download/util-0.12.3.tgz#971bb0292d2cc0c892dab7c6a5d37c2bec707888"
|
||||
integrity sha1-lxuwKS0swMiS2rfGpdN8K+xweIg=
|
||||
resolved "https://registry.yarnpkg.com/util/-/util-0.12.3.tgz#971bb0292d2cc0c892dab7c6a5d37c2bec707888"
|
||||
integrity sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog==
|
||||
dependencies:
|
||||
inherits "^2.0.3"
|
||||
is-arguments "^1.0.4"
|
||||
|
@ -10927,12 +10912,12 @@ validate-npm-package-license@^3.0.1:
|
|||
|
||||
validator@^13.1.17:
|
||||
version "13.1.17"
|
||||
resolved "https://registry.npm.taobao.org/validator/download/validator-13.1.17.tgz?cache=0&sync_timestamp=1600459985144&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvalidator%2Fdownload%2Fvalidator-13.1.17.tgz#ad677736950adddd3c37209484a6b2e0966579ad"
|
||||
integrity sha1-rWd3NpUK3d08NyCUhKay4JZlea0=
|
||||
resolved "https://registry.yarnpkg.com/validator/-/validator-13.1.17.tgz#ad677736950adddd3c37209484a6b2e0966579ad"
|
||||
integrity sha512-zL5QBoemJ3jYFb2/j38y7ljhwYGXVLUp8H6W1nVxadnAOvUOytec+L7BHh1oBQ82/TzWXHd+GSaxUWp4lROkLg==
|
||||
|
||||
vary@^1, vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
||||
|
||||
vendors@^1.0.0:
|
||||
|
@ -11260,8 +11245,8 @@ which-module@^2.0.0:
|
|||
|
||||
which-typed-array@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npm.taobao.org/which-typed-array/download/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2"
|
||||
integrity sha1-5fmOVr2pPj2sGWsB1HwRVmecALI=
|
||||
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2"
|
||||
integrity sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ==
|
||||
dependencies:
|
||||
available-typed-arrays "^1.0.2"
|
||||
es-abstract "^1.17.5"
|
||||
|
@ -11293,7 +11278,7 @@ widest-line@^3.1.0:
|
|||
|
||||
winreg@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.npm.taobao.org/winreg/download/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b"
|
||||
resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b"
|
||||
integrity sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs=
|
||||
|
||||
word-wrap@~1.2.3:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docmirror/mitmproxy",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docmirror/mitmproxy",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.1",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"keywords": [
|
||||
|
@ -15,6 +15,7 @@
|
|||
"child_process": "^1.0.2",
|
||||
"colors": "^1.1.2",
|
||||
"commander": "^2.9.0",
|
||||
"crypto-js": "^4.0.0",
|
||||
"debug": "^4.1.1",
|
||||
"dns-over-http": "^0.2.0",
|
||||
"dns-over-tls": "^0.0.8",
|
||||
|
|
|
@ -1,40 +1,35 @@
|
|||
const mitmproxy = require('./lib/proxy')
|
||||
const ProxyOptions = require('./options')
|
||||
const config = require('./lib/proxy/common/config')
|
||||
|
||||
function fireError (e) {
|
||||
process.send({ type: 'error', event: e })
|
||||
}
|
||||
function fireStatus (status) {
|
||||
process.send({ type: 'status', event: status })
|
||||
}
|
||||
const proxyConfig = require('./lib/proxy/common/config')
|
||||
const log = require('./utils/util.log')
|
||||
const { fireError, fireStatus } = require('./utils/util.process')
|
||||
|
||||
let server
|
||||
|
||||
function registerProcessListener () {
|
||||
process.on('message', function (msg) {
|
||||
console.log('child get msg: ' + JSON.stringify(msg))
|
||||
log.info('child get msg: ' + JSON.stringify(msg))
|
||||
if (msg.type === 'action') {
|
||||
api[msg.event.key](msg.event.params)
|
||||
}
|
||||
})
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
console.log('on sigint : closed ')
|
||||
log.info('on sigint : closed ')
|
||||
process.exit(0)
|
||||
})
|
||||
|
||||
// 避免异常崩溃
|
||||
process.on('uncaughtException', function (err) {
|
||||
if (err.code === 'ECONNABORTED') {
|
||||
// console.error(err.errno)
|
||||
// log.error(err.errno)
|
||||
return
|
||||
}
|
||||
console.error('uncaughtException:', err)
|
||||
log.error('uncaughtException:', err)
|
||||
})
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason)
|
||||
process.on('unhandledRejection', (err, p) => {
|
||||
log.info('Unhandled Rejection at: Promise', p, 'err:', err)
|
||||
// application specific logging, throwing an error, or other logic here
|
||||
})
|
||||
}
|
||||
|
@ -42,6 +37,13 @@ function registerProcessListener () {
|
|||
const api = {
|
||||
async start (config) {
|
||||
const proxyOptions = ProxyOptions(config)
|
||||
const setting = config.setting
|
||||
if (setting) {
|
||||
if (setting.userBasePath) {
|
||||
proxyConfig.setDefaultCABasePath(setting.userBasePath)
|
||||
}
|
||||
}
|
||||
|
||||
if (proxyOptions.setting && proxyOptions.setting.NODE_TLS_REJECT_UNAUTHORIZED === false) {
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
||||
} else {
|
||||
|
@ -49,17 +51,17 @@ const api = {
|
|||
}
|
||||
const newServer = mitmproxy.createProxy(proxyOptions, () => {
|
||||
fireStatus(true)
|
||||
console.log('代理服务已启动:127.0.0.1:' + proxyOptions.port)
|
||||
log.info('代理服务已启动:127.0.0.1:' + proxyOptions.port)
|
||||
})
|
||||
newServer.on('close', () => {
|
||||
console.log('server will closed ')
|
||||
log.info('server will closed ')
|
||||
if (server === newServer) {
|
||||
server = null
|
||||
fireStatus(false)
|
||||
}
|
||||
})
|
||||
newServer.on('error', (e) => {
|
||||
console.log('server error', e)
|
||||
log.info('server error', e)
|
||||
// newServer = null
|
||||
fireError(e)
|
||||
})
|
||||
|
@ -72,20 +74,20 @@ const api = {
|
|||
if (server) {
|
||||
server.close((err) => {
|
||||
if (err) {
|
||||
console.log('close error', err, ',', err.code, ',', err.message, ',', err.errno)
|
||||
log.info('close error', err, ',', err.code, ',', err.message, ',', err.errno)
|
||||
if (err.code === 'ERR_SERVER_NOT_RUNNING') {
|
||||
console.log('代理服务关闭成功')
|
||||
log.info('代理服务关闭成功')
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
reject(err)
|
||||
} else {
|
||||
console.log('代理服务关闭成功')
|
||||
log.info('代理服务关闭成功')
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
console.log('server is null')
|
||||
log.info('server is null')
|
||||
fireStatus(false)
|
||||
resolve()
|
||||
}
|
||||
|
@ -95,5 +97,6 @@ const api = {
|
|||
|
||||
module.exports = {
|
||||
...api,
|
||||
config
|
||||
config: proxyConfig,
|
||||
log
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
const { ChoiceCache } = require('./index')
|
||||
|
||||
module.exports = new ChoiceCache()
|
|
@ -0,0 +1,3 @@
|
|||
const { ChoiceCache } = require('./index')
|
||||
|
||||
module.exports = new ChoiceCache()
|
|
@ -0,0 +1,114 @@
|
|||
const LRU = require('lru-cache')
|
||||
const cacheSize = 1024
|
||||
const log = require('../../utils/util.log')
|
||||
class ChoiceCache {
|
||||
constructor () {
|
||||
this.cache = new LRU(cacheSize)
|
||||
}
|
||||
|
||||
get (key) {
|
||||
return this.cache.get(key)
|
||||
}
|
||||
|
||||
getOrCreate (key, backups) {
|
||||
let item = this.cache.get(key)
|
||||
if (item == null) {
|
||||
item = new DynamicChoice(key)
|
||||
item.setBackupList(backups)
|
||||
this.cache.set(key, item)
|
||||
}
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicChoice {
|
||||
constructor (key) {
|
||||
this.key = key
|
||||
this.count = {}
|
||||
this.createTime = new Date()
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置新的backup列表
|
||||
* @param backupList
|
||||
*/
|
||||
setBackupList (backupList) {
|
||||
this.backup = backupList
|
||||
let defaultTotal = backupList.length
|
||||
for (const item of backupList) {
|
||||
if (this.count[item]) {
|
||||
continue
|
||||
}
|
||||
this.count[item] = { value: item, total: defaultTotal, error: 0, keepErrorCount: 0, successRate: 1 }
|
||||
defaultTotal--
|
||||
}
|
||||
this.value = backupList.shift()
|
||||
this.doCount(this.value, false)
|
||||
}
|
||||
|
||||
doRank () {
|
||||
// 将count里面根据权重排序
|
||||
const list = []
|
||||
for (const key in this.count) {
|
||||
list.push(this.count[key])
|
||||
}
|
||||
list.sort((a, b) => {
|
||||
return b.successRate - a.successRate
|
||||
})
|
||||
log.info('do rank', JSON.stringify(list))
|
||||
const backup = list.map(item => item.value)
|
||||
|
||||
this.setBackupList(backup)
|
||||
}
|
||||
|
||||
countStart (value) {
|
||||
this.doCount(value, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 换下一个
|
||||
* @param count
|
||||
*/
|
||||
changeNext (count) {
|
||||
count.keepErrorCount = 0 // 清空连续失败
|
||||
if (this.backup > 0) {
|
||||
this.value = this.backup.shift()
|
||||
} else {
|
||||
this.value = null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录使用次数或错误次数
|
||||
* @param value
|
||||
* @param isError
|
||||
*/
|
||||
doCount (value, isError) {
|
||||
let count = this.count[value]
|
||||
if (count == null) {
|
||||
count = this.count[value] = { value: value, total: 0, error: 0, keepErrorCount: 0, successRate: 1 }
|
||||
}
|
||||
if (isError) {
|
||||
count.error++
|
||||
count.keepErrorCount++
|
||||
} else {
|
||||
count.total++
|
||||
}
|
||||
count.successRate = 1.0 - (count.error / count.total)
|
||||
if (isError && this.value === value) {
|
||||
// 连续错误4次,切换下一个
|
||||
if (count.keepErrorCount >= 4) {
|
||||
this.changeNext(count)
|
||||
}
|
||||
// 成功率小于50%,切换下一个
|
||||
if (count.successRate < 0.51) {
|
||||
this.changeNext(count)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
DynamicChoice,
|
||||
ChoiceCache
|
||||
}
|
|
@ -1,71 +1,26 @@
|
|||
const LRU = require('lru-cache')
|
||||
// const { isIP } = require('validator')
|
||||
const getLogger = require('../utils/logger')
|
||||
|
||||
const logger = getLogger('dns')
|
||||
const log = require('../../utils/util.log')
|
||||
const { DynamicChoice } = require('../choice/index')
|
||||
const cacheSize = 1024
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
// function _isIP (v) {
|
||||
// return v && isIP(v)
|
||||
// }
|
||||
|
||||
class IpCache {
|
||||
class IpCache extends DynamicChoice {
|
||||
constructor (hostname) {
|
||||
this.hostname = hostname
|
||||
this.count = {}
|
||||
super(hostname)
|
||||
this.lookupCount = 0
|
||||
this.createTime = new Date()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取到新的ipList
|
||||
* @param ipList
|
||||
*/
|
||||
setIpList (ipList) {
|
||||
this.ip = ipList.shift()
|
||||
this.ipList = ipList
|
||||
setBackupList (ipList) {
|
||||
super.setBackupList(ipList)
|
||||
this.lookupCount++
|
||||
this.doCount(this.ip, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 换下一个ip
|
||||
* @param count
|
||||
*/
|
||||
changeNext (count) {
|
||||
count.keepErrorCount = 0 // 清空连续失败
|
||||
if (this.ipList > 0) {
|
||||
this.ip = this.ipList.shift()
|
||||
} else {
|
||||
this.ip = null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录使用次数或错误次数
|
||||
* @param ip
|
||||
* @param isError
|
||||
*/
|
||||
doCount (ip, isError) {
|
||||
let count = this.count[ip]
|
||||
if (count == null) {
|
||||
count = this.count[ip] = { total: 0, error: 0, keepErrorCount: 0, successRate: 0 }
|
||||
}
|
||||
if (isError) {
|
||||
count.error++
|
||||
count.keepErrorCount++
|
||||
} else {
|
||||
count.total++
|
||||
}
|
||||
count.successRate = 1 - (count.error / count.total)
|
||||
if (isError && this.ip === ip) {
|
||||
if (count.keepErrorCount >= 5) {
|
||||
this.changeNext(count)
|
||||
}
|
||||
if (count.successRate < 0.51) {
|
||||
this.changeNext(count)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,9 +40,9 @@ module.exports = class BaseDNS {
|
|||
try {
|
||||
let ipCache = this.cache.get(hostname)
|
||||
if (ipCache) {
|
||||
if (ipCache.ip != null) {
|
||||
ipCache.doCount(ipCache.ip, false)
|
||||
return ipCache.ip
|
||||
if (ipCache.value != null) {
|
||||
ipCache.doCount(ipCache.value, false)
|
||||
return ipCache.value
|
||||
}
|
||||
} else {
|
||||
ipCache = new IpCache(hostname)
|
||||
|
@ -102,13 +57,13 @@ module.exports = class BaseDNS {
|
|||
}
|
||||
ipList.push(hostname) // 把原域名加入到统计里去
|
||||
|
||||
ipCache.setIpList(ipList)
|
||||
ipCache.setBackupList(ipList)
|
||||
|
||||
logger.debug(`[DNS] ${hostname} -> ${ipCache.ip} (${new Date() - t} ms)`)
|
||||
log.info(`[DNS] ${hostname} -> ${ipCache.value} (${new Date() - t} ms)`)
|
||||
|
||||
return ipCache.ip
|
||||
return ipCache.value
|
||||
} catch (error) {
|
||||
logger.debug(`[DNS] cannot resolve hostname ${hostname} (${error})`)
|
||||
log.error(`[DNS] cannot resolve hostname ${hostname} (${error})`, error)
|
||||
return hostname
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const { promisify } = require('util')
|
||||
const doh = require('dns-over-http')
|
||||
const BaseDNS = require('./base')
|
||||
|
||||
const log = require('../../utils/util.log')
|
||||
const dohQueryAsync = promisify(doh.query)
|
||||
|
||||
module.exports = class DNSOverHTTPS extends BaseDNS {
|
||||
|
@ -15,18 +15,18 @@ module.exports = class DNSOverHTTPS extends BaseDNS {
|
|||
const result = await dohQueryAsync({ url: this.dnsServer }, [{ type: 'A', name: hostname }])
|
||||
if (result.answers.length === 0) {
|
||||
// 说明没有获取到ip
|
||||
console.log('该域名没有ip地址解析', hostname)
|
||||
log.info('该域名没有ip地址解析', hostname)
|
||||
return []
|
||||
}
|
||||
const ret = result.answers.filter(item => { return item.type === 'A' }).map(item => { return item.data })
|
||||
if (ret.length === 0) {
|
||||
console.log('该域名没有ipv4地址解析', hostname)
|
||||
log.info('该域名没有ipv4地址解析', hostname)
|
||||
} else {
|
||||
console.log('获取到域名地址:', hostname, JSON.stringify(ret))
|
||||
log.info('获取到域名地址:', hostname, JSON.stringify(ret))
|
||||
}
|
||||
return ret
|
||||
} catch (err) {
|
||||
console.log('dns query error', hostname, err)
|
||||
log.info('dns query error', hostname, err.message)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
module.exports = {
|
||||
requestInterceptor (interceptOpt, rOptions, req, res, ssl) {
|
||||
console.log('abort:', rOptions.hostname, req.url)
|
||||
requestIntercept (context, interceptOpts, req, res, ssl, next) {
|
||||
const { rOptions, log } = context
|
||||
log.info('abort:', rOptions.hostname, req.url)
|
||||
res.writeHead(403)
|
||||
res.write('DevSidecar 403: \n\n request abort, this request is matched by abort intercept.\n\n 因配置abort拦截器,本请求将取消')
|
||||
res.end()
|
||||
return true// 是否结束
|
||||
},
|
||||
is (interceptOpt) {
|
||||
return !!interceptOpt.abort
|
||||
|
|
|
@ -1,7 +1,41 @@
|
|||
const url = require('url')
|
||||
module.exports = {
|
||||
requestInterceptor (interceptOpt, rOptions, req, res, ssl, next) {
|
||||
const proxyTarget = interceptOpt.proxy
|
||||
requestIntercept (context, interceptOpt, req, res, ssl, next) {
|
||||
const { rOptions, log, RequestCounter } = context
|
||||
|
||||
let proxyConf = interceptOpt.proxy
|
||||
if (RequestCounter && interceptOpt.backup) {
|
||||
// 优选逻辑
|
||||
const backup = [proxyConf]
|
||||
if (interceptOpt.backup) {
|
||||
for (const bk of interceptOpt.backup) {
|
||||
backup.push(bk)
|
||||
}
|
||||
}
|
||||
|
||||
const key = interceptOpt.key
|
||||
const count = RequestCounter.getOrCreate(key, backup)
|
||||
if (count.value == null) {
|
||||
count.doRank()
|
||||
}
|
||||
if (count.value == null) {
|
||||
log.error('count value is null', count)
|
||||
} else {
|
||||
count.doCount(count.value)
|
||||
proxyConf = count.value
|
||||
context.requestCount = {
|
||||
key,
|
||||
value: count.value,
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let proxyTarget = proxyConf + req.url
|
||||
if (interceptOpt.replace) {
|
||||
const regexp = new RegExp(interceptOpt.replace)
|
||||
proxyTarget = req.url.replace(regexp, proxyConf)
|
||||
}
|
||||
// const backup = interceptOpt.backup
|
||||
const proxy = proxyTarget.indexOf('http') === 0 ? proxyTarget : rOptions.protocol + '//' + proxyTarget
|
||||
// eslint-disable-next-line node/no-deprecated-api
|
||||
|
@ -10,11 +44,13 @@ module.exports = {
|
|||
rOptions.hostname = URL.host
|
||||
rOptions.host = URL.host
|
||||
rOptions.headers.host = URL.host
|
||||
rOptions.path = URL.path
|
||||
if (URL.port == null) {
|
||||
rOptions.port = rOptions.protocol === 'https:' ? 443 : 80
|
||||
}
|
||||
|
||||
console.log('proxy:', rOptions.hostname, req.url, proxyTarget)
|
||||
log.info('proxy:', rOptions.hostname, proxyTarget)
|
||||
log.debug('proxy choice:', JSON.stringify(context.requestCount))
|
||||
return true
|
||||
},
|
||||
is (interceptOpt) {
|
||||
return !!interceptOpt.proxy
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
module.exports = {
|
||||
requestInterceptor (interceptOpt, rOptions, req, res, ssl) {
|
||||
requestIntercept (context, interceptOpt, req, res, ssl, next) {
|
||||
const { rOptions, log } = context
|
||||
const url = req.url
|
||||
let redirect
|
||||
if (typeof interceptOpt.redirect === 'string') {
|
||||
|
@ -7,10 +8,10 @@ module.exports = {
|
|||
} else {
|
||||
redirect = interceptOpt.redirect(url)
|
||||
}
|
||||
console.log('请求重定向:', rOptions.hostname, url, redirect)
|
||||
log.info('请求重定向:', rOptions.hostname, url, redirect)
|
||||
res.writeHead(302, { Location: redirect })
|
||||
res.end()
|
||||
return true
|
||||
return true// 是否结束
|
||||
},
|
||||
is (interceptOpt) {
|
||||
return interceptOpt.redirect // 如果配置中有redirect,那么这个配置是需要redirect拦截的
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
const contextPath = '/____ds_script____/'
|
||||
const monkey = require('../../monkey')
|
||||
const CryptoJs = require('crypto-js')
|
||||
function getScript (key, script) {
|
||||
const scriptUrl = contextPath + key
|
||||
|
||||
const hash = CryptoJs.SHA256(script).toString(CryptoJs.enc.Base64)
|
||||
return `
|
||||
<script crossorigin="anonymous" defer="defer" type="application/javascript"
|
||||
integrity="sha256-${hash}"
|
||||
src="${scriptUrl}"></script>
|
||||
`
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
responseIntercept (context, interceptOpt, req, res, proxyReq, proxyRes, ssl, next) {
|
||||
const { rOptions, log, setting } = context
|
||||
let keys = interceptOpt.script
|
||||
if (typeof keys === 'string') {
|
||||
keys = [keys]
|
||||
}
|
||||
try {
|
||||
let tags = getScript('global', monkey.get(setting.script.defaultDir).global.script)
|
||||
for (const key of keys) {
|
||||
const script = monkey.get(setting.script.defaultDir)[key]
|
||||
if (script == null) {
|
||||
continue
|
||||
}
|
||||
const scriptTag = getScript(key, script.script)
|
||||
tags += '\r\n' + scriptTag
|
||||
}
|
||||
log.info('responseIntercept: insert script', rOptions.hostname, rOptions.path)
|
||||
return {
|
||||
head: tags
|
||||
}
|
||||
} catch (err) {
|
||||
log.error('load monkey script error', err)
|
||||
}
|
||||
},
|
||||
is (interceptOpt) {
|
||||
return interceptOpt.script
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
module.exports = {
|
||||
requestIntercept (context, interceptOpts, req, res, ssl, next) {
|
||||
const { rOptions, log } = context
|
||||
log.info('success:', rOptions.hostname, req.url)
|
||||
res.writeHead(200)
|
||||
res.write('DevSidecar 200: \n\n request success, this request is matched by success intercept.\n\n 因配置success拦截器,本请求将直接返回成功')
|
||||
res.end()
|
||||
return true// 是否结束
|
||||
},
|
||||
is (interceptOpt) {
|
||||
return !!interceptOpt.success
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
const proxy = require('./impl/proxy')
|
||||
const redirect = require('./impl/redirect')
|
||||
const abort = require('./impl/abort')
|
||||
|
||||
const modules = [proxy, redirect, abort]
|
||||
const success = require('./impl/success')
|
||||
const script = require('./impl/script')
|
||||
const modules = [proxy, redirect, abort, script, success]
|
||||
|
||||
module.exports = modules
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const log = require('../../utils/util.log')
|
||||
let scripts
|
||||
|
||||
function buildScript (sc, content) {
|
||||
const grant = sc.grant
|
||||
const pre = 'window.addEventListener("load",' +
|
||||
' ()=> { \r\n'
|
||||
let grantSc = ''
|
||||
for (const item of grant) {
|
||||
grantSc += 'const ' + item + ' = window.__ds_global__[\'' + item + '\']\r\n'
|
||||
}
|
||||
const tail = ';' + content + '\r\n' +
|
||||
'})'
|
||||
return pre + grantSc + tail
|
||||
}
|
||||
|
||||
function loadScript (content) {
|
||||
// @grant GM_registerMenuCommand
|
||||
// @grant GM_unregisterMenuCommand
|
||||
// @grant GM_openInTab
|
||||
// @grant GM_getValue
|
||||
// @grant GM_setValue
|
||||
// @grant GM_notification
|
||||
const annoFlag = '// ==/UserScript=='
|
||||
const arr = content.split(annoFlag)
|
||||
const start = 0
|
||||
|
||||
const confStr = arr[start]
|
||||
const confItemArr = confStr.split('\n')
|
||||
const sc = {
|
||||
grant: [],
|
||||
match: [],
|
||||
content: ''
|
||||
}
|
||||
for (const string of confItemArr) {
|
||||
const reg = new RegExp('.*@([^\\s]+)\\s(.+)')
|
||||
const ret = string.match(reg)
|
||||
if (ret) {
|
||||
const key = ret[1].trim()
|
||||
const value = ret[2].trim()
|
||||
if (key === 'grant') {
|
||||
sc.grant.push(value)
|
||||
} else if (key === 'match') {
|
||||
sc.match.push(value)
|
||||
} else {
|
||||
sc[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
const script = arr[start + 1].trim()
|
||||
|
||||
sc.script = buildScript(sc, script)
|
||||
return sc
|
||||
}
|
||||
|
||||
function readFile (rootDir, script) {
|
||||
const location = path.join(rootDir, './' + script)
|
||||
log.debug('script location:', location)
|
||||
return fs.readFileSync(location).toString()
|
||||
}
|
||||
|
||||
const api = {
|
||||
get (rootDir) {
|
||||
if (scripts == null) {
|
||||
api.load(rootDir)
|
||||
}
|
||||
return scripts
|
||||
},
|
||||
load (rootDir) {
|
||||
scripts = {}
|
||||
scripts.github = loadScript(readFile(rootDir, 'github.script'))
|
||||
scripts.jquery = { script: readFile(rootDir, 'jquery.min.js') }
|
||||
scripts.global = { script: readFile(rootDir, 'global.script') }
|
||||
return scripts
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = api
|
|
@ -1,32 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
require('babel-polyfill')
|
||||
const mitmproxy = require('../mitmproxy')
|
||||
const program = require('commander')
|
||||
const packageJson = require('../../package.json')
|
||||
// const tlsUtils = require('../tls/tlsUtils')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const colors = require('colors')
|
||||
|
||||
fs.existsSync = fs.existsSync || path.existsSync
|
||||
|
||||
program
|
||||
.version(packageJson.version)
|
||||
.option('-c, --config [value]', 'config file path')
|
||||
.parse(process.argv)
|
||||
|
||||
console.log(program.config)
|
||||
|
||||
const configPath = path.resolve(program.config)
|
||||
|
||||
if (fs.existsSync(configPath)) {
|
||||
const configObject = require(configPath)
|
||||
|
||||
if (typeof configObject !== 'object') {
|
||||
console.error(colors.red(`Config Error in ${configPath}`))
|
||||
} else {
|
||||
mitmproxy.createProxy(configObject)
|
||||
}
|
||||
} else {
|
||||
console.error(colors.red(`Can not find \`config file\` file: ${configPath}`))
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
const path = require('path')
|
||||
|
||||
const config = exports
|
||||
|
||||
config.caCertFileName = 'dev-sidecar.ca.crt'
|
||||
|
@ -8,10 +7,18 @@ config.caKeyFileName = 'dev-sidecar.ca.key.pem'
|
|||
|
||||
config.defaultPort = 1181
|
||||
|
||||
config.caName = 'DevSidecar CA'
|
||||
config.caName = 'This certificate is generated locally'
|
||||
|
||||
config.caBasePath = buildDefaultCABasePath()
|
||||
|
||||
config.getDefaultCABasePath = function () {
|
||||
const userHome = process.env.HOME || process.env.USERPROFILE
|
||||
return config.caBasePath
|
||||
}
|
||||
config.setDefaultCABasePath = function (path) {
|
||||
config.caBasePath = path
|
||||
}
|
||||
function buildDefaultCABasePath () {
|
||||
const userHome = process.env.USERPROFILE
|
||||
return path.resolve(userHome, './.dev-sidecar')
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ const url = require('url')
|
|||
const Agent = require('./ProxyHttpAgent')
|
||||
const HttpsAgent = require('./ProxyHttpsAgent')
|
||||
const tunnelAgent = require('tunnel-agent')
|
||||
|
||||
const log = require('../../../utils/util.log')
|
||||
const util = exports
|
||||
const httpsAgent = new HttpsAgent({
|
||||
keepAlive: true,
|
||||
|
@ -34,7 +34,7 @@ util.getOptionsFormRequest = (req, ssl, externalProxy = null) => {
|
|||
try {
|
||||
externalProxyUrl = externalProxy(req, ssl)
|
||||
} catch (e) {
|
||||
console.error('externalProxy', e)
|
||||
log.error('externalProxy', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
const through = require('through2')
|
||||
const zlib = require('zlib')
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const url = require('url')
|
||||
|
||||
const httpUtil = {}
|
||||
httpUtil.isGzip = function (res) {
|
||||
const contentEncoding = res.headers['content-encoding']
|
||||
return !!(contentEncoding && contentEncoding.toLowerCase() === 'gzip')
|
||||
}
|
||||
httpUtil.isHtml = function (res) {
|
||||
const contentType = res.headers['content-type']
|
||||
return (typeof contentType !== 'undefined') && /text\/html|application\/xhtml\+xml/.test(contentType)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function injectContentIntoHtmlHead (html, content) {
|
||||
html = html.replace(/(<\/head>)/i, function (match) {
|
||||
return content + match
|
||||
})
|
||||
return html
|
||||
}
|
||||
function injectScriptIntoHtmlHead (html, content) {
|
||||
return html
|
||||
}
|
||||
function injectContentIntoHtmlBody (html, content) {
|
||||
html = html.replace(/(<\/body>)/i, function (match) {
|
||||
return content + match
|
||||
})
|
||||
return html
|
||||
}
|
||||
|
||||
function chunkReplace (_this, chunk, enc, callback, headContent, bodyContent) {
|
||||
let chunkString = chunk.toString()
|
||||
if (headContent) {
|
||||
chunkString = injectScriptIntoHtmlHead(chunkString, headContent)
|
||||
}
|
||||
if (bodyContent) {
|
||||
chunkString = injectContentIntoHtmlBody(chunkString, bodyContent)
|
||||
}
|
||||
_this.push(Buffer.alloc(chunkString))
|
||||
callback()
|
||||
}
|
||||
|
||||
module.exports = class InjectHtmlPlugin {
|
||||
constructor ({
|
||||
head,
|
||||
body
|
||||
}) {
|
||||
this.head = head
|
||||
this.body = body
|
||||
}
|
||||
|
||||
responseInterceptor (req, res, proxyReq, proxyRes, ssl, next) {
|
||||
if (!this.head && !this.body) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
const isHtml = httpUtil.isHtml(proxyRes)
|
||||
const contentLengthIsZero = (() => {
|
||||
return proxyRes.headers['content-length'] === 0
|
||||
})()
|
||||
if (!isHtml || contentLengthIsZero) {
|
||||
next()
|
||||
} else {
|
||||
Object.keys(proxyRes.headers).forEach(function (key) {
|
||||
if (proxyRes.headers[key] !== undefined) {
|
||||
let newkey = key.replace(/^[a-z]|-[a-z]/g, (match) => {
|
||||
return match.toUpperCase()
|
||||
})
|
||||
newkey = key
|
||||
if (isHtml && key === 'content-length') {
|
||||
// do nothing
|
||||
} else {
|
||||
res.setHeader(newkey, proxyRes.headers[key])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
res.writeHead(proxyRes.statusCode)
|
||||
|
||||
const isGzip = httpUtil.isGzip(proxyRes)
|
||||
|
||||
if (isGzip) {
|
||||
proxyRes.pipe(new zlib.Gunzip())
|
||||
.pipe(through(function (chunk, enc, callback) {
|
||||
chunkReplace(this, chunk, enc, callback, this.head, this.body)
|
||||
})).pipe(new zlib.Gzip()).pipe(res)
|
||||
} else {
|
||||
proxyRes.pipe(through(function (chunk, enc, callback) {
|
||||
chunkReplace(this, chunk, enc, callback, this.head, this.body)
|
||||
})).pipe(res)
|
||||
}
|
||||
}
|
||||
next()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
const through = require('through2')
|
||||
const zlib = require('zlib')
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const url = require('url')
|
||||
|
||||
var httpUtil = {}
|
||||
httpUtil.getCharset = function (res) {
|
||||
const contentType = res.getHeader('content-type')
|
||||
const reg = /charset=(.*)/
|
||||
const matched = contentType.match(reg)
|
||||
if (matched) {
|
||||
return matched[1]
|
||||
}
|
||||
return 'utf-8'
|
||||
}
|
||||
httpUtil.isGzip = function (res) {
|
||||
var contentEncoding = res.headers['content-encoding']
|
||||
return !!(contentEncoding && contentEncoding.toLowerCase() === 'gzip')
|
||||
}
|
||||
httpUtil.isHtml = function (res) {
|
||||
var contentType = res.headers['content-type']
|
||||
return (typeof contentType !== 'undefined') && /text\/html|application\/xhtml\+xml/.test(contentType)
|
||||
}
|
||||
const HEAD = Buffer.from('</head>')
|
||||
const HEAD_UP = Buffer.from('</HEAD>')
|
||||
const BODY = Buffer.from('</body>')
|
||||
const BODY_UP = Buffer.from('</BODY>')
|
||||
|
||||
function chunkByteReplace (_this, chunk, enc, callback, append) {
|
||||
if (append && append.head) {
|
||||
const ret = injectScriptIntoHtml([HEAD, HEAD_UP], chunk, append.head)
|
||||
if (ret != null) {
|
||||
chunk = ret
|
||||
}
|
||||
}
|
||||
if (append && append.body) {
|
||||
const ret = injectScriptIntoHtml([BODY, BODY_UP], chunk, append.body)
|
||||
if (ret != null) {
|
||||
chunk = ret
|
||||
}
|
||||
}
|
||||
_this.push(chunk)
|
||||
callback()
|
||||
}
|
||||
function injectScriptIntoHtml (tags, chunk, script) {
|
||||
for (const tag of tags) {
|
||||
const index = chunk.indexOf(tag)
|
||||
if (index < 0) {
|
||||
continue
|
||||
}
|
||||
const scriptBuf = Buffer.from(script)
|
||||
const chunkNew = Buffer.alloc(chunk.length + scriptBuf.length)
|
||||
chunk.copy(chunkNew, 0, 0, index)
|
||||
scriptBuf.copy(chunkNew, index, 0)
|
||||
chunk.copy(chunkNew, index + scriptBuf.length, index)
|
||||
return chunkNew
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const contextPath = '/____ds_script____/'
|
||||
const monkey = require('../../monkey')
|
||||
module.exports = {
|
||||
|
||||
requestIntercept (context, req, res, ssl, next) {
|
||||
const { rOptions, log, setting } = context
|
||||
if (rOptions.path.indexOf(contextPath) !== 0) {
|
||||
return
|
||||
}
|
||||
const urlPath = rOptions.path
|
||||
const filename = urlPath.replace(contextPath, '')
|
||||
|
||||
const script = monkey.get(setting.script.defaultDir)[filename]
|
||||
|
||||
log.info('ds_script', filename, script != null)
|
||||
res.writeHead(200)
|
||||
res.write(script.script)
|
||||
res.end()
|
||||
return true
|
||||
},
|
||||
responseInterceptor (req, res, proxyReq, proxyRes, ssl, next, append) {
|
||||
if (!append.head && !append.body) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
const isHtml = httpUtil.isHtml(proxyRes)
|
||||
const contentLengthIsZero = (() => {
|
||||
return proxyRes.headers['content-length'] === 0
|
||||
})()
|
||||
if (!isHtml || contentLengthIsZero) {
|
||||
next()
|
||||
return
|
||||
} else {
|
||||
Object.keys(proxyRes.headers).forEach(function (key) {
|
||||
if (proxyRes.headers[key] !== undefined) {
|
||||
// let newkey = key.replace(/^[a-z]|-[a-z]/g, (match) => {
|
||||
// return match.toUpperCase()
|
||||
// })
|
||||
const newkey = key
|
||||
if (isHtml && key === 'content-length') {
|
||||
// do nothing
|
||||
return
|
||||
}
|
||||
if (isHtml && key === 'content-security-policy') {
|
||||
// content-security-policy
|
||||
let policy = proxyRes.headers[key]
|
||||
const reg = /script-src ([^:]*);/i
|
||||
const matched = policy.match(reg)
|
||||
if (matched) {
|
||||
if (matched[1].indexOf('self') < 0) {
|
||||
policy = policy.replace('script-src', 'script-src \'self\' ')
|
||||
}
|
||||
}
|
||||
res.setHeader(newkey, policy)
|
||||
return
|
||||
}
|
||||
|
||||
res.setHeader(newkey, proxyRes.headers[key])
|
||||
}
|
||||
})
|
||||
|
||||
res.writeHead(proxyRes.statusCode)
|
||||
|
||||
const isGzip = httpUtil.isGzip(proxyRes)
|
||||
|
||||
if (isGzip) {
|
||||
proxyRes.pipe(new zlib.Gunzip())
|
||||
.pipe(through(function (chunk, enc, callback) {
|
||||
chunkByteReplace(this, chunk, enc, callback, append)
|
||||
})).pipe(new zlib.Gzip()).pipe(res)
|
||||
} else {
|
||||
proxyRes.pipe(through(function (chunk, enc, callback) {
|
||||
chunkByteReplace(this, chunk, enc, callback, append)
|
||||
})).pipe(res)
|
||||
}
|
||||
}
|
||||
next()
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
const net = require('net')
|
||||
const url = require('url')
|
||||
const log = require('../../../utils/util.log')
|
||||
// const colors = require('colors')
|
||||
const DnsUtil = require('../../dns/index')
|
||||
const localIP = '127.0.0.1'
|
||||
|
@ -15,7 +16,7 @@ module.exports = function createConnectHandler (sslConnectInterceptor, fakeServe
|
|||
fakeServerCenter.getServerPromise(hostname, srvUrl.port).then((serverObj) => {
|
||||
connect(req, cltSocket, head, localIP, serverObj.port)
|
||||
}, (e) => {
|
||||
console.error('getServerPromise', e)
|
||||
log.error('getServerPromise', e)
|
||||
})
|
||||
} else {
|
||||
connect(req, cltSocket, head, hostname, srvUrl.port, dnsConfig)
|
||||
|
@ -25,7 +26,7 @@ module.exports = function createConnectHandler (sslConnectInterceptor, fakeServe
|
|||
|
||||
function connect (req, cltSocket, head, hostname, port, dnsConfig) {
|
||||
// tunneling https
|
||||
// console.log('connect:', hostname, port)
|
||||
// log.info('connect:', hostname, port)
|
||||
const start = new Date().getTime()
|
||||
let isDnsIntercept = null
|
||||
try {
|
||||
|
@ -60,23 +61,26 @@ function connect (req, cltSocket, head, hostname, port, dnsConfig) {
|
|||
cltSocket.pipe(proxySocket)
|
||||
})
|
||||
|
||||
cltSocket.on('error', (e) => {
|
||||
log.error('cltSocket error', e.message)
|
||||
})
|
||||
proxySocket.on('timeout', () => {
|
||||
const end = new Date().getTime()
|
||||
console.log('代理socket timeout:', hostname, port, (end - start) + 'ms')
|
||||
log.info('代理socket timeout:', hostname, port, (end - start) + 'ms')
|
||||
})
|
||||
proxySocket.on('error', (e) => {
|
||||
// 连接失败,可能被GFW拦截,或者服务端拥挤
|
||||
const end = new Date().getTime()
|
||||
console.error('代理连接失败:', e.message, hostname, port, (end - start) + 'ms')
|
||||
log.error('代理连接失败:', e.message, hostname, port, (end - start) + 'ms')
|
||||
cltSocket.destroy()
|
||||
if (isDnsIntercept) {
|
||||
const { dns, ip, hostname } = isDnsIntercept
|
||||
dns.count(hostname, ip, true)
|
||||
console.error('记录ip失败次数,用于优选ip:', hostname, ip)
|
||||
log.error('记录ip失败次数,用于优选ip:', hostname, ip)
|
||||
}
|
||||
})
|
||||
return proxySocket
|
||||
} catch (error) {
|
||||
console.log('connect err', error)
|
||||
log.error('connect err', error)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ const fs = require('fs')
|
|||
const forge = require('node-forge')
|
||||
const FakeServersCenter = require('../tls/FakeServersCenter')
|
||||
const colors = require('colors')
|
||||
|
||||
const log = require('../../../utils/util.log')
|
||||
module.exports = function createFakeServerCenter ({
|
||||
caCertPath,
|
||||
caKeyPath,
|
||||
|
@ -20,7 +20,7 @@ module.exports = function createFakeServerCenter ({
|
|||
caCert = forge.pki.certificateFromPem(caCertPem)
|
||||
caKey = forge.pki.privateKeyFromPem(caKeyPem)
|
||||
} catch (e) {
|
||||
console.log(colors.red('Can not find `CA certificate` or `CA key`.'), e)
|
||||
log.info(colors.red('Can not find `CA certificate` or `CA key`.'), e)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,13 @@ const https = require('https')
|
|||
const commonUtil = require('../common/util')
|
||||
// const upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i
|
||||
const DnsUtil = require('../../dns/index')
|
||||
|
||||
module.exports = function createRequestHandler (requestInterceptor, responseInterceptor, middlewares, externalProxy, dnsConfig) {
|
||||
const log = require('../../../utils/util.log')
|
||||
const RequestCounter = require('../../choice/RequestCounter')
|
||||
const InsertScriptMiddleware = require('../middleware/InsertScriptMiddleware')
|
||||
const defaultDns = require('dns')
|
||||
const MAX_SLOW_TIME = 8000 // 超过此时间 则认为太慢了
|
||||
// create requestHandler function
|
||||
module.exports = function createRequestHandler (createIntercepts, externalProxy, dnsConfig, setting) {
|
||||
// return
|
||||
return function requestHandler (req, res, ssl) {
|
||||
let proxyReq
|
||||
|
@ -17,7 +22,18 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
} else {
|
||||
req.socket.setKeepAlive(true, 30000)
|
||||
}
|
||||
const context = {}
|
||||
const context = {
|
||||
rOptions,
|
||||
log,
|
||||
RequestCounter,
|
||||
setting
|
||||
}
|
||||
let interceptors = createIntercepts(context)
|
||||
if (interceptors == null) {
|
||||
interceptors = []
|
||||
}
|
||||
const reqIncpts = interceptors.filter(item => { return item.requestIntercept != null })
|
||||
const resIncpts = interceptors.filter(item => { return item.responseIntercept != null })
|
||||
|
||||
const requestInterceptorPromise = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -25,10 +41,20 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
resolve()
|
||||
}
|
||||
try {
|
||||
if (typeof requestInterceptor === 'function') {
|
||||
requestInterceptor(rOptions, req, res, ssl, next, context)
|
||||
if (setting.script.enabled) {
|
||||
reqIncpts.unshift(InsertScriptMiddleware)
|
||||
}
|
||||
if (reqIncpts && reqIncpts.length > 0) {
|
||||
for (const reqIncpt of reqIncpts) {
|
||||
const goNext = reqIncpt.requestIntercept(context, req, res, ssl, next)
|
||||
if (goNext) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
}
|
||||
next()
|
||||
} else {
|
||||
resolve()
|
||||
next()
|
||||
}
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
|
@ -36,17 +62,21 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
})
|
||||
}
|
||||
|
||||
function countSlow (isDnsIntercept, type) {
|
||||
if (isDnsIntercept) {
|
||||
const { dns, ip, hostname } = isDnsIntercept
|
||||
dns.count(hostname, ip, true)
|
||||
log.error('记录ip失败次数,用于优选ip:', hostname, ip, type)
|
||||
}
|
||||
const counter = context.requestCount
|
||||
if (counter != null) {
|
||||
counter.count.doCount(counter.value, true)
|
||||
log.error('记录proxy失败次数:', counter.value, type)
|
||||
}
|
||||
}
|
||||
|
||||
const proxyRequestPromise = async () => {
|
||||
rOptions.host = rOptions.hostname || rOptions.host || 'localhost'
|
||||
// if (dnsConfig) {
|
||||
// const dns = DnsUtil.hasDnsLookup(dnsConfig, rOptions.host)
|
||||
// if (dns) {
|
||||
// const ip = await dns.lookup(rOptions.host)
|
||||
// console.log('使用自定义dns:', rOptions.host, ip, dns.dnsServer)
|
||||
// rOptions.host = ip
|
||||
// }
|
||||
// }
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// use the binded socket for NTLM
|
||||
if (rOptions.agent && rOptions.customSocketId != null && rOptions.agent.getName) {
|
||||
|
@ -62,7 +92,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
function onFree () {
|
||||
const url = `${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`
|
||||
const start = new Date().getTime()
|
||||
console.log('代理请求:', url, rOptions.method)
|
||||
log.info('代理请求:', url, rOptions.method)
|
||||
let isDnsIntercept
|
||||
if (dnsConfig) {
|
||||
const dns = DnsUtil.hasDnsLookup(dnsConfig, rOptions.hostname)
|
||||
|
@ -73,7 +103,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
if (ip !== hostname) {
|
||||
callback(null, ip, 4)
|
||||
} else {
|
||||
rOptions.lookup(hostname, options, callback)
|
||||
defaultDns.lookup(hostname, options, callback)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -82,50 +112,65 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
|
||||
proxyReq = (rOptions.protocol === 'https:' ? https : http).request(rOptions, (proxyRes) => {
|
||||
const end = new Date().getTime()
|
||||
const cost = end - start
|
||||
if (rOptions.protocol === 'https:') {
|
||||
console.log('代理请求返回:', url, (end - start) + 'ms')
|
||||
log.info('代理请求返回:', url, cost + 'ms')
|
||||
}
|
||||
if (cost > MAX_SLOW_TIME) {
|
||||
countSlow(isDnsIntercept, 'to slow ' + cost + 'ms')
|
||||
}
|
||||
resolve(proxyRes)
|
||||
})
|
||||
|
||||
proxyReq.on('timeout', () => {
|
||||
const end = new Date().getTime()
|
||||
if (isDnsIntercept) {
|
||||
const { dns, ip, hostname } = isDnsIntercept
|
||||
dns.count(hostname, ip, true)
|
||||
console.error('记录ip失败次数,用于优选ip:', hostname, ip)
|
||||
}
|
||||
console.error('代理请求超时', rOptions.protocol, rOptions.hostname, rOptions.path, (end - start) + 'ms')
|
||||
reject(new Error(`${rOptions.host}:${rOptions.port}, 代理请求超时`))
|
||||
const cost = end - start
|
||||
log.error('代理请求超时', rOptions.protocol, rOptions.hostname, rOptions.path, cost + 'ms')
|
||||
countSlow(isDnsIntercept, 'to slow ' + cost + 'ms')
|
||||
proxyReq.end()
|
||||
proxyReq.destroy()
|
||||
const error = new Error(`${rOptions.host}:${rOptions.port}, 代理请求超时`)
|
||||
error.status = 408
|
||||
reject(error)
|
||||
})
|
||||
|
||||
proxyReq.on('error', (e) => {
|
||||
const end = new Date().getTime()
|
||||
if (isDnsIntercept) {
|
||||
const { dns, ip, hostname } = isDnsIntercept
|
||||
dns.count(hostname, ip, true)
|
||||
console.error('记录ip失败次数,用于优选ip:', hostname, ip)
|
||||
}
|
||||
console.error('代理请求错误', e.errno, rOptions.hostname, rOptions.path, (end - start) + 'ms', e)
|
||||
const cost = end - start
|
||||
log.error('代理请求错误', e.code, e.message, rOptions.hostname, rOptions.path, cost + 'ms')
|
||||
countSlow(isDnsIntercept, 'error:' + e.message)
|
||||
reject(e)
|
||||
})
|
||||
|
||||
proxyReq.on('aborted', () => {
|
||||
console.error('代理请求被取消', rOptions.hostname, rOptions.path)
|
||||
const end = new Date().getTime()
|
||||
const cost = end - start
|
||||
log.error('代理请求被取消', rOptions.hostname, rOptions.path, cost + 'ms')
|
||||
|
||||
if (cost > MAX_SLOW_TIME) {
|
||||
countSlow(isDnsIntercept, 'to slow ' + cost + 'ms')
|
||||
}
|
||||
|
||||
if (res.writableEnded) {
|
||||
return
|
||||
}
|
||||
reject(new Error('代理请求被取消'))
|
||||
})
|
||||
|
||||
req.on('aborted', function () {
|
||||
console.error('请求被取消', rOptions.hostname, rOptions.path)
|
||||
log.error('请求被取消', rOptions.hostname, rOptions.path)
|
||||
proxyReq.abort()
|
||||
if (res.writableEnded) {
|
||||
return
|
||||
}
|
||||
reject(new Error('请求被取消'))
|
||||
})
|
||||
req.on('error', function (e, req, res) {
|
||||
console.error('请求错误:', e.errno, rOptions.hostname, rOptions.path)
|
||||
log.error('请求错误:', e.errno, rOptions.hostname, rOptions.path)
|
||||
reject(e)
|
||||
})
|
||||
req.on('timeout', () => {
|
||||
console.error('请求超时', rOptions.hostname, rOptions.path)
|
||||
log.error('请求超时', rOptions.hostname, rOptions.path)
|
||||
reject(new Error(`${rOptions.hostname}:${rOptions.port}, 请求超时`))
|
||||
})
|
||||
req.pipe(proxyReq)
|
||||
|
@ -137,21 +182,45 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
(async () => {
|
||||
await requestInterceptorPromise()
|
||||
|
||||
if (res.finished) {
|
||||
if (res.writableEnded) {
|
||||
return false
|
||||
}
|
||||
|
||||
const proxyRes = await proxyRequestPromise()
|
||||
|
||||
// proxyRes.on('data', (chunk) => {
|
||||
// // console.log('BODY: ')
|
||||
// })
|
||||
proxyRes.on('error', (error) => {
|
||||
countSlow(null, 'error:' + error.message)
|
||||
log.error('proxy res error', error)
|
||||
})
|
||||
|
||||
const responseInterceptorPromise = new Promise((resolve, reject) => {
|
||||
const next = () => {
|
||||
resolve()
|
||||
}
|
||||
if (!setting.script.enabled) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
try {
|
||||
if (typeof responseInterceptor === 'function') {
|
||||
responseInterceptor(req, res, proxyReq, proxyRes, ssl, next, context)
|
||||
if (resIncpts && resIncpts.length > 0) {
|
||||
let head = ''
|
||||
let body = ''
|
||||
for (const resIncpt of resIncpts) {
|
||||
const append = resIncpt.responseIntercept(context, req, res, proxyReq, proxyRes, ssl)
|
||||
if (append && append.head) {
|
||||
head += append.head
|
||||
}
|
||||
if (append && append.body) {
|
||||
body += append.body
|
||||
}
|
||||
}
|
||||
|
||||
InsertScriptMiddleware.responseInterceptor(req, res, proxyReq, proxyRes, ssl, next, { head, body })
|
||||
} else {
|
||||
resolve()
|
||||
next()
|
||||
}
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
|
@ -160,10 +229,6 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
|
||||
await responseInterceptorPromise
|
||||
|
||||
if (res.finished) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (!res.headersSent) { // prevent duplicate set headers
|
||||
Object.keys(proxyRes.headers).forEach(function (key) {
|
||||
if (proxyRes.headers[key] !== undefined) {
|
||||
|
@ -178,21 +243,20 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
}
|
||||
})
|
||||
|
||||
if (proxyRes.statusCode >= 400) {
|
||||
countSlow(null, 'status return :' + proxyRes.statusCode)
|
||||
}
|
||||
res.writeHead(proxyRes.statusCode)
|
||||
proxyRes.pipe(res)
|
||||
}
|
||||
})().then(
|
||||
(flag) => {
|
||||
// do nothing
|
||||
},
|
||||
(e) => {
|
||||
if (!res.finished) {
|
||||
res.writeHead(500)
|
||||
res.write(`DevSidecar Warning:\n\n ${e.toString()}`)
|
||||
res.end()
|
||||
}
|
||||
console.error('request error', e.message)
|
||||
})().catch(e => {
|
||||
if (!res.writableEnded) {
|
||||
const status = e.status || 500
|
||||
res.writeHead(status)
|
||||
res.write(`DevSidecar Warning:\n\n ${e.toString()}`)
|
||||
res.end()
|
||||
log.error('request error', e.message)
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const http = require('http')
|
||||
const https = require('https')
|
||||
const util = require('../common/util')
|
||||
|
||||
const log = require('../../../utils/util.log')
|
||||
// copy from node-http-proxy. ^_^
|
||||
|
||||
// create connectHandler function
|
||||
|
@ -11,7 +11,7 @@ module.exports = function createUpgradeHandler () {
|
|||
const clientOptions = util.getOptionsFormRequest(req, ssl)
|
||||
const proxyReq = (ssl ? https : http).request(clientOptions)
|
||||
proxyReq.on('error', (e) => {
|
||||
console.error(e)
|
||||
log.error('upgradeHandler', e)
|
||||
})
|
||||
proxyReq.on('response', function (res) {
|
||||
// if upgrade event isn't going to happen, close the socket
|
||||
|
@ -20,12 +20,11 @@ module.exports = function createUpgradeHandler () {
|
|||
|
||||
proxyReq.on('upgrade', function (proxyRes, proxySocket, proxyHead) {
|
||||
proxySocket.on('error', (e) => {
|
||||
console.log('error-----1111')
|
||||
console.error(e)
|
||||
log.error('on upgrade:', e)
|
||||
})
|
||||
|
||||
cltSocket.on('error', function () {
|
||||
console.log('error-----2222')
|
||||
cltSocket.on('error', function (e) {
|
||||
log.error('upgrade socket ', e)
|
||||
proxySocket.end()
|
||||
})
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const tlsUtils = require('../tls/tlsUtils')
|
||||
const http = require('http')
|
||||
const config = require('../common/config')
|
||||
const colors = require('colors')
|
||||
const log = require('../../../utils/util.log')
|
||||
const createRequestHandler = require('./createRequestHandler')
|
||||
const createConnectHandler = require('./createConnectHandler')
|
||||
const createFakeServerCenter = require('./createFakeServerCenter')
|
||||
|
@ -12,33 +12,35 @@ module.exports = {
|
|||
caCertPath,
|
||||
caKeyPath,
|
||||
sslConnectInterceptor,
|
||||
requestInterceptor,
|
||||
responseInterceptor,
|
||||
createIntercepts,
|
||||
getCertSocketTimeout = 1 * 1000,
|
||||
middlewares = [],
|
||||
externalProxy,
|
||||
dnsConfig
|
||||
dnsConfig,
|
||||
setting
|
||||
}, callback) {
|
||||
// Don't reject unauthorized
|
||||
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
||||
|
||||
if (!caCertPath && !caKeyPath) {
|
||||
const rs = this.createCA()
|
||||
caCertPath = rs.caCertPath
|
||||
caKeyPath = rs.caKeyPath
|
||||
if (rs.create) {
|
||||
console.log(colors.cyan(`CA Cert saved in: ${caCertPath}`))
|
||||
console.log(colors.cyan(`CA private key saved in: ${caKeyPath}`))
|
||||
}
|
||||
log.info(`CA Cert read in: ${caCertPath}`)
|
||||
log.info(`CA private key read in: ${caKeyPath}`)
|
||||
if (!caCertPath) {
|
||||
caCertPath = config.getDefaultCACertPath()
|
||||
}
|
||||
if (!caKeyPath) {
|
||||
caKeyPath = config.getDefaultCAKeyPath()
|
||||
}
|
||||
const rs = this.createCA({ caCertPath, caKeyPath })
|
||||
if (rs.create) {
|
||||
log.info(`CA Cert saved in: ${caCertPath}`)
|
||||
log.info(`CA private key saved in: ${caKeyPath}`)
|
||||
}
|
||||
|
||||
port = ~~port
|
||||
const requestHandler = createRequestHandler(
|
||||
requestInterceptor,
|
||||
responseInterceptor,
|
||||
middlewares,
|
||||
createIntercepts,
|
||||
externalProxy,
|
||||
dnsConfig
|
||||
dnsConfig,
|
||||
setting
|
||||
)
|
||||
|
||||
const upgradeHandler = createUpgradeHandler()
|
||||
|
@ -59,18 +61,18 @@ module.exports = {
|
|||
|
||||
const server = new http.Server()
|
||||
server.listen(port, () => {
|
||||
console.log(colors.green(`dev-sidecar启动端口: ${port}`))
|
||||
log.info(`dev-sidecar启动端口: ${port}`)
|
||||
server.on('error', (e) => {
|
||||
console.error(colors.red(e))
|
||||
log.error('server error', e)
|
||||
})
|
||||
server.on('request', (req, res) => {
|
||||
const ssl = false
|
||||
// console.log('request,', req.url, req.port, req.host)
|
||||
// log.info('request,', req.hostname)
|
||||
requestHandler(req, res, ssl)
|
||||
})
|
||||
// tunneling for https
|
||||
server.on('connect', (req, cltSocket, head) => {
|
||||
// console.log('connect,', req.url)
|
||||
// log.info('connect,', req.url)
|
||||
connectHandler(req, cltSocket, head)
|
||||
})
|
||||
// TODO: handler WebSocket
|
||||
|
@ -78,6 +80,10 @@ module.exports = {
|
|||
const ssl = false
|
||||
upgradeHandler(req, socket, head, ssl)
|
||||
})
|
||||
server.on('clientError', (err, socket) => {
|
||||
log.error('client error', err)
|
||||
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n')
|
||||
})
|
||||
|
||||
if (callback) {
|
||||
callback(server)
|
||||
|
@ -85,7 +91,7 @@ module.exports = {
|
|||
})
|
||||
return server
|
||||
},
|
||||
createCA (caBasePath = config.getDefaultCABasePath()) {
|
||||
return tlsUtils.initCA(caBasePath)
|
||||
createCA (caPaths) {
|
||||
return tlsUtils.initCA(caPaths)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
const _ = require('lodash')
|
||||
module.exports = (middlewares) => {
|
||||
if (middlewares) {
|
||||
if (Object.prototype.toString.call(middlewares) !== '[object Array]') {
|
||||
throw new TypeError('middlewares must be a array')
|
||||
}
|
||||
}
|
||||
//
|
||||
// const sslConnectInterceptors = []
|
||||
// const requestInterceptors = []
|
||||
// const responseInterceptors = []
|
||||
|
||||
_.each(middlewares, (m) => {
|
||||
if (m.buildIn === false || m.buildIn === 'false') {
|
||||
|
||||
} else {
|
||||
// m.name
|
||||
}
|
||||
})
|
||||
}
|
|
@ -5,7 +5,7 @@ const forge = require('node-forge')
|
|||
const pki = forge.pki
|
||||
// const colors = require('colors')
|
||||
const tls = require('tls')
|
||||
|
||||
const log = require('../../../utils/util.log')
|
||||
module.exports = class FakeServersCenter {
|
||||
constructor ({ maxLength = 256, requestHandler, upgradeHandler, caCert, caKey, getCertSocketTimeout }) {
|
||||
this.queue = []
|
||||
|
@ -23,13 +23,13 @@ module.exports = class FakeServersCenter {
|
|||
if (this.queue.length >= this.maxLength) {
|
||||
const delServerObj = this.queue.shift()
|
||||
try {
|
||||
console.log('超过最大服务数量,删除旧服务', delServerObj)
|
||||
log.info('超过最大服务数量,删除旧服务', delServerObj)
|
||||
delServerObj.serverObj.server.close()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
log.info(e)
|
||||
}
|
||||
}
|
||||
console.log('add server promise:', serverPromiseObj)
|
||||
log.info('add server promise:', serverPromiseObj)
|
||||
this.queue.push(serverPromiseObj)
|
||||
return serverPromiseObj
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ module.exports = class FakeServersCenter {
|
|||
SNICallback: (hostname, done) => {
|
||||
(async () => {
|
||||
const certObj = await this.certAndKeyContainer.getCertPromise(hostname, port)
|
||||
console.log('sni callback:', hostname)
|
||||
log.info('sni callback:', hostname)
|
||||
done(null, tls.createSecureContext({
|
||||
key: pki.privateKeyToPem(certObj.key),
|
||||
cert: pki.certificateToPem(certObj.cert)
|
||||
|
@ -88,7 +88,7 @@ module.exports = class FakeServersCenter {
|
|||
this.requestHandler(req, res, ssl)
|
||||
})
|
||||
fakeServer.on('error', (e) => {
|
||||
console.error(e)
|
||||
log.error(e)
|
||||
})
|
||||
fakeServer.on('listening', () => {
|
||||
const mappingHostNames = tlsUtils.getMappingHostNamesFormCert(certObj.cert)
|
||||
|
|
|
@ -9,6 +9,15 @@ const mkdirp = require('mkdirp')
|
|||
const utils = exports
|
||||
const pki = forge.pki
|
||||
|
||||
// const os = require('os')
|
||||
// let username = 'dev-sidecar'
|
||||
// try {
|
||||
// const user = os.userInfo()
|
||||
// username = user.username
|
||||
// } catch (e) {
|
||||
// console.log('get userinfo error', e)
|
||||
// }
|
||||
|
||||
utils.createCA = function (CN) {
|
||||
const keys = pki.rsa.generateKeyPair(2046)
|
||||
const cert = pki.createCertificate()
|
||||
|
@ -228,10 +237,7 @@ utils.getMappingHostNamesFormCert = function (cert) {
|
|||
}
|
||||
|
||||
// sync
|
||||
utils.initCA = function (basePath = config.getDefaultCABasePath()) {
|
||||
const caCertPath = path.resolve(basePath, config.caCertFileName)
|
||||
const caKeyPath = path.resolve(basePath, config.caKeyFileName)
|
||||
|
||||
utils.initCA = function ({ caCertPath, caKeyPath }) {
|
||||
try {
|
||||
fs.accessSync(caCertPath, fs.F_OK)
|
||||
fs.accessSync(caKeyPath, fs.F_OK)
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
const debug = require('debug')
|
||||
|
||||
module.exports = function getLogger (name) {
|
||||
return {
|
||||
debug: debug(`dev-sidecar:${name}:debug`),
|
||||
info: debug(`dev-sidecar:${name}:info`),
|
||||
error: debug(`dev-sidecar:${name}:error`)
|
||||
}
|
||||
}
|
||||
|
||||
debug.enable('dev-sidecar:*')
|
|
@ -1,6 +1,8 @@
|
|||
const interceptors = require('./lib/interceptor')
|
||||
const dnsUtil = require('./lib/dns')
|
||||
const lodash = require('lodash')
|
||||
const log = require('./utils/util.log')
|
||||
const path = require('path')
|
||||
function matchHostname (hostMap, hostname) {
|
||||
const value = hostMap[hostname]
|
||||
if (value) {
|
||||
|
@ -46,57 +48,66 @@ module.exports = (config) => {
|
|||
|
||||
const dnsMapping = config.dns.mapping
|
||||
const serverConfig = config
|
||||
|
||||
return {
|
||||
const setting = serverConfig.setting
|
||||
const options = {
|
||||
port: serverConfig.port,
|
||||
dnsConfig: {
|
||||
providers: dnsUtil.initDNS(serverConfig.dns.providers),
|
||||
mapping: dnsMapping
|
||||
},
|
||||
setting,
|
||||
sslConnectInterceptor: (req, cltSocket, head) => {
|
||||
const hostname = req.url.split(':')[0]
|
||||
const inWhiteList = matchHostname(whiteList, hostname) != null
|
||||
if (inWhiteList) {
|
||||
console.log('白名单域名,不拦截', hostname)
|
||||
log.info('白名单域名,不拦截', hostname)
|
||||
return false
|
||||
}
|
||||
return !!matchHostname(intercepts, hostname) // 配置了拦截的域名,将会被代理
|
||||
},
|
||||
requestInterceptor: (rOptions, req, res, ssl, next, context) => {
|
||||
createIntercepts: (context) => {
|
||||
const rOptions = context.rOptions
|
||||
const hostname = rOptions.hostname
|
||||
const interceptOpts = matchHostname(intercepts, hostname)
|
||||
if (!interceptOpts) { // 该域名没有配置拦截器,直接过
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
const matchIntercepts = []
|
||||
for (const regexp in interceptOpts) { // 遍历拦截配置
|
||||
const interceptOpt = interceptOpts[regexp]
|
||||
interceptOpt.key = regexp
|
||||
if (regexp !== true) {
|
||||
if (!isMatched(req.url, regexp)) {
|
||||
if (!isMatched(rOptions.path, regexp)) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
for (const interceptImpl of interceptors) {
|
||||
for (const impl of interceptors) {
|
||||
// 根据拦截配置挑选合适的拦截器来处理
|
||||
if (!interceptImpl.is(interceptOpt) && interceptImpl.requestInterceptor) {
|
||||
continue
|
||||
}
|
||||
try {
|
||||
const result = interceptImpl.requestInterceptor(interceptOpt, rOptions, req, res, ssl, context)
|
||||
if (result) { // 拦截成功,其他拦截器就不处理了
|
||||
return
|
||||
if (impl.is(interceptOpt)) {
|
||||
const interceptor = {}
|
||||
if (impl.requestIntercept) {
|
||||
// req拦截器
|
||||
interceptor.requestIntercept = (context, req, res, ssl, next) => {
|
||||
return impl.requestIntercept(context, interceptOpt, req, res, ssl, next)
|
||||
}
|
||||
} else if (impl.responseIntercept) {
|
||||
// res拦截器
|
||||
interceptor.responseIntercept = (context, req, res, proxyReq, proxyRes, ssl, next) => {
|
||||
return impl.responseIntercept(context, interceptOpt, req, res, proxyReq, proxyRes, ssl, next)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// 拦截失败
|
||||
console.error(err)
|
||||
matchIntercepts.push(interceptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
next()
|
||||
},
|
||||
responseInterceptor: (req, res, proxyReq, proxyRes, ssl, next, context) => {
|
||||
next()
|
||||
return matchIntercepts
|
||||
}
|
||||
}
|
||||
|
||||
if (setting.rootCaFile) {
|
||||
options.caCertPath = setting.rootCaFile.certPath
|
||||
options.caKeyPath = setting.rootCaFile.keyPath
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
const os = require('os')
|
||||
const log = require('util.log')
|
||||
const util = {
|
||||
getNodeVersion () {
|
||||
const version = process.version
|
||||
console.log(version)
|
||||
log.info(version)
|
||||
}
|
||||
}
|
||||
util.getNodeVersion()
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
const log4js = require('log4js')
|
||||
const proxyConfig = require('../lib/proxy/common/config')
|
||||
log4js.configure({
|
||||
appenders: { std: { type: 'stdout', level: 'debug' }, file: { type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename: proxyConfig.getDefaultCABasePath() + '/logs/server.log' } },
|
||||
categories: { default: { appenders: ['file', 'std'], level: 'info' } }
|
||||
})
|
||||
const logger = log4js.getLogger('server')
|
||||
module.exports = logger
|
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
fireError (e) {
|
||||
process.send({ type: 'error', event: e })
|
||||
},
|
||||
fireStatus (status) {
|
||||
process.send({ type: 'status', event: status })
|
||||
}
|
||||
}
|
|
@ -20,4 +20,13 @@ const dnsProviders = dns.initDNS({
|
|||
// dnsProviders.usa.lookup(hostname)
|
||||
|
||||
const hostname1 = 'api.github.com'
|
||||
dnsProviders.aliyun.lookup(hostname1)
|
||||
dnsProviders.usa.lookup(hostname1)
|
||||
|
||||
const hostname2 = 'hk.docmirror.cn'
|
||||
dnsProviders.usa.lookup(hostname2)
|
||||
const hostname3 = 'github.docmirror.cn'
|
||||
dnsProviders.usa.lookup(hostname3)
|
||||
const hostname4 = 'gh.docmirror.top'
|
||||
dnsProviders.usa.lookup(hostname4)
|
||||
const hostname5 = 'gh2.docmirror.top'
|
||||
dnsProviders.usa.lookup(hostname5)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
const monkey = require('../../../src/lib/monkey/index')
|
||||
const scripts = monkey.load()
|
||||
console.log(scripts[0])
|
|
@ -0,0 +1,17 @@
|
|||
const name = '/docmirror/dev-sidecar/raw/master/doc/index.png'
|
||||
// https://raw.fastgit.org/docmirror/dev-sidecar/master/doc/index.png
|
||||
const ret = name.replace(/^(.+)\/raw\/(.+)$/, 'raw.fastgit.org$1/$2')
|
||||
console.log(ret)
|
||||
|
||||
const reg = new RegExp('^/[^/]+/[^/]+$')
|
||||
console.log('/greper/d2-crud-plus/blob/master/.eslintignore'.match(reg))
|
||||
|
||||
const chunk = Buffer.from('<head></head>')
|
||||
const script = '<script>a</script>'
|
||||
const index = chunk.indexOf('</head>')
|
||||
const scriptBuf = Buffer.from(script)
|
||||
const chunkNew = Buffer.alloc(chunk.length + scriptBuf.length)
|
||||
chunk.copy(chunkNew, 0, 0, index)
|
||||
scriptBuf.copy(chunkNew, index, 0)
|
||||
chunk.copy(chunkNew, index + scriptBuf.length, index)
|
||||
console.log(chunkNew.toString())
|
|
@ -0,0 +1,4 @@
|
|||
const CryptoJs = require('crypto-js')
|
||||
const ret = CryptoJs.SHA256('111111111111')
|
||||
console.log(ret.toString(CryptoJs.enc.Base64))
|
||||
console.log(1 / 2)
|
|
@ -2159,6 +2159,11 @@ crypto-browserify@^3.11.0:
|
|||
randombytes "^2.0.0"
|
||||
randomfill "^1.0.3"
|
||||
|
||||
crypto-js@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.0.0.tgz#2904ab2677a9d042856a2ea2ef80de92e4a36dcc"
|
||||
integrity sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==
|
||||
|
||||
cyclist@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npm.taobao.org/cyclist/download/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
|
||||
|
|