refactor: adjust login settings logic (#12916)

This commit is contained in:
ssongliu
2026-06-02 15:13:59 +08:00
committed by GitHub
parent a3f8c30508
commit 9748a0794b
21 changed files with 363 additions and 239 deletions
+24
View File
@@ -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
+12 -45
View File
@@ -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
func buildPasswordExpirationTime(expirationDays int) string {
if expirationDays == 0 {
return ""
}
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
}
return true, expiredTime, nil
return time.Now().AddDate(0, 0, expirationDays).Format(constant.DateTimeLayout)
}
func deleteCurrentSession(c *gin.Context) {
+3 -9
View File
@@ -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"`
}
+11 -11
View File
@@ -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"`
+14 -31
View File
@@ -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 {
+18 -25
View File
@@ -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"
},
+18 -25
View File
@@ -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"
},
+4 -1
View File
@@ -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
+34 -10
View File
@@ -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)
+2
View File
@@ -31,6 +31,8 @@ var baseSettingKeys = map[string]struct{}{
"Theme": {},
"MenuTabs": {},
"Language": {},
"SessionTimeout": {},
"ExpirationDays": {},
"DeveloperMode": {},
"UpgradeBackupCopies": {},
"SecurityEntrance": {},
+18 -2
View File
@@ -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)
+5 -2
View File
@@ -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()
+6 -10
View File
@@ -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)
}
+2 -6
View File
@@ -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
-6
View File
@@ -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;
+1
View File
@@ -34,6 +34,7 @@ export namespace Setting {
developerMode: string;
sessionTimeout: number;
expirationDays: number;
panelName: string;
edition: string;
@@ -40,29 +40,6 @@
autocomplete="current-password"
/>
</el-form-item>
<el-form-item :label="$t('setting.days')" prop="expirationDays">
<el-input
clearable
v-model.number="form.expirationDays"
name="profile-expiration-days"
autocomplete="off"
/>
<div>
<span class="input-help" v-if="form.expirationDays !== 0">
{{ $t('setting.timeoutHelper', [loadTimeOut()]) }}
</span>
<span class="input-help" v-else>
{{ $t('setting.noneSetting') }}
</span>
</div>
<span class="input-help">{{ $t('setting.expirationHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('setting.sessionTimeout')" prop="sessionTimeout">
<el-input v-model.number="form.sessionTimeout" name="profile-session-timeout" autocomplete="off" />
<span class="input-help">
{{ $t('setting.sessionTimeoutHelper', [form.sessionTimeout]) }}
</span>
</el-form-item>
</el-form>
<el-form label-position="top" :model="form" class="setting-section">
@@ -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;
@@ -103,6 +103,19 @@
</el-select>
</el-form-item>
<el-form-item :label="$t('setting.sessionTimeout')" prop="sessionTimeout">
<el-input disabled v-model.number="form.sessionTimeout">
<template #append>
<el-button @click="onChangeTimeout" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">
{{ $t('setting.sessionTimeoutHelper', [form.sessionTimeout]) }}
</span>
</el-form-item>
<el-form-item :label="$t('setting.systemIP')" prop="systemIP">
<el-input disabled v-if="form.systemIP" v-model="form.systemIP">
<template #append>
@@ -176,6 +189,7 @@
<PanelName ref="panelNameRef" @search="search()" />
<SystemIP ref="systemIPRef" @search="search()" />
<Proxy ref="proxyRef" @search="search()" />
<Timeout ref="timeoutRef" @search="search()" />
<HideMenu ref="hideMenuRef" @search="search()" />
<ThemeColor ref="themeColorRef" />
<Watermark ref="watermarkRef" @search="search()" />
@@ -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 });
};
@@ -0,0 +1,73 @@
<template>
<DrawerPro v-model="drawerVisible" :header="$t('setting.sessionTimeout')" @close="handleClose" size="small">
<el-form ref="formRef" label-position="top" :rules="rules" :model="form" @submit.prevent v-loading="loading">
<el-form-item :label="$t('setting.sessionTimeout')" prop="sessionTimeout">
<el-input clearable v-model.number="form.sessionTimeout" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button :disabled="loading" type="primary" @click="onSaveTimeout(formRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</template>
</DrawerPro>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
import { Rules, checkNumberRange } from '@/global/form-rules';
import { updateSetting } from '@/api/modules/setting';
const emit = defineEmits<{ (e: 'search'): void }>();
interface DialogProps {
sessionTimeout: number;
}
const drawerVisible = ref();
const loading = ref();
const form = reactive({
sessionTimeout: 86400,
});
const rules = reactive({
sessionTimeout: [Rules.integerNumber, checkNumberRange(300, 864000)],
});
const formRef = ref<FormInstance>();
const acceptParams = (params: DialogProps): void => {
form.sessionTimeout = params.sessionTimeout;
drawerVisible.value = true;
};
const onSaveTimeout = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
loading.value = true;
await updateSetting({ key: 'SessionTimeout', value: form.sessionTimeout + '' })
.then(async () => {
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
loading.value = false;
drawerVisible.value = false;
emit('search');
return;
})
.catch(() => {
loading.value = false;
});
});
};
const handleClose = () => {
drawerVisible.value = false;
};
defineExpose({
acceptParams,
});
</script>
@@ -0,0 +1,72 @@
<template>
<DrawerPro v-model="drawerVisible" :header="$t('setting.expirationTime')" @close="handleClose" size="small">
<el-form ref="timeoutFormRef" @submit.prevent label-position="top" v-loading="loading" :model="form">
<el-form-item
:label="$t('setting.days')"
prop="days"
:rules="[Rules.integerNumberWith0, checkNumberRange(0, 60)]"
>
<el-input clearable v-model.number="form.days" />
<span class="input-help">{{ $t('setting.expirationHelper') }}</span>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button :disabled="loading" type="primary" @click="submitTimeout(timeoutFormRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</template>
</DrawerPro>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { MsgSuccess } from '@/utils/message';
import { updateSetting } from '@/api/modules/setting';
import { FormInstance } from 'element-plus';
import { Rules, checkNumberRange } from '@/global/form-rules';
import i18n from '@/lang';
const emit = defineEmits<{ (e: 'search'): void }>();
interface DialogProps {
expirationDays: number;
}
const drawerVisible = ref();
const loading = ref();
const timeoutFormRef = ref();
const form = reactive({
days: 0,
});
const acceptParams = (params: DialogProps): void => {
form.days = params.expirationDays;
drawerVisible.value = true;
};
const submitTimeout = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
loading.value = true;
await updateSetting({ key: 'ExpirationDays', value: form.days + '' })
.then(() => {
loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
emit('search');
drawerVisible.value = false;
})
.catch(() => {
loading.value = false;
});
});
};
const handleClose = () => {
drawerVisible.value = false;
};
defineExpose({
acceptParams,
});
</script>
+24
View File
@@ -123,6 +123,22 @@
</div>
</div>
</el-form-item>
<el-form-item :label="$t('setting.expirationTime')" prop="expirationDays">
<el-input disabled v-model="form.expirationDays">
<template #append>
<el-button @click="onChangeExpirationDays" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">
{{
form.expirationDays === 0
? $t('setting.noneSetting')
: $t('setting.expirationHelper')
}}
</span>
</el-form-item>
<el-form-item :label="$t('setting.complexity')" prop="complexityVerification">
<el-switch
@change="onSaveComplexity"
@@ -146,6 +162,7 @@
<EntranceSetting ref="entranceRef" @search="search" />
<DomainSetting ref="domainRef" @search="search" />
<AllowIPsSetting ref="allowIPsRef" @search="search" />
<ExpirationSetting ref="expirationRef" @search="search" />
<ResponseSetting ref="responseRef" @search="search()" />
</div>
</template>
@@ -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 = {