diff --git a/agent/cmd/server/docs/x-log.json b/agent/cmd/server/docs/x-log.json
index 2d60faeeb..989c6b670 100644
--- a/agent/cmd/server/docs/x-log.json
+++ b/agent/cmd/server/docs/x-log.json
@@ -816,12 +816,13 @@
},
"/core/auth/api/update": {
"bodyKeys": [
- "ipWhiteList"
+ "ipWhiteList",
+ "apiTrustedProxies"
],
"paramKeys": [],
"beforeFunctions": [],
- "formatZH": "更新 API 接口配置 =\u003e IP 白名单: [ipWhiteList]",
- "formatEN": "update api config =\u003e IP White List: [ipWhiteList]"
+ "formatZH": "更新 API 接口配置 =\u003e IP 白名单: [ipWhiteList], API 可信代理: [apiTrustedProxies]",
+ "formatEN": "update api config =\u003e IP Allowlist: [ipWhiteList], API Trusted Proxies: [apiTrustedProxies]"
},
"/core/auth/expired/reset": {
"bodyKeys": [],
@@ -1577,7 +1578,8 @@
"/core/enterprise/users/api/update": {
"bodyKeys": [
"id",
- "ipWhiteList"
+ "ipWhiteList",
+ "apiTrustedProxies"
],
"paramKeys": [],
"beforeFunctions": [
@@ -1590,8 +1592,8 @@
"output_value": "name"
}
],
- "formatZH": "更新用户 [name] API 接口配置 =\u003e IP 白名单: [ipWhiteList]",
- "formatEN": "update user [name] api config =\u003e IP White List: [ipWhiteList]"
+ "formatZH": "更新用户 [name] API 接口配置 =\u003e IP 白名单: [ipWhiteList], API 可信代理: [apiTrustedProxies]",
+ "formatEN": "update user [name] api config =\u003e IP Allowlist: [ipWhiteList], API Trusted Proxies: [apiTrustedProxies]"
},
"/core/enterprise/users/del": {
"bodyKeys": [
diff --git a/core/app/api/v2/auth.go b/core/app/api/v2/auth.go
index 4f8fb98bd..52b8cdcf7 100644
--- a/core/app/api/v2/auth.go
+++ b/core/app/api/v2/auth.go
@@ -7,6 +7,7 @@ import (
"path"
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
+ appauth "github.com/1Panel-dev/1Panel/core/app/auth"
"github.com/1Panel-dev/1Panel/core/app/dto"
"github.com/1Panel-dev/1Panel/core/app/model"
"github.com/1Panel-dev/1Panel/core/buserr"
@@ -435,7 +436,7 @@ func (b *BaseApi) GenerateApiKey(c *gin.Context) {
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /core/auth/api/update [post]
-// @x-panel-log {"bodyKeys":["ipWhiteList"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 API 接口配置 => IP 白名单: [ipWhiteList]","formatEN":"update api config => IP White List: [ipWhiteList]"}
+// @x-panel-log {"bodyKeys":["ipWhiteList","apiTrustedProxies"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 API 接口配置 => IP 白名单: [ipWhiteList], API 可信代理: [apiTrustedProxies]","formatEN":"update api config => IP Allowlist: [ipWhiteList], API Trusted Proxies: [apiTrustedProxies]"}
func (b *BaseApi) UpdateApiConfig(c *gin.Context) {
panelToken := c.GetHeader("1Panel-Token")
if panelToken != "" {
@@ -446,6 +447,12 @@ func (b *BaseApi) UpdateApiConfig(c *gin.Context) {
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
+ trustedProxies, err := appauth.NormalizeAPITrustedProxies(req.ApiTrustedProxies)
+ if err != nil {
+ helper.BadRequest(c, err)
+ return
+ }
+ req.ApiTrustedProxies = trustedProxies
if err := xpack.AuthProvider.UpdateApiConfig(c, req); err != nil {
helper.InternalServer(c, err)
diff --git a/core/app/auth/api_auth.go b/core/app/auth/api_auth.go
index 69f1b3920..002f67aa5 100644
--- a/core/app/auth/api_auth.go
+++ b/core/app/auth/api_auth.go
@@ -6,6 +6,7 @@ import (
"crypto/sha256"
"encoding/hex"
"errors"
+ "fmt"
"net"
"strconv"
"strings"
@@ -24,6 +25,7 @@ type APIAuthConfig struct {
ApiInterfaceStatus string
ApiKey string
IpWhiteList string
+ ApiTrustedProxies string
ApiKeyValidityTime int
}
@@ -66,7 +68,7 @@ func APIAuthMiddleware(loadConfig APIAuthConfigLoader, onSuccess APIAuthSuccessH
helper.BadAuth(c, "ErrApiConfigKeyInvalid", nil)
return
}
- if !isIPInWhiteList(c.ClientIP(), config.IpWhiteList) {
+ if !isIPInWhiteList(GetAPIClientIP(c, config.ApiTrustedProxies), config.IpWhiteList) {
helper.BadAuth(c, "ErrApiConfigIPInvalid", nil)
return
}
@@ -92,6 +94,9 @@ func LoadAPIAuthConfig(_ *gin.Context) (APIAuthConfig, error) {
if config.IpWhiteList, err = settingRepo.GetValueByKey("IpWhiteList"); err != nil {
return config, err
}
+ if config.ApiTrustedProxies, err = settingRepo.GetValueByKey("ApiTrustedProxies"); err != nil {
+ return config, err
+ }
apiValidity, err := settingRepo.GetValueByKey("ApiKeyValidityTime")
if err != nil {
return config, err
@@ -102,6 +107,123 @@ func LoadAPIAuthConfig(_ *gin.Context) (APIAuthConfig, error) {
return config, nil
}
+func GetAPIClientIP(c *gin.Context, trustedProxies string) string {
+ remoteAddr := common.GetRealClientIP(c)
+ remoteIP := net.ParseIP(remoteAddr)
+ if remoteIP == nil {
+ return remoteAddr
+ }
+
+ proxies, err := parseAPITrustedProxies(trustedProxies)
+ if err != nil {
+ if global.LOG != nil {
+ global.LOG.Errorf("Failed to parse API trusted proxies: %v", err)
+ }
+ return remoteAddr
+ }
+ if !isIPInNetworks(remoteIP, proxies) {
+ return remoteAddr
+ }
+
+ forwardedFor := strings.Join(c.Request.Header.Values("X-Forwarded-For"), ",")
+ if strings.TrimSpace(forwardedFor) != "" {
+ clientIP, ok := clientIPFromForwardedFor(forwardedFor, proxies)
+ if !ok {
+ return remoteAddr
+ }
+ return clientIP
+ }
+
+ realIPValue := strings.Join(c.Request.Header.Values("X-Real-IP"), ",")
+ realIP := net.ParseIP(strings.TrimSpace(realIPValue))
+ if realIP == nil {
+ return remoteAddr
+ }
+ return realIP.String()
+}
+
+func NormalizeAPITrustedProxies(value string) (string, error) {
+ lines := strings.Split(value, "\n")
+ normalized := make([]string, 0, len(lines))
+ for _, line := range lines {
+ item := strings.TrimSpace(line)
+ if item == "" {
+ continue
+ }
+ if ip := net.ParseIP(item); ip != nil {
+ normalized = append(normalized, ip.String())
+ continue
+ }
+ _, ipNet, err := net.ParseCIDR(item)
+ if err != nil {
+ return "", fmt.Errorf("invalid API trusted proxy entry %q: %w", item, err)
+ }
+ ones, _ := ipNet.Mask.Size()
+ if ones == 0 {
+ return "", fmt.Errorf("invalid API trusted proxy entry %q: unrestricted CIDR is not allowed", item)
+ }
+ normalized = append(normalized, ipNet.String())
+ }
+ return strings.Join(normalized, "\n"), nil
+}
+
+func parseAPITrustedProxies(value string) ([]*net.IPNet, error) {
+ normalized, err := NormalizeAPITrustedProxies(value)
+ if err != nil {
+ return nil, err
+ }
+ if normalized == "" {
+ return []*net.IPNet{}, nil
+ }
+
+ lines := strings.Split(normalized, "\n")
+ proxies := make([]*net.IPNet, 0, len(lines))
+ for _, item := range lines {
+ if ip := net.ParseIP(item); ip != nil {
+ bits := 128
+ if ip.To4() != nil {
+ bits = 32
+ ip = ip.To4()
+ }
+ proxies = append(proxies, &net.IPNet{IP: ip, Mask: net.CIDRMask(bits, bits)})
+ continue
+ }
+ _, ipNet, err := net.ParseCIDR(item)
+ if err != nil {
+ return nil, err
+ }
+ proxies = append(proxies, ipNet)
+ }
+ return proxies, nil
+}
+
+func clientIPFromForwardedFor(value string, trustedProxies []*net.IPNet) (string, bool) {
+ items := strings.Split(value, ",")
+ ips := make([]net.IP, len(items))
+ for i, item := range items {
+ ip := net.ParseIP(strings.TrimSpace(item))
+ if ip == nil {
+ return "", false
+ }
+ ips[i] = ip
+ }
+ for i := len(ips) - 1; i >= 0; i-- {
+ if i == 0 || !isIPInNetworks(ips[i], trustedProxies) {
+ return ips[i].String(), true
+ }
+ }
+ return "", false
+}
+
+func isIPInNetworks(ip net.IP, networks []*net.IPNet) bool {
+ for _, network := range networks {
+ if network.Contains(ip) {
+ return true
+ }
+ }
+ return false
+}
+
func IsValid1PanelTimestamp(panelTimestamp string, apiKeyValidityTime int) bool {
apiTime := apiKeyValidityTime
if apiTime < 0 {
diff --git a/core/app/auth/auth.go b/core/app/auth/auth.go
index 21bbc1509..9a00ead27 100644
--- a/core/app/auth/auth.go
+++ b/core/app/auth/auth.go
@@ -311,6 +311,10 @@ func GenerateApiKey() (string, error) {
}
func UpdateApiConfig(req dto.ApiInterfaceConfig) error {
settingRepo := repo.NewISettingRepo()
+ trustedProxies, err := NormalizeAPITrustedProxies(req.ApiTrustedProxies)
+ if err != nil {
+ return err
+ }
if err := settingRepo.UpdateOrCreate("ApiInterfaceStatus", req.ApiInterfaceStatus); err != nil {
return err
}
@@ -320,6 +324,9 @@ func UpdateApiConfig(req dto.ApiInterfaceConfig) error {
if err := settingRepo.UpdateOrCreate("IpWhiteList", req.IpWhiteList); err != nil {
return err
}
+ if err := settingRepo.UpdateOrCreate("ApiTrustedProxies", trustedProxies); err != nil {
+ return err
+ }
if err := settingRepo.UpdateOrCreate("ApiKeyValidityTime", strconv.Itoa(req.ApiKeyValidityTime)); err != nil {
return err
}
diff --git a/core/app/dto/auth.go b/core/app/dto/auth.go
index 2e46a743b..5a871849a 100644
--- a/core/app/dto/auth.go
+++ b/core/app/dto/auth.go
@@ -57,6 +57,7 @@ type ApiInterfaceConfig struct {
ApiInterfaceStatus string `json:"apiInterfaceStatus"`
ApiKey string `json:"apiKey"`
IpWhiteList string `json:"ipWhiteList"`
+ ApiTrustedProxies string `json:"apiTrustedProxies"`
ApiKeyValidityTime int `json:"apiKeyValidityTime"`
}
@@ -71,6 +72,7 @@ type CurrentUserInfo struct {
ApiInterfaceStatus string `json:"apiInterfaceStatus"`
ApiKey string `json:"apiKey"`
IpWhiteList string `json:"ipWhiteList"`
+ ApiTrustedProxies string `json:"apiTrustedProxies"`
ApiKeyValidityTime int `json:"apiKeyValidityTime"`
Role string `json:"role"`
diff --git a/core/cmd/server/docs/docs.go b/core/cmd/server/docs/docs.go
index dbcce4993..a4dd91a1b 100644
--- a/core/cmd/server/docs/docs.go
+++ b/core/cmd/server/docs/docs.go
@@ -2120,6 +2120,158 @@ const docTemplate = `{
]
}
},
+ "/ai/agents/plugins/install": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "description": "request",
+ "in": "body",
+ "name": "request",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/dto.AgentPluginMarketInstallReq"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK"
+ }
+ },
+ "security": [
+ {
+ "ApiKeyAuth": []
+ },
+ {
+ "Timestamp": []
+ }
+ ],
+ "summary": "Install an OpenClaw marketplace plugin",
+ "tags": [
+ "AI"
+ ]
+ }
+ },
+ "/ai/agents/plugins/list": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "description": "request",
+ "in": "body",
+ "name": "request",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/dto.AgentPluginsReq"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "items": {
+ "$ref": "#/definitions/dto.AgentPluginItem"
+ },
+ "type": "array"
+ }
+ }
+ },
+ "security": [
+ {
+ "ApiKeyAuth": []
+ },
+ {
+ "Timestamp": []
+ }
+ ],
+ "summary": "List OpenClaw plugins",
+ "tags": [
+ "AI"
+ ]
+ }
+ },
+ "/ai/agents/plugins/operate": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "description": "request",
+ "in": "body",
+ "name": "request",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/dto.AgentPluginOperateReq"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK"
+ }
+ },
+ "security": [
+ {
+ "ApiKeyAuth": []
+ },
+ {
+ "Timestamp": []
+ }
+ ],
+ "summary": "Operate an OpenClaw plugin",
+ "tags": [
+ "AI"
+ ]
+ }
+ },
+ "/ai/agents/plugins/search": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "description": "request",
+ "in": "body",
+ "name": "request",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/dto.AgentPluginSearchReq"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "items": {
+ "$ref": "#/definitions/dto.AgentPluginSearchItem"
+ },
+ "type": "array"
+ }
+ }
+ },
+ "security": [
+ {
+ "ApiKeyAuth": []
+ },
+ {
+ "Timestamp": []
+ }
+ ],
+ "summary": "Search OpenClaw plugins",
+ "tags": [
+ "AI"
+ ]
+ }
+ },
"/ai/agents/remark": {
"post": {
"consumes": [
@@ -9257,10 +9409,11 @@ const docTemplate = `{
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [
- "ipWhiteList"
+ "ipWhiteList",
+ "apiTrustedProxies"
],
- "formatEN": "update api config =\u003e IP White List: [ipWhiteList]",
- "formatZH": "更新 API 接口配置 =\u003e IP 白名单: [ipWhiteList]",
+ "formatEN": "update api config =\u003e IP Allowlist: [ipWhiteList], API Trusted Proxies: [apiTrustedProxies]",
+ "formatZH": "更新 API 接口配置 =\u003e IP 白名单: [ipWhiteList], API 可信代理: [apiTrustedProxies]",
"paramKeys": []
}
}
@@ -30404,6 +30557,143 @@ const docTemplate = `{
],
"type": "object"
},
+ "dto.AgentPluginItem": {
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ },
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "origin": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "dto.AgentPluginMarketInstallReq": {
+ "properties": {
+ "agentId": {
+ "type": "integer"
+ },
+ "package": {
+ "maxLength": 200,
+ "type": "string"
+ },
+ "taskID": {
+ "type": "string"
+ },
+ "version": {
+ "maxLength": 100,
+ "type": "string"
+ }
+ },
+ "required": [
+ "agentId",
+ "package",
+ "taskID",
+ "version"
+ ],
+ "type": "object"
+ },
+ "dto.AgentPluginOperateReq": {
+ "properties": {
+ "agentId": {
+ "type": "integer"
+ },
+ "operate": {
+ "enum": [
+ "enable",
+ "disable",
+ "update",
+ "uninstall"
+ ],
+ "type": "string"
+ },
+ "pluginId": {
+ "maxLength": 200,
+ "type": "string"
+ },
+ "taskID": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "agentId",
+ "operate",
+ "pluginId",
+ "taskID"
+ ],
+ "type": "object"
+ },
+ "dto.AgentPluginSearchItem": {
+ "properties": {
+ "categories": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "channel": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "downloads": {
+ "type": "integer"
+ },
+ "name": {
+ "type": "string"
+ },
+ "official": {
+ "type": "boolean"
+ },
+ "package": {
+ "type": "string"
+ },
+ "pluginId": {
+ "type": "string"
+ },
+ "score": {
+ "type": "number"
+ },
+ "verificationTier": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "dto.AgentPluginSearchReq": {
+ "properties": {
+ "agentId": {
+ "type": "integer"
+ },
+ "keyword": {
+ "maxLength": 100,
+ "type": "string"
+ },
+ "limit": {
+ "maximum": 100,
+ "minimum": 1,
+ "type": "integer"
+ }
+ },
+ "required": [
+ "agentId",
+ "keyword"
+ ],
+ "type": "object"
+ },
"dto.AgentPluginStatus": {
"properties": {
"currentVersion": {
@@ -30473,6 +30763,17 @@ const docTemplate = `{
],
"type": "object"
},
+ "dto.AgentPluginsReq": {
+ "properties": {
+ "agentId": {
+ "type": "integer"
+ }
+ },
+ "required": [
+ "agentId"
+ ],
+ "type": "object"
+ },
"dto.AgentQQBotBot": {
"properties": {
"accountId": {
@@ -31518,6 +31819,9 @@ const docTemplate = `{
"apiKeyValidityTime": {
"type": "integer"
},
+ "apiTrustedProxies": {
+ "type": "string"
+ },
"ipWhiteList": {
"type": "string"
}
@@ -33560,6 +33864,15 @@ const docTemplate = `{
"apiKeyValidityTime": {
"type": "integer"
},
+ "apiTrustedProxies": {
+ "type": "string"
+ },
+ "authSource": {
+ "type": "string"
+ },
+ "authSourceStatus": {
+ "type": "string"
+ },
"complexitySetting": {
"type": "string"
},
diff --git a/core/cmd/server/docs/swagger.json b/core/cmd/server/docs/swagger.json
index dced38cc2..d814d9cfb 100644
--- a/core/cmd/server/docs/swagger.json
+++ b/core/cmd/server/docs/swagger.json
@@ -2116,6 +2116,158 @@
]
}
},
+ "/ai/agents/plugins/install": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "description": "request",
+ "in": "body",
+ "name": "request",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/dto.AgentPluginMarketInstallReq"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK"
+ }
+ },
+ "security": [
+ {
+ "ApiKeyAuth": []
+ },
+ {
+ "Timestamp": []
+ }
+ ],
+ "summary": "Install an OpenClaw marketplace plugin",
+ "tags": [
+ "AI"
+ ]
+ }
+ },
+ "/ai/agents/plugins/list": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "description": "request",
+ "in": "body",
+ "name": "request",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/dto.AgentPluginsReq"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "items": {
+ "$ref": "#/definitions/dto.AgentPluginItem"
+ },
+ "type": "array"
+ }
+ }
+ },
+ "security": [
+ {
+ "ApiKeyAuth": []
+ },
+ {
+ "Timestamp": []
+ }
+ ],
+ "summary": "List OpenClaw plugins",
+ "tags": [
+ "AI"
+ ]
+ }
+ },
+ "/ai/agents/plugins/operate": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "description": "request",
+ "in": "body",
+ "name": "request",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/dto.AgentPluginOperateReq"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK"
+ }
+ },
+ "security": [
+ {
+ "ApiKeyAuth": []
+ },
+ {
+ "Timestamp": []
+ }
+ ],
+ "summary": "Operate an OpenClaw plugin",
+ "tags": [
+ "AI"
+ ]
+ }
+ },
+ "/ai/agents/plugins/search": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "description": "request",
+ "in": "body",
+ "name": "request",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/dto.AgentPluginSearchReq"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "items": {
+ "$ref": "#/definitions/dto.AgentPluginSearchItem"
+ },
+ "type": "array"
+ }
+ }
+ },
+ "security": [
+ {
+ "ApiKeyAuth": []
+ },
+ {
+ "Timestamp": []
+ }
+ ],
+ "summary": "Search OpenClaw plugins",
+ "tags": [
+ "AI"
+ ]
+ }
+ },
"/ai/agents/remark": {
"post": {
"consumes": [
@@ -9253,10 +9405,11 @@
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [
- "ipWhiteList"
+ "ipWhiteList",
+ "apiTrustedProxies"
],
- "formatEN": "update api config =\u003e IP White List: [ipWhiteList]",
- "formatZH": "更新 API 接口配置 =\u003e IP 白名单: [ipWhiteList]",
+ "formatEN": "update api config =\u003e IP Allowlist: [ipWhiteList], API Trusted Proxies: [apiTrustedProxies]",
+ "formatZH": "更新 API 接口配置 =\u003e IP 白名单: [ipWhiteList], API 可信代理: [apiTrustedProxies]",
"paramKeys": []
}
}
@@ -30400,6 +30553,143 @@
],
"type": "object"
},
+ "dto.AgentPluginItem": {
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ },
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "origin": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "dto.AgentPluginMarketInstallReq": {
+ "properties": {
+ "agentId": {
+ "type": "integer"
+ },
+ "package": {
+ "maxLength": 200,
+ "type": "string"
+ },
+ "taskID": {
+ "type": "string"
+ },
+ "version": {
+ "maxLength": 100,
+ "type": "string"
+ }
+ },
+ "required": [
+ "agentId",
+ "package",
+ "taskID",
+ "version"
+ ],
+ "type": "object"
+ },
+ "dto.AgentPluginOperateReq": {
+ "properties": {
+ "agentId": {
+ "type": "integer"
+ },
+ "operate": {
+ "enum": [
+ "enable",
+ "disable",
+ "update",
+ "uninstall"
+ ],
+ "type": "string"
+ },
+ "pluginId": {
+ "maxLength": 200,
+ "type": "string"
+ },
+ "taskID": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "agentId",
+ "operate",
+ "pluginId",
+ "taskID"
+ ],
+ "type": "object"
+ },
+ "dto.AgentPluginSearchItem": {
+ "properties": {
+ "categories": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "channel": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "downloads": {
+ "type": "integer"
+ },
+ "name": {
+ "type": "string"
+ },
+ "official": {
+ "type": "boolean"
+ },
+ "package": {
+ "type": "string"
+ },
+ "pluginId": {
+ "type": "string"
+ },
+ "score": {
+ "type": "number"
+ },
+ "verificationTier": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "dto.AgentPluginSearchReq": {
+ "properties": {
+ "agentId": {
+ "type": "integer"
+ },
+ "keyword": {
+ "maxLength": 100,
+ "type": "string"
+ },
+ "limit": {
+ "maximum": 100,
+ "minimum": 1,
+ "type": "integer"
+ }
+ },
+ "required": [
+ "agentId",
+ "keyword"
+ ],
+ "type": "object"
+ },
"dto.AgentPluginStatus": {
"properties": {
"currentVersion": {
@@ -30469,6 +30759,17 @@
],
"type": "object"
},
+ "dto.AgentPluginsReq": {
+ "properties": {
+ "agentId": {
+ "type": "integer"
+ }
+ },
+ "required": [
+ "agentId"
+ ],
+ "type": "object"
+ },
"dto.AgentQQBotBot": {
"properties": {
"accountId": {
@@ -31514,6 +31815,9 @@
"apiKeyValidityTime": {
"type": "integer"
},
+ "apiTrustedProxies": {
+ "type": "string"
+ },
"ipWhiteList": {
"type": "string"
}
@@ -33556,6 +33860,15 @@
"apiKeyValidityTime": {
"type": "integer"
},
+ "apiTrustedProxies": {
+ "type": "string"
+ },
+ "authSource": {
+ "type": "string"
+ },
+ "authSourceStatus": {
+ "type": "string"
+ },
"complexitySetting": {
"type": "string"
},
diff --git a/core/cmd/server/docs/x-log.json b/core/cmd/server/docs/x-log.json
index 2d60faeeb..989c6b670 100644
--- a/core/cmd/server/docs/x-log.json
+++ b/core/cmd/server/docs/x-log.json
@@ -816,12 +816,13 @@
},
"/core/auth/api/update": {
"bodyKeys": [
- "ipWhiteList"
+ "ipWhiteList",
+ "apiTrustedProxies"
],
"paramKeys": [],
"beforeFunctions": [],
- "formatZH": "更新 API 接口配置 =\u003e IP 白名单: [ipWhiteList]",
- "formatEN": "update api config =\u003e IP White List: [ipWhiteList]"
+ "formatZH": "更新 API 接口配置 =\u003e IP 白名单: [ipWhiteList], API 可信代理: [apiTrustedProxies]",
+ "formatEN": "update api config =\u003e IP Allowlist: [ipWhiteList], API Trusted Proxies: [apiTrustedProxies]"
},
"/core/auth/expired/reset": {
"bodyKeys": [],
@@ -1577,7 +1578,8 @@
"/core/enterprise/users/api/update": {
"bodyKeys": [
"id",
- "ipWhiteList"
+ "ipWhiteList",
+ "apiTrustedProxies"
],
"paramKeys": [],
"beforeFunctions": [
@@ -1590,8 +1592,8 @@
"output_value": "name"
}
],
- "formatZH": "更新用户 [name] API 接口配置 =\u003e IP 白名单: [ipWhiteList]",
- "formatEN": "update user [name] api config =\u003e IP White List: [ipWhiteList]"
+ "formatZH": "更新用户 [name] API 接口配置 =\u003e IP 白名单: [ipWhiteList], API 可信代理: [apiTrustedProxies]",
+ "formatEN": "update user [name] api config =\u003e IP Allowlist: [ipWhiteList], API Trusted Proxies: [apiTrustedProxies]"
},
"/core/enterprise/users/del": {
"bodyKeys": [
diff --git a/core/init/migration/migrate.go b/core/init/migration/migrate.go
index 411affc92..31c085c0f 100644
--- a/core/init/migration/migrate.go
+++ b/core/init/migration/migrate.go
@@ -51,6 +51,7 @@ func Init() {
migrations.AddLoginLogUser,
migrations.AddAlertAuditUser,
migrations.AddMenuAccordionSetting,
+ migrations.AddAPITrustedProxiesSetting,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
diff --git a/core/init/migration/migrations/init.go b/core/init/migration/migrations/init.go
index e54279d8f..d18b1c837 100644
--- a/core/init/migration/migrations/init.go
+++ b/core/init/migration/migrations/init.go
@@ -183,6 +183,9 @@ var InitSetting = &gormigrate.Migration{
if err := tx.Create(&model.Setting{Key: "IpWhiteList", Value: ""}).Error; err != nil {
return err
}
+ if err := tx.Create(&model.Setting{Key: "ApiTrustedProxies", Value: ""}).Error; err != nil {
+ return err
+ }
if err := tx.Create(&model.Setting{Key: "ApiKeyValidityTime", Value: "120"}).Error; err != nil {
return err
}
@@ -1282,3 +1285,17 @@ var AddMenuAccordionSetting = &gormigrate.Migration{
return nil
},
}
+
+var AddAPITrustedProxiesSetting = &gormigrate.Migration{
+ ID: "20260729-add-api-trusted-proxies-setting",
+ Migrate: func(tx *gorm.DB) error {
+ var setting model.Setting
+ if err := tx.Where("key = ?", "ApiTrustedProxies").First(&setting).Error; err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return tx.Create(&model.Setting{Key: "ApiTrustedProxies", Value: ""}).Error
+ }
+ return err
+ }
+ return nil
+ },
+}
diff --git a/frontend/src/api/interface/auth.ts b/frontend/src/api/interface/auth.ts
index 73bb14dbd..67f0ae1b5 100644
--- a/frontend/src/api/interface/auth.ts
+++ b/frontend/src/api/interface/auth.ts
@@ -61,6 +61,7 @@ export namespace Login {
apiInterfaceStatus: string;
apiKey: string;
ipWhiteList: string;
+ apiTrustedProxies: string;
apiKeyValidityTime: number;
}
export interface AuthInfoUpdate {
@@ -86,6 +87,7 @@ export namespace Login {
apiInterfaceStatus: string;
apiKey: string;
ipWhiteList: string;
+ apiTrustedProxies: string;
apiKeyValidityTime: number;
}
export interface PasswordUpdate {
diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts
index a5ff75a94..f1fae8696 100644
--- a/frontend/src/lang/modules/en.ts
+++ b/frontend/src/lang/modules/en.ts
@@ -2758,6 +2758,9 @@ const message = {
ipWhiteList: 'IP allowlist',
ipWhiteListEgs: 'One per line. For example,\n172.161.10.111\n172.161.10.0/24',
ipWhiteListHelper: 'IPs within the allowlist can access the API,0.0.0.0/0 (all IPv4), ::/0 (all IPv6)',
+ apiTrustedProxies: 'API trusted proxies',
+ apiTrustedProxiesHelper:
+ 'When using a reverse proxy, enter the IP address or network of the proxy server to correctly obtain the client IP. Otherwise, leave this blank. 0.0.0.0/0 and ::/0 are not supported.',
apiKeyValidityTime: 'Validity period of interface key',
apiKeyValidityTimeEgs: 'Validity period of interface key (in minutes)',
apiKeyValidityTimeHelper:
diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts
index b63f98211..30a1d995a 100644
--- a/frontend/src/lang/modules/es-es.ts
+++ b/frontend/src/lang/modules/es-es.ts
@@ -2807,6 +2807,9 @@ const message = {
ipWhiteListEgs: 'Una por línea. Por ejemplo,\n172.161.10.111\n172.161.10.0/24',
ipWhiteListHelper:
'Las IP en la lista blanca pueden acceder a la API, 0.0.0.0/0 (todas IPv4), ::/0 (todas IPv6)',
+ apiTrustedProxies: 'Proxies de confianza de la API',
+ apiTrustedProxiesHelper:
+ 'Al usar un proxy inverso, introduce la IP o la red del servidor proxy para obtener correctamente la IP del cliente. Si no lo usas, deja este campo vacío. No se admiten 0.0.0.0/0 ni ::/0.',
apiKeyValidityTime: 'Periodo de validez de la clave de interfaz',
apiKeyValidityTimeEgs: 'Periodo de validez de la clave de interfaz (en minutos)',
apiKeyValidityTimeHelper:
diff --git a/frontend/src/lang/modules/fa.ts b/frontend/src/lang/modules/fa.ts
index edb07c590..b5719a420 100644
--- a/frontend/src/lang/modules/fa.ts
+++ b/frontend/src/lang/modules/fa.ts
@@ -2733,6 +2733,9 @@ const message = {
ipWhiteListEgs: 'هر خط یک IP. مثلاً،\n172.161.10.111\n172.161.10.0/24',
ipWhiteListHelper:
'IPهای موجود در لیست سفید میتوانند به API دسترسی داشته باشند، 0.0.0.0/0 (همه IPv4)، ::/0 (همه IPv6)',
+ apiTrustedProxies: 'پروکسیهای قابل اعتماد API',
+ apiTrustedProxiesHelper:
+ 'هنگام استفاده از پروکسی معکوس، IP یا شبکه سرور پروکسی را وارد کنید تا IP کلاینت بهدرستی دریافت شود. در صورت عدم استفاده، این بخش را خالی بگذارید. 0.0.0.0/0 و ::/0 پشتیبانی نمیشوند.',
apiKeyValidityTime: 'مدت اعتبار کلید رابط',
apiKeyValidityTimeEgs: 'مدت اعتبار کلید رابط (به دقیقه)',
apiKeyValidityTimeHelper:
diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts
index 03dde3e6e..7ca51217a 100644
--- a/frontend/src/lang/modules/ja.ts
+++ b/frontend/src/lang/modules/ja.ts
@@ -2755,6 +2755,9 @@ const message = {
ipWhiteList: 'IP AllowList',
ipWhiteListEgs: '1行に1つ。たとえば、 n172.161.10.111 n172.161.10.0/24',
ipWhiteListHelper: 'AllowList内のIPSはAPIにアクセスできます、0.0.0.0/0(すべての IPv4)、::/0(すべての IPv6)',
+ apiTrustedProxies: 'API信頼済みプロキシ',
+ apiTrustedProxiesHelper:
+ 'リバースプロキシを使用する場合は、クライアントIPを正しく取得するために、プロキシサーバーのIPまたはネットワークを入力してください。使用しない場合は空欄にしてください。0.0.0.0/0と::/0は指定できません。',
apiKeyReset: 'インターフェイスキーリセット',
apiKeyResetHelper: '関連するキーサービスは無効になります。サービスに新しいキーを追加してください',
confDockerProxy: 'Dockerプロキシを構成します',
diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts
index fe2fc2092..2284fe18b 100644
--- a/frontend/src/lang/modules/ko.ts
+++ b/frontend/src/lang/modules/ko.ts
@@ -2706,6 +2706,9 @@ const message = {
ipWhiteList: 'IP 허용 목록',
ipWhiteListEgs: '한 줄에 하나씩 입력하십시오. 예:\n172.161.10.111\n172.161.10.0/24',
ipWhiteListHelper: '허용 목록에 있는 IP만 API 에 접근할 수 있습니다. 0.0.0.0/0(모든 IPv4), ::/0(모든 IPv6)',
+ apiTrustedProxies: 'API 신뢰 프록시',
+ apiTrustedProxiesHelper:
+ '리버스 프록시를 사용하는 경우 클라이언트 IP를 올바르게 가져오려면 프록시 서버의 IP 또는 네트워크를 입력하세요. 사용하지 않는 경우 비워 두세요. 0.0.0.0/0 및 ::/0은 지원되지 않습니다.',
apiKeyValidityTime: '인터페이스 키 유효 기간',
apiKeyValidityTimeEgs: '인터페이스 키 유효 기간 (분 단위)',
apiKeyValidityTimeHelper:
diff --git a/frontend/src/lang/modules/lo.ts b/frontend/src/lang/modules/lo.ts
index 306ab5bca..5ed6abdfa 100644
--- a/frontend/src/lang/modules/lo.ts
+++ b/frontend/src/lang/modules/lo.ts
@@ -2696,6 +2696,9 @@ const message = {
ipWhiteList: 'IP allowlist',
ipWhiteListEgs: 'ໜຶ່ງລາຍການຕໍ່ແຖວ. ຕົວຢ່າງ:\n172.161.10.111\n172.161.10.0/24',
ipWhiteListHelper: 'IP ໃນ allowlist ສາມາດເຂົ້າເຖິງ API ໄດ້, 0.0.0.0/0 (ທຸກ IPv4), ::/0 (ທຸກ IPv6)',
+ apiTrustedProxies: 'ພຣັອກຊີ API ທີ່ເຊື່ອຖື',
+ apiTrustedProxiesHelper:
+ 'ເມື່ອໃຊ້ reverse proxy, ໃຫ້ໃສ່ IP ຫຼືເຄືອຂ່າຍຂອງ proxy server ເພື່ອໃຫ້ໄດ້ client IP ຢ່າງຖືກຕ້ອງ. ຖ້າບໍ່ໃຊ້ໃຫ້ປ່ອຍຫວ່າງ. ບໍ່ຮອງຮັບ 0.0.0.0/0 ແລະ ::/0.',
apiKeyValidityTime: 'ໄລຍະເວລາທີ່ API key ໃຊ້ງານໄດ້',
apiKeyValidityTimeEgs: 'ໄລຍະເວລາທີ່ API key ໃຊ້ງານໄດ້ (ນາທີ)',
apiKeyValidityTimeHelper:
diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts
index f9a66c423..6925ec1e1 100644
--- a/frontend/src/lang/modules/ms.ts
+++ b/frontend/src/lang/modules/ms.ts
@@ -2803,6 +2803,9 @@ const message = {
ipWhiteList: 'Senarai putih IP',
ipWhiteListEgs: 'Satu per baris. Contoh,\n172.161.10.111\n172.161.10.0/24',
ipWhiteListHelper: 'IP dalam senarai putih boleh mengakses API, 0.0.0.0/0 (semua IPv4), ::/0 (semua IPv6)',
+ apiTrustedProxies: 'Proksi dipercayai API',
+ apiTrustedProxiesHelper:
+ 'Apabila menggunakan proksi songsang, masukkan IP atau rangkaian pelayan proksi untuk mendapatkan IP klien dengan betul. Jika tidak digunakan, biarkan kosong. 0.0.0.0/0 dan ::/0 tidak disokong.',
apiKeyValidityTime: 'Tempoh sah kunci antara muka',
apiKeyValidityTimeEgs: 'Tempoh sah kunci antara muka (dalam minit)',
apiKeyValidityTimeHelper:
diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts
index 30a91f35e..60bbe4c71 100644
--- a/frontend/src/lang/modules/pt-br.ts
+++ b/frontend/src/lang/modules/pt-br.ts
@@ -2919,6 +2919,9 @@ const message = {
ipWhiteListEgs: 'Um por linha. Exemplo: \n172.161.10.111\n172.161.10.0/24',
ipWhiteListHelper:
'IPs na lista de permitidos podem acessar a API, 0.0.0.0/0 (todos os IPv4), ::/0 (todos os IPv6)',
+ apiTrustedProxies: 'Proxies confiáveis da API',
+ apiTrustedProxiesHelper:
+ 'Ao usar um proxy reverso, insira o IP ou a rede do servidor proxy para obter corretamente o IP do cliente. Caso contrário, deixe este campo em branco. 0.0.0.0/0 e ::/0 não são suportados.',
apiKeyReset: 'Redefinir chave da interface',
apiKeyResetHelper:
'O serviço associado à chave se tornará inválido. Por favor, adicione uma nova chave ao serviço',
diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts
index 9d5287f0e..7e52bce1d 100644
--- a/frontend/src/lang/modules/ru.ts
+++ b/frontend/src/lang/modules/ru.ts
@@ -2778,6 +2778,9 @@ const message = {
ipWhiteListEgs: 'По одному в строке. Например,\n172.161.10.111\n172.161.10.0/24',
ipWhiteListHelper:
'IP-адреса из белого списка могут получить доступ к API, 0.0.0.0/0 (все IPv4), ::/0 (все IPv6)',
+ apiTrustedProxies: 'Доверенные прокси API',
+ apiTrustedProxiesHelper:
+ 'При использовании обратного прокси укажите IP-адрес или сеть прокси-сервера, чтобы корректно определить IP клиента. Если прокси не используется, оставьте поле пустым. 0.0.0.0/0 и ::/0 не поддерживаются.',
apiKeyValidityTime: 'Срок действия ключа интерфейса',
apiKeyValidityTimeEgs: 'Срок действия ключа интерфейса (в единицах)',
apiKeyValidityTimeHelper:
diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts
index f459938b5..b0f96224d 100644
--- a/frontend/src/lang/modules/tr.ts
+++ b/frontend/src/lang/modules/tr.ts
@@ -2786,6 +2786,9 @@ const message = {
ipWhiteList: 'IP izin listesi',
ipWhiteListEgs: 'Her satıra bir tane. Örneğin,\n172.161.10.111\n172.161.10.0/24',
ipWhiteListHelper: 'İzin listesindeki IP’ler API’ye erişebilir, 0.0.0.0/0 (tüm IPv4), ::/0 (tüm IPv6)',
+ apiTrustedProxies: 'API güvenilir proxyleri',
+ apiTrustedProxiesHelper:
+ 'Ters proxy kullanırken istemci IP adresini doğru şekilde almak için proxy sunucusunun IP adresini veya ağını girin. Kullanmıyorsanız boş bırakın. 0.0.0.0/0 ve ::/0 desteklenmez.',
apiKeyValidityTime: 'Arayüz anahtarının geçerlilik süresi',
apiKeyValidityTimeEgs: 'Arayüz anahtarının geçerlilik süresi (dakika cinsinden)',
apiKeyValidityTimeHelper:
diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts
index 0a9ef0bf1..3a0777598 100644
--- a/frontend/src/lang/modules/zh-Hant.ts
+++ b/frontend/src/lang/modules/zh-Hant.ts
@@ -2587,6 +2587,9 @@ const message = {
ipWhiteListEgs: '當存在多個 IP 時,需要換行顯示,例:\n172.16.10.111 \n172.16.10.0/24',
ipWhiteListHelper:
'必需在 IP 白名單清單中的 IP 才能存取面板 API 介面,0.0.0.0/0(所有 IPv4),::/0(所有 IPv6)',
+ apiTrustedProxies: 'API 可信代理',
+ apiTrustedProxiesHelper:
+ '使用反向代理時,請填寫代理伺服器的 IP 或網段,以便正確取得用戶端 IP;不使用時請留空。不支援 0.0.0.0/0 和 ::/0。',
apiKeyValidityTime: '介面金鑰有效期',
apiKeyValidityTimeEgs: '介面金鑰有效期(組織分)',
apiKeyValidityTimeHelper: '介面時間戳記到請求時的目前時間戳之間有效(組織分),設定為0時,不做時間戳記校驗',
diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts
index 4ea2e1959..8ae25d1d1 100644
--- a/frontend/src/lang/modules/zh.ts
+++ b/frontend/src/lang/modules/zh.ts
@@ -2582,6 +2582,9 @@ const message = {
ipWhiteListEgs: '当存在多个 IP 时,需要换行显示,例: \n172.16.10.111 \n172.16.10.0/24',
ipWhiteListHelper:
'必需在 IP 白名单列表中的 IP 才能访问面板 API 接口,0.0.0.0/0(所有 IPv4),::/0(所有 IPv6)',
+ apiTrustedProxies: 'API 可信代理',
+ apiTrustedProxiesHelper:
+ '使用反向代理时,请填写代理服务器的 IP 或网段,以便正确获取客户端 IP;不使用时请留空。不支持 0.0.0.0/0 和 ::/0。',
apiKeyValidityTime: '接口密钥有效期',
apiKeyValidityTimeEgs: '接口密钥有效期(单位分)',
apiKeyValidityTimeHelper: '接口时间戳到请求时的当前时间戳之间有效(单位分),设置为 0 时,不做时间戳校验',
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 5db385ae1..ff842b9a3 100644
--- a/frontend/src/layout/components/Sidebar/components/user-info/index.vue
+++ b/frontend/src/layout/components/Sidebar/components/user-info/index.vue
@@ -356,6 +356,15 @@
/>
{{ $t('setting.ipWhiteListHelper') }}
+
+
+ {{ $t('setting.apiTrustedProxiesHelper') }}
+
{{ $t('commons.units.minute') }}
@@ -446,6 +455,7 @@ const form = reactive({
apiInterfaceStatus: 'Disable',
apiKey: '',
ipWhiteList: '',
+ apiTrustedProxies: '',
apiKeyValidityTime: 120,
});
const mfaForm = reactive({
@@ -512,6 +522,7 @@ const mfaRules = reactive({
});
const apiRules = reactive({
ipWhiteList: [Rules.requiredInput, { validator: checkIPs, trigger: 'blur' }],
+ apiTrustedProxies: [{ validator: checkIPs, trigger: 'blur' }],
apiKey: [Rules.requiredInput],
apiKeyValidityTime: [Rules.requiredInput, Rules.integerNumberWith0],
});
@@ -523,7 +534,7 @@ const getUserFormFields = () => {
}
return fields;
};
-const apiFormFields = ['apiKey', 'ipWhiteList', 'apiKeyValidityTime'];
+const apiFormFields = ['apiKey', 'ipWhiteList', 'apiTrustedProxies', 'apiKeyValidityTime'];
const openDrawer = async () => {
if (!props.currentUser) {
@@ -538,6 +549,7 @@ const syncApiConfig = (currentUser: Login.AuthInfo) => {
form.apiInterfaceStatus = currentUser.apiInterfaceStatus || 'Disable';
form.apiKey = currentUser.apiKey;
form.ipWhiteList = currentUser.ipWhiteList;
+ form.apiTrustedProxies = currentUser.apiTrustedProxies || '';
form.apiKeyValidityTime = currentUser.apiKeyValidityTime;
savedApiStatus.value = form.apiInterfaceStatus;
};
@@ -586,9 +598,10 @@ const resetApiKey = async () => {
};
function checkIPs(rule: any, value: any, callback: any) {
- if (form.ipWhiteList !== '') {
- let addr = form.ipWhiteList.split('\n');
- for (const item of addr) {
+ if (value !== '') {
+ let addr = value.split('\n');
+ for (const rawItem of addr) {
+ const item = rawItem.trim();
if (item === '') {
continue;
}
@@ -898,6 +911,7 @@ const onSaveApi = async (formEl: FormInstance | undefined) => {
const param = {
apiKey: form.apiKey,
ipWhiteList: form.ipWhiteList,
+ apiTrustedProxies: form.apiTrustedProxies,
apiInterfaceStatus: form.apiInterfaceStatus,
apiKeyValidityTime: form.apiKeyValidityTime,
};
@@ -972,6 +986,7 @@ const handleApi = async () => {
let param = {
apiKey: form.apiKey,
ipWhiteList: form.ipWhiteList,
+ apiTrustedProxies: form.apiTrustedProxies,
apiInterfaceStatus: form.apiInterfaceStatus,
apiKeyValidityTime: form.apiKeyValidityTime,
};