Browse Source

update pack 3

user pass will be generated randomly
upgrade all dependencies
move add client buttom
MHSanaei 2 years ago
parent
commit
add853fada

+ 3 - 2
README.md

@@ -21,8 +21,7 @@ certbot renew --dry-run
 # Default settings
 
 - Port: 2053
-- user: admin
-- password: admin
+- username and password will be generated randomly you can see them after you install it (x-ui "7")
 - database path: /etc/x-ui/x-ui.db
 
 before you set ssl on settings
@@ -53,6 +52,8 @@ After you set ssl on settings
 
 # suggestion system
 - Ubuntu 20.04+
+- Debian 10
+- CentOS 8
 
 # pic
 

+ 11 - 11
go.mod

@@ -3,24 +3,25 @@ module x-ui
 go 1.20
 
 require (
-	github.com/BurntSushi/toml v1.2.1
 	github.com/Workiva/go-datastructures v1.0.53
 	github.com/gin-contrib/sessions v0.0.4
-	github.com/gin-gonic/gin v1.8.1
+	github.com/gin-gonic/gin v1.8.2
 	github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
 	github.com/nicksnyder/go-i18n/v2 v2.2.1
 	github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
+	github.com/pelletier/go-toml/v2 v2.0.6
 	github.com/robfig/cron/v3 v3.0.1
 	github.com/shirou/gopsutil/v3 v3.23.1
 	github.com/xtls/xray-core v1.7.5
 	go.uber.org/atomic v1.10.0
 	golang.org/x/text v0.7.0
 	google.golang.org/grpc v1.53.0
-	gorm.io/driver/sqlite v1.3.6
-	gorm.io/gorm v1.23.8
+	gorm.io/driver/sqlite v1.4.4
+	gorm.io/gorm v1.24.5
 )
 
 require (
+	github.com/BurntSushi/toml v1.2.1 // indirect
 	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/go-ole/go-ole v1.2.6 // indirect
 	github.com/go-playground/locales v0.14.1 // indirect
@@ -36,22 +37,21 @@ require (
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/kr/text v0.2.0 // indirect
 	github.com/leodido/go-urn v1.2.1 // indirect
-	github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
-	github.com/mattn/go-isatty v0.0.16 // indirect
+	github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de // indirect
+	github.com/mattn/go-isatty v0.0.17 // indirect
 	github.com/mattn/go-sqlite3 v1.14.16 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
-	github.com/pelletier/go-toml/v2 v2.0.6 // indirect
 	github.com/pires/go-proxyproto v0.6.2 // indirect
-	github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
+	github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
 	github.com/tklauser/go-sysconf v0.3.11 // indirect
 	github.com/tklauser/numcpus v0.6.0 // indirect
-	github.com/ugorji/go/codec v1.2.7 // indirect
+	github.com/ugorji/go/codec v1.2.9 // indirect
 	github.com/yusufpapurcu/wmi v1.2.2 // indirect
-	golang.org/x/crypto v0.5.0 // indirect
+	golang.org/x/crypto v0.6.0 // indirect
 	golang.org/x/net v0.7.0 // indirect
 	golang.org/x/sys v0.5.0 // indirect
-	google.golang.org/genproto v0.0.0-20230202175211-008b39050e57 // indirect
+	google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 )

+ 20 - 19
go.sum

@@ -20,8 +20,8 @@ github.com/gin-contrib/sessions v0.0.4/go.mod h1:pQ3sIyviBBGcxgyR8mkeJuXbeV3h3NY
 github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
-github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
-github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
+github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY=
+github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398=
 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
 github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
 github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
@@ -81,12 +81,13 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx
 github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
 github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
 github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
 github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
+github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de h1:V53FWzU6KAZVi1tPp5UIsMoUWJ2/PNwYIDXnu7QuBCE=
+github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
+github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
+github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
 github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
 github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
 github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
@@ -110,8 +111,9 @@ github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9G
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
 github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
+github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
+github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
 github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
 github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U=
 github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk=
@@ -146,10 +148,9 @@ github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYm
 github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
 github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q=
 github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
-github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
-github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
-github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
+github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU=
+github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
 github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
 github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 h1:a3Y4WVjCxwoyO4E2xdNvq577tW8lkSBgyrA8E9+2NtM=
 github.com/xtls/xray-core v1.7.5 h1:Ukr3hXnOG2ciViQL7kfYRl9S3GVej2dkV7DzabmoLL4=
@@ -165,8 +166,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
-golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
+golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
+golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
 golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -216,8 +217,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto v0.0.0-20230202175211-008b39050e57 h1:vArvWooPH749rNHpBGgVl+U9B9dATjiEhJzcWGlovNs=
-google.golang.org/genproto v0.0.0-20230202175211-008b39050e57/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44 h1:EfLuoKW5WfkgVdDy7dTK8qSbH37AX5mj/MFh+bGPz14=
+google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA=
 google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
 google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
@@ -234,10 +235,10 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gorm.io/driver/sqlite v1.3.6 h1:Fi8xNYCUplOqWiPa3/GuCeowRNBRGTf62DEmhMDHeQQ=
-gorm.io/driver/sqlite v1.3.6/go.mod h1:Sg1/pvnKtbQ7jLXxfZa+jSHvoX8hoZA8cn4xllOMTgE=
-gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
-gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE=
-gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
+gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc=
+gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
+gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
+gorm.io/gorm v1.24.5 h1:g6OPREKqqlWq4kh/3MCQbZKImeB9e6Xgc4zD+JgNZGE=
+gorm.io/gorm v1.24.5/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
 gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4=
 lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=

+ 21 - 9
install.sh

@@ -35,8 +35,6 @@ if [[ $arch == "x86_64" || $arch == "x64" || $arch == "amd64" ]]; then
     arch="amd64"
 elif [[ $arch == "aarch64" || $arch == "arm64" ]]; then
     arch="arm64"
-elif [[ $arch == "s390x" ]]; then
-    arch="s390x"
 else
     arch="amd64"
     echo -e "${red} Failed to check system arch, will use default arch: ${arch}${plain}"
@@ -60,16 +58,16 @@ if [[ -z "$os_version" && -f /etc/lsb-release ]]; then
 fi
 
 if [[ x"${release}" == x"centos" ]]; then
-    if [[ ${os_version} -le 6 ]]; then
-        echo -e "${red} Please use CentOS 7 or higher ${plain}\n" && exit 1
+    if [[ ${os_version} -le 8 ]]; then
+        echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1
     fi
 elif [[ x"${release}" == x"ubuntu" ]]; then
-    if [[ ${os_version} -lt 16 ]]; then
-        echo -e "${red} Please use Ubuntu 16 or higher ${plain}\n" && exit 1
+    if [[ ${os_version} -lt 20 ]]; then
+        echo -e "${red} Please use Ubuntu 20 or higher ${plain}\n" && exit 1
     fi
 elif [[ x"${release}" == x"debian" ]]; then
-    if [[ ${os_version} -lt 8 ]]; then
-        echo -e "${red} Please use Debian 8 or higher ${plain}\n" && exit 1
+    if [[ ${os_version} -lt 10 ]]; then
+        echo -e "${red} Please use Debian 10 or higher ${plain}\n" && exit 1
     fi
 fi
 
@@ -98,7 +96,21 @@ config_after_install() {
         /usr/local/x-ui/x-ui setting -port ${config_port}
         echo -e "${yellow}Panel port set successfully!${plain}"
     else
-        echo -e "${red}Canceled, will use the default settings.${plain}"
+        echo -e "${red}cancel...${plain}"
+        if [[ ! -f "/etc/x-ui/x-ui.db" ]]; then
+            local usernameTemp=$(head -c 6 /dev/urandom | base64)
+            local passwordTemp=$(head -c 6 /dev/urandom | base64)
+            /usr/local/x-ui/x-ui setting -username ${usernameTemp} -password ${passwordTemp}
+            echo -e "this is a fresh installation,will generate random login info for security concerns:"
+            echo -e "###############################################"
+            echo -e "${green}user name:${usernameTemp}${plain}"
+            echo -e "${green}user password:${passwordTemp}${plain}"
+            echo -e "${red}web port:${portTemp}${plain}"
+            echo -e "###############################################"
+            echo -e "${red}if you forgot your login info,you can type x-ui and then type 7 to check after installation${plain}"
+        else
+            echo -e "${red} this is your upgrade,will keep old settings,if you forgot your login info,you can type x-ui and then type 7 to check${plain}"
+        fi
     fi
 }
 

+ 1 - 1
web/assets/js/util/utils.js

@@ -179,7 +179,7 @@ class ObjectUtil {
                 }
             }
         } else {
-            return obj.toString().indexOf(key) >= 0;
+            return obj.toString().toLowerCase().indexOf(key.toLowerCase()) >= 0;
         }
         return false;
     }

