Merge remote-tracking branch 'origin/master' into master

pull/67/head
xiaojunnuo@qq.com 2020-12-07 09:07:46 +08:00
commit e1ac12aa31
71 changed files with 22213 additions and 429 deletions

View File

@ -39,8 +39,8 @@
* 官方与淘宝npm registry一键切换,
* 某些npm install的时候并且使用cnpm也无法安装时可以尝试开启npm代理再试
### 6、 更多加速配置
等你来提issue
### 6、 增强功能
* 等你来探索
## 快速开始
目前仅支持windows
@ -50,7 +50,7 @@
#### 1 下载安装包
下载安装包:
[阿里云](https://dev-sidecar.docmirror.cn/update/DevSidecar-1.2.1.exe)
[阿里云](https://dev-sidecar.docmirror.cn/update/DevSidecar-1.3.1.exe)
[Gitee Release](https://gitee.com/docmirror/dev-sidecar/releases)
[Github Release](https://github.com/docmirror/dev-sidecar/releases)
@ -160,18 +160,19 @@ const intercepts = {
## 问题排查
如果没有加速效果,请根据以下步骤进行排查
#### 1、请确认windows的代理设置处于勾选状态
#### 1. 请确认windows的代理设置处于勾选状态
如何打开查看windows代理设置
* win10: 开始->设置->网络和Internet->最下方代理
* win7: 开始->控制面板->网络和Internet->网络和共享中心->左下角Internet选项->连接选项卡->局域网设置
![](./doc/proxy.png)
#### 2. 360软件会严重拖慢设置代理命令的执行时间
如果开启了360那么软件开启windows代理的时间会特别长需要耐心等待。
#### 2. 尝试将代理设置关闭再重新打开
按上图中先关闭代理,保存,再打开代理,再保存
#### 3.如果还是不行,请在下方加作者好友,将服务日志发送给作者进行分析
日志打开方式:加速服务->右边日志按钮->另存为
#### 3. 如果还是不行,请在下方加作者好友,将服务日志发送给作者进行分析
日志打开方式:加速服务->右边日志按钮->打开日志文件夹
![](./doc/log.png)

View File

@ -14,5 +14,5 @@
"ignore": []
}
},
"version": "1.2.1"
"version": "1.3.1"
}

3
packages/core/.babelrc Normal file
View File

@ -0,0 +1,3 @@
{
"presets": ["es2020","stage-4"]
}

View File

@ -1,6 +1,6 @@
{
"name": "@docmirror/dev-sidecar",
"version": "1.2.1",
"version": "1.3.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "@docmirror/dev-sidecar",
"version": "1.2.1",
"version": "1.3.1",
"description": "给开发者的加速代理工具",
"main": "src/index.js",
"keywords": [
@ -16,8 +16,9 @@
"start": "node ./start"
},
"dependencies": {
"@docmirror/mitmproxy": "^1.2.1",
"@docmirror/mitmproxy": "^1.3.0",
"agentkeepalive": "^2.1.1",
"babel-preset-es2020": "^1.0.2",
"charset": "^1.0.0",
"child_process": "^1.0.2",
"colors": "^1.1.2",

View File

@ -49,11 +49,11 @@ module.exports = {
desc: 'clone加速复制链接脚本'
},
'/.*': {
proxy: 'github.com',
proxy: 'gh.docmirror.top/_proxy',
backup: [
'gh.docmirror.top/_proxy'
'github.com'
],
desc: '如果出现dev-sidecar报错可能是备用加速地址dns被污染了需要将本条配置删除'
desc: '如果出现dev-sidecar报错可能是加速地址dns被污染了需要将本条配置删除'
}
},
'api.github.com': {
@ -66,20 +66,30 @@ module.exports = {
'.*': { proxy: 'raw.fastgit.org' }
},
'github.githubassets.com': {
'.*': { proxy: 'assets.fastgit.org', test: 'https://github.githubassets.com/favicons/favicon.svg', desc: '静态资源加速' }
'.*': {
proxy: 'assets.fastgit.org',
backup: ['github.githubassets.com'],
test: 'https://github.githubassets.com/favicons/favicon.svg',
desc: '静态资源加速'
}
},
'customer-stories-feed.github.com': {
'.*': { proxy: 'customer-stories-feed.fastgit.org' }
},
// google cdn
'www.google.com': {
'/recaptcha/.*': { proxy: 'www.recaptcha.net' },
'.*': {
proxy: 'gg.docmirror.top/_yxorp',
desc: '呀,被你发现了,偷偷的用,别声张'
}
},
'ajax.googleapis.com': {
'.*': {
proxy: 'ajax.loli.net',
backup: ['ajax.proxy.ustclug.org'],
test: 'ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js'
}
},
'fonts.googleapis.com': {
'.*': {
@ -97,13 +107,10 @@ module.exports = {
'themes.googleusercontent.com': {
'.*': { proxy: 'google-themes.proxy.ustclug.org' }
},
'www.google.com': {
'/recaptcha/.*': { proxy: 'www.recaptcha.net' }
},
'fonts.gstatic.com': {
'.*': {
proxy: 'fonts-gstatic.proxy.ustclug.org',
backup: ['gstatic.loli.net']
proxy: 'gstatic.loli.net',
backup: ['fonts-gstatic.proxy.ustclug.org']
}
},
'clients*.google.com': { '.*': { abort: true } },
@ -115,18 +122,23 @@ module.exports = {
redirect: 'npm.taobao.org/mirrors'
}
},
'registry-1.docker.io': { '.*': { proxy: 'docker.mirrors.ustc.edu.cn' } },
'packages.elastic.co': { '.*': { proxy: 'elastic.proxy.ustclug.org' } },
'ppa.launchpad.net': { '.*': { proxy: 'launchpad.proxy.ustclug.org' } },
'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' } },
// 'packages.elastic.co': { '.*': { proxy: 'elastic.proxy.ustclug.org' } },
// 'ppa.launchpad.net': { '.*': { proxy: 'launchpad.proxy.ustclug.org' } },
// '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' } },
'*.carbonads.com': {
'/carbon.*': {
abort: true,
desc: '广告拦截'
}
},
'*.buysellads.com': {
'/ads/.*': {
abort: true,
desc: '广告拦截'
}
}
},
whiteList: {

View File

@ -19,11 +19,13 @@ function setupPlugin (key, plugin, context, config) {
const pluginStatus = plugin.status
const api = PluginClass(context)
config.addDefault(key, pluginConfig)
lodash.set(status, key, pluginStatus)
if (pluginStatus) {
lodash.set(status, key, pluginStatus)
}
return api
}
const server = modules.server
const proxy = setupPlugin('proxy', modules.proxy, context, config)
const plugin = {}
for (const key in modules.plugin) {
@ -32,99 +34,110 @@ for (const key in modules.plugin) {
plugin[key] = api
}
config.resetDefault()
const server = modules.server
const serverStart = server.start
module.exports = {
status,
api: {
startup: async ({ mitmproxyPath }) => {
const conf = config.get()
if (conf.server.enabled) {
try {
await server.start({ mitmproxyPath })
} catch (err) {
log.error('代理服务启动失败:', err)
}
}
if (conf.proxy.enabled) {
try {
await proxy.start()
} catch (err) {
log.error('开启系统代理失败:', err)
}
}
try {
const plugins = []
for (const key in plugin) {
if (conf.plugin[key].enabled) {
const start = async () => {
try {
await plugin[key].start()
log.info(`插件【${key}】已启动`)
} catch (err) {
log.error(`插件【${key}】启动失败`, err)
}
}
plugins.push(start())
const newServerStart = ({ mitmproxyPath }) => {
return serverStart({ mitmproxyPath, plugins: plugin })
}
server.start = newServerStart
async function startup ({ mitmproxyPath }) {
const conf = config.get()
if (conf.server.enabled) {
try {
await server.start({ mitmproxyPath })
} catch (err) {
log.error('代理服务启动失败:', err)
}
}
if (conf.proxy.enabled) {
try {
await proxy.start()
} catch (err) {
log.error('开启系统代理失败:', err)
}
}
try {
const plugins = []
for (const key in plugin) {
if (conf.plugin[key].enabled) {
const start = async () => {
try {
await plugin[key].start()
log.info(`插件【${key}】已启动`)
} catch (err) {
log.error(`插件【${key}】启动失败`, err)
}
}
if (plugins && plugins.length > 0) {
await Promise.all(plugins)
}
} catch (err) {
log.error('开启插件失败:', err)
plugins.push(start())
}
},
shutdown: async () => {
try {
const plugins = []
for (const key in plugin) {
if (status.plugin[key].enabled && plugin[key].close) {
const close = async () => {
try {
await plugin[key].close()
log.info(`插件【${key}】已关闭`)
} catch (err) {
log.info(`插件【${key}】关闭失败`, err)
}
}
plugins.push(close())
}
}
if (plugins.length > 0) {
await Promise.all(plugins)
}
} catch (error) {
log.error('插件关闭失败'.error)
}
if (status.proxy.enabled) {
try {
await proxy.close()
log.info('系统代理已关闭')
} catch (err) {
log.error('系统代理关闭失败', err)
}
}
if (status.server.enabled) {
try {
await server.close()
log.info('代理服务已关闭')
} catch (err) {
log.error('代理服务关闭失败', err)
}
}
},
status: {
get () {
return status
}
},
config,
event,
shell,
server,
proxy,
plugin,
log
}
if (plugins && plugins.length > 0) {
await Promise.all(plugins)
}
} catch (err) {
log.error('开启插件失败:', err)
}
}
async function shutdown () {
try {
const plugins = []
for (const key in plugin) {
if (status.plugin[key].enabled && plugin[key].close) {
const close = async () => {
try {
await plugin[key].close()
log.info(`插件【${key}】已关闭`)
} catch (err) {
log.info(`插件【${key}】关闭失败`, err)
}
}
plugins.push(close())
}
}
if (plugins.length > 0) {
await Promise.all(plugins)
}
} catch (error) {
log.error('插件关闭失败'.error)
}
if (status.proxy.enabled) {
try {
await proxy.close()
log.info('系统代理已关闭')
} catch (err) {
log.error('系统代理关闭失败', err)
}
}
if (status.server.enabled) {
try {
await server.close()
log.info('代理服务已关闭')
} catch (err) {
log.error('代理服务关闭失败', err)
}
}
}
const api = {
startup,
shutdown,
status: {
get () {
return status
}
},
config,
event,
shell,
server,
proxy,
plugin,
log
}
module.exports = {
status,
api
}

View File

@ -0,0 +1,7 @@
module.exports = {
name: 'Git代理',
enabled: false,
setting: {
sslVerify: false
}
}

View File

@ -0,0 +1,65 @@
const pluginConfig = require('./config')
const Plugin = function (context) {
const { config, shell, event, log } = context
const pluginApi = {
async start () {
const ip = '127.0.0.1'
const port = config.get().server.port
await pluginApi.setProxy(ip, port)
return { ip, port }
},
async close () {
return pluginApi.unsetProxy()
},
async restart () {
await pluginApi.close()
await pluginApi.start()
},
async save (newConfig) {
},
async setProxy (ip, port) {
const cmds = [
`git config --global http.proxy http://${ip}:${port} `,
`git config --global https.proxy http://${ip}:${port} `
]
if (pluginConfig.setting.sslVerify === true) {
cmds.push('git config --global http.sslVerify false ')
}
const ret = await shell.exec(cmds, { type: 'cmd' })
event.fire('status', { key: 'plugin.git.enabled', value: true })
log.info('开启【Git】代理成功')
return ret
},
async unsetProxy () {
const cmds = [
'git config --global --unset https.proxy ',
'git config --global --unset http.proxy '
]
if (pluginConfig.setting.sslVerify === true) {
cmds.push('git config --global http.sslVerify true ')
}
const ret = await shell.exec(cmds, { type: 'cmd' })
event.fire('status', { key: 'plugin.git.enabled', value: false })
log.info('关闭【Git】代理成功')
return ret
}
}
return pluginApi
}
module.exports = {
key: 'git',
config: pluginConfig,
status: {
enabled: false
},
plugin: Plugin
}

View File

@ -1,4 +1,7 @@
const node = require('./node')
const git = require('./git')
const overwall = require('./overwall')
module.exports = {
node
node, git, overwall
}

View File

@ -11,9 +11,9 @@ module.exports = {
NODE_TLS_REJECT_UNAUTHORIZED: false,
registry: 'https://registry.npmjs.org'// 可以选择切换官方或者淘宝镜像
},
intercepts: {
'cdn.cypress.io': [{ regexp: '/desktop/.*', proxy: 'http://npm.taobao.org/mirrors/cypress/' }]
},
// intercepts: {
// 'cdn.cypress.io': [{ regexp: '/desktop/.*', proxy: 'http://npm.taobao.org/mirrors/cypress/' }]
// },
variables: {
SASS_BINARY_SITE: 'https://npm.taobao.org/mirrors/node-sass/',
PHANTOMJS_CDNURL: 'https://npm.taobao.org/mirrors/phantomjs/',

View File

@ -0,0 +1,21 @@
module.exports = {
name: '梯子',
enabled: false,
server: {
},
serverDefault: {
'ow-prod.docmirror.top': {
path: 'X2dvX292ZXJfd2FsbF8',
password: 'dev_sidecar_is_666'
}
},
targets: {
'*facebook.com': true
},
pac: {
enabled: true,
update: [
'https://gitlab.com/gfwlist/gfwlist/raw/master/gfwlist.txt'
]
}
}

View File

@ -0,0 +1,55 @@
const pluginConfig = require('./config')
const Plugin = function (context) {
const { config, shell, event, log } = context
const api = {
async start () {
// event.fire('status', { key: 'plugin.overwall.enabled', value: true })
},
async close () {
// event.fire('status', { key: 'plugin.overwall.enabled', value: false })
},
async restart () {
await api.close()
await api.start()
},
async overrideRunningConfig_bak (serverConfig) {
const conf = config.get().plugin.overwall
if (!conf || !conf.enabled || !conf.targets) {
return
}
const server = conf.server
let i = 0
let main
const backup = []
for (const key in server) {
if (i === 0) {
main = key
} else {
backup.push(key)
}
i++
}
for (const key in conf.targets) {
serverConfig.intercepts[key] = {
'.*': {
// eslint-disable-next-line no-template-curly-in-string
proxy: main + '/${host}',
backup
}
}
}
}
}
return api
}
module.exports = {
key: 'overwall',
config: pluginConfig,
plugin: Plugin
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,7 @@ const serverApi = {
return this.close()
}
},
async start ({ mitmproxyPath }) {
async start ({ mitmproxyPath, plugins }) {
const allConfig = config.get()
const serverConfig = lodash.cloneDeep(allConfig.server)
@ -37,6 +37,9 @@ const serverApi = {
if (allConfig.plugin) {
lodash.each(allConfig.plugin, (value) => {
const plugin = value
if (!plugin.enabled) {
return
}
if (plugin.intercepts) {
lodash.merge(intercepts, plugin.intercepts)
}
@ -45,6 +48,14 @@ const serverApi = {
}
})
}
for (const key in plugins) {
const plugin = plugins[key]
if (plugin.overrideRunningConfig) {
plugin.overrideRunningConfig(serverConfig)
}
}
serverConfig.plugin = allConfig.plugin
// fireStatus('ing') // 启动中
const basePath = serverConfig.setting.userBasePath
const runningConfig = basePath + '/running.json'

View File

@ -3,11 +3,12 @@
*/
const Shell = require('../../shell')
const execute = Shell.execute
const execFile = Shell.execFile
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 path = require('path')
const _lanIP = [
'localhost',
'127.*',
@ -33,6 +34,12 @@ const _lanIP = [
]
async function _winUnsetProxy (exec) {
// eslint-disable-next-line no-constant-condition
if (true) {
const proxyPath = getProxyExePath()
await execFile(proxyPath, ['set', '1'])
return
}
const regKey = new Registry({
hive: Registry.HKCU,
key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings'
@ -43,21 +50,36 @@ async function _winUnsetProxy (exec) {
_winAsyncRegSet(regKey, 'ProxyServer', Registry.REG_SZ, '')
])
log.info('代理关闭成功等待refresh')
await exec(refreshInternetPs, { type: 'ps' })
await exec(['echo "do refresh"', refreshInternetPs], { type: 'ps' })
log.info('代理关闭refresh完成')
return true
}
function getProxyExePath () {
const proxyPath = process.env.DS_SYSPROXY_PATH
log.info('proxyPath', proxyPath)
if (proxyPath) {
return proxyPath
}
return path.join(__dirname, './sysproxy.exe')
}
async function _winSetProxy (exec, ip, port) {
let lanIpStr = ''
for (const string of _lanIP) {
lanIpStr += string + ';'
}
// eslint-disable-next-line no-constant-condition
if (true) {
const proxyPath = getProxyExePath()
await execFile(proxyPath, ['global', `${ip}:${port}`, lanIpStr])
return
}
const regKey = new Registry({
hive: Registry.HKCU,
key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings'
})
let lanIpStr = ''
for (const string of _lanIP) {
lanIpStr += string + ';'
}
// log.info('lanIps:', lanIpStr, ip, port)
await Promise.all([
_winAsyncRegSet(regKey, 'MigrateProxy', Registry.REG_DWORD, 1),
@ -67,7 +89,7 @@ async function _winSetProxy (exec, ip, port) {
_winAsyncRegSet(regKey, 'ProxyOverride', Registry.REG_SZ, lanIpStr)
])
log.info('代理设置成功等待refresh')
await exec(refreshInternetPs)
await exec(['echo "do refresh"', refreshInternetPs], { type: 'ps' })
log.info('代理设置refresh完成')
return true
}

View File

@ -2,6 +2,7 @@ const util = require('util')
const os = require('os')
const childProcess = require('child_process')
const _exec = childProcess.exec
const _execFile = childProcess.execFile
const exec = util.promisify(_exec)
const PowerShell = require('node-powershell')
const log = require('../utils/util.log')
@ -119,8 +120,23 @@ async function execute (executor, args) {
return executor[getSystemPlatform()](getSystemShell().exec, args)
}
async function execFile (file, args, options) {
return new Promise((resolve, reject) => {
_execFile(file, args, options, (err, stdout) => {
if (err) {
log.error('文件执行出错:', file, err)
reject(err)
return
}
log.debug('执行成功:', stdout)
resolve(stdout)
})
})
}
module.exports = {
getSystemShell,
getSystemPlatform,
execute
execute,
execFile
}

View File

@ -3,9 +3,12 @@ const config = require('../config/index')
function getDefaultConfigBasePath () {
return config.server.setting.userBasePath
}
const level = process.env.NODE_ENV === 'development' ? 'debug' : 'info'
const path = require('path')
const filename = path.join(getDefaultConfigBasePath(), '/logs/core.log')
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' } }
appenders: { std: { type: 'stdout' }, file: { type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename} },
categories: { default: { appenders: ['file', 'std'], level: level } }
})
const logger = log4js.getLogger('server')
module.exports = logger

View File

@ -1,6 +1,10 @@
// eslint-disable-next-line no-unused-vars
const server = require('@docmirror/mitmproxy')
const configPath = process.argv[2]
let configPath = 'C:/Users/Administrator/.dev-sidecar/running.json'
if (process.argv && process.argv.length > 3) {
configPath = process.argv[2]
}
const fs = require('fs')
const path = require('path')
const configJson = fs.readFileSync(configPath)

2
packages/core/start2.js Normal file
View File

@ -0,0 +1,2 @@
// eslint-disable-next-line no-unused-vars
const mitmproxy = require('./start/mitmproxy.js')

View File

@ -93,10 +93,10 @@
lodash "^4.17.19"
to-fast-properties "^2.0.0"
"@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==
"@docmirror/mitmproxy@^1.2.2":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@docmirror/mitmproxy/-/mitmproxy-1.2.2.tgz#a4d0020e073eaa68adb7902b5634ab2a1a3bc058"
integrity sha512-xW1xyqUfpGAZZTzqSjoQM0Mmq8VVEyvS8AiTUBvgpxUAYG2sqNCacLETwYfNBP1MStUBtGXKklcISpIY6+R+DA==
dependencies:
agentkeepalive "^2.1.1"
child_process "^1.0.2"
@ -442,6 +442,11 @@ ansi-escapes@^4.2.1:
dependencies:
type-fest "^0.11.0"
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
@ -452,6 +457,11 @@ ansi-regex@^5.0.0:
resolved "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
integrity sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
ansi-styles@^3.2.0, ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz?cache=0&sync_timestamp=1601839122515&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
@ -625,6 +635,15 @@ aws4@^1.8.0:
resolved "https://registry.npm.taobao.org/aws4/download/aws4-1.10.1.tgz?cache=0&sync_timestamp=1597236947743&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faws4%2Fdownload%2Faws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428"
integrity sha1-4eguTz6Zniz9YbFhKA0WoRH4ZCg=
babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
dependencies:
chalk "^1.1.3"
esutils "^2.0.2"
js-tokens "^3.0.2"
babel-eslint@^10.1.0:
version "10.1.0"
resolved "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz?cache=0&sync_timestamp=1599054223324&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-eslint%2Fdownload%2Fbabel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232"
@ -637,6 +656,104 @@ babel-eslint@^10.1.0:
eslint-visitor-keys "^1.0.0"
resolve "^1.12.0"
babel-messages@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=
dependencies:
babel-runtime "^6.22.0"
babel-plugin-check-es2015-constants@^6.8.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a"
integrity sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-arrow-functions@^6.8.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"
integrity sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-block-scoping@^6.9.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f"
integrity sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=
dependencies:
babel-runtime "^6.26.0"
babel-template "^6.26.0"
babel-traverse "^6.26.0"
babel-types "^6.26.0"
lodash "^4.17.4"
babel-plugin-transform-es2015-template-literals@^6.8.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d"
integrity sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=
dependencies:
babel-runtime "^6.22.0"
babel-preset-es2020@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/babel-preset-es2020/-/babel-preset-es2020-1.0.2.tgz#489272ca9c8b1fca59b2cfc4b2a2fab02eedeb79"
integrity sha1-SJJyypyLH8pZss/EsqL6sC7t63k=
dependencies:
babel-plugin-check-es2015-constants "^6.8.0"
babel-plugin-transform-es2015-arrow-functions "^6.8.0"
babel-plugin-transform-es2015-block-scoping "^6.9.0"
babel-plugin-transform-es2015-template-literals "^6.8.0"
babel-runtime@^6.22.0, babel-runtime@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.11.0"
babel-template@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02"
integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=
dependencies:
babel-runtime "^6.26.0"
babel-traverse "^6.26.0"
babel-types "^6.26.0"
babylon "^6.18.0"
lodash "^4.17.4"
babel-traverse@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee"
integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=
dependencies:
babel-code-frame "^6.26.0"
babel-messages "^6.23.0"
babel-runtime "^6.26.0"
babel-types "^6.26.0"
babylon "^6.18.0"
debug "^2.6.8"
globals "^9.18.0"
invariant "^2.2.2"
lodash "^4.17.4"
babel-types@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=
dependencies:
babel-runtime "^6.26.0"
esutils "^2.0.2"
lodash "^4.17.4"
to-fast-properties "^1.0.3"
babylon@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
@ -883,6 +1000,17 @@ caseless@~0.12.0:
resolved "https://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
dependencies:
ansi-styles "^2.2.1"
escape-string-regexp "^1.0.2"
has-ansi "^2.0.0"
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@ -1119,6 +1247,11 @@ copy-descriptor@^0.1.0:
resolved "https://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
core-js@^2.4.0:
version "2.6.12"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@ -1227,7 +1360,7 @@ date-format@^3.0.0:
resolved "https://registry.yarnpkg.com/date-format/-/date-format-3.0.0.tgz#eb8780365c7d2b1511078fb491e6479780f3ad95"
integrity sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==
debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@ -1538,7 +1671,7 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
escape-string-regexp@^1.0.5:
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
@ -2169,6 +2302,11 @@ globals@^12.1.0:
dependencies:
type-fest "^0.8.1"
globals@^9.18.0:
version "9.18.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==
globby@^9.2.0:
version "9.2.0"
resolved "https://registry.npm.taobao.org/globby/download/globby-9.2.0.tgz?cache=0&sync_timestamp=1591083812416&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglobby%2Fdownload%2Fglobby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d"
@ -2201,6 +2339,13 @@ har-validator@~5.1.3:
ajv "^6.12.3"
har-schema "^2.0.0"
has-ansi@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
dependencies:
ansi-regex "^2.0.0"
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@ -2396,6 +2541,13 @@ interpret@^1.2.0:
resolved "https://registry.npm.taobao.org/interpret/download/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
integrity sha1-Zlq4vE2iendKQFhOgS4+D6RbGh4=
invariant@^2.2.2:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
dependencies:
loose-envify "^1.0.0"
ip@^1.1.5:
version "1.1.5"
resolved "https://registry.npm.taobao.org/ip/download/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
@ -2656,11 +2808,16 @@ js-queue@2.0.0:
dependencies:
easy-stack "^1.0.0"
js-tokens@^4.0.0:
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-tokens@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
js-yaml@^3.13.1:
version "3.14.0"
resolved "https://registry.npm.taobao.org/js-yaml/download/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
@ -2838,7 +2995,7 @@ locate-path@^3.0.0:
p-locate "^3.0.0"
path-exists "^3.0.0"
lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.7.0:
lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@^4.7.0:
version "4.17.20"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
@ -2861,6 +3018,13 @@ log4js@^6.3.0:
rfdc "^1.1.4"
streamroller "^2.2.4"
loose-envify@^1.0.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
lru-cache@^4.0.1, lru-cache@^4.1.2:
version "4.1.5"
resolved "https://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz?cache=0&sync_timestamp=1594427582110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
@ -3755,6 +3919,11 @@ readdirp@~3.5.0:
dependencies:
picomatch "^2.2.1"
regenerator-runtime@^0.11.0:
version "0.11.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
regex-not@^1.0.0, regex-not@^1.0.2:
version "1.0.2"
resolved "https://registry.npm.taobao.org/regex-not/download/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
@ -4245,6 +4414,13 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
strip-ansi@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
dependencies:
ansi-regex "^2.0.0"
strip-ansi@^5.1.0, strip-ansi@^5.2.0:
version "5.2.0"
resolved "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
@ -4279,6 +4455,11 @@ strip-json-comments@^3.0.1:
resolved "https://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-3.1.1.tgz?cache=0&sync_timestamp=1594567532500&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-json-comments%2Fdownload%2Fstrip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY=
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz?cache=0&sync_timestamp=1598611709087&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@ -4374,6 +4555,11 @@ to-arraybuffer@^1.0.0:
resolved "https://registry.npm.taobao.org/to-arraybuffer/download/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
to-fast-properties@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.npm.taobao.org/to-fast-properties/download/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"

View File

@ -0,0 +1,20 @@
// ==UserScript==
// @name google增强
// @version 1.2.4
// @author Greper
// @description 去除ping链接
// @match https://www.google.com/*/*
// @icon https://www.google.com/favicon.ico
// @license GPL-3.0 License
// @run-at document-end
// @namespace
// ==/UserScript==
(function () {
console.log('google script loaded')
const aList = document.getElementsByTagName('a')
for (let i = 0; i <= aList.length; i++) {
console.log(aList[i].href)
aList[i].ping = undefined
}
})()

Binary file not shown.

View File

@ -1,6 +1,6 @@
{
"name": "@docmirror/dev-sidecar-gui",
"version": "1.2.1",
"version": "1.3.1",
"private": false,
"license": "MPL-2.0",
"scripts": {
@ -12,10 +12,11 @@
"postuninstall": "electron-builder install-app-deps",
"electron:generate-icons": "electron-icon-builder --input=./public/icon.png --output=build --flatten"
},
"author": "docmirror.cn",
"main": "background.js",
"dependencies": {
"@docmirror/dev-sidecar": "^1.2.1",
"@docmirror/mitmproxy": "^1.2.1",
"@docmirror/dev-sidecar": "^1.3.1",
"@docmirror/mitmproxy": "^1.3.0",
"ant-design-vue": "^1.6.5",
"core-js": "^3.6.5",
"electron-baidu-tongji": "^1.0.5",

View File

@ -1,11 +1,10 @@
'use strict'
/* global __static */
import path from 'path'
import { app, protocol, BrowserWindow, Menu, Tray, ipcMain } from 'electron'
import { app, protocol, BrowserWindow, Menu, Tray, ipcMain, dialog } from 'electron'
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 backend from './bridge/backend'
import DevSidecar from '@docmirror/dev-sidecar'
import log from './utils/util.log'
// eslint-disable-next-line no-unused-vars
const isMac = process.platform === 'darwin'
@ -113,7 +112,7 @@ function createWindow () {
}
async function beforeQuit () {
return bridge.devSidecar.api.shutdown()
return DevSidecar.api.shutdown()
}
async function quit (app, callback) {
if (tray) {
@ -136,12 +135,6 @@ if (!isFirstInstance) {
} else {
app.on('before-quit', async (event) => {
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) => {
log.info('new app started', commandLine)
@ -180,24 +173,13 @@ if (!isFirstInstance) {
// log.error('Vue Devtools failed to install:', e.toString())
// }
}
createWindow()
bridge.init(win)
let updateUrl = 'https://dev-sidecar.docmirror.cn/update/'
if (process.env.NODE_ENV === 'development') {
Object.defineProperty(app, 'isPackaged', {
get () {
return true
}
})
updateUrl = 'https://dev-sidecar.docmirror.cn/update/'
// updateUrl = 'http://localhost/dev-sidecar/'
try {
createWindow()
const context = { win, app, beforeQuit, ipcMain, dialog,log }
backend.install(context) // 模块安装
} catch (err) {
log.info('err', err)
}
// 自动更新
updateHandle(app, win, beforeQuit, updateUrl)
// 百度分析
ebtMain(ipcMain, isDevelopment)
try {
// 最小化到托盘

View File

@ -1,12 +1,13 @@
import lodash from 'lodash'
import DevSidecar from '@docmirror/dev-sidecar'
import { ipcMain, Menu } from 'electron'
import { ipcMain } from 'electron'
import fs from 'fs'
import JSON5 from 'json5'
import path from 'path'
const pk = require('../../package.json')
const pk = require('../../../package.json')
const mitmproxyPath = path.join(__dirname, 'mitmproxy.js')
const log = require('../utils/util.log')
process.env.DS_SYSPROXY_PATH = path.join(__dirname, '../extra/sysproxy.exe')
const log = require('../../utils/util.log')
const getDefaultConfigBasePath = function () {
return DevSidecar.api.config.get().server.setting.userBasePath
}
@ -40,12 +41,23 @@ const localApi = {
setting: {
load () {
const settingPath = _getSettingsPath()
if (!fs.existsSync(settingPath)) {
return {}
let setting = {}
if (fs.existsSync(settingPath)) {
const file = fs.readFileSync(settingPath)
setting = JSON5.parse(file.toString())
if (setting == null) {
setting = {}
}
}
const file = fs.readFileSync(settingPath)
const setting = JSON5.parse(file.toString())
return setting || {}
if (setting.overwall == null) {
setting.overwall = true
}
if (setting.installTime == null) {
setting.installTime = new Date().getTime()
localApi.setting.save(setting)
}
return setting
},
save (setting = {}) {
const settingPath = _getSettingsPath()
@ -170,25 +182,29 @@ function doMerge (defObj, newObj) {
return newObj2
}
function invoke (api, param) {
let target = lodash.get(localApi, api)
if (target == null) {
target = lodash.get(DevSidecar.api, api)
}
if (target == null) {
log.info('找不到此接口方法:', api)
}
const ret = target(param)
// log.info('api:', api, 'ret:', ret)
return ret
}
export default {
init (win) {
install ({ win }) {
// 接收view的方法调用
ipcMain.handle('apiInvoke', async (event, args) => {
const api = args[0]
let target = lodash.get(localApi, api)
if (target == null) {
target = lodash.get(DevSidecar.api, api)
}
if (target == null) {
log.info('找不到此接口方法:', api)
}
let param
if (args.length >= 2) {
param = args[1]
}
const ret = target(param)
// log.info('api:', api, 'ret:', ret)
return ret
return invoke(api, param)
})
// 注册从core里来的事件并转发给view
DevSidecar.api.event.register('status', (event) => {
@ -205,5 +221,6 @@ export default {
// 启动所有
localApi.startup()
},
devSidecar: DevSidecar
devSidecar: DevSidecar,
invoke
}

View File

@ -0,0 +1,19 @@
import api from './api/backend'
import tongji from './tongji/backend'
import update from './update/backend'
import fileSelector from './file-selector/backend'
const modules = {
api, // 核心接口模块
fileSelector, // 文件选择模块
tongji, // 统计模块
update // 自动更新
}
export default {
install (context) {
for (const module in modules) {
modules[module].install(context)
}
},
...modules
}

View File

@ -0,0 +1,21 @@
export default {
install (context) {
const { ipcMain, dialog, log } = context
ipcMain.on('file-selector', function (event, message) {
if (message.key === 'open') {
dialog.showOpenDialog({
properties: ['openFile'],
...message
}).then(result => {
if (result.canceled) {
event.sender.send('file-selector', { key: 'canceled' })
} else {
event.sender.send('file-selector', { key: 'selected', value: result.filePaths })
}
}).catch(err => {
log.error('选择文件失败', err)
})
}
})
}
}

View File

@ -0,0 +1,23 @@
function install (app, api) {
api.fileSelector = {
open (value, options) {
return new Promise((resolve, reject) => {
api.ipc.send('file-selector', { key: 'open', value: value, ...options })
api.ipc.on('file-selector', (event, message) => {
console.log('selector', message)
if (message.key === 'selected') {
resolve(message.value)
} else {
reject(new Error('没有选择文件'))
}
api.ipc.on('file-selector', () => {})
})
})
}
}
}
export default {
install
}

View File

@ -0,0 +1,21 @@
// import api from './api/front'
import error from './error/front'
import tongji from './tongji/front'
import update from './update/front'
import fileSelector from './file-selector/front'
const modules = {
// api, // 核心接口模块
error,
fileSelector, // 文件选择模块
tongji, // 统计模块
update // 自动更新
}
export default {
install (app, api, router) {
for (const module in modules) {
modules[module].install(app, api, router)
}
},
...modules
}

View File

@ -1,15 +1,14 @@
// eslint-disable-next-line no-unused-vars
const server = require('@docmirror/mitmproxy')
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)

View File

@ -0,0 +1,55 @@
/**
* first step
* @param {*} ipcMain
*/
const ebtMain = (ipcMain) => {
const isDevelopment = process.env.NODE_ENV !== 'production'
const request = require('request')
/* istanbul ignore else */
if (!(ipcMain && ipcMain.on)) {
throw new TypeError('require ipcMain')
}
// step 2
ipcMain.on('electron-baidu-tongji-message', (event, arg) => {
// electron 生产模式下是直接请求文件系统,没有 http 地址
// 前台拿不到 hm.js 的内容
request({
url: `https://hm.baidu.com/hm.js?${arg}`,
method: 'GET',
headers: {
Referer: 'https://hm.baidu.com/'
}
},
(err, response, body) => {
if (err) {
console.error('百度统计请求出错', err)
return
}
const rource = '(h.c.b.su=h.c.b.u||document.location.href),h.c.b.u=f.protocol+"//"+document.location.host+'
/* istanbul ignore else */
if (body && body.indexOf(rource) >= 0) {
// step 3
let text = body
/* istanbul ignore else */
if (!isDevelopment) {
// 百度统计可能改规则了,不统计 file:// 开始的请求
// 这里强制替换为 https
const target = '(h.c.b.su=h.c.b.u||"https://"+c.dm[0]+a[1]),h.c.b.u="https://"+c.dm[0]+'
const target2 = '"https://"+c.dm[0]+window.location.pathname+window.location.hash'
text = body.replace(rource, target).replace(/window.location.href/g, target2)
}
console.log('baidu tonji: ret')
event.sender.send('electron-baidu-tongji-reply', { text, isDevelopment })
}
})
})
}
export default {
install (context) {
ebtMain(context.ipcMain)
}
}

View File

@ -0,0 +1,62 @@
/**
* second step
* @param {*} ipcRenderer
* @param {*} siteId
* @param {*} router
*/
const ebtRenderer = (ipcRenderer, siteId, router) => {
/* istanbul ignore else */
if (!(ipcRenderer && ipcRenderer.on && ipcRenderer.send)) {
throw new TypeError('require ipcRenderer')
}
/* istanbul ignore else */
if (!(siteId && typeof siteId === 'string')) {
throw new TypeError('require siteId')
}
// step 4
ipcRenderer.on('electron-baidu-tongji-reply', (_, { text, isDevelopment }) => {
console.log('electron-baidu-tongji-reply')
/* istanbul ignore else */
if (isDevelopment) { document.body.classList.add('electron-baidu-tongji_dev') }
window._hmt = window._hmt || []
const hm = document.createElement('script')
hm.text = text
const head = document.getElementsByTagName('head')[0]
head.appendChild(hm)
// Vue单页应用时监听router的每次变化
// 把虚拟的url地址赋给百度统计的API接口
/* istanbul ignore else */
if (router && router.beforeEach) {
router.beforeEach((to, _, next) => {
/* istanbul ignore else */
if (to.path) {
window._hmt.push(['_trackPageview', '/#' + to.fullPath])
console.log('baidu trace', to.fullPath)
}
next()
})
}
})
// step 1
ipcRenderer.send('electron-baidu-tongji-message', siteId)
}
export default {
install (app, api, router) {
const BAIDU_SITE_ID = 'f2d170ce560aef0005b689f28697f852'
// 百度统计
const { ipcRenderer } = require('electron')
ebtRenderer(ipcRenderer, BAIDU_SITE_ID, router)
},
ebtRenderer
}

View File

@ -1,6 +1,5 @@
import { ipcMain, dialog } from 'electron'
import { ipcMain } from 'electron'
import { autoUpdater } from 'electron-updater'
import log from '../utils/util.log'
import path from 'path'
// win是所有窗口的引用
// const path = require('path') // 引入path模块
@ -8,7 +7,7 @@ import path from 'path'
// eslint-disable-next-line no-unused-vars
const isMac = process.platform === 'darwin'
// 检测更新在你想要检查更新的时候执行renderer事件触发后的操作自行编写
function updateHandle (app, win, beforeQuit, updateUrl) {
function updateHandle (app, win, beforeQuit, updateUrl, log) {
// // 更新前,删除本地安装包 ↓
// const updaterCacheDirName = 'dev-sidecar-updater'
// const updatePendingPath = path.join(autoUpdater.app.baseCachePath, updaterCacheDirName, 'pending')
@ -58,10 +57,7 @@ function updateHandle (app, win, beforeQuit, updateUrl) {
log.info('download complete', info.version)
win.webContents.send('update', {
key: 'downloaded',
value: {
version: info.version,
releaseData: info.releaseDate
}
value: info
})
})
@ -95,4 +91,20 @@ function updateHandle (app, win, beforeQuit, updateUrl) {
log.info('auto update inited')
return autoUpdater
}
export default updateHandle
export default {
install (context) {
const { app, win, beforeQuit, log } = context
let updateUrl = 'https://dev-sidecar.docmirror.cn/update/'
if (process.env.NODE_ENV === 'development') {
Object.defineProperty(app, 'isPackaged', {
get () {
return true
}
})
// updateUrl = 'https://dev-sidecar.docmirror.cn/update/'
updateUrl = 'http://localhost/dev-sidecar/'
}
updateHandle(app, win, beforeQuit, updateUrl, log)
}
}

View File

@ -78,11 +78,19 @@ function install (app, api) {
function newUpdateIsReady (value) {
updateParams.downloading = false
app.$confirm({
title: '新版本已准备好',
content: `是否立即升级安装v${value.version}?`,
title: `新版本(v${value.version})已准备好,是否立即升级?`,
cancelText: '暂不升级',
okText: '立即升级',
// content: h => <div><h4>{value.version}更新内容:</h4><div>{value.releaseNotes}</div></div>,
content: h => {
console.log(value)
if (value.releaseNotes) {
const notes = []
for (const note of value.releaseNotes) {
notes.push(<li>{note}</li>)
}
return <div><div>更新内容</div><ol>{notes}</ol></div>
}
},
onOk () {
console.log('OK')
api.update.doUpdateNow()

View File

@ -7,9 +7,6 @@ import VueRouter from 'vue-router'
import routes from './view/router'
import DsContainer from './view/components/container'
import './view/style/index.scss'
import { ipcRenderer } from 'electron'
const tongji = require('./tongji')
Vue.config.productionTip = false
Vue.use(antd)
@ -28,12 +25,7 @@ view.initApi().then(async (api) => {
router,
render: h => h(App)
}).$mount('#app')
const BAIDU_SITE_ID = 'f2d170ce560aef0005b689f28697f852'
// 百度统计
tongji.ebtRenderer(ipcRenderer, BAIDU_SITE_ID, router)
view.initModules(app)
view.initModules(app, router)
})
// fix vue-router NavigationDuplicated

View File

@ -1,103 +0,0 @@
const request = require('request')
/**
* first step
* @param {*} ipcMain
*/
const ebtMain = (ipcMain, isDevelopment) => {
/* istanbul ignore else */
if (!(ipcMain && ipcMain.on)) {
throw new TypeError('require ipcMain')
}
// step 2
ipcMain.on('electron-baidu-tongji-message', (event, arg) => {
// electron 生产模式下是直接请求文件系统,没有 http 地址
// 前台拿不到 hm.js 的内容
request({
url: `https://hm.baidu.com/hm.js?${arg}`,
method: 'GET',
headers: {
Referer: 'https://hm.baidu.com/'
}
},
(err, response, body) => {
if (err) {
console.error('百度统计请求出错', err)
return
}
const rource = '(h.c.b.su=h.c.b.u||document.location.href),h.c.b.u=f.protocol+"//"+document.location.host+'
/* istanbul ignore else */
if (body && body.indexOf(rource) >= 0) {
// step 3
let text = body
/* istanbul ignore else */
if (!isDevelopment) {
// 百度统计可能改规则了,不统计 file:// 开始的请求
// 这里强制替换为 https
const target = '(h.c.b.su=h.c.b.u||"https://"+c.dm[0]+a[1]),h.c.b.u="https://"+c.dm[0]+'
const target2 = '"https://"+c.dm[0]+window.location.pathname+window.location.hash'
text = body.replace(rource, target).replace(/window.location.href/g, target2)
}
console.log('baidu tonji: ret')
event.sender.send('electron-baidu-tongji-reply', { text, isDevelopment })
}
})
})
}
/**
* second step
* @param {*} ipcRenderer
* @param {*} siteId
* @param {*} router
*/
const ebtRenderer = (ipcRenderer, siteId, router) => {
/* istanbul ignore else */
if (!(ipcRenderer && ipcRenderer.on && ipcRenderer.send)) {
throw new TypeError('require ipcRenderer')
}
/* istanbul ignore else */
if (!(siteId && typeof siteId === 'string')) {
throw new TypeError('require siteId')
}
// step 4
ipcRenderer.on('electron-baidu-tongji-reply', (_, { text, isDevelopment }) => {
console.log('electron-baidu-tongji-reply')
/* istanbul ignore else */
if (isDevelopment) { document.body.classList.add('electron-baidu-tongji_dev') }
window._hmt = window._hmt || []
const hm = document.createElement('script')
hm.text = text
const head = document.getElementsByTagName('head')[0]
head.appendChild(hm)
// Vue单页应用时监听router的每次变化
// 把虚拟的url地址赋给百度统计的API接口
/* istanbul ignore else */
if (router && router.beforeEach) {
router.beforeEach((to, _, next) => {
/* istanbul ignore else */
if (to.path) {
window._hmt.push(['_trackPageview', '/#' + to.fullPath])
console.log('baidu trace', to.fullPath)
}
next()
})
}
})
// step 1
ipcRenderer.send('electron-baidu-tongji-message', siteId)
}
module.exports = { ebtMain, ebtRenderer }

View File

@ -3,9 +3,12 @@ const DevSidecar = require('@docmirror/dev-sidecar')
const getDefaultConfigBasePath = function () {
return DevSidecar.api.config.get().server.setting.userBasePath
}
const level = process.env.NODE_ENV === 'development' ? 'debug' : 'info'
const path = require('path')
const filename = path.join(getDefaultConfigBasePath(), '/logs/gui.log')
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' } }
appenders: { std: { type: 'stdout' }, file: { type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename } },
categories: { default: { appenders: ['file', 'std'], level } }
})
const logger = log4js.getLogger('server')
module.exports = logger

View File

@ -15,7 +15,7 @@
<a-sub-menu v-if="item.children && item.children.length>0" :key="item.path" @titleClick="titleClick(item)">
<span slot="title"><a-icon :type="item.icon?item.icon:'file'" /><span>{{item.title}}</span></span>
<a-menu-item v-for="(sub) of item.children" :key="sub.path" @click="menuClick(sub)" >
{{ sub.title }}
<a-icon :type="sub.icon?sub.icon:'file'"/> {{ sub.title }}
</a-menu-item>
</a-sub-menu>
<a-menu-item v-else :key="item.path" @click="menuClick(item)">
@ -45,30 +45,20 @@
</template>
<script>
import createMenus from '@/view/router/menu'
export default {
name: 'App',
components: {
},
data () {
return {
menus: [
{ title: '首页', path: '/index', icon: 'home' },
{ title: '加速服务', path: '/server', icon: 'thunderbolt' },
{ title: '系统代理', path: '/proxy', icon: 'deployment-unit' },
{
title: '应用',
path: '/plugin',
icon: 'api',
children: [
{ title: 'NPM加速', path: '/plugin/node', icon: 'like' }
]
}
]
menus: undefined
}
},
computed: {
},
created () {
this.menus = createMenus(this)
},
methods: {
handleClick (e) {

View File

@ -1,5 +1,5 @@
import api, { apiInit } from './api'
import modules from './modules'
import modules from '../bridge/front'
import status from './status'
export default {
initApi: apiInit,
@ -9,7 +9,7 @@ export default {
Vue.prototype.$global = { setting }
await status.install(api)
},
initModules (app) {
modules.install(app, api)
initModules (app, router) {
modules.install(app, api, router)
}
}

View File

@ -1,9 +0,0 @@
import update from './update'
import error from './error'
export default {
install (app, api) {
error.install(app, api)
update.install(app, api)
}
}

View File

@ -0,0 +1,61 @@
<template>
<ds-container>
<template slot="header">
Git代理设置
<span>
</span>
</template>
<div v-if="config">
<a-form layout="horizontal">
<a-form-item label="启用Git代理" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.plugin.git.enabled">
随应用启动
</a-checkbox>
<a-tag v-if="status.plugin.git.enabled" color="green">
当前已启动
</a-tag>
<a-tag v-else color="red">
当前未启动
</a-tag>
</a-form-item>
<a-form-item label="SSL校验" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.plugin.git.setting.sslVerify">
关闭sslVerify
</a-checkbox>
安装Git时未选择使用系统证书管理服务时必须关闭
</a-form-item>
</a-form>
</div>
<template slot="footer">
<div class="footer-bar">
<a-button class="md-mr-10" icon="sync" @click="resetDefault()"></a-button>
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()"></a-button>
</div>
</template>
</ds-container>
</template>
<script>
import Plugin from '../../mixins/plugin'
export default {
name: 'Git',
mixins: [Plugin],
data () {
return {
key: 'plugin.git'
}
},
created () {
console.log('status:', this.status)
},
mounted () {
},
methods: {
ready () {
}
}
}
</script>

View File

@ -19,7 +19,7 @@
当前未启动
</a-tag>
</a-form-item>
<a-form-item label="SSL相关" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item label="SSL校验" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.plugin.node.setting['strict-ssl']">
关闭strict-ssl
</a-checkbox>

View File

@ -0,0 +1,177 @@
<template>
<ds-container>
<template slot="header">
Ladder
<span>
<a-button type="primary" @click="openExternal('https://github.com/docmirror/dev-sidecar-doc/blob/main/ow.md')"></a-button>
</span>
</template>
<div v-if="config">
<a-form layout="horizontal">
<a-form-item label="Ladder" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.plugin.overwall.enabled">
启用
</a-checkbox>
<div>这是什么功能你懂的偷偷的用别声张(不要看视频流量挺小的)</div>
<div>建议按右上角说明自建服务端</div>
</a-form-item>
<a-form-item label="PAC" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.plugin.overwall.pac.enabled">
启用PAC
</a-checkbox>
</a-form-item>
<a-form-item label="自定义域名" :label-col="labelCol" :wrapper-col="wrapperCol">
<div>
<a-row :gutter="10" style="">
<a-col :span="22">
<span>PAC没有拦截到的域名可以在此处定义</span>
</a-col>
<a-col :span="2">
<a-button type="primary" icon="plus" @click="addTarget()" />
</a-col>
</a-row>
<a-row :gutter="10" v-for="(item,index) of targets" :key = 'index'>
<a-col :span="22">
<a-input v-model="item.key"></a-input>
</a-col>
<a-col :span="2">
<a-button type="danger" icon="minus" @click="deleteTarget(item,index)" />
</a-col>
</a-row>
</div>
</a-form-item>
<a-form-item label="代理服务端" :label-col="labelCol" :wrapper-col="wrapperCol">
<div>
<a-row :gutter="10" style="">
<a-col :span="22">
<span>Nginx二层代理服务端配置</span>
</a-col>
<a-col :span="2">
<a-button type="primary" icon="plus" @click="addServer()" />
</a-col>
</a-row>
<a-row :gutter="10" v-for="(item,index) of servers" :key = 'index'>
<a-col :span="8">
<a-input addon-before="" placeholder="yourdomain.com" v-model="item.key"></a-input>
</a-col>
<a-col :span="7">
<a-input addon-before="" placeholder="xxxxxx" v-model="item.value.path"/>
</a-col>
<a-col :span="7">
<a-input addon-before="" type="password" placeholder="password" v-model="item.value.password"/>
</a-col>
<a-col :span="2">
<a-button type="danger" icon="minus" @click="deleteServer(item,index)" />
</a-col>
</a-row>
<div>您可以在此处配置你自己的服务器地址</div>
</div>
</a-form-item>
</a-form>
</div>
<template slot="footer">
<div class="footer-bar">
<a-button class="md-mr-10" icon="sync" @click="resetDefault()"></a-button>
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()"></a-button>
</div>
</template>
</ds-container>
</template>
<script>
import Plugin from '../../mixins/plugin'
export default {
name: 'Overwall',
mixins: [Plugin],
data () {
return {
key: 'plugin.overwall',
targets: undefined,
servers: undefined
}
},
created () {
console.log('status:', this.status)
},
mounted () {
},
methods: {
openExternal (url) {
this.$api.ipc.openExternal(url)
},
async applyAfter () {
if (this.status.server.enabled) {
return this.$api.server.restart()
}
},
ready () {
this.initTarget()
this.initServer()
},
async applyBefore () {
this.saveTarget()
this.saveServer()
},
initTarget () {
this.targets = []
const targetsMap = this.config.plugin.overwall.targets
for (const key in targetsMap) {
const value = targetsMap[key]
this.targets.push({
key, value
})
}
},
deleteTarget (item, index) {
this.targets.splice(index, 1)
},
addTarget () {
this.targets.unshift({ key: '', value: true })
},
saveTarget () {
const map = {}
for (const item of this.targets) {
if (item.key) {
map[item.key] = item.value
}
}
this.config.plugin.overwall.targets = map
},
initServer () {
this.servers = []
const targetsMap = this.config.plugin.overwall.server
for (const key in targetsMap) {
const value = targetsMap[key]
this.servers.push({
key, value
})
}
if (this.servers.length === 0) {
this.addServer()
}
},
deleteServer (item, index) {
this.servers.splice(index, 1)
},
addServer () {
this.servers.unshift({ key: '', value: { type: 'path' } })
},
saveServer () {
const map = {}
for (const item of this.servers) {
if (item.key) {
map[item.key] = item.value
}
}
this.config.plugin.overwall.server = map
}
}
}
</script>
<style lang="sass">
</style>

View File

@ -38,8 +38,8 @@
<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-input-search addon-before="Cert" enter-button="" @search="onCrtSelect" v-model="config.server.setting.rootCaFile.certPath" />
<a-input-search addon-before="Key" enter-button="" @search="onKeySelect" v-model="config.server.setting.rootCaFile.keyPath" />
</a-form-item>
<a-form-item label="启用脚本" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-tooltip title="关闭后github的clone加速链接复制也将关闭">
@ -112,6 +112,18 @@ export default {
mounted () {
},
methods: {
async onCrtSelect () {
const value = await this.$api.fileSelector.open()
if (value != null && value.length > 0) {
this.config.server.setting.rootCaFile.certPath = value[0]
}
},
async onKeySelect () {
const value = await this.$api.fileSelector.open()
if (value != null && value.length > 0) {
this.config.server.setting.rootCaFile.keyPath = value[0]
}
},
onJsonChange (json) {
},
ready () {
@ -148,7 +160,7 @@ export default {
},
async openLog () {
const dir = await this.$api.info.getConfigDir()
this.$api.ipc.openPath(dir + '/logs/server.log')
this.$api.ipc.openPath(dir + '/logs/')
}
}
}

View File

@ -2,13 +2,17 @@ import Index from '../pages/index'
import Server from '../pages/server'
import Proxy from '../pages/proxy'
import Node from '../pages/plugin/node'
import Git from '../pages/plugin/git'
import Overwall from '../pages/plugin/overwall'
const routes = [
{ path: '/', redirect: '/index' },
{ path: '/index', component: Index },
{ path: '/server', component: Server },
{ path: '/proxy', component: Proxy },
{ path: '/plugin/node', component: Node }
{ path: '/plugin/node', component: Node },
{ path: '/plugin/git', component: Git },
{ path: '/plugin/overwall', component: Overwall }
]

View File

@ -0,0 +1,21 @@
export default function createMenus (app) {
const plugins = [
{ title: 'NPM加速', path: '/plugin/node', icon: 'like' },
{ title: 'Git代理', path: '/plugin/git', icon: 'github' }
]
const menus = [
{ title: '首页', path: '/index', icon: 'home' },
{ title: '加速服务', path: '/server', icon: 'thunderbolt' },
{ title: '系统代理', path: '/proxy', icon: 'deployment-unit' },
{
title: '应用',
path: '/plugin',
icon: 'api',
children: plugins
}
]
if (app.$global && app.$global.setting && app.$global.setting.overwall) {
plugins.push({ title: '功能增强', path: '/plugin/overwall', icon: 'global' })
}
return menus
}

View File

@ -36,3 +36,10 @@
.md-mb-10{margin-bottom: 10px;}
.md-mb-15{margin-bottom: 15px;}
.md-mb-20{margin-bottom: 20px;}
ol{
margin-block-start: 0em;
margin-block-end: 0em;
padding-inline-start: 20px;
}

View File

@ -901,12 +901,12 @@
ajv "^6.12.0"
ajv-keywords "^3.4.1"
"@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==
"@docmirror/dev-sidecar@^1.2.2":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@docmirror/dev-sidecar/-/dev-sidecar-1.2.2.tgz#4963a9dd9f3f46e614e1c1479887b8680f0f6650"
integrity sha512-gWD5WPuyijIuFrpinMR0QSLdqdhLEfZVi9lnRSor9TnnaoBpeY6QlufHACpDDo6hME8f62adXGFmL3UoFJS49Q==
dependencies:
"@docmirror/mitmproxy" "^1.2.0"
"@docmirror/mitmproxy" "^1.2.2"
agentkeepalive "^2.1.1"
charset "^1.0.0"
child_process "^1.0.2"
@ -933,10 +933,10 @@
validator "^13.1.17"
winreg "^1.2.4"
"@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==
"@docmirror/mitmproxy@^1.2.2":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@docmirror/mitmproxy/-/mitmproxy-1.2.2.tgz#a4d0020e073eaa68adb7902b5634ab2a1a3bc058"
integrity sha512-xW1xyqUfpGAZZTzqSjoQM0Mmq8VVEyvS8AiTUBvgpxUAYG2sqNCacLETwYfNBP1MStUBtGXKklcISpIY6+R+DA==
dependencies:
agentkeepalive "^2.1.1"
child_process "^1.0.2"

View File

@ -1,6 +1,6 @@
{
"name": "@docmirror/mitmproxy",
"version": "1.2.1",
"version": "1.3.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "@docmirror/mitmproxy",
"version": "1.2.1",
"version": "1.3.0",
"description": "",
"main": "src/index.js",
"keywords": [

View File

@ -39,7 +39,7 @@ class DynamicChoice {
if (this.count[item]) {
continue
}
this.count[item] = { value: item, total: defaultTotal, error: 0, keepErrorCount: 0, successRate: 1 }
this.count[item] = { value: item, total: defaultTotal, error: 0, keepErrorCount: 0, successRate: 0.5 }
defaultTotal--
}
this.value = backupList.shift()

View File

@ -4,13 +4,11 @@ module.exports = {
const { rOptions, log, RequestCounter } = context
let proxyConf = interceptOpt.proxy
if (RequestCounter && interceptOpt.backup) {
if (RequestCounter && interceptOpt.backup && interceptOpt.backup.length > 0) {
// 优选逻辑
const backup = [proxyConf]
if (interceptOpt.backup) {
for (const bk of interceptOpt.backup) {
backup.push(bk)
}
for (const bk of interceptOpt.backup) {
backup.push(bk)
}
const key = interceptOpt.key
@ -36,6 +34,9 @@ module.exports = {
const regexp = new RegExp(interceptOpt.replace)
proxyTarget = req.url.replace(regexp, proxyConf)
}
// eslint-disable-next-line no-template-curly-in-string
proxyTarget = proxyTarget.replace('${host}', rOptions.hostname)
// const backup = interceptOpt.backup
const proxy = proxyTarget.indexOf('http') === 0 ? proxyTarget : rOptions.protocol + '//' + proxyTarget
// eslint-disable-next-line node/no-deprecated-api
@ -49,7 +50,10 @@ module.exports = {
rOptions.port = rOptions.protocol === 'https:' ? 443 : 80
}
log.info('proxy:', rOptions.hostname, proxyTarget)
log.debug('proxy choice:', JSON.stringify(context.requestCount))
if (context.requestCount) {
log.debug('proxy choice:', JSON.stringify(context.requestCount))
}
return true
},
is (interceptOpt) {

View File

@ -71,6 +71,7 @@ const api = {
load (rootDir) {
scripts = {}
scripts.github = loadScript(readFile(rootDir, 'github.script'))
scripts.google = loadScript(readFile(rootDir, 'google.js'))
scripts.jquery = { script: readFile(rootDir, 'jquery.min.js') }
scripts.global = { script: readFile(rootDir, 'global.script') }
return scripts

View File

@ -48,6 +48,7 @@ function injectScriptIntoHtml (tags, chunk, script) {
if (index < 0) {
continue
}
console.log('insert script:', tag)
const scriptBuf = Buffer.from(script)
const chunkNew = Buffer.alloc(chunk.length + scriptBuf.length)
chunk.copy(chunkNew, 0, 0, index)

View File

@ -0,0 +1,93 @@
const url = require('url')
const pac = require('./source/pac')
const matchUtil = require('../../../utils/util.match')
const lodash = require('lodash')
function matched (hostname, regexpMap) {
const ret1 = matchUtil.matchHostname(regexpMap, hostname)
if (ret1) {
return true
}
const ret = pac.FindProxyForURL('https://' + hostname, hostname)
if (ret && ret.indexOf('PROXY ') === 0) {
return true
}
return false
}
module.exports = function createOverWallIntercept (overWallConfig) {
if (!overWallConfig || overWallConfig.enabled !== true) {
return null
}
let server = overWallConfig.server
let keys = Object.keys(server)
if (keys.length === 0) {
server = overWallConfig.serverDefault
keys = Object.keys(server)
}
if (keys.length === 0) {
return null
}
const regexpMap = matchUtil.domainMapRegexply(overWallConfig.intercepts)
return {
sslConnectInterceptor: (req, cltSocket, head) => {
const hostname = req.url.split(':')[0]
return matched(hostname, regexpMap)
},
requestIntercept (context, req, res, ssl, next) {
const { rOptions, log, RequestCounter } = context
if (rOptions.protocol === 'http:') {
return
}
const hostname = rOptions.hostname
if (!matched(hostname, regexpMap)) {
return
}
const cacheKey = '__over_wall_proxy__'
let proxyServer = keys[0]
if (RequestCounter && keys.length > 1) {
const count = RequestCounter.getOrCreate(cacheKey, keys)
if (count.value == null) {
count.doRank()
}
if (count.value == null) {
log.error('count value is null', count)
} else {
count.doCount(count.value)
proxyServer = count.value
context.requestCount = {
key: cacheKey,
value: count.value,
count
}
}
}
const domain = proxyServer
const path = server[domain].path
const password = server[domain].password
const proxyTarget = domain + '/' + path + '/' + hostname + req.url
// const backup = interceptOpt.backup
const proxy = proxyTarget.indexOf('http') === 0 ? proxyTarget : (rOptions.protocol + '//' + proxyTarget)
// eslint-disable-next-line node/no-deprecated-api
const URL = url.parse(proxy)
rOptions.protocol = URL.protocol
rOptions.hostname = URL.host
rOptions.host = URL.host
rOptions.headers.host = URL.host
if (password) {
rOptions.headers.dspassword = password
}
rOptions.path = URL.path
if (URL.port == null) {
rOptions.port = rOptions.protocol === 'https:' ? 443 : 80
}
log.info('OverWall:', rOptions.hostname, proxyTarget)
if (context.requestCount) {
log.debug('OverWall choice:', JSON.stringify(context.requestCount))
}
return true
}
}
}

View File

@ -0,0 +1,665 @@
var __PROXY__ = 'PROXY 127.0.0.1:1080;'
var __USERRULES__ = []
const getRules = function () {
let text = require('./pac.txt.js')
text = Buffer.from(text, 'base64').toString()
const rules = []
const arr = text.split('\n')
for (const line of arr) {
const row = line.trim()
if (row === '' || row.indexOf('!') === 0 || row.indexOf('[') === 0) {
continue
}
rules.push(row)
}
return rules
}
var __RULES__ = getRules()
/* eslint-disable */
// Was generated by gfwlist2pac in precise mode
// https://github.com/clowwindy/gfwlist2pac
// 2019-10-06: More 'javascript' way to interaction with main program
// 2019-02-08: Updated to support shadowsocks-windows user rules.
var proxy = __PROXY__;
var userrules = [];
var rules = [];
// convert to abp grammar
for (var i = 0; i < __RULES__.length; i++) {
var s = __RULES__[i];
if (s.substring(0, 2) == "||") s += "^";
rules.push(s);
}
for (var i = 0; i < __USERRULES__.length; i++) {
var s = __USERRULES__[i];
if (s.substring(0, 2) == "||") s += "^";
userrules.push(s);
}
/*
* This file is part of Adblock Plus <http://adblockplus.org/>,
* Copyright (C) 2006-2014 Eyeo GmbH
*
* Adblock Plus is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* Adblock Plus is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
*/
function createDict() {
var result = {};
result.__proto__ = null;
return result;
}
function getOwnPropertyDescriptor(obj, key) {
if (obj.hasOwnProperty(key)) {
return obj[key];
}
return null;
}
function extend(subclass, superclass, definition) {
if (Object.__proto__) {
definition.__proto__ = superclass.prototype;
subclass.prototype = definition;
} else {
var tmpclass = function () {
}, ret;
tmpclass.prototype = superclass.prototype;
subclass.prototype = new tmpclass();
subclass.prototype.constructor = superclass;
for (var i in definition) {
if (definition.hasOwnProperty(i)) {
subclass.prototype[i] = definition[i];
}
}
}
}
function Filter(text) {
this.text = text;
this.subscriptions = [];
}
Filter.prototype = {
text: null,
subscriptions: null,
toString: function () {
return this.text;
}
};
Filter.knownFilters = createDict();
Filter.elemhideRegExp = /^([^\/\*\|\@"!]*?)#(\@)?(?:([\w\-]+|\*)((?:\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\))*)|#([^{}]+))$/;
Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)?$/;
Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/;
Filter.fromText = function (text) {
if (text in Filter.knownFilters) {
return Filter.knownFilters[text];
}
var ret;
if (text.charAt(0) == "!") {
ret = new CommentFilter(text);
} else {
ret = RegExpFilter.fromText(text);
}
Filter.knownFilters[ret.text] = ret;
return ret;
};
function InvalidFilter(text, reason) {
Filter.call(this, text);
this.reason = reason;
}
extend(InvalidFilter, Filter, {
reason: null
});
function CommentFilter(text) {
Filter.call(this, text);
}
extend(CommentFilter, Filter, {});
function ActiveFilter(text, domains) {
Filter.call(this, text);
this.domainSource = domains;
}
extend(ActiveFilter, Filter, {
domainSource: null,
domainSeparator: null,
ignoreTrailingDot: true,
domainSourceIsUpperCase: false,
getDomains: function () {
var prop = getOwnPropertyDescriptor(this, "domains");
if (prop) {
return prop;
}
var domains = null;
if (this.domainSource) {
var source = this.domainSource;
if (!this.domainSourceIsUpperCase) {
source = source.toUpperCase();
}
var list = source.split(this.domainSeparator);
if (list.length == 1 && (list[0]).charAt(0) != "~") {
domains = createDict();
domains[""] = false;
if (this.ignoreTrailingDot) {
list[0] = list[0].replace(/\.+$/, "");
}
domains[list[0]] = true;
} else {
var hasIncludes = false;
for (var i = 0; i < list.length; i++) {
var domain = list[i];
if (this.ignoreTrailingDot) {
domain = domain.replace(/\.+$/, "");
}
if (domain == "") {
continue;
}
var include;
if (domain.charAt(0) == "~") {
include = false;
domain = domain.substr(1);
} else {
include = true;
hasIncludes = true;
}
if (!domains) {
domains = createDict();
}
domains[domain] = include;
}
domains[""] = !hasIncludes;
}
this.domainSource = null;
}
return this.domains;
},
sitekeys: null,
isActiveOnDomain: function (docDomain, sitekey) {
if (this.getSitekeys() && (!sitekey || this.getSitekeys().indexOf(sitekey.toUpperCase()) < 0)) {
return false;
}
if (!this.getDomains()) {
return true;
}
if (!docDomain) {
return this.getDomains()[""];
}
if (this.ignoreTrailingDot) {
docDomain = docDomain.replace(/\.+$/, "");
}
docDomain = docDomain.toUpperCase();
while (true) {
if (docDomain in this.getDomains()) {
return this.domains[docDomain];
}
var nextDot = docDomain.indexOf(".");
if (nextDot < 0) {
break;
}
docDomain = docDomain.substr(nextDot + 1);
}
return this.domains[""];
},
isActiveOnlyOnDomain: function (docDomain) {
if (!docDomain || !this.getDomains() || this.getDomains()[""]) {
return false;
}
if (this.ignoreTrailingDot) {
docDomain = docDomain.replace(/\.+$/, "");
}
docDomain = docDomain.toUpperCase();
for (var domain in this.getDomains()) {
if (this.domains[domain] && domain != docDomain && (domain.length <= docDomain.length || domain.indexOf("." + docDomain) != domain.length - docDomain.length - 1)) {
return false;
}
}
return true;
}
});
function RegExpFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys) {
ActiveFilter.call(this, text, domains, sitekeys);
if (contentType != null) {
this.contentType = contentType;
}
if (matchCase) {
this.matchCase = matchCase;
}
if (thirdParty != null) {
this.thirdParty = thirdParty;
}
if (sitekeys != null) {
this.sitekeySource = sitekeys;
}
if (regexpSource.length >= 2 && regexpSource.charAt(0) == "/" && regexpSource.charAt(regexpSource.length - 1) == "/") {
var regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), this.matchCase ? "" : "i");
this.regexp = regexp;
} else {
this.regexpSource = regexpSource;
}
}
extend(RegExpFilter, ActiveFilter, {
domainSourceIsUpperCase: true,
length: 1,
domainSeparator: "|",
regexpSource: null,
getRegexp: function () {
var prop = getOwnPropertyDescriptor(this, "regexp");
if (prop) {
return prop;
}
var source = this.regexpSource.replace(/\*+/g, "*").replace(/\^\|$/, "^").replace(/\W/g, "\\$&").replace(/\\\*/g, ".*").replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\x60\\x7B-\\x7F]|$)").replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?").replace(/^\\\|/, "^").replace(/\\\|$/, "$").replace(/^(\.\*)/, "").replace(/(\.\*)$/, "");
var regexp = new RegExp(source, this.matchCase ? "" : "i");
this.regexp = regexp;
return regexp;
},
contentType: 2147483647,
matchCase: false,
thirdParty: null,
sitekeySource: null,
getSitekeys: function () {
var prop = getOwnPropertyDescriptor(this, "sitekeys");
if (prop) {
return prop;
}
var sitekeys = null;
if (this.sitekeySource) {
sitekeys = this.sitekeySource.split("|");
this.sitekeySource = null;
}
this.sitekeys = sitekeys;
return this.sitekeys;
},
matches: function (location, contentType, docDomain, thirdParty, sitekey) {
if (this.getRegexp().test(location) && this.isActiveOnDomain(docDomain, sitekey)) {
return true;
}
return false;
}
});
RegExpFilter.prototype["0"] = "#this";
RegExpFilter.fromText = function (text) {
var blocking = true;
var origText = text;
if (text.indexOf("@@") == 0) {
blocking = false;
text = text.substr(2);
}
var contentType = null;
var matchCase = null;
var domains = null;
var sitekeys = null;
var thirdParty = null;
var collapse = null;
var options;
var match = text.indexOf("$") >= 0 ? Filter.optionsRegExp.exec(text) : null;
if (match) {
options = match[1].toUpperCase().split(",");
text = match.input.substr(0, match.index);
for (var _loopIndex6 = 0; _loopIndex6 < options.length; ++_loopIndex6) {
var option = options[_loopIndex6];
var value = null;
var separatorIndex = option.indexOf("=");
if (separatorIndex >= 0) {
value = option.substr(separatorIndex + 1);
option = option.substr(0, separatorIndex);
}
option = option.replace(/-/, "_");
if (option in RegExpFilter.typeMap) {
if (contentType == null) {
contentType = 0;
}
contentType |= RegExpFilter.typeMap[option];
} else if (option.charAt(0) == "~" && option.substr(1) in RegExpFilter.typeMap) {
if (contentType == null) {
contentType = RegExpFilter.prototype.contentType;
}
contentType &= ~RegExpFilter.typeMap[option.substr(1)];
} else if (option == "MATCH_CASE") {
matchCase = true;
} else if (option == "~MATCH_CASE") {
matchCase = false;
} else if (option == "DOMAIN" && typeof value != "undefined") {
domains = value;
} else if (option == "THIRD_PARTY") {
thirdParty = true;
} else if (option == "~THIRD_PARTY") {
thirdParty = false;
} else if (option == "COLLAPSE") {
collapse = true;
} else if (option == "~COLLAPSE") {
collapse = false;
} else if (option == "SITEKEY" && typeof value != "undefined") {
sitekeys = value;
} else {
return new InvalidFilter(origText, "Unknown option " + option.toLowerCase());
}
}
}
if (!blocking && (contentType == null || contentType & RegExpFilter.typeMap.DOCUMENT) && (!options || options.indexOf("DOCUMENT") < 0) && !/^\|?[\w\-]+:/.test(text)) {
if (contentType == null) {
contentType = RegExpFilter.prototype.contentType;
}
contentType &= ~RegExpFilter.typeMap.DOCUMENT;
}
try {
if (blocking) {
return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys, collapse);
} else {
return new WhitelistFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys);
}
} catch (e) {
return new InvalidFilter(origText, e);
}
};
RegExpFilter.typeMap = {
OTHER: 1,
SCRIPT: 2,
IMAGE: 4,
STYLESHEET: 8,
OBJECT: 16,
SUBDOCUMENT: 32,
DOCUMENT: 64,
XBL: 1,
PING: 1,
XMLHTTPREQUEST: 2048,
OBJECT_SUBREQUEST: 4096,
DTD: 1,
MEDIA: 16384,
FONT: 32768,
BACKGROUND: 4,
POPUP: 268435456,
ELEMHIDE: 1073741824
};
RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.ELEMHIDE | RegExpFilter.typeMap.POPUP);
function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys, collapse) {
RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys);
this.collapse = collapse;
}
extend(BlockingFilter, RegExpFilter, {
collapse: null
});
function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys) {
RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys);
}
extend(WhitelistFilter, RegExpFilter, {});
function Matcher() {
this.clear();
}
Matcher.prototype = {
filterByKeyword: null,
keywordByFilter: null,
clear: function () {
this.filterByKeyword = createDict();
this.keywordByFilter = createDict();
},
add: function (filter) {
if (filter.text in this.keywordByFilter) {
return;
}
var keyword = this.findKeyword(filter);
var oldEntry = this.filterByKeyword[keyword];
if (typeof oldEntry == "undefined") {
this.filterByKeyword[keyword] = filter;
} else if (oldEntry.length == 1) {
this.filterByKeyword[keyword] = [oldEntry, filter];
} else {
oldEntry.push(filter);
}
this.keywordByFilter[filter.text] = keyword;
},
remove: function (filter) {
if (!(filter.text in this.keywordByFilter)) {
return;
}
var keyword = this.keywordByFilter[filter.text];
var list = this.filterByKeyword[keyword];
if (list.length <= 1) {
delete this.filterByKeyword[keyword];
} else {
var index = list.indexOf(filter);
if (index >= 0) {
list.splice(index, 1);
if (list.length == 1) {
this.filterByKeyword[keyword] = list[0];
}
}
}
delete this.keywordByFilter[filter.text];
},
findKeyword: function (filter) {
var result = "";
var text = filter.text;
if (Filter.regexpRegExp.test(text)) {
return result;
}
var match = Filter.optionsRegExp.exec(text);
if (match) {
text = match.input.substr(0, match.index);
}
if (text.substr(0, 2) == "@@") {
text = text.substr(2);
}
var candidates = text.toLowerCase().match(/[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/g);
if (!candidates) {
return result;
}
var hash = this.filterByKeyword;
var resultCount = 16777215;
var resultLength = 0;
for (var i = 0, l = candidates.length; i < l; i++) {
var candidate = candidates[i].substr(1);
var count = candidate in hash ? hash[candidate].length : 0;
if (count < resultCount || count == resultCount && candidate.length > resultLength) {
result = candidate;
resultCount = count;
resultLength = candidate.length;
}
}
return result;
},
hasFilter: function (filter) {
return filter.text in this.keywordByFilter;
},
getKeywordForFilter: function (filter) {
if (filter.text in this.keywordByFilter) {
return this.keywordByFilter[filter.text];
} else {
return null;
}
},
_checkEntryMatch: function (keyword, location, contentType, docDomain, thirdParty, sitekey) {
var list = this.filterByKeyword[keyword];
for (var i = 0; i < list.length; i++) {
var filter = list[i];
if (filter == "#this") {
filter = list;
}
if (filter.matches(location, contentType, docDomain, thirdParty, sitekey)) {
return filter;
}
}
return null;
},
matchesAny: function (location, contentType, docDomain, thirdParty, sitekey) {
var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
if (candidates === null) {
candidates = [];
}
candidates.push("");
for (var i = 0, l = candidates.length; i < l; i++) {
var substr = candidates[i];
if (substr in this.filterByKeyword) {
var result = this._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey);
if (result) {
return result;
}
}
}
return null;
}
};
function CombinedMatcher() {
this.blacklist = new Matcher();
this.whitelist = new Matcher();
this.resultCache = createDict();
}
CombinedMatcher.maxCacheEntries = 1000;
CombinedMatcher.prototype = {
blacklist: null,
whitelist: null,
resultCache: null,
cacheEntries: 0,
clear: function () {
this.blacklist.clear();
this.whitelist.clear();
this.resultCache = createDict();
this.cacheEntries = 0;
},
add: function (filter) {
if (filter instanceof WhitelistFilter) {
this.whitelist.add(filter);
} else {
this.blacklist.add(filter);
}
if (this.cacheEntries > 0) {
this.resultCache = createDict();
this.cacheEntries = 0;
}
},
remove: function (filter) {
if (filter instanceof WhitelistFilter) {
this.whitelist.remove(filter);
} else {
this.blacklist.remove(filter);
}
if (this.cacheEntries > 0) {
this.resultCache = createDict();
this.cacheEntries = 0;
}
},
findKeyword: function (filter) {
if (filter instanceof WhitelistFilter) {
return this.whitelist.findKeyword(filter);
} else {
return this.blacklist.findKeyword(filter);
}
},
hasFilter: function (filter) {
if (filter instanceof WhitelistFilter) {
return this.whitelist.hasFilter(filter);
} else {
return this.blacklist.hasFilter(filter);
}
},
getKeywordForFilter: function (filter) {
if (filter instanceof WhitelistFilter) {
return this.whitelist.getKeywordForFilter(filter);
} else {
return this.blacklist.getKeywordForFilter(filter);
}
},
isSlowFilter: function (filter) {
var matcher = filter instanceof WhitelistFilter ? this.whitelist : this.blacklist;
if (matcher.hasFilter(filter)) {
return !matcher.getKeywordForFilter(filter);
} else {
return !matcher.findKeyword(filter);
}
},
matchesAnyInternal: function (location, contentType, docDomain, thirdParty, sitekey) {
var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
if (candidates === null) {
candidates = [];
}
candidates.push("");
var blacklistHit = null;
for (var i = 0, l = candidates.length; i < l; i++) {
var substr = candidates[i];
if (substr in this.whitelist.filterByKeyword) {
var result = this.whitelist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey);
if (result) {
return result;
}
}
if (substr in this.blacklist.filterByKeyword && blacklistHit === null) {
blacklistHit = this.blacklist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey);
}
}
return blacklistHit;
},
matchesAny: function (location, docDomain) {
var key = location + " " + docDomain + " ";
if (key in this.resultCache) {
return this.resultCache[key];
}
var result = this.matchesAnyInternal(location, 0, docDomain, null, null);
if (this.cacheEntries >= CombinedMatcher.maxCacheEntries) {
this.resultCache = createDict();
this.cacheEntries = 0;
}
this.resultCache[key] = result;
this.cacheEntries++;
return result;
}
};
var userrulesMatcher = new CombinedMatcher();
var defaultMatcher = new CombinedMatcher();
var direct = 'DIRECT;';
for (var i = 0; i < userrules.length; i++) {
userrulesMatcher.add(Filter.fromText(userrules[i]));
}
for (var i = 0; i < rules.length; i++) {
defaultMatcher.add(Filter.fromText(rules[i]));
}
function FindProxyForURL(url, host) {
if (userrulesMatcher.matchesAny(url, host) instanceof BlockingFilter) {
return proxy;
}
if (userrulesMatcher.matchesAny(url, host) instanceof WhitelistFilter) {
return direct;
}
// Hack for Geosite, it provides a whitelist...
if (defaultMatcher.matchesAny(url, host) instanceof WhitelistFilter) {
return direct;
}
if (defaultMatcher.matchesAny(url, host) instanceof BlockingFilter) {
return proxy;
}
return direct;
}
module.exports = {
FindProxyForURL
}

File diff suppressed because one or more lines are too long

View File

@ -5,14 +5,32 @@ const log = require('../../../utils/util.log')
const DnsUtil = require('../../dns/index')
const localIP = '127.0.0.1'
const defaultDns = require('dns')
function isSslConnect (sslConnectInterceptors, req, cltSocket, head) {
for (const intercept of sslConnectInterceptors) {
const ret = intercept(req, cltSocket, head)
if (ret) {
return true
}
}
return false
}
// create connectHandler function
module.exports = function createConnectHandler (sslConnectInterceptor, fakeServerCenter, dnsConfig) {
module.exports = function createConnectHandler (sslConnectInterceptor, middlewares, fakeServerCenter, dnsConfig) {
// return
const sslConnectInterceptors = []
sslConnectInterceptors.push(sslConnectInterceptor)
for (const middleware of middlewares) {
if (middleware.sslConnectInterceptor) {
sslConnectInterceptors.push(middleware.sslConnectInterceptor)
}
}
return function connectHandler (req, cltSocket, head) {
// eslint-disable-next-line node/no-deprecated-api
const srvUrl = url.parse(`https://${req.url}`)
const hostname = srvUrl.hostname
if (typeof sslConnectInterceptor === 'function' && sslConnectInterceptor(req, cltSocket, head)) {
if (isSslConnect(sslConnectInterceptors, req, cltSocket, head)) {
fakeServerCenter.getServerPromise(hostname, srvUrl.port).then((serverObj) => {
connect(req, cltSocket, head, localIP, serverObj.port)
}, (e) => {

View File

@ -6,10 +6,12 @@ const DnsUtil = require('../../dns/index')
const log = require('../../../utils/util.log')
const RequestCounter = require('../../choice/RequestCounter')
const InsertScriptMiddleware = require('../middleware/InsertScriptMiddleware')
const OverWallMiddleware = require('../middleware/overwall')
const defaultDns = require('dns')
const MAX_SLOW_TIME = 8000 // 超过此时间 则认为太慢了
// create requestHandler function
module.exports = function createRequestHandler (createIntercepts, externalProxy, dnsConfig, setting) {
module.exports = function createRequestHandler (createIntercepts, middlewares, externalProxy, dnsConfig, setting) {
// return
return function requestHandler (req, res, ssl) {
let proxyReq
@ -44,8 +46,14 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
if (setting.script.enabled) {
reqIncpts.unshift(InsertScriptMiddleware)
}
for (const middleware of middlewares) {
reqIncpts.push(middleware)
}
if (reqIncpts && reqIncpts.length > 0) {
for (const reqIncpt of reqIncpts) {
if (!reqIncpt.requestIntercept) {
continue
}
const goNext = reqIncpt.requestIntercept(context, req, res, ssl, next)
if (goNext) {
next()
@ -200,6 +208,11 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
const next = () => {
resolve()
}
for (const middleware of middlewares) {
if (middleware.responseInterceptor) {
middleware.responseInterceptor(req, res, proxyReq, proxyRes, ssl, next)
}
}
if (!setting.script.enabled) {
next()
return
@ -217,7 +230,6 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
body += append.body
}
}
InsertScriptMiddleware.responseInterceptor(req, res, proxyReq, proxyRes, ssl, next, { head, body })
} else {
next()

View File

@ -38,6 +38,7 @@ module.exports = {
port = ~~port
const requestHandler = createRequestHandler(
createIntercepts,
middlewares,
externalProxy,
dnsConfig,
setting
@ -55,6 +56,7 @@ module.exports = {
const connectHandler = createConnectHandler(
sslConnectInterceptor,
middlewares,
fakeServersCenter,
dnsConfig
)

View File

@ -1,54 +1,22 @@
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) {
return value
}
if (!value) {
for (const target in hostMap) {
if (target.indexOf('*') < 0) {
continue
}
// 正则表达式匹配
if (hostname.match(target)) {
return hostMap[target]
}
}
}
}
function isMatched (url, regexp) {
return url.match(regexp)
}
function domainRegexply (target) {
return target.replace(/\./g, '\\.').replace(/\*/g, '.*')
}
function domainMapRegexply (hostMap) {
const regexpMap = {}
lodash.each(hostMap, (value, domain) => {
if (domain.indexOf('*') >= 0) {
const regDomain = domainRegexply(domain)
regexpMap[regDomain] = value
} else {
regexpMap[domain] = value
}
})
return regexpMap
}
const matchUtil = require('./utils/util.match')
const createOverwallMiddleware = require('./lib/proxy/middleware/overwall')
module.exports = (config) => {
const intercepts = domainMapRegexply(config.intercepts)
const whiteList = domainMapRegexply(config.whiteList)
const intercepts = matchUtil.domainMapRegexply(config.intercepts)
const whiteList = matchUtil.domainMapRegexply(config.whiteList)
const dnsMapping = config.dns.mapping
const serverConfig = config
const setting = serverConfig.setting
const overwallMiddleware = createOverwallMiddleware(serverConfig.plugin.overwall)
const middlewares = []
if (overwallMiddleware) {
middlewares.push(overwallMiddleware)
}
const options = {
port: serverConfig.port,
dnsConfig: {
@ -56,19 +24,21 @@ module.exports = (config) => {
mapping: dnsMapping
},
setting,
middlewares,
sslConnectInterceptor: (req, cltSocket, head) => {
const hostname = req.url.split(':')[0]
const inWhiteList = matchHostname(whiteList, hostname) != null
const inWhiteList = matchUtil.matchHostname(whiteList, hostname) != null
if (inWhiteList) {
log.info('白名单域名,不拦截', hostname)
return false
}
return !!matchHostname(intercepts, hostname) // 配置了拦截的域名,将会被代理
// 配置了拦截的域名,将会被代理
return !!matchUtil.matchHostname(intercepts, hostname)
},
createIntercepts: (context) => {
const rOptions = context.rOptions
const hostname = rOptions.hostname
const interceptOpts = matchHostname(intercepts, hostname)
const interceptOpts = matchUtil.matchHostname(intercepts, hostname)
if (!interceptOpts) { // 该域名没有配置拦截器,直接过
return
}
@ -78,13 +48,13 @@ module.exports = (config) => {
const interceptOpt = interceptOpts[regexp]
interceptOpt.key = regexp
if (regexp !== true) {
if (!isMatched(rOptions.path, regexp)) {
if (!matchUtil.isMatched(rOptions.path, regexp)) {
continue
}
}
for (const impl of interceptors) {
// 根据拦截配置挑选合适的拦截器来处理
if (impl.is(interceptOpt)) {
if (impl.is && impl.is(interceptOpt)) {
const interceptor = {}
if (impl.requestIntercept) {
// req拦截器

View File

@ -1,8 +1,11 @@
const log4js = require('log4js')
const proxyConfig = require('../lib/proxy/common/config')
const level = process.env.NODE_ENV === 'development' ? 'debug' : 'info'
const path = require('path')
const filename = path.join(proxyConfig.getDefaultCABasePath(), '/logs/server.log')
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' } }
appenders: { std: { type: 'stdout', level: 'debug' }, file: { type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename } },
categories: { default: { appenders: ['file', 'std'], level } }
})
const logger = log4js.getLogger('server')
module.exports = logger

View File

@ -0,0 +1,48 @@
const lodash = require('lodash')
function isMatched (url, regexp) {
return url.match(regexp)
}
function domainRegexply (target) {
return target.replace(/\./g, '\\.').replace(/\*/g, '.*')
}
function domainMapRegexply (hostMap) {
const regexpMap = {}
if (hostMap == null) {
return regexpMap
}
lodash.each(hostMap, (value, domain) => {
if (domain.indexOf('*') >= 0) {
const regDomain = domainRegexply(domain)
regexpMap[regDomain] = value
} else {
regexpMap[domain] = value
}
})
return regexpMap
}
function matchHostname (hostMap, hostname) {
const value = hostMap[hostname]
if (value) {
return value
}
if (!value) {
for (const target in hostMap) {
if (target.indexOf('*') < 0) {
continue
}
// 正则表达式匹配
if (hostname.match(target)) {
return hostMap[target]
}
}
}
}
module.exports = {
isMatched,
domainRegexply,
domainMapRegexply,
matchHostname
}

View File

@ -1,8 +1,12 @@
module.exports = {
fireError (e) {
process.send({ type: 'error', event: e })
if (process.send) {
process.send({ type: 'error', event: e })
}
},
fireStatus (status) {
process.send({ type: 'status', event: status })
if (process.send) {
process.send({ type: 'status', event: status })
}
}
}

View File

@ -30,3 +30,5 @@ const hostname4 = 'gh.docmirror.top'
dnsProviders.usa.lookup(hostname4)
const hostname5 = 'gh2.docmirror.top'
dnsProviders.usa.lookup(hostname5)

View File

@ -15,3 +15,6 @@ chunk.copy(chunkNew, 0, 0, index)
scriptBuf.copy(chunkNew, index, 0)
chunk.copy(chunkNew, index + scriptBuf.length, index)
console.log(chunkNew.toString())
const reg2 = '/aaaa/i'
console.log(new RegExp(reg2).test('aaaa'))

View File

@ -0,0 +1,6 @@
const pac = require('../src/lib/proxy/middleware/source/pac')
const string = pac.FindProxyForURL('https://www.facebook.com', 'www.facebook.com')
console.log(string)
const string2 = pac.FindProxyForURL('https://http2.golang.org', 'http2.golang.org')
console.log(string2)