Реализован production-hardening по fix1: env/reconfigure, IPv4-only, TLS, secrets, firewall, docs

This commit is contained in:
2026-04-26 07:27:06 +05:00
parent 2b4a45ad23
commit 3fccd5c442
109 changed files with 1773 additions and 569 deletions
+16 -8
View File
@@ -26,14 +26,15 @@ func Login(c *gin.Context) {
return
}
token, err := service.Login(*loginDto.Username, util.SHA224String(*loginDto.Pass))
token, forcePasswordChange, err := service.Login(*loginDto.Username, *loginDto.Pass)
if err != nil {
vo.Fail(err.Error(), c)
return
}
jwtVo := vo.JwtVo{
TokenType: constant.TokenType,
AccessToken: token,
TokenType: constant.TokenType,
AccessToken: token,
ForcePasswordChange: forcePasswordChange,
}
vo.Success(jwtVo, c)
}
@@ -100,7 +101,11 @@ func SaveAccount(c *gin.Context) {
return
}
passEncrypt := util.SHA224String(*accountSaveDto.Pass)
passEncrypt, err := util.HashPassword(*accountSaveDto.Pass)
if err != nil {
vo.Fail(err.Error(), c)
return
}
conPass := fmt.Sprintf("%s.%s", *accountSaveDto.Username, *accountSaveDto.ConPass)
account := entity.Account{
Username: accountSaveDto.Username,
@@ -167,8 +172,12 @@ func UpdateAccount(c *gin.Context) {
var passEncrypt *string
if accountUpdateDto.Pass != nil && *accountUpdateDto.Pass != "" {
passEncryptSha224 := util.SHA224String(*accountUpdateDto.Pass)
passEncrypt = &passEncryptSha224
passEncryptHash, hashErr := util.HashPassword(*accountUpdateDto.Pass)
if hashErr != nil {
vo.Fail(hashErr.Error(), c)
return
}
passEncrypt = &passEncryptHash
}
account := entity.Account{
@@ -331,6 +340,5 @@ func VerifyDefaultPass(c *gin.Context) {
vo.Fail(err.Error(), c)
return
}
vo.Success(account.Pass != nil && *account.Pass == "02f382b76ca1ab7aa06ab03345c7712fd5b971fb0c0f2aef98bac9cd", c)
vo.Success(account.Pass != nil && !util.IsBcryptHash(*account.Pass), c)
}
+16 -59
View File
@@ -17,7 +17,6 @@ import (
"io"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
@@ -35,7 +34,6 @@ func UpdateConfigs(c *gin.Context) {
return
}
needResetPortHopping := false
needRestart := false
for _, item := range configsUpdateDto.ConfigUpdateDtos {
@@ -81,19 +79,8 @@ func UpdateConfigs(c *gin.Context) {
}
if key == constant.Hysteria2ConfigPortHopping {
re := regexp.MustCompile(`^\d+(?:-\d+)?(?:,\d+(?:-\d+)?)*$`)
if value != "" && !re.MatchString(value) {
vo.Fail(fmt.Sprintf("port hopping: %s is invalid", value), c)
return
}
hysteria2ConfigPortHopping, err := service.GetConfig(constant.Hysteria2ConfigPortHopping)
if err != nil {
vo.Fail(err.Error(), c)
return
}
if *hysteria2ConfigPortHopping.Value != value {
needResetPortHopping = true
}
vo.Fail("port hopping out of scope in HY2XS production", c)
return
}
if key == constant.ResetTrafficCron {
@@ -113,13 +100,6 @@ func UpdateConfigs(c *gin.Context) {
}
}
if needResetPortHopping {
if err := service.InitPortHopping(); err != nil {
vo.Fail(err.Error(), c)
return
}
}
if needRestart {
go func() {
_ = service.StopServer()
@@ -197,33 +177,11 @@ func UpdateHysteria2Config(c *gin.Context) {
return
}
hysteria2Config, err := service.GetHysteria2Config()
if err != nil {
vo.Fail(err.Error(), c)
return
}
needResetPortHopping := false
if hysteria2Config.Listen != nil &&
*hysteria2Config.Listen != "" &&
hysteria2ServerConfig.Listen != nil &&
*hysteria2ServerConfig.Listen != "" &&
*hysteria2ServerConfig.Listen != *hysteria2Config.Listen {
needResetPortHopping = true
}
if err = service.UpdateHysteria2Config(hysteria2ServerConfig); err != nil {
vo.Fail(err.Error(), c)
return
}
if needResetPortHopping {
if err := service.InitPortHopping(); err != nil {
vo.Fail(err.Error(), c)
return
}
}
running := service.Hysteria2IsRunning()
if running {
if err = service.RestartHysteria2(); err != nil {
@@ -242,24 +200,24 @@ func ExportHysteria2Config(c *gin.Context) {
}
// Значения по умолчанию
config, err := dao.ListConfig("key in ?", []string{constant.HUIWebPort, constant.JwtSecret})
config, err := dao.ListConfig("key in ?", []string{constant.HUIWebPort, constant.Hysteria2TrafficStatsSecret})
if err != nil {
vo.Fail(err.Error(), c)
return
}
var hUIWebPort string
var jwtSecret string
var trafficStatsSecret string
for _, item := range config {
if *item.Key == constant.HUIWebPort {
hUIWebPort = *item.Value
} else if *item.Key == constant.JwtSecret {
jwtSecret = *item.Value
} else if *item.Key == constant.Hysteria2TrafficStatsSecret {
trafficStatsSecret = *item.Value
}
}
if hUIWebPort == "" || jwtSecret == "" {
logrus.Errorf("hUIWebPort or jwtSecret is nil")
if hUIWebPort == "" || trafficStatsSecret == "" {
logrus.Errorf("hUIWebPort or trafficStatsSecret is nil")
vo.Fail(constant.SysError, c)
return
}
@@ -279,7 +237,7 @@ func ExportHysteria2Config(c *gin.Context) {
http.Insecure = &authHttpInsecure
auth.HTTP = &http
hysteria2ServerConfig.Auth = &auth
hysteria2ServerConfig.TrafficStats.Secret = &jwtSecret
hysteria2ServerConfig.TrafficStats.Secret = &trafficStatsSecret
fileName := fmt.Sprintf("Hysteria2Config-%s.yaml", time.Now().Format("20060102150405"))
filePath := constant.ExportPathDir + fileName
@@ -325,24 +283,24 @@ func ImportHysteria2Config(c *gin.Context) {
}
// Значения по умолчанию
config, err := dao.ListConfig("key in ?", []string{constant.HUIWebPort, constant.JwtSecret})
config, err := dao.ListConfig("key in ?", []string{constant.HUIWebPort, constant.Hysteria2TrafficStatsSecret})
if err != nil {
vo.Fail(err.Error(), c)
return
}
var hUIWebPort string
var jwtSecret string
var trafficStatsSecret string
for _, item := range config {
if *item.Key == constant.HUIWebPort {
hUIWebPort = *item.Value
} else if *item.Key == constant.JwtSecret {
jwtSecret = *item.Value
} else if *item.Key == constant.Hysteria2TrafficStatsSecret {
trafficStatsSecret = *item.Value
}
}
if hUIWebPort == "" || jwtSecret == "" {
logrus.Errorf("hUIWebPort or jwtSecret is nil")
if hUIWebPort == "" || trafficStatsSecret == "" {
logrus.Errorf("hUIWebPort or trafficStatsSecret is nil")
vo.Fail(constant.SysError, c)
return
}
@@ -362,7 +320,7 @@ func ImportHysteria2Config(c *gin.Context) {
http.Insecure = &authHttpInsecure
auth.HTTP = &http
hysteria2ServerConfig.Auth = &auth
hysteria2ServerConfig.TrafficStats.Secret = &jwtSecret
hysteria2ServerConfig.TrafficStats.Secret = &trafficStatsSecret
if err = service.SetHysteria2Config(hysteria2ServerConfig); err != nil {
vo.Fail(err.Error(), c)
@@ -501,4 +459,3 @@ func UploadCertFile(c *gin.Context) {
}
vo.Success(certPath, c)
}
-1
View File
@@ -150,4 +150,3 @@ func Hysteria2Subscribe(c *gin.Context) {
c.String(200, configStr)
}
-1
View File
@@ -114,4 +114,3 @@ func ExportLog(c *gin.Context) {
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", fileName))
c.File(filePath)
}
-1
View File
@@ -23,4 +23,3 @@ func MonitorHysteria2(c *gin.Context) {
}
vo.Success(hysteria2MonitorVo, c)
}
-1
View File
@@ -39,4 +39,3 @@ func validateField[T interface{}](c *gin.Context, field T) (T, error) {
}
return field, nil
}