/* 触发器 手动触发 */
const onRun = async () => {
showUI()
}
/* 触发器 APP就绪后 */
const onReady = async () => {
const appStore = Plugins.useAppStore()
appStore.addCustomActions('profiles_header', {
id: Plugin.id,
component: 'Button',
componentProps: {
type: 'link',
onClick: showUI
},
componentSlots: {
default: '快速配置向导'
}
})
}
const showUI = () => {
const { h, ref, watch, computed, resolveComponent } = Vue
const currentStep = ref(0)
const isDirectIPv6Enabled = ref(false)
const isProxyIPv6Enabled = ref(false)
const isAllowLanEnabled = ref(false)
const lanPort = ref()
const isTUNEnabled = ref(false)
const isFakeIPEnabled = ref(false)
const isBanQUICEnabled = ref(true)
const name = ref(Plugins.sampleID())
const subsMap = ref({})
const subsRef = ref([])
const isSupportIPv6 = ref()
watch(currentStep, async (step) => {
if (step === 1) {
isSupportIPv6.value = undefined
isSupportIPv6.value = await checkIPv6Support()
}
})
const component = {
template: `
欢迎使用快速配置向导
此向导可帮你生成一份不会出错的配置。开始前请:
- 关闭所有代理软件(避免影响IPv6判断)
- 开启路由器及本机的IPv6协议栈(避免影响IPv6判断)
- 如果你禁用过Windows的智能多宿主DNS解析,请还原(避免影响TUN模式)
直连网站是否需要IPv6?
正在检测你的网络环境...
提示:你的网络环境已支持IPv6,推荐开启!访问国内网站能获得更好的效果!
提示:你的网络环境不支持IPv6,建议关闭!强行开启会导致部分网站无法访问!
代理网站是否需要IPv6?
如果你是自建用户,且节点支持IPv6,请选择需要;如果你是机场用户,节点通常不支持IPv6,请选择不需要。
是否需要开启TUN模式?
开启后,会新建一张虚拟网卡,所有软件的流量将通过核心进行转发
注意事项
- Windows下启用TUN模式需要管理员权限,Linux/MacOS下需要到设置-内核页进行手动授权(每次更新核心后均需要重新手动授权)。
- MacOS下需要前往系统网络设置,将系统DNS修改为公网IP,例如8.8.8.8,以便核心劫持DNS请求。
- 如果遇到网络不通,请尝试更换不同的TUN堆栈模式。
是否需要开启Fake-IP模式?
开启后,部分网站的DNS查询将返回虚假的IP。(通常对需要代理的网站返回fake-ip)
是否需要禁用QUIC?
部分网站会使用QUIC协议,这通常会影响访问代理网站的速度
现在,为此配置引用一个或多个订阅?
点击下方+号,左侧填写订阅名称,右侧填写订阅链接。或者,稍后再说~
哇哦!你已经添加了一些订阅,勾选它们直接引用!
如果你打算引用多个订阅,这些订阅中可能包含相同名称的节点,造成核心启动失败。但你可以在插件中心找到解决方案。
`,
setup() {
const subscribeStore = Plugins.useSubscribesStore()
const subs = computed(() => subscribeStore.subscribes.map((v) => ({ name: v.name, id: v.id })))
return {
currentStep,
isSupportIPv6,
isDirectIPv6Enabled,
isProxyIPv6Enabled,
isAllowLanEnabled,
lanPort,
isTUNEnabled,
isFakeIPEnabled,
isBanQUICEnabled,
subsMap,
subsRef,
subs,
name,
toggleSubRef(sub) {
const idx = subsRef.value.indexOf(sub)
if (idx === -1) {
subsRef.value.push(sub)
} else {
subsRef.value.splice(idx, 1)
}
}
}
}
}
const modal = Plugins.modal(
{
title: Plugin.name,
width: '90',
height: '90',
maskClosable: true,
submitText: '完成',
afterClose() {
modal.destroy()
},
async onOk() {
const profilesStore = Plugins.useProfilesStore()
const subscribeStore = Plugins.useSubscribesStore()
// 1、导入订阅
const subIds = []
for (const [name, url] of Object.entries(subsMap.value)) {
const sub = subscribeStore.getSubscribeTemplate(name, { url })
await subscribeStore.addSubscribe(sub)
await Plugins.sleep(1000)
subIds.push({ name, id: sub.id })
}
// 2、导入配置
const profile = profilesStore.getProfileTemplate(name.value)
;[...subIds, ...subsRef.value].forEach(({ name, id }) => {
if (Plugins.APP_TITLE.includes('SingBox')) {
profile.outbounds[0].outbounds.push({ id: id, tag: name, type: 'Subscription' })
profile.outbounds[1].outbounds.push({ id: id, tag: name, type: 'Subscription' })
} else if (Plugins.APP_TITLE.includes('Clash')) {
profile.proxyGroupsConfig[0].use.push(id)
profile.proxyGroupsConfig[1].use.push(id)
}
})
// 3、个性化配置
personalizeProfile(profile, {
isDirectIPv6Enabled: isDirectIPv6Enabled.value,
isProxyIPv6Enabled: isProxyIPv6Enabled.value,
isAllowLanEnabled: isAllowLanEnabled.value,
lanPort: lanPort.value,
isTUNEnabled: isTUNEnabled.value,
isFakeIPEnabled: isFakeIPEnabled.value,
isBanQUICEnabled: isBanQUICEnabled.value
})
await profilesStore.addProfile(profile)
Plugins.message.success('完事~')
}
},
{
default: () => h(component),
action: () =>
h('div', { class: 'mr-auto' }, [
h(
resolveComponent('Button'),
{
type: 'text',
disabled: currentStep.value < 1,
onClick: () => (currentStep.value -= 1)
},
() => '上一步'
),
h(
resolveComponent('Button'),
{
type: 'text',
disabled: currentStep.value >= 7,
onClick: () => (currentStep.value += 1)
},
() => '下一步'
)
])
}
)
modal.open()
}
const getRandomUA = () => {
const userAgents = [
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2',
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0',
'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10'
]
return userAgents[Math.floor(Math.random() * userAgents.length)]
}
const checkIPv6Support = async () => {
try {
const { status } = await Plugins.HttpGet('https://ipv6.lookup.test-ipv6.com/ip/', {
'User-Agent': getRandomUA()
})
return status === 200
} catch (error) {
console.log(`[${Plugin.name}]`, '检测IPv6失败', error)
return false
}
}
const personalizeProfile = async (profile, options) => {
if (Plugins.APP_TITLE.includes('SingBox')) {
if (options.isDirectIPv6Enabled) {
profile.dns.rules[0].strategy = 'prefer_ipv6'
profile.dns.rules[3].strategy = 'prefer_ipv6'
} else {
profile.dns.rules[0].strategy = 'ipv4_only'
profile.dns.rules[3].strategy = 'ipv4_only'
profile.inbounds[1].tun.address.pop()
}
if (options.isProxyIPv6Enabled) {
profile.dns.strategy = 'prefer_ipv6'
profile.dns.rules[1].strategy = 'prefer_ipv6'
profile.dns.rules[4].strategy = 'prefer_ipv6'
profile.dns.rules[5].strategy = 'prefer_ipv6'
} else {
profile.dns.strategy = 'ipv4_only'
profile.dns.rules[1].strategy = 'ipv4_only'
profile.dns.rules[4].strategy = 'ipv4_only'
profile.dns.rules[5].strategy = 'ipv4_only'
}
profile.inbounds[0].mixed.listen.listen = options.isAllowLanEnabled ? '0.0.0.0' : '127.0.0.1'
if (options.lanPort) {
profile.inbounds[0].mixed.listen.listen_port = Number(options.lanPort)
}
profile.inbounds[1].enable = options.isTUNEnabled
profile.dns.rules[4].enable = options.isFakeIPEnabled
profile.route.rules[6].enable = options.isBanQUICEnabled
} else if (Plugins.APP_TITLE.includes('Clash')) {
profile.generalConfig.ipv6 = options.isDirectIPv6Enabled || options.isProxyIPv6Enabled
profile.dnsConfig.ipv6 = options.isDirectIPv6Enabled || options.isProxyIPv6Enabled
if (!options.isDirectIPv6Enabled) {
profile.dnsConfig['nameserver-policy']['rule-set:GEOSITE-CN'] += '&disable-ipv6=true'
}
if (!options.isProxyIPv6Enabled) {
profile.dnsConfig['nameserver-policy']['rule-set:geolocation-!cn'] += '&disable-ipv6=true'
}
profile.generalConfig['allow-lan'] = options.isAllowLanEnabled
if (options.lanPort) {
profile.generalConfig['mixed-port'] = Number(options.lanPort)
}
profile.tunConfig.enable = options.isTUNEnabled
if (options.isFakeIPEnabled) {
profile.dnsConfig['enhanced-mode'] = 'fake-ip'
profile.dnsConfig.nameserver = ['https://223.5.5.5/dns-query#' + profile.proxyGroupsConfig[2].name]
profile.dnsConfig['fake-ip-filter'].push('rule-set:GEOSITE-CN')
}
profile.rulesConfig[1].enable = options.isBanQUICEnabled
}
}