feature: 域名白名单,支持反向配置,用于大范围设置不代理,个别域名设置需要代理。

master
王良 2025-02-26 11:19:26 +08:00
parent f575e6bda9
commit a6d2685e38
16 changed files with 209 additions and 146 deletions

View File

@ -5,8 +5,6 @@ import { colorTheme } from './composables/theme'
export default { export default {
name: 'App', name: 'App',
components: {
},
data () { data () {
return { return {
locale: zhCN, locale: zhCN,
@ -39,9 +37,6 @@ export default {
}) })
}, },
methods: { methods: {
handleClick (e) {
console.log('click', e)
},
titleClick (item) { titleClick (item) {
console.log('title click:', item) console.log('title click:', item)
}, },

View File

@ -27,6 +27,9 @@ export function apiInit (app) {
ipcRenderer.removeAllListeners(channel) ipcRenderer.removeAllListeners(channel)
}, },
invoke, invoke,
postMessage (channel, ...args) {
ipcRenderer.postMessage(channel, ...args)
},
send, send,
async openExternal (href) { async openExternal (href) {
await shell.openExternal(href) await shell.openExternal(href)

View File

@ -8,7 +8,8 @@ export default {
<div class="ds-container"> <div class="ds-container">
<div class="body-wrapper"> <div class="body-wrapper">
<div v-if="$slots.header" class="container-header"> <div v-if="$slots.header" class="container-header">
<slot name="header" /> <span><slot name="header" /></span>
<span style="color:#999"><slot name="header-right" /></span>
</div> </div>
<div class="container-body"> <div class="container-body">
<slot /> <slot />
@ -23,16 +24,16 @@ export default {
<style lang="scss"> <style lang="scss">
.ds-container { .ds-container {
height: 100%; height: 100%;
background: #fff; background-color: #fff;
display: flex; display: flex;
position: relative; position: relative;
.body-wrapper { .body-wrapper {
position: absolute; position: absolute;
top: 0px; top: 0;
right: 0px; right: 0;
bottom: 0px; bottom: 0;
left: 0px; left: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
@ -41,7 +42,7 @@ export default {
.container-header { .container-header {
padding: 15px; padding: 15px;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
background: #fff; background-color: #fff;
height: 60px; height: 60px;
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -142,5 +142,17 @@ export default {
const dir = await this.$api.info.getLogDir() const dir = await this.$api.info.getLogDir()
this.$api.ipc.openPath(dir) this.$api.ipc.openPath(dir)
}, },
handleHostname (hostname) {
if (this.isNotHostname(hostname)) {
return ''
}
// 移除所有空白符
return hostname.replaceAll(/\s+/g, '')
},
isNotHostname (hostname) {
// 暂时只判断数字
return !hostname || /^[\d\s]+$/.test(hostname)
},
}, },
} }

View File

@ -25,10 +25,10 @@ export default {
<ds-container> <ds-container>
<template slot="header"> <template slot="header">
帮助中心 帮助中心
<span> </template>
<a-button class="md-mr-10" @click="openExternal('https://github.com/docmirror/dev-sidecar/issues/new/choose')"></a-button> <template slot="header-right">
<a-button class="md-mr-10" icon="profile" @click="openLog()"></a-button> <a-button class="md-mr-10" @click="openExternal('https://github.com/docmirror/dev-sidecar/issues/new/choose')"></a-button>
</span> <a-button class="md-mr-10" icon="profile" @click="openLog()"></a-button>
</template> </template>
<div v-if="config" class="help-list"> <div v-if="config" class="help-list">

View File

@ -259,20 +259,20 @@ export default {
<DsContainer class="page_index"> <DsContainer class="page_index">
<template slot="header"> <template slot="header">
给开发者的辅助工具 给开发者的辅助工具
<span> </template>
<a-button style="margin-right:10px" @click="openSetupCa"> <template slot="header-right">
<a-badge :count="_rootCaSetuped ? 0 : 1" dot>安装根证书</a-badge> <a-button style="margin-right:10px" @click="openSetupCa">
</a-button> <a-badge :count="_rootCaSetuped ? 0 : 1" dot>安装根证书</a-badge>
</a-button>
<a-button <a-button
style="margin-right:10px" :loading="update.downloading || update.checking" :title="`当前版本:${info.version}`" style="margin-right:10px" :loading="update.downloading || update.checking" :title="`当前版本:${info.version}`"
@click="doCheckUpdate(true)" @click="doCheckUpdate(true)"
> >
<a-badge :count="update.newVersion ? 1 : 0" dot> <a-badge :count="update.newVersion ? 1 : 0" dot>
<span v-if="update.downloading">{{ update.progress }}%</span>{{ update.downloading ? '' : (`${update.checking ? '' : ''}`) }} <span v-if="update.downloading">{{ update.progress }}%</span>{{ update.downloading ? '' : (`${update.checking ? '' : ''}`) }}
</a-badge> </a-badge>
</a-button> </a-button>
</span>
</template> </template>
<div class="box"> <div class="box">
@ -319,7 +319,7 @@ export default {
</div> </div>
<div :span="12"> <div :span="12">
<a-form style="margin-top:20px" :label-col="{ span: 15 }" :wrapper-col="{ span: 9 }"> <a-form style="margin-top:20px" :label-col="{ span: 15 }" :wrapper-col="{ span: 9 }">
<a-form-item v-for=" (item, key) in switchBtns" :key="key" :label="item.label"> <a-form-item v-for="(item, key) in switchBtns" :key="key" :label="item.label">
<a-tooltip placement="topLeft"> <a-tooltip placement="topLeft">
<a-switch <a-switch
style="margin-left:10px" :loading="item.loading" :checked="item.status()" default-checked style="margin-left:10px" :loading="item.loading" :checked="item.status()" default-checked

View File

@ -7,6 +7,8 @@ export default {
data () { data () {
return { return {
key: 'plugin.git', key: 'plugin.git',
labelCol: { span: 4 },
wrapperCol: { span: 20 },
noProxyUrls: [], noProxyUrls: [],
needRestart: false, needRestart: false,
} }
@ -45,7 +47,7 @@ export default {
} }
}, },
addNoProxyUrl () { addNoProxyUrl () {
this.noProxyUrls.unshift({ key: '', value: true }) this.noProxyUrls.unshift({ key: '' })
}, },
delNoProxyUrl (item, index) { delNoProxyUrl (item, index) {
this.noProxyUrls.splice(index, 1) this.noProxyUrls.splice(index, 1)
@ -54,7 +56,10 @@ export default {
const noProxyUrls = {} const noProxyUrls = {}
for (const item of this.noProxyUrls) { for (const item of this.noProxyUrls) {
if (item.key) { if (item.key) {
noProxyUrls[item.key] = item.value const hostname = this.handleHostname(item.key)
if (hostname) {
noProxyUrls[hostname] = true
}
} }
} }
this.config.plugin.git.setting.noProxyUrls = noProxyUrls this.config.plugin.git.setting.noProxyUrls = noProxyUrls
@ -67,9 +72,9 @@ export default {
<ds-container> <ds-container>
<template slot="header"> <template slot="header">
Git.exe代理设置 Git.exe代理设置
<span style="color:#999;"> </template>
仅针对git命令行的代理设置github网站的访问无需设置 <template slot="header-right">
</span> 仅针对git命令行的代理设置github网站的访问无需设置
</template> </template>
<div v-if="config"> <div v-if="config">
@ -103,7 +108,7 @@ export default {
</a-row> </a-row>
<a-row v-for="(item, index) of noProxyUrls" :key="index" :gutter="10"> <a-row v-for="(item, index) of noProxyUrls" :key="index" :gutter="10">
<a-col :span="22"> <a-col :span="22">
<a-input v-model="item.key" :disabled="item.value === false" /> <a-input v-model="item.key" />
</a-col> </a-col>
<a-col :span="2"> <a-col :span="2">
<a-button type="danger" icon="minus" @click="delNoProxyUrl(item, index)" /> <a-button type="danger" icon="minus" @click="delNoProxyUrl(item, index)" />

View File

@ -7,6 +7,8 @@ export default {
data () { data () {
return { return {
key: 'plugin.node', key: 'plugin.node',
labelCol: { span: 4 },
wrapperCol: { span: 20 },
npmVariables: undefined, npmVariables: undefined,
registry: false, registry: false,
} }
@ -51,9 +53,9 @@ export default {
<ds-container> <ds-container>
<template slot="header"> <template slot="header">
NPM加速 NPM加速
<span style="color:#999;"> </template>
由于nodejs不走系统证书所以npm加速不是很好用可以用淘宝registry <template slot="header-right">
</span> 由于nodejs不走系统证书所以npm加速不是很好用可以用淘宝registry
</template> </template>
<div v-if="config"> <div v-if="config">
@ -97,7 +99,6 @@ export default {
设置后立即生效即使关闭 ds 也会继续保持 设置后立即生效即使关闭 ds 也会继续保持
</div> </div>
</a-form-item> </a-form-item>
<a-form-item label="yarn仓库镜像" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="yarn仓库镜像" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-radio-group v-model="config.plugin.node.setting.yarnRegistry" default-value="null" button-style="solid" @change="onSwitchYarnRegistry"> <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"> <a-radio-button value="default" title="https://registry.yarnpkg.com">
@ -111,7 +112,6 @@ export default {
设置后立即生效即使关闭 ds 也会继续保持 设置后立即生效即使关闭 ds 也会继续保持
</div> </div>
</a-form-item> </a-form-item>
<a-form-item label="镜像变量设置" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="镜像变量设置" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.plugin.node.startup.variables"> <a-checkbox v-model="config.plugin.node.startup.variables">
自动设置启动npm加速开关时将会设置如下环境变量 自动设置启动npm加速开关时将会设置如下环境变量
@ -123,10 +123,10 @@ export default {
<a-col :span="10"> <a-col :span="10">
<a-input v-model="item.key" :title="item.key" read-only /> <a-input v-model="item.key" :title="item.key" read-only />
</a-col> </a-col>
<a-col :span="10"> <a-col :span="13">
<a-input v-model="item.value" :title="item.value" read-only /> <a-input v-model="item.value" :title="item.value" read-only />
</a-col> </a-col>
<a-col :span="4"> <a-col :span="1">
<a-icon v-if="item.exists && item.hadSet" title="已设置" style="color:green" type="check" /> <a-icon v-if="item.exists && item.hadSet" title="已设置" style="color:green" type="check" />
<a-icon v-else title="还未设置" style="color:red" type="exclamation-circle" /> <a-icon v-else title="还未设置" style="color:red" type="exclamation-circle" />
</a-col> </a-col>

View File

@ -7,6 +7,8 @@ export default {
data () { data () {
return { return {
key: 'plugin.overwall', key: 'plugin.overwall',
labelCol: { span: 4 },
wrapperCol: { span: 20 },
targets: undefined, targets: undefined,
servers: undefined, servers: undefined,
overwallOptions: [ overwallOptions: [
@ -40,8 +42,8 @@ export default {
this.initServer() this.initServer()
}, },
async applyBefore () { async applyBefore () {
this.saveTarget() this.submitTarget()
this.saveServer() this.submitServer()
}, },
initTarget () { initTarget () {
this.targets = [] this.targets = []
@ -54,17 +56,20 @@ export default {
}) })
} }
}, },
deleteTarget (item, index) {
this.targets.splice(index, 1)
},
addTarget () { addTarget () {
this.targets.unshift({ key: '', value: 'true' }) this.targets.unshift({ key: '', value: 'true' })
}, },
saveTarget () { deleteTarget (item, index) {
this.targets.splice(index, 1)
},
submitTarget () {
const map = {} const map = {}
for (const item of this.targets) { for (const item of this.targets) {
if (item.key) { if (item.key) {
map[item.key] = item.value === 'true' const hostname = this.handleHostname(item.key)
if (hostname) {
map[hostname] = (item.value === 'true')
}
} }
} }
this.config.plugin.overwall.targets = map this.config.plugin.overwall.targets = map
@ -90,11 +95,14 @@ export default {
addServer () { addServer () {
this.servers.unshift({ key: '', value: { type: 'path' } }) this.servers.unshift({ key: '', value: { type: 'path' } })
}, },
saveServer () { submitServer () {
const map = {} const map = {}
for (const item of this.servers) { for (const item of this.servers) {
if (item.key) { if (item.key) {
map[item.key] = item.value const hostname = this.handleHostname(item.key)
if (hostname) {
map[hostname] = item.value
}
} }
} }
this.config.plugin.overwall.server = map this.config.plugin.overwall.server = map
@ -107,9 +115,9 @@ export default {
<ds-container> <ds-container>
<template slot="header"> <template slot="header">
梯子 梯子
<span> </template>
<a-button type="primary" @click="openExternal('https://github.com/docmirror/dev-sidecar-doc/blob/main/ow.md')"></a-button> <template slot="header-right">
</span> <a-button type="primary" @click="openExternal('https://github.com/docmirror/dev-sidecar-doc/blob/main/ow.md')"></a-button>
</template> </template>
<div v-if="config"> <div v-if="config">
@ -142,7 +150,7 @@ export default {
只要下载成功后即使关闭自动更新功能也会优先读取最近下载的文件 只要下载成功后即使关闭自动更新功能也会优先读取最近下载的文件
</div> </div>
</a-form-item> </a-form-item>
<a-form-item label="远程PAC文件地址" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="远程PAC文件" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input v-model="config.plugin.overwall.pac.pacFileUpdateUrl" :title="config.plugin.overwall.pac.pacFileUpdateUrl" /> <a-input v-model="config.plugin.overwall.pac.pacFileUpdateUrl" :title="config.plugin.overwall.pac.pacFileUpdateUrl" />
<div class="form-help"> <div class="form-help">
远程PAC文件内容可以是<code>base64</code>编码格式也可以是未经过编码的 远程PAC文件内容可以是<code>base64</code>编码格式也可以是未经过编码的

View File

@ -7,6 +7,8 @@ export default {
data () { data () {
return { return {
key: 'plugin.pip', key: 'plugin.pip',
labelCol: { span: 4 },
wrapperCol: { span: 20 },
npmVariables: undefined, npmVariables: undefined,
registry: false, registry: false,
trustedHostList: [], trustedHostList: [],

View File

@ -68,7 +68,10 @@ export default {
const excludeIpList = {} const excludeIpList = {}
for (const item of this.excludeIpList) { for (const item of this.excludeIpList) {
if (item.key) { if (item.key) {
excludeIpList[item.key] = item.value === 'true' const hostname = this.handleHostname(item.key)
if (hostname) {
excludeIpList[hostname] = (item.value === 'true')
}
} }
} }
this.config.proxy.excludeIpList = excludeIpList this.config.proxy.excludeIpList = excludeIpList

View File

@ -12,9 +12,20 @@ export default {
data () { data () {
return { return {
key: 'server', key: 'server',
activeTabKey: '1',
dnsMappings: [], dnsMappings: [],
speedTestList: [], speedTestList: [],
whiteList: [], whiteList: [],
whiteListOptions: [
{
label: '不代理',
value: 'true',
},
{
label: '代理',
value: 'false',
},
],
} }
}, },
computed: { computed: {
@ -58,8 +69,9 @@ export default {
} }
}, },
async applyBefore () { async applyBefore () {
this.submitDnsMapping() this.submitDnsMappings()
this.submitWhiteList() this.submitWhiteList()
this.delEmptySpeedHostname()
}, },
async applyAfter () { async applyAfter () {
if (this.status.server.enabled) { if (this.status.server.enabled) {
@ -77,20 +89,20 @@ export default {
}) })
} }
}, },
submitDnsMapping () { submitDnsMappings () {
const dnsMapping = {} const dnsMapping = {}
for (const item of this.dnsMappings) { for (const item of this.dnsMappings) {
if (item.key) { if (item.key) {
dnsMapping[item.key] = item.value const hostname = this.handleHostname(item.key)
if (hostname) {
dnsMapping[hostname] = item.value
}
} }
} }
this.config.server.dns.mapping = dnsMapping this.config.server.dns.mapping = dnsMapping
}, },
deleteDnsMapping (item, index) { deleteDnsMapping (item, index) {
this.dnsMappings.splice(index, 1) this.dnsMappings.splice(index, 1)
},
restoreDefDnsMapping (item, index) {
}, },
addDnsMapping () { addDnsMapping () {
this.dnsMappings.unshift({ key: '', value: 'quad9' }) this.dnsMappings.unshift({ key: '', value: 'quad9' })
@ -102,26 +114,29 @@ export default {
for (const key in this.config.server.whiteList) { for (const key in this.config.server.whiteList) {
const value = this.config.server.whiteList[key] const value = this.config.server.whiteList[key]
this.whiteList.push({ this.whiteList.push({
key, key: key || '',
value, value: value === true ? 'true' : 'false',
}) })
} }
}, },
addWhiteList () {
this.whiteList.unshift({ key: '', value: 'true' })
},
deleteWhiteList (item, index) {
this.whiteList.splice(index, 1)
},
submitWhiteList () { submitWhiteList () {
const whiteList = {} const whiteList = {}
for (const item of this.whiteList) { for (const item of this.whiteList) {
if (item.key) { if (item.key) {
whiteList[item.key] = item.value const hostname = this.handleHostname(item.key)
if (hostname) {
whiteList[hostname] = (item.value === 'true')
}
} }
} }
this.config.server.whiteList = whiteList this.config.server.whiteList = whiteList
}, },
deleteWhiteList (item, index) {
this.whiteList.splice(index, 1)
},
addWhiteList () {
this.whiteList.unshift({ key: '', value: true })
},
getSpeedTestConfig () { getSpeedTestConfig () {
return this.config.server.dns.speedTest return this.config.server.dns.speedTest
}, },
@ -131,6 +146,14 @@ export default {
delSpeedHostname (item, index) { delSpeedHostname (item, index) {
this.getSpeedTestConfig().hostnameList.splice(index, 1) this.getSpeedTestConfig().hostnameList.splice(index, 1)
}, },
delEmptySpeedHostname () {
for (let i = this.getSpeedTestConfig().hostnameList.length - 1; i >= 0; i--) {
const hostname = this.handleHostname(this.getSpeedTestConfig().hostnameList[i])
if (!hostname) {
this.getSpeedTestConfig().hostnameList.splice(i, 1)
}
}
},
reSpeedTest () { reSpeedTest () {
this.$api.server.reSpeedTest() this.$api.server.reSpeedTest()
}, },
@ -159,14 +182,14 @@ export default {
}, 5000) }, 5000)
}, },
async handleTabChange (key) { async handleTabChange (key) {
this.activeTabKey = key
if (key !== '2' && key !== '3' && key !== '5' && key !== '6' && key !== '7') { if (key !== '2' && key !== '3' && key !== '5' && key !== '6' && key !== '7') {
return // JsonEditorSearchBar
window.config.disableSearchBar = false
} else {
// JsonEditorSearchBar
window.config.disableSearchBar = true
} }
// vue-json-editor
setTimeout(() => {
window.dispatchEvent(new Event('resize'))
}, 10)
}, },
}, },
} }
@ -181,13 +204,13 @@ export default {
<div style="height: 100%" class="json-wrapper"> <div style="height: 100%" class="json-wrapper">
<a-tabs <a-tabs
v-if="config" v-if="config"
default-active-key="1" :default-active-key="activeTabKey"
tab-position="left" tab-position="left"
:style="{ height: '100%' }" :style="{ height: '100%' }"
@change="handleTabChange" @change="handleTabChange"
> >
<a-tab-pane key="1" tab="基本设置"> <a-tab-pane key="1" tab="基本设置">
<div style="padding-right:10px"> <div v-if="activeTabKey === '1'" style="padding-right:10px">
<a-form-item label="代理服务:" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="代理服务:" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.server.enabled"> <a-checkbox v-model="config.server.enabled">
随应用启动 随应用启动
@ -260,13 +283,15 @@ export default {
</div> </div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="2" tab="拦截设置"> <a-tab-pane key="2" tab="拦截设置">
<VueJsonEditor <div v-if="activeTabKey === '2'" style="height:100%">
ref="editor" v-model="config.server.intercepts" style="height:100%" mode="code" <VueJsonEditor
:show-btns="false" :expanded-on-start="true" v-model="config.server.intercepts" style="height:100%" mode="code"
/> :show-btns="false" :expanded-on-start="true"
/>
</div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="3" tab="超时时间设置"> <a-tab-pane key="3" tab="超时时间设置">
<div style="height:100%;display:flex;flex-direction:column"> <div v-if="activeTabKey === '3'" style="height:100%;display:flex;flex-direction:column">
<a-form-item label="默认超时时间" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="默认超时时间" :label-col="labelCol" :wrapper-col="wrapperCol">
请求<a-input-number v-model="config.server.setting.defaultTimeout" :step="1000" :min="1000" :precision="0" /> ms对应<code>timeout</code>配置<br> 请求<a-input-number v-model="config.server.setting.defaultTimeout" :step="1000" :min="1000" :precision="0" /> ms对应<code>timeout</code>配置<br>
连接<a-input-number v-model="config.server.setting.defaultKeepAliveTimeout" :step="1000" :min="1000" :precision="0" /> ms对应<code>keepAliveTimeout</code>配置 连接<a-input-number v-model="config.server.setting.defaultKeepAliveTimeout" :step="1000" :min="1000" :precision="0" /> ms对应<code>keepAliveTimeout</code>配置
@ -274,60 +299,71 @@ export default {
<hr style="margin-bottom:15px"> <hr style="margin-bottom:15px">
<div>这里指定域名的超时时间<span class="form-help">域名配置可使用通配符或正则</span></div> <div>这里指定域名的超时时间<span class="form-help">域名配置可使用通配符或正则</span></div>
<VueJsonEditor <VueJsonEditor
ref="editor" v-model="config.server.setting.timeoutMapping" style="flex-grow:1;min-height:300px;margin-top:10px" mode="code" 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" :show-btns="false" :expanded-on-start="true"
/> />
</div> </div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="4" tab="域名白名单"> <a-tab-pane key="4" tab="域名白名单">
<a-row style="margin-top:10px"> <div v-if="activeTabKey === '4'">
<a-col span="21"> <a-row style="margin-top:10px">
<div>这里配置的域名不会通过代理</div> <a-col span="21">
</a-col> <div>这里配置的域名不会通过代理</div>
<a-col span="3"> </a-col>
<a-button style="margin-left:8px" type="primary" icon="plus" @click="addWhiteList()" /> <a-col span="3">
</a-col> <a-button style="margin-left:8px" type="primary" icon="plus" @click="addWhiteList()" />
</a-row> </a-col>
<a-row v-for="(item, index) of whiteList" :key="index" :gutter="10" style="margin-top: 5px"> </a-row>
<a-col :span="21"> <a-row v-for="(item, index) of whiteList" :key="index" :gutter="10" style="margin-top: 5px">
<a-input v-model="item.key" :disabled="item.value === false" /> <a-col :span="16">
</a-col> <a-input v-model="item.key" />
<a-col :span="3"> </a-col>
<a-button v-if="item.value !== false" type="danger" icon="minus" @click="deleteWhiteList(item, index)" /> <a-col :span="5">
</a-col> <a-select v-model="item.value" style="width:100%">
</a-row> <a-select-option v-for="(item2) of whiteListOptions" :key="item2.value" :value="item2.value">
{{ item2.label }}
</a-select-option>
</a-select>
</a-col>
<a-col :span="3">
<a-button type="danger" icon="minus" @click="deleteWhiteList(item, index)" />
</a-col>
</a-row>
</div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="5" tab="自动兼容程序"> <a-tab-pane key="5" tab="自动兼容程序">
<div style="height:100%;display:flex;flex-direction:column"> <div v-if="activeTabKey === '5'" style="height:100%;display:flex;flex-direction:column">
<div> <div>
说明<code>自动兼容程序</code>会自动根据错误信息进行兼容性调整并将兼容设置保存在 <code>~/.dev-sidecar/automaticCompatibleConfig.json</code> 说明<code>自动兼容程序</code>会自动根据错误信息进行兼容性调整并将兼容设置保存在 <code>~/.dev-sidecar/automaticCompatibleConfig.json</code>
</div> </div>
<VueJsonEditor <VueJsonEditor
ref="editor" v-model="config.server.compatible" style="flex-grow:1;min-height:300px;margin-top:10px;" mode="code" v-model="config.server.compatible" style="flex-grow:1;min-height:300px;margin-top:10px;" mode="code"
:show-btns="false" :expanded-on-start="true" :show-btns="false" :expanded-on-start="true"
/> />
</div> </div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="6" tab="IP预设置"> <a-tab-pane key="6" tab="IP预设置">
<div style="height:100%;display:flex;flex-direction:column"> <div v-if="activeTabKey === '6'" style="height:100%;display:flex;flex-direction:column">
<div> <div>
提示<code>IP预设置</code>功能优先级高于 <code>DNS设置</code> 提示<code>IP预设置</code>功能优先级高于 <code>DNS设置</code>
<span class="form-help">域名配置可使用通配符或正则</span> <span class="form-help">域名配置可使用通配符或正则</span>
</div> </div>
<VueJsonEditor <VueJsonEditor
ref="editor" v-model="config.server.preSetIpList" style="flex-grow:1;min-height:300px;margin-top:10px;" mode="code" v-model="config.server.preSetIpList" style="flex-grow:1;min-height:300px;margin-top:10px;" mode="code"
:show-btns="false" :expanded-on-start="true" :show-btns="false" :expanded-on-start="true"
/> />
</div> </div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="7" tab="DNS服务管理"> <a-tab-pane key="7" tab="DNS服务管理">
<VueJsonEditor <div v-if="activeTabKey === '7'" style="height:100%">
ref="editor" v-model="config.server.dns.providers" style="height:100%" mode="code" <VueJsonEditor
:show-btns="false" :expanded-on-start="true" v-model="config.server.dns.providers" style="height:100%" mode="code"
/> :show-btns="false" :expanded-on-start="true"
/>
</div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="8" tab="DNS设置"> <a-tab-pane key="8" tab="DNS设置">
<div> <div v-if="activeTabKey === '8'">
<a-row style="margin-top:10px"> <a-row style="margin-top:10px">
<a-col span="21"> <a-col span="21">
<div>这里配置哪些域名需要通过国外DNS服务器获取IP进行访问</div> <div>这里配置哪些域名需要通过国外DNS服务器获取IP进行访问</div>
@ -338,7 +374,7 @@ export default {
</a-row> </a-row>
<a-row v-for="(item, index) of dnsMappings" :key="index" :gutter="10" style="margin-top: 5px"> <a-row v-for="(item, index) of dnsMappings" :key="index" :gutter="10" style="margin-top: 5px">
<a-col :span="15"> <a-col :span="15">
<a-input v-model="item.key" :disabled="item.value === false" /> <a-input v-model="item.key" />
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-select v-model="item.value" :disabled="item.value === false" style="width: 100%"> <a-select v-model="item.value" :disabled="item.value === false" style="width: 100%">
@ -348,14 +384,13 @@ export default {
</a-select> </a-select>
</a-col> </a-col>
<a-col :span="3"> <a-col :span="3">
<a-button v-if="item.value !== false" type="danger" icon="minus" @click="deleteDnsMapping(item, index)" /> <a-button 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-col>
</a-row> </a-row>
</div> </div>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="9" tab="IP测速"> <a-tab-pane key="9" tab="IP测速">
<div class="ip-tester" style="padding-right: 10px"> <div v-if="activeTabKey === '9'" class="ip-tester" style="padding-right: 10px">
<a-alert type="info" message="对从DNS获取到的IP进行测速使用速度最快的IP进行访问注意对使用了增强功能的域名没啥用" /> <a-alert type="info" message="对从DNS获取到的IP进行测速使用速度最快的IP进行访问注意对使用了增强功能的域名没啥用" />
<a-form-item label="开启DNS测速" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-item label="开启DNS测速" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="getSpeedTestConfig().enabled"> <a-checkbox v-model="getSpeedTestConfig().enabled">
@ -385,10 +420,7 @@ export default {
<a-button style="margin-left:10px" type="primary" icon="plus" @click="addSpeedHostname()" /> <a-button style="margin-left:10px" type="primary" icon="plus" @click="addSpeedHostname()" />
</a-col> </a-col>
</a-row> </a-row>
<a-row <a-row v-for="(item, index) of getSpeedTestConfig().hostnameList" :key="index" :gutter="10" style="margin-top: 5px">
v-for="(item, index) of getSpeedTestConfig().hostnameList" :key="index" :gutter="10"
style="margin-top: 5px"
>
<a-col :span="21"> <a-col :span="21">
<a-input v-model="getSpeedTestConfig().hostnameList[index]" /> <a-input v-model="getSpeedTestConfig().hostnameList[index]" />
</a-col> </a-col>
@ -471,5 +503,8 @@ export default {
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
} }
.ant-input-group-addon:first-child {
width: 50px;
}
} }
</style> </style>

View File

@ -338,9 +338,9 @@ export default {
<ds-container> <ds-container>
<template slot="header"> <template slot="header">
设置 设置
<span> </template>
<a-button class="md-mr-10" icon="profile" @click="openLog()"></a-button> <template slot="header-right">
</span> <a-button class="md-mr-10" icon="profile" @click="openLog()"></a-button>
</template> </template>
<div v-if="config"> <div v-if="config">

View File

@ -17,7 +17,7 @@ $dark-input: #777; //输入框:背景色
.ds-container, .ds-container,
.ds-container .container-header, .ds-container .container-header,
.ant-layout-footer { .ant-layout-footer {
background: $dark-bg; background-color: $dark-bg;
color: $dark-text; color: $dark-text;
} }
div, div,
@ -36,7 +36,7 @@ $dark-input: #777; //输入框:背景色
/* 高亮块:背景色和字体颜色 */ /* 高亮块:背景色和字体颜色 */
/* 警告类型 */ /* 警告类型 */
.ant-alert-warning { .ant-alert-warning {
background: $dark-bg-highlight; background-color: $dark-bg-highlight;
border-color: $dark-bg-highlight; border-color: $dark-bg-highlight;
color: $dark-text; color: $dark-text;
/* 关闭图标颜色 */ /* 关闭图标颜色 */
@ -46,7 +46,7 @@ $dark-input: #777; //输入框:背景色
} }
/* 消息类型 */ /* 消息类型 */
.ant-alert-info { .ant-alert-info {
background: $dark-bg-highlight; background-color: $dark-bg-highlight;
border-color: $dark-bg-highlight; border-color: $dark-bg-highlight;
color: $dark-text; color: $dark-text;
} }
@ -66,7 +66,7 @@ $dark-input: #777; //输入框:背景色
background-color: #666; background-color: #666;
} }
.ant-divider { .ant-divider {
background: $dark-bd; background-color: $dark-bd;
} }
.help-list .title1 { .help-list .title1 {
@ -76,7 +76,7 @@ $dark-input: #777; //输入框:背景色
/* 左侧 */ /* 左侧 */
/** 背景色 **/ /** 背景色 **/
.ant-layout-sider { .ant-layout-sider {
background: $dark-bg; background-color: $dark-bg;
} }
/** Logo **/ /** Logo **/
.logo { .logo {
@ -84,14 +84,14 @@ $dark-input: #777; //输入框:背景色
} }
/** 菜单 **/ /** 菜单 **/
.ant-menu { .ant-menu {
background: $dark-bg; background-color: $dark-bg;
color: $dark-text; color: $dark-text;
} }
/* 菜单选中时,或鼠标移到菜单上时的样式 */ /* 菜单选中时,或鼠标移到菜单上时的样式 */
.ant-menu-item:hover, .ant-menu-item:hover,
.ant-menu-submenu .ant-menu-submenu-title:hover, .ant-menu-submenu .ant-menu-submenu-title:hover,
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected { .ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
background: $dark-bg-highlight; background-color: $dark-bg-highlight;
color: #1890ff; color: #1890ff;
span { span {
color: #1890ff; color: #1890ff;
@ -104,7 +104,7 @@ $dark-input: #777; //输入框:背景色
.ant-input-number, .ant-input-number,
.ant-select-selection, .ant-select-selection,
.ant-input-group-addon { .ant-input-group-addon {
background: $dark-input; background-color: $dark-input;
border-color: #aaa; border-color: #aaa;
color: $dark-text; color: $dark-text;
&:hover, &:hover,
@ -115,7 +115,7 @@ $dark-input: #777; //输入框:背景色
/* 卡片消息IP测速 */ /* 卡片消息IP测速 */
.ant-card { .ant-card {
background: $dark-input; background-color: $dark-input;
border-color: $dark-input; border-color: $dark-input;
.ant-card-head { .ant-card-head {
border-bottom-color: #929292; border-bottom-color: #929292;
@ -124,26 +124,26 @@ $dark-input: #777; //输入框:背景色
/* 标签:未启用 */ /* 标签:未启用 */
.ant-tag-red { .ant-tag-red {
background: #4f4749; background-color: #4f4749;
border-color: #4f4749; border-color: #4f4749;
color: #bf8285; color: #bf8285;
} }
/* 标签:已启用 */ /* 标签:已启用 */
.ant-tag-green { .ant-tag-green {
background: #505f5f; background-color: #505f5f;
border-color: #505f5f; border-color: #505f5f;
color: #90cb9f; color: #90cb9f;
} }
/* 标签:警告 */ /* 标签:警告 */
.ant-tag-orange { .ant-tag-orange {
background: #5a5750; background-color: #5a5750;
border-color: #5a5750; border-color: #5a5750;
color: #cfa572; color: #cfa572;
} }
/* 按钮 */ /* 按钮 */
.ant-btn:not(.ant-btn-danger, .ant-btn-primary) { .ant-btn:not(.ant-btn-danger, .ant-btn-primary) {
background: $dark-btn; background-color: $dark-btn;
border-color: $dark-btn; border-color: $dark-btn;
color: $dark-text; color: $dark-text;
&:hover { &:hover {
@ -153,7 +153,7 @@ $dark-input: #777; //输入框:背景色
/* 单选框:开关式 */ /* 单选框:开关式 */
.ant-switch:not(.ant-switch-checked) { .ant-switch:not(.ant-switch-checked) {
background: $dark-btn; background-color: $dark-btn;
border-color: $dark-btn; border-color: $dark-btn;
&:hover { &:hover {
opacity: 0.8; opacity: 0.8;
@ -161,7 +161,7 @@ $dark-input: #777; //输入框:背景色
} }
/* 单选框:按钮式 */ /* 单选框:按钮式 */
.ant-radio-button-wrapper { .ant-radio-button-wrapper {
background: $dark-btn; background-color: $dark-btn;
border-color: $dark-btn; border-color: $dark-btn;
color: $dark-text; color: $dark-text;
&:hover { &:hover {
@ -173,24 +173,24 @@ $dark-input: #777; //输入框:背景色
.jsoneditor-vue { .jsoneditor-vue {
/*整个编辑框:背景色和边框*/ /*整个编辑框:背景色和边框*/
div.jsoneditor { div.jsoneditor {
background: $dark-bg-highlight; background-color: $dark-bg-highlight;
border: none; border: none;
} }
/* 头部菜单栏:边框 */ /* 头部菜单栏:边框 */
div.jsoneditor-menu { div.jsoneditor-menu {
background: $dark-bg-highlight; background-color: $dark-bg-highlight;
border-color: $dark-bg-highlight; border-color: $dark-bg-highlight;
} }
/* 内容区域左边:行号 */ /* 内容区域左边:行号 */
.ace_gutter { .ace_gutter {
background: #444; background-color: #444;
.ace_gutter-cell { .ace_gutter-cell {
color: #aaa; color: #aaa;
} }
} }
/* 内容区域右边JSON内容 */ /* 内容区域右边JSON内容 */
.ace_scroller { .ace_scroller {
background: #555; background-color: #555;
} }
/* key的颜色 */ /* key的颜色 */
.ace_variable, .ace_variable,
@ -215,12 +215,12 @@ $dark-input: #777; //输入框:背景色
/* 当前行高亮样式 */ /* 当前行高亮样式 */
.ace_gutter-active-line, .ace_gutter-active-line,
.ace_marker-layer .ace_active-line { .ace_marker-layer .ace_active-line {
background: #838774; background-color: #838774;
} }
/* 选中行高亮样式 */ /* 选中行高亮样式 */
.ace-jsoneditor { .ace-jsoneditor {
.ace_marker-layer .ace_selection { .ace_marker-layer .ace_selection {
background: #8b2929; /* 同时应用于当前选中的搜索结果项的背景色,建议与搜索结果边框颜色保持一致 */ background-color: #8b2929; /* 同时应用于当前选中的搜索结果项的背景色,建议与搜索结果边框颜色保持一致 */
} }
/* 光标颜色 */ /* 光标颜色 */

View File

@ -17,11 +17,10 @@ module.exports = {
'Cross-Origin-Resource-Policy': interceptOpt.optionsCrossPolicy || 'cross-origin', 'Cross-Origin-Resource-Policy': interceptOpt.optionsCrossPolicy || 'cross-origin',
} }
res.setHeader('DS-AfterOPTIONSHeaders-Interceptor', '1')
// 替换响应头 // 替换响应头
if (responseReplaceApi.replaceResponseHeaders({ ...headers }, res, proxyRes)) { if (responseReplaceApi.replaceResponseHeaders({ ...headers }, res, proxyRes)) {
log.info('AfterOPTIONSHeaders intercept:', JSON.stringify(headers)) log.info('AfterOPTIONSHeaders intercept:', JSON.stringify(headers))
res.setHeader('DS-AfterOPTIONSHeaders-Interceptor', '1')
} else { } else {
res.setHeader('DS-AfterOPTIONSHeaders-Interceptor', '0') res.setHeader('DS-AfterOPTIONSHeaders-Interceptor', '0')
} }

View File

@ -108,7 +108,7 @@ module.exports = (serverConfig) => {
const hostname = req.url.split(':')[0] const hostname = req.url.split(':')[0]
// 配置了白名单的域名,将跳过代理 // 配置了白名单的域名,将跳过代理
const inWhiteList = matchUtil.matchHostname(whiteList, hostname, 'in whiteList') != null const inWhiteList = !!matchUtil.matchHostname(whiteList, hostname, 'in whiteList')
if (inWhiteList) { if (inWhiteList) {
log.info(`为白名单域名,不拦截: ${hostname}, headers:`, jsonApi.stringify2(req.headers)) log.info(`为白名单域名,不拦截: ${hostname}, headers:`, jsonApi.stringify2(req.headers))
return false // 不拦截 return false // 不拦截