mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-03-21 01:55:49 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31339d6bf8 | ||
|
|
8865443438 | ||
|
|
835deb77f4 | ||
|
|
6a7c3716ac | ||
|
|
15211f81b1 | ||
|
|
b3f7a6572e | ||
|
|
6f28a3a2fe | ||
|
|
896cc5386c | ||
|
|
76f70ce1e9 | ||
|
|
6aa3c8d4a2 |
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -38,7 +38,7 @@ jobs:
|
|||||||
- name: package
|
- name: package
|
||||||
run: tar -zcvf x-ui-linux-amd64.tar.gz x-ui
|
run: tar -zcvf x-ui-linux-amd64.tar.gz x-ui
|
||||||
- name: upload
|
- name: upload
|
||||||
uses: svenstaro/upload-release-action@2.5.0
|
uses: svenstaro/upload-release-action@2.6.0
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
@@ -80,7 +80,7 @@ jobs:
|
|||||||
- name: package
|
- name: package
|
||||||
run: tar -zcvf x-ui-linux-arm64.tar.gz x-ui
|
run: tar -zcvf x-ui-linux-arm64.tar.gz x-ui
|
||||||
- name: upload
|
- name: upload
|
||||||
uses: svenstaro/upload-release-action@2.5.0
|
uses: svenstaro/upload-release-action@2.6.0
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.6.0
|
1.6.1
|
||||||
6
go.mod
6
go.mod
@@ -11,7 +11,7 @@ require (
|
|||||||
github.com/mymmrac/telego v0.24.0
|
github.com/mymmrac/telego v0.24.0
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.2.1
|
github.com/nicksnyder/go-i18n/v2 v2.2.1
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||||
github.com/pelletier/go-toml/v2 v2.0.7
|
github.com/pelletier/go-toml/v2 v2.0.8
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/shirou/gopsutil/v3 v3.23.4
|
github.com/shirou/gopsutil/v3 v3.23.4
|
||||||
github.com/xtls/xray-core v1.8.1
|
github.com/xtls/xray-core v1.8.1
|
||||||
@@ -25,7 +25,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.2.1 // indirect
|
github.com/BurntSushi/toml v1.2.1 // indirect
|
||||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||||
github.com/bytedance/sonic v1.8.9 // indirect
|
github.com/bytedance/sonic v1.8.10 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
github.com/fasthttp/router v1.4.19 // indirect
|
github.com/fasthttp/router v1.4.19 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
@@ -64,7 +64,7 @@ require (
|
|||||||
golang.org/x/crypto v0.9.0 // indirect
|
golang.org/x/crypto v0.9.0 // indirect
|
||||||
golang.org/x/net v0.10.0 // indirect
|
golang.org/x/net v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
golang.org/x/sys v0.8.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
google.golang.org/genproto v0.0.0-20230524185152-1884fd1fac28 // indirect
|
||||||
google.golang.org/protobuf v1.30.0 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
15
go.sum
15
go.sum
@@ -10,8 +10,8 @@ github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P
|
|||||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||||
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
|
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
|
||||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
github.com/bytedance/sonic v1.8.9 h1:mXB6OoHaI9OrWugkvNxWiuHTy5RCrVfxg2Nn40sf0oc=
|
github.com/bytedance/sonic v1.8.10 h1:XFSQg4/rwpQnNWSybNDr8oz6QtQY9uRGfRKDVWVsvP8=
|
||||||
github.com/bytedance/sonic v1.8.9/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
github.com/bytedance/sonic v1.8.10/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||||
@@ -116,8 +116,8 @@ github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
|
|||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
|
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||||
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||||
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
|
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
|
||||||
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
|
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
|
||||||
@@ -157,8 +157,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||||
|
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg=
|
github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg=
|
||||||
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
||||||
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
|
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
|
||||||
@@ -246,8 +247,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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/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-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
google.golang.org/genproto v0.0.0-20230524185152-1884fd1fac28 h1:+55/MuGJORMxCrkAgo2595fMAnN/4rweCuwibbqrvpc=
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
google.golang.org/genproto v0.0.0-20230524185152-1884fd1fac28/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
||||||
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
||||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
|||||||
9
web/assets/ant-design-vue@1.7.2/antd.min.css
vendored
9
web/assets/ant-design-vue@1.7.2/antd.min.css
vendored
@@ -996,7 +996,8 @@ to{transform:scale(0) translate(50%,-50%);opacity:0}
|
|||||||
.ant-menu-horizontal .ant-menu-item,.ant-menu-horizontal .ant-menu-submenu{margin-top:-1px}
|
.ant-menu-horizontal .ant-menu-item,.ant-menu-horizontal .ant-menu-submenu{margin-top:-1px}
|
||||||
.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu .ant-menu-submenu-title:hover{background-color:transparent}
|
.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu .ant-menu-submenu-title:hover{background-color:transparent}
|
||||||
.ant-menu-item-selected,.ant-menu-item-selected>a,.ant-menu-item-selected>a:hover{color:#1890ff}
|
.ant-menu-item-selected,.ant-menu-item-selected>a,.ant-menu-item-selected>a:hover{color:#1890ff}
|
||||||
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected{background: linear-gradient(90deg,#009670 0,#026247 100%);color: #fff;border-radius: 0.5rem}
|
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected{background-color: #0a7557;background-image: linear-gradient( 270deg, rgba(123, 199, 77, 0) 30%, #00ab80, rgba(123, 199, 77, 0) 100% );background-repeat: no-repeat;animation: ma-bg-move linear 6.6s infinite;/*background: linear-gradient(90deg,#009670 0,#026247 100%);*/color: #fff;border-radius: 0.5rem}
|
||||||
|
@-webkit-keyframes ma-bg-move {0% {background-position: -500px 0;}100% {background-position: 1000px 0;}}@keyframes ma-bg-move {0% {background-position: -500px 0;}50% {background-position: 1000px 0;}100% {background-position: 1000px 0;}}
|
||||||
.ant-menu-vertical-right{border-left:1px solid #e8e8e8}
|
.ant-menu-vertical-right{border-left:1px solid #e8e8e8}
|
||||||
.ant-menu-vertical-left.ant-menu-sub,.ant-menu-vertical-right.ant-menu-sub,.ant-menu-vertical.ant-menu-sub{min-width:160px;padding:0;border-right:0;transform-origin:0 0}
|
.ant-menu-vertical-left.ant-menu-sub,.ant-menu-vertical-right.ant-menu-sub,.ant-menu-vertical.ant-menu-sub{min-width:160px;padding:0;border-right:0;transform-origin:0 0}
|
||||||
.ant-menu-vertical-left.ant-menu-sub .ant-menu-item,.ant-menu-vertical-right.ant-menu-sub .ant-menu-item,.ant-menu-vertical.ant-menu-sub .ant-menu-item{left:0;margin-left:0;border-right:0}
|
.ant-menu-vertical-left.ant-menu-sub .ant-menu-item,.ant-menu-vertical-right.ant-menu-sub .ant-menu-item,.ant-menu-vertical.ant-menu-sub .ant-menu-item{left:0;margin-left:0;border-right:0}
|
||||||
@@ -1081,8 +1082,8 @@ to{transform:scale(0) translate(50%,-50%);opacity:0}
|
|||||||
.ant-menu-dark .ant-menu-item-selected{color:#fff;border-right:0}
|
.ant-menu-dark .ant-menu-item-selected{color:#fff;border-right:0}
|
||||||
.ant-menu-dark .ant-menu-item-selected:after{border-right:0}
|
.ant-menu-dark .ant-menu-item-selected:after{border-right:0}
|
||||||
.ant-menu-dark .ant-menu-item-selected .anticon,.ant-menu-dark .ant-menu-item-selected .anticon+span,.ant-menu-dark .ant-menu-item-selected>a,.ant-menu-dark .ant-menu-item-selected>a:hover{color:#ffffff}
|
.ant-menu-dark .ant-menu-item-selected .anticon,.ant-menu-dark .ant-menu-item-selected .anticon+span,.ant-menu-dark .ant-menu-item-selected>a,.ant-menu-dark .ant-menu-item-selected>a:hover{color:#ffffff}
|
||||||
.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected,.ant-menu.ant-menu-dark .ant-menu-item-selected{background-color:#15223a}
|
.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected,.ant-menu.ant-menu-dark .ant-menu-item-selected{background-color:#0a7557}
|
||||||
.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-active,.ant-menu.ant-menu-dark .ant-menu-item-active{background-color:#38383800}
|
/*.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-active,.ant-menu.ant-menu-dark .ant-menu-item-active{background-color:#0a7557}*/
|
||||||
.ant-menu-dark .ant-menu-item-disabled,.ant-menu-dark .ant-menu-item-disabled>a,.ant-menu-dark .ant-menu-submenu-disabled,.ant-menu-dark .ant-menu-submenu-disabled>a{color:hsla(0,0%,100%,.35)!important;opacity:.8}
|
.ant-menu-dark .ant-menu-item-disabled,.ant-menu-dark .ant-menu-item-disabled>a,.ant-menu-dark .ant-menu-submenu-disabled,.ant-menu-dark .ant-menu-submenu-disabled>a{color:hsla(0,0%,100%,.35)!important;opacity:.8}
|
||||||
.ant-menu-dark .ant-menu-item-disabled>.ant-menu-submenu-title,.ant-menu-dark .ant-menu-submenu-disabled>.ant-menu-submenu-title{color:hsla(0,0%,100%,.35)!important}
|
.ant-menu-dark .ant-menu-item-disabled>.ant-menu-submenu-title,.ant-menu-dark .ant-menu-submenu-disabled>.ant-menu-submenu-title{color:hsla(0,0%,100%,.35)!important}
|
||||||
.ant-menu-dark .ant-menu-item-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-item-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before{background:hsla(0,0%,100%,.35)!important}
|
.ant-menu-dark .ant-menu-item-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-item-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before{background:hsla(0,0%,100%,.35)!important}
|
||||||
@@ -3231,7 +3232,7 @@ textarea.ant-input-number{max-width:100%;height:auto;min-height:32px;line-height
|
|||||||
.ant-input-number-handler-down-inner:before,.ant-input-number-handler-up-inner:before{display:none}
|
.ant-input-number-handler-down-inner:before,.ant-input-number-handler-up-inner:before{display:none}
|
||||||
.ant-input-number-handler-down-inner .ant-input-number-handler-down-inner-icon,.ant-input-number-handler-down-inner .ant-input-number-handler-up-inner-icon,.ant-input-number-handler-up-inner .ant-input-number-handler-down-inner-icon,.ant-input-number-handler-up-inner .ant-input-number-handler-up-inner-icon{display:block}
|
.ant-input-number-handler-down-inner .ant-input-number-handler-down-inner-icon,.ant-input-number-handler-down-inner .ant-input-number-handler-up-inner-icon,.ant-input-number-handler-up-inner .ant-input-number-handler-down-inner-icon,.ant-input-number-handler-up-inner .ant-input-number-handler-up-inner-icon{display:block}
|
||||||
.ant-input-number-focused,.ant-input-number:hover{border-color:rgb(0, 150, 112) !important;border-right-width:1px!important}
|
.ant-input-number-focused,.ant-input-number:hover{border-color:rgb(0, 150, 112) !important;border-right-width:1px!important}
|
||||||
.ant-input-number-focused{outline:0;box-shadow:0 0 0 2px rgba(24,144,255,.2)}
|
.ant-input-number-focused{outline:0;box-shadow:rgba(0, 150, 112, 0.2) 0px 0px 0px 2px}
|
||||||
.ant-input-number-disabled{color:rgba(0,0,0,.25);background-color:#f5f5f5;cursor:not-allowed;opacity:1}
|
.ant-input-number-disabled{color:rgba(0,0,0,.25);background-color:#f5f5f5;cursor:not-allowed;opacity:1}
|
||||||
.ant-input-number-disabled:hover{border-color:#d9d9d9;border-right-width:1px!important}
|
.ant-input-number-disabled:hover{border-color:#d9d9d9;border-right-width:1px!important}
|
||||||
.ant-input-number-disabled .ant-input-number-input{cursor:not-allowed}
|
.ant-input-number-disabled .ant-input-number-input{cursor:not-allowed}
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-dark-box-nohover{
|
.ant-card-dark-box-nohover{
|
||||||
|
margin-top: .5rem;
|
||||||
padding: 0 20px 20px !important;
|
padding: 0 20px 20px !important;
|
||||||
box-shadow: 0 1px 10px -1px rgb(154 175 238 / 0%) !important;
|
box-shadow: 0 1px 10px -1px rgb(154 175 238 / 0%) !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ const ONE_TB = ONE_GB * 1024;
|
|||||||
const ONE_PB = ONE_TB * 1024;
|
const ONE_PB = ONE_TB * 1024;
|
||||||
|
|
||||||
function sizeFormat(size) {
|
function sizeFormat(size) {
|
||||||
if (size < ONE_KB) {
|
if (size < 0) {
|
||||||
|
return "0 B";
|
||||||
|
} else if (size < ONE_KB) {
|
||||||
return size.toFixed(0) + " B";
|
return size.toFixed(0) + " B";
|
||||||
} else if (size < ONE_MB) {
|
} else if (size < ONE_MB) {
|
||||||
return (size / ONE_KB).toFixed(2) + " KB";
|
return (size / ONE_KB).toFixed(2) + " KB";
|
||||||
@@ -20,6 +22,23 @@ function sizeFormat(size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cpuSpeedFormat(speed) {
|
||||||
|
if (speed > 1000) {
|
||||||
|
const GHz = speed / 1000;
|
||||||
|
return GHz.toFixed(2) + " GHz";
|
||||||
|
} else {
|
||||||
|
return speed.toFixed(2) + " MHz";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cpuCoreFormat(cores) {
|
||||||
|
if (cores === 1) {
|
||||||
|
return "1 Core";
|
||||||
|
} else {
|
||||||
|
return cores + " Cores";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function base64(str) {
|
function base64(str) {
|
||||||
return Base64.encode(str);
|
return Base64.encode(str);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
:stroke-color="status.cpu.color"
|
:stroke-color="status.cpu.color"
|
||||||
:class="themeSwitcher.darkCardClass"
|
:class="themeSwitcher.darkCardClass"
|
||||||
:percent="status.cpu.percent"></a-progress>
|
:percent="status.cpu.percent"></a-progress>
|
||||||
<div>CPU</div>
|
<div>CPU: [[ cpuCoreFormat(status.cpuCores) ]]</div>
|
||||||
|
<div>Speed: [[ cpuSpeedFormat(status.cpuSpeedMhz) ]]</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="12" style="text-align: center">
|
<a-col :span="12" style="text-align: center">
|
||||||
<a-progress type="dashboard" status="normal"
|
<a-progress type="dashboard" status="normal"
|
||||||
@@ -84,14 +85,10 @@
|
|||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
||||||
{{ i18n "pages.index.operationHours" }}:
|
{{ i18n "menu.link" }}:
|
||||||
<a-tag color="green">[[ formatSecond(status.uptime) ]]</a-tag>
|
<a-tag color="blue" style="cursor: pointer;" @click="openLogs(20)">{{ i18n "pages.index.logs" }}</a-tag>
|
||||||
<a-tooltip>
|
<a-tag color="blue" style="cursor: pointer;" @click="openConfig">{{ i18n "pages.index.config" }}</a-tag>
|
||||||
<template slot="title">
|
<a-tag color="blue" style="cursor: pointer;" @click="openBackup">{{ i18n "pages.index.backup" }}</a-tag>
|
||||||
{{ i18n "pages.index.operationHoursDesc" }}
|
|
||||||
</template>
|
|
||||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
|
||||||
</a-tooltip>
|
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
@@ -111,26 +108,69 @@
|
|||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
||||||
{{ i18n "menu.link" }}:
|
<a-row>
|
||||||
<a-tag color="blue" style="cursor: pointer;" @click="openLogs(20)">{{ i18n "pages.index.logs" }}</a-tag>
|
<a-col :span="12">
|
||||||
<a-tag color="blue" style="cursor: pointer;" @click="openConfig">{{ i18n "pages.index.config" }}</a-tag>
|
{{ i18n "pages.index.systemLoad" }}: [[ status.loads[0] ]] | [[ status.loads[1] ]] | [[ status.loads[2] ]]
|
||||||
<a-tag color="blue" style="cursor: pointer;" @click="openBackup">{{ i18n "pages.index.backup" }}</a-tag>
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
{{ i18n "pages.index.systemLoadDesc" }}
|
||||||
|
</template>
|
||||||
|
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
{{ i18n "pages.index.operationHours" }}:
|
||||||
|
<a-tag color="green">[[ formatSecond(status.uptime) ]]</a-tag>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
||||||
{{ i18n "pages.index.systemLoad" }}: [[ status.loads[0] ]] | [[ status.loads[1] ]] | [[ status.loads[2] ]]
|
<a-row>
|
||||||
|
<a-col :span="12">
|
||||||
|
IPv4:
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
[[ status.publicIP.ipv4 ]]
|
||||||
|
</template>
|
||||||
|
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
IPv6:
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
[[ status.publicIP.ipv6 ]]
|
||||||
|
</template>
|
||||||
|
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
||||||
TCP / UDP {{ i18n "pages.index.connectionCount" }}: [[ status.tcpCount ]] / [[ status.udpCount ]]
|
<a-row>
|
||||||
<a-tooltip>
|
<a-col :span="12">
|
||||||
<template slot="title">
|
TCP: [[ status.tcpCount ]]
|
||||||
{{ i18n "pages.index.connectionCountDesc" }}
|
<a-tooltip>
|
||||||
</template>
|
<template slot="title">
|
||||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
{{ i18n "pages.index.connectionTcpCountDesc" }}
|
||||||
</a-tooltip>
|
</template>
|
||||||
|
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
UDP: [[ status.udpCount ]]
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
{{ i18n "pages.index.connectionUdpCountDesc" }}
|
||||||
|
</template>
|
||||||
|
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
@@ -138,7 +178,7 @@
|
|||||||
<a-row>
|
<a-row>
|
||||||
<a-col :span="12">
|
<a-col :span="12">
|
||||||
<a-icon type="arrow-up"></a-icon>
|
<a-icon type="arrow-up"></a-icon>
|
||||||
[[ sizeFormat(status.netIO.up) ]] / S
|
[[ sizeFormat(status.netIO.up) ]]/S
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.upSpeed" }}
|
{{ i18n "pages.index.upSpeed" }}
|
||||||
@@ -148,7 +188,7 @@
|
|||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="12">
|
<a-col :span="12">
|
||||||
<a-icon type="arrow-down"></a-icon>
|
<a-icon type="arrow-down"></a-icon>
|
||||||
[[ sizeFormat(status.netIO.down) ]] / S
|
[[ sizeFormat(status.netIO.down) ]]/S
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.downSpeed" }}
|
{{ i18n "pages.index.downSpeed" }}
|
||||||
@@ -294,11 +334,14 @@
|
|||||||
class Status {
|
class Status {
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
this.cpu = new CurTotal(0, 0);
|
this.cpu = new CurTotal(0, 0);
|
||||||
|
this.cpuCores = 0;
|
||||||
|
this.cpuSpeedMhz = 0;
|
||||||
this.disk = new CurTotal(0, 0);
|
this.disk = new CurTotal(0, 0);
|
||||||
this.loads = [0, 0, 0];
|
this.loads = [0, 0, 0];
|
||||||
this.mem = new CurTotal(0, 0);
|
this.mem = new CurTotal(0, 0);
|
||||||
this.netIO = { up: 0, down: 0 };
|
this.netIO = { up: 0, down: 0 };
|
||||||
this.netTraffic = { sent: 0, recv: 0 };
|
this.netTraffic = { sent: 0, recv: 0 };
|
||||||
|
this.publicIP = { ipv4: 0, ipv6: 0 };
|
||||||
this.swap = new CurTotal(0, 0);
|
this.swap = new CurTotal(0, 0);
|
||||||
this.tcpCount = 0;
|
this.tcpCount = 0;
|
||||||
this.udpCount = 0;
|
this.udpCount = 0;
|
||||||
@@ -309,11 +352,14 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.cpu = new CurTotal(data.cpu, 100);
|
this.cpu = new CurTotal(data.cpu, 100);
|
||||||
|
this.cpuCores = data.cpuCores;
|
||||||
|
this.cpuSpeedMhz = data.cpuSpeedMhz;
|
||||||
this.disk = new CurTotal(data.disk.current, data.disk.total);
|
this.disk = new CurTotal(data.disk.current, data.disk.total);
|
||||||
this.loads = data.loads.map(load => toFixed(load, 2));
|
this.loads = data.loads.map(load => toFixed(load, 2));
|
||||||
this.mem = new CurTotal(data.mem.current, data.mem.total);
|
this.mem = new CurTotal(data.mem.current, data.mem.total);
|
||||||
this.netIO = data.netIO;
|
this.netIO = data.netIO;
|
||||||
this.netTraffic = data.netTraffic;
|
this.netTraffic = data.netTraffic;
|
||||||
|
this.publicIP = data.publicIP;
|
||||||
this.swap = new CurTotal(data.swap.current, data.swap.total);
|
this.swap = new CurTotal(data.swap.current, data.swap.total);
|
||||||
this.tcpCount = data.tcpCount;
|
this.tcpCount = data.tcpCount;
|
||||||
this.udpCount = data.udpCount;
|
this.udpCount = data.udpCount;
|
||||||
|
|||||||
@@ -26,14 +26,32 @@
|
|||||||
|
|
||||||
.alert-msg {
|
.alert-msg {
|
||||||
color: rgb(194, 117, 18);
|
color: rgb(194, 117, 18);
|
||||||
font-weight: bold;
|
font-weight: normal;
|
||||||
font-size: 20px;
|
font-size: 16px;
|
||||||
margin-top: 5px;
|
padding: .5rem 1rem;
|
||||||
padding: 16px 6px;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-bottom: 1px solid;
|
background: rgb(255 145 0 / 15%);
|
||||||
|
margin: 1.5rem 2.5rem 0rem 2.5rem;
|
||||||
|
border-radius: .5rem;
|
||||||
|
transition: all 0.5s;
|
||||||
|
animation: signal 3s cubic-bezier(0.18, 0.89, 0.32, 1.28) infinite;
|
||||||
|
}
|
||||||
|
.alert-msg:hover {
|
||||||
|
cursor: default;
|
||||||
|
transition-duration: .3s;
|
||||||
|
animation: signal 0.9s ease infinite;
|
||||||
|
}
|
||||||
|
@keyframes signal{
|
||||||
|
0%{
|
||||||
|
box-shadow: 0 0 0 0 rgba(194, 118, 18, 0.5);
|
||||||
|
}
|
||||||
|
50%{
|
||||||
|
box-shadow: 0 0 0 6px rgba(0 ,0,0,0);
|
||||||
|
}
|
||||||
|
100%{
|
||||||
|
box-shadow: 0 0 0 6px rgba(0 ,0,0,0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-msg > i {
|
.alert-msg > i {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sync"
|
||||||
"x-ui/database"
|
"x-ui/database"
|
||||||
"x-ui/database/model"
|
"x-ui/database/model"
|
||||||
"x-ui/logger"
|
"x-ui/logger"
|
||||||
@@ -20,34 +21,38 @@ import (
|
|||||||
|
|
||||||
type CheckClientIpJob struct {
|
type CheckClientIpJob struct {
|
||||||
xrayService service.XrayService
|
xrayService service.XrayService
|
||||||
|
AllowedIps []string
|
||||||
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
var job *CheckClientIpJob
|
var job *CheckClientIpJob
|
||||||
var disAllowedIps []string
|
var AllowedIps []string
|
||||||
|
var ipRegx *regexp.Regexp = regexp.MustCompile(`[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+`)
|
||||||
|
var emailRegx *regexp.Regexp = regexp.MustCompile(`email:.+`)
|
||||||
|
|
||||||
func NewCheckClientIpJob() *CheckClientIpJob {
|
func NewCheckClientIpJob() *CheckClientIpJob {
|
||||||
job = new(CheckClientIpJob)
|
job := &CheckClientIpJob{}
|
||||||
return job
|
return job
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *CheckClientIpJob) Run() {
|
func (j *CheckClientIpJob) Run() {
|
||||||
logger.Debug("Check Client IP Job...")
|
logger.Debug("Check Client IP Job...")
|
||||||
processLogFile()
|
j.processLogFile()
|
||||||
|
|
||||||
// disAllowedIps = []string{"192.168.1.183","192.168.1.197"}
|
// AllowedIps = []string{"192.168.1.183","192.168.1.197"}
|
||||||
blockedIps := []byte(strings.Join(disAllowedIps, ","))
|
allowedIps := []byte(strings.Join(j.getAllowedIps(), ","))
|
||||||
|
|
||||||
// check if file exists, if not create one
|
// check if file exists, if not create one
|
||||||
_, err := os.Stat(xray.GetBlockedIPsPath())
|
_, err := os.Stat(xray.GetAllowedIPsPath())
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
_, err = os.OpenFile(xray.GetBlockedIPsPath(), os.O_RDWR|os.O_CREATE, 0755)
|
_, err = os.OpenFile(xray.GetAllowedIPsPath(), os.O_RDWR|os.O_CREATE, 0755)
|
||||||
checkError(err)
|
checkError(err)
|
||||||
}
|
}
|
||||||
err = os.WriteFile(xray.GetBlockedIPsPath(), blockedIps, 0755)
|
err = os.WriteFile(xray.GetAllowedIPsPath(), allowedIps, 0755)
|
||||||
checkError(err)
|
checkError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func processLogFile() {
|
func (j *CheckClientIpJob) processLogFile() {
|
||||||
accessLogPath := GetAccessLogPath()
|
accessLogPath := GetAccessLogPath()
|
||||||
if accessLogPath == "" {
|
if accessLogPath == "" {
|
||||||
logger.Warning("access.log doesn't exist in your config.json")
|
logger.Warning("access.log doesn't exist in your config.json")
|
||||||
@@ -65,8 +70,6 @@ func processLogFile() {
|
|||||||
|
|
||||||
lines := strings.Split(string(data), "\n")
|
lines := strings.Split(string(data), "\n")
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
ipRegx, _ := regexp.Compile(`[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+`)
|
|
||||||
emailRegx, _ := regexp.Compile(`email:.+`)
|
|
||||||
|
|
||||||
matchesIp := ipRegx.FindString(line)
|
matchesIp := ipRegx.FindString(line)
|
||||||
if len(matchesIp) > 0 {
|
if len(matchesIp) > 0 {
|
||||||
@@ -81,19 +84,13 @@ func processLogFile() {
|
|||||||
}
|
}
|
||||||
matchesEmail = strings.TrimSpace(strings.Split(matchesEmail, "email: ")[1])
|
matchesEmail = strings.TrimSpace(strings.Split(matchesEmail, "email: ")[1])
|
||||||
|
|
||||||
if InboundClientIps[matchesEmail] != nil {
|
if !contains(InboundClientIps[matchesEmail], ip) {
|
||||||
if contains(InboundClientIps[matchesEmail], ip) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip)
|
InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
disAllowedIps = []string{}
|
j.setAllowedIps([]string{})
|
||||||
|
|
||||||
for clientEmail, ips := range InboundClientIps {
|
for clientEmail, ips := range InboundClientIps {
|
||||||
inboundClientIps, err := GetInboundClientIps(clientEmail)
|
inboundClientIps, err := GetInboundClientIps(clientEmail)
|
||||||
@@ -102,7 +99,7 @@ func processLogFile() {
|
|||||||
addInboundClientIps(clientEmail, ips)
|
addInboundClientIps(clientEmail, ips)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
updateInboundClientIps(inboundClientIps, clientEmail, ips)
|
j.updateInboundClientIps(inboundClientIps, clientEmail, ips)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -115,6 +112,7 @@ func processLogFile() {
|
|||||||
stop <- true
|
stop <- true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAccessLogPath() string {
|
func GetAccessLogPath() string {
|
||||||
|
|
||||||
config, err := os.ReadFile(xray.GetConfigPath())
|
config, err := os.ReadFile(xray.GetConfigPath())
|
||||||
@@ -135,20 +133,22 @@ func GetAccessLogPath() string {
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkError(e error) {
|
func checkError(e error) {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
logger.Warning("client ip job err:", e)
|
logger.Warning("client ip job err:", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func contains(s []string, str string) bool {
|
func contains(s []string, str string) bool {
|
||||||
for _, v := range s {
|
for _, v := range s {
|
||||||
if v == str {
|
if v == str {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetInboundClientIps(clientEmail string) (*model.InboundClientIps, error) {
|
func GetInboundClientIps(clientEmail string) (*model.InboundClientIps, error) {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
InboundClientIps := &model.InboundClientIps{}
|
InboundClientIps := &model.InboundClientIps{}
|
||||||
@@ -158,6 +158,7 @@ func GetInboundClientIps(clientEmail string) (*model.InboundClientIps, error) {
|
|||||||
}
|
}
|
||||||
return InboundClientIps, nil
|
return InboundClientIps, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addInboundClientIps(clientEmail string, ips []string) error {
|
func addInboundClientIps(clientEmail string, ips []string) error {
|
||||||
inboundClientIps := &model.InboundClientIps{}
|
inboundClientIps := &model.InboundClientIps{}
|
||||||
jsonIps, err := json.Marshal(ips)
|
jsonIps, err := json.Marshal(ips)
|
||||||
@@ -170,10 +171,10 @@ func addInboundClientIps(clientEmail string, ips []string) error {
|
|||||||
tx := db.Begin()
|
tx := db.Begin()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err == nil {
|
if r := recover(); r != nil {
|
||||||
tx.Commit()
|
|
||||||
} else {
|
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
|
} else {
|
||||||
|
tx.Commit()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -183,13 +184,7 @@ func addInboundClientIps(clientEmail string, ips []string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmail string, ips []string) error {
|
func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmail string, ips []string) error {
|
||||||
|
|
||||||
jsonIps, err := json.Marshal(ips)
|
|
||||||
checkError(err)
|
|
||||||
|
|
||||||
inboundClientIps.ClientEmail = clientEmail
|
|
||||||
inboundClientIps.Ips = string(jsonIps)
|
|
||||||
|
|
||||||
// check inbound limitation
|
// check inbound limitation
|
||||||
inbound, err := GetInboundByEmail(clientEmail)
|
inbound, err := GetInboundByEmail(clientEmail)
|
||||||
@@ -206,17 +201,22 @@ func updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmai
|
|||||||
|
|
||||||
for _, client := range clients {
|
for _, client := range clients {
|
||||||
if client.Email == clientEmail {
|
if client.Email == clientEmail {
|
||||||
|
|
||||||
limitIp := client.LimitIP
|
limitIp := client.LimitIP
|
||||||
|
|
||||||
if limitIp < len(ips) && limitIp != 0 && inbound.Enable {
|
if limitIp < len(ips) && limitIp != 0 && inbound.Enable {
|
||||||
|
for _, ip := range ips[:limitIp] {
|
||||||
disAllowedIps = append(disAllowedIps, ips[limitIp:]...)
|
j.addAllowedIp(ip)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.Debug("disAllowedIps ", disAllowedIps)
|
|
||||||
sort.Strings(disAllowedIps)
|
jsonIps, err := json.Marshal(ips) // marshal the possibly truncated list of IPs
|
||||||
|
checkError(err)
|
||||||
|
|
||||||
|
inboundClientIps.ClientEmail = clientEmail
|
||||||
|
inboundClientIps.Ips = string(jsonIps)
|
||||||
|
|
||||||
|
logger.Debug("Allowed IPs: ", ips)
|
||||||
|
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
err = db.Save(inboundClientIps).Error
|
err = db.Save(inboundClientIps).Error
|
||||||
@@ -225,6 +225,25 @@ func updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmai
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *CheckClientIpJob) setAllowedIps(ips []string) {
|
||||||
|
j.mutex.Lock()
|
||||||
|
defer j.mutex.Unlock()
|
||||||
|
j.AllowedIps = ips
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *CheckClientIpJob) addAllowedIp(ip string) {
|
||||||
|
j.mutex.Lock()
|
||||||
|
defer j.mutex.Unlock()
|
||||||
|
j.AllowedIps = append(j.AllowedIps, ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *CheckClientIpJob) getAllowedIps() []string {
|
||||||
|
j.mutex.Lock()
|
||||||
|
defer j.mutex.Unlock()
|
||||||
|
return j.AllowedIps
|
||||||
|
}
|
||||||
|
|
||||||
func DisableInbound(id int) error {
|
func DisableInbound(id int) error {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
result := db.Model(model.Inbound{}).
|
result := db.Model(model.Inbound{}).
|
||||||
@@ -278,7 +297,7 @@ func LimitDevice() {
|
|||||||
srcPort = portRegx.FindString(data[1])
|
srcPort = portRegx.FindString(data[1])
|
||||||
srcPort = strings.Replace(srcPort, ":", "", -1)
|
srcPort = strings.Replace(srcPort, ":", "", -1)
|
||||||
|
|
||||||
if contains(disAllowedIps, srcIp) {
|
if contains(AllowedIps, srcIp) {
|
||||||
dropCmd := cmd.NewCmd("bash", "-c", "ss -K dport = "+srcPort)
|
dropCmd := cmd.NewCmd("bash", "-c", "ss -K dport = "+srcPort)
|
||||||
dropCmd.Start()
|
dropCmd.Start()
|
||||||
|
|
||||||
|
|||||||
@@ -38,9 +38,11 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
T time.Time `json:"-"`
|
T time.Time `json:"-"`
|
||||||
Cpu float64 `json:"cpu"`
|
Cpu float64 `json:"cpu"`
|
||||||
Mem struct {
|
CpuCores int `json:"cpuCores"`
|
||||||
|
CpuSpeedMhz float64 `json:"cpuSpeedMhz"`
|
||||||
|
Mem struct {
|
||||||
Current uint64 `json:"current"`
|
Current uint64 `json:"current"`
|
||||||
Total uint64 `json:"total"`
|
Total uint64 `json:"total"`
|
||||||
} `json:"mem"`
|
} `json:"mem"`
|
||||||
@@ -69,6 +71,10 @@ type Status struct {
|
|||||||
Sent uint64 `json:"sent"`
|
Sent uint64 `json:"sent"`
|
||||||
Recv uint64 `json:"recv"`
|
Recv uint64 `json:"recv"`
|
||||||
} `json:"netTraffic"`
|
} `json:"netTraffic"`
|
||||||
|
PublicIP struct {
|
||||||
|
IPv4 string `json:"ipv4"`
|
||||||
|
IPv6 string `json:"ipv6"`
|
||||||
|
} `json:"publicIP"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Release struct {
|
type Release struct {
|
||||||
@@ -80,6 +86,33 @@ type ServerService struct {
|
|||||||
inboundService InboundService
|
inboundService InboundService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DebugMode = false // Set to true during development
|
||||||
|
|
||||||
|
func getPublicIP(url string) string {
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
if DebugMode {
|
||||||
|
logger.Warning("get public IP failed:", err)
|
||||||
|
}
|
||||||
|
return "N/A"
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
ip, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
if DebugMode {
|
||||||
|
logger.Warning("read public IP failed:", err)
|
||||||
|
}
|
||||||
|
return "N/A"
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(ip) == "" {
|
||||||
|
return "N/A" // default value
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(ip)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ServerService) GetStatus(lastStatus *Status) *Status {
|
func (s *ServerService) GetStatus(lastStatus *Status) *Status {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
status := &Status{
|
status := &Status{
|
||||||
@@ -93,6 +126,21 @@ func (s *ServerService) GetStatus(lastStatus *Status) *Status {
|
|||||||
status.Cpu = percents[0]
|
status.Cpu = percents[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status.CpuCores, err = cpu.Counts(false)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warning("get cpu cores count failed:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cpuInfos, err := cpu.Info()
|
||||||
|
if err != nil {
|
||||||
|
logger.Warning("get cpu info failed:", err)
|
||||||
|
} else if len(cpuInfos) > 0 {
|
||||||
|
cpuInfo := cpuInfos[0]
|
||||||
|
status.CpuSpeedMhz = cpuInfo.Mhz // setting CPU speed in MHz
|
||||||
|
} else {
|
||||||
|
logger.Warning("could not find cpu info")
|
||||||
|
}
|
||||||
|
|
||||||
upTime, err := host.Uptime()
|
upTime, err := host.Uptime()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warning("get uptime failed:", err)
|
logger.Warning("get uptime failed:", err)
|
||||||
@@ -161,6 +209,9 @@ func (s *ServerService) GetStatus(lastStatus *Status) *Status {
|
|||||||
logger.Warning("get udp connections failed:", err)
|
logger.Warning("get udp connections failed:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status.PublicIP.IPv4 = getPublicIP("https://api.ipify.org")
|
||||||
|
status.PublicIP.IPv6 = getPublicIP("https://api6.ipify.org")
|
||||||
|
|
||||||
if s.xrayService.IsXrayRunning() {
|
if s.xrayService.IsXrayRunning() {
|
||||||
status.Xray.State = Running
|
status.Xray.State = Running
|
||||||
status.Xray.ErrorMsg = ""
|
status.Xray.ErrorMsg = ""
|
||||||
|
|||||||
@@ -75,14 +75,15 @@
|
|||||||
"xrayStatus" = "Xray Status"
|
"xrayStatus" = "Xray Status"
|
||||||
"stopXray" = "Stop"
|
"stopXray" = "Stop"
|
||||||
"restartXray" = "Restart"
|
"restartXray" = "Restart"
|
||||||
"xraySwitch" = "Switch Version"
|
"xraySwitch" = "SwitchV"
|
||||||
"xraySwitchClick" = "Choose the version you want to switch to."
|
"xraySwitchClick" = "Choose the version you want to switch to."
|
||||||
"xraySwitchClickDesk" = "Choose wisely, as older versions may not be compatible with current configurations."
|
"xraySwitchClickDesk" = "Choose wisely, as older versions may not be compatible with current configurations."
|
||||||
"operationHours" = "Operation Hours"
|
"operationHours" = "Uptime"
|
||||||
"operationHoursDesc" = "System uptime: time since startup."
|
|
||||||
"systemLoad" = "System Load"
|
"systemLoad" = "System Load"
|
||||||
|
"systemLoadDesc" = "system load average for the past 1, 5, and 15 minutes"
|
||||||
|
"connectionTcpCountDesc" = "Total TCP connections across all network cards."
|
||||||
|
"connectionUdpCountDesc" = "Total UDP connections across all network cards."
|
||||||
"connectionCount" = "Number of Connections"
|
"connectionCount" = "Number of Connections"
|
||||||
"connectionCountDesc" = "Total connections across all network cards."
|
|
||||||
"upSpeed" = "Total upload speed for all network cards."
|
"upSpeed" = "Total upload speed for all network cards."
|
||||||
"downSpeed" = "Total download speed for all network cards."
|
"downSpeed" = "Total download speed for all network cards."
|
||||||
"totalSent" = "Total upload traffic of all network cards since system startup."
|
"totalSent" = "Total upload traffic of all network cards since system startup."
|
||||||
|
|||||||
@@ -78,11 +78,12 @@
|
|||||||
"xraySwitch" = "تغییر ورژن"
|
"xraySwitch" = "تغییر ورژن"
|
||||||
"xraySwitchClick" = "ورژن مورد نظر را انتخاب کنید"
|
"xraySwitchClick" = "ورژن مورد نظر را انتخاب کنید"
|
||||||
"xraySwitchClickDesk" = "لطفا با دقت انتخاب کنید ، در صورت انتخاب اشتباه امکان قطعی سیستم وجود دارد "
|
"xraySwitchClickDesk" = "لطفا با دقت انتخاب کنید ، در صورت انتخاب اشتباه امکان قطعی سیستم وجود دارد "
|
||||||
"operationHours" = "مدت فعالیت"
|
"operationHours" = "آپ تایم سیستم"
|
||||||
"operationHoursDesc" = "مدت فعالیت سیستم بعد از روشن شدن"
|
"systemLoad" = "بار سیستم"
|
||||||
"systemLoad" = "بار روی سیستم"
|
"systemLoadDesc" = "میانگین بار سیستم برای 1، 5 و 15 دقیقه گذشته"
|
||||||
|
"connectionTcpCountDesc" = "مجموع اتصالات TCP در تمام کارت های شبکه"
|
||||||
|
"connectionUdpCountDesc" = "مجموع اتصالات UDP در تمام کارت های شبکه"
|
||||||
"connectionCount" = "تعداد کانکشن ها"
|
"connectionCount" = "تعداد کانکشن ها"
|
||||||
"connectionCountDesc" = "تعداد کانکشن ها برای کل شبکه"
|
|
||||||
"upSpeed" = "سرعت آپلود در حال حاضر سیستم"
|
"upSpeed" = "سرعت آپلود در حال حاضر سیستم"
|
||||||
"downSpeed" = "سرعت دانلود در حال حاضر سیستم"
|
"downSpeed" = "سرعت دانلود در حال حاضر سیستم"
|
||||||
"totalSent" = "جمع کل ترافیک آپلود مصرفی"
|
"totalSent" = "جمع کل ترافیک آپلود مصرفی"
|
||||||
|
|||||||
@@ -78,11 +78,12 @@
|
|||||||
"xraySwitch" = "Переключить версию"
|
"xraySwitch" = "Переключить версию"
|
||||||
"xraySwitchClick" = "Выберите желаемую версию"
|
"xraySwitchClick" = "Выберите желаемую версию"
|
||||||
"xraySwitchClickDesk" = "Выбирайте внимательно, так как старые версии могут быть несовместимы с текущими конфигурациями"
|
"xraySwitchClickDesk" = "Выбирайте внимательно, так как старые версии могут быть несовместимы с текущими конфигурациями"
|
||||||
"operationHours" = "Часы работы"
|
"operationHours" = "Время работы системы"
|
||||||
"operationHoursDesc" = "Аптайм системы: время системы в сети"
|
|
||||||
"systemLoad" = "Системная нагрузка"
|
"systemLoad" = "Системная нагрузка"
|
||||||
|
"systemLoadDesc" = "средняя загрузка системы за последние 1, 5 и 15 минут"
|
||||||
|
"connectionTcpCountDesc" = "Всего подключений TCP по всем сетевым картам."
|
||||||
|
"connectionUdpCountDesc" = "Общее количество подключений UDP по всем сетевым картам."
|
||||||
"connectionCount" = "Количество соединений"
|
"connectionCount" = "Количество соединений"
|
||||||
"connectionCountDesc" = "Всего подключений по всем сетям"
|
|
||||||
"upSpeed" = "Общая скорость upload для всех сетей"
|
"upSpeed" = "Общая скорость upload для всех сетей"
|
||||||
"downSpeed" = "Общая скорость download для всех сетей"
|
"downSpeed" = "Общая скорость download для всех сетей"
|
||||||
"totalSent" = "Общий объем загруженных данных для всех сетей с момента запуска системы"
|
"totalSent" = "Общий объем загруженных данных для всех сетей с момента запуска системы"
|
||||||
|
|||||||
@@ -78,11 +78,12 @@
|
|||||||
"xraySwitch" = "切换版本"
|
"xraySwitch" = "切换版本"
|
||||||
"xraySwitchClick" = "点击你想切换的版本"
|
"xraySwitchClick" = "点击你想切换的版本"
|
||||||
"xraySwitchClickDesk" = "请谨慎选择,旧版本可能配置不兼容"
|
"xraySwitchClickDesk" = "请谨慎选择,旧版本可能配置不兼容"
|
||||||
"operationHours" = "运行时间"
|
"operationHours" = "系统正常运行时间"
|
||||||
"operationHoursDesc" = "系统自启动以来的运行时间"
|
|
||||||
"systemLoad" = "系统负载"
|
"systemLoad" = "系统负载"
|
||||||
|
"systemLoadDesc" = "过去 1、5 和 15 分钟的系统平均负载"
|
||||||
|
"connectionTcpCountDesc" = "所有网卡的总 TCP 连接数。"
|
||||||
|
"connectionUdpCountDesc" = "所有网卡的总 UDP 连接数。"
|
||||||
"connectionCount" = "连接数"
|
"connectionCount" = "连接数"
|
||||||
"connectionCountDesc" = "所有网卡的总连接数"
|
|
||||||
"upSpeed" = "所有网卡的总上传速度"
|
"upSpeed" = "所有网卡的总上传速度"
|
||||||
"downSpeed" = "所有网卡的总下载速度"
|
"downSpeed" = "所有网卡的总下载速度"
|
||||||
"totalSent" = "系统启动以来所有网卡的总上传流量"
|
"totalSent" = "系统启动以来所有网卡的总上传流量"
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ func GetIranPath() string {
|
|||||||
return config.GetBinFolderPath() + "/iran.dat"
|
return config.GetBinFolderPath() + "/iran.dat"
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBlockedIPsPath() string {
|
func GetAllowedIPsPath() string {
|
||||||
return config.GetBinFolderPath() + "/blockedIPs"
|
return config.GetBinFolderPath() + "/AllowedIPs"
|
||||||
}
|
}
|
||||||
|
|
||||||
func stopProcess(p *Process) {
|
func stopProcess(p *Process) {
|
||||||
@@ -173,7 +173,7 @@ func (p *process) Start() (err error) {
|
|||||||
return common.NewErrorf("Failed to write configuration file: %v", err)
|
return common.NewErrorf("Failed to write configuration file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command(GetBinaryPath(), "-c", configPath, "-restrictedIPsPath", GetBlockedIPsPath())
|
cmd := exec.Command(GetBinaryPath(), "-c", configPath, "-restrictedIPsPath", GetAllowedIPsPath())
|
||||||
p.cmd = cmd
|
p.cmd = cmd
|
||||||
|
|
||||||
stdReader, err := cmd.StdoutPipe()
|
stdReader, err := cmd.StdoutPipe()
|
||||||
|
|||||||
Reference in New Issue
Block a user