fix Style

1.x
王良 2024-11-15 16:31:17 +08:00
parent 47b4e119e4
commit 30889f6645
115 changed files with 876 additions and 750 deletions

View File

@ -3,5 +3,5 @@ module.exports = require('./src')
// TODO 这是一个解谜游戏 ↓ ↓ ↓ ↓ ↓ ↓ ,如果你破解了它,请不要公开,好好用它来学习和查资料吧(特别注意:为了你的人身安全,请不要用它来查看和发表不当言论,你懂得)。 // TODO 这是一个解谜游戏 ↓ ↓ ↓ ↓ ↓ ↓ ,如果你破解了它,请不要公开,好好用它来学习和查资料吧(特别注意:为了你的人身安全,请不要用它来查看和发表不当言论,你懂得)。
/** /**
\u0061\u0048\u0052\u0030\u0063\u0044\u006f\u0076\u004c\u0032\u0052\u006c\u0064\u0069\u0031\u007a\u0061\u0057\u0052\u006c\u0059\u0032\u0046\u0079\u004c\u006d\u0052\u0076\u0059\u0032\u0031\u0070\u0063\u006e\u004a\u0076\u0063\u0069\u0035\u006a\u0062\u0069\u0039\u0035\u0062\u0033\u0056\u006d\u0061\u0057\u0035\u006b\u0061\u0058\u0051\u0076\u0061\u0057\u0035\u006b\u005a\u0058\u0067\u0075\u0061\u0048\u0052\u0074\u0062\u0041\u003d\u003d \u0061\u0048\u0052\u0030\u0063\u0044\u006f\u0076\u004c\u0032\u0052\u006c\u0064\u0069\u0031\u007a\u0061\u0057\u0052\u006c\u0059\u0032\u0046\u0079\u004c\u006d\u0052\u0076\u0059\u0032\u0031\u0070\u0063\u006e\u004a\u0076\u0063\u0069\u0035\u006a\u0062\u0069\u0039\u0035\u0062\u0033\u0056\u006d\u0061\u0057\u0035\u006b\u0061\u0058\u0051\u0076\u0061\u0057\u0035\u006b\u005a\u0058\u0067\u0075\u0061\u0048\u0052\u0074\u0062\u0041\u003d\u003d
**/ */
// 这个项目里有一点点解谜提示: https://github.com/fast-crud/fast-crud (打开拉到最下面) // 这个项目里有一点点解谜提示: https://github.com/fast-crud/fast-crud (打开拉到最下面)

View File

