From 7a64d76d08d90619874dc31081aafb52277cfc00 Mon Sep 17 00:00:00 2001 From: Crimson Date: Sat, 9 May 2026 00:45:20 +0500 Subject: [PATCH] =?UTF-8?q?Fix25.1:=20=D1=81=D1=82=D0=B0=D0=B1=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=20auth=5Fid=20?= =?UTF-8?q?flow=20=D0=B8=20unlimited-=D1=81=D0=B5=D0=BC=D0=B0=D0=BD=D1=82?= =?UTF-8?q?=D0=B8=D0=BA=D0=B0,=20=D1=83=D1=81=D0=B8=D0=BB=D0=B5=D0=BD=20bo?= =?UTF-8?q?otstrap=20secrets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/dao/sqlite.go | 57 +++++++++++++++++++-- apps/frontend/src/views/peer/list/index.vue | 4 +- apps/service/cron.go | 30 ++++++----- apps/service/hysteria2_api.go | 18 ++++--- 4 files changed, 83 insertions(+), 26 deletions(-) diff --git a/apps/dao/sqlite.go b/apps/dao/sqlite.go index 8b0c6da..a956d47 100644 --- a/apps/dao/sqlite.go +++ b/apps/dao/sqlite.go @@ -63,6 +63,9 @@ func InitSql(port string) error { if err := ensureSecureBootstrapAdmin(); err != nil { return err } + if _, err := getOrCreateJwtSecret(); err != nil { + return err + } if err := ensureTrafficStatsSecret(); err != nil { return err } @@ -337,7 +340,11 @@ func migrateLegacyAccounts() error { if authErr != nil { return authErr } - secretDigest := util.PeerSecretDigest(*acc.ConPass) + peerSecretKey, keyErr := getOrCreatePeerSecretDigestKey() + if keyErr != nil { + return keyErr + } + secretDigest := util.HmacSHA256Hex(*acc.ConPass, peerSecretKey) secretEncrypted := *acc.ConPass quota := int64(0) if acc.Quota != nil { @@ -397,6 +404,46 @@ func migrateLegacyAccounts() error { return nil } +func getOrCreateJwtSecret() (string, error) { + if existing, err := GetConfig("key = ?", constant.JwtSecret); err == nil { + if existing.Value != nil && strings.TrimSpace(*existing.Value) != "" { + return strings.TrimSpace(*existing.Value), nil + } + } + secret, secErr := util.RandomString(64) + if secErr != nil { + return "", secErr + } + if err := UpdateConfig([]string{constant.JwtSecret}, map[string]interface{}{"value": secret}); err != nil { + key := constant.JwtSecret + remark := "JWT signing secret" + if _, saveErr := SaveConfig(entity.Config{Key: &key, Value: &secret, Remark: &remark}); saveErr != nil { + return "", saveErr + } + } + return secret, nil +} + +func getOrCreatePeerSecretDigestKey() (string, error) { + if existing, err := GetConfig("key = ?", constant.PeerSecretKey); err == nil { + if existing.Value != nil && strings.TrimSpace(*existing.Value) != "" { + return strings.TrimSpace(*existing.Value), nil + } + } + keyValue, keyErr := util.RandomString(48) + if keyErr != nil { + return "", keyErr + } + if err := UpdateConfig([]string{constant.PeerSecretKey}, map[string]interface{}{"value": keyValue}); err != nil { + key := constant.PeerSecretKey + remark := "Peer secret digest key" + if _, saveErr := SaveConfig(entity.Config{Key: &key, Value: &keyValue, Remark: &remark}); saveErr != nil { + return "", saveErr + } + } + return keyValue, nil +} + func archiveLegacyAccount() error { if !tableExists("account") { return nil @@ -517,7 +564,7 @@ func ensureTrafficStatsSecret() error { envSecret := strings.TrimSpace(os.Getenv("HY2XS_HYSTERIA_TRAFFIC_STATS_SECRET")) if envSecret != "" { if existing, err := GetConfig("key = ?", constant.Hysteria2TrafficStatsSecret); err == nil { - if existing.Value != nil && *existing.Value != envSecret { + if existing.Value != nil && strings.TrimSpace(*existing.Value) != envSecret { return UpdateConfig([]string{constant.Hysteria2TrafficStatsSecret}, map[string]interface{}{"value": envSecret}) } return nil @@ -530,8 +577,10 @@ func ensureTrafficStatsSecret() error { return nil } - if _, err := GetConfig("key = ?", constant.Hysteria2TrafficStatsSecret); err == nil { - return nil + if existing, err := GetConfig("key = ?", constant.Hysteria2TrafficStatsSecret); err == nil { + if existing.Value != nil && strings.TrimSpace(*existing.Value) != "" { + return nil + } } secret, secErr := util.RandomString(32) if secErr != nil { diff --git a/apps/frontend/src/views/peer/list/index.vue b/apps/frontend/src/views/peer/list/index.vue index 7a610d7..ce8cf93 100644 --- a/apps/frontend/src/views/peer/list/index.vue +++ b/apps/frontend/src/views/peer/list/index.vue @@ -99,7 +99,7 @@ const dialog = reactive({ visible: false, title: "", editId: 0 }); const dataForm = reactive({ name: "", secret: "", - quotaBytes: 0, + quotaBytes: -1, expiresAt: getMonthLater(), maxDevices: 3, disabled: 0, @@ -123,7 +123,7 @@ async function handleQuery() { } function handleAdd() { - Object.assign(dataForm, { id: undefined, name: "", secret: "", quotaBytes: 0, expiresAt: getMonthLater(), maxDevices: 3, disabled: 0, remark: "" }); + Object.assign(dataForm, { id: undefined, name: "", secret: "", quotaBytes: -1, expiresAt: getMonthLater(), maxDevices: 3, disabled: 0, remark: "" }); dialog.title = t("common.add"); dialog.editId = 0; dialog.visible = true; diff --git a/apps/service/cron.go b/apps/service/cron.go index a76e4ab..9c96a39 100644 --- a/apps/service/cron.go +++ b/apps/service/cron.go @@ -83,10 +83,7 @@ func saveAccountTraffic(apiPort int64, trafficStatsSecret string) { peer, peerErr := dao.GetPeer("auth_id = ?", key) if peerErr != nil { - peer, peerErr = dao.GetPeer("name = ?", key) - if peerErr != nil { - continue - } + continue } if peer.Id == nil { continue @@ -133,32 +130,37 @@ func kickAccount(apiPort int64, trafficStatsSecret string) { } if len(users) > 0 { i := 0 - usernames := make([]string, len(users)) + authIDs := make([]string, len(users)) for k := range users { - usernames[i] = k + authIDs[i] = k i++ } - usernameLists := util.SplitArr(usernames, 10) + authIDLists := util.SplitArr(authIDs, 10) var wg sync.WaitGroup - for _, usernameList := range usernameLists { + for _, authIDList := range authIDLists { wg.Add(1) - go func(usernameList []string) { + go func(authIDList []string) { defer wg.Done() now := time.Now().UnixMilli() - peers, err := dao.ListPeer("name in ? and (disabled = 1 or (quota_bytes > 0 and quota_bytes < download_bytes + upload_bytes) or ? > expires_at or ? < banned_until)", usernameList, now, now) + peers, err := dao.ListPeer(`auth_id in ? and ( + disabled = 1 + or (quota_bytes > 0 and quota_bytes < download_bytes + upload_bytes) + or (expires_at > 0 and ? > expires_at) + or ? < banned_until + )`, authIDList, now, now) if err != nil { return } - kickUsernames := make([]string, len(peers)) + kickAuthIDs := make([]string, len(peers)) j := 0 for _, item := range peers { - kickUsernames[j] = *item.Name + kickAuthIDs[j] = *item.AuthId j++ } - if err = proxy.NewHysteria2Api(apiPort).KickUsers(kickUsernames, trafficStatsSecret); err != nil { + if err = proxy.NewHysteria2Api(apiPort).KickUsers(kickAuthIDs, trafficStatsSecret); err != nil { return } - }(usernameList) + }(authIDList) } wg.Wait() } diff --git a/apps/service/hysteria2_api.go b/apps/service/hysteria2_api.go index c45cea1..a0492c8 100644 --- a/apps/service/hysteria2_api.go +++ b/apps/service/hysteria2_api.go @@ -5,7 +5,6 @@ import ( "hy2xs-admin/dao" "hy2xs-admin/model/constant" "hy2xs-admin/proxy" - "hy2xs-admin/util" "net" "net/url" "os" @@ -36,8 +35,15 @@ func Hysteria2Auth(conPass string) (int64, string, error) { } now := time.Now().UnixMilli() - secretDigest := util.PeerSecretDigest(conPass) - peer, err := dao.GetPeer("secret_digest = ? and disabled = 0 and (quota_bytes < 0 or quota_bytes > download_bytes + upload_bytes) and ? < expires_at and ? > banned_until", secretDigest, now, now) + secretDigest, digestErr := PeerSecretDigest(conPass) + if digestErr != nil { + return 0, "", digestErr + } + peer, err := dao.GetPeer(`secret_digest = ? + and disabled = 0 + and (quota_bytes < 0 or quota_bytes > download_bytes + upload_bytes) + and (expires_at = 0 or ? < expires_at) + and ? > banned_until`, secretDigest, now, now) if err != nil { return 0, "", err } @@ -47,12 +53,12 @@ func Hysteria2Auth(conPass string) (int64, string, error) { if err != nil { return 0, "", err } - device, exist := onlineUsers[*peer.Name] + device, exist := onlineUsers[*peer.AuthId] if exist && *peer.MaxDevices <= device { return 0, "", errors.New("device limited") } - return *peer.Id, *peer.Name, nil + return *peer.Id, *peer.AuthId, nil } func Hysteria2Online() (map[string]int64, error) { @@ -88,7 +94,7 @@ func Hysteria2Kick(ids []int64, kickUtilTime int64) error { } var keys []string for _, item := range peers { - keys = append(keys, *item.Name) + keys = append(keys, *item.AuthId) } apiPort, err := GetHysteria2ApiPort() if err != nil {