all adjustments
This commit is contained in:
+84
-203
@@ -2,10 +2,7 @@
|
||||
<InboundVue
|
||||
v-model="modal.visible"
|
||||
:visible="modal.visible"
|
||||
:index="modal.index"
|
||||
:stats="modal.stats"
|
||||
:data="modal.data"
|
||||
:cData="modal.cData"
|
||||
:id="modal.id"
|
||||
:inTags="inTags"
|
||||
:outTags="outTags"
|
||||
:tlsConfigs="tlsConfigs"
|
||||
@@ -21,7 +18,7 @@
|
||||
/>
|
||||
<v-row>
|
||||
<v-col cols="12" justify="center" align="center">
|
||||
<v-btn color="primary" @click="showModal(-1)">{{ $t('actions.add') }}</v-btn>
|
||||
<v-btn color="primary" @click="showModal(0)">{{ $t('actions.add') }}</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
@@ -48,22 +45,25 @@
|
||||
<v-row>
|
||||
<v-col>{{ $t('objects.tls') }}</v-col>
|
||||
<v-col dir="ltr">
|
||||
{{ Object.hasOwn(item,'tls') ? $t(item.tls?.enabled ? 'enable' : 'disable') : '-' }}
|
||||
{{ item.tls_id > 0 ? $t('enable') : $t('disable') }}
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col>{{ $t('pages.clients') }}</v-col>
|
||||
<v-col dir="ltr">
|
||||
<v-tooltip activator="parent" dir="ltr" location="bottom" v-if="Object.hasOwn(item,'users')">
|
||||
<span v-for="u in findInbounsUsers(item)">{{ u }}<br /></span>
|
||||
</v-tooltip>
|
||||
{{ Array.isArray(item.users) ? item.users.length : '-' }}
|
||||
<template v-if="inboundWithUsers.includes(item.tag)">
|
||||
<v-tooltip activator="parent" dir="ltr" location="bottom" v-if="findInboundUsers(item.tag).length > 0">
|
||||
<span v-for="u in findInboundUsers(item.tag)">{{ u }}<br /></span>
|
||||
</v-tooltip>
|
||||
{{ findInboundUsers(item.tag).length }}
|
||||
</template>
|
||||
<template v-else>-</template>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col>{{ $t('online') }}</v-col>
|
||||
<v-col dir="ltr">
|
||||
<template v-if="onlines[index]">
|
||||
<template v-if="onlines.includes(item.tag)">
|
||||
<v-chip density="comfortable" size="small" color="success" variant="flat">{{ $t('online') }}</v-chip>
|
||||
</template>
|
||||
<template v-else>-</template>
|
||||
@@ -72,7 +72,7 @@
|
||||
</v-card-text>
|
||||
<v-divider></v-divider>
|
||||
<v-card-actions style="padding: 0;">
|
||||
<v-btn icon="mdi-file-edit" @click="showModal(index)">
|
||||
<v-btn icon="mdi-file-edit" @click="showModal(item.id)">
|
||||
<v-icon />
|
||||
<v-tooltip activator="parent" location="top" :text="$t('actions.edit')"></v-tooltip>
|
||||
</v-btn>
|
||||
@@ -89,12 +89,12 @@
|
||||
<v-divider></v-divider>
|
||||
<v-card-text>{{ $t('confirm') }}</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn color="error" variant="outlined" @click="delInbound(index)">{{ $t('yes') }}</v-btn>
|
||||
<v-btn color="error" variant="outlined" @click="delInbound(item.id)">{{ $t('yes') }}</v-btn>
|
||||
<v-btn color="success" variant="outlined" @click="delOverlay[index] = false">{{ $t('no') }}</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-overlay>
|
||||
<v-btn icon="mdi-chart-line" @click="showStats(item.tag)" v-if="v2rayStats.inbounds.includes(item.tag)">
|
||||
<v-btn icon="mdi-chart-line" @click="showStats(item.tag)">
|
||||
<v-icon />
|
||||
<v-tooltip activator="parent" location="top" :text="$t('stats.graphTitle')"></v-tooltip>
|
||||
</v-btn>
|
||||
@@ -108,9 +108,9 @@
|
||||
import Data from '@/store/modules/data'
|
||||
import InboundVue from '@/layouts/modals/Inbound.vue'
|
||||
import Stats from '@/layouts/modals/Stats.vue'
|
||||
import { Config, V2rayApiStats } from '@/types/config'
|
||||
import { computed, ref } from 'vue'
|
||||
import { InTypes, Inbound, InboundWithUser, ShadowTLS, VLESS } from '@/types/inbounds'
|
||||
import { Config } from '@/types/config'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { Inbound, inboundWithUsers } from '@/types/inbounds'
|
||||
import { Client } from '@/types/clients'
|
||||
import { Link, LinkUtil } from '@/plugins/link'
|
||||
import { i18n } from '@/locales'
|
||||
@@ -122,17 +122,13 @@ const appConfig = computed((): Config => {
|
||||
})
|
||||
|
||||
const inbounds = computed((): Inbound[] => {
|
||||
return <Inbound[]> appConfig.value.inbounds
|
||||
return <Inbound[]> Data().inbounds
|
||||
})
|
||||
|
||||
const tlsConfigs = computed((): any[] => {
|
||||
return <any[]> Data().tlsConfigs
|
||||
})
|
||||
|
||||
const inData = computed((): any[] => {
|
||||
return <any[]> Data().inData
|
||||
})
|
||||
|
||||
const inTags = computed((): string[] => {
|
||||
return inbounds.value?.map(i => i.tag)
|
||||
})
|
||||
@@ -149,216 +145,101 @@ const onlines = computed(() => {
|
||||
return Data().onlines.inbound ? inbounds.value.map(i => Data().onlines.inbound.includes(i.tag)) : []
|
||||
})
|
||||
|
||||
const v2rayStats = computed((): V2rayApiStats => {
|
||||
return <V2rayApiStats> appConfig.value.experimental?.v2ray_api.stats
|
||||
})
|
||||
|
||||
const modal = ref({
|
||||
visible: false,
|
||||
index: -1,
|
||||
data: "",
|
||||
cData: "",
|
||||
stats: false,
|
||||
id: 0,
|
||||
})
|
||||
|
||||
let delOverlay = ref(new Array<boolean>)
|
||||
|
||||
const showModal = (index: number) => {
|
||||
modal.value.index = index
|
||||
if (index == -1){
|
||||
modal.value.data = ''
|
||||
modal.value.cData = ''
|
||||
modal.value.stats = false
|
||||
} else {
|
||||
modal.value.data = JSON.stringify(inbounds.value[index])
|
||||
modal.value.stats = v2rayStats.value.inbounds.includes(inbounds.value[index].tag)
|
||||
const inDataIndex = inData.value.findIndex(d => d.tag == inbounds.value[index].tag)
|
||||
modal.value.cData = inDataIndex == -1 ? '' : JSON.stringify(inData.value[inDataIndex])
|
||||
}
|
||||
const showModal = (id: number) => {
|
||||
modal.value.id = id
|
||||
modal.value.visible = true
|
||||
}
|
||||
const closeModal = () => {
|
||||
modal.value.visible = false
|
||||
}
|
||||
const saveModal = (data:Inbound, stats: boolean, tls_id: number, cData: any) => {
|
||||
const saveModal = async (data:Inbound) => {
|
||||
// Check duplicate tag
|
||||
const oldTag = modal.value.index != -1 ? inbounds.value[modal.value.index].tag : null
|
||||
if (data.tag != oldTag && inTags.value.includes(data.tag)) {
|
||||
const oldInbound = modal.value.id > 0 ? inbounds.value.findLast(i => i.id == modal.value.id) : null
|
||||
if (data.tag != oldInbound?.tag && inTags.value.includes(data.tag)) {
|
||||
push.error({
|
||||
message: i18n.global.t('error.dplData') + ": " + i18n.global.t('objects.tag')
|
||||
})
|
||||
return
|
||||
}
|
||||
if (cData.id != -1) {
|
||||
cData.tag = data.tag
|
||||
fillData(cData.outJson, data,tls_id>0 ? tlsConfigs.value.findLast(t => t.id == tls_id).client : {})
|
||||
|
||||
// Fill outjson
|
||||
if (data.out_json){
|
||||
fillData(data, data.tls_id > 0 ? tlsConfigs?.value.findLast((t:any) => t.id == data.tls_id) : null)
|
||||
}
|
||||
|
||||
let userLinkDiff = []
|
||||
// Update links
|
||||
if (data.id > 0 && oldInbound != null) {
|
||||
userLinkDiff = updateLinks(data,oldInbound)
|
||||
}
|
||||
|
||||
// New or Edit
|
||||
if (modal.value.index == -1) {
|
||||
inbounds.value.push(data)
|
||||
if (stats && data.tag.length>0) {
|
||||
v2rayStats.value.inbounds.push(data.tag)
|
||||
}
|
||||
if (cData.id != -1){
|
||||
inData.value.push(cData)
|
||||
}
|
||||
} else {
|
||||
const oldTag = inbounds.value[modal.value.index].tag
|
||||
const sIndex = v2rayStats.value.inbounds.findIndex(i => i == data.tag) // Find if new tag exists
|
||||
|
||||
// Update tls preset
|
||||
const oldTlsConfigIndex = tlsConfigs?.value.findIndex(t => t.inbounds?.includes(oldTag))
|
||||
if (oldTlsConfigIndex != -1){
|
||||
tlsConfigs.value[oldTlsConfigIndex].inbounds = tlsConfigs?.value[oldTlsConfigIndex].inbounds.filter((i:string) => i != oldTag)
|
||||
}
|
||||
|
||||
if (oldTag != data.tag) {
|
||||
v2rayStats.value.inbounds = v2rayStats.value.inbounds.filter(item => item != oldTag)
|
||||
changeClientInboundsTag(oldTag,data.tag)
|
||||
}
|
||||
|
||||
if (stats) {
|
||||
// Add if dos not exist
|
||||
if (data.tag.length>0 && sIndex == -1) v2rayStats.value.inbounds.push(data.tag)
|
||||
} else {
|
||||
// Delete if exists
|
||||
if (sIndex != -1) v2rayStats.value.inbounds.splice(sIndex,1)
|
||||
}
|
||||
|
||||
inbounds.value[modal.value.index] = data
|
||||
const inDataIndex = inData.value.findIndex(indata => indata.tag == oldTag)
|
||||
if (cData.id != -1) {
|
||||
if (inDataIndex == -1){
|
||||
inData.value.push(cData)
|
||||
} else {
|
||||
inData.value[inDataIndex] = cData
|
||||
}
|
||||
} else if (inDataIndex != -1) {
|
||||
Data().delInData(inData.value[inDataIndex].id)
|
||||
inData.value.splice(inDataIndex,1)
|
||||
}
|
||||
}
|
||||
// Update tls preset
|
||||
if (tls_id>0) {
|
||||
tlsConfigs.value.findLast(t => t.id == tls_id).inbounds.push(data.tag)
|
||||
tlsConfigs.value.sort()
|
||||
}
|
||||
|
||||
if (Object.hasOwn(data,'users')) {
|
||||
// Set users
|
||||
data = buildInboundsUsers(data)
|
||||
// Update links
|
||||
updateLinks(data)
|
||||
}
|
||||
modal.value.visible = false
|
||||
// save data
|
||||
const success = await Data().save("inbounds", modal.value.id == 0 ? "new" : "edit", data, userLinkDiff)
|
||||
if (success) modal.value.visible = false
|
||||
}
|
||||
const updateLinks = (i: any) => {
|
||||
if(i.users){
|
||||
const uClients = clients.value.filter(c => c.inbounds.includes(i.tag))
|
||||
uClients.forEach((u:Client) => {
|
||||
const clientInbounds = <Inbound[]>inbounds.value.filter(inb => u.inbounds.includes(inb.tag))
|
||||
const newLinks = <Link[]>[]
|
||||
clientInbounds.forEach(i =>{
|
||||
const tlsClient = tlsConfigs?.value.findLast((t:any) => t.inbounds.includes(i.tag))?.client?? {}
|
||||
const cData = <any>Data().inData?.findLast((d:any) => d.tag == i.tag)
|
||||
const addrs = cData ? <any[]>cData.addrs : []
|
||||
const uris = LinkUtil.linkGenerator(u,i, tlsClient, addrs)
|
||||
if (uris.length>0){
|
||||
uris.forEach(uri => {
|
||||
newLinks.push(<Link>{ type: 'local', remark: i.tag, uri: uri })
|
||||
})
|
||||
}
|
||||
})
|
||||
let links = u.links && u.links.length>0? u.links : <Link[]>[]
|
||||
links = [...newLinks, ...links.filter(l => l.type != 'local')]
|
||||
const updateLinks = (i: Inbound, o: Inbound): any[] => {
|
||||
let diff = <any[]>[]
|
||||
const uClients = clients.value.filter(c => c.inbounds.includes(i.id))
|
||||
if (uClients.length == 0) return diff
|
||||
|
||||
u.links = links
|
||||
if (inboundWithUsers.includes(o.type) && !inboundWithUsers.includes(i.type)){
|
||||
// Remove old inbound links if new type does not support users
|
||||
uClients.forEach((u:Client) => {
|
||||
u.inbounds = u.inbounds.filter(i => i != o.id)
|
||||
const otherLocalLinks = u.links.filter(l => l.type == 'local' && l.remark != o.tag)
|
||||
let links = u.links && u.links.length>0? u.links : <Link[]>[]
|
||||
links = [...otherLocalLinks, ...links.filter(l => l.type != 'local')]
|
||||
|
||||
diff.push({ id: u.id, links: links, inbounds: u.inbounds })
|
||||
})
|
||||
} else if(inboundWithUsers.includes(i.type)){
|
||||
// Add new inbound links if new type supports users
|
||||
const tls = tlsConfigs?.value.findLast((t:any) => t.id == i.tls_id)
|
||||
uClients.forEach((u:Client) => {
|
||||
const otherLocalLinks = u.links.filter(l => l.type == 'local' && l.remark != i.tag)
|
||||
const uris = LinkUtil.linkGenerator(u,i, tls, i.addrs)
|
||||
let newLinks = <Link[]>[]
|
||||
if (uris.length>0){
|
||||
uris.forEach(uri => {
|
||||
newLinks.push(<Link>{ type: 'local', remark: i.tag, uri: uri })
|
||||
})
|
||||
}
|
||||
let links = u.links && u.links.length>0? u.links : <Link[]>[]
|
||||
links = [...otherLocalLinks, ...newLinks, ...links.filter(l => l.type != 'local')]
|
||||
|
||||
diff.push({ id: u.id, links: links, inbounds: u.inbounds })
|
||||
})
|
||||
}
|
||||
|
||||
return diff
|
||||
}
|
||||
const delInbound = (index: number) => {
|
||||
const delInbound = async (id: number) => {
|
||||
const index = inbounds.value.findIndex(i => i.id == id)
|
||||
const inb = inbounds.value[index]
|
||||
inbounds.value.splice(index,1)
|
||||
const tag = inb.tag
|
||||
|
||||
if (Object.hasOwn(inb,'users')) {
|
||||
const inbU = <InboundWithUser>inb
|
||||
if (inbU.users && inbU.users.length>0){
|
||||
inbU.users.forEach((u:any) => {
|
||||
const c_index = clients.value.findIndex(c => u.username? u.username == c.name : u.name == c.name)
|
||||
if (c_index != -1) {
|
||||
clients.value[c_index].inbounds = clients.value[c_index].inbounds.filter((x:string) => x!=tag)
|
||||
clients.value[c_index].links = clients.value[c_index].links.filter((x:any) => x.remark!=tag)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Delete binded tls if exists
|
||||
if (Object.hasOwn(inb,'tls')) {
|
||||
const oldTlsConfigIndex = tlsConfigs?.value.findIndex(t => t.inbounds?.includes(inb.tag))
|
||||
if (oldTlsConfigIndex != -1){
|
||||
tlsConfigs.value[oldTlsConfigIndex].inbounds = tlsConfigs?.value[oldTlsConfigIndex].inbounds.filter((i:string) => i != inb.tag)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete stats if exists and will be orphaned
|
||||
const tagCounts = inbounds.value.filter(i => i.tag == inb.tag).length
|
||||
const sIndex = v2rayStats.value.inbounds.findIndex(i => i == inb.tag)
|
||||
if (tagCounts == 1 && sIndex != -1){
|
||||
v2rayStats.value.inbounds.splice(sIndex,1)
|
||||
}
|
||||
if (index < Data().oldData.config.inbounds.length){
|
||||
Data().delInbound(index)
|
||||
} else {
|
||||
// Delete new inbound's inData if exists
|
||||
const inDataIndex = Data().inData.findIndex((d:any) => d.tag == tag)
|
||||
if (inDataIndex != -1) Data().inData.splice(inDataIndex, 1)
|
||||
}
|
||||
delOverlay.value[index] = false
|
||||
}
|
||||
const buildInboundsUsers = (inbound:any):Inbound => {
|
||||
const users = <any>[]
|
||||
const inboundClients = clients.value.filter(c => c.enable && c.inbounds.includes(inbound.tag))
|
||||
inboundClients.forEach(c => {
|
||||
// Remove flow in non tls VLESS
|
||||
if (inbound.type == InTypes.VLESS) {
|
||||
const vlessInbound = <VLESS>inbound
|
||||
if (!vlessInbound.tls?.enabled || vlessInbound.transport?.type) delete(c.config?.vless?.flow)
|
||||
}
|
||||
users.push(c.config[inbound.type])
|
||||
})
|
||||
inbound.users = users
|
||||
|
||||
// Exceptions for Naive and ShadowTLSv3
|
||||
if (users.length == 0){
|
||||
if (inbound.type == InTypes.Naive){
|
||||
inbound.users = <any>[{}]
|
||||
} else {
|
||||
if (inbound.type == InTypes.ShadowTLS){
|
||||
const ssTls = <ShadowTLS>inbound
|
||||
if (ssTls.version == 3) inbound.users = <any>[{}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return <Inbound>inbound
|
||||
}
|
||||
const changeClientInboundsTag = (oldtag: string, newTag:string) => {
|
||||
clients.value.forEach((c, c_index) => {
|
||||
const inbound_index = c.inbounds.findIndex(i => i == oldtag)
|
||||
if (inbound_index != -1) {
|
||||
c.inbounds[inbound_index] = newTag
|
||||
clients.value[c_index].inbounds = c.inbounds
|
||||
}
|
||||
let diff = <any[]>[]
|
||||
// delete inbound in client table
|
||||
const inboundClients = clients.value.filter(c => c.inbounds.includes(id))
|
||||
inboundClients.forEach((c:Client) => {
|
||||
c.inbounds = c.inbounds.filter((x:number) => x!=id)
|
||||
c.links = c.links.filter((x:any) => x.remark!=tag)
|
||||
diff.push({ id: c.id, links: c.links, inbounds: c.inbounds })
|
||||
})
|
||||
}
|
||||
const findInbounsUsers = (inbound: InboundWithUser): string[] => {
|
||||
if (inbound.users === null || !Array.isArray(inbound.users) || inbound.users.length == 0) return []
|
||||
|
||||
const users = inbound.users.map(user => "username" in user ? user.username : user.name)
|
||||
return users
|
||||
const success = await Data().save("inbounds", "del", tag, diff)
|
||||
if (success) delOverlay.value[index] = false
|
||||
}
|
||||
|
||||
const findInboundUsers = (i: Inbound): string[] => {
|
||||
return clients.value.filter(c => c.inbounds.includes(i.id)).map(c => c.name)
|
||||
}
|
||||
|
||||
const stats = ref({
|
||||
|
||||
Reference in New Issue
Block a user