@ -1,12 +1,12 @@
const fs = require('fs') const fs = require('fs')
const Shell = require('./shell')
const lodash = require('lodash')
const defConfig = require('./config/index.js')
const jsonApi = require('@docmirror/mitmproxy/src/json')
const request = require('request')
const path = require('path') const path = require('path')
const log = require('./utils/util.log') const jsonApi = require('@docmirror/mitmproxy/src/json')
const lodash = require('lodash')
const request = require('request')
const defConfig = require('./config/index.js')
const mergeApi = require('./merge.js') const mergeApi = require('./merge.js')
const Shell = require('./shell')
const log = require('./utils/util.log')
let configTarget = lodash.cloneDeep(defConfig) let configTarget = lodash.cloneDeep(defConfig)
@ -80,7 +80,7 @@ const configApi = {
configApi.deleteRemoteConfigFile(suffix) configApi.deleteRemoteConfigFile(suffix)
return return
} }
// eslint-disable-next-line handle-callback-err
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
log.info('开始下载远程配置:', remoteConfigUrl) log.info('开始下载远程配置:', remoteConfigUrl)
@ -131,7 +131,7 @@ const configApi = {
if (response) { if (response) {
message = `下载远程配置失败: ${remoteConfigUrl}, message: ${response.message}, code: ${response.statusCode}` message = `下载远程配置失败: ${remoteConfigUrl}, message: ${response.message}, code: ${response.statusCode}`
} else { } else {
message = '下载远程配置失败: response: ' + response message = `下载远程配置失败: response: ${response}`
} }
reject(new Error(message)) reject(new Error(message))
} }
@ -337,7 +337,7 @@ const configApi = {
}, },
async setVariables (type) { async setVariables (type) {
const list = await configApi.getVariables(type) const list = await configApi.getVariables(type)
const noSetList = list.filter(item => { const noSetList = list.filter((item) => {
return !item.exists return !item.exists
}) })
if (list.length > 0) { if (list.length > 0) {
@ -345,9 +345,9 @@ const configApi = {
root_ca_cert_path: configApi.get().server.setting.rootCaFile.certPath root_ca_cert_path: configApi.get().server.setting.rootCaFile.certPath
} }
for (const item of noSetList) { for (const item of noSetList) {
if (item.value.indexOf('${') >= 0) { if (item.value.includes('${')) {
for (const key in context) { for (const key in context) {
item.value = item.value.replcace(new RegExp('${' + key + '}', 'g'), context[key]) item.value = item.value.replcace(new RegExp(`\${${key}}`, 'g'), context[key])
} }
} }
} }

View File

@ -1,10 +1,11 @@
const status = require('./status') const lodash = require('lodash')
const config = require('./config') const config = require('./config')
const event = require('./event') const event = require('./event')
const shell = require('./shell')
const modules = require('./modules') const modules = require('./modules')
const lodash = require('lodash') const shell = require('./shell')
const status = require('./status')
const log = require('./utils/util.log') const log = require('./utils/util.log')
const context = { const context = {
config, config,
shell, shell,
@ -29,14 +30,14 @@ const proxy = setupPlugin('proxy', modules.proxy, context, config)
const plugin = {} const plugin = {}
for (const key in modules.plugin) { for (const key in modules.plugin) {
const target = modules.plugin[key] const target = modules.plugin[key]
const api = setupPlugin('plugin.' + key, target, context, config) const api = setupPlugin(`plugin.${key}`, target, context, config)
plugin[key] = api plugin[key] = api
} }
config.resetDefault() config.resetDefault()
const server = modules.server const server = modules.server
const serverStart = server.start const serverStart = server.start
const newServerStart = ({ mitmproxyPath }) => { function newServerStart ({ mitmproxyPath }) {
return serverStart({ mitmproxyPath, plugins: plugin }) return serverStart({ mitmproxyPath, plugins: plugin })
} }
server.start = newServerStart server.start = newServerStart

View File

@ -3,7 +3,7 @@ const log = require('./utils/util.log')
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' // process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
// 避免异常崩溃 // 避免异常崩溃
process.on('uncaughtException', function (err) { process.on('uncaughtException', (err) => {
if (err.code === 'ECONNABORTED') { if (err.code === 'ECONNABORTED') {
// console.error(err.errno) // console.error(err.errno)
return return

View File

@ -75,8 +75,8 @@ function deleteNullItems (target) {
} }
module.exports = { module.exports = {
doMerge: function (oldObj, newObj) { doMerge (oldObj, newObj) {
return lodash.mergeWith(oldObj, newObj, function (objValue, srcValue) { return lodash.mergeWith(oldObj, newObj, (objValue, srcValue) => {
if (lodash.isArray(objValue)) { if (lodash.isArray(objValue)) {
return srcValue return srcValue
} }

View File

@ -1,11 +1,5 @@
const server = require('./server')
const proxy = require('./proxy')
const plugin = require('./plugin')
module.exports = { module.exports = {
server, server: require('./server'),
proxy, proxy: require('./proxy'),
plugin plugin: require('./plugin')
} }

View File

@ -1,4 +1,5 @@
const pluginConfig = require('./config') const pluginConfig = require('./config')
const Plugin = function (context) { const Plugin = function (context) {
const { config, shell, event, log } = context const { config, shell, event, log } = context
const pluginApi = { const pluginApi = {

View File

@ -1,8 +1,6 @@
const node = require('./node')
const git = require('./git')
const overwall = require('./overwall')
const pip = require('./pip')
module.exports = { module.exports = {
node, git, pip, overwall node: require('./node'),
git: require('./git'),
pip: require('./pip'),
overwall: require('./overwall')
} }

View File

@ -11,7 +11,7 @@ module.exports = {
cafile: false, cafile: false,
NODE_EXTRA_CA_CERTS: false, NODE_EXTRA_CA_CERTS: false,
NODE_TLS_REJECT_UNAUTHORIZED: false, NODE_TLS_REJECT_UNAUTHORIZED: false,
yarnRegistry: 'null', yarnRegistry: 'default',
registry: 'https://registry.npmjs.org'// 可以选择切换官方或者淘宝镜像 registry: 'https://registry.npmjs.org'// 可以选择切换官方或者淘宝镜像
}, },
// intercepts: { // intercepts: {

View File

@ -1,5 +1,6 @@
const nodeConfig = require('./config')
const jsonApi = require('@docmirror/mitmproxy/src/json') const jsonApi = require('@docmirror/mitmproxy/src/json')
const nodeConfig = require('./config')
const NodePlugin = function (context) { const NodePlugin = function (context) {
const { config, shell, event, log } = context const { config, shell, event, log } = context
const nodeApi = { const nodeApi = {
@ -44,7 +45,7 @@ const NodePlugin = function (context) {
const cmds = [] const cmds = []
for (const item of list) { for (const item of list) {
if (item.value != null && item.value.length > 0 && item.value !== 'null') { if (item.value != null && item.value.length > 0 && item.value !== 'default' && item.value !== 'null') {
cmds.push(`${command} config set ${item.key} ${item.value}`) cmds.push(`${command} config set ${item.key} ${item.value}`)
} else { } else {
cmds.push(`${command} config delete ${item.key}`) cmds.push(`${command} config delete ${item.key}`)
@ -67,7 +68,7 @@ const NodePlugin = function (context) {
const cmds = [] const cmds = []
log.debug('yarn set:', JSON.stringify(list)) log.debug('yarn set:', JSON.stringify(list))
for (const item of list) { for (const item of list) {
if (item.value != null && item.value.length > 0 && item.value !== 'null') { if (item.value != null && item.value.length > 0 && item.value !== 'default' && item.value !== 'null') {
cmds.push(`yarn config set ${item.key} ${item.value}`) cmds.push(`yarn config set ${item.key} ${item.value}`)
} else { } else {
cmds.push(`yarn config delete ${item.key}`) cmds.push(`yarn config delete ${item.key}`)
@ -103,7 +104,7 @@ const NodePlugin = function (context) {
async setVariables () { async setVariables () {
const list = await nodeApi.getVariables() const list = await nodeApi.getVariables()
const noSetList = list.filter(item => { const noSetList = list.filter((item) => {
return !item.exists return !item.exists
}) })
if (noSetList.length > 0) { if (noSetList.length > 0) {

View File

@ -36,14 +36,12 @@ const Plugin = function (context) {
for (const key in conf.targets) { for (const key in conf.targets) {
serverConfig.intercepts[key] = { serverConfig.intercepts[key] = {
'.*': { '.*': {
// eslint-disable-next-line no-template-curly-in-string proxy: `${main}/\${host}`,
proxy: main + '/${host}',
backup backup
} }
} }
} }
} }
} }
return api return api
} }

View File

@ -8,6 +8,6 @@ module.exports = {
setting: { setting: {
command: 'pip', command: 'pip',
trustedHost: 'pypi.org', trustedHost: 'pypi.org',
registry: 'https://pypi.org/simple/'// 可以选择切换官方或者淘宝镜像 registry: 'https://pypi.org/simple/' // 可以选择切换官方或者淘宝镜像
} }
} }

View File

@ -1,4 +1,5 @@
const pipConfig = require('./config') const pipConfig = require('./config')
const PipPlugin = function (context) { const PipPlugin = function (context) {
const { config, shell, event, log } = context const { config, shell, event, log } = context
const api = { const api = {
@ -20,7 +21,7 @@ const PipPlugin = function (context) {
}, },
async getPipEnv () { async getPipEnv () {
const command = config.get().plugin.pip.setting.command const command = config.get().plugin.pip.setting.command
let ret = await shell.exec([command + ' config list'], { type: 'cmd' }) let ret = await shell.exec([`${command} config list`], { type: 'cmd' })
if (ret != null) { if (ret != null) {
ret = ret.trim() ret = ret.trim()
const lines = ret.split('\n') const lines = ret.split('\n')

View File

@ -1,19 +1,19 @@
const lodash = require('lodash')
const config = require('../../config') const config = require('../../config')
const event = require('../../event') const event = require('../../event')
const status = require('../../status') const status = require('../../status')
const lodash = require('lodash')
const fork = require('child_process').fork const fork = require('child_process').fork
const log = require('../../utils/util.log')
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const jsonApi = require('@docmirror/mitmproxy/src/json') const jsonApi = require('@docmirror/mitmproxy/src/json')
const log = require('../../utils/util.log')
let server = null let server = null
function fireStatus (status) { function fireStatus (status) {
event.fire('status', { key: 'server.enabled', value: status }) event.fire('status', { key: 'server.enabled', value: status })
} }
function sleep (time) { function sleep (time) {
return new Promise(resolve => { return new Promise((resolve) => {
setTimeout(() => { setTimeout(() => {
resolve() resolve()
}, time) }, time)
@ -98,7 +98,7 @@ const serverApi = {
serverProcess.on('uncaughtException', (err, origin) => { serverProcess.on('uncaughtException', (err, origin) => {
log.error('server process uncaughtException:', err) log.error('server process uncaughtException:', err)
}) })
serverProcess.on('message', function (msg) { serverProcess.on('message', (msg) => {
log.info('收到子进程消息:', JSON.stringify(msg)) log.info('收到子进程消息:', JSON.stringify(msg))
if (msg.type === 'status') { if (msg.type === 'status') {
fireStatus(msg.event) fireStatus(msg.event)

View File

@ -1,13 +1,14 @@
const shell = require('./shell')
const killByPort = require('./scripts/kill-by-port')
const setupCa = require('./scripts/setup-ca')
const getSystemEnv = require('./scripts/get-system-env')
const setSystemEnv = require('./scripts/set-system-env')
const getNpmEnv = require('./scripts/get-npm-env')
const setNpmEnv = require('./scripts/set-npm-env')
const setSystemProxy = require('./scripts/set-system-proxy/index')
const enableLoopback = require('./scripts/enable-loopback') const enableLoopback = require('./scripts/enable-loopback')
const extraPath = require('./scripts/extra-path') const extraPath = require('./scripts/extra-path')
const getNpmEnv = require('./scripts/get-npm-env')
const getSystemEnv = require('./scripts/get-system-env')
const killByPort = require('./scripts/kill-by-port')
const setNpmEnv = require('./scripts/set-npm-env')
const setSystemEnv = require('./scripts/set-system-env')
const setSystemProxy = require('./scripts/set-system-proxy/index')
const setupCa = require('./scripts/setup-ca')
const shell = require('./shell')
module.exports = { module.exports = {
killByPort, killByPort,
setupCa, setupCa,

View File

@ -2,7 +2,9 @@
*/ */
const Shell = require('../shell') const Shell = require('../shell')
const extraPath = require('./extra-path') const extraPath = require('./extra-path')
const execute = Shell.execute const execute = Shell.execute
const executor = { const executor = {
async windows (exec) { async windows (exec) {
const loopbackPath = extraPath.getEnableLoopbackPath() const loopbackPath = extraPath.getEnableLoopbackPath()
@ -10,10 +12,10 @@ const executor = {
await execFile(loopbackPath) await execFile(loopbackPath)
}, },
async linux (exec, { port }) { async linux (exec, { port }) {
throw Error('不支持此操作') throw new Error('不支持此操作')
}, },
async mac (exec, { port }) { async mac (exec, { port }) {
throw Error('不支持此操作') throw new Error('不支持此操作')
} }
} }

View File

@ -1,5 +1,5 @@
const log = require('../../../utils/util.log')
const path = require('path') const path = require('path')
const log = require('../../../utils/util.log')
function getExtraPath () { function getExtraPath () {
let extraPath = process.env.DS_EXTRA_PATH let extraPath = process.env.DS_EXTRA_PATH

View File

@ -1,9 +1,11 @@
/** /**
* 获取环境变量 * 获取环境变量
*/ */
const Shell = require('../shell')
const jsonApi = require('@docmirror/mitmproxy/src/json') const jsonApi = require('@docmirror/mitmproxy/src/json')
const Shell = require('../shell')
const execute = Shell.execute const execute = Shell.execute
const executor = { const executor = {
async windows (exec) { async windows (exec) {
const ret = await exec(['npm config list --json'], { type: 'cmd' }) const ret = await exec(['npm config list --json'], { type: 'cmd' })
@ -14,10 +16,10 @@ const executor = {
return {} return {}
}, },
async linux (exec, { port }) { async linux (exec, { port }) {
throw Error('暂未实现此功能') throw new Error('暂未实现此功能')
}, },
async mac (exec, { port }) { async mac (exec, { port }) {
throw Error('暂未实现此功能') throw new Error('暂未实现此功能')
} }
} }

View File

@ -2,7 +2,9 @@
* 获取环境变量 * 获取环境变量
*/ */
const Shell = require('../shell') const Shell = require('../shell')
const execute = Shell.execute const execute = Shell.execute
const executor = { const executor = {
async windows (exec) { async windows (exec) {
const ret = await exec(['set'], { type: 'cmd' }) const ret = await exec(['set'], { type: 'cmd' })
@ -19,10 +21,10 @@ const executor = {
return map return map
}, },
async linux (exec, { port }) { async linux (exec, { port }) {
throw Error('暂未实现此功能') throw new Error('暂未实现此功能')
}, },
async mac (exec, { port }) { async mac (exec, { port }) {
throw Error('暂未实现此功能') throw new Error('暂未实现此功能')
} }
} }

View File

@ -1,4 +1,5 @@
const Shell = require('../shell') const Shell = require('../shell')
const execute = Shell.execute const execute = Shell.execute
const executor = { const executor = {
@ -9,11 +10,11 @@ const executor = {
return true return true
}, },
async linux (exec, { port }) { async linux (exec, { port }) {
await exec('kill `lsof -i:' + port + " |grep 'dev-sidecar\\|electron\\|@docmirro' |awk '{print $2}'`") await exec(`kill \`lsof -i:${port} |grep 'dev-sidecar\\|electron\\|@docmirro' |awk '{print $2}'\``)
return true return true
}, },
async mac (exec, { port }) { async mac (exec, { port }) {
await exec('kill `lsof -i:' + port + " |grep 'dev-side\\|Elect' |awk '{print $2}'`") await exec(`kill \`lsof -i:${port} |grep 'dev-side\\|Elect' |awk '{print $2}'\``)
return true return true
} }
} }

View File

@ -2,7 +2,9 @@
* 设置环境变量 * 设置环境变量
*/ */
const Shell = require('../shell') const Shell = require('../shell')
const execute = Shell.execute const execute = Shell.execute
const executor = { const executor = {
async windows (exec, { list }) { async windows (exec, { list }) {
const cmds = [] const cmds = []
@ -13,10 +15,10 @@ const executor = {
return ret return ret
}, },
async linux (exec, { port }) { async linux (exec, { port }) {
throw Error('暂未实现此功能') throw new Error('暂未实现此功能')
}, },
async mac (exec, { port }) { async mac (exec, { port }) {
throw Error('暂未实现此功能') throw new Error('暂未实现此功能')
} }
} }

View File

@ -2,7 +2,9 @@
* 设置环境变量 * 设置环境变量
*/ */
const Shell = require('../shell') const Shell = require('../shell')
const execute = Shell.execute const execute = Shell.execute
const executor = { const executor = {
async windows (exec, { list }) { async windows (exec, { list }) {
const cmds = [] const cmds = []
@ -22,10 +24,10 @@ const executor = {
return ret return ret
}, },
async linux (exec, { port }) { async linux (exec, { port }) {
throw Error('暂未实现此功能') throw new Error('暂未实现此功能')
}, },
async mac (exec, { port }) { async mac (exec, { port }) {
throw Error('暂未实现此功能') throw new Error('暂未实现此功能')
} }
} }

View File

@ -1,16 +1,16 @@
/** /**
* 获取环境变量 * 获取环境变量
*/ */
const Shell = require('../../shell')
const Registry = require('winreg') const Registry = require('winreg')
const Shell = require('../../shell')
const execute = Shell.execute
const execFile = Shell.execFile
const log = require('../../../utils/util.log')
const extraPath = require('../extra-path/index')
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const request = require('request') const request = require('request')
const log = require('../../../utils/util.log')
const extraPath = require('../extra-path/index')
const execute = Shell.execute
const execFile = Shell.execFile
let config = null let config = null
function loadConfig () { function loadConfig () {
@ -20,7 +20,6 @@ function loadConfig () {
} }
async function _winUnsetProxy (exec, setEnv) { async function _winUnsetProxy (exec, setEnv) {
// eslint-disable-next-line no-constant-condition
const proxyPath = extraPath.getProxyExePath() const proxyPath = extraPath.getProxyExePath()
await execFile(proxyPath, ['set', '1']) await execFile(proxyPath, ['set', '1'])
@ -74,12 +73,12 @@ async function downloadDomesticDomainAllowListAsync () {
let fileTxt = body let fileTxt = body
try { try {
if (fileTxt.indexOf('*.') < 0) { if (!fileTxt.includes('*.')) {
fileTxt = Buffer.from(fileTxt, 'base64').toString('utf8') fileTxt = Buffer.from(fileTxt, 'base64').toString('utf8')
// log.debug('解析 base64 后的 domestic-domain-allowlist:', fileTxt) // log.debug('解析 base64 后的 domestic-domain-allowlist:', fileTxt)
} }
} catch (e) { } catch (e) {
if (fileTxt.indexOf('*.') < 0) { if (!fileTxt.includes('*.')) {
log.error(`远程 domestic-domain-allowlist.txt 文件内容即不是base64格式也不是要求的格式url: ${remoteFileUrl}body: ${body}`) log.error(`远程 domestic-domain-allowlist.txt 文件内容即不是base64格式也不是要求的格式url: ${remoteFileUrl}body: ${body}`)
return return
} }
@ -195,7 +194,7 @@ function getProxyExcludeIpStr (split) {
try { try {
let domesticDomainAllowList = getDomesticDomainAllowList() let domesticDomainAllowList = getDomesticDomainAllowList()
if (domesticDomainAllowList) { if (domesticDomainAllowList) {
domesticDomainAllowList = (domesticDomainAllowList + '\n').replaceAll(/[\r\n]+/g, '\n').replaceAll(/[^\n]*[^*.a-zA-Z\d-\n]+[^\n]*\r?\n/g, '').trim().replaceAll(/\s*\n+\s*/g, split) domesticDomainAllowList = (`${domesticDomainAllowList}\n`).replaceAll(/[\r\n]+/g, '\n').replaceAll(/[\d*\-.A-Z]*[^\d\n*\-.A-Z][^\n]*\n/gi, '').trim().replaceAll(/\s*\n\s*/g, split)
if (domesticDomainAllowList) { if (domesticDomainAllowList) {
excludeIpStr += domesticDomainAllowList excludeIpStr += domesticDomainAllowList
log.info('系统代理排除列表拼接国内域名') log.info('系统代理排除列表拼接国内域名')
@ -224,7 +223,7 @@ async function _winSetProxy (exec, ip, port, setEnv) {
let proxyAddr = `https=http://${ip}:${port}` let proxyAddr = `https=http://${ip}:${port}`
// http // http
if (config.get().proxy.proxyHttp) { if (config.get().proxy.proxyHttp) {
proxyAddr = `http=http://${ip}:${port - 1};` + proxyAddr proxyAddr = `http=http://${ip}:${port - 1};${proxyAddr}`
} }
// 读取排除域名 // 读取排除域名
@ -283,12 +282,12 @@ const executor = {
setProxyCmd.push(`gsettings set org.gnome.system.proxy.http host ${ip}`) setProxyCmd.push(`gsettings set org.gnome.system.proxy.http host ${ip}`)
setProxyCmd.push(`gsettings set org.gnome.system.proxy.http port ${port - 1}`) setProxyCmd.push(`gsettings set org.gnome.system.proxy.http port ${port - 1}`)
} else { } else {
setProxyCmd.push("gsettings set org.gnome.system.proxy.http host ''") setProxyCmd.push('gsettings set org.gnome.system.proxy.http host \'\'')
setProxyCmd.push('gsettings set org.gnome.system.proxy.http port 0') setProxyCmd.push('gsettings set org.gnome.system.proxy.http port 0')
} }
// 设置排除域名ignore-hosts // 设置排除域名ignore-hosts
const excludeIpStr = getProxyExcludeIpStr("', '") const excludeIpStr = getProxyExcludeIpStr('\', \'')
setProxyCmd.push(`gsettings set org.gnome.system.proxy ignore-hosts "['${excludeIpStr}']"`) setProxyCmd.push(`gsettings set org.gnome.system.proxy ignore-hosts "['${excludeIpStr}']"`)
await exec(setProxyCmd) await exec(setProxyCmd)

View File

@ -1,22 +1,21 @@
const Shell = require('../shell') const Shell = require('../shell')
const execute = Shell.execute const execute = Shell.execute
const executor = { const executor = {
async windows (exec, { certPath }) { async windows (exec, { certPath }) {
const cmds = ['start "" "' + certPath + '"'] const cmds = [`start "" "${certPath}"`]
// eslint-disable-next-line no-unused-vars await exec(cmds, { type: 'cmd' })
const ret = await exec(cmds, { type: 'cmd' })
return true return true
}, },
async linux (exec, { certPath }) { async linux (exec, { certPath }) {
const cmds = [`sudo cp ${certPath} /usr/local/share/ca-certificates`, 'sudo update-ca-certificates '] const cmds = [`sudo cp ${certPath} /usr/local/share/ca-certificates`, 'sudo update-ca-certificates ']
// eslint-disable-next-line no-unused-vars await exec(cmds)
const ret = await exec(cmds)
return true return true
}, },
async mac (exec, { certPath }) { async mac (exec, { certPath }) {
const cmds = ['open "' + certPath + '"'] const cmds = [`open "${certPath}"`]
// eslint-disable-next-line no-unused-vars await exec(cmds, { type: 'cmd' })
const ret = await exec(cmds, { type: 'cmd' })
return true return true
} }
} }

View File

@ -1,11 +1,14 @@
const os = require('os')
const childProcess = require('child_process') const childProcess = require('child_process')
const _execFile = childProcess.execFile const os = require('os')
const PowerShell = require('node-powershell')
const log = require('../utils/util.log')
const fixPath = require('fix-path') const fixPath = require('fix-path')
const iconv = require('iconv-lite') const iconv = require('iconv-lite')
const PowerShell = require('node-powershell')
const log = require('../utils/util.log')
const _execFile = childProcess.execFile
fixPath() fixPath()
class SystemShell { class SystemShell {
static async exec (cmds, args) { static async exec (cmds, args) {
throw new Error('You have to implement the method exec!') throw new Error('You have to implement the method exec!')
@ -63,7 +66,7 @@ class WindowsSystemShell extends SystemShell {
} else { } else {
let compose = 'echo "test" ' // 'chcp 65001 ' let compose = 'echo "test" ' // 'chcp 65001 '
for (const cmd of cmds) { for (const cmd of cmds) {
compose += ' && ' + cmd compose += ` && ${cmd}`
} }
// compose += '&& exit' // compose += '&& exit'
const ret = await childExec(compose, args) const ret = await childExec(compose, args)
@ -77,7 +80,7 @@ function _childExec (composeCmds, options = {}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const childProcess = require('child_process') const childProcess = require('child_process')
log.info('shell:', composeCmds) log.info('shell:', composeCmds)
childProcess.exec(composeCmds, options, function (error, stdout, stderr) { childProcess.exec(composeCmds, options, (error, stdout, stderr) => {
if (error) { if (error) {
if (options.printErrorLog !== false) { if (options.printErrorLog !== false) {
log.error('cmd 命令执行错误:\n===>\ncommands:', composeCmds, '\n error:', error, '\n<===') log.error('cmd 命令执行错误:\n===>\ncommands:', composeCmds, '\n error:', error, '\n<===')
@ -100,7 +103,7 @@ function childExec (composeCmds, options = {}) {
const childProcess = require('child_process') const childProcess = require('child_process')
log.info('shell:', composeCmds) log.info('shell:', composeCmds)
childProcess.exec(composeCmds, { encoding: binaryEncoding }, function (error, stdout, stderr) { childProcess.exec(composeCmds, { encoding: binaryEncoding }, (error, stdout, stderr) => {
if (error) { if (error) {
// console.log('------', decoder.decode(stderr)) // console.log('------', decoder.decode(stderr))
const message = iconv.decode(Buffer.from(stderr, binaryEncoding), encoding) const message = iconv.decode(Buffer.from(stderr, binaryEncoding), encoding)

View File

@ -34,8 +34,9 @@
// console.error(e) // console.error(e)
// }) // })
const request = require('request')
const fs = require('fs') const fs = require('fs')
const request = require('request')
request({ request({
url: 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js', url: 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js',
proxy: 'http://127.0.0.1:31181', proxy: 'http://127.0.0.1:31181',

View File

@ -1,6 +1,7 @@
const event = require('./event')
const lodash = require('lodash') const lodash = require('lodash')
const event = require('./event')
const log = require('./utils/util.log') const log = require('./utils/util.log')
const status = { const status = {
server: { enabled: false }, server: { enabled: false },
proxy: {}, proxy: {},

View File

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

View File

@ -1,6 +1,6 @@
const fs = require('fs')
const jsonApi = require('@docmirror/mitmproxy/src/json') const jsonApi = require('@docmirror/mitmproxy/src/json')
const DevSidecar = require('../index') const DevSidecar = require('../index')
const fs = require('fs')
const log = require('../src/utils/util.log') const log = require('../src/utils/util.log')
// 启动服务 // 启动服务

View File

@ -1,9 +1,11 @@
const fs = require('fs')
const path = require('path')
const server = require('@docmirror/mitmproxy') const server = require('@docmirror/mitmproxy')
const jsonApi = require('@docmirror/mitmproxy/src/json') const jsonApi = require('@docmirror/mitmproxy/src/json')
const path = require('path')
const home = process.env.USER_HOME || process.env.HOME || 'C:/Users/Administrator/'
const log = require('../src/utils/util.log') const log = require('../src/utils/util.log')
const home = process.env.USER_HOME || process.env.HOME || 'C:/Users/Administrator/'
let configPath let configPath
if (process.argv && process.argv.length > 3) { if (process.argv && process.argv.length > 3) {
configPath = process.argv[2] configPath = process.argv[2]
@ -11,7 +13,6 @@ if (process.argv && process.argv.length > 3) {
configPath = path.join(home, '.dev-sidecar/running.json') configPath = path.join(home, '.dev-sidecar/running.json')
} }
const fs = require('fs')
const configJson = fs.readFileSync(configPath) const configJson = fs.readFileSync(configPath)
log.info('读取 running.json by core 成功:', configPath) log.info('读取 running.json by core 成功:', configPath)
const config = jsonApi.parse(configJson.toString()) const config = jsonApi.parse(configJson.toString())

View File

@ -1,42 +1,42 @@
{ {
app: { "app": {
autoStart: { "autoStart": {
enabled: true, "enabled": true
}, },
mode: 'default', "mode": "default"
}, },
plugin: { "plugin": {
node: { "node": {
setting: { "setting": {
yarnRegistry: 'null', "yarnRegistry": "null"
},
},
git: {
enabled: true,
},
overwall: {
enabled: false,
targets: {
'*gagedigital.com': true,
'*yonsz.net': true,
'*bootstrapcdn.com': true,
'*cloudflare.com': true,
'help.yonsz.net': true,
},
},
},
server: {
intercepts: {
'dev-sidecar.docmirror.cn': {
'.*': {
proxy: 'dev-sidecar-preview.docmirror.cn',
},
},
'test1111.gagedigital.com': {
'.*': {
proxy: 'test1.gagedigital.com',
},
} }
}, },
"git": {
"enabled": true
},
"overwall": {
"enabled": false,
"targets": {
"*gagedigital.com": true,
"*yonsz.net": true,
"*bootstrapcdn.com": true,
"*cloudflare.com": true,
"help.yonsz.net": true
}
}
},
"server": {
"intercepts": {
"dev-sidecar.docmirror.cn": {
".*": {
"proxy": "dev-sidecar-preview.docmirror.cn"
}
},
"test1111.gagedigital.com": {
".*": {
"proxy": "test1.gagedigital.com"
}
}
}
} }
} }

View File

@ -1,5 +1,7 @@
const https = require('https') const https = require('https')
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1' process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'
function request () { function request () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const options = { const options = {
@ -28,12 +30,12 @@ function request () {
}) })
} }
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
describe('ssl.verify', function () { describe('ssl.verify', () => {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
it('regex.test.js', async function () { it('regex.test.js', async () => {
// https.request('https://test1.gagedigital.com/ssltest.php') // https.request('https://test1.gagedigital.com/ssltest.php')
await request() await request()
// eslint-disable-next-line no-unused-expressions
// expect(ret).be.ok // expect(ret).be.ok
}) })
}) })

View File

@ -1,8 +1,8 @@
const expect = require('chai').expect const expect = require('chai').expect
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
describe('test', function () { describe('test', () => {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
it('regexp', function () { it('regexp', () => {
const test = '^/[^/]+/[^/]+(/releases(/.*)?)?$' const test = '^/[^/]+/[^/]+(/releases(/.*)?)?$'
const reg = new RegExp(test) const reg = new RegExp(test)

View File

@ -1,5 +1,5 @@
const request = require('request')
const HttpsAgent = require('@docmirror/mitmproxy/src/lib/proxy/common/ProxyHttpsAgent') const HttpsAgent = require('@docmirror/mitmproxy/src/lib/proxy/common/ProxyHttpsAgent')
const request = require('request')
const options = { const options = {
url: 'https://raw.githubusercontent.com/docmirror/dev-sidecar/refs/heads/master/packages/core/src/config/remote_config.json5', url: 'https://raw.githubusercontent.com/docmirror/dev-sidecar/refs/heads/master/packages/core/src/config/remote_config.json5',

View File

@ -24,7 +24,7 @@
"@docmirror/dev-sidecar": "^1.8.9", "@docmirror/dev-sidecar": "^1.8.9",
"@docmirror/mitmproxy": "^1.8.9", "@docmirror/mitmproxy": "^1.8.9",
"@mihomo-party/sysproxy": "^2.0.4", "@mihomo-party/sysproxy": "^2.0.4",
"@natmri/platform-napi": "^0.0.8", "@natmri/platform-napi": "^0.0.7",
"adm-zip": "^0.5.5", "adm-zip": "^0.5.5",
"ant-design-vue": "^1.6.5", "ant-design-vue": "^1.6.5",
"compressing": "^1.5.1", "compressing": "^1.5.1",

View File

@ -1,6 +1,6 @@
const fs = require('fs')
const path = require('path') const path = require('path')
const pkg = require('../package.json') const pkg = require('../package.json')
const fs = require('fs')
function appendIntro (context, systemType, latest) { function appendIntro (context, systemType, latest) {
const version = pkg.version const version = pkg.version
@ -14,8 +14,7 @@ partMiniVersion: 1.7.0
releaseNotes: releaseNotes:
- 升级日志 - 升级日志
- https://download.fastgit.org/docmirror/dev-sidecar/releases/download/v${version}/DevSidecar-${version}.exe - https://download.fastgit.org/docmirror/dev-sidecar/releases/download/v${version}/DevSidecar-${version}.exe
`, `, (err) => {
(err) => {
if (err) { if (err) {
console.log('修改latest 失败') console.log('修改latest 失败')
} }

View File

@ -1,7 +1,7 @@
const fs = require('fs')
const path = require('path') const path = require('path')
const AdmZip = require('adm-zip') const AdmZip = require('adm-zip')
const pkg = require('../package.json') const pkg = require('../package.json')
const fs = require('fs')
function writeAppUpdateYmlForLinux () { function writeAppUpdateYmlForLinux () {
const publishUrl = process.env.VUE_APP_PUBLISH_URL const publishUrl = process.env.VUE_APP_PUBLISH_URL

View File

@ -1,17 +1,15 @@
'use strict' 'use strict'
/* global __static */ /* global __static */
import path from 'path' import path from 'path'
import { app, protocol, BrowserWindow, Menu, Tray, ipcMain, dialog, powerMonitor, nativeImage, nativeTheme, globalShortcut } from 'electron' import DevSidecar from '@docmirror/dev-sidecar'
import { app, BrowserWindow, dialog, globalShortcut, ipcMain, Menu, nativeImage, nativeTheme, powerMonitor, protocol, Tray } from 'electron'
import minimist from 'minimist'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib' import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import backend from './bridge/backend' import backend from './bridge/backend'
import DevSidecar from '@docmirror/dev-sidecar'
import log from './utils/util.log' import log from './utils/util.log'
import minimist from 'minimist'
const isWindows = process.platform === 'win32' const isWindows = process.platform === 'win32'
// eslint-disable-next-line no-unused-vars
const isMac = process.platform === 'darwin' const isMac = process.platform === 'darwin'
// import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production' const isDevelopment = process.env.NODE_ENV !== 'production'
// 避免其他系统出现异常,只有 Windows 使用 './background/powerMonitor' // 避免其他系统出现异常,只有 Windows 使用 './background/powerMonitor'
@ -21,7 +19,7 @@ const _powerMonitor = isWindows ? require('./background/powerMonitor').powerMoni
// be closed automatically when the JavaScript object is garbage collected. // be closed automatically when the JavaScript object is garbage collected.
let win let win
let winIsHidden = false let winIsHidden = false
// eslint-disable-next-line no-unused-vars
let tray // 防止被内存清理 let tray // 防止被内存清理
let forceClose = false let forceClose = false
DevSidecar.api.config.reload() DevSidecar.api.config.reload()
@ -123,8 +121,8 @@ function setTray () {
showWin() showWin()
}) })
appTray.on('right-click', function () { appTray.on('right-click', () => {
setTimeout(function () { setTimeout(() => {
appTray.popUpContextMenu(contextMenu) appTray.popUpContextMenu(contextMenu)
}, 200) }, 200)
}) })
@ -184,7 +182,6 @@ function createWindow (startHideWindow) {
nodeIntegration: true// process.env.ELECTRON_NODE_INTEGRATION nodeIntegration: true// process.env.ELECTRON_NODE_INTEGRATION
}, },
show: !startHideWindow, show: !startHideWindow,
// eslint-disable-next-line no-undef
icon: path.join(__static, 'icon.png') icon: path.join(__static, 'icon.png')
}) })
winIsHidden = !!startHideWindow winIsHidden = !!startHideWindow
@ -368,7 +365,7 @@ if (app.getLoginItemSettings().wasOpenedAsHidden) {
log.info('start args:', args) log.info('start args:', args)
// 通过启动参数,判断是否隐藏窗口 // 通过启动参数,判断是否隐藏窗口
const hideWindowArg = args.hideWindow + '' const hideWindowArg = `${args.hideWindow}`
if (hideWindowArg === 'true' || hideWindowArg === '1') { if (hideWindowArg === 'true' || hideWindowArg === '1') {
startHideWindow = true startHideWindow = true
} else if (hideWindowArg === 'false' || hideWindowArg === '0') { } else if (hideWindowArg === 'false' || hideWindowArg === '0') {
@ -483,7 +480,7 @@ if (isDevelopment) {
} }
} }
// 系统关机和重启时的操作 // 系统关机和重启时的操作
process.on('exit', function () { process.on('exit', () => {
log.info('进程结束退出app') log.info('进程结束退出app')
quit() quit()
}) })

View File

@ -1,5 +1,5 @@
import { acquireShutdownBlock, insertWndProcHook, releaseShutdownBlock, removeWndProcHook, setMainWindowHandle } from '@natmri/platform-napi'
import { powerMonitor as _powerMonitor } from 'electron' import { powerMonitor as _powerMonitor } from 'electron'
import { setMainWindowHandle, insertWndProcHook, removeWndProcHook, releaseShutdownBlock, acquireShutdownBlock } from '@natmri/platform-napi'
class PowerMonitor { class PowerMonitor {
constructor () { constructor () {

View File

@ -1,14 +1,16 @@
import lodash from 'lodash'
import DevSidecar from '@docmirror/dev-sidecar'
import { ipcMain } from 'electron'
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
import DevSidecar from '@docmirror/dev-sidecar'
import { ipcMain } from 'electron'
import lodash from 'lodash'
const pk = require('../../../package.json') const pk = require('../../../package.json')
const mitmproxyPath = path.join(__dirname, 'mitmproxy.js')
process.env.DS_EXTRA_PATH = path.join(__dirname, '../extra/')
const jsonApi = require('@docmirror/mitmproxy/src/json') const jsonApi = require('@docmirror/mitmproxy/src/json')
const log = require('../../utils/util.log') const log = require('../../utils/util.log')
const mitmproxyPath = path.join(__dirname, 'mitmproxy.js')
process.env.DS_EXTRA_PATH = path.join(__dirname, '../extra/')
const getDefaultConfigBasePath = function () { const getDefaultConfigBasePath = function () {
return DevSidecar.api.config.get().server.setting.userBasePath return DevSidecar.api.config.get().server.setting.userBasePath
} }
@ -129,7 +131,7 @@ function _deepFindFunction (list, parent, parentKey) {
if (item instanceof Function) { if (item instanceof Function) {
list.push(parentKey + key) list.push(parentKey + key)
} else if (item instanceof Object) { } else if (item instanceof Object) {
_deepFindFunction(list, item, parentKey + key + '.') _deepFindFunction(list, item, `${parentKey + key}.`)
} }
} }
} }
@ -184,14 +186,20 @@ export default {
// 注册从core里来的事件并转发给view // 注册从core里来的事件并转发给view
DevSidecar.api.event.register('status', (event) => { DevSidecar.api.event.register('status', (event) => {
log.info('bridge on status, event:', event) log.info('bridge on status, event:', event)
if (win) win.webContents.send('status', { ...event }) if (win) {
win.webContents.send('status', { ...event })
}
}) })
DevSidecar.api.event.register('error', (event) => { DevSidecar.api.event.register('error', (event) => {
log.error('bridge on error, event:', event) log.error('bridge on error, event:', event)
if (win) win.webContents.send('error.core', event) if (win) {
win.webContents.send('error.core', event)
}
}) })
DevSidecar.api.event.register('speed', (event) => { DevSidecar.api.event.register('speed', (event) => {
if (win) win.webContents.send('speed', event) if (win) {
win.webContents.send('speed', event)
}
}) })
// 合并用户配置 // 合并用户配置

View File

@ -1,12 +1,14 @@
import Sudoer from 'electron-sudo'
import DevSidecar from '@docmirror/dev-sidecar' import DevSidecar from '@docmirror/dev-sidecar'
import Sudoer from 'electron-sudo'
export default { export default {
async open () { async open () {
const options = { name: '设置loopback' } const options = { name: '设置loopback' }
const sudoer = new Sudoer(options) const sudoer = new Sudoer(options)
const exeFile = DevSidecar.api.shell.extraPath.getEnableLoopbackPath() const exeFile = DevSidecar.api.shell.extraPath.getEnableLoopbackPath()
await sudoer.exec( await sudoer.exec(
exeFile, { env: { PARAM: 'VALUE' } } exeFile,
{ env: { PARAM: 'VALUE' } }
) )
} }
} }

View File

@ -44,7 +44,8 @@ export default {
openAtLogin: true, openAtLogin: true,
openAsHidden: true, openAsHidden: true,
args: [ args: [
'--hideWindow', '"true"' '--hideWindow',
'"true"'
] ]
}) })
} }

View File

@ -1,4 +1,3 @@
function install (app, api) { function install (app, api) {
api.ipc.on('auto-start', (event, message) => { api.ipc.on('auto-start', (event, message) => {
if (message.value === true) { if (message.value === true) {

View File

@ -1,8 +1,8 @@
import api from './api/backend' import api from './api/backend'
import autoStart from './auto-start/backend'
import fileSelector from './file-selector/backend'
import tongji from './tongji/backend' import tongji from './tongji/backend'
import update from './update/backend' import update from './update/backend'
import fileSelector from './file-selector/backend'
import autoStart from './auto-start/backend'
const modules = { const modules = {
api, // 核心接口模块 api, // 核心接口模块

View File

@ -13,15 +13,14 @@ function install (app, api) {
function handleServerStartError (message, err, app, api) { function handleServerStartError (message, err, app, api) {
if (message.value === 'EADDRINUSE') { if (message.value === 'EADDRINUSE') {
// eslint-disable-next-line no-debugger
app.$confirm({ app.$confirm({
title: '端口被占用,代理服务启动失败', title: '端口被占用,代理服务启动失败',
content: '是否要杀掉占用进程?您也可以点击取消,然后前往加速服务->基本设置中修改代理端口', content: '是否要杀掉占用进程?您也可以点击取消,然后前往加速服务->基本设置中修改代理端口',
onOk () { onOk () {
// TODO 杀掉进程 // TODO 杀掉进程
api.config.get().then(config => { api.config.get().then((config) => {
console.log('config', config) console.log('config', config)
api.shell.killByPort({ port: config.server.port }).then(ret => { api.shell.killByPort({ port: config.server.port }).then((ret) => {
app.$message.info('杀掉进程成功,请重试开启代理服务') app.$message.info('杀掉进程成功,请重试开启代理服务')
}) })
}) })
@ -31,7 +30,7 @@ function handleServerStartError (message, err, app, api) {
} }
}) })
} else { } else {
app.$message.error('加速服务启动失败:' + message.message) app.$message.error(`加速服务启动失败:${message.message}`)
} }
} }

View File

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

View File

@ -1,9 +1,8 @@
function install (app, api) { function install (app, api) {
api.fileSelector = { api.fileSelector = {
open (value, options) { open (value, options) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
api.ipc.send('file-selector', { key: 'open', value: value, ...options }) api.ipc.send('file-selector', { key: 'open', value, ...options })
api.ipc.on('file-selector', (event, message) => { api.ipc.on('file-selector', (event, message) => {
console.log('selector', message) console.log('selector', message)
if (message.key === 'selected') { if (message.key === 'selected') {

View File

@ -1,10 +1,11 @@
// import api from './api/front' // import api from './api/front'
import autoStart from './auto-start/front'
import error from './error/front' import error from './error/front'
import fileSelector from './file-selector/front'
import onClose from './on-close/front'
import tongji from './tongji/front' import tongji from './tongji/front'
import update from './update/front' import update from './update/front'
import fileSelector from './file-selector/front'
import autoStart from './auto-start/front'
import onClose from './on-close/front'
const modules = { const modules = {
// api, // 核心接口模块 // api, // 核心接口模块
error, error,

View File

@ -1,10 +1,10 @@
// eslint-disable-next-line no-unused-vars
const log = require('../utils/util.log')
const server = require('@docmirror/mitmproxy')
const jsonApi = require('@docmirror/mitmproxy/src/json')
const configPath = process.argv[2]
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const server = require('@docmirror/mitmproxy')
const jsonApi = require('@docmirror/mitmproxy/src/json')
const log = require('../utils/util.log')
const configPath = process.argv[2]
const configJson = fs.readFileSync(configPath) const configJson = fs.readFileSync(configPath)
log.info('读取 running.json by gui bridge 成功:', configPath) log.info('读取 running.json by gui bridge 成功:', configPath)
const config = jsonApi.parse(configJson.toString()) const config = jsonApi.parse(configJson.toString())

View File

@ -12,19 +12,21 @@ function install (app, api) {
} }
app.$confirm({ app.$confirm({
title: '关闭策略', title: '关闭策略',
content: h => <div> content: (h) => (
<div style={'margin-top:10px'}> <div>
<a-radio-group vOn:change={onRadioChange} defaultValue={closeType}> <div style="margin-top:10px">
<a-radio value={1}>直接关闭</a-radio> <a-radio-group vOn:change={onRadioChange} defaultValue={closeType}>
<a-radio value={2}>最小化到系统托盘</a-radio> <a-radio value={1}>直接关闭</a-radio>
</a-radio-group> <a-radio value={2}>最小化到系统托盘</a-radio>
</a-radio-group>
</div>
<div style="margin-top:10px">
<a-checkbox vOn:change={onCheckChange} defaultChecked={doSave}>
记住本次选择不再提示
</a-checkbox>
</div>
</div> </div>
<div style={'margin-top:10px'}> ),
<a-checkbox vOn:change={onCheckChange} defaultChecked={doSave}>
记住本次选择不再提示
< /a-checkbox>
</div>
</div>,
async onOk () { async onOk () {
console.log('OK. closeType=', closeType) console.log('OK. closeType=', closeType)
if (doSave) { if (doSave) {

View File

@ -1,9 +1,8 @@
/** /**
* first step * first step
* @param {*} ipcMain * @param {*} ipcMain
*/ */
const ebtMain = (ipcMain) => { function ebtMain (ipcMain) {
const isDevelopment = process.env.NODE_ENV !== 'production' const isDevelopment = process.env.NODE_ENV !== 'production'
const request = require('request') const request = require('request')
/* istanbul ignore else */ /* istanbul ignore else */
@ -21,15 +20,14 @@ const ebtMain = (ipcMain) => {
headers: { headers: {
Referer: 'https://hm.baidu.com/' Referer: 'https://hm.baidu.com/'
} }
}, }, (err, response, body) => {
(err, response, body) => {
if (err) { if (err) {
console.error('百度统计请求出错', err) console.error('百度统计请求出错', err)
return return
} }
const rource = '(h.c.b.su=h.c.b.u||document.location.href),h.c.b.u=f.protocol+"//"+document.location.host+' 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 */ /* istanbul ignore else */
if (body && body.indexOf(rource) >= 0) { if (body && body.includes(rource)) {
// step 3 // step 3
let text = body let text = body

View File

@ -1,11 +1,10 @@
/** /**
* second step * second step
* @param {*} ipcRenderer * @param {*} ipcRenderer
* @param {*} siteId * @param {*} siteId
* @param {*} router * @param {*} router
*/ */
const ebtRenderer = (ipcRenderer, siteId, router) => { function ebtRenderer (ipcRenderer, siteId, router) {
/* istanbul ignore else */ /* istanbul ignore else */
if (!(ipcRenderer && ipcRenderer.on && ipcRenderer.send)) { if (!(ipcRenderer && ipcRenderer.on && ipcRenderer.send)) {
throw new TypeError('require ipcRenderer') throw new TypeError('require ipcRenderer')
@ -38,7 +37,7 @@ const ebtRenderer = (ipcRenderer, siteId, router) => {
router.beforeEach((to, _, next) => { router.beforeEach((to, _, next) => {
/* istanbul ignore else */ /* istanbul ignore else */
if (to.path) { if (to.path) {
window._hmt.push(['_trackPageview', '/#' + to.fullPath]) window._hmt.push(['_trackPageview', `/#${to.fullPath}`])
console.log('baidu trace', to.fullPath) console.log('baidu trace', to.fullPath)
} }

View File

@ -1,16 +1,15 @@
import fs from 'fs'
import path from 'path'
import DevSidecar from '@docmirror/dev-sidecar'
import AdmZip from 'adm-zip'
import { ipcMain } from 'electron' import { ipcMain } from 'electron'
import { autoUpdater } from 'electron-updater' import { autoUpdater } from 'electron-updater'
import path from 'path'
import request from 'request' import request from 'request'
import progress from 'request-progress' import progress from 'request-progress'
import fs from 'fs'
import AdmZip from 'adm-zip'
import log from '../../utils/util.log'
import appPathUtil from '../../utils/util.apppath'
import pkg from '../../../package.json' import pkg from '../../../package.json'
import DevSidecar from '@docmirror/dev-sidecar' import appPathUtil from '../../utils/util.apppath'
import log from '../../utils/util.log'
// eslint-disable-next-line no-unused-vars
const isMac = process.platform === 'darwin' const isMac = process.platform === 'darwin'
const isLinux = process.platform === 'linux' const isLinux = process.platform === 'linux'
@ -24,16 +23,16 @@ function downloadFile (uri, filePath, onProgress, onSuccess, onError) {
// delay: 1000, // Only start to emit after 1000ms delay, defaults to 0ms // delay: 1000, // Only start to emit after 1000ms delay, defaults to 0ms
// lengthHeader: 'x-transfer-length' // Length header to use, defaults to content-length // lengthHeader: 'x-transfer-length' // Length header to use, defaults to content-length
}) })
.on('progress', function (state) { .on('progress', (state) => {
onProgress(state.percent * 100) onProgress(state.percent * 100)
log.log('progress', state.percent) log.log('progress', state.percent)
}) })
.on('error', function (err) { .on('error', (err) => {
// Do something with err // Do something with err
log.error('下载升级包失败:', err) log.error('下载升级包失败:', err)
onError(err) onError(err)
}) })
.on('end', function () { .on('end', () => {
// Do something after request finishes // Do something after request finishes
onSuccess() onSuccess()
}) })
@ -44,9 +43,9 @@ function parseVersion (version) {
const matched = version.match(/^v?(\d+\.\d+\.\d+)(.*)$/) const matched = version.match(/^v?(\d+\.\d+\.\d+)(.*)$/)
const versionArr = matched[1].split('.') const versionArr = matched[1].split('.')
return { return {
major: parseInt(versionArr[0]), major: Number.parseInt(versionArr[0]),
minor: parseInt(versionArr[1]), minor: Number.parseInt(versionArr[1]),
patch: parseInt(versionArr[2]), patch: Number.parseInt(versionArr[2]),
suffix: matched[2] suffix: matched[2]
} }
} }
@ -141,11 +140,11 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
// 检查更新 // 检查更新
const releasesApiUrl = 'https://api.github.com/repos/docmirror/dev-sidecar/releases' const releasesApiUrl = 'https://api.github.com/repos/docmirror/dev-sidecar/releases'
async function checkForUpdatesFromGitHub () { async function checkForUpdatesFromGitHub () {
request(releasesApiUrl, { headers: { 'User-Agent': 'DS/' + curVersion, 'Server-Name': 'baidu.com' } }, (error, response, body) => { request(releasesApiUrl, { headers: { 'User-Agent': `DS/${curVersion}`, 'Server-Name': 'baidu.com' } }, (error, response, body) => {
try { try {
if (error) { if (error) {
log.error('检查更新失败:', error) log.error('检查更新失败:', error)
const errorMsg = '检查更新失败:' + error const errorMsg = `检查更新失败:${error}`
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: errorMsg }) win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: errorMsg })
return return
} }
@ -203,7 +202,7 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
value: { value: {
version, version,
releaseNotes: versionData.body releaseNotes: versionData.body
? (versionData.body.replace(/\r\n/g, '\n').replace(/https:\/\/github.com\/docmirror\/dev-sidecar/g, '').replace(/(?<=(^|\n))[ \t]*[ #]*#\s*/g, '') || '无') ? (versionData.body.replace(/\r\n/g, '\n').replace(/https:\/\/github.com\/docmirror\/dev-sidecar/g, '').replace(/(?<=(^|\n))[ \t]*(?:#[ #]*)?#\s*/g, '') || '无')
: '无' : '无'
} }
}) })
@ -229,15 +228,15 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
let message let message
if (response) { if (response) {
message = '检查更新失败: ' + (bodyObj && bodyObj.message ? bodyObj.message : response.message) + ', code: ' + response.statusCode message = `检查更新失败: ${bodyObj && bodyObj.message ? bodyObj.message : response.message}, code: ${response.statusCode}`
} else { } else {
message = '检查更新失败: ' + (bodyObj && bodyObj.message ? bodyObj.message : body) message = `检查更新失败: ${bodyObj && bodyObj.message ? bodyObj.message : body}`
} }
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: message }) win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: message })
} }
} catch (e) { } catch (e) {
log.error('检查更新失败:', e) log.error('检查更新失败:', e)
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: '检查更新失败:' + e.message }) win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: `检查更新失败:${e.message}` })
} }
}) })
} }
@ -252,10 +251,10 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
} catch (e) { } catch (e) {
fs.mkdirSync(fileDir) fs.mkdirSync(fileDir)
} }
const filePath = path.join(fileDir, value.version + '.zip') const filePath = path.join(fileDir, `${value.version}.zip`)
downloadFile(value.partPackage, filePath, (data) => { downloadFile(value.partPackage, filePath, (data) => {
win.webContents.send('update', { key: 'progress', value: parseInt(data) }) win.webContents.send('update', { key: 'progress', value: Number.parseInt(data) })
}, () => { }, () => {
// 文件下载完成 // 文件下载完成
win.webContents.send('update', { key: 'progress', value: 100 }) win.webContents.send('update', { key: 'progress', value: 100 })
@ -263,10 +262,10 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
partPackagePath = filePath partPackagePath = filePath
win.webContents.send('update', { win.webContents.send('update', {
key: 'downloaded', key: 'downloaded',
value: value value
}) })
}, (error) => { }, (error) => {
sendUpdateMessage({ key: 'error', value: error, error: error }) sendUpdateMessage({ key: 'error', value: error, error })
}) })
} }
@ -294,30 +293,30 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
} }
} }
autoUpdater.on('error', function (error) { autoUpdater.on('error', (error) => {
log.warn('autoUpdater error:', error) log.warn('autoUpdater error:', error)
sendUpdateMessage({ key: 'error', value: error, error: error }) sendUpdateMessage({ key: 'error', value: error, error })
// dialog.showErrorBox('Error: ', error == null ? 'unknown' : (error.stack || error).toString()) // dialog.showErrorBox('Error: ', error == null ? 'unknown' : (error.stack || error).toString())
}) })
autoUpdater.on('checking-for-update', function () { autoUpdater.on('checking-for-update', () => {
log.info('autoUpdater checking-for-update') log.info('autoUpdater checking-for-update')
sendUpdateMessage({ key: 'checking', value: message.checking }) sendUpdateMessage({ key: 'checking', value: message.checking })
}) })
autoUpdater.on('update-available', function (info) { autoUpdater.on('update-available', (info) => {
log.info('autoUpdater update-available') log.info('autoUpdater update-available')
sendUpdateMessage({ key: 'available', value: info }) sendUpdateMessage({ key: 'available', value: info })
}) })
autoUpdater.on('update-not-available', function () { autoUpdater.on('update-not-available', () => {
log.info('autoUpdater update-not-available') log.info('autoUpdater update-not-available')
sendUpdateMessage({ key: 'notAvailable', value: message.updateNotAva }) sendUpdateMessage({ key: 'notAvailable', value: message.updateNotAva })
}) })
// 更新下载进度 // 更新下载进度
autoUpdater.on('download-progress', function (progressObj) { autoUpdater.on('download-progress', (progressObj) => {
log.info('autoUpdater download-progress') log.info('autoUpdater download-progress')
win.webContents.send('update', { key: 'progress', value: parseInt(progressObj.percent) }) win.webContents.send('update', { key: 'progress', value: Number.parseInt(progressObj.percent) })
}) })
// 更新完成,重启应用 // 更新完成,重启应用
autoUpdater.on('update-downloaded', function (info) { autoUpdater.on('update-downloaded', (info) => {
log.info('download complete, version:', info.version) log.info('download complete, version:', info.version)
win.webContents.send('update', { win.webContents.send('update', {
key: 'downloaded', key: 'downloaded',

View File

@ -80,11 +80,13 @@ function install (app, api) {
cancelText: '取消', cancelText: '取消',
okText: '打开链接', okText: '打开链接',
width: 420, width: 420,
content: h => { content: (h) => {
return <div> return (
<div>请前往 <a onClick={openGithubUrl}>github项目release页面</a> </div> <div>
<div><a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div> <div>请前往 <a onClick={openGithubUrl}>github项目release页面</a> </div>
</div> <div><a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div>
</div>
)
}, },
onOk () { onOk () {
openGithubUrl() openGithubUrl()
@ -141,31 +143,35 @@ function install (app, api) {
} }
console.log(value) console.log(value)
app.$confirm({ app.$confirm({
title: '发现新版本v' + value.version, title: `发现新版本v${value.version}`,
cancelText: '暂不升级', cancelText: '暂不升级',
okText: '升级', okText: '升级',
width: 700, width: 700,
content: h => { content: (h) => {
if (value.releaseNotes) { if (value.releaseNotes) {
const notes = [] const notes = []
if (typeof value.releaseNotes === 'string') { if (typeof value.releaseNotes === 'string') {
const releaseNotes = value.releaseNotes.replace(/\r\n/g, '\n') const releaseNotes = value.releaseNotes.replace(/\r\n/g, '\n')
return <div> return (
<div>发布公告<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div> <div>
<hr/> <div>发布公告<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div>
<pre style="max-height:350px;font-family:auto"> <hr/>
{releaseNotes} <pre style="max-height:350px;font-family:auto">
</pre> {releaseNotes}
</div> </pre>
</div>
)
} else { } else {
for (const note of value.releaseNotes) { for (const note of value.releaseNotes) {
notes.push(<li>{note}</li>) notes.push(<li>{note}</li>)
} }
return <div> return (
<div>发布公告<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div> <div>
<div>更新内容</div> <div>发布公告<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div>
<ol>{notes}</ol> <div>更新内容</div>
</div> <ol>{notes}</ol>
</div>
)
} }
} }
}, },
@ -187,27 +193,31 @@ function install (app, api) {
cancelText: '暂不升级', cancelText: '暂不升级',
okText: '立即升级', okText: '立即升级',
width: 700, width: 700,
content: h => { content: (h) => {
if (value.releaseNotes) { if (value.releaseNotes) {
const notes = [] const notes = []
if (typeof value.releaseNotes === 'string') { if (typeof value.releaseNotes === 'string') {
const releaseNotes = value.releaseNotes.replace(/\r\n/g, '\n') const releaseNotes = value.releaseNotes.replace(/\r\n/g, '\n')
return <div> return (
<div>发布公告<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div> <div>
<hr/> <div>发布公告<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div>
<pre style="max-height:350px;font-family:auto"> <hr/>
{releaseNotes} <pre style="max-height:350px;font-family:auto">
</pre> {releaseNotes}
</div> </pre>
</div>
)
} else { } else {
for (const note of value.releaseNotes) { for (const note of value.releaseNotes) {
notes.push(<li>{note}</li>) notes.push(<li>{note}</li>)
} }
return <div> return (
<div>发布公告<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div> <div>
<div>更新内容</div> <div>发布公告<a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div>
<ol>{notes}</ol> <div>更新内容</div>
</div> <ol>{notes}</ol>
</div>
)
} }
} }
}, },

View File

@ -1,11 +1,11 @@
import Vue from 'vue'
import App from './view/App.vue'
import antd from 'ant-design-vue' import antd from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css' import Vue from 'vue'
import view from './view'
import VueRouter from 'vue-router' import VueRouter from 'vue-router'
import routes from './view/router' import view from './view'
import App from './view/App.vue'
import DsContainer from './view/components/container' import DsContainer from './view/components/container'
import routes from './view/router'
import 'ant-design-vue/dist/antd.css'
import './view/style/index.scss' import './view/style/index.scss'
import './view/style/theme/dark.scss' // 暗色主题 import './view/style/theme/dark.scss' // 暗色主题

View File

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

View File

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

View File

@ -1,15 +1,15 @@
<script> <script>
export default { export default {
name: 'ds-container' name: 'DsContainer'
} }
</script> </script>
<template> <template>
<div class="ds-container"> <div class="ds-container">
<div class="body-wrapper"> <div class="body-wrapper">
<div v-if="$slots.header" class="container-header"><slot name="header"></slot></div> <div v-if="$slots.header" class="container-header"><slot name="header" /></div>
<div class="container-body"> <slot></slot></div> <div class="container-body"><slot /></div>
<div class="container-footer"> <slot name="footer"></slot></div> <div class="container-footer"><slot name="footer" /></div>
</div> </div>
</div> </div>
</template> </template>
@ -49,5 +49,4 @@ export default {
padding:15px; padding:15px;
} }
} }
</style> </style>

View File

@ -1,6 +1,6 @@
<script> <script>
export default { export default {
name: 'setup-ca', name: 'SetupCa',
components: { components: {
}, },
@ -18,10 +18,6 @@ export default {
systemPlatform: '' systemPlatform: ''
} }
}, },
async created () {
const platform = await this.$api.info.getSystemPlatform()
this.systemPlatform = platform
},
computed: { computed: {
setupImage () { setupImage () {
if (this.systemPlatform === 'mac') { if (this.systemPlatform === 'mac') {
@ -33,6 +29,10 @@ export default {
} }
} }
}, },
async created () {
const platform = await this.$api.info.getSystemPlatform()
this.systemPlatform = platform
},
methods: { methods: {
async openExternal (url) { async openExternal (url) {
await this.$api.ipc.openExternal(url) await this.$api.ipc.openExternal(url)
@ -61,27 +61,27 @@ export default {
:closable="false" :closable="false"
:visible="visible" :visible="visible"
:after-visible-change="afterVisibleChange" :after-visible-change="afterVisibleChange"
@close="onClose"
width="660px" width="660px"
height="100%" height="100%"
:slots="{ title: 'title' }" :slots="{ title: 'title' }"
wrapClassName="json-wrapper" wrap-class-name="json-wrapper"
@close="onClose"
> >
<template slot="title"> <template slot="title">
{{title}} {{ title }}
<a-button type="primary" style="float:right" @click="doSetup()"></a-button> <a-button type="primary" style="float:right" @click="doSetup()"></a-button>
<a-button style="float:right;margin-right:10px;" @click="openExternal('https://github.com/docmirror/dev-sidecar/blob/master/doc/caroot.md')"></a-button> <a-button style="float:right;margin-right:10px;" @click="openExternal('https://github.com/docmirror/dev-sidecar/blob/master/doc/caroot.md')"></a-button>
</template> </template>
<div> <div>
<b>本应用在非安全模式下必须安装和信任CA根证书</b>该证书是应用启动时本地随机生成的<br/> <b>本应用在非安全模式下必须安装和信任CA根证书</b>该证书是应用启动时本地随机生成的<br/>
<template v-if="this.systemPlatform === 'mac'"> <template v-if="systemPlatform === 'mac'">
1点击右上角点此去安装按钮打开钥匙串<b style="color:red">选择系统</b><br/> 1点击右上角点此去安装按钮打开钥匙串<b style="color:red">选择系统</b><br/>
2然后按如下图步骤将随机生成的根证书设置为始终信任<br/> 2然后按如下图步骤将随机生成的根证书设置为始终信任<br/>
3可能需要重新启动应用和浏览器才能生效<br/> 3可能需要重新启动应用和浏览器才能生效<br/>
4注意如果出现无法导入提示时先点一下钥匙串的左边切换到<b style="color:red">系统</b>然后再重新安装证书即可<br/> 4注意如果出现无法导入提示时先点一下钥匙串的左边切换到<b style="color:red">系统</b>然后再重新安装证书即可<br/>
</template> </template>
<template v-else-if="this.systemPlatform === 'linux'"> <template v-else-if="systemPlatform === 'linux'">
1点击右上角点此去安装按钮,将自动安装到系统证书库中<br/> 1点击右上角点此去安装按钮,将自动安装到系统证书库中<br/>
2<b color="red">火狐chrome等浏览器不走系统证书</b>需要手动安装(下图以chrome为例安装根证书)<br/> 2<b color="red">火狐chrome等浏览器不走系统证书</b>需要手动安装(下图以chrome为例安装根证书)<br/>
</template> </template>
@ -90,6 +90,6 @@ export default {
2然后按如下图步骤将根证书添加到<b style="color:red">信任的根证书颁发机构</b> 2然后按如下图步骤将根证书添加到<b style="color:red">信任的根证书颁发机构</b>
</template> </template>
</div> </div>
<img width="100%" :src="setupImage"/> <img width="100%" :src="setupImage">
</a-drawer> </a-drawer>
</template> </template>

View File

@ -1,5 +1,5 @@
import DsContainer from '../components/container'
import lodash from 'lodash' import lodash from 'lodash'
import DsContainer from '../components/container'
export default { export default {
components: { components: {

View File

@ -1,21 +1,13 @@
<script> <script>
import lodash from 'lodash' import lodash from 'lodash'
import setupCa from '../components/setup-ca'
import DsContainer from '../components/container' import DsContainer from '../components/container'
import SetupCa from '../components/setup-ca'
export default { export default {
name: 'Index', name: 'Index',
components: { components: {
DsContainer, DsContainer,
setupCa SetupCa
},
computed: {
_rootCaSetuped () {
if (this.setting.rootCa) {
return this.setting.rootCa.setuped === true
}
return false
}
}, },
data () { data () {
return { return {
@ -52,6 +44,14 @@ export default {
update: { checking: false, downloading: false, progress: 0, newVersion: false } update: { checking: false, downloading: false, progress: 0, newVersion: false }
} }
}, },
computed: {
_rootCaSetuped () {
if (this.setting.rootCa) {
return this.setting.rootCa.setuped === true
}
return false
}
},
async created () { async created () {
await this.doCheckRootCa() await this.doCheckRootCa()
await this.reloadConfig() await this.reloadConfig()
@ -62,7 +62,7 @@ export default {
this.update.autoChecked = true // this.update.autoChecked = true //
this.doCheckUpdate(false) this.doCheckUpdate(false)
} }
this.$api.info.get().then(ret => { this.$api.info.get().then((ret) => {
this.info = ret this.info = ret
}) })
}, },
@ -101,7 +101,7 @@ export default {
title: '彩蛋(增强模式)', title: '彩蛋(增强模式)',
content: ( content: (
<div> <div>
我把它藏在了源码里感兴趣的话可以找一找它线索提示 // TODO 我把它藏在了源码里感兴趣的话可以找一找它线索提示 // TODO
</div> </div>
) )
}) })
@ -162,7 +162,7 @@ export default {
this.$api.setting.save(this.setting) this.$api.setting.save(this.setting)
}, },
reloadConfig () { reloadConfig () {
return this.$api.config.reload().then(ret => { return this.$api.config.reload().then((ret) => {
this.config = ret this.config = ret
return ret return ret
}) })
@ -257,26 +257,28 @@ export default {
</script> </script>
<template> <template>
<ds-container class="page_index"> <DsContainer class="page_index">
<template slot="header"> <template slot="header">
给开发者的辅助工具 给开发者的辅助工具
<span> <span>
<a-button style="margin-right:10px" @click="openSetupCa"> <a-button style="margin-right:10px" @click="openSetupCa">
<a-badge :count="_rootCaSetuped?0:1" dot>安装根证书</a-badge> <a-badge :count="_rootCaSetuped ? 0 : 1" dot>安装根证书</a-badge>
</a-button> </a-button>
<a-button style="margin-right:10px" @click="doCheckUpdate(true)" :loading="update.downloading || update.checking" <a-button
:title="'当前版本:'+info.version"> style="margin-right:10px" :loading="update.downloading || update.checking" :title="`当前版本:${info.version}`"
<a-badge :count="update.newVersion?1:0" dot> @click="doCheckUpdate(true)"
<span v-if="update.downloading">{{ update.progress }}%</span>{{ update.downloading ? '' : ('' + (update.checking ? '' : '')) }} >
</a-badge> <a-badge :count="update.newVersion ? 1 : 0" dot>
</a-button> <span v-if="update.downloading">{{ update.progress }}%</span>{{ update.downloading ? '' : (`${update.checking ? '' : ''}`) }}
</a-badge>
</a-button>
</span> </span>
</template> </template>
<div class="box"> <div class="box">
<a-alert v-if="config && config.app.showShutdownTip" message="本应用开启后会修改系统代理,直接重启电脑可能会无法上网,您可以再次启动本应用即可恢复。如您需要卸载,在卸载前请务必完全退出本应用再进行卸载" banner closable @close="onShutdownTipClose"/> <a-alert v-if="config && config.app.showShutdownTip" message="本应用开启后会修改系统代理,直接重启电脑可能会无法上网,您可以再次启动本应用即可恢复。如您需要卸载,在卸载前请务必完全退出本应用再进行卸载" banner closable @close="onShutdownTipClose" />
<div class="mode-bar" style="margin:20px;" v-if="config && config.app"> <div v-if="config && config.app" class="mode-bar" style="margin:20px;">
<a-radio-group v-model="config.app.mode" button-style="solid" @change="modeChange"> <a-radio-group v-model="config.app.mode" button-style="solid" @change="modeChange">
<a-tooltip placement="topLeft" title="启用测速,关闭拦截,关闭增强(不稳定,不需要安装证书,最安全)"> <a-tooltip placement="topLeft" title="启用测速,关闭拦截,关闭增强(不稳定,不需要安装证书,最安全)">
<a-radio-button value="safe"> <a-radio-button value="safe">
@ -301,61 +303,67 @@ export default {
</a-radio-group> </a-radio-group>
</div> </div>
<div v-if="status" <div
style="margin-top:20px;display: flex; align-items:center;justify-content:space-around;flex-direction: row"> v-if="status"
style="margin-top:20px;display: flex; align-items:center;justify-content:space-around;flex-direction: row"
>
<div style="text-align: center"> <div style="text-align: center">
<div class="big_button"> <div class="big_button">
<a-button shape="circle" :type="startup.type()" :loading="startup.loading" @click="startup.doClick"> <a-button shape="circle" :type="startup.type()" :loading="startup.loading" @click="startup.doClick">
<img v-if="!startup.loading && !status.server.enabled" width="50" src="/logo/logo-simple.svg"> <img v-if="!startup.loading && !status.server.enabled" width="50" src="/logo/logo-simple.svg">
<img v-if="!startup.loading && status.server.enabled" width="50" src="/logo/logo-fff.svg"> <img v-if="!startup.loading && status.server.enabled" width="50" src="/logo/logo-fff.svg">
</a-button> </a-button>
<div class="mt10">{{ status.server.enabled ? '已开启' : '已关闭' }}</div> <div class="mt10">
{{ status.server.enabled ? '已开启' : '已关闭' }}
</div>
</div> </div>
</div> </div>
<div :span="12"> <div :span="12">
<a-form style="margin-top:20px" :label-col="{ span: 15 }" :wrapper-col="{ span: 9 }"> <a-form style="margin-top:20px" :label-col="{ span: 15 }" :wrapper-col="{ span: 9 }">
<a-form-item v-for=" (item, key) in switchBtns" :key="key" :label="item.label"> <a-form-item v-for=" (item, key) in switchBtns" :key="key" :label="item.label">
<a-tooltip placement="topLeft"> <a-tooltip placement="topLeft">
<a-switch style="margin-left:10px" :loading="item.loading" :checked="item.status()" default-checked <a-switch
@change="item.doClick"> style="margin-left:10px" :loading="item.loading" :checked="item.status()" default-checked
<a-icon slot="checkedChildren" type="check"/> @change="item.doClick"
<a-icon slot="unCheckedChildren" type="close"/> >
<a-icon slot="checkedChildren" type="check" />
<a-icon slot="unCheckedChildren" type="close" />
</a-switch> </a-switch>
</a-tooltip> </a-tooltip>
</a-form-item> </a-form-item>
</a-form> </a-form>
</div> </div>
</div> </div>
</div> </div>
<setup-ca title="安装证书" :visible.sync="setupCa.visible" @setup="handleCaSetuped"></setup-ca> <SetupCa title="安装证书" :visible.sync="setupCa.visible" @setup="handleCaSetuped" />
<div slot="footer"> <div slot="footer">
<div class="star" v-if="!setting.overwall"> <div v-if="!setting.overwall" class="star">
<div class="donate"> <div class="donate">
<a-tooltip placement="topLeft" title="彩蛋,点我"> <a-tooltip placement="topLeft" title="彩蛋,点我">
<span style="display: block;width:100px;height:50px;" @click="wantOW()"></span> <span style="display: block;width:100px;height:50px;" @click="wantOW()" />
</a-tooltip> </a-tooltip>
</div> </div>
<div class="right"></div> <div class="right" />
</div> </div>
<div class="star" v-if="setting.development == null || !setting.development"> <div v-if="setting.development == null || !setting.development" class="star">
<div class="donate" @click="donateModal=true"> <div class="donate" @click="donateModal = true">
<a-icon type="like" theme="outlined"/> <a-icon type="like" theme="outlined" />
捐赠 捐赠
</div> </div>
<div class="right"> <div class="right">
<div>如果它解决了你的问题请不要吝啬你的star哟点这里 <div>
<a-icon style="margin-right:10px;" type="arrow-right" theme="outlined"/> 如果它解决了你的问题请不要吝啬你的star哟点这里
<a-icon style="margin-right:10px;" type="arrow-right" theme="outlined" />
</div> </div>
<a @click="openExternal('https://github.com/docmirror/dev-sidecar')"><img alt="GitHub stars" <a @click="openExternal('https://github.com/docmirror/dev-sidecar')"><img
src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"></a> alt="GitHub stars"
src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"
></a>
</div> </div>
</div> </div>
<a-modal title="捐赠" v-if="setting.development == null || !setting.development" v-model="donateModal" width="550px" cancelText="不了" okText="果断支持" @ok="goDonate"> <a-modal v-if="setting.development == null || !setting.development" v-model="donateModal" title="捐赠" width="550px" cancel-text="不了" ok-text="果断支持" @ok="goDonate">
<div>* 本应用完全免费如果觉得好用可以给予捐赠</div> <div>* 本应用完全免费如果觉得好用可以给予捐赠</div>
<div>* 开源项目持续发展离不开您的支持感谢</div> <div>* 开源项目持续发展离不开您的支持感谢</div>
<div class="payQrcode"> <div class="payQrcode">
@ -363,8 +371,7 @@ export default {
</div> </div>
</a-modal> </a-modal>
</div> </div>
</ds-container> </DsContainer>
</template> </template>
<style lang="scss"> <style lang="scss">

View File

@ -97,15 +97,15 @@ export default {
<span><code>Git.exe</code>将不代理以下仓库可以是根地址组织/机构地址完整地址</span> <span><code>Git.exe</code>将不代理以下仓库可以是根地址组织/机构地址完整地址</span>
</a-col> </a-col>
<a-col :span="2"> <a-col :span="2">
<a-button type="primary" icon="plus" @click="addNoProxyUrl()"/> <a-button type="primary" icon="plus" @click="addNoProxyUrl()" />
</a-col> </a-col>
</a-row> </a-row>
<a-row :gutter="10" v-for="(item,index) of noProxyUrls" :key='index'> <a-row v-for="(item, index) of noProxyUrls" :key="index" :gutter="10">
<a-col :span="22"> <a-col :span="22">
<a-input :disabled="item.value === false" v-model="item.key"></a-input> <a-input v-model="item.key" :disabled="item.value === false" />
</a-col> </a-col>
<a-col :span="2"> <a-col :span="2">
<a-button type="danger" icon="minus" @click="delNoProxyUrl(item,index)"/> <a-button type="danger" icon="minus" @click="delNoProxyUrl(item, index)" />
</a-col> </a-col>
</a-row> </a-row>
</div> </div>

View File

@ -18,7 +18,7 @@ export default {
}, },
methods: { methods: {
ready () { ready () {
return this.$api.plugin.node.getVariables().then(ret => { return this.$api.plugin.node.getVariables().then((ret) => {
console.log('variables', ret) console.log('variables', ret)
this.npmVariables = ret this.npmVariables = ret
}) })
@ -70,8 +70,10 @@ export default {
</a-tag> </a-tag>
</a-form-item> </a-form-item>
<a-form-item label="npm命令名" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="npm命令名" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input v-model="config.plugin.node.setting.command"></a-input> <a-input v-model="config.plugin.node.setting.command" />
<div class="form-help">如果你的npm命令改成了其他名字或者想设置绿色版npm程序路径可在此处修改</div> <div class="form-help">
如果你的npm命令改成了其他名字或者想设置绿色版npm程序路径可在此处修改
</div>
</a-form-item> </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']"> <a-checkbox v-model="config.plugin.node.setting['strict-ssl']">
@ -80,8 +82,10 @@ export default {
npm代理启用后必须关闭 npm代理启用后必须关闭
</a-form-item> </a-form-item>
<a-form-item label="npm仓库镜像" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="npm仓库镜像" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-radio-group v-model="config.plugin.node.setting.registry" @change="onSwitchRegistry" <a-radio-group
default-value="https://registry.npmjs.org" button-style="solid"> v-model="config.plugin.node.setting.registry" default-value="https://registry.npmjs.org"
button-style="solid" @change="onSwitchRegistry"
>
<a-radio-button value="https://registry.npmjs.org" title="https://registry.npmjs.org"> <a-radio-button value="https://registry.npmjs.org" title="https://registry.npmjs.org">
npmjs原生 npmjs原生
</a-radio-button> </a-radio-button>
@ -89,36 +93,42 @@ export default {
taobao镜像 taobao镜像
</a-radio-button> </a-radio-button>
</a-radio-group> </a-radio-group>
<div class="form-help">设置后立即生效即使关闭 ds 也会继续保持</div> <div class="form-help">
设置后立即生效即使关闭 ds 也会继续保持
</div>
</a-form-item> </a-form-item>
<a-form-item label="yarn仓库镜像" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="yarn仓库镜像" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-radio-group v-model="config.plugin.node.setting.yarnRegistry" :default-value="'null'" @change="onSwitchYarnRegistry" button-style="solid"> <a-radio-group v-model="config.plugin.node.setting.yarnRegistry" default-value="null" button-style="solid" @change="onSwitchYarnRegistry">
<a-radio-button :value="'null'" title="https://registry.yarnpkg.com"> <a-radio-button value="default" title="https://registry.yarnpkg.com">
yarn原生 yarn原生
</a-radio-button> </a-radio-button>
<a-radio-button value="https://registry.npmmirror.com" title="https://registry.npmmirror.com"> <a-radio-button value="https://registry.npmmirror.com" title="https://registry.npmmirror.com">
taobao镜像 taobao镜像
</a-radio-button> </a-radio-button>
</a-radio-group> </a-radio-group>
<div class="form-help">设置后立即生效即使关闭 ds 也会继续保持</div> <div class="form-help">
设置后立即生效即使关闭 ds 也会继续保持
</div>
</a-form-item> </a-form-item>
<a-form-item label="镜像变量设置" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="镜像变量设置" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.plugin.node.startup.variables"> <a-checkbox v-model="config.plugin.node.startup.variables">
自动设置启动npm加速开关时将会设置如下环境变量 自动设置启动npm加速开关时将会设置如下环境变量
</a-checkbox> </a-checkbox>
<div class="form-help">某些库需要自己设置镜像变量才能下载比如<code>electron</code></div> <div class="form-help">
<a-row :gutter="10" style="margin-top: 2px" v-for="(item,index) of npmVariables" :key='index'> 某些库需要自己设置镜像变量才能下载比如<code>electron</code>
</div>
<a-row v-for="(item, index) of npmVariables" :key="index" :gutter="10" style="margin-top: 2px">
<a-col :span="10"> <a-col :span="10">
<a-input v-model="item.key" :title="item.key" readOnly></a-input> <a-input v-model="item.key" :title="item.key" read-only />
</a-col> </a-col>
<a-col :span="10"> <a-col :span="10">
<a-input v-model="item.value" :title="item.value" readOnly></a-input> <a-input v-model="item.value" :title="item.value" read-only />
</a-col> </a-col>
<a-col :span="4"> <a-col :span="4">
<a-icon v-if="item.exists && item.hadSet" title="已设置" style="color:green" type="check"/> <a-icon v-if="item.exists && item.hadSet" title="已设置" style="color:green" type="check" />
<a-icon v-else title="还未设置" style="color:red" type="exclamation-circle"/> <a-icon v-else title="还未设置" style="color:red" type="exclamation-circle" />
</a-col> </a-col>
</a-row> </a-row>
</a-form-item> </a-form-item>

View File

@ -152,12 +152,12 @@ export default {
<span>PAC没有拦截到的域名可以在此处定义配置为<code>禁用</code>将不使用梯子</span> <span>PAC没有拦截到的域名可以在此处定义配置为<code>禁用</code>将不使用梯子</span>
</a-col> </a-col>
<a-col :span="2"> <a-col :span="2">
<a-button type="primary" icon="plus" @click="addTarget()"/> <a-button type="primary" icon="plus" @click="addTarget()" />
</a-col> </a-col>
</a-row> </a-row>
<a-row :gutter="10" v-for="(item,index) of targets" :key="index"> <a-row v-for="(item, index) of targets" :key="index" :gutter="10">
<a-col :span="18"> <a-col :span="18">
<a-input v-model="item.key"></a-input> <a-input v-model="item.key" />
</a-col> </a-col>
<a-col :span="4"> <a-col :span="4">
<a-select v-model="item.value" style="width:100%"> <a-select v-model="item.value" style="width:100%">
@ -167,7 +167,7 @@ export default {
</a-select> </a-select>
</a-col> </a-col>
<a-col :span="2"> <a-col :span="2">
<a-button type="danger" icon="minus" @click="deleteTarget(item,index)"/> <a-button type="danger" icon="minus" @click="deleteTarget(item, index)" />
</a-col> </a-col>
</a-row> </a-row>
</div> </div>
@ -179,24 +179,24 @@ export default {
<span>Nginx二层代理服务端配置</span> <span>Nginx二层代理服务端配置</span>
</a-col> </a-col>
<a-col :span="2"> <a-col :span="2">
<a-button type="primary" icon="plus" @click="addServer()"/> <a-button type="primary" icon="plus" @click="addServer()" />
</a-col> </a-col>
</a-row> </a-row>
<a-row :gutter="10" v-for="(item,index) of servers" :key="index"> <a-row v-for="(item, index) of servers" :key="index" :gutter="10">
<a-col :span="6"> <a-col :span="6">
<a-input addon-before="" placeholder="yourdomain.com" v-model="item.key"/> <a-input v-model="item.key" addon-before="" placeholder="yourdomain.com" />
</a-col> </a-col>
<a-col :span="5"> <a-col :span="5">
<a-input addon-before="" placeholder="443" v-model="item.value.port"/> <a-input v-model="item.value.port" addon-before="" placeholder="443" />
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-input addon-before="" placeholder="xxxxxx" v-model="item.value.path"/> <a-input v-model="item.value.path" addon-before="" placeholder="xxxxxx" />
</a-col> </a-col>
<a-col :span="5"> <a-col :span="5">
<a-input addon-before="" type="password" placeholder="password" v-model="item.value.password"/> <a-input v-model="item.value.password" addon-before="" type="password" placeholder="password" />
</a-col> </a-col>
<a-col :span="2"> <a-col :span="2">
<a-button type="danger" icon="minus" @click="deleteServer(item,index)"/> <a-button type="danger" icon="minus" @click="deleteServer(item, index)" />
</a-col> </a-col>
</a-row> </a-row>
<div class="form-help"> <div class="form-help">

View File

@ -2,7 +2,7 @@
import Plugin from '../../mixins/plugin' import Plugin from '../../mixins/plugin'
export default { export default {
name: 'pip', name: 'Pip',
mixins: [Plugin], mixins: [Plugin],
data () { data () {
return { return {
@ -37,7 +37,6 @@ export default {
this.config.plugin.pip.setting.trustedHost = domain this.config.plugin.pip.setting.trustedHost = domain
await this.apply() await this.apply()
} }
} }
} }
</script> </script>
@ -46,30 +45,32 @@ export default {
<ds-container> <ds-container>
<template slot="header"> <template slot="header">
PIP加速 PIP加速
<span style="color:#999;">
</span>
</template> </template>
<div v-if="config"> <div v-if="config">
<a-form layout="horizontal"> <a-form layout="horizontal">
<!-- <a-form-item label="启用PIP加速" :label-col="labelCol" :wrapper-col="wrapperCol">--> <!-- <a-form-item label="启用PIP加速" :label-col="labelCol" :wrapper-col="wrapperCol"> -->
<!-- <a-checkbox v-model="config.plugin.pip.enabled">--> <!-- <a-checkbox v-model="config.plugin.pip.enabled"> -->
<!-- 随应用启动--> <!-- 随应用启动 -->
<!-- </a-checkbox>--> <!-- </a-checkbox> -->
<!-- <a-tag v-if="status.plugin.pip.enabled" color="green">--> <!-- <a-tag v-if="status.plugin.pip.enabled" color="green"> -->
<!-- 当前已启动--> <!-- 当前已启动 -->
<!-- </a-tag>--> <!-- </a-tag> -->
<!-- <a-tag v-else color="red">--> <!-- <a-tag v-else color="red"> -->
<!-- 当前未启动--> <!-- 当前未启动 -->
<!-- </a-tag>--> <!-- </a-tag> -->
<!-- </a-form-item>--> <!-- </a-form-item> -->
<a-form-item label="pip命令名" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="pip命令名" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input v-model="config.plugin.pip.setting.command"></a-input> <a-input v-model="config.plugin.pip.setting.command" />
<div class="form-help">如果你的<code>pip</code>命令改成了其他名字<code>pip3</code>或想设置绿色版<code>pip</code>程序路径可在此处修改</div> <div class="form-help">
如果你的<code>pip</code>命令改成了其他名字<code>pip3</code>或想设置绿色版<code>pip</code>程序路径可在此处修改
</div>
</a-form-item> </a-form-item>
<a-form-item label="仓库镜像" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="仓库镜像" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-radio-group v-model="config.plugin.pip.setting.registry" @change="onSwitchRegistry" <a-radio-group
default-value="https://pypi.org/simple/" button-style="solid"> v-model="config.plugin.pip.setting.registry" default-value="https://pypi.org/simple/"
button-style="solid" @change="onSwitchRegistry"
>
<a-radio-button value="https://pypi.org/simple/" title="https://pypi.org/simple/"> <a-radio-button value="https://pypi.org/simple/" title="https://pypi.org/simple/">
原生 原生
</a-radio-button> </a-radio-button>
@ -104,10 +105,12 @@ export default {
山东理工大学镜像 山东理工大学镜像
</a-radio-button> </a-radio-button>
</a-radio-group> </a-radio-group>
<div class="form-help">设置后立即生效即使关闭 ds 也会继续保持</div> <div class="form-help">
设置后立即生效即使关闭 ds 也会继续保持
</div>
</a-form-item> </a-form-item>
<a-form-item label="信任仓库域名" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="信任仓库域名" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input v-model="config.plugin.pip.setting.trustedHost"></a-input> <a-input v-model="config.plugin.pip.setting.trustedHost" />
<div class="form-help"> <div class="form-help">
使用以上域名安装包时不会进行SSL证书验证多个域名用空格隔开<br/> 使用以上域名安装包时不会进行SSL证书验证多个域名用空格隔开<br/>
注意切换仓库镜像同时会修改<code>pip.ini</code>中的<code>trusted-host</code>配置即使关闭 ds 也会继续保持 注意切换仓库镜像同时会修改<code>pip.ini</code>中的<code>trusted-host</code>配置即使关闭 ds 也会继续保持

View File

@ -1,5 +1,6 @@
<script> <script>
import Plugin from '../mixins/plugin' import Plugin from '../mixins/plugin'
export default { export default {
name: 'Proxy', name: 'Proxy',
mixins: [Plugin], mixins: [Plugin],
@ -31,11 +32,11 @@ export default {
try { try {
await this.$api.proxy.setEnableLoopback() await this.$api.proxy.setEnableLoopback()
} catch (e) { } catch (e) {
if (e.message.indexOf('EACCES') !== -1) { if (e.message.includes('EACCES')) {
this.$message.error('请将DevSidecar关闭后以管理员身份重新打开再尝试此操作') this.$message.error('请将DevSidecar关闭后以管理员身份重新打开再尝试此操作')
return return
} }
this.$message.error('打开失败:' + e.message) this.$message.error(`打开失败:${e.message}`)
} }
}, },
getProxyConfig () { getProxyConfig () {
@ -73,13 +74,11 @@ export default {
<ds-container> <ds-container>
<template slot="header"> <template slot="header">
系统代理设置 系统代理设置
<span>
</span>
</template> </template>
<div v-if="config"> <div v-if="config">
<a-form-item label="启用系统代理" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="启用系统代理" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.proxy.enabled" > <a-checkbox v-model="config.proxy.enabled">
随应用启动 随应用启动
</a-checkbox> </a-checkbox>
<a-tag v-if="status.proxy.enabled" color="green"> <a-tag v-if="status.proxy.enabled" color="green">
@ -93,7 +92,7 @@ export default {
</div> </div>
</a-form-item> </a-form-item>
<a-form-item label="代理HTTP请求" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="代理HTTP请求" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.proxy.proxyHttp" > <a-checkbox v-model="config.proxy.proxyHttp">
是否代理HTTP请求 是否代理HTTP请求
</a-checkbox> </a-checkbox>
<div class="form-help"> <div class="form-help">
@ -104,7 +103,7 @@ export default {
<!-- 以下两个功能仅windows支持mac和linux暂不支持 --> <!-- 以下两个功能仅windows支持mac和linux暂不支持 -->
<a-form-item v-if="isWindows()" label="设置环境变量" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item v-if="isWindows()" label="设置环境变量" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.proxy.setEnv" > <a-checkbox v-model="config.proxy.setEnv">
是否同时修改<code>HTTPS_PROXY</code>环境变量不好用不建议勾选 是否同时修改<code>HTTPS_PROXY</code>环境变量不好用不建议勾选
</a-checkbox> </a-checkbox>
<div class="form-help"> <div class="form-help">
@ -113,18 +112,20 @@ export default {
</div> </div>
</a-form-item> </a-form-item>
<a-form-item v-if="isWindows()" label="设置loopback" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item v-if="isWindows()" label="设置loopback" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-button @click="loopbackVisible=true"></a-button> <a-button @click="loopbackVisible = true">去设置</a-button>
<div class="form-help">解决<code>OneNote</code><code>MicrosoftStore</code><code>Outlook</code><code>UWP应用</code>开启代理后无法访问网络的问题</div> <div class="form-help">
解决<code>OneNote</code><code>MicrosoftStore</code><code>Outlook</code><code>UWP应用</code>开启代理后无法访问网络的问题
</div>
</a-form-item> </a-form-item>
<hr/> <hr/>
<a-form-item label="排除国内域名" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="排除国内域名" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.proxy.excludeDomesticDomainAllowList" > <a-checkbox v-model="config.proxy.excludeDomesticDomainAllowList">
是否排除国内域名白名单 是否排除国内域名白名单
</a-checkbox> </a-checkbox>
</a-form-item> </a-form-item>
<a-form-item label="自动更新国内域名" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="自动更新国内域名" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.proxy.autoUpdateDomesticDomainAllowList" > <a-checkbox v-model="config.proxy.autoUpdateDomesticDomainAllowList">
是否自动更新国内域名白名单 是否自动更新国内域名白名单
</a-checkbox> </a-checkbox>
<div class="form-help"> <div class="form-help">
@ -133,7 +134,7 @@ export default {
</div> </div>
</a-form-item> </a-form-item>
<a-form-item label="远程国内域名地址" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="远程国内域名地址" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input v-model="config.proxy.remoteDomesticDomainAllowListFileUrl" :title="config.proxy.remoteDomesticDomainAllowListFileUrl"></a-input> <a-input v-model="config.proxy.remoteDomesticDomainAllowListFileUrl" :title="config.proxy.remoteDomesticDomainAllowListFileUrl" />
<div class="form-help"> <div class="form-help">
远程国内域名白名单文件内容可以是<code>base64</code>编码格式也可以是未经过编码的 远程国内域名白名单文件内容可以是<code>base64</code>编码格式也可以是未经过编码的
</div> </div>
@ -145,15 +146,15 @@ export default {
<span>访问的域名或IP符合下列配置时将跳过系统代理</span> <span>访问的域名或IP符合下列配置时将跳过系统代理</span>
</a-col> </a-col>
<a-col :span="2"> <a-col :span="2">
<a-button type="primary" icon="plus" @click="addExcludeIp()"/> <a-button type="primary" icon="plus" @click="addExcludeIp()" />
</a-col> </a-col>
</a-row> </a-row>
<a-row :gutter="10" v-for="(item,index) of excludeIpList" :key='index'> <a-row v-for="(item, index) of excludeIpList" :key="index" :gutter="10">
<a-col :span="22"> <a-col :span="22">
<a-input :disabled="item.value === false" v-model="item.key"></a-input> <a-input v-model="item.key" :disabled="item.value === false" />
</a-col> </a-col>
<a-col :span="2"> <a-col :span="2">
<a-button type="danger" icon="minus" @click="delExcludeIp(item,index)"/> <a-button type="danger" icon="minus" @click="delExcludeIp(item, index)" />
</a-col> </a-col>
</a-row> </a-row>
</a-form-item> </a-form-item>
@ -171,12 +172,13 @@ export default {
:visible.sync="loopbackVisible" :visible.sync="loopbackVisible"
width="660px" width="660px"
height="100%" height="100%"
@close="loopbackVisible=false"
:slots="{ title: 'title' }" :slots="{ title: 'title' }"
wrapClassName="json-wrapper" wrap-class-name="json-wrapper"
@close="loopbackVisible = false"
> >
<template slot="title"> <template slot="title">
设置Loopback <a-button style="float:right;margin-right:10px;" @click="openEnableLoopback()">EnableLoopback</a-button> 设置Loopback
<a-button style="float:right;margin-right:10px;" @click="openEnableLoopback()">EnableLoopback</a-button>
</template> </template>
<div> <div>
<div>1此设置用于解决OneNoteMicrosoftStoreOutlook等UWP应用无法访问网络的问题</div> <div>1此设置用于解决OneNoteMicrosoftStoreOutlook等UWP应用无法访问网络的问题</div>
@ -184,8 +186,6 @@ export default {
<div>3注意此操作需要<b style="color:red">DevSidecar以管理员身份启动</b>才能打开下面的EnableLoopback设置界面</div> <div>3注意此操作需要<b style="color:red">DevSidecar以管理员身份启动</b>才能打开下面的EnableLoopback设置界面</div>
<img style="margin-top:20px;border:1px solid #eee" width="80%" src="loopback.png"/> <img style="margin-top:20px;border:1px solid #eee" width="80%" src="loopback.png"/>
</div> </div>
</a-drawer> </a-drawer>
</ds-container> </ds-container>
</template> </template>

View File

@ -1,12 +1,12 @@
<script> <script>
import vueJsonEditor from 'vue-json-editor-fix-cn'
import Plugin from '../mixins/plugin'
import _ from 'lodash' import _ from 'lodash'
import VueJsonEditor from 'vue-json-editor-fix-cn'
import Plugin from '../mixins/plugin'
export default { export default {
name: 'Server', name: 'Server',
components: { components: {
vueJsonEditor VueJsonEditor
}, },
mixins: [Plugin], mixins: [Plugin],
data () { data () {
@ -17,11 +17,6 @@ export default {
whiteList: [] whiteList: []
} }
}, },
created () {
},
mounted () {
this.registerSpeedTestEvent()
},
computed: { computed: {
speedDnsOptions () { speedDnsOptions () {
const options = [] const options = []
@ -37,6 +32,11 @@ export default {
return options return options
} }
}, },
created () {
},
mounted () {
this.registerSpeedTestEvent()
},
methods: { methods: {
async onCrtSelect () { async onCrtSelect () {
const value = await this.$api.fileSelector.open() const value = await this.$api.fileSelector.open()
@ -122,7 +122,7 @@ export default {
}, },
async openLog () { async openLog () {
const dir = await this.$api.info.getConfigDir() const dir = await this.$api.info.getConfigDir()
this.$api.ipc.openPath(dir + '/logs/') this.$api.ipc.openPath(`${dir}/logs/`)
}, },
getSpeedTestConfig () { getSpeedTestConfig () {
return this.config.server.dns.speedTest return this.config.server.dns.speedTest
@ -178,19 +178,17 @@ export default {
<ds-container> <ds-container>
<template slot="header"> <template slot="header">
加速服务设置 加速服务设置
<span>
</span>
</template> </template>
<div style="height: 100%" class="json-wrapper"> <div style="height: 100%" class="json-wrapper">
<a-tabs <a-tabs
v-if="config"
default-active-key="1" default-active-key="1"
tab-position="left" tab-position="left"
:style="{ height: '100%' }" :style="{ height: '100%' }"
v-if="config"
@change="handleTabChange" @change="handleTabChange"
> >
<a-tab-pane tab="基本设置" key="1"> <a-tab-pane key="1" tab="基本设置">
<div style="padding-right:10px"> <div style="padding-right:10px">
<a-form-item label="代理服务:" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="代理服务:" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.server.enabled"> <a-checkbox v-model="config.server.enabled">
@ -205,148 +203,174 @@ export default {
<a-button class="md-mr-10" icon="profile" @click="openLog()"></a-button> <a-button class="md-mr-10" icon="profile" @click="openLog()"></a-button>
</a-form-item> </a-form-item>
<a-form-item label="绑定IP" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="绑定IP" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input v-model="config.server.host"/> <a-input v-model="config.server.host" />
<div class="form-help">你可以设置为<code>0.0.0.0</code>让其他电脑可以使用此代理服务</div> <div class="form-help">
你可以设置为<code>0.0.0.0</code>让其他电脑可以使用此代理服务
</div>
</a-form-item> </a-form-item>
<a-form-item label="代理端口" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="代理端口" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input-number v-model="config.server.port" :min="0" :max="65535"/> <a-input-number v-model="config.server.port" :min="0" :max="65535" />
<div class="form-help">修改后需要重启应用</div> <div class="form-help">
修改后需要重启应用
</div>
</a-form-item> </a-form-item>
<hr/> <hr/>
<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.server.setting.NODE_TLS_REJECT_UNAUTHORIZED"> <a-checkbox v-model="config.server.setting.NODE_TLS_REJECT_UNAUTHORIZED">
NODE_TLS_REJECT_UNAUTHORIZED NODE_TLS_REJECT_UNAUTHORIZED
</a-checkbox> </a-checkbox>
<div class="form-help">高风险操作没有特殊情况请勿关闭</div> <div class="form-help">
高风险操作没有特殊情况请勿关闭
</div>
</a-form-item> </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.server.setting.verifySsl"> <a-checkbox v-model="config.server.setting.verifySsl">
校验加速目标网站的ssl证书 校验加速目标网站的ssl证书
</a-checkbox> </a-checkbox>
<div class="form-help">如果目标网站证书有问题但你想强行访问可以临时关闭此项</div> <div class="form-help">
如果目标网站证书有问题但你想强行访问可以临时关闭此项
</div>
</a-form-item> </a-form-item>
<a-form-item label="根证书" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="根证书" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input-search addon-before="Cert" enter-button="" @search="onCrtSelect" <a-input-search
v-model="config.server.setting.rootCaFile.certPath" v-model="config.server.setting.rootCaFile.certPath" addon-before="Cert" enter-button="选择"
:title="config.server.setting.rootCaFile.certPath"/> :title="config.server.setting.rootCaFile.certPath"
<a-input-search addon-before="Key" enter-button="" @search="onKeySelect" @search="onCrtSelect"
v-model="config.server.setting.rootCaFile.keyPath" />
:title="config.server.setting.rootCaFile.keyPath"/> <a-input-search
v-model="config.server.setting.rootCaFile.keyPath" addon-before="Key" enter-button="选择"
:title="config.server.setting.rootCaFile.keyPath"
@search="onKeySelect"
/>
</a-form-item> </a-form-item>
<hr/> <hr/>
<a-form-item label="启用拦截" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="启用拦截" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.server.intercept.enabled"> <a-checkbox v-model="config.server.intercept.enabled">
启用拦截 启用拦截
</a-checkbox> </a-checkbox>
<div class="form-help">关闭拦截且关闭功能增强时就不需要安装根证书退化为安全模式</div> <div class="form-help">
关闭拦截且关闭功能增强时就不需要安装根证书退化为安全模式
</div>
</a-form-item> </a-form-item>
<a-form-item label="启用脚本" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="启用脚本" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.server.setting.script.enabled"> <a-checkbox v-model="config.server.setting.script.enabled">
允许插入并运行脚本 允许插入并运行脚本
</a-checkbox> </a-checkbox>
<div class="form-help">关闭后<code>Github油猴脚本</code>也将关闭</div> <div class="form-help">
关闭后<code>Github油猴脚本</code>也将关闭
</div>
</a-form-item> </a-form-item>
</div> </div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane tab="拦截设置" key="2"> <a-tab-pane key="2" tab="拦截设置">
<vue-json-editor style="height:100%" ref="editor" v-model="config.server.intercepts" mode="code" <VueJsonEditor
:show-btns="false" :expandedOnStart="true"></vue-json-editor> ref="editor" v-model="config.server.intercepts" style="height:100%" mode="code"
:show-btns="false" :expanded-on-start="true"
/>
</a-tab-pane> </a-tab-pane>
<a-tab-pane tab="超时时间设置" key="3"> <a-tab-pane key="3" tab="超时时间设置">
<div style="height:100%;display:flex;flex-direction:column;padding-right:10px"> <div style="height:100%;display:flex;flex-direction:column;padding-right:10px">
<a-form-item label="默认超时时间" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="默认超时时间" :label-col="labelCol" :wrapper-col="wrapperCol">
请求<a-input-number v-model="config.server.setting.defaultTimeout" :step="1000" :min="1000"/> ms对应<code>timeout</code>配置<br/> 请求<a-input-number v-model="config.server.setting.defaultTimeout" :step="1000" :min="1000" /> ms对应<code>timeout</code>配置<br>
连接<a-input-number v-model="config.server.setting.defaultKeepAliveTimeout" :step="1000" :min="1000"/> ms对应<code>keepAliveTimeout</code>配置 连接<a-input-number v-model="config.server.setting.defaultKeepAliveTimeout" :step="1000" :min="1000" /> ms对应<code>keepAliveTimeout</code>配置
</a-form-item> </a-form-item>
<hr style="margin-bottom:15px"/> <hr style="margin-bottom:15px"/>
<div>这里指定域名的超时时间<span class="form-help">域名配置可使用通配符或正则</span></div> <div>这里指定域名的超时时间<span class="form-help">域名配置可使用通配符或正则</span></div>
<vue-json-editor style="flex-grow:1;min-height:300px;margin-top:10px" ref="editor" v-model="config.server.setting.timeoutMapping" mode="code" <VueJsonEditor
:show-btns="false" :expandedOnStart="true"></vue-json-editor> ref="editor" v-model="config.server.setting.timeoutMapping" style="flex-grow:1;min-height:300px;margin-top:10px" mode="code"
:show-btns="false" :expanded-on-start="true"
/>
</div> </div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane tab="域名白名单" key="4"> <a-tab-pane key="4" tab="域名白名单">
<a-row style="margin-top:10px"> <a-row style="margin-top:10px">
<a-col span="19"> <a-col span="19">
<div>这里配置的域名不会通过代理</div> <div>这里配置的域名不会通过代理</div>
</a-col> </a-col>
<a-col span="3"> <a-col span="3">
<a-button style="margin-left:8px" type="primary" icon="plus" @click="addWhiteList()"/> <a-button style="margin-left:8px" type="primary" icon="plus" @click="addWhiteList()" />
</a-col> </a-col>
</a-row> </a-row>
<a-row :gutter="10" style="margin-top: 5px" v-for="(item,index) of whiteList" :key='index'> <a-row v-for="(item, index) of whiteList" :key="index" :gutter="10" style="margin-top: 5px">
<a-col :span="19"> <a-col :span="19">
<a-input :disabled="item.value === false" v-model="item.key"></a-input> <a-input v-model="item.key" :disabled="item.value === false" />
</a-col> </a-col>
<a-col :span="3"> <a-col :span="3">
<a-button v-if="item.value !== false" type="danger" icon="minus" @click="deleteWhiteList(item,index)"/> <a-button v-if="item.value !== false" type="danger" icon="minus" @click="deleteWhiteList(item, index)" />
</a-col> </a-col>
</a-row> </a-row>
</a-tab-pane> </a-tab-pane>
<a-tab-pane tab="自动兼容程序" key="5"> <a-tab-pane key="5" tab="自动兼容程序">
<div style="height:100%;display:flex;flex-direction:column"> <div style="height:100%;display:flex;flex-direction:column">
<div> <div>
说明<code>自动兼容程序</code>会自动根据错误信息进行兼容性调整并将兼容设置保存在 <code>~/.dev-sidecar/automaticCompatibleConfig.json</code> 说明<code>自动兼容程序</code>会自动根据错误信息进行兼容性调整并将兼容设置保存在 <code>~/.dev-sidecar/automaticCompatibleConfig.json</code>
</div> </div>
<vue-json-editor style="flex-grow:1;min-height:300px;margin-top:10px;" ref="editor" v-model="config.server.compatible" mode="code" <VueJsonEditor
:show-btns="false" :expandedOnStart="true"></vue-json-editor> ref="editor" v-model="config.server.compatible" style="flex-grow:1;min-height:300px;margin-top:10px;" mode="code"
:show-btns="false" :expanded-on-start="true"
/>
</div> </div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane tab="IP预设置" key="6"> <a-tab-pane key="6" tab="IP预设置">
<div style="height:100%;display:flex;flex-direction:column"> <div style="height:100%;display:flex;flex-direction:column">
<div> <div>
提示<code>IP预设置</code>功能优先级高于 <code>DNS设置</code> 提示<code>IP预设置</code>功能优先级高于 <code>DNS设置</code>
<span class="form-help">域名配置可使用通配符或正则</span> <span class="form-help">域名配置可使用通配符或正则</span>
</div> </div>
<vue-json-editor style="flex-grow:1;min-height:300px;margin-top:10px;" ref="editor" v-model="config.server.preSetIpList" mode="code" <VueJsonEditor
:show-btns="false" :expandedOnStart="true"></vue-json-editor> ref="editor" v-model="config.server.preSetIpList" style="flex-grow:1;min-height:300px;margin-top:10px;" mode="code"
:show-btns="false" :expanded-on-start="true"
/>
</div> </div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane tab="DNS服务管理" key="7"> <a-tab-pane key="7" tab="DNS服务管理">
<vue-json-editor style="height:100%" ref="editor" v-model="config.server.dns.providers" mode="code" <VueJsonEditor
:show-btns="false" :expandedOnStart="true"></vue-json-editor> ref="editor" v-model="config.server.dns.providers" style="height:100%" mode="code"
:show-btns="false" :expanded-on-start="true"
/>
</a-tab-pane> </a-tab-pane>
<a-tab-pane tab="DNS设置" key="8"> <a-tab-pane key="8" tab="DNS设置">
<div> <div>
<a-row style="margin-top:10px"> <a-row style="margin-top:10px">
<a-col span="19"> <a-col span="19">
<div>这里配置哪些域名需要通过国外DNS服务器获取IP进行访问</div> <div>这里配置哪些域名需要通过国外DNS服务器获取IP进行访问</div>
</a-col> </a-col>
<a-col span="3"> <a-col span="3">
<a-button style="margin-left:8px" type="primary" icon="plus" @click="addDnsMapping()"/> <a-button style="margin-left:8px" type="primary" icon="plus" @click="addDnsMapping()" />
</a-col> </a-col>
</a-row> </a-row>
<a-row :gutter="10" style="margin-top: 5px" v-for="(item,index) of dnsMappings" :key='index'> <a-row v-for="(item, index) of dnsMappings" :key="index" :gutter="10" style="margin-top: 5px">
<a-col :span="14"> <a-col :span="14">
<a-input :disabled="item.value === false" v-model="item.key"></a-input> <a-input v-model="item.key" :disabled="item.value === false" />
</a-col> </a-col>
<a-col :span="5"> <a-col :span="5">
<a-select :disabled="item.value === false" v-model="item.value" style="width: 100%"> <a-select v-model="item.value" :disabled="item.value === false" style="width: 100%">
<a-select-option v-for="(item) of speedDnsOptions" :key="item.value" :value="item.value"> <a-select-option v-for="(item) of speedDnsOptions" :key="item.value" :value="item.value">
{{ item.value }} {{ item.value }}
</a-select-option> </a-select-option>
</a-select> </a-select>
</a-col> </a-col>
<a-col :span="3"> <a-col :span="3">
<a-button v-if="item.value !== false" type="danger" icon="minus" @click="deleteDnsMapping(item,index)"/> <a-button v-if="item.value !== false" type="danger" icon="minus" @click="deleteDnsMapping(item, index)" />
<a-button v-if="item.value === false" type="primary" icon="checked" @click="restoreDefDnsMapping(item,index)"/> <a-button v-if="item.value === false" type="primary" icon="checked" @click="restoreDefDnsMapping(item, index)" />
</a-col> </a-col>
</a-row> </a-row>
</div> </div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane tab="IP测速" key="9"> <a-tab-pane key="9" tab="IP测速">
<div class="ip-tester" style="padding-right: 10px"> <div class="ip-tester" style="padding-right: 10px">
<a-alert type="info" message="对从DNS获取到的IP进行测速使用速度最快的IP进行访问注意对使用了增强功能的域名没啥用"></a-alert> <a-alert type="info" message="对从DNS获取到的IP进行测速使用速度最快的IP进行访问注意对使用了增强功能的域名没啥用" />
<a-form-item label="开启DNS测速" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="开启DNS测速" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="getSpeedTestConfig().enabled"> <a-checkbox v-model="getSpeedTestConfig().enabled">
启用 启用
</a-checkbox> </a-checkbox>
</a-form-item> </a-form-item>
<a-form-item label="自动测试间隔" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="自动测试间隔" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input-number v-model="getSpeedTestConfig().interval" :step="1000" :min="1"/> ms <a-input-number v-model="getSpeedTestConfig().interval" :step="1000" :min="1" /> ms
</a-form-item> </a-form-item>
<!--<a-form-item label="慢速IP阈值" :label-col="labelCol" :wrapper-col="wrapperCol"> <!-- <a-form-item label="慢速IP阈值" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input-number v-model="config.server.setting.lowSpeedDelay" :step="10" :min="100"/> ms <a-input-number v-model="config.server.setting.lowSpeedDelay" :step="10" :min="100"/> ms
</a-form-item>--> </a-form-item> -->
<div>使用以下DNS获取IP进行测速</div> <div>使用以下DNS获取IP进行测速</div>
<a-row style="margin-top:10px"> <a-row style="margin-top:10px">
<a-col span="24"> <a-col span="24">
@ -361,20 +385,22 @@ export default {
以下域名在启动后立即进行测速其他域名在第一次访问时才测速 以下域名在启动后立即进行测速其他域名在第一次访问时才测速
</a-col> </a-col>
<a-col :span="2"> <a-col :span="2">
<a-button style="margin-left:10px" type="primary" icon="plus" @click="addSpeedHostname()"/> <a-button style="margin-left:10px" type="primary" icon="plus" @click="addSpeedHostname()" />
</a-col> </a-col>
</a-row> </a-row>
<a-row :gutter="10" style="margin-top: 5px" v-for="(item,index) of getSpeedTestConfig().hostnameList" <a-row
:key='index'> v-for="(item, index) of getSpeedTestConfig().hostnameList" :key="index" :gutter="10"
style="margin-top: 5px"
>
<a-col :span="21"> <a-col :span="21">
<a-input v-model="getSpeedTestConfig().hostnameList[index]"/> <a-input v-model="getSpeedTestConfig().hostnameList[index]" />
</a-col> </a-col>
<a-col :span="2"> <a-col :span="2">
<a-button style="margin-left:10px" type="danger" icon="minus" @click="delSpeedHostname(item,index)"/> <a-button style="margin-left:10px" type="danger" icon="minus" @click="delSpeedHostname(item, index)" />
</a-col> </a-col>
</a-row> </a-row>
<a-divider/> <a-divider />
<a-row :gutter="10" class="mt10"> <a-row :gutter="10" class="mt10">
<a-col span="24"> <a-col span="24">
<a-button type="primary" icon="plus" @click="reSpeedTest()"></a-button> <a-button type="primary" icon="plus" @click="reSpeedTest()"></a-button>
@ -383,14 +409,16 @@ export default {
</a-row> </a-row>
<a-row :gutter="20"> <a-row :gutter="20">
<a-col span="12" v-for="(item,key) of speedTestList" :key='key'> <a-col v-for="(item, key) of speedTestList" :key="key" span="12">
<a-card size="small" class="md-mt-10" :title="key"> <a-card size="small" class="md-mt-10" :title="key">
<a slot="extra" href="#"> <a slot="extra" href="#">
<a-icon v-if="item.alive.length>0" type="check"/> <a-icon v-if="item.alive.length > 0" type="check" />
<a-icon v-else type="info-circle"/> <a-icon v-else type="info-circle" />
</a> </a>
<a-tag style="margin:2px;" v-for="(element,index) of item.backupList" :title="element.dns" <a-tag
:color="element.time?(element.time>config.server.setting.lowSpeedDelay?'orange':'green'):'red'" :key='index'> v-for="(element, index) of item.backupList" :key="index" style="margin:2px;"
:title="element.dns" :color="element.time ? (element.time > config.server.setting.lowSpeedDelay ? 'orange' : 'green') : 'red'"
>
{{ element.host }} {{ element.time }}{{ element.time ? 'ms' : '' }} {{ element.dns }} {{ element.host }} {{ element.time }}{{ element.time ? 'ms' : '' }} {{ element.dns }}
</a-tag> </a-tag>
</a-card> </a-card>

View File

@ -1,6 +1,6 @@
<script> <script>
import Plugin from '../mixins/plugin'
import { ipcRenderer } from 'electron' import { ipcRenderer } from 'electron'
import Plugin from '../mixins/plugin'
export default { export default {
name: 'Setting', name: 'Setting',
@ -28,7 +28,7 @@ export default {
}, },
async openLog () { async openLog () {
const dir = await this.$api.info.getConfigDir() const dir = await this.$api.info.getConfigDir()
this.$api.ipc.openPath(dir + '/logs/') this.$api.ipc.openPath(`${dir}/logs/`)
}, },
getEventKey (event) { getEventKey (event) {
// //
@ -130,7 +130,7 @@ export default {
async disableBeforeInputEvent () { async disableBeforeInputEvent () {
clearTimeout(window.enableBeforeInputEventTimeout) clearTimeout(window.enableBeforeInputEventTimeout)
window.config.disableBeforeInputEvent = true window.config.disableBeforeInputEvent = true
window.enableBeforeInputEventTimeout = setTimeout(function () { window.enableBeforeInputEventTimeout = setTimeout(() => {
window.config.disableBeforeInputEvent = false window.config.disableBeforeInputEvent = false
}, 2000) }, 2000)
}, },
@ -158,12 +158,18 @@ export default {
// CtrlAltShiftWindow // CtrlAltShiftWindow
let shortcut = event.ctrlKey ? 'Ctrl + ' : '' let shortcut = event.ctrlKey ? 'Ctrl + ' : ''
if (event.altKey) shortcut += 'Alt + ' if (event.altKey) {
if (event.shiftKey) shortcut += 'Shift + ' shortcut += 'Alt + '
if (event.metaKey) shortcut += 'Meta + ' }
if (event.shiftKey) {
shortcut += 'Shift + '
}
if (event.metaKey) {
shortcut += 'Meta + '
}
// F1~F4F6~F11F5F12DevTools // F1~F4F6~F11F5F12DevTools
if (shortcut === '' && !key.match(/^F([12346789]|1[01])$/g)) { if (shortcut === '' && !key.match(/^F([1-46-9]|1[01])$/g)) {
this.config.app.showHideShortcut = '无' this.config.app.showHideShortcut = '无'
return return
} }
@ -250,7 +256,7 @@ export default {
this.$confirm({ this.$confirm({
title: '确定要恢复出厂设置吗?', title: '确定要恢复出厂设置吗?',
width: 610, width: 610,
content: h => content: (h) => (
<div class="restore-factory-settings"> <div class="restore-factory-settings">
<hr/> <hr/>
<p> <p>
@ -267,7 +273,8 @@ export default {
2. 将该备份文件重命名为<span>config.json</span>再重启软件即可恢复个性化配置 2. 将该备份文件重命名为<span>config.json</span>再重启软件即可恢复个性化配置
</div> </div>
</p> </p>
</div>, </div>
),
cancelText: '取消', cancelText: '取消',
okText: '确定', okText: '确定',
onOk: async () => { onOk: async () => {
@ -296,8 +303,6 @@ export default {
<ds-container> <ds-container>
<template slot="header"> <template slot="header">
设置 设置
<span>
</span>
</template> </template>
<div v-if="config"> <div v-if="config">
@ -330,10 +335,10 @@ export default {
</div> </div>
</a-form-item> </a-form-item>
<a-form-item label="共享远程配置地址" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="共享远程配置地址" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input v-model="config.app.remoteConfig.url" :title="config.app.remoteConfig.url"></a-input> <a-input v-model="config.app.remoteConfig.url" :title="config.app.remoteConfig.url" />
</a-form-item> </a-form-item>
<a-form-item label="个人远程配置地址" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="个人远程配置地址" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input v-model="config.app.remoteConfig.personalUrl" :title="config.app.remoteConfig.personalUrl"></a-input> <a-input v-model="config.app.remoteConfig.personalUrl" :title="config.app.remoteConfig.personalUrl" />
</a-form-item> </a-form-item>
<a-form-item label="重载远程配置" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="重载远程配置" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-button :disabled="config.app.remoteConfig.enabled === false" :loading="reloadLoading" icon="sync" @click="reloadRemoteConfig()"></a-button> <a-button :disabled="config.app.remoteConfig.enabled === false" :loading="reloadLoading" icon="sync" @click="reloadRemoteConfig()"></a-button>
@ -345,10 +350,10 @@ export default {
<hr/> <hr/>
<a-form-item label="主题设置" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="主题设置" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-radio-group v-model="config.app.theme" default-value="light" button-style="solid"> <a-radio-group v-model="config.app.theme" default-value="light" button-style="solid">
<a-radio-button :value="'light'" title="light"> <a-radio-button value="light" title="light">
亮色 亮色
</a-radio-button> </a-radio-button>
<a-radio-button :value="'dark'" title="dark"> <a-radio-button value="dark" title="dark">
暗色 暗色
</a-radio-button> </a-radio-button>
</a-radio-group> </a-radio-group>
@ -384,7 +389,7 @@ export default {
</a-form-item> </a-form-item>
<hr/> <hr/>
<a-form-item label="打开窗口快捷键" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="打开窗口快捷键" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input v-model="config.app.showHideShortcut" @change="shortcutChange" @keydown="shortcutKeyDown" @keyup="shortcutKeyUp"></a-input> <a-input v-model="config.app.showHideShortcut" @change="shortcutChange" @keydown="shortcutKeyDown" @keyup="shortcutKeyUp" />
<div class="form-help"> <div class="form-help">
部分快捷键已被占用F5=刷新页面F12=开发者工具DevTools 部分快捷键已被占用F5=刷新页面F12=开发者工具DevTools
</div> </div>
@ -403,8 +408,8 @@ export default {
</div> </div>
</a-form-item> </a-form-item>
<a-form-item label="启动时窗口大小" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="启动时窗口大小" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input-number v-model="config.app.windowSize.width" :step="50" :min="600" :max="2400"/>&nbsp;× <a-input-number v-model="config.app.windowSize.width" :step="50" :min="600" :max="2400" />&nbsp;×
<a-input-number v-model="config.app.windowSize.height" :step="50" :min="500" :max="2000"/> <a-input-number v-model="config.app.windowSize.height" :step="50" :min="500" :max="2000" />
</a-form-item> </a-form-item>
<hr/> <hr/>
<a-form-item label="自动检查更新" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="自动检查更新" :label-col="labelCol" :wrapper-col="wrapperCol">
@ -442,5 +447,4 @@ export default {
</div> </div>
</template> </template>
</ds-container> </ds-container>
</template> </template>

View File

@ -1,23 +1,23 @@
import Index from '../pages/index' import Index from '../pages/index'
import Server from '../pages/server' import Server from '../pages/server'
import Proxy from '../pages/proxy' import Proxy from '../pages/proxy'
import Setting from '../pages/setting'
import Node from '../pages/plugin/node' import Node from '../pages/plugin/node'
import Git from '../pages/plugin/git' import Git from '../pages/plugin/git'
import Pip from '../pages/plugin/pip' import Pip from '../pages/plugin/pip'
import Overwall from '../pages/plugin/overwall' import Overwall from '../pages/plugin/overwall'
import Setting from '../pages/setting'
const routes = [ const routes = [
{ path: '/', redirect: '/index' }, { path: '/', redirect: '/index' },
{ path: '/index', component: Index }, { path: '/index', component: Index },
{ path: '/server', component: Server }, { path: '/server', component: Server },
{ path: '/proxy', component: Proxy }, { path: '/proxy', component: Proxy },
{ path: '/setting', component: Setting },
{ path: '/plugin/node', component: Node }, { path: '/plugin/node', component: Node },
{ path: '/plugin/git', component: Git }, { path: '/plugin/git', component: Git },
{ path: '/plugin/pip', component: Pip }, { path: '/plugin/pip', component: Pip },
{ path: '/plugin/overwall', component: Overwall }, { path: '/plugin/overwall', component: Overwall }
{ path: '/setting', component: Setting }
] ]
export default routes export default routes

View File

@ -1,8 +1,13 @@
const path = require('path') const path = require('path')
const webpack = require('webpack') const webpack = require('webpack')
const publishUrl = process.env.VUE_APP_PUBLISH_URL const publishUrl = process.env.VUE_APP_PUBLISH_URL
const publishProvider = process.env.VUE_APP_PUBLISH_PROVIDER const publishProvider = process.env.VUE_APP_PUBLISH_PROVIDER
console.log('Publish url:', publishUrl) console.log('Publish url:', publishUrl)
/**
* @type {import('@vue/cli-service').ProjectOptions}
*/
module.exports = { module.exports = {
pages: { pages: {
index: { index: {
@ -11,7 +16,7 @@ module.exports = {
} }
}, },
configureWebpack: (config) => { configureWebpack: (config) => {
const configNew = { return {
plugins: [ plugins: [
new webpack.DefinePlugin({ 'global.GENTLY': true }) new webpack.DefinePlugin({ 'global.GENTLY': true })
], ],
@ -28,7 +33,6 @@ module.exports = {
] ]
} }
} }
return configNew
}, },
pluginOptions: { pluginOptions: {
electronBuilder: { electronBuilder: {

View File

@ -1,13 +1,14 @@
const mitmproxy = require('./lib/proxy') const mitmproxy = require('./lib/proxy')
const ProxyOptions = require('./options')
const proxyConfig = require('./lib/proxy/common/config') const proxyConfig = require('./lib/proxy/common/config')
const speedTest = require('./lib/speed/index.js')
const ProxyOptions = require('./options')
const log = require('./utils/util.log') const log = require('./utils/util.log')
const { fireError, fireStatus } = require('./utils/util.process') const { fireError, fireStatus } = require('./utils/util.process')
const speedTest = require('./lib/speed/index.js')
let servers = [] let servers = []
function registerProcessListener () { function registerProcessListener () {
process.on('message', function (msg) { process.on('message', (msg) => {
log.info('child get msg:', JSON.stringify(msg)) log.info('child get msg:', JSON.stringify(msg))
if (msg.type === 'action') { if (msg.type === 'action') {
api[msg.event.key](msg.event.params) api[msg.event.key](msg.event.params)
@ -22,7 +23,7 @@ function registerProcessListener () {
}) })
// 避免异常崩溃 // 避免异常崩溃
process.on('uncaughtException', function (err) { process.on('uncaughtException', (err) => {
if (err.code === 'ECONNABORTED') { if (err.code === 'ECONNABORTED') {
// log.error(err.errno) // log.error(err.errno)
return return
@ -37,7 +38,7 @@ function registerProcessListener () {
process.on('uncaughtExceptionMonitor', (err, origin) => { process.on('uncaughtExceptionMonitor', (err, origin) => {
log.info('Process uncaughtExceptionMonitor:', err, origin) log.info('Process uncaughtExceptionMonitor:', err, origin)
}) })
process.on('exit', function (code, signal) { process.on('exit', (code, signal) => {
log.info('代理服务进程被关闭:', code, signal) log.info('代理服务进程被关闭:', code, signal)
}) })
process.on('beforeExit', (code, signal) => { process.on('beforeExit', (code, signal) => {

View File

@ -1,6 +1,8 @@
const LRU = require('lru-cache') const LRU = require('lru-cache')
const cacheSize = 1024
const log = require('../../utils/util.log') const log = require('../../utils/util.log')
const cacheSize = 1024
class ChoiceCache { class ChoiceCache {
constructor () { constructor () {
this.cache = new LRU(cacheSize) this.cache = new LRU(cacheSize)

View File

@ -1,12 +1,8 @@
const LRU = require('lru-cache') const LRU = require('lru-cache')
// const { isIP } = require('validator')
const log = require('../../utils/util.log') const log = require('../../utils/util.log')
const { DynamicChoice } = require('../choice/index') const { DynamicChoice } = require('../choice/index')
const cacheSize = 1024 const cacheSize = 1024
// eslint-disable-next-line no-unused-vars
// function _isIP (v) {
// return v && isIP(v)
// }
class IpCache extends DynamicChoice { class IpCache extends DynamicChoice {
constructor (hostname) { constructor (hostname) {

View File

@ -1,14 +1,17 @@
const { promisify } = require('util') const { promisify } = require('util')
const doh = require('dns-over-http') const doh = require('dns-over-http')
const BaseDNS = require('./base')
const log = require('../../utils/util.log') const log = require('../../utils/util.log')
const dohQueryAsync = promisify(doh.query)
const matchUtil = require('../../utils/util.match') const matchUtil = require('../../utils/util.match')
const BaseDNS = require('./base')
const dohQueryAsync = promisify(doh.query)
function mapToList (ipMap) { function mapToList (ipMap) {
const ipList = [] const ipList = []
for (const key in ipMap) { for (const key in ipMap) {
if (!ipMap[key]) continue if (!ipMap[key]) {
continue
}
ipList.push(ipMap[key]) ipList.push(ipMap[key])
} }
return ipList return ipList

View File

@ -1,8 +1,8 @@
const DNSOverTLS = require('./tls.js') const matchUtil = require('../../utils/util.match')
const DNSOverHTTPS = require('./https.js') const DNSOverHTTPS = require('./https.js')
const DNSOverIpAddress = require('./ipaddress.js') const DNSOverIpAddress = require('./ipaddress.js')
const DNSOverPreSetIpList = require('./preset.js') const DNSOverPreSetIpList = require('./preset.js')
const matchUtil = require('../../utils/util.match') const DNSOverTLS = require('./tls.js')
module.exports = { module.exports = {
initDNS (dnsProviders, preSetIpList) { initDNS (dnsProviders, preSetIpList) {

View File

@ -1,6 +1,7 @@
const BaseDNS = require('./base')
const axios = require('axios') const axios = require('axios')
const log = require('../../utils/util.log') const log = require('../../utils/util.log')
const BaseDNS = require('./base')
module.exports = class DNSOverIpAddress extends BaseDNS { module.exports = class DNSOverIpAddress extends BaseDNS {
async _lookup (hostname) { async _lookup (hostname) {
const url = `https://${hostname}.ipaddress.com` const url = `https://${hostname}.ipaddress.com`
@ -8,7 +9,7 @@ module.exports = class DNSOverIpAddress extends BaseDNS {
// const res = fs.readFileSync(path.resolve(__dirname, './data.txt')).toString() // const res = fs.readFileSync(path.resolve(__dirname, './data.txt')).toString()
const res = await axios.get(url) const res = await axios.get(url)
if (res.status !== 200 && res.status !== 201) { if (res.status !== 200 && res.status !== 201) {
log.info(`[dns] get ${hostname} ipaddress: error:${res}`) log.error(`[dns] get ${hostname} ipaddress: error: ${res}`)
return return
} }
const ret = res.data const ret = res.data

View File

@ -1,5 +1,4 @@
module.exports = { module.exports = {
lookup () { lookup () {
} }
} }

View File

@ -1,10 +1,12 @@
const BaseDNS = require('./base')
const matchUtil = require('../../utils/util.match') const matchUtil = require('../../utils/util.match')
const BaseDNS = require('./base')
function mapToList (ipMap) { function mapToList (ipMap) {
const ipList = [] const ipList = []
for (const key in ipMap) { for (const key in ipMap) {
if (!ipMap[key]) continue if (!ipMap[key]) {
continue
}
ipList.push(ipMap[key]) ipList.push(ipMap[key])
} }
return ipList return ipList

View File

@ -1,6 +1,7 @@
const dnstls = require('dns-over-tls') const dnstls = require('dns-over-tls')
const BaseDNS = require('./base')
const log = require('../../utils/util.log') const log = require('../../utils/util.log')
const BaseDNS = require('./base')
module.exports = class DNSOverTLS extends BaseDNS { module.exports = class DNSOverTLS extends BaseDNS {
async _lookup (hostname) { async _lookup (hostname) {
const { answers } = await dnstls.query(hostname) const { answers } = await dnstls.query(hostname)

View File

@ -9,8 +9,8 @@ module.exports = {
'DS-Interceptor': 'abort' 'DS-Interceptor': 'abort'
}) })
res.write( res.write(
'DevSidecar 403: Request abort.\r\n\r\n' + 'DevSidecar 403: Request abort.\n\n' +
' This request is matched by abort intercept.\r\n' + ' This request is matched by abort intercept.\n' +
' 因配置abort拦截器本请求直接返回403禁止访问。' ' 因配置abort拦截器本请求直接返回403禁止访问。'
) )
res.end() res.end()

View File

@ -22,13 +22,13 @@ function getTomorrow () {
// } // }
const AipOcrClient = require('baidu-aip-sdk').ocr const AipOcrClient = require('baidu-aip-sdk').ocr
const AipOcrClientMap = {} const AipOcrClientMap = {}
const apis = [ const apis = [
'accurateBasic', // 调用通用文字识别(高精度版) 'accurateBasic', // 调用通用文字识别(高精度版)
'accurate', // 调用通用文字识别(含位置高精度版) 'accurate', // 调用通用文字识别(含位置高精度版)
'handwriting' // 手写文字识别 'handwriting' // 手写文字识别
] ]
const limitMap = {} const limitMap = {}
function createBaiduOcrClient (config) { function createBaiduOcrClient (config) {
@ -57,7 +57,9 @@ function getConfig (interceptOpt, tryCount, log) {
} }
// 避免count值过大造成问题 // 避免count值过大造成问题
if (count >= 100000) count = 0 if (count >= 100000) {
count = 0
}
} else { } else {
config = interceptOpt.baiduOcr config = interceptOpt.baiduOcr
tryCount = null // 将tryCount设置为null代表只有一个配置 tryCount = null // 将tryCount设置为null代表只有一个配置
@ -95,13 +97,13 @@ function getConfig (interceptOpt, tryCount, log) {
} }
function limitConfig (id, api) { function limitConfig (id, api) {
const key = id + '_' + api const key = `${id}_${api}`
limitMap[key] = getTomorrow() limitMap[key] = getTomorrow()
// limitMap[key] = Date.now() + 5000 // 测试用5秒后解禁 // limitMap[key] = Date.now() + 5000 // 测试用5秒后解禁
} }
function checkIsLimitConfig (id, api) { function checkIsLimitConfig (id, api) {
const key = id + '_' + api const key = `${id}_${api}`
const limitTime = limitMap[key] const limitTime = limitMap[key]
return limitTime && limitTime > Date.now() return limitTime && limitTime > Date.now()
} }
@ -154,7 +156,7 @@ module.exports = {
...(config.options || {}) ...(config.options || {})
} }
log.info('发起百度ocr请求', req.hostname) log.info('发起百度ocr请求', req.hostname)
client[config.api || apis[0]](imageBase64, options).then(function (result) { client[config.api || apis[0]](imageBase64, options).then((result) => {
if (result.error_code != null) { if (result.error_code != null) {
log.error('baiduOcr error:', result) log.error('baiduOcr error:', result)
if (result.error_code === 17) { if (result.error_code === 17) {
@ -169,13 +171,17 @@ module.exports = {
res.writeHead(200, headers) res.writeHead(200, headers)
res.write(JSON.stringify(result)) // 格式如:{"words_result":[{"words":"6525"}],"words_result_num":1,"log_id":1818877093747960000} res.write(JSON.stringify(result)) // 格式如:{"words_result":[{"words":"6525"}],"words_result_num":1,"log_id":1818877093747960000}
res.end() res.end()
if (next) next() // 异步执行完继续next if (next) {
}).catch(function (err) { next() // 异步执行完继续next
}
}).catch((err) => {
log.info('baiduOcr error:', err) log.info('baiduOcr error:', err)
res.writeHead(200, headers) res.writeHead(200, headers)
res.write('{"error_code": 999500, "error_msg": "' + err + '"}') // 格式如:{"words_result":[{"words":"6525"}],"words_result_num":1,"log_id":1818877093747960000} res.write(`{"error_code": 999500, "error_msg": "${err}"}`) // 格式如:{"words_result":[{"words":"6525"}],"words_result_num":1,"log_id":1818877093747960000}
res.end() res.end()
if (next) next() // 异步执行完继续next if (next) {
next() // 异步执行完继续next
}
}) })
log.info('proxy baiduOcr: hostname:', req.hostname) log.info('proxy baiduOcr: hostname:', req.hostname)

View File

@ -44,7 +44,7 @@ function getLastModifiedTimeFromIfModifiedSince (rOptions, log) {
return new Date(lastModified).getTime() return new Date(lastModified).getTime()
} catch (e) { } catch (e) {
// 为数字时,直接返回 // 为数字时,直接返回
if (/\\d+/g.test(lastModified)) { if (/\\d+/.test(lastModified)) {
return lastModified - 0 return lastModified - 0
} }
@ -66,12 +66,12 @@ module.exports = {
// 获取 Cache-Control 用于判断是否禁用缓存 // 获取 Cache-Control 用于判断是否禁用缓存
const cacheControl = rOptions.headers['cache-control'] const cacheControl = rOptions.headers['cache-control']
if (cacheControl && (cacheControl.indexOf('no-cache') >= 0 || cacheControl.indexOf('no-store') >= 0)) { if (cacheControl && (cacheControl.includes('no-cache') || cacheControl.includes('no-store'))) {
return // 当前请求指定要禁用缓存,跳过当前拦截器 return // 当前请求指定要禁用缓存,跳过当前拦截器
} }
// 获取 Pragma 用于判断是否禁用缓存 // 获取 Pragma 用于判断是否禁用缓存
const pragma = rOptions.headers.pragma const pragma = rOptions.headers.pragma
if (pragma && (pragma.indexOf('no-cache') >= 0 || pragma.indexOf('no-store') >= 0)) { if (pragma && (pragma.includes('no-cache') || pragma.includes('no-store'))) {
return // 当前请求指定要禁用缓存,跳过当前拦截器 return // 当前请求指定要禁用缓存,跳过当前拦截器
} }
@ -91,7 +91,7 @@ module.exports = {
// 缓存未过期直接拦截请求并响应304 // 缓存未过期直接拦截请求并响应304
res.writeHead(304, { res.writeHead(304, {
'DS-Interceptor': 'cache: ' + maxAge 'DS-Interceptor': `cache: ${maxAge}`
}) })
res.end() res.end()

View File

@ -3,20 +3,18 @@ const lodash = require('lodash')
// 替换占位符 // 替换占位符
function replacePlaceholder (url, rOptions, matched) { function replacePlaceholder (url, rOptions, matched) {
if (url.indexOf('${') >= 0) { if (url.includes('${')) {
// eslint-disable-next-line
// no-template-curly-in-string
// eslint-disable-next-line no-template-curly-in-string // eslint-disable-next-line no-template-curly-in-string
url = url.replace('${host}', rOptions.hostname) url = url.replace('${host}', rOptions.hostname)
if (matched && url.indexOf('${') >= 0) { if (matched && url.includes('${')) {
for (let i = 0; i < matched.length; i++) { for (let i = 0; i < matched.length; i++) {
url = url.replace('${m[' + i + ']}', matched[i] == null ? '' : matched[i]) url = url.replace(`\${m[${i}]}`, matched[i] == null ? '' : matched[i])
} }
} }
// 移除多余的占位符 // 移除多余的占位符
if (url.indexOf('${') >= 0) { if (url.includes('${')) {
url = url.replace(/\$\{[^}]+}/g, '') url = url.replace(/\$\{[^}]+}/g, '')
} }
} }
@ -45,7 +43,7 @@ function buildTargetUrl (rOptions, urlConf, interceptOpt, matched) {
targetUrl = replacePlaceholder(targetUrl, rOptions, matched) targetUrl = replacePlaceholder(targetUrl, rOptions, matched)
// 拼接协议 // 拼接协议
targetUrl = targetUrl.indexOf('http:') === 0 || targetUrl.indexOf('https:') === 0 ? targetUrl : rOptions.protocol + '//' + targetUrl targetUrl = targetUrl.indexOf('http:') === 0 || targetUrl.indexOf('https:') === 0 ? targetUrl : `${rOptions.protocol}//${targetUrl}`
return targetUrl return targetUrl
} }
@ -90,7 +88,7 @@ module.exports = {
for (const bk of interceptOpt.backup) { for (const bk of interceptOpt.backup) {
backupList.push(bk) backupList.push(bk)
} }
const key = rOptions.hostname + '/' + interceptOpt.key const key = `${rOptions.hostname}/${interceptOpt.key}`
const count = RequestCounter.getOrCreate(key, backupList) const count = RequestCounter.getOrCreate(key, backupList)
if (count.value == null) { if (count.value == null) {
count.doRank() count.doRank()

View File

@ -32,7 +32,7 @@ module.exports = {
// 替换请求头 // 替换请求头
if (requestReplaceConfig.headers) { if (requestReplaceConfig.headers) {
replaceRequestHeaders(rOptions, requestReplaceConfig.headers, log) replaceRequestHeaders(rOptions, requestReplaceConfig.headers, log)
actions += (actions ? ',' : '') + 'headers' actions += `${actions ? ',' : ''}headers`
} }
// 替换下载文件请求的请求地址(此功能主要是为了方便拦截配置) // 替换下载文件请求的请求地址(此功能主要是为了方便拦截配置)
@ -40,7 +40,7 @@ module.exports = {
if (requestReplaceConfig.doDownload && rOptions.path.match(/DS_DOWNLOAD/i)) { if (requestReplaceConfig.doDownload && rOptions.path.match(/DS_DOWNLOAD/i)) {
rOptions.doDownload = true rOptions.doDownload = true
rOptions.path = rOptions.path.replace(/[?&/]?DS_DOWNLOAD(=[^?&/]+)?$/gi, '') rOptions.path = rOptions.path.replace(/[?&/]?DS_DOWNLOAD(=[^?&/]+)?$/gi, '')
actions += (actions ? ',' : '') + 'path:remove-DS_DOWNLOAD' actions += `${actions ? ',' : ''}path:remove-DS_DOWNLOAD`
} }
res.setHeader('DS-RequestReplace-Interceptor', actions) res.setHeader('DS-RequestReplace-Interceptor', actions)

View File

@ -12,7 +12,7 @@ module.exports = {
} }
// 判断当前响应码是否不使用缓存 // 判断当前响应码是否不使用缓存
if (interceptOpt.cacheExcludeStatusCodeList && interceptOpt.cacheExcludeStatusCodeList[proxyRes.statusCode + '']) { if (interceptOpt.cacheExcludeStatusCodeList && interceptOpt.cacheExcludeStatusCodeList[`${proxyRes.statusCode}`]) {
return return
} }
@ -32,7 +32,7 @@ module.exports = {
// 获取maxAge配置 // 获取maxAge配置
let maxAge = cacheReq.getMaxAge(interceptOpt) let maxAge = cacheReq.getMaxAge(interceptOpt)
// public 或 private // public 或 private
const cacheControlType = (interceptOpt.cacheControlType || 'public') + ', ' const cacheControlType = `${interceptOpt.cacheControlType || 'public'}, `
// immutable属性 // immutable属性
const cacheImmutable = interceptOpt.cacheImmutable !== false ? ', immutable' : '' const cacheImmutable = interceptOpt.cacheImmutable !== false ? ', immutable' : ''
@ -65,7 +65,7 @@ module.exports = {
if (originalHeaders.cacheControl) { if (originalHeaders.cacheControl) {
const maxAgeMatch = originalHeaders.cacheControl.value.match(/max-age=(\d+)/) const maxAgeMatch = originalHeaders.cacheControl.value.match(/max-age=(\d+)/)
if (maxAgeMatch && maxAgeMatch[1] > maxAge) { if (maxAgeMatch && maxAgeMatch[1] > maxAge) {
if (interceptOpt.cacheImmutable !== false && originalHeaders.cacheControl.value.indexOf('immutable') < 0) { if (interceptOpt.cacheImmutable !== false && !originalHeaders.cacheControl.value.includes('immutable')) {
maxAge = maxAgeMatch[1] maxAge = maxAgeMatch[1]
} else { } else {
const url = `${rOptions.method}${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${req.url}` const url = `${rOptions.method}${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${req.url}`

View File

@ -1,5 +1,6 @@
const lodash = require('lodash') const lodash = require('lodash')
const cacheReq = require('../req/cacheReq') const cacheReq = require('../req/cacheReq')
const REMOVE = '[remove]' const REMOVE = '[remove]'
// 替换响应头 // 替换响应头
@ -96,17 +97,17 @@ module.exports = {
replaceHeaders.expires = '[remove]' replaceHeaders.expires = '[remove]'
} }
actions += (actions ? ',' : '') + 'download:' + filename actions += `${actions ? ',' : ''}download:${filename}`
} }
// 替换响应头 // 替换响应头
if (replaceResponseHeaders(replaceHeaders, res, proxyRes)) { if (replaceResponseHeaders(replaceHeaders, res, proxyRes)) {
actions += (actions ? ',' : '') + 'headers' actions += `${actions ? ',' : ''}headers`
} }
if (actions) { if (actions) {
res.setHeader('DS-ResponseReplace-Interceptor', actions) res.setHeader('DS-ResponseReplace-Interceptor', actions)
log.info('response intercept: ' + actions) log.info(`response intercept: ${actions}`)
} }
}, },
is (interceptOpt) { is (interceptOpt) {

View File

@ -29,7 +29,7 @@ module.exports = {
} }
// 如果没有响应头 'content-type',或其值不是 'text/html',则不处理 // 如果没有响应头 'content-type',或其值不是 'text/html',则不处理
if (!proxyRes.headers['content-type'] || proxyRes.headers['content-type'].indexOf('text/html') < 0) { if (!proxyRes.headers['content-type'] || !proxyRes.headers['content-type'].includes('text/html')) {
res.setHeader('DS-Script-Interceptor', 'Not text/html') res.setHeader('DS-Script-Interceptor', 'Not text/html')
return return
} }
@ -50,7 +50,7 @@ module.exports = {
let scriptTag let scriptTag
if (key.indexOf('/') >= 0) { if (key.includes('/')) {
scriptTag = getScriptByUrlOrPath(key) // 1.绝对地址或相对地址注意当目标站点限制跨域脚本时可使用相对地址再结合proxy拦截器进行代理可规避掉限制跨域脚本问题。 scriptTag = getScriptByUrlOrPath(key) // 1.绝对地址或相对地址注意当目标站点限制跨域脚本时可使用相对地址再结合proxy拦截器进行代理可规避掉限制跨域脚本问题。
} else { } else {
const script = scripts[key] const script = scripts[key]
@ -60,7 +60,7 @@ module.exports = {
scriptTag = getScript(key, script.script) // 2.DS内置脚本 scriptTag = getScript(key, script.script) // 2.DS内置脚本
} }
tags += '\r\n\t' + scriptTag tags += `\r\n\t${scriptTag}`
} }
// 如果脚本为空,则不插入 // 如果脚本为空,则不插入
@ -70,15 +70,15 @@ module.exports = {
// 插入油猴脚本浏览器扩展 // 插入油猴脚本浏览器扩展
if (typeof interceptOpt.tampermonkeyScript === 'string') { if (typeof interceptOpt.tampermonkeyScript === 'string') {
tags = '\r\n\t' + getScriptByUrlOrPath(interceptOpt.tampermonkeyScript) + tags tags = `\r\n\t${getScriptByUrlOrPath(interceptOpt.tampermonkeyScript)}${tags}`
} else { } else {
tags = '\r\n\t' + getScript('tampermonkey', scripts.tampermonkey.script) + tags tags = `\r\n\t${getScript('tampermonkey', scripts.tampermonkey.script)}${tags}`
} }
res.setHeader('DS-Script-Interceptor', 'true') res.setHeader('DS-Script-Interceptor', 'true')
log.info(`script response intercept: insert script ${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`, ', head:', tags) log.info(`script response intercept: insert script ${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`, ', head:', tags)
return { return {
head: tags + '\r\n' head: `${tags}\r\n`
} }
} catch (err) { } catch (err) {
try { try {
@ -102,10 +102,12 @@ module.exports = {
const handleScriptUrl = (scriptUrl, name, replaceScriptUrlFun) => { const handleScriptUrl = (scriptUrl, name, replaceScriptUrlFun) => {
if (scriptUrl.indexOf('https:') === 0 || scriptUrl.indexOf('http:') === 0) { if (scriptUrl.indexOf('https:') === 0 || scriptUrl.indexOf('http:') === 0) {
// 绝对地址 // 绝对地址
const scriptKey = SCRIPT_PROXY_URL_PRE + scriptUrl.replace('.js', '').replace(/[\W_]+/g, '_') + '.js' // 伪脚本地址:移除 script 中可能存在的特殊字符,并转为相对地址 const scriptKey = `${SCRIPT_PROXY_URL_PRE + scriptUrl.replace('.js', '').replace(/[\W_]+/g, '_')}.js` // 伪脚本地址:移除 script 中可能存在的特殊字符,并转为相对地址
scriptProxy[scriptKey] = scriptUrl scriptProxy[scriptKey] = scriptUrl
log.info(`替换${name}配置值:'${scriptUrl}' -> '${scriptKey}'`) log.info(`替换${name}配置值:'${scriptUrl}' -> '${scriptKey}'`)
if (typeof replaceScriptUrlFun === 'function') replaceScriptUrlFun(scriptKey) if (typeof replaceScriptUrlFun === 'function') {
replaceScriptUrlFun(scriptKey)
}
} else if (scriptUrl.indexOf('/') === 0) { } else if (scriptUrl.indexOf('/') === 0) {
// 相对地址 // 相对地址
scriptProxy[scriptUrl] = scriptUrl scriptProxy[scriptUrl] = scriptUrl

View File

@ -1,10 +1,11 @@
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const log = require('../../utils/util.log') const log = require('../../utils/util.log')
let scripts let scripts
function buildScript (sc, content, scriptName) { function buildScript (sc, content, scriptName) {
const scriptKey = `ds_${scriptName}${sc.version ? ('_' + sc.version) : ''}:` const scriptKey = `ds_${scriptName}${sc.version ? (`_${sc.version}`) : ''}:`
// 代码1监听事件 // 代码1监听事件
const runAt = sc['run-at'] || 'document-end' const runAt = sc['run-at'] || 'document-end'
@ -45,9 +46,9 @@ if (!((window.__ds_global__ || {}).GM_getValue || (() => true))("ds_enabled", tr
} }
if (item.indexOf('.') > 0) { if (item.indexOf('.') > 0) {
grantStr += item + ' = (window.__ds_global__ || {})[\'' + item + '\'];' grantStr += `${item} = (window.__ds_global__ || {})['${item}'];`
} else { } else {
grantStr += 'const ' + item + ' = (window.__ds_global__ || {})[\'' + item + '\'] || (() => {});' grantStr += `const ${item} = (window.__ds_global__ || {})['${item}'] || (() => {});`
} }
} }
@ -81,7 +82,7 @@ function loadScript (content, scriptName) {
script: '' script: ''
} }
for (const string of confItemArr) { for (const string of confItemArr) {
const reg = new RegExp('.*@([^\\s]+)\\s(.+)') const reg = new RegExp('.*@(\\S+)\\s(.+)')
const ret = string.match(reg) const ret = string.match(reg)
if (ret) { if (ret) {
const key = ret[1].trim() const key = ret[1].trim()
@ -103,7 +104,7 @@ function loadScript (content, scriptName) {
function readFile (rootDir, script) { function readFile (rootDir, script) {
log.info('read script, script root location:', path.resolve('./')) log.info('read script, script root location:', path.resolve('./'))
const location = path.join(rootDir, './' + script) const location = path.join(rootDir, `./${script}`)
log.info('read script, the script location:', location) log.info('read script, the script location:', location)
return fs.readFileSync(location).toString() return fs.readFileSync(location).toString()
} }

View File

@ -1,4 +1,5 @@
const path = require('path') const path = require('path')
const config = exports const config = exports
config.defaultHost = '127.0.0.1' config.defaultHost = '127.0.0.1'

View File

@ -1,9 +1,10 @@
const url = require('url') const url = require('url')
const Agent = require('./ProxyHttpAgent')
const HttpsAgent = require('./ProxyHttpsAgent')
const tunnelAgent = require('tunnel-agent') const tunnelAgent = require('tunnel-agent')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const matchUtil = require('../../../utils/util.match') const matchUtil = require('../../../utils/util.match')
const Agent = require('./ProxyHttpAgent')
const HttpsAgent = require('./ProxyHttpsAgent')
const util = exports const util = exports
const httpsAgentCache = {} const httpsAgentCache = {}
@ -25,7 +26,7 @@ function getTimeoutConfig (hostname, serverSetting) {
} }
function createHttpsAgent (timeoutConfig, verifySsl) { function createHttpsAgent (timeoutConfig, verifySsl) {
const key = timeoutConfig.timeout + '-' + timeoutConfig.keepAliveTimeout const key = `${timeoutConfig.timeout}-${timeoutConfig.keepAliveTimeout}`
if (!httpsAgentCache[key]) { if (!httpsAgentCache[key]) {
verifySsl = !!verifySsl verifySsl = !!verifySsl
@ -57,7 +58,7 @@ function createHttpsAgent (timeoutConfig, verifySsl) {
} }
function createHttpAgent (timeoutConfig) { function createHttpAgent (timeoutConfig) {
const key = timeoutConfig.timeout + '-' + timeoutConfig.keepAliveTimeout const key = `${timeoutConfig.timeout}-${timeoutConfig.keepAliveTimeout}`
if (!httpAgentCache[key]) { if (!httpAgentCache[key]) {
httpAgentCache[key] = new Agent({ httpAgentCache[key] = new Agent({
keepAlive: true, keepAlive: true,
@ -80,12 +81,12 @@ util.parseHostnameAndPort = (host, defaultPort) => {
if (arr) { if (arr) {
arr = arr.slice(1) arr = arr.slice(1)
if (arr[1]) { if (arr[1]) {
arr[1] = parseInt(arr[1], 10) arr[1] = Number.parseInt(arr[1], 10)
} }
} else { } else {
arr = host.split(':') arr = host.split(':')
if (arr.length > 1) { if (arr.length > 1) {
arr[1] = parseInt(arr[1], 10) arr[1] = Number.parseInt(arr[1], 10)
} }
} }
@ -188,7 +189,7 @@ util.getTunnelAgent = (requestIsSSL, externalProxyUrl) => {
httpsOverHttpAgent = tunnelAgent.httpsOverHttp({ httpsOverHttpAgent = tunnelAgent.httpsOverHttp({
proxy: { proxy: {
host: hostname, host: hostname,
port: port port
} }
}) })
} }
@ -198,7 +199,7 @@ util.getTunnelAgent = (requestIsSSL, externalProxyUrl) => {
httpsOverHttpsAgent = tunnelAgent.httpsOverHttps({ httpsOverHttpsAgent = tunnelAgent.httpsOverHttps({
proxy: { proxy: {
host: hostname, host: hostname,
port: port port
} }
}) })
} }
@ -220,7 +221,7 @@ util.getTunnelAgent = (requestIsSSL, externalProxyUrl) => {
httpOverHttpsAgent = tunnelAgent.httpOverHttps({ httpOverHttpsAgent = tunnelAgent.httpOverHttps({
proxy: { proxy: {
host: hostname, host: hostname,
port: port port
} }
}) })
} }

View File

@ -1,6 +1,6 @@
const log = require('../../../utils/util.log')
const through = require('through2')
const zlib = require('zlib') const zlib = require('zlib')
const through = require('through2')
const log = require('../../../utils/util.log')
// 编解码器 // 编解码器
const codecMap = { const codecMap = {
@ -84,7 +84,7 @@ function injectScriptIntoHtml (tags, chunk, script) {
} }
function handleResponseHeaders (res, proxyRes) { function handleResponseHeaders (res, proxyRes) {
Object.keys(proxyRes.headers).forEach(function (key) { Object.keys(proxyRes.headers).forEach((key) => {
if (proxyRes.headers[key] !== undefined) { if (proxyRes.headers[key] !== undefined) {
// let newkey = key.replace(/^[a-z]|-[a-z]/g, (match) => { // let newkey = key.replace(/^[a-z]|-[a-z]/g, (match) => {
// return match.toUpperCase() // return match.toUpperCase()
@ -100,7 +100,7 @@ function handleResponseHeaders (res, proxyRes) {
const reg = /script-src ([^:]*);/i const reg = /script-src ([^:]*);/i
const matched = policy.match(reg) const matched = policy.match(reg)
if (matched) { if (matched) {
if (matched[1].indexOf('self') < 0) { if (!matched[1].includes('self')) {
policy = policy.replace('script-src', 'script-src \'self\' ') policy = policy.replace('script-src', 'script-src \'self\' ')
} }
} }
@ -117,6 +117,7 @@ function handleResponseHeaders (res, proxyRes) {
const contextPath = '/____ds_script____/' const contextPath = '/____ds_script____/'
const monkey = require('../../monkey') const monkey = require('../../monkey')
module.exports = { module.exports = {
requestIntercept (context, req, res, ssl, next) { requestIntercept (context, req, res, ssl, next) {
const { rOptions, log, setting } = context const { rOptions, log, setting } = context

View File

@ -1,12 +1,13 @@
const url = require('url')
const request = require('request')
const lodash = require('lodash')
const pac = require('./source/pac')
const matchUtil = require('../../../utils/util.match')
const log = require('../../../utils/util.log')
const path = require('path')
const fs = require('fs')
const { Buffer } = require('buffer') const { Buffer } = require('buffer')
const fs = require('fs')
const path = require('path')
const url = require('url')
const lodash = require('lodash')
const request = require('request')
const log = require('../../../utils/util.log')
const matchUtil = require('../../../utils/util.match')
const pac = require('./source/pac')
let pacClient = null let pacClient = null
function matched (hostname, overWallTargetMap) { function matched (hostname, overWallTargetMap) {
@ -23,7 +24,7 @@ function matched (hostname, overWallTargetMap) {
if (pacClient == null) { if (pacClient == null) {
return null return null
} }
const ret = pacClient.FindProxyForURL('https://' + hostname, hostname) const ret = pacClient.FindProxyForURL(`https://${hostname}`, hostname)
if (ret && ret.indexOf('PROXY ') === 0) { if (ret && ret.indexOf('PROXY ') === 0) {
log.info(`matchHostname: matched overwall: '${hostname}' -> '${ret}' in pac.txt`) log.info(`matchHostname: matched overwall: '${hostname}' -> '${ret}' in pac.txt`)
return 'in pac.txt' return 'in pac.txt'
@ -113,12 +114,12 @@ async function downloadPacAsync (pacConfig) {
// 尝试解析Base64https://gitlab.com/gfwlist/gfwlist/raw/master/gfwlist.txt 下载下来的是Base64格式 // 尝试解析Base64https://gitlab.com/gfwlist/gfwlist/raw/master/gfwlist.txt 下载下来的是Base64格式
let pacTxt = body let pacTxt = body
try { try {
if (pacTxt.indexOf('!---------------------EOF') < 0) { if (!pacTxt.includes('!---------------------EOF')) {
pacTxt = Buffer.from(pacTxt, 'base64').toString('utf8') pacTxt = Buffer.from(pacTxt, 'base64').toString('utf8')
// log.debug('解析 base64 后的 pax:', pacTxt) // log.debug('解析 base64 后的 pax:', pacTxt)
} }
} catch (e) { } catch (e) {
if (pacTxt.indexOf('!---------------------EOF') < 0) { if (!pacTxt.includes('!---------------------EOF')) {
log.error(`远程 pac.txt 文件内容即不是base64格式也不是要求的格式url: ${remotePacFileUrl}body: ${body}`) log.error(`远程 pac.txt 文件内容即不是base64格式也不是要求的格式url: ${remotePacFileUrl}body: ${body}`)
return return
} }
@ -190,10 +191,10 @@ function createOverwallMiddleware (overWallConfig) {
const port = server[domain].port const port = server[domain].port
const path = server[domain].path const path = server[domain].path
const password = server[domain].password const password = server[domain].password
const proxyTarget = domain + '/' + path + '/' + hostname + req.url const proxyTarget = `${domain}/${path}/${hostname}${req.url}`
// const backup = interceptOpt.backup // const backup = interceptOpt.backup
const proxy = proxyTarget.indexOf('http:') === 0 || proxyTarget.indexOf('https:') === 0 ? proxyTarget : (rOptions.protocol + '//' + proxyTarget) const proxy = proxyTarget.indexOf('http:') === 0 || proxyTarget.indexOf('https:') === 0 ? proxyTarget : (`${rOptions.protocol}//${proxyTarget}`)
// eslint-disable-next-line node/no-deprecated-api // eslint-disable-next-line node/no-deprecated-api
const URL = url.parse(proxy) const URL = url.parse(proxy)
rOptions.origional = lodash.cloneDeep(rOptions) // 备份原始请求参数 rOptions.origional = lodash.cloneDeep(rOptions) // 备份原始请求参数

View File

@ -20,7 +20,7 @@ function createPacClient (pacFilePath) {
const getRules = function (pacFilePath) { const getRules = function (pacFilePath) {
let text = readFile(pacFilePath) let text = readFile(pacFilePath)
if (text.indexOf('!---------------------EOF') < 0) { if (!text.includes('!---------------------EOF')) {
text = Buffer.from(text, 'base64').toString() text = Buffer.from(text, 'base64').toString()
} }
const rules = [] const rules = []

View File

@ -1,10 +1,11 @@
const net = require('net') const net = require('net')
const url = require('url') const url = require('url')
const jsonApi = require('../../../json')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const DnsUtil = require('../../dns/index') const DnsUtil = require('../../dns/index')
const localIP = '127.0.0.1'
const dnsLookup = require('./dnsLookup') const dnsLookup = require('./dnsLookup')
const jsonApi = require('../../../json')
const localIP = '127.0.0.1'
function isSslConnect (sslConnectInterceptors, req, cltSocket, head) { function isSslConnect (sslConnectInterceptors, req, cltSocket, head) {
for (const intercept of sslConnectInterceptors) { for (const intercept of sslConnectInterceptors) {
@ -32,7 +33,7 @@ module.exports = function createConnectHandler (sslConnectInterceptor, middlewar
return function connectHandler (req, cltSocket, head, ssl) { return function connectHandler (req, cltSocket, head, ssl) {
// eslint-disable-next-line node/no-deprecated-api // eslint-disable-next-line node/no-deprecated-api
let { hostname, port } = url.parse(`${ssl ? 'https' : 'http'}://${req.url}`) let { hostname, port } = url.parse(`${ssl ? 'https' : 'http'}://${req.url}`)
port = parseInt(port) port = Number.parseInt(port)
if (isSslConnect(sslConnectInterceptors, req, cltSocket, head)) { if (isSslConnect(sslConnectInterceptors, req, cltSocket, head)) {
// 需要拦截代替目标服务器让客户端连接DS在本地启动的代理服务 // 需要拦截代替目标服务器让客户端连接DS在本地启动的代理服务

View File

@ -1,7 +1,8 @@
const fs = require('fs') const fs = require('fs')
const forge = require('node-forge') const forge = require('node-forge')
const FakeServersCenter = require('../tls/FakeServersCenter')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const FakeServersCenter = require('../tls/FakeServersCenter')
module.exports = function createFakeServerCenter ({ module.exports = function createFakeServerCenter ({
maxLength, maxLength,
caCertPath, caCertPath,

View File

@ -1,14 +1,15 @@
const http = require('http') const http = require('http')
const https = require('https') const https = require('https')
const commonUtil = require('../common/util')
const jsonApi = require('../../../json') const jsonApi = require('../../../json')
// const upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i
const DnsUtil = require('../../dns/index')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const RequestCounter = require('../../choice/RequestCounter') const RequestCounter = require('../../choice/RequestCounter')
const commonUtil = require('../common/util')
// const upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i
const DnsUtil = require('../../dns/index')
const compatible = require('../compatible/compatible')
const InsertScriptMiddleware = require('../middleware/InsertScriptMiddleware') const InsertScriptMiddleware = require('../middleware/InsertScriptMiddleware')
const dnsLookup = require('./dnsLookup') const dnsLookup = require('./dnsLookup')
const compatible = require('../compatible/compatible')
const MAX_SLOW_TIME = 8000 // 超过此时间 则认为太慢了 const MAX_SLOW_TIME = 8000 // 超过此时间 则认为太慢了
// create requestHandler function // create requestHandler function
@ -63,7 +64,9 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
} }
const goNext = reqIncpt.requestIntercept(context, req, res, ssl, next) const goNext = reqIncpt.requestIntercept(context, req, res, ssl, next)
if (goNext) { if (goNext) {
if (goNext !== 'no-next') next() if (goNext !== 'no-next') {
next()
}
return return
} }
} }
@ -107,7 +110,7 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
function onFree () { function onFree () {
url = `${rOptions.method}${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}` url = `${rOptions.method}${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`
const start = new Date() const start = new Date()
log.info('发起代理请求:', url, (rOptions.servername ? ', sni: ' + rOptions.servername : ''), ', headers:', jsonApi.stringify2(rOptions.headers)) log.info('发起代理请求:', url, (rOptions.servername ? `, sni: ${rOptions.servername}` : ''), ', headers:', jsonApi.stringify2(rOptions.headers))
const isDnsIntercept = {} const isDnsIntercept = {}
if (dnsConfig && dnsConfig.dnsMap) { if (dnsConfig && dnsConfig.dnsMap) {
@ -181,7 +184,7 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
proxyReq.on('error', (e) => { proxyReq.on('error', (e) => {
const cost = new Date() - start const cost = new Date() - start
log.error(`代理请求错误: ${url}, cost: ${cost} ms, error:`, e, ', rOptions:', jsonApi.stringify2(rOptions)) log.error(`代理请求错误: ${url}, cost: ${cost} ms, error:`, e, ', rOptions:', jsonApi.stringify2(rOptions))
countSlow(isDnsIntercept, '代理请求错误: ' + e.message) countSlow(isDnsIntercept, `代理请求错误: ${e.message}`)
reject(e) reject(e)
// 自动兼容程序2 // 自动兼容程序2
@ -205,7 +208,7 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
}) })
// 原始请求的事件监听 // 原始请求的事件监听
req.on('aborted', function () { req.on('aborted', () => {
const cost = new Date() - start const cost = new Date() - start
const errorMsg = `请求被取消: ${url}, cost: ${cost} ms` const errorMsg = `请求被取消: ${url}, cost: ${cost} ms`
log.error(errorMsg, ', rOptions:', jsonApi.stringify2(rOptions)) log.error(errorMsg, ', rOptions:', jsonApi.stringify2(rOptions))
@ -215,7 +218,7 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
} }
reject(new Error(errorMsg)) reject(new Error(errorMsg))
}) })
req.on('error', function (e, req, res) { req.on('error', (e, req, res) => {
const cost = new Date() - start const cost = new Date() - start
log.error(`请求错误: ${url}, cost: ${cost} ms, error:`, e, ', rOptions:', jsonApi.stringify2(rOptions)) log.error(`请求错误: ${url}, cost: ${cost} ms, error:`, e, ', rOptions:', jsonApi.stringify2(rOptions))
reject(e) reject(e)
@ -246,7 +249,7 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
// // console.log('BODY: ') // // console.log('BODY: ')
// }) // })
proxyRes.on('error', (error) => { proxyRes.on('error', (error) => {
countSlow(null, 'error: ' + error.message) countSlow(null, `error: ${error.message}`)
log.error(`proxy res error: ${url}, error:`, error) log.error(`proxy res error: ${url}, error:`, error)
}) })
@ -300,7 +303,7 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
await responseInterceptorPromise await responseInterceptorPromise
if (!res.headersSent) { // prevent duplicate set headers if (!res.headersSent) { // prevent duplicate set headers
Object.keys(proxyRes.headers).forEach(function (key) { Object.keys(proxyRes.headers).forEach((key) => {
if (proxyRes.headers[key] !== undefined) { if (proxyRes.headers[key] !== undefined) {
// https://github.com/nodejitsu/node-http-proxy/issues/362 // https://github.com/nodejitsu/node-http-proxy/issues/362
if (/^www-authenticate$/i.test(key)) { if (/^www-authenticate$/i.test(key)) {
@ -314,12 +317,12 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
}) })
if (proxyRes.statusCode >= 400) { if (proxyRes.statusCode >= 400) {
countSlow(null, 'Status return: ' + proxyRes.statusCode) countSlow(null, `Status return: ${proxyRes.statusCode}`)
} }
res.writeHead(proxyRes.statusCode) res.writeHead(proxyRes.statusCode)
proxyRes.pipe(res) proxyRes.pipe(res)
} }
})().catch(e => { })().catch((e) => {
if (!res.writableEnded) { if (!res.writableEnded) {
try { try {
const status = e.status || 500 const status = e.status || 500

View File

@ -1,7 +1,8 @@
const http = require('http') const http = require('http')
const https = require('https') const https = require('https')
const util = require('../common/util')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const util = require('../common/util')
// copy from node-http-proxy. ^_^ // copy from node-http-proxy. ^_^
// create connectHandler function // create connectHandler function
@ -13,17 +14,19 @@ module.exports = function createUpgradeHandler (serverSetting) {
proxyReq.on('error', (e) => { proxyReq.on('error', (e) => {
log.error('upgradeHandler error:', e) log.error('upgradeHandler error:', e)
}) })
proxyReq.on('response', function (res) { proxyReq.on('response', (res) => {
// if upgrade event isn't going to happen, close the socket // if upgrade event isn't going to happen, close the socket
if (!res.upgrade) cltSocket.end() if (!res.upgrade) {
cltSocket.end()
}
}) })
proxyReq.on('upgrade', function (proxyRes, proxySocket, proxyHead) { proxyReq.on('upgrade', (proxyRes, proxySocket, proxyHead) => {
proxySocket.on('error', (e) => { proxySocket.on('error', (e) => {
log.error('upgrade error:', e) log.error('upgrade error:', e)
}) })
cltSocket.on('error', function (e) { cltSocket.on('error', (e) => {
log.error('upgrade socket error:', e) log.error('upgrade socket error:', e)
proxySocket.end() proxySocket.end()
}) })
@ -33,23 +36,24 @@ module.exports = function createUpgradeHandler (serverSetting) {
proxySocket.setKeepAlive(true, 0) proxySocket.setKeepAlive(true, 0)
if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead) if (proxyHead && proxyHead.length) {
proxySocket.unshift(proxyHead)
}
cltSocket.write( cltSocket.write(
Object.keys(proxyRes.headers).reduce(function (head, key) { `${Object.keys(proxyRes.headers).reduce((head, key) => {
const value = proxyRes.headers[key] const value = proxyRes.headers[key]
if (!Array.isArray(value)) { if (!Array.isArray(value)) {
head.push(key + ': ' + value) head.push(`${key}: ${value}`)
return head return head
} }
for (let i = 0; i < value.length; i++) { for (let i = 0; i < value.length; i++) {
head.push(key + ': ' + value[i]) head.push(`${key}: ${value[i]}`)
} }
return head return head
}, ['HTTP/1.1 101 Switching Protocols']) }, ['HTTP/1.1 101 Switching Protocols']).join('\r\n')}\r\n\r\n`
.join('\r\n') + '\r\n\r\n'
) )
proxySocket.pipe(cltSocket).pipe(proxySocket) proxySocket.pipe(cltSocket).pipe(proxySocket)

View File

@ -1,10 +1,10 @@
const speedTest = require('../../speed')
const log = require('../../../utils/util.log')
const defaultDns = require('dns') const defaultDns = require('dns')
const log = require('../../../utils/util.log')
const speedTest = require('../../speed')
module.exports = { module.exports = {
createLookupFunc: function (res, dns, action, target, isDnsIntercept) { createLookupFunc (res, dns, action, target, isDnsIntercept) {
target = target ? (', target: ' + target) : '' target = target ? (`, target: ${target}`) : ''
return (hostname, options, callback) => { return (hostname, options, callback) => {
const tester = speedTest.getSpeedTester(hostname) const tester = speedTest.getSpeedTester(hostname)
@ -12,14 +12,16 @@ module.exports = {
const aliveIpObj = tester.pickFastAliveIpObj() const aliveIpObj = tester.pickFastAliveIpObj()
if (aliveIpObj) { if (aliveIpObj) {
log.info(`----- ${action}: ${hostname}, use alive ip from dns '${aliveIpObj.dns}': ${aliveIpObj.host}${target} -----`) log.info(`----- ${action}: ${hostname}, use alive ip from dns '${aliveIpObj.dns}': ${aliveIpObj.host}${target} -----`)
if (res) res.setHeader('DS-DNS-Lookup', `IpTester: ${aliveIpObj.host} ${aliveIpObj.dns === '预设IP' ? 'PreSet' : aliveIpObj.dns}`) if (res) {
res.setHeader('DS-DNS-Lookup', `IpTester: ${aliveIpObj.host} ${aliveIpObj.dns === '预设IP' ? 'PreSet' : aliveIpObj.dns}`)
}
callback(null, aliveIpObj.host, 4) callback(null, aliveIpObj.host, 4)
return return
} else { } else {
log.info(`----- ${action}: ${hostname}, no alive ip${target}, tester: { "ready": ${tester.ready}, "backupList": ${JSON.stringify(tester.backupList)} }`) log.info(`----- ${action}: ${hostname}, no alive ip${target}, tester: { "ready": ${tester.ready}, "backupList": ${JSON.stringify(tester.backupList)} }`)
} }
} }
dns.lookup(hostname).then(ip => { dns.lookup(hostname).then((ip) => {
if (isDnsIntercept) { if (isDnsIntercept) {
isDnsIntercept.dns = dns isDnsIntercept.dns = dns
isDnsIntercept.hostname = hostname isDnsIntercept.hostname = hostname
@ -42,7 +44,9 @@ module.exports = {
} }
if (isTestFailedIp === false) { if (isTestFailedIp === false) {
log.info(`----- ${action}: ${hostname}, use ip from dns '${dns.name}': ${ip}${target} -----`) log.info(`----- ${action}: ${hostname}, use ip from dns '${dns.name}': ${ip}${target} -----`)
if (res) res.setHeader('DS-DNS-Lookup', `DNS: ${ip} ${dns.name === '预设IP' ? 'PreSet' : dns.name}`) if (res) {
res.setHeader('DS-DNS-Lookup', `DNS: ${ip} ${dns.name === '预设IP' ? 'PreSet' : dns.name}`)
}
callback(null, ip, 4) callback(null, ip, 4)
return return
} else { } else {

View File

@ -1,12 +1,13 @@
const tlsUtils = require('../tls/tlsUtils')
const http = require('http') const http = require('http')
const config = require('../common/config')
const log = require('../../../utils/util.log') const log = require('../../../utils/util.log')
const createRequestHandler = require('./createRequestHandler') const speedTest = require('../../speed/index.js')
const config = require('../common/config')
const tlsUtils = require('../tls/tlsUtils')
const createConnectHandler = require('./createConnectHandler') const createConnectHandler = require('./createConnectHandler')
const createFakeServerCenter = require('./createFakeServerCenter') const createFakeServerCenter = require('./createFakeServerCenter')
const createRequestHandler = require('./createRequestHandler')
const createUpgradeHandler = require('./createUpgradeHandler') const createUpgradeHandler = require('./createUpgradeHandler')
const speedTest = require('../../speed/index.js')
module.exports = { module.exports = {
createProxy ({ createProxy ({
host = config.defaultHost, host = config.defaultHost,
@ -96,7 +97,7 @@ module.exports = {
connectHandler(req, cltSocket, head, ssl) connectHandler(req, cltSocket, head, ssl)
}) })
// TODO: handler WebSocket // TODO: handler WebSocket
server.on('upgrade', function (req, cltSocket, head) { server.on('upgrade', (req, cltSocket, head) => {
if (printDebugLog) { if (printDebugLog) {
log.debug(`【server upgrade, ssl: ${ssl}\r\n----- req -----\r\n`, req) log.debug(`【server upgrade, ssl: ${ssl}\r\n----- req -----\r\n`, req)
} else { } else {

View File

@ -1,8 +1,9 @@
const https = require('https')
const http = require('http') const http = require('http')
const tlsUtils = require('./tlsUtils') const https = require('https')
const CertAndKeyContainer = require('./CertAndKeyContainer')
const forge = require('node-forge') const forge = require('node-forge')
const CertAndKeyContainer = require('./CertAndKeyContainer')
const tlsUtils = require('./tlsUtils')
const pki = forge.pki const pki = forge.pki
// const colors = require('colors') // const colors = require('colors')
const tls = require('tls') const tls = require('tls')

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