+ 99 - 114
web/html/xui/form/protocol/trojan.html

@@ -1,141 +1,126 @@
 {{define "form/trojan"}}
 <a-form layout="inline">
+<label>{{ i18n "clients"}} </label>
 <a-collapse activeKey="0"  v-for="(trojan, index) in inbound.settings.trojans"
 :key="`trojan-${index}`">
 
-
-<a-collapse-panel :class="getHeaderStyle(trojan.email)" :header="getHeaderText(trojan.email)">
-    <a-tag v-if="isExpiry(index) || ((getUpStats(trojan.email) + getDownStats(trojan.email)) > trojan.totalGB && trojan.totalGB != 0)" color="red" style="margin-bottom: 10px;display: block;text-align: center;">Account is (Expired|Traffic Ended) And Disabled</a-tag>
-    <a-form layout="inline">
+    <a-collapse-panel :class="getHeaderStyle(trojan.email)" :header="getHeaderText(trojan.email)">
+        <a-tag v-if="isExpiry(index) || ((getUpStats(trojan.email) + getDownStats(trojan.email)) > trojan.totalGB && trojan.totalGB != 0)" color="red" style="margin-bottom: 10px;display: block;text-align: center;">Account is (Expired|Traffic Ended) And Disabled</a-tag>
+        <a-form layout="inline">
+            <a-form-item>
+                <span slot="label">
+                    Email
+                    <a-tooltip>
+                        <template slot="title">
+                            The Email Must Be Completely Unique
+                        </template>
+                        <!--Renew Svg Icon-->
+                        <svg 
+                            @click="getNewEmail(trojan)"
+                            xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="anticon anticon-question-circle" viewBox="0 0 16 16"> <path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"/> <path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"/> </svg>
+                    </a-tooltip>
+                </span>
+                <a-input v-model.trim="trojan.email"></a-input>
+            </a-form-item>
+        </a-form>
+        <a-form-item label="Password">
+            <a-input v-model.trim="trojan.password"></a-input>
+        </a-form-item>
+        <a-form-item v-if="inbound.xtls" label="Flow">
+            <a-select v-model="trojan.flow" style="width: 150px">
+                <a-select-option value="">{{ i18n "none" }}</a-select-option>
+                <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
+            </a-select>
+        </a-form-item>
         <a-form-item>
             <span slot="label">
