diff --git a/agent/cmd/server/docs/x-log.json b/agent/cmd/server/docs/x-log.json index 1de58c9591bf..0081a2101784 100644 --- a/agent/cmd/server/docs/x-log.json +++ b/agent/cmd/server/docs/x-log.json @@ -858,6 +858,15 @@ "formatZH": "查看 AI 网关 API Key [id]", "formatEN": "reveal AI proxy API key [id]" }, + "/core/enterprise/ai-proxy/api-keys/token/reset": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "重置 AI 网关 API Key Token [id]", + "formatEN": "reset AI proxy API key token [id]" + }, "/core/enterprise/ai-proxy/api-keys/update": { "bodyKeys": [ "id", diff --git a/core/app/api/v2/setting.go b/core/app/api/v2/setting.go index fd8a61025cb7..b2aa7d6cbe95 100644 --- a/core/app/api/v2/setting.go +++ b/core/app/api/v2/setting.go @@ -7,6 +7,7 @@ import ( "os" "path" "regexp" + "strconv" "strings" "github.com/1Panel-dev/1Panel/core/app/api/v2/helper" @@ -94,6 +95,10 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) { return } } + if !checkSettingValueRange(req.Key, req.Value) { + helper.ErrorWithDetail(c, http.StatusBadRequest, "ErrInvalidParams", buserr.WithName("ErrInvalidParams", req.Value)) + return + } if req.Key == "PasskeyTrustedProxies" { value, err := normalizePasskeyTrustedProxies(req.Value) if err != nil { @@ -113,6 +118,25 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) { helper.Success(c) } +func checkSettingValueRange(key, value string) bool { + switch key { + case "SessionTimeout": + valueNum, err := strconv.Atoi(value) + if err != nil { + return false + } + return valueNum >= 300 && valueNum <= 864000 + case "ExpirationDays": + valueNum, err := strconv.Atoi(value) + if err != nil { + return false + } + return valueNum >= 0 && valueNum <= 60 + default: + return true + } +} + // @Tags System Setting // @Summary Update system terminal setting // @Accept json diff --git a/core/app/auth/auth.go b/core/app/auth/auth.go index 3ae56db90f1d..76f600e364e8 100644 --- a/core/app/auth/auth.go +++ b/core/app/auth/auth.go @@ -245,8 +245,6 @@ func GetCurrentUserInfo() (*dto.CurrentUserInfo, error) { if err := json.Unmarshal(arr, &info); err != nil { return nil, err } - info.SessionTimeout, _ = strconv.Atoi(settingMap["SessionTimeout"]) - info.ExpirationDays, _ = strconv.Atoi(settingMap["ExpirationDays"]) info.MFAInterval, _ = strconv.Atoi(settingMap["MFAInterval"]) info.ApiKeyValidityTime, _ = strconv.Atoi(settingMap["ApiKeyValidityTime"]) info.Name = settingMap["UserName"] @@ -255,6 +253,13 @@ func GetCurrentUserInfo() (*dto.CurrentUserInfo, error) { info.NodeRoles = []dto.CurrentUserNodeRole{} return &info, nil } +func LoadPasswordExpirationTime(_ *gin.Context) (string, error) { + return repo.NewISettingRepo().GetValueByKey("ExpirationTime") +} +func SyncPasswordExpirationTime(expirationDays string) error { + expiredDays, _ := strconv.Atoi(expirationDays) + return repo.NewISettingRepo().Update("ExpirationTime", buildPasswordExpirationTime(expiredDays)) +} func UpdateCurrentUserInfo(c *gin.Context, req dto.CurrentUserUpdate) error { settingRepo := repo.NewISettingRepo() currentName, err := settingRepo.GetValueByKey("UserName") @@ -281,20 +286,6 @@ func UpdateCurrentUserInfo(c *gin.Context, req dto.CurrentUserUpdate) error { if err := settingRepo.Update("UserName", req.Name); err != nil { return err } - if err := settingRepo.Update("SessionTimeout", strconv.Itoa(req.SessionTimeout)); err != nil { - return err - } - if err := settingRepo.Update("ExpirationDays", strconv.Itoa(req.ExpirationDays)); err != nil { - return err - } - - expirationTime := "" - if req.ExpirationDays != 0 { - expirationTime = time.Now().AddDate(0, 0, req.ExpirationDays).Format(constant.DateTimeLayout) - } - if err := settingRepo.Update("ExpirationTime", expirationTime); err != nil { - return err - } if shouldDeleteSession { deleteCurrentSession(c) } @@ -349,7 +340,7 @@ func HandlePasswordExpired(c *gin.Context, old, new string) error { return err } timeout, _ := strconv.Atoi(expiredSetting.Value) - if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format(constant.DateTimeLayout)); err != nil { + if err := settingRepo.Update("ExpirationTime", buildPasswordExpirationTime(timeout)); err != nil { return err } return nil @@ -357,35 +348,11 @@ func HandlePasswordExpired(c *gin.Context, old, new string) error { return buserr.New("ErrInitialPassword") } -func LoadSessionTimeout(sessionUser psession.SessionUser) (int, error) { - settingRepo := repo.NewISettingRepo() - sessionTimeout, err := settingRepo.GetValueByKey("SessionTimeout") - if err != nil { - return 0, err - } - lifeTime, _ := strconv.Atoi(sessionTimeout) - return lifeTime, nil -} -func LoadExpired(sessionUser psession.SessionUser) (bool, time.Time, error) { - settingRepo := repo.NewISettingRepo() - expirationDays, err := settingRepo.GetValueByKey("ExpirationDays") - if err != nil { - return true, time.Time{}, err - } - expiredDays, _ := strconv.Atoi(expirationDays) - if expiredDays == 0 { - return false, time.Time{}, nil - } - - expirationTime, err := settingRepo.GetValueByKey("ExpirationTime") - if err != nil { - return true, time.Time{}, err - } - expiredTime, err := time.ParseInLocation(constant.DateTimeLayout, expirationTime, common.LoadExpiredLocation()) - if err != nil { - return true, time.Time{}, err +func buildPasswordExpirationTime(expirationDays int) string { + if expirationDays == 0 { + return "" } - return true, expiredTime, nil + return time.Now().AddDate(0, 0, expirationDays).Format(constant.DateTimeLayout) } func deleteCurrentSession(c *gin.Context) { diff --git a/core/app/dto/auth.go b/core/app/dto/auth.go index aa2051dba353..4220c497767b 100644 --- a/core/app/dto/auth.go +++ b/core/app/dto/auth.go @@ -62,11 +62,8 @@ type ApiInterfaceConfig struct { type CurrentUserInfo struct { Name string `json:"name"` - SessionTimeout int `json:"sessionTimeout"` MFAStatus string `json:"mfaStatus"` MFAInterval int `json:"mfaInterval"` - ExpirationDays int `json:"expirationDays"` - ExpirationTime string `json:"expirationTime"` ComplexitySetting string `json:"complexitySetting"` ApiInterfaceStatus string `json:"apiInterfaceStatus"` @@ -87,10 +84,7 @@ type CurrentUserNodeRole struct { } type CurrentUserUpdate struct { - Name string `json:"name" validate:"required"` - Password string `json:"password"` - OldPassword string `json:"oldPassword"` - SessionTimeout int `json:"sessionTimeout" validate:"required,min=300,max=864000"` - ExpirationDays int `json:"expirationDays" validate:"min=0,max=60"` - ExpirationTime string `json:"expirationTime"` + Name string `json:"name" validate:"required"` + Password string `json:"password"` + OldPassword string `json:"oldPassword"` } diff --git a/core/app/dto/setting.go b/core/app/dto/setting.go index f3b54a0c7cc7..9527d1a9fc8b 100644 --- a/core/app/dto/setting.go +++ b/core/app/dto/setting.go @@ -9,16 +9,17 @@ type SettingInfo struct { DeveloperMode string `json:"developerMode"` UpgradeBackupCopies string `json:"upgradeBackupCopies"` - Port string `json:"port"` - Ipv6 string `json:"ipv6"` - BindAddress string `json:"bindAddress"` - PanelName string `json:"panelName"` - Edition string `json:"edition"` - Theme string `json:"theme"` - MenuTabs string `json:"menuTabs"` - Language string `json:"language"` - DocSource string `json:"docSource"` - IsOffline string `json:"isOffline"` + SessionTimeout string `json:"sessionTimeout"` + Port string `json:"port"` + Ipv6 string `json:"ipv6"` + BindAddress string `json:"bindAddress"` + PanelName string `json:"panelName"` + Edition string `json:"edition"` + Theme string `json:"theme"` + MenuTabs string `json:"menuTabs"` + Language string `json:"language"` + DocSource string `json:"docSource"` + IsOffline string `json:"isOffline"` ServerPort string `json:"serverPort"` SSL string `json:"ssl"` @@ -30,7 +31,6 @@ type SettingInfo struct { DashboardMemoVisible string `json:"dashboardMemoVisible"` DashboardSimpleNodeVisible string `json:"dashboardSimpleNodeVisible"` ExpirationDays string `json:"expirationDays"` - ExpirationTime string `json:"expirationTime"` ComplexityVerification string `json:"complexityVerification"` AppStoreVersion string `json:"appStoreVersion"` diff --git a/core/app/service/setting.go b/core/app/service/setting.go index 278a4c814d6e..545efe0be9f5 100644 --- a/core/app/service/setting.go +++ b/core/app/service/setting.go @@ -169,11 +169,17 @@ func (u *SettingService) Update(c *gin.Context, key, value string) error { if oldVal.Value == value { return nil } + sessionLifeTime := 0 switch key { case "IsOffline": if !global.CONF.Base.IsEnterprise { return buserr.New("ErrNotSupportInEnterpriseEdition") } + case "SessionTimeout": + sessionLifeTime, err = strconv.Atoi(value) + if err != nil { + return err + } case "AppStoreLastModified": exist, _ := settingRepo.Get(repo.WithByKey("AppStoreLastModified")) if exist.ID == 0 { @@ -200,6 +206,14 @@ func (u *SettingService) Update(c *gin.Context, key, value string) error { if err := settingRepo.Update(key, value); err != nil { return err } + if key == "ExpirationDays" { + if err := xpack.AuthProvider.SyncPasswordExpirationTime(value); err != nil { + return err + } + } + if key == "SessionTimeout" { + global.SESSION.ApplyTimeout(sessionLifeTime) + } switch key { case "BindDomain": @@ -504,37 +518,6 @@ func (u *SettingService) LoadFromCert() (*dto.SSLInfo, error) { return &data, nil } -func (u *SettingService) HandlePasswordExpired(c *gin.Context, old, new string) error { - setting, err := settingRepo.Get(repo.WithByKey("Password")) - if err != nil { - return err - } - passwordFromDB, err := encrypt.StringDecrypt(setting.Value) - if err != nil { - return err - } - if passwordFromDB == old { - newPassword, err := encrypt.StringEncrypt(new) - if err != nil { - return err - } - if err := settingRepo.Update("Password", newPassword); err != nil { - return err - } - - expiredSetting, err := settingRepo.Get(repo.WithByKey("ExpirationDays")) - if err != nil { - return err - } - timeout, _ := strconv.Atoi(expiredSetting.Value) - if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format(constant.DateTimeLayout)); err != nil { - return err - } - return nil - } - return buserr.New("ErrInitialPassword") -} - func (u *SettingService) GetTerminalInfo() (*dto.TerminalInfo, error) { setting, err := settingRepo.List() if err != nil { diff --git a/core/cmd/server/docs/docs.go b/core/cmd/server/docs/docs.go index e6aad283d19e..09a67f1611f8 100644 --- a/core/cmd/server/docs/docs.go +++ b/core/cmd/server/docs/docs.go @@ -27460,7 +27460,8 @@ const docTemplate = `{ "enum": [ "SystemIP", "DockerSockPath", - "FileRecycleBin" + "FileRecycleBin", + "FirewallPortWhiteList" ], "type": "string" }, @@ -29939,12 +29940,6 @@ const docTemplate = `{ "complexitySetting": { "type": "string" }, - "expirationDays": { - "type": "integer" - }, - "expirationTime": { - "type": "string" - }, "ipWhiteList": { "type": "string" }, @@ -29971,9 +29966,6 @@ const docTemplate = `{ }, "role": { "type": "string" - }, - "sessionTimeout": { - "type": "integer" } }, "type": "object" @@ -29997,14 +29989,6 @@ const docTemplate = `{ }, "dto.CurrentUserUpdate": { "properties": { - "expirationDays": { - "maximum": 60, - "minimum": 0, - "type": "integer" - }, - "expirationTime": { - "type": "string" - }, "name": { "type": "string" }, @@ -30013,16 +29997,10 @@ const docTemplate = `{ }, "password": { "type": "string" - }, - "sessionTimeout": { - "maximum": 864000, - "minimum": 300, - "type": "integer" } }, "required": [ - "name", - "sessionTimeout" + "name" ], "type": "object" }, @@ -34284,6 +34262,9 @@ const docTemplate = `{ }, "dto.SearchLgLogWithPage": { "properties": { + "endTime": { + "type": "string" + }, "info": { "type": "string" }, @@ -34293,6 +34274,9 @@ const docTemplate = `{ "pageSize": { "type": "integer" }, + "startTime": { + "type": "string" + }, "status": { "type": "string" } @@ -34409,6 +34393,9 @@ const docTemplate = `{ ], "type": "string" }, + "endTime": { + "type": "string" + }, "info": { "type": "string" }, @@ -34417,6 +34404,9 @@ const docTemplate = `{ }, "pageSize": { "type": "integer" + }, + "startTime": { + "type": "string" } }, "required": [ @@ -34559,6 +34549,9 @@ const docTemplate = `{ "fileRecycleBin": { "type": "string" }, + "firewallPortWhiteList": { + "type": "string" + }, "lastCleanData": { "type": "string" }, diff --git a/core/cmd/server/docs/swagger.json b/core/cmd/server/docs/swagger.json index 6f9ea21accd6..d9c831368f5d 100644 --- a/core/cmd/server/docs/swagger.json +++ b/core/cmd/server/docs/swagger.json @@ -27456,7 +27456,8 @@ "enum": [ "SystemIP", "DockerSockPath", - "FileRecycleBin" + "FileRecycleBin", + "FirewallPortWhiteList" ], "type": "string" }, @@ -29935,12 +29936,6 @@ "complexitySetting": { "type": "string" }, - "expirationDays": { - "type": "integer" - }, - "expirationTime": { - "type": "string" - }, "ipWhiteList": { "type": "string" }, @@ -29967,9 +29962,6 @@ }, "role": { "type": "string" - }, - "sessionTimeout": { - "type": "integer" } }, "type": "object" @@ -29993,14 +29985,6 @@ }, "dto.CurrentUserUpdate": { "properties": { - "expirationDays": { - "maximum": 60, - "minimum": 0, - "type": "integer" - }, - "expirationTime": { - "type": "string" - }, "name": { "type": "string" }, @@ -30009,16 +29993,10 @@ }, "password": { "type": "string" - }, - "sessionTimeout": { - "maximum": 864000, - "minimum": 300, - "type": "integer" } }, "required": [ - "name", - "sessionTimeout" + "name" ], "type": "object" }, @@ -34280,6 +34258,9 @@ }, "dto.SearchLgLogWithPage": { "properties": { + "endTime": { + "type": "string" + }, "info": { "type": "string" }, @@ -34289,6 +34270,9 @@ "pageSize": { "type": "integer" }, + "startTime": { + "type": "string" + }, "status": { "type": "string" } @@ -34405,6 +34389,9 @@ ], "type": "string" }, + "endTime": { + "type": "string" + }, "info": { "type": "string" }, @@ -34413,6 +34400,9 @@ }, "pageSize": { "type": "integer" + }, + "startTime": { + "type": "string" } }, "required": [ @@ -34555,6 +34545,9 @@ "fileRecycleBin": { "type": "string" }, + "firewallPortWhiteList": { + "type": "string" + }, "lastCleanData": { "type": "string" }, diff --git a/core/cmd/server/docs/x-log.json b/core/cmd/server/docs/x-log.json index 1de58c9591bf..0081a2101784 100644 --- a/core/cmd/server/docs/x-log.json +++ b/core/cmd/server/docs/x-log.json @@ -858,6 +858,15 @@ "formatZH": "查看 AI 网关 API Key [id]", "formatEN": "reveal AI proxy API key [id]" }, + "/core/enterprise/ai-proxy/api-keys/token/reset": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "重置 AI 网关 API Key Token [id]", + "formatEN": "reset AI proxy API key token [id]" + }, "/core/enterprise/ai-proxy/api-keys/update": { "bodyKeys": [ "id", diff --git a/core/init/router/proxy.go b/core/init/router/proxy.go index ceeb1d5bf580..236b0951ca81 100644 --- a/core/init/router/proxy.go +++ b/core/init/router/proxy.go @@ -3,9 +3,11 @@ package router import ( "net/http" "net/url" + "strconv" "strings" "github.com/1Panel-dev/1Panel/core/app/api/v2/helper" + baseRepo "github.com/1Panel-dev/1Panel/core/app/repo" "github.com/1Panel-dev/1Panel/core/cmd/server/res" "github.com/1Panel-dev/1Panel/core/constant" "github.com/1Panel-dev/1Panel/core/global" @@ -75,11 +77,12 @@ func checkSession(c *gin.Context) bool { return false } c.Set(psessionUtils.GinContextSessionUserKey, psession) - lifeTime, err := xpack.AuthProvider.LoadSessionTimeout(c, psession) + sessionTimeout, err := baseRepo.NewISettingRepo().GetValueByKey("SessionTimeout") if err != nil { global.LOG.Errorf("get session timeout failed, err: %v", err) return false } + lifeTime, _ := strconv.Atoi(sessionTimeout) if _, err := global.SESSION.RefreshIfNeeded(c, psession, global.CONF.Conn.SSL == constant.StatusEnable, lifeTime); err != nil { global.LOG.Warnf("proxy refresh session failed, path=%s, err=%v", c.Request.URL.Path, err) return false diff --git a/core/init/session/psession/psession.go b/core/init/session/psession/psession.go index 9e94ddca65dd..3349901d3754 100644 --- a/core/init/session/psession/psession.go +++ b/core/init/session/psession/psession.go @@ -23,10 +23,11 @@ const SuperAdminSessionUserID = "__super_admin__" const GinContextSessionUserKey = "session_user" type sessionItem struct { - CreatedAt time.Time - CSRFToken string - User SessionUser - ExpiredAt time.Time + CreatedAt time.Time + LastActiveAt time.Time + CSRFToken string + User SessionUser + ExpiredAt time.Time } type PSession struct { @@ -92,8 +93,9 @@ func (p *PSession) set(c *gin.Context, user SessionUser, secure bool, ttlSeconds } } - expiredAt := time.Now().Add(time.Duration(ttlSeconds) * time.Second) - createdAt := time.Now() + now := time.Now() + expiredAt := now.Add(time.Duration(ttlSeconds) * time.Second) + createdAt := now csrfToken := "" p.mu.Lock() @@ -111,10 +113,11 @@ func (p *PSession) set(c *gin.Context, user SessionUser, secure bool, ttlSeconds } } p.sessions[sessionID] = sessionItem{ - CreatedAt: createdAt, - CSRFToken: csrfToken, - User: user, - ExpiredAt: expiredAt, + CreatedAt: createdAt, + LastActiveAt: now, + CSRFToken: csrfToken, + User: user, + ExpiredAt: expiredAt, } p.evictOverflowLocked(sessionID) p.mu.Unlock() @@ -217,6 +220,27 @@ func (p *PSession) DeleteByID(id string) error { return nil } +func (p *PSession) ApplyTimeout(ttlSeconds int) { + now := time.Now() + ttl := time.Duration(ttlSeconds) * time.Second + + p.mu.Lock() + defer p.mu.Unlock() + for sessionID, item := range p.sessions { + lastActiveAt := item.LastActiveAt + if lastActiveAt.IsZero() { + lastActiveAt = item.CreatedAt + } + expiredAt := lastActiveAt.Add(ttl) + if now.After(expiredAt) { + delete(p.sessions, sessionID) + continue + } + item.ExpiredAt = expiredAt + p.sessions[sessionID] = item + } +} + func (p *PSession) Clean() error { p.mu.Lock() p.sessions = make(map[string]sessionItem) diff --git a/core/init/validator/validator.go b/core/init/validator/validator.go index 65f24706f6b7..ad657838077d 100644 --- a/core/init/validator/validator.go +++ b/core/init/validator/validator.go @@ -31,6 +31,8 @@ var baseSettingKeys = map[string]struct{}{ "Theme": {}, "MenuTabs": {}, "Language": {}, + "SessionTimeout": {}, + "ExpirationDays": {}, "DeveloperMode": {}, "UpgradeBackupCopies": {}, "SecurityEntrance": {}, diff --git a/core/middleware/password_expired.go b/core/middleware/password_expired.go index b5ff6cd6c70e..169ddaac31bf 100644 --- a/core/middleware/password_expired.go +++ b/core/middleware/password_expired.go @@ -2,13 +2,17 @@ package middleware import ( "net/http" + "strconv" "strings" "time" "github.com/1Panel-dev/1Panel/core/app/api/v2/helper" + baseRepo "github.com/1Panel-dev/1Panel/core/app/repo" "github.com/1Panel-dev/1Panel/core/buserr" + "github.com/1Panel-dev/1Panel/core/constant" "github.com/1Panel-dev/1Panel/core/global" psessionUtils "github.com/1Panel-dev/1Panel/core/init/session/psession" + "github.com/1Panel-dev/1Panel/core/utils/common" "github.com/1Panel-dev/1Panel/core/utils/xpack" "github.com/gin-gonic/gin" ) @@ -52,15 +56,27 @@ func PasswordExpired() gin.HandlerFunc { helper.BadAuth(c, "ErrNotLogin", err) return } - needCheck, expiredTime, err := xpack.AuthProvider.LoadExpired(c, psession) + settingRepo := baseRepo.NewISettingRepo() + expirationDays, err := settingRepo.GetValueByKey("ExpirationDays") if err != nil { helper.ErrorWithDetail(c, http.StatusInternalServerError, "ErrPasswordExpired", err) return } - if !needCheck { + expiredDays, _ := strconv.Atoi(expirationDays) + if expiredDays == 0 { c.Next() return } + expirationTime, err := xpack.AuthProvider.LoadPasswordExpirationTime(c) + if err != nil { + helper.ErrorWithDetail(c, http.StatusInternalServerError, "ErrPasswordExpired", err) + return + } + expiredTime, err := time.ParseInLocation(constant.DateTimeLayout, expirationTime, common.LoadExpiredLocation()) + if err != nil { + helper.ErrorWithDetail(c, http.StatusInternalServerError, "ErrPasswordExpired", err) + return + } if time.Now().After(expiredTime) { helper.ErrorWithDetail(c, 313, "ErrPasswordExpired", err) diff --git a/core/middleware/session.go b/core/middleware/session.go index 574c4dbfa3c9..1c69fe63a31b 100644 --- a/core/middleware/session.go +++ b/core/middleware/session.go @@ -1,12 +1,14 @@ package middleware import ( + "strconv" + "github.com/1Panel-dev/1Panel/core/app/api/v2/helper" + baseRepo "github.com/1Panel-dev/1Panel/core/app/repo" "github.com/1Panel-dev/1Panel/core/buserr" "github.com/1Panel-dev/1Panel/core/constant" "github.com/1Panel-dev/1Panel/core/global" psessionUtils "github.com/1Panel-dev/1Panel/core/init/session/psession" - "github.com/1Panel-dev/1Panel/core/utils/xpack" "github.com/gin-gonic/gin" ) @@ -33,13 +35,14 @@ func SessionAuth() gin.HandlerFunc { return } c.Set(psessionUtils.GinContextSessionUserKey, psession) - lifeTime, err := xpack.AuthProvider.LoadSessionTimeout(c, psession) + sessionTimeout, err := baseRepo.NewISettingRepo().GetValueByKey("SessionTimeout") if err != nil { global.LOG.Errorf("get session timeout failed, err: %v", err) helper.InternalServer(c, err) c.Abort() return } + lifeTime, _ := strconv.Atoi(sessionTimeout) if _, err := global.SESSION.RefreshIfNeeded(c, psession, global.CONF.Conn.SSL == constant.StatusEnable, lifeTime); err != nil { errItem := err.Error() diff --git a/core/utils/xpack/helper/auth_helper.go b/core/utils/xpack/helper/auth_helper.go index cd45d19b07ea..e77277626efe 100644 --- a/core/utils/xpack/helper/auth_helper.go +++ b/core/utils/xpack/helper/auth_helper.go @@ -1,11 +1,8 @@ package helper import ( - "time" - "github.com/1Panel-dev/1Panel/core/app/auth" baseDto "github.com/1Panel-dev/1Panel/core/app/dto" - "github.com/1Panel-dev/1Panel/core/init/session/psession" "github.com/1Panel-dev/1Panel/core/utils/mfa" "github.com/1Panel-dev/1Panel/core/utils/xpack/providers" "github.com/gin-gonic/gin" @@ -54,13 +51,6 @@ func (a *authHelper) ResetSuperAdminUser(name, password string) error { return nil } -func (a *authHelper) LoadSessionTimeout(_ *gin.Context, sessionUser psession.SessionUser) (int, error) { - return auth.LoadSessionTimeout(sessionUser) -} -func (a *authHelper) LoadExpired(_ *gin.Context, sessionUser psession.SessionUser) (bool, time.Time, error) { - return auth.LoadExpired(sessionUser) -} - func (a *authHelper) CoreAPIAuthMiddleware() gin.HandlerFunc { return auth.APIAuthMiddleware(auth.LoadAPIAuthConfig, nil) } @@ -86,6 +76,12 @@ func (a *authHelper) UpdateApiConfig(c *gin.Context, req baseDto.ApiInterfaceCon func (a *authHelper) GetCurrentUserInfo(_ *gin.Context) (*baseDto.CurrentUserInfo, error) { return auth.GetCurrentUserInfo() } +func (a *authHelper) LoadPasswordExpirationTime(c *gin.Context) (string, error) { + return auth.LoadPasswordExpirationTime(c) +} +func (a *authHelper) SyncPasswordExpirationTime(expirationDays string) error { + return auth.SyncPasswordExpirationTime(expirationDays) +} func (a *authHelper) UpdateCurrentUserInfo(c *gin.Context, req baseDto.CurrentUserUpdate) error { return auth.UpdateCurrentUserInfo(c, req) } diff --git a/core/utils/xpack/providers/auth.go b/core/utils/xpack/providers/auth.go index efca16e29cf1..db2d4a802c4a 100644 --- a/core/utils/xpack/providers/auth.go +++ b/core/utils/xpack/providers/auth.go @@ -1,10 +1,7 @@ package providers import ( - "time" - "github.com/1Panel-dev/1Panel/core/app/dto" - "github.com/1Panel-dev/1Panel/core/init/session/psession" "github.com/1Panel-dev/1Panel/core/utils/mfa" "github.com/gin-gonic/gin" ) @@ -15,9 +12,6 @@ type AuthProvider interface { ResetSuperAdminUser(name, password string) error - LoadSessionTimeout(c *gin.Context, sessionUser psession.SessionUser) (int, error) - LoadExpired(c *gin.Context, sessionUser psession.SessionUser) (bool, time.Time, error) - LoadMFA(c *gin.Context, req dto.MfaRequest) (mfa.Otp, error) MFABind(c *gin.Context, req dto.MfaCredential) error MFAClose(c *gin.Context) error @@ -35,6 +29,8 @@ type AuthProvider interface { ClearPasskeys() error GetCurrentUserInfo(c *gin.Context) (*dto.CurrentUserInfo, error) + LoadPasswordExpirationTime(c *gin.Context) (string, error) + SyncPasswordExpirationTime(expirationDays string) error UpdateCurrentUserInfo(c *gin.Context, req dto.CurrentUserUpdate) error HandlePasswordExpired(c *gin.Context, old, new string) error diff --git a/frontend/src/api/interface/auth.ts b/frontend/src/api/interface/auth.ts index 67dc65c6ecdc..c6e99493425b 100644 --- a/frontend/src/api/interface/auth.ts +++ b/frontend/src/api/interface/auth.ts @@ -48,9 +48,6 @@ export namespace Login { export interface AuthInfo { id: number; name: string; - sessionTimeout: number; - expirationDays: number; - expirationTime: string; mfaStatus: string; mfaInterval: number; role: string; @@ -68,9 +65,6 @@ export namespace Login { name: string; password: string; oldPassword: string; - sessionTimeout: number; - expirationDays: number; - expirationTime: string; } export interface MFARequest { title: string; diff --git a/frontend/src/api/interface/setting.ts b/frontend/src/api/interface/setting.ts index 51373162c603..d635ac408167 100644 --- a/frontend/src/api/interface/setting.ts +++ b/frontend/src/api/interface/setting.ts @@ -34,6 +34,7 @@ export namespace Setting { developerMode: string; sessionTimeout: number; + expirationDays: number; panelName: string; edition: string; diff --git a/frontend/src/layout/components/Sidebar/components/user-info/index.vue b/frontend/src/layout/components/Sidebar/components/user-info/index.vue index 7d0491745249..78b7bf135bc6 100644 --- a/frontend/src/layout/components/Sidebar/components/user-info/index.vue +++ b/frontend/src/layout/components/Sidebar/components/user-info/index.vue @@ -40,29 +40,6 @@ autocomplete="current-password" /> - - - - - {{ $t('setting.timeoutHelper', [loadTimeOut()]) }} - - - {{ $t('setting.noneSetting') }} - - - {{ $t('setting.expirationHelper') }} - - - - - {{ $t('setting.sessionTimeoutHelper', [form.sessionTimeout]) }} - - @@ -449,11 +426,8 @@ const form = reactive({ name: '', password: '', oldPassword: '', - sessionTimeout: 0, mfaStatus: 'Disable', mfaInterval: 30, - expirationDays: 0, - expirationTime: '', apiInterfaceStatus: 'Disable', apiKey: '', ipWhiteList: '', @@ -514,8 +488,6 @@ const userRules = reactive({ name: [Rules.requiredInput, Rules.noSpace], oldPassword: [Rules.requiredInput], password: [{ validator: validatePassword, trigger: 'blur' }], - sessionTimeout: [Rules.integerNumber, checkNumberRange(300, 864000)], - expirationDays: [Rules.integerNumberWith0, checkNumberRange(0, 60)], }); const mfaRules = reactive({ code: [Rules.requiredInput], @@ -529,7 +501,7 @@ const apiRules = reactive({ }); const getUserFormFields = () => { - const fields = ['name', 'password', 'sessionTimeout', 'expirationDays']; + const fields = ['name', 'password']; if (form.password) { fields.push('oldPassword'); } @@ -559,15 +531,11 @@ const syncCurrentUser = (currentUser: Login.AuthInfo) => { form.name = currentUser.name; form.password = ''; form.oldPassword = ''; - form.sessionTimeout = currentUser.sessionTimeout; - form.expirationTime = currentUser.expirationTime; - form.expirationDays = currentUser.expirationDays; form.mfaStatus = currentUser.mfaStatus || 'Disable'; form.mfaInterval = currentUser.mfaInterval; savedMfaStatus.value = form.mfaStatus; mfaDialogOpen.value = false; apiDialogOpen.value = false; - form.expirationDays = form.expirationDays ? form.expirationDays : 0; syncApiConfig(currentUser); }; @@ -862,9 +830,6 @@ const onSubmit = async (formEl: FormInstance | undefined) => { name: form.name, password: form.password, oldPassword: form.oldPassword, - sessionTimeout: form.sessionTimeout, - expirationDays: form.expirationDays, - expirationTime: form.expirationTime, }; loading.value = true; await updateUserInfo(param) @@ -933,26 +898,6 @@ const onSaveApi = async (formEl: FormInstance | undefined) => { }); }; -function loadTimeOut() { - if (!form.expirationTime) { - if (form.expirationDays) { - return form.expirationDays; - } else { - return '-'; - } - } - if (form.expirationDays === 0) { - form.expirationTime = '-'; - return '-'; - } - let stayGap = new Date(form.expirationTime).getTime() - new Date().getTime(); - if (stayGap < 0) { - form.expirationTime = '-'; - return '-'; - } - return Math.floor(stayGap / (3600 * 1000 * 24)); -} - const handleMFA = async () => { if (!form.mfaStatus) { return; diff --git a/frontend/src/views/setting/panel/index.vue b/frontend/src/views/setting/panel/index.vue index fd496725eca8..9b0b9a3e7840 100644 --- a/frontend/src/views/setting/panel/index.vue +++ b/frontend/src/views/setting/panel/index.vue @@ -103,6 +103,19 @@ + + + + + {{ $t('commons.button.set') }} + + + + + {{ $t('setting.sessionTimeoutHelper', [form.sessionTimeout]) }} + + + @@ -176,6 +189,7 @@ + @@ -193,6 +207,7 @@ import { MsgSuccess } from '@/utils/message'; import ThemeColor from '@/views/setting/panel/theme-color/index.vue'; import Watermark from '@/views/setting/panel/watermark/index.vue'; import Edition from '@/views/setting/panel/edition/index.vue'; +import Timeout from '@/views/setting/panel/timeout/index.vue'; import PanelName from '@/views/setting/panel/name/index.vue'; import SystemIP from '@/views/setting/panel/systemip/index.vue'; import Proxy from '@/views/setting/panel/proxy/index.vue'; @@ -236,6 +251,7 @@ const form = reactive({ themeColor: {} as ThemeColor, menuTabs: '', language: '', + sessionTimeout: 0, docSource: 'withByRegion', edition: '', isOffline: 'Disable', @@ -259,6 +275,7 @@ const show = ref(); const panelNameRef = ref(); const systemIPRef = ref(); const proxyRef = ref(); +const timeoutRef = ref(); const hideMenuRef = ref(); const watermarkRef = ref(); const themeColorRef = ref(); @@ -291,6 +308,7 @@ const search = async () => { form.menuTabs = res.data.menuTabs; form.panelName = res.data.panelName; form.language = res.data.language; + form.sessionTimeout = Number(res.data.sessionTimeout || 0); form.docSource = res.data.docSource || 'withByRegion'; form.edition = res.data.edition; form.isOffline = res.data.isOffline || 'Disable'; @@ -335,6 +353,9 @@ const search = async () => { const onChangeTitle = () => { panelNameRef.value.acceptParams({ panelName: form.panelName }); }; +const onChangeTimeout = () => { + timeoutRef.value.acceptParams({ sessionTimeout: form.sessionTimeout }); +}; const onChangeSystemIP = () => { systemIPRef.value.acceptParams({ systemIP: form.systemIP }); }; diff --git a/frontend/src/views/setting/panel/timeout/index.vue b/frontend/src/views/setting/panel/timeout/index.vue new file mode 100644 index 000000000000..d44a2b9a10a2 --- /dev/null +++ b/frontend/src/views/setting/panel/timeout/index.vue @@ -0,0 +1,73 @@ + + + + + + + + + {{ $t('commons.button.cancel') }} + + {{ $t('commons.button.confirm') }} + + + + + diff --git a/frontend/src/views/setting/safe/expiration/index.vue b/frontend/src/views/setting/safe/expiration/index.vue new file mode 100644 index 000000000000..216d2e07e0a8 --- /dev/null +++ b/frontend/src/views/setting/safe/expiration/index.vue @@ -0,0 +1,72 @@ + + + + + + {{ $t('setting.expirationHelper') }} + + + + {{ $t('commons.button.cancel') }} + + {{ $t('commons.button.confirm') }} + + + + + diff --git a/frontend/src/views/setting/safe/index.vue b/frontend/src/views/setting/safe/index.vue index daccfdbc56fe..70cf4cbd87be 100644 --- a/frontend/src/views/setting/safe/index.vue +++ b/frontend/src/views/setting/safe/index.vue @@ -123,6 +123,22 @@ + + + + + {{ $t('commons.button.set') }} + + + + + {{ + form.expirationDays === 0 + ? $t('setting.noneSetting') + : $t('setting.expirationHelper') + }} + + + @@ -157,6 +174,7 @@ import PortSetting from '@/views/setting/safe/port/index.vue'; import BindSetting from '@/views/setting/safe/bind/index.vue'; import ResponseSetting from '@/views/setting/safe/response/index.vue'; import SSLSetting from '@/views/setting/safe/ssl/index.vue'; +import ExpirationSetting from '@/views/setting/safe/expiration/index.vue'; import EntranceSetting from '@/views/setting/safe/entrance/index.vue'; import DomainSetting from '@/views/setting/safe/domain/index.vue'; import AllowIPsSetting from '@/views/setting/safe/allowips/index.vue'; @@ -172,6 +190,7 @@ const loading = ref(false); const entranceRef = ref(); const portRef = ref(); const bindRef = ref(); +const expirationRef = ref(); const responseRef = ref(); const sslRef = ref(); @@ -188,6 +207,7 @@ const form = reactive({ sslItem: 'Disable', sslType: 'self', securityEntrance: '', + expirationDays: 0, complexityVerification: 'Disable', allowIPs: '', bindDomain: '', @@ -210,6 +230,7 @@ const search = async () => { loadInfo(); } form.securityEntrance = res.data.securityEntrance; + form.expirationDays = Number(res.data.expirationDays); form.complexityVerification = res.data.complexityVerification; form.allowIPs = res.data.allowIPs.replaceAll(',', '\n'); form.bindDomain = res.data.bindDomain; @@ -256,6 +277,9 @@ const onChangeBindDomain = () => { const onChangeAllowIPs = () => { allowIPsRef.value.acceptParams({ allowIPs: form.allowIPs }); }; +const onChangeExpirationDays = async () => { + expirationRef.value.acceptParams({ expirationDays: form.expirationDays }); +}; const handleSSL = async () => { if (form.sslItem !== 'Disable') { let params = {