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 这是一个解谜游戏 ↓ ↓ ↓ ↓ ↓ ↓ ,如果你破解了它,请不要公开,好好用它来学习和查资料吧(特别注意:为了你的人身安全,请不要用它来查看和发表不当言论,你懂得)。
/**
\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 (打开拉到最下面)

View File

@ -1,12 +1,12 @@
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 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 Shell = require('./shell')
const log = require('./utils/util.log')
let configTarget = lodash.cloneDeep(defConfig)
@ -80,7 +80,7 @@ const configApi = {
configApi.deleteRemoteConfigFile(suffix)
return
}
// eslint-disable-next-line handle-callback-err
return new Promise((resolve, reject) => {
log.info('开始下载远程配置:', remoteConfigUrl)
@ -131,7 +131,7 @@ const configApi = {
if (response) {
message = `下载远程配置失败: ${remoteConfigUrl}, message: ${response.message}, code: ${response.statusCode}`
} else {
message = '下载远程配置失败: response: ' + response
message = `下载远程配置失败: response: ${response}`
}
reject(new Error(message))
}
@ -337,7 +337,7 @@ const configApi = {
},
async setVariables (type) {
const list = await configApi.getVariables(type)
const noSetList = list.filter(item => {
const noSetList = list.filter((item) => {
return !item.exists
})
if (list.length > 0) {
@ -345,9 +345,9 @@ const configApi = {
root_ca_cert_path: configApi.get().server.setting.rootCaFile.certPath
}
for (const item of noSetList) {
if (item.value.indexOf('${') >= 0) {
if (item.value.includes('${')) {
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 event = require('./event')
const shell = require('./shell')
const modules = require('./modules')
const lodash = require('lodash')
const shell = require('./shell')
const status = require('./status')
const log = require('./utils/util.log')
const context = {
config,
shell,
@ -29,14 +30,14 @@ const proxy = setupPlugin('proxy', modules.proxy, context, config)
const plugin = {}
for (const key in modules.plugin) {
const target = modules.plugin[key]
const api = setupPlugin('plugin.' + key, target, context, config)
const api = setupPlugin(`plugin.${key}`, target, context, config)
plugin[key] = api
}
config.resetDefault()
const server = modules.server
const serverStart = server.start
const newServerStart = ({ mitmproxyPath }) => {
function newServerStart ({ mitmproxyPath }) {
return serverStart({ mitmproxyPath, plugins: plugin })
}
server.start = newServerStart

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
const pluginConfig = require('./config')
const Plugin = function (context) {
const { config, shell, event, log } = context
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 = {
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,
NODE_EXTRA_CA_CERTS: false,
NODE_TLS_REJECT_UNAUTHORIZED: false,
yarnRegistry: 'null',
yarnRegistry: 'default',
registry: 'https://registry.npmjs.org'// 可以选择切换官方或者淘宝镜像
},
// intercepts: {

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
const pipConfig = require('./config')
const PipPlugin = function (context) {
const { config, shell, event, log } = context
const api = {
@ -20,7 +21,7 @@ const PipPlugin = function (context) {
},
async getPipEnv () {
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) {
ret = ret.trim()
const lines = ret.split('\n')

View File

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

View File

@ -2,7 +2,9 @@
*/
const Shell = require('../shell')
const extraPath = require('./extra-path')
const execute = Shell.execute
const executor = {
async windows (exec) {
const loopbackPath = extraPath.getEnableLoopbackPath()
@ -10,10 +12,10 @@ const executor = {
await execFile(loopbackPath)
},
async linux (exec, { port }) {
throw Error('不支持此操作')
throw new Error('不支持此操作')
},
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 log = require('../../../utils/util.log')
function getExtraPath () {
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 Shell = require('../shell')
const execute = Shell.execute
const executor = {
async windows (exec) {
const ret = await exec(['npm config list --json'], { type: 'cmd' })
@ -14,10 +16,10 @@ const executor = {
return {}
},
async linux (exec, { port }) {
throw Error('暂未实现此功能')
throw new Error('暂未实现此功能')
},
async mac (exec, { port }) {
throw Error('暂未实现此功能')
throw new Error('暂未实现此功能')
}
}

View File

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

View File

@ -1,4 +1,5 @@
const Shell = require('../shell')
const execute = Shell.execute
const executor = {
@ -9,11 +10,11 @@ const executor = {
return true
},
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
},
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
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,42 +1,42 @@
{
app: {
autoStart: {
enabled: true,
"app": {
"autoStart": {
"enabled": true
},
mode: 'default',
"mode": "default"
},
plugin: {
node: {
setting: {
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',
},
"plugin": {
"node": {
"setting": {
"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"
}
}
}
}
}

View File

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

View File

@ -1,8 +1,8 @@
const expect = require('chai').expect
// eslint-disable-next-line no-undef
describe('test', function () {
describe('test', () => {
// eslint-disable-next-line no-undef
it('regexp', function () {
it('regexp', () => {
const test = '^/[^/]+/[^/]+(/releases(/.*)?)?$'
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 request = require('request')
const options = {
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/mitmproxy": "^1.8.9",
"@mihomo-party/sysproxy": "^2.0.4",
"@natmri/platform-napi": "^0.0.8",
"@natmri/platform-napi": "^0.0.7",
"adm-zip": "^0.5.5",
"ant-design-vue": "^1.6.5",
"compressing": "^1.5.1",

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
import { acquireShutdownBlock, insertWndProcHook, releaseShutdownBlock, removeWndProcHook, setMainWindowHandle } from '@natmri/platform-napi'
import { powerMonitor as _powerMonitor } from 'electron'
import { setMainWindowHandle, insertWndProcHook, removeWndProcHook, releaseShutdownBlock, acquireShutdownBlock } from '@natmri/platform-napi'
class PowerMonitor {
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 path from 'path'
import DevSidecar from '@docmirror/dev-sidecar'
import { ipcMain } from 'electron'
import lodash from 'lodash'
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 log = require('../../utils/util.log')
const mitmproxyPath = path.join(__dirname, 'mitmproxy.js')
process.env.DS_EXTRA_PATH = path.join(__dirname, '../extra/')
const getDefaultConfigBasePath = function () {
return DevSidecar.api.config.get().server.setting.userBasePath
}
@ -129,7 +131,7 @@ function _deepFindFunction (list, parent, parentKey) {
if (item instanceof Function) {
list.push(parentKey + key)
} else if (item instanceof Object) {
_deepFindFunction(list, item, parentKey + key + '.')
_deepFindFunction(list, item, `${parentKey + key}.`)
}
}
}
@ -184,14 +186,20 @@ export default {
// 注册从core里来的事件并转发给view
DevSidecar.api.event.register('status', (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) => {
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) => {
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 Sudoer from 'electron-sudo'
export default {
async open () {
const options = { name: '设置loopback' }
const sudoer = new Sudoer(options)
const exeFile = DevSidecar.api.shell.extraPath.getEnableLoopbackPath()
await sudoer.exec(
exeFile, { env: { PARAM: 'VALUE' } }
exeFile,
{ env: { PARAM: 'VALUE' } }
)
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,10 +1,11 @@
// import api from './api/front'
import autoStart from './auto-start/front'
import error from './error/front'
import fileSelector from './file-selector/front'
import onClose from './on-close/front'
import tongji from './tongji/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 = {
// api, // 核心接口模块
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 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)
log.info('读取 running.json by gui bridge 成功:', configPath)
const config = jsonApi.parse(configJson.toString())

View File

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

View File

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

View File

@ -1,11 +1,10 @@
/**
* second step
* @param {*} ipcRenderer
* @param {*} siteId
* @param {*} router
*/
const ebtRenderer = (ipcRenderer, siteId, router) => {
function ebtRenderer (ipcRenderer, siteId, router) {
/* istanbul ignore else */
if (!(ipcRenderer && ipcRenderer.on && ipcRenderer.send)) {
throw new TypeError('require ipcRenderer')
@ -38,7 +37,7 @@ const ebtRenderer = (ipcRenderer, siteId, router) => {
router.beforeEach((to, _, next) => {
/* istanbul ignore else */
if (to.path) {
window._hmt.push(['_trackPageview', '/#' + to.fullPath])
window._hmt.push(['_trackPageview', `/#${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 { autoUpdater } from 'electron-updater'
import path from 'path'
import request from 'request'
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 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 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
// lengthHeader: 'x-transfer-length' // Length header to use, defaults to content-length
})
.on('progress', function (state) {
.on('progress', (state) => {
onProgress(state.percent * 100)
log.log('progress', state.percent)
})
.on('error', function (err) {
.on('error', (err) => {
// Do something with err
log.error('下载升级包失败:', err)
onError(err)
})
.on('end', function () {
.on('end', () => {
// Do something after request finishes
onSuccess()
})
@ -44,9 +43,9 @@ function parseVersion (version) {
const matched = version.match(/^v?(\d+\.\d+\.\d+)(.*)$/)
const versionArr = matched[1].split('.')
return {
major: parseInt(versionArr[0]),
minor: parseInt(versionArr[1]),
patch: parseInt(versionArr[2]),
major: Number.parseInt(versionArr[0]),
minor: Number.parseInt(versionArr[1]),
patch: Number.parseInt(versionArr[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'
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 {
if (error) {
log.error('检查更新失败:', error)
const errorMsg = '检查更新失败:' + error
const errorMsg = `检查更新失败:${error}`
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: errorMsg })
return
}
@ -203,7 +202,7 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
value: {
version,
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
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 {
message = '检查更新失败: ' + (bodyObj && bodyObj.message ? bodyObj.message : body)
message = `检查更新失败: ${bodyObj && bodyObj.message ? bodyObj.message : body}`
}
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: message })
}
} catch (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) {
fs.mkdirSync(fileDir)
}
const filePath = path.join(fileDir, value.version + '.zip')
const filePath = path.join(fileDir, `${value.version}.zip`)
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 })
@ -263,10 +262,10 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
partPackagePath = filePath
win.webContents.send('update', {
key: 'downloaded',
value: value
value
})
}, (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)
sendUpdateMessage({ key: 'error', value: error, error: error })
sendUpdateMessage({ key: 'error', value: error, error })
// 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')
sendUpdateMessage({ key: 'checking', value: message.checking })
})
autoUpdater.on('update-available', function (info) {
autoUpdater.on('update-available', (info) => {
log.info('autoUpdater update-available')
sendUpdateMessage({ key: 'available', value: info })
})
autoUpdater.on('update-not-available', function () {
autoUpdater.on('update-not-available', () => {
log.info('autoUpdater update-not-available')
sendUpdateMessage({ key: 'notAvailable', value: message.updateNotAva })
})
// 更新下载进度
autoUpdater.on('download-progress', function (progressObj) {
autoUpdater.on('download-progress', (progressObj) => {
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)
win.webContents.send('update', {
key: 'downloaded',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -97,15 +97,15 @@ export default {
<span><code>Git.exe</code>将不代理以下仓库可以是根地址组织/机构地址完整地址</span>
</a-col>
<a-col :span="2">
<a-button type="primary" icon="plus" @click="addNoProxyUrl()"/>
<a-button type="primary" icon="plus" @click="addNoProxyUrl()" />
</a-col>
</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-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 :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-row>
</div>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
<script>
import Plugin from '../mixins/plugin'
import { ipcRenderer } from 'electron'
import Plugin from '../mixins/plugin'
export default {
name: 'Setting',
@ -28,7 +28,7 @@ export default {
},
async openLog () {
const dir = await this.$api.info.getConfigDir()
this.$api.ipc.openPath(dir + '/logs/')
this.$api.ipc.openPath(`${dir}/logs/`)
},
getEventKey (event) {
//
@ -130,7 +130,7 @@ export default {
async disableBeforeInputEvent () {
clearTimeout(window.enableBeforeInputEventTimeout)
window.config.disableBeforeInputEvent = true
window.enableBeforeInputEventTimeout = setTimeout(function () {
window.enableBeforeInputEventTimeout = setTimeout(() => {
window.config.disableBeforeInputEvent = false
}, 2000)
},
@ -158,12 +158,18 @@ export default {
// CtrlAltShiftWindow
let shortcut = event.ctrlKey ? 'Ctrl + ' : ''
if (event.altKey) shortcut += 'Alt + '
if (event.shiftKey) shortcut += 'Shift + '
if (event.metaKey) shortcut += 'Meta + '
if (event.altKey) {
shortcut += 'Alt + '
}
if (event.shiftKey) {
shortcut += 'Shift + '
}
if (event.metaKey) {
shortcut += 'Meta + '
}
// 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 = '无'
return
}
@ -250,7 +256,7 @@ export default {
this.$confirm({
title: '确定要恢复出厂设置吗?',
width: 610,
content: h =>
content: (h) => (
<div class="restore-factory-settings">
<hr/>
<p>
@ -267,7 +273,8 @@ export default {
2. 将该备份文件重命名为<span>config.json</span>再重启软件即可恢复个性化配置
</div>
</p>
</div>,
</div>
),
cancelText: '取消',
okText: '确定',
onOk: async () => {
@ -296,8 +303,6 @@ export default {
<ds-container>
<template slot="header">
设置
<span>
</span>
</template>
<div v-if="config">
@ -330,10 +335,10 @@ export default {
</div>
</a-form-item>
<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 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 label="重载远程配置" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-button :disabled="config.app.remoteConfig.enabled === false" :loading="reloadLoading" icon="sync" @click="reloadRemoteConfig()"></a-button>
@ -345,10 +350,10 @@ export default {
<hr/>
<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-button :value="'light'" title="light">
<a-radio-button value="light" title="light">
亮色
</a-radio-button>
<a-radio-button :value="'dark'" title="dark">
<a-radio-button value="dark" title="dark">
暗色
</a-radio-button>
</a-radio-group>
@ -384,7 +389,7 @@ export default {
</a-form-item>
<hr/>
<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">
部分快捷键已被占用F5=刷新页面F12=开发者工具DevTools
</div>
@ -403,8 +408,8 @@ export default {
</div>
</a-form-item>
<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.height" :step="50" :min="500" :max="2000"/>
<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-form-item>
<hr/>
<a-form-item label="自动检查更新" :label-col="labelCol" :wrapper-col="wrapperCol">
@ -442,5 +447,4 @@ export default {
</div>
</template>
</ds-container>
</template>

View File

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

View File

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

View File

@ -1,13 +1,14 @@
const mitmproxy = require('./lib/proxy')
const ProxyOptions = require('./options')
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 { fireError, fireStatus } = require('./utils/util.process')
const speedTest = require('./lib/speed/index.js')
let servers = []
function registerProcessListener () {
process.on('message', function (msg) {
process.on('message', (msg) => {
log.info('child get msg:', JSON.stringify(msg))
if (msg.type === 'action') {
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') {
// log.error(err.errno)
return
@ -37,7 +38,7 @@ function registerProcessListener () {
process.on('uncaughtExceptionMonitor', (err, origin) => {
log.info('Process uncaughtExceptionMonitor:', err, origin)
})
process.on('exit', function (code, signal) {
process.on('exit', (code, signal) => {
log.info('代理服务进程被关闭:', code, signal)
})
process.on('beforeExit', (code, signal) => {

View File

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

View File

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

View File

@ -1,14 +1,17 @@
const { promisify } = require('util')
const doh = require('dns-over-http')
const BaseDNS = require('./base')
const log = require('../../utils/util.log')
const dohQueryAsync = promisify(doh.query)
const matchUtil = require('../../utils/util.match')
const BaseDNS = require('./base')
const dohQueryAsync = promisify(doh.query)
function mapToList (ipMap) {
const ipList = []
for (const key in ipMap) {
if (!ipMap[key]) continue
if (!ipMap[key]) {
continue
}
ipList.push(ipMap[key])
}
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 DNSOverIpAddress = require('./ipaddress.js')
const DNSOverPreSetIpList = require('./preset.js')
const matchUtil = require('../../utils/util.match')
const DNSOverTLS = require('./tls.js')
module.exports = {
initDNS (dnsProviders, preSetIpList) {

View File

@ -1,6 +1,7 @@
const BaseDNS = require('./base')
const axios = require('axios')
const log = require('../../utils/util.log')
const BaseDNS = require('./base')
module.exports = class DNSOverIpAddress extends BaseDNS {
async _lookup (hostname) {
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 = await axios.get(url)
if (res.status !== 200 && res.status !== 201) {
log.info(`[dns] get ${hostname} ipaddress: error:${res}`)
log.error(`[dns] get ${hostname} ipaddress: error: ${res}`)
return
}
const ret = res.data

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -44,7 +44,7 @@ function getLastModifiedTimeFromIfModifiedSince (rOptions, log) {
return new Date(lastModified).getTime()
} catch (e) {
// 为数字时,直接返回
if (/\\d+/g.test(lastModified)) {
if (/\\d+/.test(lastModified)) {
return lastModified - 0
}
@ -66,12 +66,12 @@ module.exports = {
// 获取 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 // 当前请求指定要禁用缓存,跳过当前拦截器
}
// 获取 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 // 当前请求指定要禁用缓存,跳过当前拦截器
}
@ -91,7 +91,7 @@ module.exports = {
// 缓存未过期直接拦截请求并响应304
res.writeHead(304, {
'DS-Interceptor': 'cache: ' + maxAge
'DS-Interceptor': `cache: ${maxAge}`
})
res.end()

View File

@ -3,20 +3,18 @@ const lodash = require('lodash')
// 替换占位符
function replacePlaceholder (url, rOptions, matched) {
if (url.indexOf('${') >= 0) {
// eslint-disable-next-line
// no-template-curly-in-string
if (url.includes('${')) {
// eslint-disable-next-line no-template-curly-in-string
url = url.replace('${host}', rOptions.hostname)
if (matched && url.indexOf('${') >= 0) {
if (matched && url.includes('${')) {
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, '')
}
}
@ -45,7 +43,7 @@ function buildTargetUrl (rOptions, urlConf, interceptOpt, 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
}
@ -90,7 +88,7 @@ module.exports = {
for (const bk of interceptOpt.backup) {
backupList.push(bk)
}
const key = rOptions.hostname + '/' + interceptOpt.key
const key = `${rOptions.hostname}/${interceptOpt.key}`
const count = RequestCounter.getOrCreate(key, backupList)
if (count.value == null) {
count.doRank()

View File

@ -32,7 +32,7 @@ module.exports = {
// 替换请求头
if (requestReplaceConfig.headers) {
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)) {
rOptions.doDownload = true
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)

View File

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

View File

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

View File

@ -29,7 +29,7 @@ module.exports = {
}
// 如果没有响应头 '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')
return
}
@ -50,7 +50,7 @@ module.exports = {
let scriptTag
if (key.indexOf('/') >= 0) {
if (key.includes('/')) {
scriptTag = getScriptByUrlOrPath(key) // 1.绝对地址或相对地址注意当目标站点限制跨域脚本时可使用相对地址再结合proxy拦截器进行代理可规避掉限制跨域脚本问题。
} else {
const script = scripts[key]
@ -60,7 +60,7 @@ module.exports = {
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') {
tags = '\r\n\t' + getScriptByUrlOrPath(interceptOpt.tampermonkeyScript) + tags
tags = `\r\n\t${getScriptByUrlOrPath(interceptOpt.tampermonkeyScript)}${tags}`
} 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')
log.info(`script response intercept: insert script ${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`, ', head:', tags)
return {
head: tags + '\r\n'
head: `${tags}\r\n`
}
} catch (err) {
try {
@ -102,10 +102,12 @@ module.exports = {
const handleScriptUrl = (scriptUrl, name, replaceScriptUrlFun) => {
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
log.info(`替换${name}配置值:'${scriptUrl}' -> '${scriptKey}'`)
if (typeof replaceScriptUrlFun === 'function') replaceScriptUrlFun(scriptKey)
if (typeof replaceScriptUrlFun === 'function') {
replaceScriptUrlFun(scriptKey)
}
} else if (scriptUrl.indexOf('/') === 0) {
// 相对地址
scriptProxy[scriptUrl] = scriptUrl

View File

@ -1,10 +1,11 @@
const fs = require('fs')
const path = require('path')
const log = require('../../utils/util.log')
let scripts
function buildScript (sc, content, scriptName) {
const scriptKey = `ds_${scriptName}${sc.version ? ('_' + sc.version) : ''}:`
const scriptKey = `ds_${scriptName}${sc.version ? (`_${sc.version}`) : ''}:`
// 代码1监听事件
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) {
grantStr += item + ' = (window.__ds_global__ || {})[\'' + item + '\'];'
grantStr += `${item} = (window.__ds_global__ || {})['${item}'];`
} else {
grantStr += 'const ' + item + ' = (window.__ds_global__ || {})[\'' + item + '\'] || (() => {});'
grantStr += `const ${item} = (window.__ds_global__ || {})['${item}'] || (() => {});`
}
}
@ -81,7 +82,7 @@ function loadScript (content, scriptName) {
script: ''
}
for (const string of confItemArr) {
const reg = new RegExp('.*@([^\\s]+)\\s(.+)')
const reg = new RegExp('.*@(\\S+)\\s(.+)')
const ret = string.match(reg)
if (ret) {
const key = ret[1].trim()
@ -103,7 +104,7 @@ function loadScript (content, scriptName) {
function readFile (rootDir, script) {
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)
return fs.readFileSync(location).toString()
}

View File

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

View File

@ -1,9 +1,10 @@
const url = require('url')
const Agent = require('./ProxyHttpAgent')
const HttpsAgent = require('./ProxyHttpsAgent')
const tunnelAgent = require('tunnel-agent')
const log = require('../../../utils/util.log')
const matchUtil = require('../../../utils/util.match')
const Agent = require('./ProxyHttpAgent')
const HttpsAgent = require('./ProxyHttpsAgent')
const util = exports
const httpsAgentCache = {}
@ -25,7 +26,7 @@ function getTimeoutConfig (hostname, serverSetting) {
}
function createHttpsAgent (timeoutConfig, verifySsl) {
const key = timeoutConfig.timeout + '-' + timeoutConfig.keepAliveTimeout
const key = `${timeoutConfig.timeout}-${timeoutConfig.keepAliveTimeout}`
if (!httpsAgentCache[key]) {
verifySsl = !!verifySsl
@ -57,7 +58,7 @@ function createHttpsAgent (timeoutConfig, verifySsl) {
}
function createHttpAgent (timeoutConfig) {
const key = timeoutConfig.timeout + '-' + timeoutConfig.keepAliveTimeout
const key = `${timeoutConfig.timeout}-${timeoutConfig.keepAliveTimeout}`
if (!httpAgentCache[key]) {
httpAgentCache[key] = new Agent({
keepAlive: true,
@ -80,12 +81,12 @@ util.parseHostnameAndPort = (host, defaultPort) => {
if (arr) {
arr = arr.slice(1)
if (arr[1]) {
arr[1] = parseInt(arr[1], 10)
arr[1] = Number.parseInt(arr[1], 10)
}
} else {
arr = host.split(':')
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({
proxy: {
host: hostname,
port: port
port
}
})
}
@ -198,7 +199,7 @@ util.getTunnelAgent = (requestIsSSL, externalProxyUrl) => {
httpsOverHttpsAgent = tunnelAgent.httpsOverHttps({
proxy: {
host: hostname,
port: port
port
}
})
}
@ -220,7 +221,7 @@ util.getTunnelAgent = (requestIsSSL, externalProxyUrl) => {
httpOverHttpsAgent = tunnelAgent.httpOverHttps({
proxy: {
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 through = require('through2')
const log = require('../../../utils/util.log')
// 编解码器
const codecMap = {
@ -84,7 +84,7 @@ function injectScriptIntoHtml (tags, chunk, script) {
}
function handleResponseHeaders (res, proxyRes) {
Object.keys(proxyRes.headers).forEach(function (key) {
Object.keys(proxyRes.headers).forEach((key) => {
if (proxyRes.headers[key] !== undefined) {
// let newkey = key.replace(/^[a-z]|-[a-z]/g, (match) => {
// return match.toUpperCase()
@ -100,7 +100,7 @@ function handleResponseHeaders (res, proxyRes) {
const reg = /script-src ([^:]*);/i
const matched = policy.match(reg)
if (matched) {
if (matched[1].indexOf('self') < 0) {
if (!matched[1].includes('self')) {
policy = policy.replace('script-src', 'script-src \'self\' ')
}
}
@ -117,6 +117,7 @@ function handleResponseHeaders (res, proxyRes) {
const contextPath = '/____ds_script____/'
const monkey = require('../../monkey')
module.exports = {
requestIntercept (context, req, res, ssl, next) {
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 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
function matched (hostname, overWallTargetMap) {
@ -23,7 +24,7 @@ function matched (hostname, overWallTargetMap) {
if (pacClient == null) {
return null
}
const ret = pacClient.FindProxyForURL('https://' + hostname, hostname)
const ret = pacClient.FindProxyForURL(`https://${hostname}`, hostname)
if (ret && ret.indexOf('PROXY ') === 0) {
log.info(`matchHostname: matched overwall: '${hostname}' -> '${ret}' 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格式
let pacTxt = body
try {
if (pacTxt.indexOf('!---------------------EOF') < 0) {
if (!pacTxt.includes('!---------------------EOF')) {
pacTxt = Buffer.from(pacTxt, 'base64').toString('utf8')
// log.debug('解析 base64 后的 pax:', pacTxt)
}
} catch (e) {
if (pacTxt.indexOf('!---------------------EOF') < 0) {
if (!pacTxt.includes('!---------------------EOF')) {
log.error(`远程 pac.txt 文件内容即不是base64格式也不是要求的格式url: ${remotePacFileUrl}body: ${body}`)
return
}
@ -190,10 +191,10 @@ function createOverwallMiddleware (overWallConfig) {
const port = server[domain].port
const path = server[domain].path
const password = server[domain].password
const proxyTarget = domain + '/' + path + '/' + hostname + req.url
const proxyTarget = `${domain}/${path}/${hostname}${req.url}`
// 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
const URL = url.parse(proxy)
rOptions.origional = lodash.cloneDeep(rOptions) // 备份原始请求参数

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,8 @@
const http = require('http')
const https = require('https')
const util = require('../common/util')
const log = require('../../../utils/util.log')
const util = require('../common/util')
// copy from node-http-proxy. ^_^
// create connectHandler function
@ -13,17 +14,19 @@ module.exports = function createUpgradeHandler (serverSetting) {
proxyReq.on('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 (!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) => {
log.error('upgrade error:', e)
})
cltSocket.on('error', function (e) {
cltSocket.on('error', (e) => {
log.error('upgrade socket error:', e)
proxySocket.end()
})
@ -33,23 +36,24 @@ module.exports = function createUpgradeHandler (serverSetting) {
proxySocket.setKeepAlive(true, 0)
if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead)
if (proxyHead && proxyHead.length) {
proxySocket.unshift(proxyHead)
}
cltSocket.write(
Object.keys(proxyRes.headers).reduce(function (head, key) {
`${Object.keys(proxyRes.headers).reduce((head, key) => {
const value = proxyRes.headers[key]
if (!Array.isArray(value)) {
head.push(key + ': ' + value)
head.push(`${key}: ${value}`)
return head
}
for (let i = 0; i < value.length; i++) {
head.push(key + ': ' + value[i])
head.push(`${key}: ${value[i]}`)
}
return head
}, ['HTTP/1.1 101 Switching Protocols'])
.join('\r\n') + '\r\n\r\n'
}, ['HTTP/1.1 101 Switching Protocols']).join('\r\n')}\r\n\r\n`
)
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 log = require('../../../utils/util.log')
const speedTest = require('../../speed')
module.exports = {
createLookupFunc: function (res, dns, action, target, isDnsIntercept) {
target = target ? (', target: ' + target) : ''
createLookupFunc (res, dns, action, target, isDnsIntercept) {
target = target ? (`, target: ${target}`) : ''
return (hostname, options, callback) => {
const tester = speedTest.getSpeedTester(hostname)
@ -12,14 +12,16 @@ module.exports = {
const aliveIpObj = tester.pickFastAliveIpObj()
if (aliveIpObj) {
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)
return
} else {
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) {
isDnsIntercept.dns = dns
isDnsIntercept.hostname = hostname
@ -42,7 +44,9 @@ module.exports = {
}
if (isTestFailedIp === false) {
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)
return
} else {

View File

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

View File

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

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