-                Email
+                <span >{{ i18n "pages.inbounds.totalFlow" }}</span>(GB)
                 <a-tooltip>
                     <template slot="title">
-                        The Email Must Be Completely Unique
+                        0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span>
                     </template>
-                    <!--Renew Svg Icon-->
-                    <svg 
-                        @click="getNewEmail(trojan)"
-                        xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="anticon anticon-question-circle" viewBox="0 0 16 16"> <path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"/> <path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"/> </svg>
+                    <a-icon type="question-circle" theme="filled"></a-icon>
                 </a-tooltip>
             </span>
-            <a-input v-model.trim="trojan.email"></a-input>
+            <a-input-number v-model="trojan._totalGB" :min="0"></a-input-number>
         </a-form-item>
-    </a-form>
-    <a-form-item label="Password">
-        <a-input v-model.trim="trojan.password"></a-input>
-    </a-form-item>
-        <a-form-item v-if="inbound.xtls" label="Flow">
-            <a-select v-model="inbound.settings.trojans[index].flow" style="width: 150px">
-                <a-select-option value="" selected>none</a-select-option>
-                <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
-            </a-select>
+        <a-form-item>
+            <span slot="label">
+                <span >{{ i18n "pages.inbounds.expireDate" }}</span>
+                <a-tooltip>
+                    <template slot="title">
+                        <span>{{ i18n "pages.inbounds.leaveBlankToNeverExpire" }}</span>
+                    </template>
+                    <a-icon type="question-circle" theme="filled"></a-icon>
+                </a-tooltip>
+            </span>
+            <a-date-picker :show-time="{ format: 'HH:mm' }" format="YYYY-MM-DD HH:mm"
+                           v-model="trojan._expiryTime" style="width: 300px;"></a-date-picker>
         </a-form-item>
-    <a-form-item>
-        <span slot="label">
-            <span >{{ i18n "pages.inbounds.totalFlow" }}</span>(GB)
-            <a-tooltip>
+        <a-form layout="inline">
+            <a-tooltip v-if="trojan._totalGB > 0">
                 <template slot="title">
-                    0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span>
+                    {{ i18n "pages.inbounds.resetTraffic" }}
                 </template>
-                <a-icon type="question-circle" theme="filled"></a-icon>
+                <span style="color: #FF4D4F">
+                    <a-icon type="delete" @click="resetClientTraffic(trojan,$event)"></a-icon>
+                </span>
             </a-tooltip>
