fix(fix4): enforce runtime contract and orchestrator guardrails
This commit is contained in:
@@ -19,6 +19,21 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func isOrchestratorManagedConfigKey(key string) bool {
|
||||
switch key {
|
||||
case constant.HUIWebPort,
|
||||
constant.HUIWebContext,
|
||||
constant.HUICrtPath,
|
||||
constant.HUIKeyPath,
|
||||
constant.Hysteria2Enable,
|
||||
constant.Hysteria2Config,
|
||||
constant.Hysteria2TrafficStatsSecret:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateConfigs(c *gin.Context) {
|
||||
configsUpdateDto, err := validateField(c, dto.ConfigsUpdateDto{})
|
||||
if err != nil {
|
||||
@@ -37,6 +52,11 @@ func UpdateConfigs(c *gin.Context) {
|
||||
key := *item.Key
|
||||
value := *item.Value
|
||||
|
||||
if isOrchestratorManagedConfigKey(key) {
|
||||
vo.Fail(fmt.Sprintf("%s managed by orchestrator: use hy2xs-orchestrator reconfigure", key), c)
|
||||
return
|
||||
}
|
||||
|
||||
if key == constant.HUIWebPort && strconv.FormatInt(port, 10) != value {
|
||||
port, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
@@ -117,17 +137,12 @@ func GetConfig(c *gin.Context) {
|
||||
}
|
||||
|
||||
running := service.Hysteria2IsRunning()
|
||||
|
||||
if (*config.Value == "1") != running {
|
||||
enable := "0"
|
||||
if *config.Key == constant.Hysteria2Enable {
|
||||
if running {
|
||||
enable = "1"
|
||||
configVo.Value = "1"
|
||||
} else {
|
||||
configVo.Value = "0"
|
||||
}
|
||||
if err := service.UpdateConfig(constant.Hysteria2Enable, enable); err != nil {
|
||||
vo.Fail(err.Error(), c)
|
||||
return
|
||||
}
|
||||
configVo.Value = enable
|
||||
}
|
||||
|
||||
vo.Success(configVo, c)
|
||||
@@ -284,6 +299,12 @@ func ImportConfig(c *gin.Context) {
|
||||
vo.Fail("content Unmarshal err", c)
|
||||
return
|
||||
}
|
||||
for _, cfg := range configs {
|
||||
if cfg.Key != nil && isOrchestratorManagedConfigKey(*cfg.Key) {
|
||||
vo.Fail(fmt.Sprintf("%s managed by orchestrator: use hy2xs-orchestrator reconfigure", *cfg.Key), c)
|
||||
return
|
||||
}
|
||||
}
|
||||
if err = service.UpsertConfig(configs); err != nil {
|
||||
vo.Fail(err.Error(), c)
|
||||
return
|
||||
|
||||
+8
-16
@@ -2,7 +2,6 @@ package dao
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/glebarez/sqlite"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
@@ -120,7 +119,7 @@ func ensureAccountSchema() error {
|
||||
func ensureSecureBootstrapAdmin() error {
|
||||
adminUser := strings.TrimSpace(os.Getenv("HY2XS_ADMIN_USER"))
|
||||
if adminUser == "" {
|
||||
adminUser = "admin"
|
||||
adminUser = "hy2xsadmin"
|
||||
}
|
||||
adminPassword := strings.TrimSpace(os.Getenv("HY2XS_ADMIN_INITIAL_PASSWORD"))
|
||||
if adminPassword == "" {
|
||||
@@ -136,11 +135,14 @@ func ensureSecureBootstrapAdmin() error {
|
||||
deviceNo := int64(envInt("HY2XS_ADMIN_DEVICE_NO", 6))
|
||||
role := "admin"
|
||||
deleted := int64(0)
|
||||
conPassSecret, conErr := util.RandomString(28)
|
||||
if conErr != nil {
|
||||
return conErr
|
||||
conPass := strings.TrimSpace(os.Getenv("HY2XS_ADMIN_CON_PASS"))
|
||||
if conPass == "" {
|
||||
generated, genErr := util.RandomString(28)
|
||||
if genErr != nil {
|
||||
return genErr
|
||||
}
|
||||
conPass = generated
|
||||
}
|
||||
conPass := fmt.Sprintf("%s.%s", adminUser, conPassSecret)
|
||||
hash, hashErr := util.HashPassword(adminPassword)
|
||||
if hashErr != nil {
|
||||
return hashErr
|
||||
@@ -169,16 +171,6 @@ func ensureSecureBootstrapAdmin() error {
|
||||
if admin.Pass == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"username": adminUser,
|
||||
"pass": hash,
|
||||
"con_pass": conPass,
|
||||
"force_password_change": forcePasswordChange,
|
||||
}
|
||||
if updateErr := UpdateAccount([]int64{*admin.Id}, updates); updateErr != nil {
|
||||
return updateErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -27,9 +27,6 @@ func NewHysteria2Api(apiPort int64) *Hysteria2Api {
|
||||
// ListUsers Информация о трафике каждого пользователя
|
||||
func (h *Hysteria2Api) ListUsers(clear bool, secret string) (map[string]bo.Hysteria2UserTraffic, error) {
|
||||
var users map[string]bo.Hysteria2UserTraffic
|
||||
if !NewHysteria2Instance().IsRunning() {
|
||||
return users, nil
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
url := fmt.Sprintf("http://127.0.0.1:%d/traffic", h.apiPort)
|
||||
@@ -66,9 +63,6 @@ func (h *Hysteria2Api) ListUsers(clear bool, secret string) (map[string]bo.Hyste
|
||||
|
||||
// KickUsers Принудительное отключение
|
||||
func (h *Hysteria2Api) KickUsers(keys []string, secret string) error {
|
||||
if !NewHysteria2Instance().IsRunning() {
|
||||
return nil
|
||||
}
|
||||
usernamesByte, err := json.Marshal(keys)
|
||||
if err != nil {
|
||||
logrus.Errorf("Hysteria2 KickUsers Marshal err: %v", err)
|
||||
@@ -101,9 +95,6 @@ func (h *Hysteria2Api) KickUsers(keys []string, secret string) error {
|
||||
// OnlineUsers Пользователи онлайн
|
||||
func (h *Hysteria2Api) OnlineUsers(secret string) (map[string]int64, error) {
|
||||
var onlineUsers map[string]int64
|
||||
if !NewHysteria2Instance().IsRunning() {
|
||||
return onlineUsers, nil
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
url := fmt.Sprintf("http://127.0.0.1:%d/online", h.apiPort)
|
||||
|
||||
@@ -15,26 +15,6 @@ import (
|
||||
)
|
||||
|
||||
func UpdateConfig(key string, value string) error {
|
||||
if key == constant.Hysteria2Enable {
|
||||
if value == "1" {
|
||||
hysteria2Config, err := GetHysteria2Config()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if hysteria2Config.Listen == nil || *hysteria2Config.Listen == "" {
|
||||
logrus.Errorf("hysteria2 config is empty")
|
||||
return errors.New("hysteria2 config is empty")
|
||||
}
|
||||
// Запуск Hysteria2
|
||||
if err = StartHysteria2(); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := StopHysteria2(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return dao.UpdateConfig([]string{key}, map[string]interface{}{"value": value})
|
||||
}
|
||||
|
||||
|
||||
+14
-16
@@ -17,27 +17,25 @@ var kickMutex sync.Mutex
|
||||
|
||||
func CronHandleAccount() {
|
||||
go func() {
|
||||
hysteriaEnable, err := dao.GetConfig("key = ?", constant.Hysteria2Enable)
|
||||
if !Hysteria2IsRunning() {
|
||||
return
|
||||
}
|
||||
|
||||
apiPort, err := GetHysteria2ApiPort()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if hysteriaEnable.Value != nil && *hysteriaEnable.Value == "1" {
|
||||
apiPort, err := GetHysteria2ApiPort()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
trafficSecretConfig, err := dao.GetConfig("key = ?", constant.Hysteria2TrafficStatsSecret)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Сохранение данных трафика
|
||||
go saveAccountTraffic(apiPort, *trafficSecretConfig.Value)
|
||||
|
||||
// Принудительное отключение
|
||||
go kickAccount(apiPort, *trafficSecretConfig.Value)
|
||||
trafficSecretConfig, err := dao.GetConfig("key = ?", constant.Hysteria2TrafficStatsSecret)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Сохранение данных трафика
|
||||
go saveAccountTraffic(apiPort, *trafficSecretConfig.Value)
|
||||
|
||||
// Принудительное отключение
|
||||
go kickAccount(apiPort, *trafficSecretConfig.Value)
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,6 @@ func StartServer(crtPath string, keyPath string) error {
|
||||
}
|
||||
|
||||
func StopServer() error {
|
||||
if err := StopHysteria2(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
if err := server.Shutdown(ctx); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user