fix: align admin behavior and Kratos integrations

This commit is contained in:
2026-08-14 14:14:51 +08:00
parent 8c4c6ba661
commit e0b0e1d8c8
123 changed files with 4334 additions and 1877 deletions
+114 -19
View File
@@ -2,12 +2,15 @@ package service
import (
"context"
"encoding/json"
"time"
"kra/internal/conf"
"kra/internal/service/dto"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/durationpb"
)
func (s *SystemService) PersistConfig(ctx context.Context) error { return s.uc.PersistConfig(ctx) }
@@ -22,42 +25,84 @@ func (s *SystemService) PersistAdminConfig(ctx context.Context, value *conf.Admi
func (s *SystemService) ReloadConfig(ctx context.Context) error { return s.uc.ReloadConfig(ctx) }
func (s *SystemService) DiskMountPoints() []string {
config := s.runtime.Admin()
if config == nil {
return nil
}
points := make([]string, 0, len(config.DiskList))
for _, item := range config.DiskList {
if item != nil && item.MountPoint != "" {
points = append(points, item.MountPoint)
}
}
return points
}
func (s *SystemService) SystemConfig() map[string]any {
admin := map[string]any{"routerPrefix": ""}
email := map[string]any{}
if s.config == nil {
return map[string]any{"config": map[string]any{"admin": admin, "email": email}}
config := s.runtime.Admin()
if config == nil {
return map[string]any{"config": map[string]any{"admin": admin, "email": email, "data": map[string]any{}}}
}
admin["routerPrefix"] = s.config.RouterPrefix
if s.config.Jwt != nil {
admin["jwt"] = map[string]any{"signingKey": "******", "expiresTime": s.config.Jwt.ExpiresTime.AsDuration().String(), "bufferTime": s.config.Jwt.BufferTime.AsDuration().String(), "issuer": s.config.Jwt.Issuer}
admin["routerPrefix"] = config.RouterPrefix
if config.System != nil {
admin["system"] = map[string]any{"useRedis": config.System.UseRedis, "useMultipoint": config.System.UseMultipoint, "useStrictAuth": config.System.UseStrictAuth, "disableAutoMigrate": config.System.DisableAutoMigrate}
}
if s.config.Captcha != nil {
admin["captcha"] = map[string]any{"keyLong": s.config.Captcha.KeyLong, "imgWidth": s.config.Captcha.ImgWidth, "imgHeight": s.config.Captcha.ImgHeight, "storeExpiration": s.config.Captcha.StoreExpiration.AsDuration().String()}
if config.Jwt != nil {
admin["jwt"] = map[string]any{"signingKey": "******", "expiresTime": config.Jwt.ExpiresTime.AsDuration().String(), "bufferTime": config.Jwt.BufferTime.AsDuration().String(), "issuer": config.Jwt.Issuer}
}
if s.config.Local != nil {
admin["local"] = map[string]any{"storePath": s.config.Local.StorePath, "pathPrefix": s.config.Local.PathPrefix}
if config.Captcha != nil {
admin["captcha"] = map[string]any{"keyLong": config.Captcha.KeyLong, "imgWidth": config.Captcha.ImgWidth, "imgHeight": config.Captcha.ImgHeight, "storeExpiration": config.Captcha.StoreExpiration.AsDuration().String()}
}
if s.config.Media != nil {
admin["media"] = map[string]any{"sessionTtl": s.config.Media.SessionTtl}
if config.Local != nil {
admin["local"] = map[string]any{"storePath": config.Local.StorePath, "pathPrefix": config.Local.PathPrefix}
}
if s.config.Email != nil {
email = map[string]any{"to": s.config.Email.To, "from": s.config.Email.From, "host": s.config.Email.Host, "secret": "******", "nickname": s.config.Email.Nickname, "port": s.config.Email.Port, "is-ssl": s.config.Email.IsSsl, "is-loginauth": s.config.Email.IsLoginAuth}
if config.Media != nil {
admin["media"] = map[string]any{"sessionTtl": config.Media.SessionTtl}
}
if s.config.Storage != nil {
storage := proto.Clone(s.config.Storage).(*conf.AdminBackend_Storage)
if config.Email != nil {
email = map[string]any{"to": config.Email.To, "from": config.Email.From, "host": config.Email.Host, "secret": "******", "nickname": config.Email.Nickname, "port": config.Email.Port, "is-ssl": config.Email.IsSsl, "is-loginauth": config.Email.IsLoginAuth}
}
if config.Storage != nil {
storage := proto.Clone(config.Storage).(*conf.AdminBackend_Storage)
maskStorageSecrets(storage)
admin["storage"] = storage
}
return map[string]any{"config": map[string]any{"admin": admin, "email": email}}
data := s.runtime.Data()
if data != nil {
if data.Database != nil {
data.Database.Password = "******"
}
for _, database := range data.DatabaseList {
if database != nil {
database.Password = "******"
}
}
}
dataMap := map[string]any{}
if raw, err := (protojson.MarshalOptions{UseProtoNames: true}).Marshal(data); err == nil {
_ = json.Unmarshal(raw, &dataMap)
}
return map[string]any{"config": map[string]any{"admin": admin, "email": email, "data": dataMap}}
}
func (s *SystemService) SaveSystemConfig(ctx context.Context, req *dto.SetSystemConfigRequest) error {
if s.config == nil {
config := s.runtime.Admin()
if config == nil {
return nil
}
next := proto.Clone(s.config).(*conf.AdminBackend)
next := proto.Clone(config).(*conf.AdminBackend)
data := s.runtime.Data()
next.RouterPrefix = req.Config.Admin.RouterPrefix
if next.System == nil {
next.System = &conf.AdminBackend_System{}
}
next.System.UseRedis = req.Config.Admin.System.UseRedis
next.System.UseMultipoint = req.Config.Admin.System.UseMultipoint
next.System.UseStrictAuth = req.Config.Admin.System.UseStrictAuth
next.System.DisableAutoMigrate = req.Config.Admin.System.DisableAutoMigrate
if next.Jwt != nil {
if req.Config.Admin.JWT.SigningKey != "" && req.Config.Admin.JWT.SigningKey != "******" {
next.Jwt.SigningKey = req.Config.Admin.JWT.SigningKey
@@ -65,6 +110,26 @@ func (s *SystemService) SaveSystemConfig(ctx context.Context, req *dto.SetSystem
if req.Config.Admin.JWT.Issuer != "" {
next.Jwt.Issuer = req.Config.Admin.JWT.Issuer
}
if value, err := time.ParseDuration(req.Config.Admin.JWT.ExpiresTime); err == nil && value > 0 {
next.Jwt.ExpiresTime = durationpb.New(value)
}
if value, err := time.ParseDuration(req.Config.Admin.JWT.BufferTime); err == nil && value >= 0 {
next.Jwt.BufferTime = durationpb.New(value)
}
}
if next.Captcha != nil {
if req.Config.Admin.Captcha.KeyLong > 0 {
next.Captcha.KeyLong = req.Config.Admin.Captcha.KeyLong
}
if req.Config.Admin.Captcha.ImgWidth > 0 {
next.Captcha.ImgWidth = req.Config.Admin.Captcha.ImgWidth
}
if req.Config.Admin.Captcha.ImgHeight > 0 {
next.Captcha.ImgHeight = req.Config.Admin.Captcha.ImgHeight
}
if value, err := time.ParseDuration(req.Config.Admin.Captcha.StoreExpiration); err == nil && value > 0 {
next.Captcha.StoreExpiration = durationpb.New(value)
}
}
if next.Local != nil {
if req.Config.Admin.Local.StorePath != "" {
@@ -89,7 +154,37 @@ func (s *SystemService) SaveSystemConfig(ctx context.Context, req *dto.SetSystem
next.Email.Secret = req.Config.Email.Secret
}
}
return s.PersistAdminConfig(ctx, next)
if req.Config.Data != nil {
if data == nil {
data = &conf.Data{}
}
if value := req.Config.Data.Database; value != nil {
password := value.Password
if data.Database != nil && (password == "" || password == "******") {
password = data.Database.Password
}
data.Database = &conf.Data_Database{Driver: value.Driver, Source: value.Source, Host: value.Host, Port: value.Port, User: value.User, Password: password, Name: value.Name, Config: value.Config, Path: value.Path}
}
if value := req.Config.Data.Redis; value != nil {
redis := &conf.Data_Redis{Network: value.Network, Addr: value.Addr}
if duration, parseErr := time.ParseDuration(value.ReadTimeout); parseErr == nil && duration >= 0 {
redis.ReadTimeout = durationpb.New(duration)
}
if duration, parseErr := time.ParseDuration(value.WriteTimeout); parseErr == nil && duration >= 0 {
redis.WriteTimeout = durationpb.New(duration)
}
data.Redis = redis
}
}
dataRaw, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(data)
if err != nil {
return err
}
adminRaw, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(next)
if err != nil {
return err
}
return s.uc.PersistRuntimeConfig(ctx, dataRaw, adminRaw)
}
func objectStores(storage *conf.AdminBackend_Storage) []*conf.AdminBackend_ObjectStore {