-        </span>
-        <a-input-number v-model="trojan._totalGB" :min="0"></a-input-number>
-    </a-form-item>
-    <a-form-item>
-        <span slot="label">
-            <span >{{ i18n "pages.inbounds.expireDate" }}</span>
-            <a-tooltip>
-                <template slot="title">
-                    <span>{{ i18n "pages.inbounds.leaveBlankToNeverExpire" }}</span>
-                </template>
-                <a-icon type="question-circle" theme="filled"></a-icon>
-            </a-tooltip>
-        </span>
-        <a-date-picker :show-time="{ format: 'HH:mm' }" format="YYYY-MM-DD HH:mm"
-                       v-model="trojan._expiryTime" style="width: 300px;"></a-date-picker>
-    </a-form-item>
-    <a-form layout="inline">
-        <a-tooltip v-if="trojan._totalGB > 0">
-            <template slot="title">
-                {{ i18n "pages.inbounds.resetTraffic" }}
-            </template>
-            <span style="color: #FF4D4F">
-                <a-icon type="delete" @click="resetClientTraffic(trojan,$event)"></a-icon>
-            </span>
-        </a-tooltip>
-        <a-tag color="blue">[[ sizeFormat(getUpStats(trojan.email)) ]] / [[ sizeFormat(getDownStats(trojan.email)) ]]</a-tag>
-        <a-tag v-if="trojan._totalGB > 0" color="red">used : [[ sizeFormat(getUpStats(trojan.email) + getDownStats(trojan.email)) ]]</a-tag>
-        <a-tag>
-            <svg
-                @click="addClient(inbound.protocol,trojan, inbound.settings.trojans)"
-                xmlns="http://www.w3.org/2000/svg"
-                viewBox="0 0 24 24"
-                width="24"
-                height="24"
-                class="ml-2 cursor-pointer"
-                >
-                <path fill="none" d="M0 0h24v24H0z" />
-                <path
-                fill="green"
-                d="M11 11V7h2v4h4v2h-4v4h-2v-4H7v-2h4zm1 11C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"
-                />
-            </svg>
-        </a-tag>
-        <a-tag v-show="inbound.settings.trojans.length > 1">
-            <svg
-                v-show="inbound.settings.trojans.length > 1"
-                @click="removeClient(index, inbound.settings.trojans)"
-                xmlns="http://www.w3.org/2000/svg"
-                viewBox="0 0 24 24"
-                width="24"
-                height="24"
-                class="ml-2 cursor-pointer"
-                >
-                <path fill="none" d="M0 0h24v24H0z" />
-                <path
-                fill="#EC4899"
-                d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-9.414l2.828-2.829 1.415 1.415L13.414 12l2.829 2.828-1.415 1.415L12 13.414l-2.828 2.829-1.415-1.415L10.586 12 7.757 9.172l1.415-1.415L12 10.586z"
-                />
-            </svg>
-        </a-tag>
-       </a-form>
-    </a-form>
+            <a-tag color="blue">[[ sizeFormat(getUpStats(trojan.email)) ]] / [[ sizeFormat(getDownStats(trojan.email)) ]]</a-tag>
+            <a-tag v-if="trojan._totalGB > 0" color="red">used : [[ sizeFormat(getUpStats(trojan.email) + getDownStats(trojan.email)) ]]</a-tag>
+            <a-tag v-show="inbound.settings.trojans.length > 1" @click="removeClient(index, inbound.settings.trojans)">
+                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" width="22" height="22" class="mt-2 cursor-pointer">
+                    <path fill="none" d="M0 0h24v24H0z" />
+                    <path fill="#EC4899"
+                    d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-9.414l2.828-2.829 1.415 1.415L13.414 12l2.829 2.828-1.415 1.415L12 13.414l-2.828 2.829-1.415-1.415L10.586 12 7.757 9.172l1.415-1.415L12 10.586z"
+                    />
+                </svg>
+            </a-tag>
+        </a-form>
+    </a-collapse-panel>
+</a-collapse>
+<a-tag @click="addClient(inbound.protocol, inbound.settings.trojans)">
+    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" class="ml-2 cursor-pointer">
+        <path fill="none" d="M0 0h24v24H0z" />
+        <path fill="green"
+        d="M11 11V7h2v4h4v2h-4v4h-2v-4H7v-2h4zm1 11C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"
+        />
+    </svg>
+</a-tag>
+
 <a-form layout="inline">
     <a-form-item label="Fallbacks">
-         <a-row>
-              <a-button type="primary" size="small"
-                  @click="inbound.settings.addTrojanFallback()">
-            +
-              </a-button>
+        <a-row>
+            <a-button type="primary" size="small"
+                      @click="inbound.settings.addTrojanFallback()">
+                +
+            </a-button>
         </a-row>
     </a-form-item>
 </a-form>
 
 <!-- trojan fallbacks -->
 <a-form v-for="(fallback, index) in inbound.settings.fallbacks" layout="inline">
