Compare commits

...

21 Commits

Author SHA1 Message Date
Alireza Ahmadi fb999b4ee8 v1.3.5 2025-09-12 00:42:39 +02:00
Alireza Ahmadi e3ebfcf721 bump packages 2025-09-12 00:39:58 +02:00
Alireza Ahmadi 33071deb53 Merge pull request #782 from alireza0/dependabot/github_actions/actions/setup-go-6
Bump actions/setup-go from 5 to 6
2025-09-12 00:37:45 +02:00
Alireza Ahmadi 9b3b8d4540 Merge pull request #783 from alireza0/dependabot/github_actions/actions/setup-node-5
Bump actions/setup-node from 4 to 5
2025-09-12 00:37:32 +02:00
Alireza Ahmadi 98bf124078 sing-box v1.12.5 2025-09-12 00:24:13 +02:00
Alireza Ahmadi abc73a6525 fix external link on tls change 2025-09-12 00:19:51 +02:00
Alireza Ahmadi 2276175354 reality support links #794 2025-09-12 00:19:30 +02:00
Alireza Ahmadi 7f24735677 fix hysteria link generator #801 2025-09-11 23:23:58 +02:00
Alireza Ahmadi 4d1544864d go 1.25.1 2025-09-11 21:10:56 +02:00
Alireza Ahmadi 4aadee7ca0 fix ipv6 hostname #789 2025-09-09 22:30:07 +02:00
Alireza Ahmadi 6aba1354d5 fix client api error handling #781 2025-09-04 19:56:56 +02:00
dependabot[bot] 63b229143d Bump actions/setup-node from 4 to 5
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 5.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-04 16:10:29 +00:00
dependabot[bot] f861950c50 Bump actions/setup-go from 5 to 6
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5 to 6.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-04 16:10:26 +00:00
Alireza Ahmadi 97d1694bfa fix numbered external links #774 2025-09-04 00:47:58 +02:00
Alireza Ahmadi 2d28d9b409 v1.3.4 2025-09-01 01:06:51 +02:00
Alireza Ahmadi 560c41acbe disable traffic charts if set to zero 2025-08-30 02:11:43 +02:00
Alireza Ahmadi e3c33bf649 sing-box v1.12.4 2025-08-30 01:20:38 +02:00
Alireza Ahmadi 216db63551 fix reality link to clash sub #766 2025-08-29 23:28:00 +02:00
Alireza Ahmadi 05d8a6bf85 Merge pull request #757 from Peter1303/main
update: docker run command
2025-08-26 20:22:45 +02:00
PeterPan 1e6c2b9598 update: docker run command 2025-08-25 11:35:00 +08:00
Alireza Ahmadi f006323f54 remove OS version dependency 2025-08-21 13:39:33 +02:00
21 changed files with 158 additions and 273 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
with: with:
submodules: recursive submodules: recursive
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v5
with: with:
node-version: 20 node-version: 20
- name: Install dependencies and build frontend - name: Install dependencies and build frontend
+2 -2
View File
@@ -37,13 +37,13 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v6
with: with:
cache: false cache: false
go-version-file: go.mod go-version-file: go.mod
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v5
with: with:
node-version: '22' node-version: '22'
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
+4 -4
View File
@@ -26,13 +26,13 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v6
with: with:
cache: false cache: false
go-version-file: go.mod go-version-file: go.mod
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v5
with: with:
node-version: '22' node-version: '22'
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
@@ -110,13 +110,13 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v6
with: with:
cache: false cache: false
go-version-file: go.mod go-version-file: go.mod
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v5
with: with:
node-version: '22' node-version: '22'
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
+1 -16
View File
@@ -134,7 +134,7 @@ docker compose up -d
mkdir s-ui && cd s-ui mkdir s-ui && cd s-ui
docker run -itd \ docker run -itd \
-p 2095:2095 -p 2096:2096 -p 443:443 -p 80:80 \ -p 2095:2095 -p 2096:2096 -p 443:443 -p 80:80 \
-v $PWD/db/:/usr/local/s-ui/db/ \ -v $PWD/db/:/app/db/ \
-v $PWD/cert/:/root/cert/ \ -v $PWD/cert/:/root/cert/ \
--name s-ui --restart=unless-stopped \ --name s-ui --restart=unless-stopped \
alireza7/s-ui:latest alireza7/s-ui:latest
@@ -217,21 +217,6 @@ To run backend (from root folder of repository):
- HTTPS for secure access to the web panel and subscription service (self-provided domain + SSL certificate) - HTTPS for secure access to the web panel and subscription service (self-provided domain + SSL certificate)
- Dark/Light theme - Dark/Light theme
## Recommended OS
- Ubuntu 22.04+
- Debian 12+
- CentOS 9+
- Fedora 36+
- Arch Linux
- Parch Linux
- Manjaro
- Armbian
- AlmaLinux 9.5+
- Rocky Linux 9.5+
- Oracle Linux 8+
- OpenSUSE Tubleweed
## Environment Variables ## Environment Variables
<details> <details>
+6 -2
View File
@@ -7,7 +7,6 @@ import (
"s-ui/service" "s-ui/service"
"s-ui/util" "s-ui/util"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -86,7 +85,11 @@ func (a *ApiService) getData(c *gin.Context) (interface{}, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
subURI, err := a.SettingService.GetFinalSubURI(strings.Split(c.Request.Host, ":")[0]) subURI, err := a.SettingService.GetFinalSubURI(getHostname(c))
if err != nil {
return "", err
}
trafficAge, err := a.SettingService.GetTrafficAge()
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -98,6 +101,7 @@ func (a *ApiService) getData(c *gin.Context) (interface{}, error) {
data["endpoints"] = endpoints data["endpoints"] = endpoints
data["services"] = services data["services"] = services
data["subURI"] = subURI data["subURI"] = subURI
data["enableTraffic"] = trafficAge > 0
data["onlines"] = onlines data["onlines"] = onlines
} else { } else {
data["onlines"] = onlines data["onlines"] = onlines
+4 -1
View File
@@ -29,8 +29,11 @@ func getRemoteIp(c *gin.Context) string {
func getHostname(c *gin.Context) string { func getHostname(c *gin.Context) string {
host := c.Request.Host host := c.Request.Host
if colonIndex := strings.LastIndex(host, ":"); colonIndex != -1 { if strings.Contains(host, ":") {
host, _, _ = net.SplitHostPort(c.Request.Host) host, _, _ = net.SplitHostPort(c.Request.Host)
if strings.Contains(host, ":") {
host = "[" + host + "]"
}
} }
return host return host
} }
+1 -1
View File
@@ -1 +1 @@
1.3.3 1.3.5
+3 -1
View File
@@ -20,11 +20,13 @@ func (c *CronJob) Start(loc *time.Location, trafficAge int) error {
go func() { go func() {
// Start stats job // Start stats job
c.cron.AddJob("@every 10s", NewStatsJob()) c.cron.AddJob("@every 10s", NewStatsJob(trafficAge > 0))
// Start expiry job // Start expiry job
c.cron.AddJob("@every 1m", NewDepleteJob()) c.cron.AddJob("@every 1m", NewDepleteJob())
// Start deleting old stats // Start deleting old stats
if trafficAge > 0 {
c.cron.AddJob("@daily", NewDelStatsJob(trafficAge)) c.cron.AddJob("@daily", NewDelStatsJob(trafficAge))
}
// Start core if it is not running // Start core if it is not running
c.cron.AddJob("@every 5s", NewCheckCoreJob()) c.cron.AddJob("@every 5s", NewCheckCoreJob())
}() }()
+6 -3
View File
@@ -7,14 +7,17 @@ import (
type StatsJob struct { type StatsJob struct {
service.StatsService service.StatsService
enableTraffic bool
} }
func NewStatsJob() *StatsJob { func NewStatsJob(saveTraffic bool) *StatsJob {
return &StatsJob{} return &StatsJob{
enableTraffic: saveTraffic,
}
} }
func (s *StatsJob) Run() { func (s *StatsJob) Run() {
err := s.StatsService.SaveStats() err := s.StatsService.SaveStats(s.enableTraffic)
if err != nil { if err != nil {
logger.Warning("Get stats failed: ", err) logger.Warning("Get stats failed: ", err)
return return
+9 -9
View File
@@ -1,6 +1,6 @@
module s-ui module s-ui
go 1.25.0 go 1.25.1
require ( require (
github.com/gin-contrib/gzip v1.2.3 github.com/gin-contrib/gzip v1.2.3
@@ -9,14 +9,14 @@ require (
github.com/gofrs/uuid/v5 v5.3.2 github.com/gofrs/uuid/v5 v5.3.2
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/sagernet/sing v0.7.6-0.20250815070458-d33ece7a184f github.com/sagernet/sing v0.7.8
github.com/sagernet/sing-box v1.12.3 github.com/sagernet/sing-box v1.12.5
github.com/sagernet/sing-dns v0.4.6 github.com/sagernet/sing-dns v0.4.6
github.com/shirou/gopsutil/v4 v4.25.7 github.com/shirou/gopsutil/v4 v4.25.8
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/sqlite v1.6.0 gorm.io/driver/sqlite v1.6.0
gorm.io/gorm v1.30.1 gorm.io/gorm v1.30.5
) )
require ( require (
@@ -107,14 +107,14 @@ require (
github.com/sagernet/nftables v0.3.0-beta.4 // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect
github.com/sagernet/quic-go v0.52.0-beta.1 // indirect github.com/sagernet/quic-go v0.52.0-beta.1 // indirect
github.com/sagernet/sing-mux v0.3.3 // indirect github.com/sagernet/sing-mux v0.3.3 // indirect
github.com/sagernet/sing-quic v0.5.0 // indirect github.com/sagernet/sing-quic v0.5.2-0.20250909083218-00a55617c0fb // indirect
github.com/sagernet/sing-shadowsocks v0.2.8 // indirect github.com/sagernet/sing-shadowsocks v0.2.8 // indirect
github.com/sagernet/sing-shadowsocks2 v0.2.1 // indirect github.com/sagernet/sing-shadowsocks2 v0.2.1 // indirect
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 // indirect github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 // indirect
github.com/sagernet/sing-tun v0.7.0-beta.1 // indirect github.com/sagernet/sing-tun v0.7.1-0.20250909064831-29d619807240 // indirect
github.com/sagernet/sing-vmess v0.2.7 // indirect github.com/sagernet/sing-vmess v0.2.7 // indirect
github.com/sagernet/smux v1.5.34-mod.2 // indirect github.com/sagernet/smux v1.5.34-mod.2 // indirect
github.com/sagernet/tailscale v1.80.3-mod.5 // indirect github.com/sagernet/tailscale v1.80.3-sing-box-1.12-mod.1 // indirect
github.com/sagernet/wireguard-go v0.0.1-beta.7 // indirect github.com/sagernet/wireguard-go v0.0.1-beta.7 // indirect
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect
@@ -139,7 +139,7 @@ require (
go.uber.org/zap/exp v0.3.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/arch v0.19.0 // indirect golang.org/x/arch v0.20.0 // indirect
golang.org/x/crypto v0.41.0 // indirect golang.org/x/crypto v0.41.0 // indirect
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
golang.org/x/mod v0.27.0 // indirect golang.org/x/mod v0.27.0 // indirect
+18 -18
View File
@@ -214,36 +214,36 @@ github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/l
github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs= github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs=
github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4= github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing v0.7.6-0.20250815070458-d33ece7a184f h1:HIBo8l+tsS3wLwuI1E56uRTQw46QytXSUpZTP3vwG/U= github.com/sagernet/sing v0.7.8 h1:i3JBTzeEOqMRtYcyNV17LKvxkb3mr2Y/omM5ldvhCYo=
github.com/sagernet/sing v0.7.6-0.20250815070458-d33ece7a184f/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing v0.7.8/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-box v1.12.3 h1:EWtKXSJ0L8OVHS4Swl8HsakMOwwiEC68AU+pEkcUlQw= github.com/sagernet/sing-box v1.12.5 h1:epv38kun08FI6Va7XlCxlovtTSUoOVPTWEEabQVbHbc=
github.com/sagernet/sing-box v1.12.3/go.mod h1:spyNZpDcPQIl5VUL/6rnDF7x/SFtQ0u0dybT5hIuU/c= github.com/sagernet/sing-box v1.12.5/go.mod h1:mZUQY2lEhu5R3REhUYoGgpn2oVtLtJNf2UFjZ98vFFA=
github.com/sagernet/sing-dns v0.4.6 h1:mjZC0o6d5sQ1sraoOBbK3G3apCbuL8wWYwu2RNu5rbM= github.com/sagernet/sing-dns v0.4.6 h1:mjZC0o6d5sQ1sraoOBbK3G3apCbuL8wWYwu2RNu5rbM=
github.com/sagernet/sing-dns v0.4.6/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8= github.com/sagernet/sing-dns v0.4.6/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8=
github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw= github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw=
github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA= github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
github.com/sagernet/sing-quic v0.5.0 h1:jNLIyVk24lFPvu8A4x+ZNEnZdI+Tg1rp7eCJ6v0Csak= github.com/sagernet/sing-quic v0.5.2-0.20250909083218-00a55617c0fb h1:5Wx3XeTiKrrrcrAky7Hc1bO3CGxrvho2Vu5b/adlEIM=
github.com/sagernet/sing-quic v0.5.0/go.mod h1:SAv/qdeDN+75msGG5U5ZIwG+3Ua50jVIKNrRSY8pkx0= github.com/sagernet/sing-quic v0.5.2-0.20250909083218-00a55617c0fb/go.mod h1:evP1e++ZG8TJHVV5HudXV4vWeYzGfCdF4HwSJZcdqkI=
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE= github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI= github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI=
github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo= github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo=
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w= github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
github.com/sagernet/sing-tun v0.7.0-beta.1 h1:mBIFXYAnGO5ey/HcCYanqnBx61E7yF8zTFGRZonGYmY= github.com/sagernet/sing-tun v0.7.1-0.20250909064831-29d619807240 h1:QJrYOLJB4A0ONEl1dmZtcyY9NmY6EOKAx3CblLOb+Y8=
github.com/sagernet/sing-tun v0.7.0-beta.1/go.mod h1:AHJuRrLbNRJuivuFZ2VhXwDj4ViYp14szG5EkkKAqRQ= github.com/sagernet/sing-tun v0.7.1-0.20250909064831-29d619807240/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM=
github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk= github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk=
github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs= github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4= github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4=
github.com/sagernet/smux v1.5.34-mod.2/go.mod h1:0KW0+R+ycvA2INW4gbsd7BNyg+HEfLIAxa5N02/28Zc= github.com/sagernet/smux v1.5.34-mod.2/go.mod h1:0KW0+R+ycvA2INW4gbsd7BNyg+HEfLIAxa5N02/28Zc=
github.com/sagernet/tailscale v1.80.3-mod.5 h1:7V7z+p2C//TGtff20pPnDCt3qP6uFyY62peJoKF9z/A= github.com/sagernet/tailscale v1.80.3-sing-box-1.12-mod.1 h1:gMC0q+0VvZBotZMZ9G0R8ZMEIT/Q6KnXbw0/OgMjmdk=
github.com/sagernet/tailscale v1.80.3-mod.5/go.mod h1:EBxXsWu4OH2ELbQLq32WoBeIubG8KgDrg4/Oaxjs6lI= github.com/sagernet/tailscale v1.80.3-sing-box-1.12-mod.1/go.mod h1:EBxXsWu4OH2ELbQLq32WoBeIubG8KgDrg4/Oaxjs6lI=
github.com/sagernet/wireguard-go v0.0.1-beta.7 h1:ltgBwYHfr+9Wz1eG59NiWnHrYEkDKHG7otNZvu85DXI= github.com/sagernet/wireguard-go v0.0.1-beta.7 h1:ltgBwYHfr+9Wz1eG59NiWnHrYEkDKHG7otNZvu85DXI=
github.com/sagernet/wireguard-go v0.0.1-beta.7/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo= github.com/sagernet/wireguard-go v0.0.1-beta.7/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc= github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA= github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM= github.com/shirou/gopsutil/v4 v4.25.8 h1:NnAsw9lN7587WHxjJA9ryDnqhJpFH6A+wagYWTOH970=
github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U= github.com/shirou/gopsutil/v4 v4.25.8/go.mod h1:q9QdMmfAOVIw7a+eF86P7ISEU6ka+NLgkUxlopV4RwI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -255,8 +255,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ= github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ=
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4= github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4=
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4= github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4=
@@ -322,8 +322,8 @@ go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4
go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/arch v0.19.0 h1:LmbDQUodHThXE+htjrnmVD73M//D9GTH6wFZjyDkjyU= golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
golang.org/x/arch v0.19.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
@@ -383,8 +383,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
gorm.io/gorm v1.30.1 h1:lSHg33jJTBxs2mgJRfRZeLDG+WZaHYCk3Wtfl6Ngzo4= gorm.io/gorm v1.30.5 h1:dvEfYwxL+i+xgCNSGGBT1lDjCzfELK8fHZxL3Ee9X0s=
gorm.io/gorm v1.30.1/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= gorm.io/gorm v1.30.5/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
-60
View File
@@ -38,66 +38,6 @@ arch() {
echo "arch: $(arch)" echo "arch: $(arch)"
os_version=""
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
if [[ "${release}" == "arch" ]]; then
echo "Your OS is Arch Linux"
elif [[ "${release}" == "parch" ]]; then
echo "Your OS is Parch linux"
elif [[ "${release}" == "manjaro" ]]; then
echo "Your OS is Manjaro"
elif [[ "${release}" == "armbian" ]]; then
echo "Your OS is Armbian"
elif [[ "${release}" == "opensuse-tumbleweed" ]]; then
echo "Your OS is OpenSUSE Tumbleweed"
elif [[ "${release}" == "centos" ]]; then
if [[ ${os_version} -lt 9 ]]; then
echo -e "${red} Please use CentOS 9 or higher ${plain}\n" && exit 1
fi
elif [[ "${release}" == "ubuntu" ]]; then
if [[ ${os_version} -lt 22 ]]; then
echo -e "${red} Please use Ubuntu 22 or higher version!${plain}\n" && exit 1
fi
elif [[ "${release}" == "fedora" ]]; then
if [[ ${os_version} -lt 36 ]]; then
echo -e "${red} Please use Fedora 36 or higher version!${plain}\n" && exit 1
fi
elif [[ "${release}" == "debian" ]]; then
if [[ ${os_version} -lt 12 ]]; then
echo -e "${red} Please use Debian 12 or higher ${plain}\n" && exit 1
fi
elif [[ "${release}" == "almalinux" ]]; then
if [[ ${os_version} -lt 95 ]]; then
echo -e "${red} Please use AlmaLinux 9.5 or higher ${plain}\n" && exit 1
fi
elif [[ "${release}" == "rocky" ]]; then
if [[ ${os_version} -lt 95 ]]; then
echo -e "${red} Please use Rocky Linux 9.5 or higher ${plain}\n" && exit 1
fi
elif [[ "${release}" == "ol" ]]; then
if [[ ${os_version} -lt 8 ]]; then
echo -e "${red} Please use Oracle Linux 8 or higher ${plain}\n" && exit 1
fi
else
echo -e "${red}Your operating system is not supported by this script.${plain}\n"
echo "Please ensure you are using one of the following supported operating systems:"
echo "- Ubuntu 22.04+"
echo "- Debian 12+"
echo "- CentOS 9+"
echo "- Fedora 36+"
echo "- Arch Linux"
echo "- Parch Linux"
echo "- Manjaro"
echo "- Armbian"
echo "- AlmaLinux 9.5+"
echo "- Rocky Linux 9.5+"
echo "- Oracle Linux 8+"
echo "- OpenSUSE Tumbleweed"
exit 1
fi
install_base() { install_base() {
case "${release}" in case "${release}" in
centos | almalinux | rocky | oracle) centos | almalinux | rocky | oracle)
+1 -1
View File
@@ -283,7 +283,7 @@ func (s *ClientService) UpdateLinksByInboundChange(tx *gorm.DB, inbounds *[]mode
}) })
} }
for _, clientLink := range clientLinks { for _, clientLink := range clientLinks {
if clientLink["remark"] != inbound.Tag && clientLink["remark"] != oldTag { if clientLink["type"] != "local" || (clientLink["remark"] != inbound.Tag && clientLink["remark"] != oldTag) {
newClientLinks = append(newClientLinks, clientLink) newClientLinks = append(newClientLinks, clientLink)
} }
} }
+2 -1
View File
@@ -142,7 +142,8 @@ func (s *ConfigService) Save(obj string, act string, data json.RawMessage, initU
switch obj { switch obj {
case "clients": case "clients":
inboundIds, err := s.ClientService.Save(tx, act, data, hostname) var inboundIds []uint
inboundIds, err = s.ClientService.Save(tx, act, data, hostname)
if err == nil && len(inboundIds) > 0 { if err == nil && len(inboundIds) > 0 {
objs = append(objs, "inbounds") objs = append(objs, "inbounds")
err = s.InboundService.RestartInbounds(tx, inboundIds) err = s.InboundService.RestartInbounds(tx, inboundIds)
+7
View File
@@ -391,6 +391,13 @@ func (s *SettingService) Save(tx *gorm.DB, data json.RawMessage) error {
} }
} }
// Delete all stats if it is set to 0
if key == "trafficAge" && obj == "0" {
err = tx.Where("id > 0").Delete(model.Stats{}).Error
if err != nil {
return err
}
}
err = tx.Model(model.Setting{}).Where("key = ?", key).Update("value", obj).Error err = tx.Model(model.Setting{}).Where("key = ?", key).Update("value", obj).Error
if err != nil { if err != nil {
return err return err
+5 -3
View File
@@ -19,7 +19,7 @@ var onlineResources = &onlines{}
type StatsService struct { type StatsService struct {
} }
func (s *StatsService) SaveStats() error { func (s *StatsService) SaveStats(enableTraffic bool) error {
if !corePtr.IsRunning() { if !corePtr.IsRunning() {
return nil return nil
} }
@@ -70,8 +70,10 @@ func (s *StatsService) SaveStats() error {
} }
} }
err = tx.Create(&stats).Error if !enableTraffic {
return err return nil
}
return tx.Create(&stats).Error
} }
func (s *StatsService) GetStats(resource string, tag string, limit int) ([]model.Stats, error) { func (s *StatsService) GetStats(resource string, tag string, limit int) ([]model.Stats, error) {
+5 -1
View File
@@ -73,8 +73,12 @@ func (s *ClashService) GetClash(subId string) (*string, []string, error) {
} }
links := s.LinkService.GetLinks(&client.Links, "external", "") links := s.LinkService.GetLinks(&client.Links, "external", "")
tagNumEnable := 0
if len(links) > 1 {
tagNumEnable = 1
}
for index, link := range links { for index, link := range links {
json, tag, err := util.GetOutbound(link, index) json, tag, err := util.GetOutbound(link, (index+1)*tagNumEnable)
if err == nil && len(tag) > 0 { if err == nil && len(tag) > 0 {
*outbounds = append(*outbounds, *json) *outbounds = append(*outbounds, *json)
*outTags = append(*outTags, tag) *outTags = append(*outTags, tag)
+5 -1
View File
@@ -61,8 +61,12 @@ func (j *JsonService) GetJson(subId string, format string) (*string, []string, e
} }
links := j.LinkService.GetLinks(&client.Links, "external", "") links := j.LinkService.GetLinks(&client.Links, "external", "")
tagNumEnable := 0
if len(links) > 1 {
tagNumEnable = 1
}
for index, link := range links { for index, link := range links {
json, tag, err := util.GetOutbound(link, index) json, tag, err := util.GetOutbound(link, (index+1)*tagNumEnable)
if err == nil && len(tag) > 0 { if err == nil && len(tag) > 0 {
*outbounds = append(*outbounds, *json) *outbounds = append(*outbounds, *json)
*outTags = append(*outTags, tag) *outTags = append(*outTags, tag)
+69 -139
View File
@@ -67,7 +67,9 @@ func LinkGenerator(clientConfig json.RawMessage, i *model.Inbound, hostname stri
return httpLink(userConfig["http"], *inbound, Addrs) return httpLink(userConfig["http"], *inbound, Addrs)
case "mixed": case "mixed":
return append( return append(
socksLink(userConfig["socks"], *inbound, Addrs), httpLink(userConfig["http"], *inbound, Addrs)...) socksLink(userConfig["socks"], *inbound, Addrs),
httpLink(userConfig["http"], *inbound, Addrs)...,
)
case "shadowsocks": case "shadowsocks":
return shadowsocksLink(userConfig, *inbound, Addrs) return shadowsocksLink(userConfig, *inbound, Addrs)
case "naive": case "naive":
@@ -157,7 +159,7 @@ func shadowsocksLink(
var links []string var links []string
for _, addr := range addrs { for _, addr := range addrs {
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
links = append(links, fmt.Sprintf("%s@%s:%d#%s", uriBase, addr["server"].(string), uint(port), addr["remark"].(string))) links = append(links, fmt.Sprintf("%s@%s:%.0f#%s", uriBase, addr["server"].(string), port, addr["remark"].(string)))
} }
return links return links
} }
@@ -198,7 +200,7 @@ func naiveLink(
} }
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
uri := baseUri + toBase64([]byte(fmt.Sprintf("%s:%s@%s:%d", username, password, addr["server"].(string), uint(port)))) uri := baseUri + toBase64([]byte(fmt.Sprintf("%s:%s@%s:%.0f", username, password, addr["server"].(string), port)))
links = append(links, addParams(uri, params, addr["remark"].(string))) links = append(links, addParams(uri, params, addr["remark"].(string)))
} }
return links return links
@@ -214,29 +216,17 @@ func hysteriaLink(
for _, addr := range addrs { for _, addr := range addrs {
params := map[string]string{} params := map[string]string{}
if upmbps, ok := inbound["up_mbps"].(string); ok { if upmbps, ok := inbound["up_mbps"].(float64); ok {
params["up_mbps"] = upmbps params["upmbps"] = fmt.Sprintf("%.0f", upmbps)
} }
if downmbps, ok := inbound["down_mbps"].(string); ok { if downmbps, ok := inbound["down_mbps"].(float64); ok {
params["down_mbps"] = downmbps params["downmbps"] = fmt.Sprintf("%.0f", downmbps)
} }
if auth, ok := userConfig["auth_str"].(string); ok { if auth, ok := userConfig["auth_str"].(string); ok {
params["auth"] = auth params["auth"] = auth
} }
if tls, ok := addr["tls"].(map[string]interface{}); ok { if tls, ok := addr["tls"].(map[string]interface{}); ok {
if sni, ok := tls["server_name"].(string); ok { getTlsParams(&params, tls, "insecure")
params["peer"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["insecure"] = "1"
}
} }
if obfs, ok := inbound["obfs"].(string); ok { if obfs, ok := inbound["obfs"].(string); ok {
params["obfs"] = obfs params["obfs"] = obfs
@@ -246,9 +236,18 @@ func hysteriaLink(
} else { } else {
params["fastopen"] = "0" params["fastopen"] = "0"
} }
var outJson map[string]interface{}
json.Unmarshal(inbound["out_json"].(json.RawMessage), &outJson)
if mport, ok := outJson["server_ports"].([]interface{}); ok {
mportList := make([]string, len(mport))
for i, v := range mport {
mportList[i] = v.(string)
}
params["mport"] = strings.Join(mportList, ",")
}
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
uri := fmt.Sprintf("%s%s:%d", baseUri, addr["server"].(string), uint(port)) uri := fmt.Sprintf("%s%s:%.0f", baseUri, addr["server"].(string), port)
links = append(links, addParams(uri, params, addr["remark"].(string))) links = append(links, addParams(uri, params, addr["remark"].(string)))
} }
@@ -266,26 +265,14 @@ func hysteria2Link(
for _, addr := range addrs { for _, addr := range addrs {
params := map[string]string{} params := map[string]string{}
if upmbps, ok := inbound["up_mbps"].(string); ok { if upmbps, ok := inbound["up_mbps"].(float64); ok {
params["up_mbps"] = upmbps params["upmbps"] = fmt.Sprintf("%.0f", upmbps)
} }
if downmbps, ok := inbound["down_mbps"].(string); ok { if downmbps, ok := inbound["down_mbps"].(float64); ok {
params["down_mbps"] = downmbps params["downmbps"] = fmt.Sprintf("%.0f", downmbps)
} }
if tls, ok := addr["tls"].(map[string]interface{}); ok { if tls, ok := addr["tls"].(map[string]interface{}); ok {
if sni, ok := tls["server_name"].(string); ok { getTlsParams(&params, tls, "insecure")
params["sni"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["insecure"] = "1"
}
} }
if obfs, ok := inbound["obfs"].(map[string]interface{}); ok { if obfs, ok := inbound["obfs"].(map[string]interface{}); ok {
if obfsType, ok := obfs["type"].(string); ok { if obfsType, ok := obfs["type"].(string); ok {
@@ -300,9 +287,18 @@ func hysteria2Link(
} else { } else {
params["fastopen"] = "0" params["fastopen"] = "0"
} }
var outJson map[string]interface{}
json.Unmarshal(inbound["out_json"].(json.RawMessage), &outJson)
if mport, ok := outJson["server_ports"].([]interface{}); ok {
mportList := make([]string, len(mport))
for i, v := range mport {
mportList[i] = v.(string)
}
params["mport"] = strings.Join(mportList, ",")
}
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
uri := fmt.Sprintf("%s%s:%d", baseUri, addr["server"].(string), uint(port)) uri := fmt.Sprintf("%s%s:%.0f", baseUri, addr["server"].(string), port)
links = append(links, addParams(uri, params, addr["remark"].(string))) links = append(links, addParams(uri, params, addr["remark"].(string)))
} }
@@ -320,23 +316,11 @@ func anytlsLink(
for _, addr := range addrs { for _, addr := range addrs {
params := map[string]string{} params := map[string]string{}
if tls, ok := addr["tls"].(map[string]interface{}); ok { if tls, ok := addr["tls"].(map[string]interface{}); ok {
if sni, ok := tls["server_name"].(string); ok { getTlsParams(&params, tls, "insecure")
params["sni"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["insecure"] = "1"
}
} }
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
uri := fmt.Sprintf("%s%s:%d", baseUri, addr["server"].(string), uint(port)) uri := fmt.Sprintf("%s%s:%.0f", baseUri, addr["server"].(string), port)
links = append(links, addParams(uri, params, addr["remark"].(string))) links = append(links, addParams(uri, params, addr["remark"].(string)))
} }
@@ -356,29 +340,14 @@ func tuicLink(
for _, addr := range addrs { for _, addr := range addrs {
params := map[string]string{} params := map[string]string{}
if tls, ok := addr["tls"].(map[string]interface{}); ok { if tls, ok := addr["tls"].(map[string]interface{}); ok {
if sni, ok := tls["server_name"].(string); ok { getTlsParams(&params, tls, "insecure")
params["sni"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["insecure"] = "1"
}
if disableSni, ok := tls["disable_sni"].(bool); ok && disableSni {
params["disable_sni"] = "1"
}
} }
if congestionControl, ok := inbound["congestion_control"].(string); ok { if congestionControl, ok := inbound["congestion_control"].(string); ok {
params["congestion_control"] = congestionControl params["congestion_control"] = congestionControl
} }
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
uri := fmt.Sprintf("%s%s:%d", baseUri, addr["server"].(string), uint(port)) uri := fmt.Sprintf("%s%s:%.0f", baseUri, addr["server"].(string), port)
links = append(links, addParams(uri, params, addr["remark"].(string))) links = append(links, addParams(uri, params, addr["remark"].(string)))
} }
@@ -397,39 +366,13 @@ func vlessLink(
for _, addr := range addrs { for _, addr := range addrs {
params := baseParams params := baseParams
if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) { if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) {
if reality, ok := tls["reality"].(map[string]interface{}); ok && reality["enabled"].(bool) { getTlsParams(&params, tls, "allowInsecure")
params["security"] = "reality"
if pbk, ok := reality["public_key"].(string); ok {
params["pbk"] = pbk
}
if sid, ok := reality["short_id"].(string); ok {
params["sid"] = sid
}
} else {
params["security"] = "tls"
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["allowInsecure"] = "1"
}
}
if flow, ok := userConfig["flow"].(string); ok { if flow, ok := userConfig["flow"].(string); ok {
params["flow"] = flow params["flow"] = flow
} }
if utls, ok := tls["utls"].(map[string]interface{}); ok {
params["fp"], _ = utls["fingerprint"].(string)
}
if sni, ok := tls["server_name"].(string); ok {
params["sni"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
} }
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
uri := fmt.Sprintf("vless://%s@%s:%d", uuid, addr["server"].(string), uint(port)) uri := fmt.Sprintf("vless://%s@%s:%.0f", uuid, addr["server"].(string), port)
uri = addParams(uri, params, addr["remark"].(string)) uri = addParams(uri, params, addr["remark"].(string))
links = append(links, uri) links = append(links, uri)
} }
@@ -448,36 +391,10 @@ func trojanLink(
for _, addr := range addrs { for _, addr := range addrs {
params := baseParams params := baseParams
if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) { if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) {
if reality, ok := tls["reality"].(map[string]interface{}); ok && reality["enabled"].(bool) { getTlsParams(&params, tls, "allowInsecure")
params["security"] = "reality"
if pbk, ok := reality["public_key"].(string); ok {
params["pbk"] = pbk
}
if sid, ok := reality["short_id"].(string); ok {
params["sid"] = sid
}
} else {
params["security"] = "tls"
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["allowInsecure"] = "1"
}
}
if utls, ok := tls["utls"].(map[string]interface{}); ok {
params["fp"], _ = utls["fingerprint"].(string)
}
if sni, ok := tls["server_name"].(string); ok {
params["sni"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
} }
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
uri := fmt.Sprintf("trojan://%s@%s:%d", password, addr["server"].(string), uint(port)) uri := fmt.Sprintf("trojan://%s@%s:%.0f", password, addr["server"].(string), port)
uri = addParams(uri, params, addr["remark"].(string)) uri = addParams(uri, params, addr["remark"].(string))
links = append(links, uri) links = append(links, uri)
} }
@@ -556,11 +473,11 @@ func toBase64(d []byte) string {
func addParams(uri string, params map[string]string, remark string) string { func addParams(uri string, params map[string]string, remark string) string {
URL, _ := url.Parse(uri) URL, _ := url.Parse(uri)
q := URL.Query() var q []string
for k, v := range params { for k, v := range params {
q.Add(k, v) q = append(q, fmt.Sprintf("%s=%s", k, v))
} }
URL.RawQuery = q.Encode() URL.RawQuery = strings.Join(q, "&")
URL.Fragment = remark URL.Fragment = remark
return URL.String() return URL.String()
} }
@@ -610,22 +527,35 @@ func getTransportParams(t interface{}) map[string]string {
return params return params
} }
func getTlsParams(t interface{}) map[string]string { func getTlsParams(params *map[string]string, tls map[string]interface{}, insecureKey string) {
params := map[string]string{} if reality, ok := tls["reality"].(map[string]interface{}); ok && reality["enabled"].(bool) {
if tls, hasTls := t.(map[string]interface{}); hasTls { (*params)["security"] = "reality"
if pbk, ok := reality["public_key"].(string); ok {
(*params)["pbk"] = pbk
}
if sid, ok := reality["short_id"].(string); ok {
(*params)["sid"] = sid
}
} else {
(*params)["security"] = "tls"
if insecure, ok := tls["insecure"].(bool); ok && insecure {
(*params)[insecureKey] = "1"
}
if disableSni, ok := tls["disable_sni"].(bool); ok && disableSni {
(*params)["disable_sni"] = "1"
}
}
if utls, ok := tls["utls"].(map[string]interface{}); ok {
(*params)["fp"], _ = utls["fingerprint"].(string)
}
if sni, ok := tls["server_name"].(string); ok { if sni, ok := tls["server_name"].(string); ok {
params["sni"] = sni (*params)["sni"] = sni
} }
if alpn, ok := tls["alpn"].([]interface{}); ok { if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn)) alpnList := make([]string, len(alpn))
for i, v := range alpn { for i, v := range alpn {
alpnList[i] = v.(string) alpnList[i] = v.(string)
} }
params["alpn"] = strings.Join(alpnList, ",") (*params)["alpn"] = strings.Join(alpnList, ",")
}
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["insecure"] = "1"
} }
} }
return params
}
+4 -4
View File
@@ -435,7 +435,7 @@ func ss(u *url.URL, i int) (*map[string]interface{}, string, error) {
return &ss, tag, nil return &ss, tag, nil
} }
func getTransport(tp_type string, q *url.Values) *map[string]interface{} { func getTransport(tp_type string, q *url.Values) map[string]interface{} {
transport := map[string]interface{}{} transport := map[string]interface{}{}
tp_host := q.Get("host") tp_host := q.Get("host")
tp_path := q.Get("path") tp_path := q.Get("path")
@@ -472,10 +472,10 @@ func getTransport(tp_type string, q *url.Values) *map[string]interface{} {
transport["path"] = tp_path transport["path"] = tp_path
transport["host"] = tp_host transport["host"] = tp_host
} }
return &transport return transport
} }
func getTls(security string, q *url.Values) *map[string]interface{} { func getTls(security string, q *url.Values) map[string]interface{} {
tls := map[string]interface{}{} tls := map[string]interface{}{}
tls_fp := q.Get("fp") tls_fp := q.Get("fp")
tls_sni := q.Get("sni") tls_sni := q.Get("sni")
@@ -516,5 +516,5 @@ func getTls(security string, q *url.Values) *map[string]interface{} {
}, },
} }
} }
return &tls return tls
} }