Outbound modal

This commit is contained in:
Alireza Ahmadi
2024-05-09 23:27:08 +02:00
parent 9a02e6593c
commit 43d1aecec7
45 changed files with 2391 additions and 308 deletions
+26 -12
View File
@@ -1,14 +1,14 @@
<template>
<v-card subtitle="Direct">
<v-row>
<v-col cols="12" sm="6" md="4">
<Network :inbound="inbound" />
<v-col cols="12" sm="6" md="4" v-if="direction == 'in'">
<Network :data="data" />
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
label="Override Address"
hide-details
v-model="inbound.override_address">
v-model="data.override_address">
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
@@ -20,6 +20,16 @@
v-model="override_port">
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4" v-if="direction == 'out'">
<v-text-field
label="Proxy Protocol"
type="number"
min="0"
max="2"
hide-details
v-model="proxy_protocol">
</v-text-field>
</v-col>
</v-row>
</v-card>
</template>
@@ -28,16 +38,20 @@
import Network from '@/components/Network.vue'
export default {
props: ['inbound'],
data() {
return {}
props: ['direction','data'],
data() {
return {}
},
computed: {
override_port: {
get() { return this.$props.data.override_port ? this.$props.data.override_port : ''; },
set(newValue: any) { this.$props.data.override_port = newValue.length == 0 || newValue == 0 ? undefined : parseInt(newValue); }
},
computed: {
override_port: {
get() { return this.$props.inbound.override_port ? this.$props.inbound.override_port : ''; },
set(newValue: any) { this.$props.inbound.override_port = newValue.length == 0 || newValue == 0 ? undefined : parseInt(newValue); }
},
proxy_protocol: {
get() { return this.$props.data.proxy_protocol ? this.$props.data.proxy_protocol : ''; },
set(newValue: any) { this.$props.data.proxy_protocol = newValue.length == 0 || newValue == 0 ? undefined : parseInt(newValue); }
},
components: { Network }
},
components: { Network }
}
</script>
@@ -0,0 +1,50 @@
<template>
<v-card subtitle="HTTP">
<v-row>
<v-col cols="12" sm="6" md="4">
<v-text-field
label="Username"
hide-details
v-model="username">
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
label="Password"
hide-details
v-model="password">
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
label="Path"
hide-details
v-model="data.path">
</v-text-field>
</v-col>
</v-row>
<Headers :data="data" />
</v-card>
</template>
<script lang="ts">
import Headers from '@/components/Headers.vue';
export default {
props: ['data'],
data() {
return {}
},
computed: {
username: {
get(): string { return this.data.username?.length > 0 ? this.data.username : '' },
set(v:string) { this.data.username = v.length > 0 ? v : undefined },
},
password: {
get(): string { return this.data.password?.length > 0 ? this.data.password : '' },
set(v:string) { this.data.password = v.length > 0 ? v : undefined },
},
},
components: { Headers }
}
</script>
+105 -9
View File
@@ -26,38 +26,134 @@
<v-text-field
label="obfs Password"
hide-details
v-model="inbound.obfs">
v-model="data.obfs">
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4" v-if="direction=='out'">
<v-text-field
label="Authentication String"
hide-details
v-model="data.auth_str">
</v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4" v-if="direction=='out'">
<Network :data="data" />
</v-col>
<v-col cols="12" sm="6" md="4">
<v-switch v-model="data.disable_mtu_discovery" color="primary" label="Disable MTU discovery" hide-details></v-switch>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4" v-if="data.recv_window_conn != undefined">
<v-text-field
label="Recv window conn"
hide-details
type="number"
min="0"
v-model.number="data.recv_window_conn">
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4" v-if="data.recv_window != undefined">
<v-text-field
label="Recv window"
hide-details
type="number"
min="0"
v-model.number="data.recv_window">
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4" v-if="data.recv_window_client != undefined">
<v-text-field
label="Recv window client"
hide-details
type="number"
min="0"
v-model.number="data.recv_window_client">
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4" v-if="data.max_conn_client != undefined">
<v-text-field
label="Max conn client"
hide-details
type="number"
min="0"
v-model.number="data.max_conn_client">
</v-text-field>
</v-col>
</v-row>
<v-card-actions>
<v-spacer></v-spacer>
<v-menu v-model="menu" :close-on-content-click="false" location="start">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" hide-details>Hysteria Options</v-btn>
</template>
<v-card>
<v-list>
<v-list-item>
<v-switch v-model="optionRsvConn" color="primary" label="Recv window conn" hide-details></v-switch>
</v-list-item>
<v-list-item v-if="direction=='out'">
<v-switch v-model="optionRsvWin" color="primary" label="Recv window" hide-details></v-switch>
</v-list-item>
<v-list-item v-if="direction=='in'">
<v-switch v-model="optionRsvClnt" color="primary" label="Recv window client" hide-details></v-switch>
</v-list-item>
<v-list-item v-if="direction=='in'">
<v-switch v-model="optionMaxConn" color="primary" label="Max connection" hide-details></v-switch>
</v-list-item>
</v-list>
</v-card>
</v-menu>
</v-card-actions>
</v-card>
</template>
<script lang="ts">
import Network from '@/components/Network.vue'
export default {
props: ['inbound'],
props: ['direction','data'],
data() {
return {
menu: false,
}
},
computed: {
optionRsvConn: {
get(): boolean { return this.$props.data.recv_window_conn != undefined },
set(v:boolean) { this.$props.data.recv_window_conn = v ? 15728640 : undefined }
},
optionRsvWin: {
get(): boolean { return this.$props.data.recv_window != undefined },
set(v:boolean) { this.$props.data.recv_window = v ? 67108864 : undefined }
},
optionRsvClnt: {
get(): boolean { return this.$props.data.recv_window_client != undefined },
set(v:boolean) { this.$props.data.recv_window_client = v ? 67108864 : undefined }
},
optionMaxConn: {
get(): boolean { return this.$props.data.max_conn_client != undefined },
set(v:boolean) { this.$props.data.max_conn_client = v ? 1024 : undefined }
},
down_mbps: {
get() { return this.$props.inbound.down_mbps ? this.$props.inbound.down_mbps : 0 },
get() { return this.$props.data.down_mbps ? this.$props.data.down_mbps : 0 },
set(newValue:any) {
if (newValue.length != 0 ){
this.$props.inbound.down_mbps = newValue
this.$props.inbound.down = "" + newValue + " Mbps"
this.$props.data.down_mbps = newValue
this.$props.data.down = "" + newValue + " Mbps"
} else {
this.$props.inbound.down_mbps = 0
this.$props.inbound.down = "0 Mbps"
this.$props.data.down_mbps = 0
this.$props.data.down = "0 Mbps"
}
}
},
up_mbps: {
get() { return this.$props.inbound.up_mbps ? this.$props.inbound.up_mbps : 0 },
set(newValue:number) { this.$props.inbound.up_mbps = newValue > 0 ? newValue : 0 }
get() { return this.$props.data.up_mbps ? this.$props.data.up_mbps : 0 },
set(newValue:number) { this.$props.data.up_mbps = newValue > 0 ? newValue : 0 }
},
},
components: { Network }
}
</script>
+30 -19
View File
@@ -1,23 +1,37 @@
<template>
<v-card subtitle="Hysteria2">
<v-row>
<v-row v-if="direction == 'in'">
<v-col cols="12" sm="6" md="4">
<v-text-field
label="Masquerade"
hide-details
v-model="hysteria2.masquerade"></v-text-field>
v-model="data.masquerade">
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-switch v-model="hysteria2.ignore_client_bandwidth" color="primary" label="Ignore Client Bandwidth" hide-details></v-switch>
<v-switch v-model="data.ignore_client_bandwidth" color="primary" label="Ignore Client Bandwidth" hide-details></v-switch>
</v-col>
</v-row>
<v-row v-if="!hysteria2.ignore_client_bandwidth">
<v-row v-else>
<v-col cols="12" sm="6" md="4">
<v-text-field
label="Password"
hide-details
v-model="data.password">
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<Network :data="data" />
</v-col>
</v-row>
<v-row v-if="!data.ignore_client_bandwidth">
<v-col cols="12" sm="6" md="4">
<v-text-field
label="Uplink Limit"
hide-details
type="number"
suffix="Mbps"
min="0"
v-model.number="up_mbps">
</v-text-field>
</v-col>
@@ -32,12 +46,12 @@
</v-text-field>
</v-col>
</v-row>
<v-row v-if="hysteria2.obfs">
<v-row v-if="data.obfs">
<v-col cols="12" sm="6" md="4">
<v-text-field
label="obfs Password"
hide-details
v-model="hysteria2.obfs.password">
v-model="data.obfs.password">
</v-text-field>
</v-col>
</v-row>
@@ -45,7 +59,7 @@
<v-spacer></v-spacer>
<v-menu v-model="menu" :close-on-content-click="false" location="start">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" hide-details>Options</v-btn>
<v-btn v-bind="props" hide-details>Hysteria2 Options</v-btn>
</template>
<v-card>
<v-list>
@@ -60,32 +74,29 @@
</template>
<script lang="ts">
import { Hysteria2, createInbound } from '@/types/inbounds'
import Network from '@/components/Network.vue'
export default {
props: ['inbound'],
props: ['direction', 'data'],
data() {
return {
menu: false,
hysteria2: <Hysteria2> createInbound("hysteria2",{ "tag": "" }),
}
},
computed: {
down_mbps: {
get() { return this.hysteria2.down_mbps ? this.hysteria2.down_mbps : 0 },
set(newValue:number) { this.hysteria2.down_mbps = newValue?? undefined }
get() { return this.$props.data.down_mbps?? 0 },
set(newValue:number) { this.$props.data.down_mbps = newValue>0 ? newValue : undefined }
},
up_mbps: {
get() { return this.hysteria2.up_mbps ? this.hysteria2.up_mbps : 0 },
set(newValue:number) { this.hysteria2.up_mbps = newValue?? undefined }
get() { return this.$props.data.up_mbps?? 0 },
set(newValue:number) { this.$props.data.up_mbps = newValue>0 ? newValue : undefined }
},
optionObfs: {
get(): boolean { return this.hysteria2.obfs != undefined },
set(v:boolean) { this.$props.inbound.obfs = v ? { type: "salamander", password: ""} : undefined }
get(): boolean { return this.$props.data.obfs != undefined },
set(v:boolean) { this.$props.data.obfs = v ? { type: "salamander", password: "" } : undefined }
}
},
mounted() {
this.hysteria2 = <Hysteria2> this.$props.inbound
}
components: { Network }
}
</script>
+1 -1
View File
@@ -2,7 +2,7 @@
<v-card subtitle="Naive">
<v-row>
<v-col cols="12" sm="6" md="4">
<Network :inbound="inbound" />
<Network :data="inbound" />
</v-col>
</v-row>
</v-card>
@@ -0,0 +1,44 @@
<template>
<v-card subtitle="ShadowTls">
<v-row>
<v-col cols="12" sm="6" md="4">
<v-select
hide-details
:items="[1,2,3]"
label="Version"
v-model="version">
</v-select>
</v-col>
<v-col cols="12" sm="6" md="4" v-if="data.version > 1">
<v-text-field
label="Password"
hide-details
v-model="data.password">
</v-text-field>
</v-col>
</v-row>
</v-card>
</template>
<script lang="ts">
export default {
props: ['data'],
data() {
return {}
},
computed: {
version: {
get() { return this.$props.data.version ?? 3 },
set(v: number) {
this.$props.data.version = v
if (v==1) {
delete this.$props.data.password
} else if (this.$props.data.password === undefined ) {
this.$props.data.password = ""
}
}
},
}
}
</script>
@@ -0,0 +1,31 @@
<template>
<v-card subtitle="Selector">
<v-row>
<v-col cols="12" sm="6">
<v-text-field v-model="outbounds" label="Outbounds(comma separated)" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="data.default" label="Default" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6">
<v-switch v-model="data.interrupt_exist_connections" color="primary" label="Interrupt exist connections" hide-details></v-switch>
</v-col>
</v-row>
</v-card>
</template>
<script lang="ts">
export default {
props: ['data'],
data() {
return {}
},
computed: {
outbounds: {
get() { return this.$props.data.outbounds ? this.$props.data.outbounds.join(',') : '' },
set(v:string) { this.$props.data.outbounds = v.length > 0 ? v.split(',') : undefined }
},
},
}
</script>
+52 -52
View File
@@ -92,62 +92,62 @@ import { ShadowTLS } from '@/types/inbounds'
import Dial from '../Dial.vue'
export default {
props: ['inbound'],
data() {
return {
handshake_server: ''
props: ['inbound'],
data() {
return {
handshake_server: ''
}
},
methods: {
addHandshakeServer() {
this.inbound.handshake_for_server_name[this.handshake_server] = {}
// Clear the input field after adding the server
this.handshake_server = ''
}
},
mounted() {
this.version = this.Inbound.version
},
computed: {
version: {
get() { this.version = this.Inbound.version; return this.Inbound.version; },
set(newValue: any) {
switch (newValue) {
case 1:
this.Inbound.password = undefined
this.Inbound.users = undefined
this.Inbound.handshake_for_server_name = undefined
break;
case 2:
if (!this.Inbound.password) {
this.Inbound.password = ""
}
this.Inbound.users = undefined
if (!this.Inbound.handshake_for_server_name) {
this.Inbound.handshake_for_server_name = {}
}
break;
case 3:
this.Inbound.password = undefined
if (Object.hasOwn(this.Inbound, 'users')) {
this.Inbound.users = []
}
if (!this.Inbound.handshake_for_server_name) {
this.Inbound.handshake_for_server_name = {}
}
break;
}
},
methods: {
addHandshakeServer() {
this.inbound.handshake_for_server_name[this.handshake_server] = {}
// Clear the input field after adding the server
this.handshake_server = ''
this.Inbound.version = newValue;
}
},
mounted() {
this.version = this.Inbound.version
Inbound(): ShadowTLS {
return <ShadowTLS>this.$props.inbound;
},
computed: {
version: {
get() { this.version = this.Inbound.version; return this.Inbound.version; },
set(newValue: any) {
switch (newValue) {
case 1:
this.Inbound.password = undefined
this.Inbound.users = undefined
this.Inbound.handshake_for_server_name = undefined
break;
case 2:
if (!this.Inbound.password) {
this.Inbound.password = ""
}
this.Inbound.users = undefined
if (!this.Inbound.handshake_for_server_name) {
this.Inbound.handshake_for_server_name = {}
}
break;
case 3:
this.Inbound.password = undefined
if (Object.hasOwn(this.Inbound, 'users')) {
this.Inbound.users = []
}
if (!this.Inbound.handshake_for_server_name) {
this.Inbound.handshake_for_server_name = {}
}
break;
}
this.Inbound.version = newValue;
}
},
Inbound(): ShadowTLS {
return <ShadowTLS>this.$props.inbound;
},
server_port: {
get() { return this.Inbound.handshake.server_port ? this.Inbound.handshake.server_port : 443; },
set(newValue: any) { this.Inbound.handshake.server_port = newValue.length == 0 || newValue == 0 ? 443 : parseInt(newValue); }
},
server_port: {
get() { return this.Inbound.handshake.server_port ? this.Inbound.handshake.server_port : 443; },
set(newValue: any) { this.Inbound.handshake.server_port = newValue.length == 0 || newValue == 0 ? 443 : parseInt(newValue); }
},
components: { Dial }
},
components: { Dial }
}
</script>
@@ -6,14 +6,17 @@
hide-details
label="Method"
:items="ssMethods"
v-model="inbound.method">
v-model="data.method">
</v-select>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="inbound.password" label="Password" hide-details></v-text-field>
<v-text-field v-model="data.password" label="Password" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<Network :inbound="inbound" />
<Network :data="data" />
</v-col>
<v-col cols="12" sm="6" md="4" v-if="direction == 'out'">
<UoT :data="data" />
</v-col>
</v-row>
</v-card>
@@ -21,24 +24,25 @@
<script lang="ts">
import Network from '@/components/Network.vue'
import UoT from '@/components/UoT.vue';
export default {
props: ['inbound'],
data() {
return {
ssMethods: [
"none",
"aes-128-gcm",
"aes-192-gcm",
"aes-256-gcm",
"chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305",
"2022-blake3-aes-128-gcm",
"2022-blake3-aes-256-gcm",
"2022-blake3-chacha20-poly1305"
]
}
},
components: { Network }
props: ['direction','data'],
data() {
return {
ssMethods: [
"none",
"aes-128-gcm",
"aes-192-gcm",
"aes-256-gcm",
"chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305",
"2022-blake3-aes-128-gcm",
"2022-blake3-aes-256-gcm",
"2022-blake3-chacha20-poly1305"
]
}
},
components: { Network, UoT }
}
</script>
@@ -0,0 +1,59 @@
<template>
<v-card subtitle="SOCKS">
<v-row>
<v-col cols="12" sm="6" md="4">
<v-text-field
label="Username"
hide-details
v-model="username">
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
label="Password"
hide-details
v-model="password">
</v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-select
hide-details
:items="['4','4a','5']"
label="Version"
v-model="data.version">
</v-select>
</v-col>
<v-col cols="12" sm="6" md="4">
<Network :data="data" />
</v-col>
<v-col cols="12" sm="6" md="4">
<UoT :data="data" />
</v-col>
</v-row>
</v-card>
</template>
<script lang="ts">
import Network from '@/components/Network.vue'
import UoT from '@/components/UoT.vue';
export default {
props: ['data'],
data() {
return {}
},
computed: {
username: {
get(): string { return this.data.username?.length > 0 ? this.data.username : '' },
set(v:string) { this.data.username = v.length > 0 ? v : undefined },
},
password: {
get(): string { return this.data.password?.length > 0 ? this.data.password : '' },
set(v:string) { this.data.password = v.length > 0 ? v : undefined },
},
},
components: { Network, UoT }
}
</script>
+151
View File
@@ -0,0 +1,151 @@
<template>
<v-card subtitle="SSH">
<template v-if="optionKey">
<v-row>
<v-col cols="auto">
<v-btn-toggle v-model="usePath"
class="rounded-xl"
density="compact"
variant="outlined"
shaped
mandatory>
<v-btn
@click="data.private_key=undefined; data.private_key_path=''"
>{{ $t('tls.usePath') }}</v-btn>
<v-btn
@click="data.private_key_path=undefined; data.private_key=''"
>{{ $t('tls.useText') }}</v-btn>
</v-btn-toggle>
</v-col>
</v-row>
<v-row v-if="usePath == 0">
<v-col cols="12" sm="6">
<v-text-field
:label="$t('tls.keyPath')"
hide-details
v-model="data.private_key_path">
</v-text-field>
</v-col>
</v-row>
<v-row v-else>
<v-col cols="12" sm="6">
<v-textarea
:label="$t('tls.key')"
hide-details
v-model="data.private_key">
</v-textarea>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6">
<v-text-field
label="Passphrase"
hide-details
v-model="data.private_key_passphrase">
</v-text-field>
</v-col>
</v-row>
</template>
<template v-else>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="data.user" label="SSH User" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="data.password" label="Password" hide-details></v-text-field>
</v-col>
</v-row>
</template>
<v-row v-if="optionHostKey">
<v-col cols="12" sm="6">
<v-textarea
label="Host Keys"
hide-details
v-model="host_key">
</v-textarea>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4" v-if="data.host_key_algorithms != undefined">
<v-text-field v-model="algorithms" label="Key Algorithms (comma separated)" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4" v-if="data.client_version != undefined">
<v-text-field v-model="data.client_version" label="Client Version" hide-details></v-text-field>
</v-col>
</v-row>
<v-card-actions>
<v-spacer></v-spacer>
<v-menu v-model="menu" :close-on-content-click="false" location="start">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" hide-details>SSH Options</v-btn>
</template>
<v-card>
<v-list>
<v-list-item>
<v-switch v-model="optionKey" color="primary" label="SSH Key" hide-details></v-switch>
</v-list-item>
<v-list-item>
<v-switch v-model="optionHostKey" color="primary" label="Host Key" hide-details></v-switch>
</v-list-item>
<v-list-item>
<v-switch v-model="optionAlgorithms" color="primary" label="Key Algorithms" hide-details></v-switch>
</v-list-item>
<v-list-item>
<v-switch v-model="optionVer" color="primary" label="Client Version" hide-details></v-switch>
</v-list-item>
</v-list>
</v-card>
</v-menu>
</v-card-actions>
</v-card>
</template>
<script lang="ts">
export default {
props: ['data'],
data() {
return {
menu: false,
usePath: 0,
}
},
computed: {
optionKey: {
get(): boolean { return this.data.private_key != undefined || this.data.private_key_path != undefined },
set(v:boolean) {
this.usePath = 0
if (v) {
this.$props.data.private_key_path = ""
delete this.$props.data.user
delete this.$props.data.password
} else {
delete this.$props.data.private_key_path
delete this.$props.data.private_key
delete this.$props.data.private_key_passphrase
}
}
},
optionHostKey: {
get(): boolean { return this.data.host_key != undefined },
set(v:boolean) { this.data.host_key = v ? '' : undefined }
},
optionAlgorithms: {
get(): boolean { return this.data.host_key_algorithms != undefined },
set(v:boolean) { this.data.host_key_algorithms = v ? [] : undefined }
},
optionVer: {
get(): boolean { return this.data.client_version != undefined },
set(v:boolean) { this.data.client_version = v ? 'SSH-2.0-OpenSSH_7.4p1' : undefined }
},
host_key: {
get(): string { return this.$props.data.host_key ? this.$props.data.host_key.join('\n') : '' },
set(v:string) { this.$props.data.host_key = v.split('\n') }
},
algorithms: {
get() { return this.$props.data.host_key_algorithms ? this.$props.data.host_key_algorithms.join(',') : '' },
set(v:string) { this.$props.data.host_key_algorithms = v.length > 0 ? v.split(',') : undefined }
},
},
}
</script>
+1 -1
View File
@@ -2,7 +2,7 @@
<v-card subtitle="TProxy">
<v-row>
<v-col cols="12" sm="6" md="4">
<Network :inbound="inbound" />
<Network :data="inbound" />
</v-col>
</v-row>
</v-card>
+33
View File
@@ -0,0 +1,33 @@
<template>
<v-card subtitle="Tor">
<v-row>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="data.executable_path" label="Executable Path" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="data.data_directory" label="Data Directory" hide-details></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="extra_args" label="Extra Args (comma separated)" hide-details></v-text-field>
</v-col>
</v-row>
</v-card>
</template>
<script lang="ts">
export default {
props: ['data'],
data() {
return {}
},
computed: {
extra_args: {
get() { return this.$props.data.extra_args?.join(',') },
set(v:string) { this.$props.data.extra_args = v.length > 0 ? v.split(',') : undefined }
},
},
}
</script>
@@ -0,0 +1,24 @@
<template>
<v-card subtitle="Trojan">
<v-row>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="data.password" label="Password" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<Network :data="data" />
</v-col>
</v-row>
</v-card>
</template>
<script lang="ts">
import Network from '@/components/Network.vue'
export default {
props: ['data'],
data() {
return {}
},
components: { Network }
}
</script>
+36 -13
View File
@@ -1,20 +1,44 @@
<template>
<v-card subtitle="TUIC">
<v-row v-if="direction == 'out'">
<v-col cols="12" sm="6">
<v-text-field v-model="data.uuid" label="UUID" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="data.password" label="Password" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<Network :data="data" />
</v-col>
<v-col cols="12" sm="6" md="4">
<v-select
hide-details
label="UDP Relay Mode"
:items="['native', 'quic']"
clearable
@click:clear="delete data.udp_relay_mode"
v-model="data.udp_relay_mode">
</v-select>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-switch color="primary" label="UDP Over Stream" v-model="data.udp_over_stream" hide-details></v-switch>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-select
hide-details
label="Congestion Control"
:items="congestion_controls"
v-model="inbound.congestion_control">
v-model="data.congestion_control">
</v-select>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-switch color="primary" label="Zero-RTT Handshake" v-model="inbound.zero_rtt_handshake" hide-details></v-switch>
<v-switch color="primary" label="Zero-RTT Handshake" v-model="data.zero_rtt_handshake" hide-details></v-switch>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-col cols="12" sm="6" md="4" v-if="direction == 'in'">
<v-text-field
label="Authentication Timeout"
hide-details
@@ -39,9 +63,10 @@
</template>
<script lang="ts">
import { TUIC } from '@/types/inbounds'
import Network from '@/components/Network.vue'
export default {
props: ['inbound'],
props: ['direction', 'data'],
data() {
return {
congestion_controls: [
@@ -50,17 +75,15 @@ export default {
}
},
computed: {
Inbound(): TUIC {
return <TUIC> this.$props.inbound
},
auth_timeout: {
get() { return this.Inbound.auth_timeout ? parseInt(this.Inbound.auth_timeout.replace('s','')) : '' },
set(newValue:number) { this.$props.inbound.auth_timeout = newValue ? newValue + 's' : '' }
get() { return this.$props.data.auth_timeout ? parseInt(this.$props.data.auth_timeout.replace('s','')) : '' },
set(newValue:number) { this.$props.data.auth_timeout = newValue ? newValue + 's' : '' }
},
heartbeat: {
get() { return this.Inbound.heartbeat ? parseInt(this.Inbound.heartbeat.replace('s','')) : '' },
set(newValue:number) { this.$props.inbound.heartbeat = newValue ? newValue + 's' : '' }
get() { return this.$props.data.heartbeat ? parseInt(this.$props.data.heartbeat.replace('s','')) : '' },
set(newValue:number) { this.$props.data.heartbeat = newValue ? newValue + 's' : '' }
}
}
},
components: { Network }
}
</script>
@@ -0,0 +1,118 @@
<template>
<v-card subtitle="URL Test">
<v-row>
<v-col cols="12" sm="6">
<v-text-field v-model="outbounds" label="Outbounds(comma separated)" hide-details></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" v-if="optionUrl">
<v-text-field v-model="data.url" label="URL" hide-details></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4" v-if="optionInterval">
<v-text-field
label="Interval"
hide-details
type="number"
min="3"
suffix="s"
v-model.number="interval"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4" v-if="optionTolerance">
<v-text-field
label="Tolerance"
hide-details
type="number"
min="0"
suffix="ms"
v-model.number="tolerance"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4" v-if="optionIdle">
<v-text-field
label="Idle Timeout"
hide-details
type="number"
min="0"
suffix="m"
v-model.number="idle_timeout"></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6">
<v-switch v-model="data.interrupt_exist_connections" color="primary" label="Interrupt exist connections" hide-details></v-switch>
</v-col>
</v-row>
<v-card-actions>
<v-spacer></v-spacer>
<v-menu v-model="menu" :close-on-content-click="false" location="start">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" hide-details>SSH Options</v-btn>
</template>
<v-card>
<v-list>
<v-list-item>
<v-switch v-model="optionUrl" color="primary" label="Test URL" hide-details></v-switch>
</v-list-item>
<v-list-item>
<v-switch v-model="optionInterval" color="primary" label="Interval" hide-details></v-switch>
</v-list-item>
<v-list-item>
<v-switch v-model="optionTolerance" color="primary" label="Tolerance" hide-details></v-switch>
</v-list-item>
<v-list-item>
<v-switch v-model="optionIdle" color="primary" label="Idle Timeout" hide-details></v-switch>
</v-list-item>
</v-list>
</v-card>
</v-menu>
</v-card-actions>
</v-card>
</template>
<script lang="ts">
export default {
props: ['data'],
data() {
return {
menu: false,
}
},
computed: {
optionUrl: {
get(): boolean { return this.$props.data.url != undefined },
set(v:boolean) { this.$props.data.url = v ? 'https://www.gstatic.com/generate_204' : undefined }
},
optionInterval: {
get(): boolean { return this.$props.data.interval != undefined },
set(v:boolean) { this.$props.data.interval = v ? '3s' : undefined }
},
optionTolerance: {
get(): boolean { return this.$props.data.tolerance != undefined },
set(v:boolean) { this.$props.data.tolerance = v ? 50 : undefined }
},
optionIdle: {
get(): boolean { return this.$props.data.idle_timeout != undefined },
set(v:boolean) { this.$props.data.idle_timeout = v ? '30m' : undefined }
},
interval: {
get() { return this.$props.data.interval ? parseInt(this.$props.data.interval.replace('s','')) : 3 },
set(v:number) { this.$props.data.interval = v > 0 ? v + 's' : '3s' }
},
tolerance: {
get() { return this.$props.data.tolerance ? parseInt(this.$props.data.tolerance) : 0 },
set(v:number) { this.$props.data.tolerance = v > 0 ? v : 0 }
},
idle_timeout: {
get() { return this.$props.data.idle_timeout ? parseInt(this.$props.data.idle_timeout.replace('m','')) : 30 },
set(v:number) { this.$props.data.idle_timeout = v > 0 ? v + 'm' : '0m' }
},
outbounds: {
get() { return this.$props.data.outbounds ? this.$props.data.outbounds.join(',') : '' },
set(v:string) { this.$props.data.outbounds = v.length > 0 ? v.split(',') : undefined }
},
},
}
</script>
@@ -0,0 +1,48 @@
<template>
<v-card subtitle="VLESS">
<v-row>
<v-col cols="12" sm="6">
<v-text-field v-model="data.uuid" label="UUID" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-select
hide-details
label="Flow"
:items="['','xtls-rprx-vision']"
v-model="data.flow">
</v-select>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-select
hide-details
label="UDP Packet Encoding"
:items="['none','packetaddr','xudp']"
v-model="packet_encoding">
</v-select>
</v-col>
<v-col cols="12" sm="6" md="4">
<Network :data="data" />
</v-col>
</v-row>
</v-card>
</template>
<script lang="ts">
import Network from '@/components/Network.vue'
export default {
props: ['data'],
data() {
return {}
},
computed: {
packet_encoding: {
get() { return this.$props.data.packet_encoding != undefined ? this.$props.data.packet_encoding : 'none'; },
set(newValue:string) { this.$props.data.packet_encoding = newValue != "none" ? newValue : undefined }
},
},
components: { Network }
}
</script>
@@ -0,0 +1,72 @@
<template>
<v-card subtitle="VMESS">
<v-row>
<v-col cols="12" sm="6">
<v-text-field v-model="data.uuid" label="UUID" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
label="Alter ID"
hide-details
type="number"
min=0
v-model.number="data.alter_id">
</v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-select
hide-details
label="Security"
:items="securities"
v-model="data.security">
</v-select>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-select
hide-details
label="UDP Packet Encoding"
:items="['none','packetaddr','xudp']"
v-model="packet_encoding">
</v-select>
</v-col>
<v-col cols="12" sm="6" md="4">
<Network :data="data" />
</v-col>
<v-col cols="12" sm="6" md="4">
<v-switch v-model="data.global_padding" color="primary" label="Global Padding" hide-details></v-switch>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-switch v-model="data.authenticated_length" color="primary" label="Encryptrd Length" hide-details></v-switch>
</v-col>
</v-row>
</v-card>
</template>
<script lang="ts">
import Network from '@/components/Network.vue'
export default {
props: ['data'],
data() {
return {
securities: [
"auto",
"none",
"zero",
"aes-128-gcm",
"aes-128-ctr",
"chacha20-poly1305",
]
}
},
computed: {
packet_encoding: {
get() { return this.$props.data.packet_encoding != undefined ? this.$props.data.packet_encoding : 'none'; },
set(newValue:string) { this.$props.data.packet_encoding = newValue != "none" ? newValue : undefined }
},
},
components: { Network }
}
</script>
@@ -0,0 +1,163 @@
<template>
<v-card subtitle="Wireguard">
<v-row>
<v-col cols="12" sm="8">
<v-text-field v-model="data.private_key" label="Private Key" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="8">
<v-text-field v-model="data.peer_public_key" label="Peer Public Key" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="8" v-if="data.pre_shared_key != undefined">
<v-text-field v-model="data.pre_shared_key" label="Pre-Shared Key" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="8">
<v-text-field v-model="local_ips" label="Local IPs (comma separated)" hide-details></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4" v-if="data.reserved != undefined">
<v-text-field v-model="reserved" label="Reserved (comma separated)" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4" v-if="data.workers != undefined">
<v-text-field
label="Workers"
hide-details
type="number"
min=1
v-model.number="data.workers">
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4" v-if="data.mtu != undefined">
<v-text-field
label="MTU"
hide-details
type="number"
min=0
v-model.number="data.mtu">
</v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4">
<Network :data="data" />
</v-col>
<v-col cols="12" sm="6" md="4" v-if="data.interface_name != undefined">
<v-text-field
label="Interface Name"
hide-details
v-model.number="data.interface_name">
</v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-switch v-model="data.system_interface" color="primary" label="System Interface" hide-details></v-switch>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-switch v-model="data.gso" color="primary" label="Segmentation Offload" hide-details></v-switch>
</v-col>
</v-row>
<v-card-actions>
<v-spacer></v-spacer>
<v-menu v-model="menu" :close-on-content-click="false" location="start">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" hide-details>Wireguard Options</v-btn>
</template>
<v-card>
<v-list>
<v-list-item>
<v-switch v-model="optionPsk" color="primary" label="Pre-shared Key" hide-details></v-switch>
</v-list-item>
<v-list-item>
<v-switch v-model="optionRsrv" color="primary" label="Reserved" hide-details></v-switch>
</v-list-item>
<v-list-item>
<v-switch v-model="optionWorker" color="primary" label="Worker" hide-details></v-switch>
</v-list-item>
<v-list-item>
<v-switch v-model="optionMtu" color="primary" label="MTU" hide-details></v-switch>
</v-list-item>
<v-list-item>
<v-switch v-model="optionInterface" color="primary" label="Interface Name" hide-details></v-switch>
</v-list-item>
<v-list-item>
<v-switch v-model="optionPeers" color="primary" label="Multi Peer" hide-details></v-switch>
</v-list-item>
</v-list>
</v-card>
</v-menu>
</v-card-actions>
</v-card>
<v-card subtitle="Peers" v-if="data.peers != undefined">
<template v-for="(p, index) in data.peers">
Peer {{ index+1 }} <v-icon icon="mdi-delete" @click="data.peers.splice(index,1)" />
<v-divider></v-divider>
<Peer :data="p" />
</template>
<v-card-actions class="pt-0">
<v-spacer></v-spacer>
<v-btn @click="addPeer" rounded>
<v-icon icon="mdi-plus" />Peer
</v-btn>
</v-card-actions>
</v-card>
</template>
<script lang="ts">
import Network from '@/components/Network.vue'
import Peer from '@/components/WgPeer.vue'
import { WgPeer } from '@/types/outbounds'
export default {
props: ['data'],
data() {
return {
menu: false,
}
},
methods: {
addPeer() {
this.$props.data.peers.push({server: '', port: ''})
}
},
computed: {
optionPsk: {
get(): boolean { return this.$props.data.pre_shared_key != undefined },
set(v:boolean) { this.$props.data.pre_shared_key = v ? "" : undefined }
},
optionRsrv: {
get(): boolean { return this.$props.data.reserved != undefined },
set(v:boolean) { this.$props.data.reserved = v ? [0,0,0] : undefined }
},
optionWorker: {
get(): boolean { return this.$props.data.workers != undefined },
set(v:boolean) { this.$props.data.workers = v ? 2 : undefined }
},
optionMtu: {
get(): boolean { return this.$props.data.mtu != undefined },
set(v:boolean) { this.$props.data.mtu = v ? 1408 : undefined }
},
optionInterface: {
get(): boolean { return this.$props.data.interface_name != undefined },
set(v:boolean) { this.$props.data.interface_name = v ? "" : undefined }
},
optionPeers: {
get(): boolean { return this.$props.data.peers != undefined },
set(v:boolean) { this.$props.data.peers = v ? <WgPeer[]>[] : undefined }
},
local_ips: {
get() { return this.$props.data.local_address?.join(',') },
set(v:string) { this.$props.data.local_address = v.length > 0 ? v.split(',') : undefined }
},
reserved: {
get() { return this.$props.data.reserved?.join(',') },
set(v:string) {
if(!v.endsWith(',')) {
this.$props.data.reserved = v.length > 0 ? v.split(',').map(str => parseInt(str, 10)) : []
}
}
},
},
components: { Network, Peer }
}
</script>