-<a-divider>
-    fallback[[ index + 1 ]]
-    <a-icon type="delete" @click="() => inbound.settings.delTrojanFallback(index)"
-            style="color: rgb(255, 77, 79);cursor: pointer;"/>
-</a-divider>
-<a-form-item label="Name">
-    <a-input v-model="fallback.name"></a-input>
-</a-form-item>
-<a-form-item label="Alpn">
-    <a-input v-model="fallback.alpn"></a-input>
-</a-form-item>
-<a-form-item label="Path">
-    <a-input v-model="fallback.path"></a-input>
-</a-form-item>
-<a-form-item label="Dest">
-    <a-input v-model="fallback.dest"></a-input>
-</a-form-item>
-<a-form-item label="xVer">
-    <a-input type="number" v-model.number="fallback.xver"></a-input>
-</a-form-item>
-<a-divider v-if="inbound.settings.fallbacks.length - 1 === index"/>
+    <a-divider>
+        fallback[[ index + 1 ]]
+        <a-icon type="delete" @click="() => inbound.settings.delTrojanFallback(index)"
+                style="color: rgb(255, 77, 79);cursor: pointer;"/>
+    </a-divider>
+    <a-form-item label="Name">
+        <a-input v-model="fallback.name"></a-input>
+    </a-form-item>
+    <a-form-item label="Alpn">
+        <a-input v-model="fallback.alpn"></a-input>
+    </a-form-item>
+    <a-form-item label="Path">
+        <a-input v-model="fallback.path"></a-input>
+    </a-form-item>
+    <a-form-item label="Dest">
+        <a-input v-model="fallback.dest"></a-input>
+    </a-form-item>
+    <a-form-item label="xVer">
+        <a-input type="number" v-model.number="fallback.xver"></a-input>
+    </a-form-item>
+    <a-divider v-if="inbound.settings.fallbacks.length - 1 === index"/>
 </a-form>
 {{end}}

+ 24 - 40
web/html/xui/form/protocol/vless.html

@@ -1,6 +1,7 @@
 {{define "form/vless"}}
 <a-form layout="inline">
-<a-collapse activeKey="0" v-for="(vless, index) in inbound.settings.vlesses"
+<label>{{ i18n "clients"}}</label>
+<a-collapse activeKey="0"  v-for="(vless, index) in inbound.settings.vlesses"
 :key="`vless-${index}`">
 
     <a-collapse-panel :class="getHeaderStyle(vless.email)" :header="getHeaderText(vless.email)">
@@ -26,20 +27,20 @@
         <a-form-item label="ID">
             <a-input v-model.trim="vless.id"></a-input>
         </a-form-item>
-		<a-form-item v-if="inbound.xtls" label="flow">
+		<a-form-item v-if="inbound.xtls" label="Flow">
             <a-select v-model="inbound.settings.vlesses[index].flow" style="width: 150px">
-                <a-select-option value="" selected>none</a-select-option>
+                <a-select-option value="" selected>{{ i18n "none" }}</a-select-option>
                 <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
             </a-select>
         </a-form-item>
-        <a-form-item v-else-if="inbound.canEnableTlsFlow()" label="flow" layout="inline">
+        <a-form-item v-else-if="inbound.canEnableTlsFlow()" label="Flow" layout="inline">
             <a-select v-model="inbound.settings.vlesses[index].flow" style="width: 150px">
-                <a-select-option value="" selected>none</a-select-option>
+                <a-select-option value="" selected>{{ i18n "none" }}</a-select-option>
                 <a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
             </a-select>
         </a-form-item>
-        <a-form-item v-if="inbound.tls" label="utls" layout="inline">
-                <a-select v-model="inbound.settings.vlesses[index].fingerprint" label="utls" style="width: 150px">
+        <a-form-item v-if="inbound.tls" label="uTLS" layout="inline">
+                <a-select v-model="inbound.settings.vlesses[index].fingerprint" label="uTLS" style="width: 150px">
                     <a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
                 </a-select>
         </a-form-item>
@@ -71,7 +72,7 @@
         <a-form layout="inline">
             <a-tooltip v-if="vless._totalGB > 0">
                 <template slot="title">
-                   {{ i18n "pages.inbounds.resetTraffic" }}
+                    {{ i18n "pages.inbounds.resetTraffic" }}
                 </template>
                 <span style="color: #FF4D4F">
                     <a-icon type="delete" @click="resetClientTraffic(vless,$event)"></a-icon>
@@ -79,43 +80,26 @@
             </a-tooltip>
             <a-tag color="blue">[[ sizeFormat(getUpStats(vless.email)) ]] / [[ sizeFormat(getDownStats(vless.email)) ]]</a-tag>
             <a-tag v-if="vless._totalGB > 0" color="red">used : [[ sizeFormat(getUpStats(vless.email) + getDownStats(vless.email)) ]]</a-tag>
