From d638796798c96fa26fbbbf60ffa0cc153322b72a Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Wed, 25 Oct 2023 10:41:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=9D=A2=E6=9D=BF=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=9B=91=E5=90=AC=E5=9C=B0=E5=9D=80=20(#2663?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/setting.go | 43 ++++++ backend/app/dto/setting.go | 7 + backend/app/service/setting.go | 38 +++++ backend/configs/system.go | 2 + backend/init/hook/hook.go | 10 ++ backend/init/migration/migrate.go | 2 + backend/init/migration/migrations/v_1_8.go | 13 ++ backend/router/ro_setting.go | 2 + backend/server/server.go | 50 ++++--- cmd/server/docs/docs.go | 94 +++++++++++- cmd/server/docs/swagger.json | 90 ++++++++++++ cmd/server/docs/swagger.yaml | 58 ++++++++ frontend/src/api/interface/setting.ts | 2 + frontend/src/api/modules/setting.ts | 8 ++ frontend/src/global/form-rules.ts | 33 +++++ frontend/src/lang/modules/en.ts | 6 + frontend/src/lang/modules/tw.ts | 5 + frontend/src/lang/modules/zh.ts | 5 + .../src/views/setting/safe/bind/index.vue | 136 ++++++++++++++++++ frontend/src/views/setting/safe/index.vue | 29 +++- go.mod | 1 - go.sum | 2 - 22 files changed, 601 insertions(+), 35 deletions(-) create mode 100644 frontend/src/views/setting/safe/bind/index.vue diff --git a/backend/app/api/v1/setting.go b/backend/app/api/v1/setting.go index 767365dc3..0b606485a 100644 --- a/backend/app/api/v1/setting.go +++ b/backend/app/api/v1/setting.go @@ -150,6 +150,49 @@ func (b *BaseApi) DownloadSSL(c *gin.Context) { c.File(pathItem) } +// @Tags System Setting +// @Summary Load system address +// @Description 获取系统地址信息 +// @Accept json +// @Success 200 +// @Security ApiKeyAuth +// @Router /settings/interface [get] +func (b *BaseApi) LoadInterfaceAddr(c *gin.Context) { + data, err := settingService.LoadInterfaceAddr() + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, data) +} + +// @Tags System Setting +// @Summary Update system bind info +// @Description 更新系统监听信息 +// @Accept json +// @Param request body dto.BindInfo true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /settings/bind/update [post] +// @x-panel-log {"bodyKeys":["ipv6", "bindAddress"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改系统监听信息 => ipv6: [ipv6], 监听 IP: [bindAddress]","formatEN":"update system bind info => ipv6: [ipv6], 监听 IP: [bindAddress]"} +func (b *BaseApi) UpdateBindInfo(c *gin.Context) { + var req dto.BindInfo + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + if err := settingService.UpdateBindInfo(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} + // @Tags System Setting // @Summary Update system port // @Description 更新系统端口 diff --git a/backend/app/dto/setting.go b/backend/app/dto/setting.go index 271ec1020..3e099dcaf 100644 --- a/backend/app/dto/setting.go +++ b/backend/app/dto/setting.go @@ -14,6 +14,8 @@ type SettingInfo struct { NtpSite string `json:"ntpSite"` Port string `json:"port"` + Ipv6 string `json:"ipv6"` + BindAddress string `json:"bindAddress"` PanelName string `json:"panelName"` Theme string `json:"theme"` Language string `json:"language"` @@ -136,6 +138,11 @@ type SyncTime struct { NtpSite string `json:"ntpSite"` } +type BindInfo struct { + Ipv6 string `json:"ipv6" validate:"required,oneof=enable disable"` + BindAddress string `json:"bindAddress" validate:"required"` +} + type Upgrade struct { Version string `json:"version"` } diff --git a/backend/app/service/setting.go b/backend/app/service/setting.go index 4f3ae4ef4..9001a14f3 100644 --- a/backend/app/service/setting.go +++ b/backend/app/service/setting.go @@ -6,6 +6,7 @@ import ( "encoding/json" "encoding/pem" "fmt" + "net" "os" "path" "strconv" @@ -30,10 +31,12 @@ type SettingService struct{} type ISettingService interface { GetSettingInfo() (*dto.SettingInfo, error) + LoadInterfaceAddr() ([]string, error) LoadTimeZone() ([]string, error) Update(key, value string) error UpdatePassword(c *gin.Context, old, new string) error UpdatePort(port uint) error + UpdateBindInfo(req dto.BindInfo) error UpdateSSL(c *gin.Context, req dto.SSLUpdate) error LoadFromCert() (*dto.SSLInfo, error) HandlePasswordExpired(c *gin.Context, old, new string) error @@ -160,6 +163,41 @@ func (u *SettingService) SyncTime(req dto.SyncTime) error { return nil } +func (u *SettingService) LoadInterfaceAddr() ([]string, error) { + addrMap := make(map[string]struct{}) + addrs, err := net.InterfaceAddrs() + if err != nil { + return nil, err + } + for _, addr := range addrs { + ipNet, ok := addr.(*net.IPNet) + if ok && ipNet.IP.To16() != nil { + addrMap[ipNet.IP.String()] = struct{}{} + } + } + var data []string + for key := range addrMap { + data = append(data, key) + } + return data, nil +} + +func (u *SettingService) UpdateBindInfo(req dto.BindInfo) error { + if err := settingRepo.Update("Ipv6", req.Ipv6); err != nil { + return err + } + if err := settingRepo.Update("BindAddress", req.BindAddress); err != nil { + return err + } + go func() { + _, err := cmd.Exec("systemctl restart 1panel.service") + if err != nil { + global.LOG.Errorf("restart system with new bind info failed, err: %v", err) + } + }() + return nil +} + func (u *SettingService) UpdatePort(port uint) error { if common.ScanPort(int(port)) { return buserr.WithDetail(constant.ErrPortInUsed, port, nil) diff --git a/backend/configs/system.go b/backend/configs/system.go index 3e46799dc..11ff98033 100644 --- a/backend/configs/system.go +++ b/backend/configs/system.go @@ -2,6 +2,8 @@ package configs type System struct { Port string `mapstructure:"port"` + Ipv6 string `mapstructure:"ipv6"` + BindAddress string `mapstructure:"bindAddress"` SSL string `mapstructure:"ssl"` DbFile string `mapstructure:"db_file"` DbPath string `mapstructure:"db_path"` diff --git a/backend/init/hook/hook.go b/backend/init/hook/hook.go index 1bbf35dbc..7422826cb 100644 --- a/backend/init/hook/hook.go +++ b/backend/init/hook/hook.go @@ -18,6 +18,16 @@ func Init() { global.LOG.Errorf("load service port from setting failed, err: %v", err) } global.CONF.System.Port = portSetting.Value + ipv6Setting, err := settingRepo.Get(settingRepo.WithByKey("Ipv6")) + if err != nil { + global.LOG.Errorf("load ipv6 status from setting failed, err: %v", err) + } + global.CONF.System.Ipv6 = ipv6Setting.Value + bindAddressSetting, err := settingRepo.Get(settingRepo.WithByKey("BindAddress")) + if err != nil { + global.LOG.Errorf("load bind address from setting failed, err: %v", err) + } + global.CONF.System.BindAddress = bindAddressSetting.Value sslSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL")) if err != nil { global.LOG.Errorf("load service ssl from setting failed, err: %v", err) diff --git a/backend/init/migration/migrate.go b/backend/init/migration/migrate.go index 568b0f09e..580b95099 100644 --- a/backend/init/migration/migrate.go +++ b/backend/init/migration/migrate.go @@ -47,7 +47,9 @@ func Init() { migrations.AddDefaultNetwork, migrations.UpdateRuntime, migrations.UpdateTag, + migrations.AddFavorite, + migrations.AddBindAddress, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/backend/init/migration/migrations/v_1_8.go b/backend/init/migration/migrations/v_1_8.go index 84dd19ff7..0549e3dac 100644 --- a/backend/init/migration/migrations/v_1_8.go +++ b/backend/init/migration/migrations/v_1_8.go @@ -15,3 +15,16 @@ var AddFavorite = &gormigrate.Migration{ return nil }, } + +var AddBindAddress = &gormigrate.Migration{ + ID: "20231024-add-bind-address", + Migrate: func(tx *gorm.DB) error { + if err := tx.Create(&model.Setting{Key: "BindAddress", Value: "0.0.0.0"}).Error; err != nil { + return err + } + if err := tx.Create(&model.Setting{Key: "Ipv6", Value: "disable"}).Error; err != nil { + return err + } + return nil + }, +} diff --git a/backend/router/ro_setting.go b/backend/router/ro_setting.go index 20b399813..9cb98ee50 100644 --- a/backend/router/ro_setting.go +++ b/backend/router/ro_setting.go @@ -22,6 +22,8 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) { router.POST("/expired/handle", baseApi.HandlePasswordExpired) settingRouter.GET("/search/available", baseApi.GetSystemAvailable) settingRouter.POST("/update", baseApi.UpdateSetting) + settingRouter.GET("/interface", baseApi.LoadInterfaceAddr) + settingRouter.POST("/bind/update", baseApi.UpdateBindInfo) settingRouter.POST("/port/update", baseApi.UpdatePort) settingRouter.POST("/ssl/update", baseApi.UpdateSSL) settingRouter.GET("/ssl/info", baseApi.LoadFromCert) diff --git a/backend/server/server.go b/backend/server/server.go index 8b4a6b78f..8e71f661f 100644 --- a/backend/server/server.go +++ b/backend/server/server.go @@ -4,10 +4,10 @@ import ( "crypto/tls" "encoding/gob" "fmt" + "net" "net/http" "os" "path" - "time" "github.com/1Panel-dev/1Panel/backend/init/app" "github.com/1Panel-dev/1Panel/backend/init/business" @@ -26,7 +26,6 @@ import ( "github.com/1Panel-dev/1Panel/backend/init/validator" "github.com/1Panel-dev/1Panel/backend/init/viper" - "github.com/fvbock/endless" "github.com/gin-gonic/gin" ) @@ -46,19 +45,17 @@ func Start() { hook.Init() rootRouter := router.Routers() - address := fmt.Sprintf(":%s", global.CONF.System.Port) - s := endless.NewServer(address, rootRouter) - s.ReadHeaderTimeout = 20 * time.Second - s.WriteTimeout = 60 * time.Second - s.MaxHeaderBytes = 1 << 20 - if global.CONF.System.SSL == "disable" { - global.LOG.Infof("server run success on %s with http", global.CONF.System.Port) - if err := s.ListenAndServe(); err != nil { - global.LOG.Error(err) - panic(err) - } - } else { + tcpItem := "tcp4" + if global.CONF.System.Ipv6 == "enable" { + tcpItem = "tcp" + global.CONF.System.BindAddress = fmt.Sprintf("[%s]", global.CONF.System.BindAddress) + } + server := &http.Server{ + Addr: global.CONF.System.BindAddress + ":" + global.CONF.System.Port, + Handler: rootRouter, + } + if global.CONF.System.SSL == "enable" { certificate, err := os.ReadFile(path.Join(global.CONF.System.BaseDir, "1panel/secret/server.crt")) if err != nil { panic(err) @@ -71,18 +68,19 @@ func Start() { if err != nil { panic(err) } - s := &http.Server{ - Addr: address, - Handler: rootRouter, - TLSConfig: &tls.Config{ - Certificates: []tls.Certificate{cert}, - }, - } - - global.LOG.Infof("server run success on %s with https", global.CONF.System.Port) - if err := s.ListenAndServeTLS("", ""); err != nil { - global.LOG.Error(err) - panic(err) + server.TLSConfig = &tls.Config{ + Certificates: []tls.Certificate{cert}, } } + global.LOG.Infof("listen at %s:%s [%s]", global.CONF.System.BindAddress, global.CONF.System.Port, tcpItem) + ln, err := net.Listen(tcpItem, global.CONF.System.BindAddress+":"+global.CONF.System.Port) + if err != nil { + panic(err) + } + type tcpKeepAliveListener struct { + *net.TCPListener + } + if err := server.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}); err != nil { + panic(err) + } } diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index aa0229a88..97ed1396a 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -1,5 +1,5 @@ -// Package docs GENERATED BY SWAG; DO NOT EDIT -// This file was generated by swaggo/swag +// Code generated by swaggo/swag. DO NOT EDIT. + package docs import "github.com/swaggo/swag" @@ -8931,6 +8931,49 @@ const docTemplate = `{ } } }, + "/settings/bind/update": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "更新系统监听信息", + "consumes": [ + "application/json" + ], + "tags": [ + "System Setting" + ], + "summary": "Update system bind info", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.BindInfo" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [ + "ipv6", + "bindAddress" + ], + "formatEN": "update system bind info =\u003e ipv6: [ipv6], 监听 IP: [bindAddress]", + "formatZH": "修改系统监听信息 =\u003e ipv6: [ipv6], 监听 IP: [bindAddress]", + "paramKeys": [] + } + } + }, "/settings/clean": { "post": { "security": [ @@ -9014,6 +9057,28 @@ const docTemplate = `{ } } }, + "/settings/interface": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "获取系统地址信息", + "consumes": [ + "application/json" + ], + "tags": [ + "System Setting" + ], + "summary": "Load system address", + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/settings/mfa": { "post": { "security": [ @@ -12501,6 +12566,25 @@ const docTemplate = `{ } } }, + "dto.BindInfo": { + "type": "object", + "required": [ + "bindAddress", + "ipv6" + ], + "properties": { + "bindAddress": { + "type": "string" + }, + "ipv6": { + "type": "string", + "enum": [ + "enable", + "disable" + ] + } + } + }, "dto.CaptchaResponse": { "type": "object", "properties": { @@ -15379,6 +15463,9 @@ const docTemplate = `{ "appStoreVersion": { "type": "string" }, + "bindAddress": { + "type": "string" + }, "bindDomain": { "type": "string" }, @@ -15403,6 +15490,9 @@ const docTemplate = `{ "expirationTime": { "type": "string" }, + "ipv6": { + "type": "string" + }, "language": { "type": "string" }, diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index b873464d3..4391b1d9e 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -8924,6 +8924,49 @@ } } }, + "/settings/bind/update": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "更新系统监听信息", + "consumes": [ + "application/json" + ], + "tags": [ + "System Setting" + ], + "summary": "Update system bind info", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.BindInfo" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [ + "ipv6", + "bindAddress" + ], + "formatEN": "update system bind info =\u003e ipv6: [ipv6], 监听 IP: [bindAddress]", + "formatZH": "修改系统监听信息 =\u003e ipv6: [ipv6], 监听 IP: [bindAddress]", + "paramKeys": [] + } + } + }, "/settings/clean": { "post": { "security": [ @@ -9007,6 +9050,28 @@ } } }, + "/settings/interface": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "获取系统地址信息", + "consumes": [ + "application/json" + ], + "tags": [ + "System Setting" + ], + "summary": "Load system address", + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/settings/mfa": { "post": { "security": [ @@ -12494,6 +12559,25 @@ } } }, + "dto.BindInfo": { + "type": "object", + "required": [ + "bindAddress", + "ipv6" + ], + "properties": { + "bindAddress": { + "type": "string" + }, + "ipv6": { + "type": "string", + "enum": [ + "enable", + "disable" + ] + } + } + }, "dto.CaptchaResponse": { "type": "object", "properties": { @@ -15372,6 +15456,9 @@ "appStoreVersion": { "type": "string" }, + "bindAddress": { + "type": "string" + }, "bindDomain": { "type": "string" }, @@ -15396,6 +15483,9 @@ "expirationTime": { "type": "string" }, + "ipv6": { + "type": "string" + }, "language": { "type": "string" }, diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 4198ad127..b48b35689 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -122,6 +122,19 @@ definitions: required: - type type: object + dto.BindInfo: + properties: + bindAddress: + type: string + ipv6: + enum: + - enable + - disable + type: string + required: + - bindAddress + - ipv6 + type: object dto.CaptchaResponse: properties: captchaID: @@ -2064,6 +2077,8 @@ definitions: type: string appStoreVersion: type: string + bindAddress: + type: string bindDomain: type: string complexityVerification: @@ -2080,6 +2095,8 @@ definitions: type: string expirationTime: type: string + ipv6: + type: string language: type: string lastCleanData: @@ -9879,6 +9896,34 @@ paths: summary: Load local backup dir tags: - System Setting + /settings/bind/update: + post: + consumes: + - application/json + description: 更新系统监听信息 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/dto.BindInfo' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Update system bind info + tags: + - System Setting + x-panel-log: + BeforeFunctions: [] + bodyKeys: + - ipv6 + - bindAddress + formatEN: 'update system bind info => ipv6: [ipv6], 监听 IP: [bindAddress]' + formatZH: '修改系统监听信息 => ipv6: [ipv6], 监听 IP: [bindAddress]' + paramKeys: [] /settings/clean: post: consumes: @@ -9933,6 +9978,19 @@ paths: formatEN: reset an expired Password formatZH: 重置过期密码 paramKeys: [] + /settings/interface: + get: + consumes: + - application/json + description: 获取系统地址信息 + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Load system address + tags: + - System Setting /settings/mfa: post: consumes: diff --git a/frontend/src/api/interface/setting.ts b/frontend/src/api/interface/setting.ts index 5080f391a..3ec666ed7 100644 --- a/frontend/src/api/interface/setting.ts +++ b/frontend/src/api/interface/setting.ts @@ -22,6 +22,8 @@ export namespace Setting { lastCleanData: string; serverPort: number; + ipv6: string; + bindAddress: string; ssl: string; sslType: string; allowIPs: string; diff --git a/frontend/src/api/modules/setting.ts b/frontend/src/api/modules/setting.ts index 712a46682..231cf4b45 100644 --- a/frontend/src/api/modules/setting.ts +++ b/frontend/src/api/modules/setting.ts @@ -21,6 +21,14 @@ export const updatePassword = (param: Setting.PasswordUpdate) => { return http.post(`/settings/password/update`, param); }; +export const loadInterfaceAddr = () => { + return http.get(`/settings/interface`); +}; + +export const updateBindInfo = (ipv6: string, bindAddress: string) => { + return http.post(`/settings/bind/update`, { ipv6: ipv6, bindAddress: bindAddress }); +}; + export const updatePort = (param: Setting.PortUpdate) => { return http.post(`/settings/port/update`, param); }; diff --git a/frontend/src/global/form-rules.ts b/frontend/src/global/form-rules.ts index 997865695..bbc50382b 100644 --- a/frontend/src/global/form-rules.ts +++ b/frontend/src/global/form-rules.ts @@ -22,6 +22,33 @@ const checkIp = (rule: any, value: any, callback: any) => { } }; +const checkIpV6 = (rule: any, value: any, callback: any) => { + if (value === '' || typeof value === 'undefined' || value == null) { + callback(new Error(i18n.global.t('commons.rule.requiredInput'))); + } else { + const IPv4SegmentFormat = '(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'; + const IPv4AddressFormat = `(${IPv4SegmentFormat}[.]){3}${IPv4SegmentFormat}`; + const IPv6SegmentFormat = '(?:[0-9a-fA-F]{1,4})'; + const IPv6AddressRegExp = new RegExp( + '^(' + + `(?:${IPv6SegmentFormat}:){7}(?:${IPv6SegmentFormat}|:)|` + + `(?:${IPv6SegmentFormat}:){6}(?:${IPv4AddressFormat}|:${IPv6SegmentFormat}|:)|` + + `(?:${IPv6SegmentFormat}:){5}(?::${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,2}|:)|` + + `(?:${IPv6SegmentFormat}:){4}(?:(:${IPv6SegmentFormat}){0,1}:${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,3}|:)|` + + `(?:${IPv6SegmentFormat}:){3}(?:(:${IPv6SegmentFormat}){0,2}:${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,4}|:)|` + + `(?:${IPv6SegmentFormat}:){2}(?:(:${IPv6SegmentFormat}){0,3}:${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,5}|:)|` + + `(?:${IPv6SegmentFormat}:){1}(?:(:${IPv6SegmentFormat}){0,4}:${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,6}|:)|` + + `(?::((?::${IPv6SegmentFormat}){0,5}:${IPv4AddressFormat}|(?::${IPv6SegmentFormat}){1,7}|:))` + + ')(%[0-9a-zA-Z-.:]{1,})?$', + ); + if (!IPv6AddressRegExp.test(value) && value !== '') { + callback(new Error(i18n.global.t('commons.rule.ip'))); + } else { + callback(); + } + } +}; + const checkIpV4V6OrDomain = (rule: any, value: any, callback: any) => { if (value === '' || typeof value === 'undefined' || value == null) { callback(new Error(i18n.global.t('commons.rule.requiredInput'))); @@ -453,6 +480,7 @@ interface CommonRule { integerNumberWith0: FormItemRule; floatNumber: FormItemRule; ip: FormItemRule; + ipV6: FormItemRule; ipV4V6OrDomain: FormItemRule; host: FormItemRule; illegal: FormItemRule; @@ -576,6 +604,11 @@ export const Rules: CommonRule = { required: true, trigger: 'blur', }, + ipV6: { + validator: checkIpV6, + required: true, + trigger: 'blur', + }, ipV4V6OrDomain: { validator: checkIpV4V6OrDomain, required: true, diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index e2f94d340..b6c3c2405 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1125,6 +1125,12 @@ const message = { path: 'Path', safe: 'Security', + bindInfo: 'BindInfo', + bindAll: 'Listen All', + bindInfoHelper: + 'Changing the service listening address or protocol may result in service unavailability. Do you want to continue?', + ipv6: 'Listen IPv6', + bindAddress: 'Listen Address', entrance: 'Entrance', showEntrance: 'Enable Home Page Notification Not Enabled', entranceHelper: 'Enabling secure entry will only allow logging in to the panel through specified secure entry.', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index 89eb6f1cb..cb6ed5944 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -1119,6 +1119,11 @@ const message = { hasNewVersion: '有新版本', safe: '安全', + bindInfo: '監聽地址', + bindAll: '監聽所有', + bindInfoHelper: '修改服務監聽地址或協議可能導致服務不可用,是否繼續?', + ipv6: '監聽 IPv6', + bindAddress: '監聽地址', entrance: '安全入口', showEntrance: '啟用概覽頁未開啟提醒', entranceHelper: '開啟安全入口後只能通過指定安全入口登錄面板', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 9cb12b729..6cdeba110 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -1120,6 +1120,11 @@ const message = { hasNewVersion: '有新版本', safe: '安全', + bindInfo: '监听地址', + bindAll: '监听所有', + bindInfoHelper: '修改服务监听地址或协议可能导致服务不可用,是否继续?', + ipv6: '监听 IPv6', + bindAddress: '监听地址', entrance: '安全入口', showEntrance: '启用概览页未开启提醒', entranceHelper: '开启安全入口后只能通过指定安全入口登录面板', diff --git a/frontend/src/views/setting/safe/bind/index.vue b/frontend/src/views/setting/safe/bind/index.vue new file mode 100644 index 000000000..607e2cf47 --- /dev/null +++ b/frontend/src/views/setting/safe/bind/index.vue @@ -0,0 +1,136 @@ + + diff --git a/frontend/src/views/setting/safe/index.vue b/frontend/src/views/setting/safe/index.vue index 982df84cb..93edd3cc3 100644 --- a/frontend/src/views/setting/safe/index.vue +++ b/frontend/src/views/setting/safe/index.vue @@ -15,7 +15,15 @@ - + + + + + + - + @@ -161,6 +170,7 @@ import { ref, reactive, onMounted } from 'vue'; import { ElForm, ElMessageBox } from 'element-plus'; import PortSetting from '@/views/setting/safe/port/index.vue'; +import BindSetting from '@/views/setting/safe/bind/index.vue'; import SSLSetting from '@/views/setting/safe/ssl/index.vue'; import MfaSetting from '@/views/setting/safe/mfa/index.vue'; import TimeoutSetting from '@/views/setting/safe/timeout/index.vue'; @@ -177,7 +187,8 @@ const globalStore = GlobalStore(); const loading = ref(false); const entranceRef = ref(); const portRef = ref(); -const timeoutref = ref(); +const bindRef = ref(); +const timeoutRef = ref(); const mfaRef = ref(); const sslRef = ref(); @@ -187,6 +198,9 @@ const allowIPsRef = ref(); const form = reactive({ serverPort: 9999, + ipv6: 'disable', + bindAddress: '', + bindAddressItem: '', ssl: 'disable', sslType: 'self', securityEntrance: '', @@ -204,6 +218,10 @@ const unset = ref(i18n.global.t('setting.unSetting')); const search = async () => { const res = await getSettingInfo(); form.serverPort = Number(res.data.serverPort); + form.ipv6 = res.data.ipv6; + form.bindAddress = res.data.bindAddress; + let proto = form.ipv6 === 'enable' ? 'ipv6' : 'ipv4'; + form.bindAddressItem = ' [' + proto + '] ' + res.data.bindAddress; form.ssl = res.data.ssl; form.sslType = res.data.sslType; if (form.ssl === 'enable') { @@ -259,6 +277,9 @@ const onChangeEntrance = () => { const onChangePort = () => { portRef.value.acceptParams({ serverPort: form.serverPort }); }; +const onChangeBind = () => { + bindRef.value.acceptParams({ ipv6: form.ipv6, bindAddress: form.bindAddress }); +}; const onChangeBindDomain = () => { domainRef.value.acceptParams({ bindDomain: form.bindDomain }); }; @@ -305,7 +326,7 @@ const loadInfo = async () => { }; const onChangeExpirationTime = async () => { - timeoutref.value.acceptParams({ expirationDays: form.expirationDays }); + timeoutRef.value.acceptParams({ expirationDays: form.expirationDays }); }; function loadTimeOut() { diff --git a/go.mod b/go.mod index aaec20818..4d6fb9df3 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/docker/docker v23.0.3+incompatible github.com/docker/go-connections v0.4.0 github.com/fsnotify/fsnotify v1.6.0 - github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 github.com/gin-contrib/gzip v0.0.6 github.com/gin-contrib/i18n v0.0.1 github.com/gin-gonic/gin v1.9.1 diff --git a/go.sum b/go.sum index 616975c39..c82630710 100644 --- a/go.sum +++ b/go.sum @@ -228,8 +228,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 h1:6VSn3hB5U5GeA6kQw4TwWIWbOhtvR2hmbBJnTOtqTWc= -github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6/go.mod h1:YxOVT5+yHzKvwhsiSIWmbAYM3Dr9AEEbER2dVayfBkg= github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo= github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=