-            <a-tag>
-                <svg
-    
-                    @click="addClient(inbound.protocol,vless, inbound.settings.vlesses)"
-                    xmlns="http://www.w3.org/2000/svg"
-                    viewBox="0 0 22 22"
-                    width="22"
-                    height="22"
-                    class="mt-2 cursor-pointer"
-                    >
+
+            <a-tag v-show="inbound.settings.vlesses.length > 1" @click="removeClient(index, inbound.settings.vlesses)">
+                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" width="22" height="22" class="mt-2 cursor-pointer">
                     <path fill="none" d="M0 0h24v24H0z" />
-                    <path
-                    fill="green"
-                    d="M11 11V7h2v4h4v2h-4v4h-2v-4H7v-2h4zm1 11C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"
+                    <path fill="#EC4899"
+                    d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-9.414l2.828-2.829 1.415 1.415L13.414 12l2.829 2.828-1.415 1.415L12 13.414l-2.828 2.829-1.415-1.415L10.586 12 7.757 9.172l1.415-1.415L12 10.586z"
                     />
                 </svg>
             </a-tag>
-            <a-tag v-show="inbound.settings.vlesses.length > 1">
-                <svg
-                @click="removeClient(index, inbound.settings.vlesses)"
-                xmlns="http://www.w3.org/2000/svg"
-                viewBox="0 0 22 22"
-                width="22"
-                height="22"
-                class="mt-2 cursor-pointer"
-                >
-                <path fill="none" d="M0 0h24v24H0z" />
-                <path
-                fill="#EC4899"
-                d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-9.414l2.828-2.829 1.415 1.415L13.414 12l2.829 2.828-1.415 1.415L12 13.414l-2.828 2.829-1.415-1.415L10.586 12 7.757 9.172l1.415-1.415L12 10.586z"
-                />
-                </svg>
-            </a-tag>
         </a-form>
-
-
-    </a-form>
+    </a-collapse-panel>
+</a-collapse>
+<a-tag @click="addClient(inbound.protocol, inbound.settings.vlesses)">
+    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" class="ml-2 cursor-pointer">
+        <path fill="none" d="M0 0h24v24H0z" />
+        <path fill="green"
+        d="M11 11V7h2v4h4v2h-4v4h-2v-4H7v-2h4zm1 11C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"
+        />
+    </svg>
+</a-tag>
 
 <a-form layout="inline">
     <a-form-item label="Fallbacks">

+ 23 - 44
web/html/xui/form/protocol/vmess.html

@@ -1,5 +1,6 @@
 {{define "form/vmess"}}
 <a-form layout="inline">
+<label>{{ i18n "clients"}}</label>
 <a-collapse activeKey="0"  v-for="(vmess, index) in inbound.settings.vmesses"
 :key="`vmess-${index}`">
     <a-collapse-panel :class="getHeaderStyle(vmess.email)" :header="getHeaderText(vmess.email)">
@@ -56,7 +57,7 @@
         <a-form layout="inline">
             <a-tooltip v-if="vmess._totalGB > 0">
                 <template slot="title">
-                  {{ i18n "pages.inbounds.resetTraffic" }}
+                    {{ i18n "pages.inbounds.resetTraffic" }}
                 </template>
                 <span style="color: #FF4D4F">
                     <a-icon type="delete" @click="resetClientTraffic(vmess,$event)"></a-icon>
@@ -64,56 +65,34 @@
             </a-tooltip>
             <a-tag color="blue">[[ sizeFormat(getUpStats(vmess.email)) ]] / [[ sizeFormat(getDownStats(vmess.email)) ]]</a-tag>
             <a-tag v-if="vmess._totalGB > 0" color="red">used : [[ sizeFormat(getUpStats(vmess.email) + getDownStats(vmess.email)) ]]</a-tag>
-            <a-tag>
-                <!--Add Svg Icon-->
-                <svg
-    
-                    @click="addClient(inbound.protocol,vmess, inbound.settings.vmesses)"
-                    xmlns="http://www.w3.org/2000/svg"
-                    viewBox="0 0 22 22"
-                    width="22"
-                    height="22"
-                    class="mt-2 cursor-pointer"
-                    >
-                    <path fill="none" d="M0 0h24v24H0z" />
-                    <path
-                    fill="green"
-                    d="M11 11V7h2v4h4v2h-4v4h-2v-4H7v-2h4zm1 11C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"
-                    />
-                </svg>
+                <a-tag v-show="inbound.settings.vmesses.length > 1" @click="removeClient(index, inbound.settings.vmesses)">
+                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" width="22" height="22" class="mt-2 cursor-pointer">
+                        <path fill="none" d="M0 0h24v24H0z" />
+                        <path fill="#EC4899"
+                        d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-9.414l2.828-2.829 1.415 1.415L13.414 12l2.829 2.828-1.415 1.415L12 13.414l-2.828 2.829-1.415-1.415L10.586 12 7.757 9.172l1.415-1.415L12 10.586z"
+                        />
+                    </svg>
             </a-tag>
-            <a-tag v-show="inbound.settings.vmesses.length > 1">
-
-                <!--Remove Svg Icon-->
-                <svg
-                    @click="removeClient(index, inbound.settings.vmesses)"
-                    xmlns="http://www.w3.org/2000/svg"
-                    viewBox="0 0 22 22"
-                    width="22"
-                    height="22"
-                    class="mt-2 cursor-pointer"
-                    >
-                    <path fill="none" d="M0 0h24v24H0z" />
-                    <path
-                    fill="#EC4899"
-                    d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-9.414l2.828-2.829 1.415 1.415L13.414 12l2.829 2.828-1.415 1.415L12 13.414l-2.828 2.829-1.415-1.415L10.586 12 7.757 9.172l1.415-1.415L12 10.586z"
-                    />
-                </svg>
-        </a-tag>
-    </a-form>
+        </a-form>
 
 
-</a-collapse-panel>
+    </a-collapse-panel>
 
 </a-collapse>
 
+<a-tag @click="addClient(inbound.protocol, inbound.settings.vmesses)">
+    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" class="ml-2 cursor-pointer">
+        <path fill="none" d="M0 0h24v24H0z" />
+        <path fill="green"
+        d="M11 11V7h2v4h4v2h-4v4h-2v-4H7v-2h4zm1 11C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"
+        />
+    </svg>
+</a-tag>
 
-</a-form>
-</a-form>
 <a-form layout="inline">
-<a-form-item label='{{ i18n "pages.inbounds.disableInsecureEncryption" }}'>
-    <a-switch v-model.number="inbound.settings.disableInsecure"></a-switch>
-</a-form-item>
+    <a-form-item label='{{ i18n "pages.inbounds.disableInsecureEncryption" }}'>
+        <a-switch v-model.number="inbound.settings.disableInsecure"></a-switch>
+    </a-form-item>
 </a-form>
 
-{{end}}
+{{end}}

+ 4 - 18
web/html/xui/inbound_modal.html

@@ -77,7 +77,7 @@
                     this.inModal.inbound.tls = false;
                 }
             },
-            addClient(protocol,value, clients) {
+            addClient(protocol, clients) {
                 switch (protocol) {
                     case Protocols.VMESS: return clients.push(new Inbound.VmessSettings.Vmess());
                     case Protocols.VLESS: return clients.push(new Inbound.VLESSSettings.VLESS());
@@ -88,7 +88,6 @@
             removeClient(index, clients) {
                 clients.splice(index, 1);
             },
-
             async resetClientTraffic(client,event) {
                 const msg = await HttpUtil.post('/xui/inbound/resetClientTraffic/'+ client.email);
                 if (!msg.success) {
@@ -122,7 +121,6 @@
                         }
                     }
                 }
-
             },
             getDownStats(email) {
                 clientStats = this.inbound.clientStats
@@ -138,30 +136,18 @@
                 }
             },
             isClientEnable(email) {
-                clientStats = this.inbound.clientStats
-                if(clientStats.length > 0)
-                {
-                    for (const key in clientStats) {
-                        if (Object.hasOwnProperty.call(clientStats, key)) {
-                            if(clientStats[key]['email'] == email)
-                                return clientStats[key]['enable']
-
-                        }
-                    }
-                }
+                clientStats = this.dbInbound.clientStats ? this.dbInbound.clientStats.find(stats => stats.email === email) : null
+                return clientStats ? clientStats['enable'] : true
             },
-
             getHeaderText(email) {
                 if(email == "")
                     return "Add Client"
                 
                 return email + (this.isClientEnable(email) == true ? ' Active' : ' Deactive')
             },
-
             getHeaderStyle(email) {
                 return (this.isClientEnable(email) == true ? '' : 'deactive-client')
             },
-
             getNewEmail(client) {
                 var chars = 'abcdefghijklmnopqrstuvwxyz1234567890';
                 var string = '';
@@ -175,4 +161,4 @@
     });
 
 </script>
-{{end}}
+{{end}}

+ 1 - 1
web/job/stats_notify_job.go

@@ -240,7 +240,7 @@ func (j *StatsNotifyJob) getClientUsage(id string) string {
 	} else {
 		total = fmt.Sprintf("%s", common.FormatTraffic((traffic.Total)))
 	}
-	output := fmt.Sprintf("💡 Active: %t\r\n📧 Email: %s\r\n🔼 Upload↑: %s\r\n🔽 Download↓: %s\r\n🔄 Total: %s / %s\r\n📅 Expire in: %s\r\n",
+	output := fmt.Sprintf("💡 Active: %t\r\n📧 Email: %s\r\n🔼 Download↑: %s\r\n🔽 Upload↓: %s\r\n🔄 Total: %s / %s\r\n📅 Expire in: %s\r\n",
 		traffic.Enable, traffic.Email, common.FormatTraffic(traffic.Up), common.FormatTraffic(traffic.Down), common.FormatTraffic((traffic.Up + traffic.Down)),
 		total, expiryTime)
 

+ 10 - 10
web/service/inbound.go

@@ -238,9 +238,9 @@ func (s *InboundService) AddTraffic(traffics []*xray.Traffic) (err error) {
 	for _, traffic := range traffics {
 		if traffic.IsInbound {
 			err = tx.Where("tag = ?", traffic.Tag).
-				UpdateColumn("up", gorm.Expr("up + ?", traffic.Up)).
-				UpdateColumn("down", gorm.Expr("down + ?", traffic.Down)).
-				Error
+				UpdateColumns(map[string]interface{}{
+					"up":   gorm.Expr("up + ?", traffic.Up),
+					"down": gorm.Expr("down + ?", traffic.Down)}).Error
 			if err != nil {
 				return
 			}
@@ -298,11 +298,12 @@ func (s *InboundService) AddClientTraffic(traffics []*xray.ClientTraffic) (err e
 			}
 		}
 		if tx.Where("inbound_id = ?", inbound.Id).Where("email = ?", traffic.Email).
-			UpdateColumn("enable", true).
-			UpdateColumn("expiry_time", traffic.ExpiryTime).
-			UpdateColumn("total", traffic.Total).
-			UpdateColumn("up", gorm.Expr("up + ?", traffic.Up)).
-			UpdateColumn("down", gorm.Expr("down + ?", traffic.Down)).RowsAffected == 0 {
+			UpdateColumns(map[string]interface{}{
+				"enable":      true,
+				"expiry_time": traffic.ExpiryTime,
+				"total":       traffic.Total,
+				"up":          gorm.Expr("up + ?", traffic.Up),
+				"down":        gorm.Expr("down + ?", traffic.Down)}).RowsAffected == 0 {
 			err = tx.Create(traffic).Error
 		}
 
@@ -374,8 +375,7 @@ func (s *InboundService) ResetClientTraffic(clientEmail string) error {
 
 	result := db.Model(xray.ClientTraffic{}).
 		Where("email = ?", clientEmail).
-		Update("up", 0).
-		Update("down", 0)
+		Updates(map[string]interface{}{"up": 0, "down": 0})
 
 	err := result.Error
 

+ 1 - 2
web/service/user.go

@@ -46,8 +46,7 @@ func (s *UserService) UpdateUser(id int, username string, password string) error
 	db := database.GetDB()
 	return db.Model(model.User{}).
 		Where("id = ?", id).
-		Update("username", username).
-		Update("password", password).
+		Updates(map[string]interface{}{"username": username, "password": password}).
 		Error
 }
 

+ 1 - 1
web/translation/translate.fa_IR.toml

@@ -48,7 +48,7 @@
 
 [menu]
 "dashboard" = "وضعیت سیستم"
-"inbounds" = "سروریس ها" 
+"inbounds" = "سرویس ها" 
 "setting" = "تنظیمات پنل"
 "logout" = "خروج"
 "link" = "دیگر"

+ 11 - 8
x-ui.sh

@@ -367,7 +367,7 @@ show_status() {
     check_status
     case $? in
     0)
-        echo -e "Panel state: ${green}Runing${plain}"
+        echo -e "Panel state: ${green}Running${plain}"
         show_enable_status
         ;;
     1)
@@ -402,7 +402,7 @@ check_xray_status() {
 show_xray_status() {
     check_xray_status
     if [[ $? == 0 ]]; then
-        echo -e "xray state: ${green}Runing${plain}"
+        echo -e "xray state: ${green}Running${plain}"
     else
         echo -e "xray state: ${red}Not Running${plain}"
     fi
@@ -449,11 +449,14 @@ install_acme() {
 
 #method for standalone mode
 ssl_cert_issue_standalone() {
-    #install acme first
-    install_acme
-    if [ $? -ne 0 ]; then
-        LOGE "install acme failed,please check logs"
-        exit 1
+    #check for acme.sh first
+    if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
+        echo "acme.sh could not be found. we will install it"
+        install_acme
+        if [ $? -ne 0 ]; then
+            LOGE "install acme failed, please check logs"
+            exit 1
+        fi
     fi
     #install socat second
     if [[ x"${release}" == x"centos" ]]; then
@@ -636,7 +639,7 @@ show_usage() {
 
 show_menu() {
     echo -e "
-  ${green}3x-ui Panel Management Script${plain}
+  ${green}3X-ui Panel Management Script${plain}
   ${green}0.${plain} Exit Script
 ————————————————
   ${green}1.${plain} Install x-ui