mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-23 18:49:21 +08:00
feat: Add API interface authentication function (#7146)
This commit is contained in:
parent
c2fd02ac48
commit
28597721f2
@ -342,3 +342,52 @@ func (b *BaseApi) MFABind(c *gin.Context) {
|
|||||||
|
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags System Setting
|
||||||
|
// @Summary generate api key
|
||||||
|
// @Description 生成 API 接口密钥
|
||||||
|
// @Accept json
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /settings/api/config/generate/key [post]
|
||||||
|
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"生成 API 接口密钥","formatEN":"generate api key"}
|
||||||
|
func (b *BaseApi) GenerateApiKey(c *gin.Context) {
|
||||||
|
panelToken := c.GetHeader("1Panel-Token")
|
||||||
|
if panelToken != "" {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrUnauthorized, constant.ErrApiConfigDisable, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apiKey, err := settingService.GenerateApiKey()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, apiKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags System Setting
|
||||||
|
// @Summary Update api config
|
||||||
|
// @Description 更新 API 接口配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.ApiInterfaceConfig true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /settings/api/config/update [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["ipWhiteList"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 API 接口配置 => IP 白名单: [ipWhiteList]","formatEN":"update api config => IP White List: [ipWhiteList]"}
|
||||||
|
func (b *BaseApi) UpdateApiConfig(c *gin.Context) {
|
||||||
|
panelToken := c.GetHeader("1Panel-Token")
|
||||||
|
if panelToken != "" {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrUnauthorized, constant.ErrApiConfigDisable, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var req dto.ApiInterfaceConfig
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settingService.UpdateApiConfig(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
@ -66,6 +66,10 @@ type SettingInfo struct {
|
|||||||
ProxyUser string `json:"proxyUser"`
|
ProxyUser string `json:"proxyUser"`
|
||||||
ProxyPasswd string `json:"proxyPasswd"`
|
ProxyPasswd string `json:"proxyPasswd"`
|
||||||
ProxyPasswdKeep string `json:"proxyPasswdKeep"`
|
ProxyPasswdKeep string `json:"proxyPasswdKeep"`
|
||||||
|
|
||||||
|
ApiInterfaceStatus string `json:"apiInterfaceStatus"`
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
IpWhiteList string `json:"ipWhiteList"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SettingUpdate struct {
|
type SettingUpdate struct {
|
||||||
@ -231,3 +235,9 @@ type XpackHideMenu struct {
|
|||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
Children []XpackHideMenu `json:"children,omitempty"`
|
Children []XpackHideMenu `json:"children,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ApiInterfaceConfig struct {
|
||||||
|
ApiInterfaceStatus string `json:"apiInterfaceStatus"`
|
||||||
|
ApiKey string `json:"apiKey"`
|
||||||
|
IpWhiteList string `json:"ipWhiteList"`
|
||||||
|
}
|
||||||
|
@ -40,6 +40,8 @@ type ISettingService interface {
|
|||||||
UpdateSSL(c *gin.Context, req dto.SSLUpdate) error
|
UpdateSSL(c *gin.Context, req dto.SSLUpdate) error
|
||||||
LoadFromCert() (*dto.SSLInfo, error)
|
LoadFromCert() (*dto.SSLInfo, error)
|
||||||
HandlePasswordExpired(c *gin.Context, old, new string) error
|
HandlePasswordExpired(c *gin.Context, old, new string) error
|
||||||
|
GenerateApiKey() (string, error)
|
||||||
|
UpdateApiConfig(req dto.ApiInterfaceConfig) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewISettingService() ISettingService {
|
func NewISettingService() ISettingService {
|
||||||
@ -485,3 +487,28 @@ func checkCertValid() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *SettingService) GenerateApiKey() (string, error) {
|
||||||
|
apiKey := common.RandStr(32)
|
||||||
|
if err := settingRepo.Update("ApiKey", apiKey); err != nil {
|
||||||
|
return global.CONF.System.ApiKey, err
|
||||||
|
}
|
||||||
|
global.CONF.System.ApiKey = apiKey
|
||||||
|
return apiKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SettingService) UpdateApiConfig(req dto.ApiInterfaceConfig) error {
|
||||||
|
if err := settingRepo.Update("ApiInterfaceStatus", req.ApiInterfaceStatus); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
global.CONF.System.ApiInterfaceStatus = req.ApiInterfaceStatus
|
||||||
|
if err := settingRepo.Update("ApiKey", req.ApiKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
global.CONF.System.ApiKey = req.ApiKey
|
||||||
|
if err := settingRepo.Update("IpWhiteList", req.IpWhiteList); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
global.CONF.System.IpWhiteList = req.IpWhiteList
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -1,28 +1,31 @@
|
|||||||
package configs
|
package configs
|
||||||
|
|
||||||
type System struct {
|
type System struct {
|
||||||
Port string `mapstructure:"port"`
|
Port string `mapstructure:"port"`
|
||||||
Ipv6 string `mapstructure:"ipv6"`
|
Ipv6 string `mapstructure:"ipv6"`
|
||||||
BindAddress string `mapstructure:"bindAddress"`
|
BindAddress string `mapstructure:"bindAddress"`
|
||||||
SSL string `mapstructure:"ssl"`
|
SSL string `mapstructure:"ssl"`
|
||||||
DbFile string `mapstructure:"db_file"`
|
DbFile string `mapstructure:"db_file"`
|
||||||
DbPath string `mapstructure:"db_path"`
|
DbPath string `mapstructure:"db_path"`
|
||||||
LogPath string `mapstructure:"log_path"`
|
LogPath string `mapstructure:"log_path"`
|
||||||
DataDir string `mapstructure:"data_dir"`
|
DataDir string `mapstructure:"data_dir"`
|
||||||
TmpDir string `mapstructure:"tmp_dir"`
|
TmpDir string `mapstructure:"tmp_dir"`
|
||||||
Cache string `mapstructure:"cache"`
|
Cache string `mapstructure:"cache"`
|
||||||
Backup string `mapstructure:"backup"`
|
Backup string `mapstructure:"backup"`
|
||||||
EncryptKey string `mapstructure:"encrypt_key"`
|
EncryptKey string `mapstructure:"encrypt_key"`
|
||||||
BaseDir string `mapstructure:"base_dir"`
|
BaseDir string `mapstructure:"base_dir"`
|
||||||
Mode string `mapstructure:"mode"`
|
Mode string `mapstructure:"mode"`
|
||||||
RepoUrl string `mapstructure:"repo_url"`
|
RepoUrl string `mapstructure:"repo_url"`
|
||||||
Version string `mapstructure:"version"`
|
Version string `mapstructure:"version"`
|
||||||
Username string `mapstructure:"username"`
|
Username string `mapstructure:"username"`
|
||||||
Password string `mapstructure:"password"`
|
Password string `mapstructure:"password"`
|
||||||
Entrance string `mapstructure:"entrance"`
|
Entrance string `mapstructure:"entrance"`
|
||||||
IsDemo bool `mapstructure:"is_demo"`
|
IsDemo bool `mapstructure:"is_demo"`
|
||||||
AppRepo string `mapstructure:"app_repo"`
|
AppRepo string `mapstructure:"app_repo"`
|
||||||
ChangeUserInfo string `mapstructure:"change_user_info"`
|
ChangeUserInfo string `mapstructure:"change_user_info"`
|
||||||
OneDriveID string `mapstructure:"one_drive_id"`
|
OneDriveID string `mapstructure:"one_drive_id"`
|
||||||
OneDriveSc string `mapstructure:"one_drive_sc"`
|
OneDriveSc string `mapstructure:"one_drive_sc"`
|
||||||
|
ApiInterfaceStatus string `mapstructure:"api_interface_status"`
|
||||||
|
ApiKey string `mapstructure:"api_key"`
|
||||||
|
IpWhiteList string `mapstructure:"ip_white_list"`
|
||||||
}
|
}
|
||||||
|
@ -37,18 +37,22 @@ var (
|
|||||||
|
|
||||||
// api
|
// api
|
||||||
var (
|
var (
|
||||||
ErrTypeInternalServer = "ErrInternalServer"
|
ErrTypeInternalServer = "ErrInternalServer"
|
||||||
ErrTypeInvalidParams = "ErrInvalidParams"
|
ErrTypeInvalidParams = "ErrInvalidParams"
|
||||||
ErrTypeNotLogin = "ErrNotLogin"
|
ErrTypeNotLogin = "ErrNotLogin"
|
||||||
ErrTypePasswordExpired = "ErrPasswordExpired"
|
ErrTypePasswordExpired = "ErrPasswordExpired"
|
||||||
ErrNameIsExist = "ErrNameIsExist"
|
ErrNameIsExist = "ErrNameIsExist"
|
||||||
ErrDemoEnvironment = "ErrDemoEnvironment"
|
ErrDemoEnvironment = "ErrDemoEnvironment"
|
||||||
ErrCmdIllegal = "ErrCmdIllegal"
|
ErrCmdIllegal = "ErrCmdIllegal"
|
||||||
ErrXpackNotFound = "ErrXpackNotFound"
|
ErrXpackNotFound = "ErrXpackNotFound"
|
||||||
ErrXpackNotActive = "ErrXpackNotActive"
|
ErrXpackNotActive = "ErrXpackNotActive"
|
||||||
ErrXpackLost = "ErrXpackLost"
|
ErrXpackLost = "ErrXpackLost"
|
||||||
ErrXpackTimeout = "ErrXpackTimeout"
|
ErrXpackTimeout = "ErrXpackTimeout"
|
||||||
ErrXpackOutOfDate = "ErrXpackOutOfDate"
|
ErrXpackOutOfDate = "ErrXpackOutOfDate"
|
||||||
|
ErrApiConfigStatusInvalid = "ErrApiConfigStatusInvalid"
|
||||||
|
ErrApiConfigKeyInvalid = "ErrApiConfigKeyInvalid"
|
||||||
|
ErrApiConfigIPInvalid = "ErrApiConfigIPInvalid"
|
||||||
|
ErrApiConfigDisable = "ErrApiConfigDisable"
|
||||||
)
|
)
|
||||||
|
|
||||||
// app
|
// app
|
||||||
|
@ -8,6 +8,10 @@ ErrStructTransform: "Type conversion failure: {{ .detail }}"
|
|||||||
ErrNotLogin: "User is not Login: {{ .detail }}"
|
ErrNotLogin: "User is not Login: {{ .detail }}"
|
||||||
ErrPasswordExpired: "The current password has expired: {{ .detail }}"
|
ErrPasswordExpired: "The current password has expired: {{ .detail }}"
|
||||||
ErrNotSupportType: "The system does not support the current type: {{ .detail }}"
|
ErrNotSupportType: "The system does not support the current type: {{ .detail }}"
|
||||||
|
ErrApiConfigStatusInvalid: "API Interface access prohibited: {{ .detail }}"
|
||||||
|
ErrApiConfigKeyInvalid: "API Interface key error: {{ .detail }}"
|
||||||
|
ErrApiConfigIPInvalid: "API Interface IP is not on the whitelist: {{ .detail }}"
|
||||||
|
ErrApiConfigDisable: "This interface prohibits the use of API Interface calls: {{ .detail }}"
|
||||||
|
|
||||||
#common
|
#common
|
||||||
ErrNameIsExist: "Name is already exist"
|
ErrNameIsExist: "Name is already exist"
|
||||||
|
@ -8,6 +8,10 @@ ErrStructTransform: "類型轉換失敗: {{ .detail }}"
|
|||||||
ErrNotLogin: "用戶未登入: {{ .detail }}"
|
ErrNotLogin: "用戶未登入: {{ .detail }}"
|
||||||
ErrPasswordExpired: "當前密碼已過期: {{ .detail }}"
|
ErrPasswordExpired: "當前密碼已過期: {{ .detail }}"
|
||||||
ErrNotSupportType: "系統暫不支持當前類型: {{ .detail }}"
|
ErrNotSupportType: "系統暫不支持當前類型: {{ .detail }}"
|
||||||
|
ErrApiConfigStatusInvalid: "API 接口禁止訪問: {{ .detail }}"
|
||||||
|
ErrApiConfigKeyInvalid: "API 接口密钥錯誤: {{ .detail }}"
|
||||||
|
ErrApiConfigIPInvalid: "调用 API 接口 IP 不在白名单: {{ .detail }}"
|
||||||
|
ErrApiConfigDisable: "此接口禁止使用 API 接口調用: {{ .detail }}"
|
||||||
|
|
||||||
#common
|
#common
|
||||||
ErrNameIsExist: "名稱已存在"
|
ErrNameIsExist: "名稱已存在"
|
||||||
|
@ -8,6 +8,10 @@ ErrStructTransform: "类型转换失败: {{ .detail }}"
|
|||||||
ErrNotLogin: "用户未登录: {{ .detail }}"
|
ErrNotLogin: "用户未登录: {{ .detail }}"
|
||||||
ErrPasswordExpired: "当前密码已过期: {{ .detail }}"
|
ErrPasswordExpired: "当前密码已过期: {{ .detail }}"
|
||||||
ErrNotSupportType: "系统暂不支持当前类型: {{ .detail }}"
|
ErrNotSupportType: "系统暂不支持当前类型: {{ .detail }}"
|
||||||
|
ErrApiConfigStatusInvalid: "API 接口禁止访问: {{ .detail }}"
|
||||||
|
ErrApiConfigKeyInvalid: "API 接口密钥错误: {{ .detail }}"
|
||||||
|
ErrApiConfigIPInvalid: "调用 API 接口 IP 不在白名单: {{ .detail }}"
|
||||||
|
ErrApiConfigDisable: "此接口禁止使用 API 接口调用: {{ .detail }}"
|
||||||
|
|
||||||
#common
|
#common
|
||||||
ErrNameIsExist: "名称已存在"
|
ErrNameIsExist: "名称已存在"
|
||||||
|
@ -61,6 +61,24 @@ func Init() {
|
|||||||
global.LOG.Fatalf("init service before start failed, err: %v", err)
|
global.LOG.Fatalf("init service before start failed, err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apiInterfaceStatusSetting, err := settingRepo.Get(settingRepo.WithByKey("ApiInterfaceStatus"))
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("load service api interface from setting failed, err: %v", err)
|
||||||
|
}
|
||||||
|
global.CONF.System.ApiInterfaceStatus = apiInterfaceStatusSetting.Value
|
||||||
|
if apiInterfaceStatusSetting.Value == "enable" {
|
||||||
|
apiKeySetting, err := settingRepo.Get(settingRepo.WithByKey("ApiKey"))
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("load service api key from setting failed, err: %v", err)
|
||||||
|
}
|
||||||
|
global.CONF.System.ApiKey = apiKeySetting.Value
|
||||||
|
ipWhiteListSetting, err := settingRepo.Get(settingRepo.WithByKey("IpWhiteList"))
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("load service ip white list from setting failed, err: %v", err)
|
||||||
|
}
|
||||||
|
global.CONF.System.IpWhiteList = ipWhiteListSetting.Value
|
||||||
|
}
|
||||||
|
|
||||||
handleUserInfo(global.CONF.System.ChangeUserInfo, settingRepo)
|
handleUserInfo(global.CONF.System.ChangeUserInfo, settingRepo)
|
||||||
|
|
||||||
handleCronjobStatus()
|
handleCronjobStatus()
|
||||||
|
@ -97,6 +97,7 @@ func Init() {
|
|||||||
migrations.AddComposeColumn,
|
migrations.AddComposeColumn,
|
||||||
|
|
||||||
migrations.AddAutoRestart,
|
migrations.AddAutoRestart,
|
||||||
|
migrations.AddApiInterfaceConfig,
|
||||||
})
|
})
|
||||||
if err := m.Migrate(); err != nil {
|
if err := m.Migrate(); err != nil {
|
||||||
global.LOG.Error(err)
|
global.LOG.Error(err)
|
||||||
|
@ -334,3 +334,19 @@ var AddAutoRestart = &gormigrate.Migration{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var AddApiInterfaceConfig = &gormigrate.Migration{
|
||||||
|
ID: "202411-add-api-interface-config",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
if err := tx.Create(&model.Setting{Key: "ApiInterfaceStatus", Value: "disable"}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := tx.Create(&model.Setting{Key: "ApiKey", Value: ""}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := tx.Create(&model.Setting{Key: "IpWhiteList", Value: ""}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
@ -16,6 +20,28 @@ func SessionAuth() gin.HandlerFunc {
|
|||||||
c.Next()
|
c.Next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
panelToken := c.GetHeader("1Panel-Token")
|
||||||
|
panelTimestamp := c.GetHeader("1Panel-Timestamp")
|
||||||
|
if panelToken != "" || panelTimestamp != "" {
|
||||||
|
if global.CONF.System.ApiInterfaceStatus == "enable" {
|
||||||
|
clientIP := c.ClientIP()
|
||||||
|
if !isValid1PanelToken(panelToken, panelTimestamp) {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrUnauthorized, constant.ErrApiConfigKeyInvalid, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isIPInWhiteList(clientIP) {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrUnauthorized, constant.ErrApiConfigIPInvalid, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrUnauthorized, constant.ErrApiConfigStatusInvalid, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sId, err := c.Cookie(constant.SessionName)
|
sId, err := c.Cookie(constant.SessionName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrUnauthorized, constant.ErrTypeNotLogin, nil)
|
helper.ErrorWithDetail(c, constant.CodeErrUnauthorized, constant.ErrTypeNotLogin, nil)
|
||||||
@ -36,3 +62,38 @@ func SessionAuth() gin.HandlerFunc {
|
|||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isValid1PanelToken(panelToken string, panelTimestamp string) bool {
|
||||||
|
system1PanelToken := global.CONF.System.ApiKey
|
||||||
|
if GenerateMD5("1panel"+panelToken+panelTimestamp) == GenerateMD5("1panel"+system1PanelToken+panelTimestamp) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isIPInWhiteList(clientIP string) bool {
|
||||||
|
ipWhiteString := global.CONF.System.IpWhiteList
|
||||||
|
ipWhiteList := strings.Split(ipWhiteString, "\n")
|
||||||
|
for _, cidr := range ipWhiteList {
|
||||||
|
if cidr == "0.0.0.0" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
_, ipNet, err := net.ParseCIDR(cidr)
|
||||||
|
if err != nil {
|
||||||
|
if cidr == clientIP {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ipNet.Contains(net.ParseIP(clientIP)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateMD5(input string) string {
|
||||||
|
hash := md5.New()
|
||||||
|
hash.Write([]byte(input))
|
||||||
|
return hex.EncodeToString(hash.Sum(nil))
|
||||||
|
}
|
||||||
|
@ -64,5 +64,7 @@ func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) {
|
|||||||
settingRouter.POST("/upgrade/notes", baseApi.GetNotesByVersion)
|
settingRouter.POST("/upgrade/notes", baseApi.GetNotesByVersion)
|
||||||
settingRouter.GET("/upgrade", baseApi.GetUpgradeInfo)
|
settingRouter.GET("/upgrade", baseApi.GetUpgradeInfo)
|
||||||
settingRouter.GET("/basedir", baseApi.LoadBaseDir)
|
settingRouter.GET("/basedir", baseApi.LoadBaseDir)
|
||||||
|
settingRouter.POST("/api/config/generate/key", baseApi.GenerateApiKey)
|
||||||
|
settingRouter.POST("/api/config/update", baseApi.UpdateApiConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -887,20 +887,6 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/auth/issafety": {
|
|
||||||
"get": {
|
|
||||||
"description": "获取系统安全登录状态",
|
|
||||||
"tags": [
|
|
||||||
"Auth"
|
|
||||||
],
|
|
||||||
"summary": "Load safety status",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/auth/language": {
|
"/auth/language": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "获取系统语言设置",
|
"description": "获取系统语言设置",
|
||||||
@ -9507,6 +9493,77 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/settings/api/config/generate/key": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "生成 API 接口密钥",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"System Setting"
|
||||||
|
],
|
||||||
|
"summary": "generate api key",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFunctions": [],
|
||||||
|
"bodyKeys": [],
|
||||||
|
"formatEN": "generate api key",
|
||||||
|
"formatZH": "生成 API 接口密钥",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/settings/api/config/update": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "更新 API 接口配置",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"System Setting"
|
||||||
|
],
|
||||||
|
"summary": "Update api config",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/dto.ApiInterfaceConfig"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFunctions": [],
|
||||||
|
"bodyKeys": [
|
||||||
|
"ipWhiteList"
|
||||||
|
],
|
||||||
|
"formatEN": "update api config =\u003e IP White List: [ipWhiteList]",
|
||||||
|
"formatZH": "更新 API 接口配置 =\u003e IP 白名单: [ipWhiteList]",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/settings/backup": {
|
"/settings/backup": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
@ -15310,6 +15367,20 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dto.ApiInterfaceConfig": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"apiInterfaceStatus": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"apiKey": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ipWhiteList": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dto.AppInstallInfo": {
|
"dto.AppInstallInfo": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -19629,6 +19700,12 @@ const docTemplate = `{
|
|||||||
"allowIPs": {
|
"allowIPs": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"apiInterfaceStatus": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"apiKey": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"appStoreLastModified": {
|
"appStoreLastModified": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -19677,6 +19754,9 @@ const docTemplate = `{
|
|||||||
"fileRecycleBin": {
|
"fileRecycleBin": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"ipWhiteList": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"ipv6": {
|
"ipv6": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -23635,15 +23715,29 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"securityDefinitions": {
|
||||||
|
"CustomToken": {
|
||||||
|
"description": "自定义 Token 格式,格式:md5('1panel' + 1Panel-Token + 1Panel-Timestamp)。\n` + "`" + `` + "`" + `` + "`" + `\n示例请求头:\ncurl -X GET \"http://localhost:4004/api/v1/resource\" \\\n-H \"1Panel-Token: \u003c1panel_token\u003e\" \\\n-H \"1Panel-Timestamp: \u003ccurrent_unix_timestamp\u003e\"\n` + "`" + `` + "`" + `` + "`" + `\n- ` + "`" + `1Panel-Token` + "`" + ` 为面板 API 接口密钥。",
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "1Panel-Token",
|
||||||
|
"in": "Header"
|
||||||
|
},
|
||||||
|
"Timestamp": {
|
||||||
|
"description": "- ` + "`" + `1Panel-Timestamp` + "`" + ` 为当前时间的 Unix 时间戳(单位:秒)。",
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "1Panel-Timestamp",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||||
var SwaggerInfo = &swag.Spec{
|
var SwaggerInfo = &swag.Spec{
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
Host: "localhost",
|
Host: "",
|
||||||
BasePath: "/api/v1",
|
BasePath: "/api/v1",
|
||||||
Schemes: []string{},
|
Schemes: []string{"http", "https"},
|
||||||
Title: "1Panel",
|
Title: "1Panel",
|
||||||
Description: "开源Linux面板",
|
Description: "开源Linux面板",
|
||||||
InfoInstanceName: "swagger",
|
InfoInstanceName: "swagger",
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
{
|
{
|
||||||
|
"schemes": [
|
||||||
|
"http",
|
||||||
|
"https"
|
||||||
|
],
|
||||||
"swagger": "2.0",
|
"swagger": "2.0",
|
||||||
"info": {
|
"info": {
|
||||||
"description": "开源Linux面板",
|
"description": "开源Linux面板",
|
||||||
@ -11,7 +15,6 @@
|
|||||||
},
|
},
|
||||||
"version": "1.0"
|
"version": "1.0"
|
||||||
},
|
},
|
||||||
"host": "localhost",
|
|
||||||
"basePath": "/api/v1",
|
"basePath": "/api/v1",
|
||||||
"paths": {
|
"paths": {
|
||||||
"/apps/:key": {
|
"/apps/:key": {
|
||||||
@ -881,20 +884,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/auth/issafety": {
|
|
||||||
"get": {
|
|
||||||
"description": "获取系统安全登录状态",
|
|
||||||
"tags": [
|
|
||||||
"Auth"
|
|
||||||
],
|
|
||||||
"summary": "Load safety status",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/auth/language": {
|
"/auth/language": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "获取系统语言设置",
|
"description": "获取系统语言设置",
|
||||||
@ -9501,6 +9490,77 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/settings/api/config/generate/key": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "生成 API 接口密钥",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"System Setting"
|
||||||
|
],
|
||||||
|
"summary": "generate api key",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFunctions": [],
|
||||||
|
"bodyKeys": [],
|
||||||
|
"formatEN": "generate api key",
|
||||||
|
"formatZH": "生成 API 接口密钥",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/settings/api/config/update": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "更新 API 接口配置",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"System Setting"
|
||||||
|
],
|
||||||
|
"summary": "Update api config",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/dto.ApiInterfaceConfig"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFunctions": [],
|
||||||
|
"bodyKeys": [
|
||||||
|
"ipWhiteList"
|
||||||
|
],
|
||||||
|
"formatEN": "update api config =\u003e IP White List: [ipWhiteList]",
|
||||||
|
"formatZH": "更新 API 接口配置 =\u003e IP 白名单: [ipWhiteList]",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/settings/backup": {
|
"/settings/backup": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
@ -15304,6 +15364,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dto.ApiInterfaceConfig": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"apiInterfaceStatus": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"apiKey": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ipWhiteList": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dto.AppInstallInfo": {
|
"dto.AppInstallInfo": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -19623,6 +19697,12 @@
|
|||||||
"allowIPs": {
|
"allowIPs": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"apiInterfaceStatus": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"apiKey": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"appStoreLastModified": {
|
"appStoreLastModified": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -19671,6 +19751,9 @@
|
|||||||
"fileRecycleBin": {
|
"fileRecycleBin": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"ipWhiteList": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"ipv6": {
|
"ipv6": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -23629,5 +23712,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"securityDefinitions": {
|
||||||
|
"CustomToken": {
|
||||||
|
"description": "自定义 Token 格式,格式:md5('1panel' + 1Panel-Token + 1Panel-Timestamp)。\n```\n示例请求头:\ncurl -X GET \"http://localhost:4004/api/v1/resource\" \\\n-H \"1Panel-Token: \u003c1panel_token\u003e\" \\\n-H \"1Panel-Timestamp: \u003ccurrent_unix_timestamp\u003e\"\n```\n- `1Panel-Token` 为面板 API 接口密钥。",
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "1Panel-Token",
|
||||||
|
"in": "Header"
|
||||||
|
},
|
||||||
|
"Timestamp": {
|
||||||
|
"description": "- `1Panel-Timestamp` 为当前时间的 Unix 时间戳(单位:秒)。",
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "1Panel-Timestamp",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -28,6 +28,15 @@ definitions:
|
|||||||
oldRule:
|
oldRule:
|
||||||
$ref: '#/definitions/dto.AddrRuleOperate'
|
$ref: '#/definitions/dto.AddrRuleOperate'
|
||||||
type: object
|
type: object
|
||||||
|
dto.ApiInterfaceConfig:
|
||||||
|
properties:
|
||||||
|
apiInterfaceStatus:
|
||||||
|
type: string
|
||||||
|
apiKey:
|
||||||
|
type: string
|
||||||
|
ipWhiteList:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
dto.AppInstallInfo:
|
dto.AppInstallInfo:
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
@ -2951,6 +2960,10 @@ definitions:
|
|||||||
properties:
|
properties:
|
||||||
allowIPs:
|
allowIPs:
|
||||||
type: string
|
type: string
|
||||||
|
apiInterfaceStatus:
|
||||||
|
type: string
|
||||||
|
apiKey:
|
||||||
|
type: string
|
||||||
appStoreLastModified:
|
appStoreLastModified:
|
||||||
type: string
|
type: string
|
||||||
appStoreSyncStatus:
|
appStoreSyncStatus:
|
||||||
@ -2983,6 +2996,8 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
fileRecycleBin:
|
fileRecycleBin:
|
||||||
type: string
|
type: string
|
||||||
|
ipWhiteList:
|
||||||
|
type: string
|
||||||
ipv6:
|
ipv6:
|
||||||
type: string
|
type: string
|
||||||
language:
|
language:
|
||||||
@ -5624,7 +5639,6 @@ definitions:
|
|||||||
version:
|
version:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
host: localhost
|
|
||||||
info:
|
info:
|
||||||
contact: {}
|
contact: {}
|
||||||
description: 开源Linux面板
|
description: 开源Linux面板
|
||||||
@ -6181,15 +6195,6 @@ paths:
|
|||||||
summary: Check System isDemo
|
summary: Check System isDemo
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- Auth
|
||||||
/auth/issafety:
|
|
||||||
get:
|
|
||||||
description: 获取系统安全登录状态
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
summary: Load safety status
|
|
||||||
tags:
|
|
||||||
- Auth
|
|
||||||
/auth/language:
|
/auth/language:
|
||||||
get:
|
get:
|
||||||
description: 获取系统语言设置
|
description: 获取系统语言设置
|
||||||
@ -11638,6 +11643,52 @@ paths:
|
|||||||
formatEN: Update runtime [name]
|
formatEN: Update runtime [name]
|
||||||
formatZH: 更新运行环境 [name]
|
formatZH: 更新运行环境 [name]
|
||||||
paramKeys: []
|
paramKeys: []
|
||||||
|
/settings/api/config/generate/key:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 生成 API 接口密钥
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: generate api key
|
||||||
|
tags:
|
||||||
|
- System Setting
|
||||||
|
x-panel-log:
|
||||||
|
BeforeFunctions: []
|
||||||
|
bodyKeys: []
|
||||||
|
formatEN: generate api key
|
||||||
|
formatZH: 生成 API 接口密钥
|
||||||
|
paramKeys: []
|
||||||
|
/settings/api/config/update:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 更新 API 接口配置
|
||||||
|
parameters:
|
||||||
|
- description: request
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/dto.ApiInterfaceConfig'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: Update api config
|
||||||
|
tags:
|
||||||
|
- System Setting
|
||||||
|
x-panel-log:
|
||||||
|
BeforeFunctions: []
|
||||||
|
bodyKeys:
|
||||||
|
- ipWhiteList
|
||||||
|
formatEN: 'update api config => IP White List: [ipWhiteList]'
|
||||||
|
formatZH: '更新 API 接口配置 => IP 白名单: [ipWhiteList]'
|
||||||
|
paramKeys: []
|
||||||
/settings/backup:
|
/settings/backup:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
@ -15292,4 +15343,26 @@ paths:
|
|||||||
formatEN: Update website [primaryDomain]
|
formatEN: Update website [primaryDomain]
|
||||||
formatZH: 更新网站 [primaryDomain]
|
formatZH: 更新网站 [primaryDomain]
|
||||||
paramKeys: []
|
paramKeys: []
|
||||||
|
schemes:
|
||||||
|
- http
|
||||||
|
- https
|
||||||
|
securityDefinitions:
|
||||||
|
CustomToken:
|
||||||
|
description: |-
|
||||||
|
自定义 Token 格式,格式:md5('1panel' + 1Panel-Token + 1Panel-Timestamp)。
|
||||||
|
```
|
||||||
|
示例请求头:
|
||||||
|
curl -X GET "http://localhost:4004/api/v1/resource" \
|
||||||
|
-H "1Panel-Token: <1panel_token>" \
|
||||||
|
-H "1Panel-Timestamp: <current_unix_timestamp>"
|
||||||
|
```
|
||||||
|
- `1Panel-Token` 为面板 API 接口密钥。
|
||||||
|
in: Header
|
||||||
|
name: 1Panel-Token
|
||||||
|
type: apiKey
|
||||||
|
Timestamp:
|
||||||
|
description: '- `1Panel-Timestamp` 为当前时间的 Unix 时间戳(单位:秒)。'
|
||||||
|
in: header
|
||||||
|
name: 1Panel-Timestamp
|
||||||
|
type: apiKey
|
||||||
swagger: "2.0"
|
swagger: "2.0"
|
||||||
|
@ -15,8 +15,26 @@ import (
|
|||||||
// @termsOfService http://swagger.io/terms/
|
// @termsOfService http://swagger.io/terms/
|
||||||
// @license.name Apache 2.0
|
// @license.name Apache 2.0
|
||||||
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
// @host localhost
|
|
||||||
// @BasePath /api/v1
|
// @BasePath /api/v1
|
||||||
|
// @schemes http https
|
||||||
|
|
||||||
|
// @securityDefinitions.apikey CustomToken
|
||||||
|
// @description 自定义 Token 格式,格式:md5('1panel' + 1Panel-Token + 1Panel-Timestamp)。
|
||||||
|
// @description ```
|
||||||
|
// @description 示例请求头:
|
||||||
|
// @description curl -X GET "http://localhost:4004/api/v1/resource" \
|
||||||
|
// @description -H "1Panel-Token: <1panel_token>" \
|
||||||
|
// @description -H "1Panel-Timestamp: <current_unix_timestamp>"
|
||||||
|
// @description ```
|
||||||
|
// @description - `1Panel-Token` 为面板 API 接口密钥。
|
||||||
|
// @type apiKey
|
||||||
|
// @in Header
|
||||||
|
// @name 1Panel-Token
|
||||||
|
// @securityDefinitions.apikey Timestamp
|
||||||
|
// @type apiKey
|
||||||
|
// @in header
|
||||||
|
// @name 1Panel-Timestamp
|
||||||
|
// @description - `1Panel-Timestamp` 为当前时间的 Unix 时间戳(单位:秒)。
|
||||||
|
|
||||||
//go:generate swag init -o ./docs -g main.go -d ../../backend -g ../cmd/server/main.go
|
//go:generate swag init -o ./docs -g main.go -d ../../backend -g ../cmd/server/main.go
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -58,6 +58,10 @@ export namespace Setting {
|
|||||||
proxyUser: string;
|
proxyUser: string;
|
||||||
proxyPasswd: string;
|
proxyPasswd: string;
|
||||||
proxyPasswdKeep: string;
|
proxyPasswdKeep: string;
|
||||||
|
|
||||||
|
apiInterfaceStatus: string;
|
||||||
|
apiKey: string;
|
||||||
|
ipWhiteList: string;
|
||||||
}
|
}
|
||||||
export interface SettingUpdate {
|
export interface SettingUpdate {
|
||||||
key: string;
|
key: string;
|
||||||
@ -186,4 +190,9 @@ export namespace Setting {
|
|||||||
trial: boolean;
|
trial: boolean;
|
||||||
status: string;
|
status: string;
|
||||||
}
|
}
|
||||||
|
export interface ApiConfig {
|
||||||
|
apiInterfaceStatus: string;
|
||||||
|
apiKey: string;
|
||||||
|
ipWhiteList: string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,3 +210,11 @@ export const loadReleaseNotes = (version: string) => {
|
|||||||
export const upgrade = (version: string) => {
|
export const upgrade = (version: string) => {
|
||||||
return http.post(`/settings/upgrade`, { version: version });
|
return http.post(`/settings/upgrade`, { version: version });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// api config
|
||||||
|
export const generateApiKey = () => {
|
||||||
|
return http.post<string>(`/settings/api/config/generate/key`);
|
||||||
|
};
|
||||||
|
export const updateApiConfig = (param: Setting.ApiConfig) => {
|
||||||
|
return http.post(`/settings/api/config/update`, param);
|
||||||
|
};
|
||||||
|
@ -1401,11 +1401,28 @@ const message = {
|
|||||||
proxyPort: 'Proxy Port',
|
proxyPort: 'Proxy Port',
|
||||||
proxyPasswdKeep: 'Remember Password',
|
proxyPasswdKeep: 'Remember Password',
|
||||||
proxyDocker: 'Docker Proxy',
|
proxyDocker: 'Docker Proxy',
|
||||||
ProxyDockerHelper:
|
proxyDockerHelper:
|
||||||
'Synchronize proxy server configuration to Docker, support offline server image pulling and other operations',
|
'Synchronize proxy server configuration to Docker, support offline server image pulling and other operations',
|
||||||
ConfDockerProxy: 'Configure Docker Proxy',
|
apiInterface: 'API Interface',
|
||||||
RestartNowHelper: 'Configuring Docker proxy requires restarting the Docker service.',
|
apiInterfaceClose: 'Once closed, API interfaces cannot be accessed. Do you want to continue?',
|
||||||
RestartNow: 'Restart immediately',
|
apiInterfaceHelper: 'Provide panel support for API interface access',
|
||||||
|
apiInterfaceAlert1:
|
||||||
|
'Please do not enable it in production environments as it may increase server security risks',
|
||||||
|
apiInterfaceAlert2:
|
||||||
|
'Please do not use third-party applications to call the panel API to prevent potential security threats.',
|
||||||
|
apiInterfaceAlert3: 'API Interface Document:',
|
||||||
|
apiInterfaceAlert4: 'Usage Document:',
|
||||||
|
apiKey: 'Interface Key',
|
||||||
|
apiKeyHelper: 'Interface key is used for external applications to access API interfaces',
|
||||||
|
ipWhiteList: 'IP Whitelist',
|
||||||
|
ipWhiteListEgs:
|
||||||
|
'When there are multiple IPs, line breaks are required for display, for example: \n172.161.10.111 \n172.161.10.0/24 ',
|
||||||
|
ipWhiteListHelper: 'IPs must be in the IP whitelist list to access the panel API interface',
|
||||||
|
apiKeyReset: 'Interface key reset',
|
||||||
|
apiKeyResetHelper: 'the associated key service will become invalid. Please add a new key to the service',
|
||||||
|
confDockerProxy: 'Configure Docker Proxy',
|
||||||
|
restartNowHelper: 'Configuring Docker proxy requires restarting the Docker service.',
|
||||||
|
restartNow: 'Restart immediately',
|
||||||
systemIPWarning: 'The server address is not currently set. Please set it in the control panel first!',
|
systemIPWarning: 'The server address is not currently set. Please set it in the control panel first!',
|
||||||
systemIPWarning1: 'The current server address is set to {0}, and quick redirection is not possible!',
|
systemIPWarning1: 'The current server address is set to {0}, and quick redirection is not possible!',
|
||||||
defaultNetwork: 'Network Card',
|
defaultNetwork: 'Network Card',
|
||||||
|
@ -1323,9 +1323,23 @@ const message = {
|
|||||||
proxyPort: '代理端口',
|
proxyPort: '代理端口',
|
||||||
proxyPasswdKeep: '記住密碼',
|
proxyPasswdKeep: '記住密碼',
|
||||||
proxyDocker: 'Docker 代理',
|
proxyDocker: 'Docker 代理',
|
||||||
proxyDockerHelper: '將代理伺服器配寘同步至Docker,支持離線服務器拉取鏡像等操作',
|
proxyDockerHelper: '將代理伺服器配寘同步至 Docker,支持離線服務器拉取鏡像等操作',
|
||||||
confDockerProxy: '配寘Docker代理',
|
apiInterface: 'API 接口',
|
||||||
restartNowHelper: '配寘Docker代理需要重啓Docker服務。',
|
apiInterfaceClose: '關閉後將不能使用 API 接口進行訪問,是否繼續?',
|
||||||
|
apiInterfaceHelper: '提供面板支持 API 接口訪問',
|
||||||
|
apiInterfaceAlert1: '請不要在生產環境開啟,這可能新增服務器安全風險',
|
||||||
|
apiInterfaceAlert2: '請不要使用協力廠商應用調用面板 API,以防止潜在的安全威脅。',
|
||||||
|
apiInterfaceAlert3: 'API 接口檔案:',
|
||||||
|
apiInterfaceAlert4: '使用檔案:',
|
||||||
|
apiKey: '接口密钥',
|
||||||
|
apiKeyHelper: '接口密钥用於外部應用訪問 API 接口',
|
||||||
|
ipWhiteList: 'IP白名單',
|
||||||
|
ipWhiteListEgs: '當存在多個 IP 時,需要換行顯示,例:\n172.16.10.111 \n172.16.10.0/24',
|
||||||
|
ipWhiteListHelper: '必需在 IP 白名單清單中的 IP 才能訪問面板 API 接口',
|
||||||
|
apiKeyReset: '接口密钥重置',
|
||||||
|
apiKeyResetHelper: '重置密钥後,已關聯密钥服務將失效,請重新添加新密鑰至服務。',
|
||||||
|
confDockerProxy: '配寘 Docker 代理',
|
||||||
|
restartNowHelper: '配寘 Docker 代理需要重啓 Docker 服務。',
|
||||||
restartNow: '立即重啓',
|
restartNow: '立即重啓',
|
||||||
systemIPWarning: '當前未設置服務器地址,請先在面板設置中設置!',
|
systemIPWarning: '當前未設置服務器地址,請先在面板設置中設置!',
|
||||||
systemIPWarning1: '當前服務器地址設置為 {0},無法快速跳轉!',
|
systemIPWarning1: '當前服務器地址設置為 {0},無法快速跳轉!',
|
||||||
@ -2095,7 +2109,7 @@ const message = {
|
|||||||
domainHelper: '一行一個網域名稱,支援*和IP位址',
|
domainHelper: '一行一個網域名稱,支援*和IP位址',
|
||||||
pushDir: '推送憑證到本機目錄',
|
pushDir: '推送憑證到本機目錄',
|
||||||
dir: '目錄',
|
dir: '目錄',
|
||||||
pushDirHelper: '會在此目錄下產生兩個文件,憑證檔案:fullchain.pem 金鑰檔案:privkey.pem',
|
pushDirHelper: '會在此目錄下產生兩個文件,憑證檔案:fullchain.pem 密钥檔案:privkey.pem',
|
||||||
organizationDetail: '機構詳情',
|
organizationDetail: '機構詳情',
|
||||||
fromWebsite: '從網站獲取',
|
fromWebsite: '從網站獲取',
|
||||||
dnsMauanlHelper: '手動解析模式需要在建立完之後點選申請按鈕取得 DNS 解析值',
|
dnsMauanlHelper: '手動解析模式需要在建立完之後點選申請按鈕取得 DNS 解析值',
|
||||||
|
@ -1326,6 +1326,20 @@ const message = {
|
|||||||
proxyPasswdKeep: '记住密码',
|
proxyPasswdKeep: '记住密码',
|
||||||
proxyDocker: 'Docker 代理',
|
proxyDocker: 'Docker 代理',
|
||||||
proxyDockerHelper: '将代理服务器配置同步至 Docker,支持离线服务器拉取镜像等操作',
|
proxyDockerHelper: '将代理服务器配置同步至 Docker,支持离线服务器拉取镜像等操作',
|
||||||
|
apiInterface: 'API 接口',
|
||||||
|
apiInterfaceClose: '关闭后将不能使用 API 接口进行访问,是否继续?',
|
||||||
|
apiInterfaceHelper: '提供面板支持 API 接口访问',
|
||||||
|
apiInterfaceAlert1: '请不要在生产环境开启,这可能增加服务器安全风险',
|
||||||
|
apiInterfaceAlert2: '请不要使用第三方应用调用面板 API,以防止潜在的安全威胁。',
|
||||||
|
apiInterfaceAlert3: 'API 接口文档:',
|
||||||
|
apiInterfaceAlert4: '使用文档:',
|
||||||
|
apiKey: '接口密钥',
|
||||||
|
apiKeyHelper: '接口密钥用于外部应用访问 API 接口',
|
||||||
|
ipWhiteList: 'IP 白名单',
|
||||||
|
ipWhiteListEgs: '当存在多个 IP 时,需要换行显示,例: \n172.16.10.111 \n172.16.10.0/24',
|
||||||
|
ipWhiteListHelper: '必需在 IP 白名单列表中的 IP 才能访问面板 API 接口',
|
||||||
|
apiKeyReset: '接口密钥重置',
|
||||||
|
apiKeyResetHelper: '重置密钥后,已关联密钥服务将失效,请重新添加新密钥至服务。',
|
||||||
confDockerProxy: '配置 Docker 代理',
|
confDockerProxy: '配置 Docker 代理',
|
||||||
restartNowHelper: '配置 Docker 代理需要重启 Docker 服务。',
|
restartNowHelper: '配置 Docker 代理需要重启 Docker 服务。',
|
||||||
restartNow: '立即重启',
|
restartNow: '立即重启',
|
||||||
|
@ -88,7 +88,7 @@ html.dark {
|
|||||||
--panel-border-color: var(--panel-main-bg-color-8);
|
--panel-border-color: var(--panel-main-bg-color-8);
|
||||||
--panel-button-active: var(--panel-main-bg-color-10);
|
--panel-button-active: var(--panel-main-bg-color-10);
|
||||||
--panel-button-text-color: var(--panel-main-bg-color-10);
|
--panel-button-text-color: var(--panel-main-bg-color-10);
|
||||||
--panel-button-bg-color: var(--panel-color-primary);
|
--panel-button-bg-color: var(--panel-color-primary);
|
||||||
--panel-footer-bg: var(--panel-main-bg-color-9);
|
--panel-footer-bg: var(--panel-main-bg-color-9);
|
||||||
--panel-footer-border: var(--panel-main-bg-color-7);
|
--panel-footer-border: var(--panel-main-bg-color-7);
|
||||||
--panel-text-color: var(--panel-main-bg-color-1);
|
--panel-text-color: var(--panel-main-bg-color-1);
|
||||||
@ -96,6 +96,7 @@ html.dark {
|
|||||||
--panel-terminal-tag-bg-color: var(--panel-main-bg-color-10);
|
--panel-terminal-tag-bg-color: var(--panel-main-bg-color-10);
|
||||||
--panel-terminal-tag-active-bg-color: var(--panel-main-bg-color-10);
|
--panel-terminal-tag-active-bg-color: var(--panel-main-bg-color-10);
|
||||||
--panel-terminal-bg-color: var(--panel-main-bg-color-10);
|
--panel-terminal-bg-color: var(--panel-main-bg-color-10);
|
||||||
|
--panel-terminal-tag-active-text-color: var(--panel-color-primary);
|
||||||
--panel-logs-bg-color: var(--panel-main-bg-color-9);
|
--panel-logs-bg-color: var(--panel-main-bg-color-9);
|
||||||
|
|
||||||
--el-menu-item-bg-color: var(--panel-main-bg-color-10);
|
--el-menu-item-bg-color: var(--panel-main-bg-color-10);
|
||||||
|
@ -45,6 +45,7 @@ html {
|
|||||||
--panel-footer-border: #e4e7ed;
|
--panel-footer-border: #e4e7ed;
|
||||||
--panel-terminal-tag-bg-color: #efefef;
|
--panel-terminal-tag-bg-color: #efefef;
|
||||||
--panel-terminal-tag-active-bg-color: #575758;
|
--panel-terminal-tag-active-bg-color: #575758;
|
||||||
|
--panel-terminal-tag-active-text-color: #ebeef5;
|
||||||
--panel-terminal-bg-color: #1e1e1e;
|
--panel-terminal-bg-color: #1e1e1e;
|
||||||
--panel-logs-bg-color: #1e1e1e;
|
--panel-logs-bg-color: #1e1e1e;
|
||||||
|
|
||||||
|
@ -160,3 +160,8 @@ defineExpose({
|
|||||||
acceptParams,
|
acceptParams,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
:deep(.log-container) {
|
||||||
|
background-color: var(--panel-main-bg-color-10);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -433,6 +433,7 @@ onMounted(() => {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
:deep(.el-tabs__item.is-active) {
|
:deep(.el-tabs__item.is-active) {
|
||||||
|
color: var(--panel-terminal-tag-active-text-color);
|
||||||
background-color: var(--panel-terminal-tag-active-bg-color);
|
background-color: var(--panel-terminal-tag-active-bg-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,6 +228,9 @@ const loadDetail = (log: string) => {
|
|||||||
if (log.indexOf('[MonitorStoreDays]') !== -1) {
|
if (log.indexOf('[MonitorStoreDays]') !== -1) {
|
||||||
return log.replace('[MonitorStoreDays]', '[' + i18n.global.t('setting.monitor') + ']');
|
return log.replace('[MonitorStoreDays]', '[' + i18n.global.t('setting.monitor') + ']');
|
||||||
}
|
}
|
||||||
|
if (log.indexOf('[ApiInterfaceStatus]') !== -1) {
|
||||||
|
return log.replace('[ApiInterfaceStatus]', '[' + i18n.global.t('setting.apiInterface') + ']');
|
||||||
|
}
|
||||||
return log;
|
return log;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
183
frontend/src/views/setting/panel/api-interface/index.vue
Normal file
183
frontend/src/views/setting/panel/api-interface/index.vue
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-drawer
|
||||||
|
v-model="drawerVisible"
|
||||||
|
:destroy-on-close="true"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
@close="handleClose"
|
||||||
|
size="35%"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<DrawerHeader :header="$t('setting.apiInterface')" :back="handleClose" />
|
||||||
|
</template>
|
||||||
|
<el-alert class="common-prompt" :closable="false" type="warning">
|
||||||
|
<template #default>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<el-text type="danger">{{ $t('setting.apiInterfaceAlert1') }}</el-text>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<el-text type="danger">{{ $t('setting.apiInterfaceAlert2') }}</el-text>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ $t('setting.apiInterfaceAlert3') }}
|
||||||
|
<el-link :href="apiURL" type="success" target="_blank" class="mb-0.5 ml-0.5">
|
||||||
|
{{ apiURL }}
|
||||||
|
</el-link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ $t('setting.apiInterfaceAlert4') }}
|
||||||
|
<el-link :href="panelURL" type="success" target="_blank" class="mb-0.5 ml-0.5">
|
||||||
|
{{ panelURL }}
|
||||||
|
</el-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
</el-alert>
|
||||||
|
<el-form
|
||||||
|
:model="form"
|
||||||
|
ref="formRef"
|
||||||
|
@submit.prevent
|
||||||
|
v-loading="loading"
|
||||||
|
label-position="top"
|
||||||
|
:rules="rules"
|
||||||
|
>
|
||||||
|
<el-row type="flex" justify="center">
|
||||||
|
<el-col :span="22">
|
||||||
|
<el-form-item :label="$t('setting.apiKey')" prop="apiKey">
|
||||||
|
<el-input v-model="form.apiKey" readonly>
|
||||||
|
<template #suffix>
|
||||||
|
<CopyButton type="icon" :content="form.apiKey" class="w-30" />
|
||||||
|
</template>
|
||||||
|
<template #append>
|
||||||
|
<el-button @click="resetApiKey()">
|
||||||
|
{{ $t('commons.button.reset') }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<span class="input-help">{{ $t('setting.apiKeyHelper') }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('setting.ipWhiteList')" prop="ipWhiteList">
|
||||||
|
<el-input
|
||||||
|
type="textarea"
|
||||||
|
:placeholder="$t('setting.ipWhiteListEgs')"
|
||||||
|
:rows="4"
|
||||||
|
v-model="form.ipWhiteList"
|
||||||
|
/>
|
||||||
|
<span class="input-help">{{ $t('setting.ipWhiteListHelper') }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="handleClose">{{ $t('commons.button.cancel') }}</el-button>
|
||||||
|
<el-button :disabled="loading" type="primary" @click="onBind(formRef)">
|
||||||
|
{{ $t('commons.button.confirm') }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-drawer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { generateApiKey, updateApiConfig } from '@/api/modules/setting';
|
||||||
|
import { reactive, ref } from 'vue';
|
||||||
|
import { Rules } from '@/global/form-rules';
|
||||||
|
import i18n from '@/lang';
|
||||||
|
import { MsgSuccess } from '@/utils/message';
|
||||||
|
import { ElMessageBox, FormInstance } from 'element-plus';
|
||||||
|
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||||
|
|
||||||
|
const loading = ref();
|
||||||
|
const drawerVisible = ref();
|
||||||
|
const formRef = ref();
|
||||||
|
const apiURL = `${window.location.protocol}//${window.location.hostname}${
|
||||||
|
window.location.port ? `:${window.location.port}` : ''
|
||||||
|
}/1panel/swagger/index.html`;
|
||||||
|
const panelURL = `https://1panel.cn/docs`;
|
||||||
|
|
||||||
|
const form = reactive({
|
||||||
|
apiKey: '',
|
||||||
|
ipWhiteList: '',
|
||||||
|
apiInterfaceStatus: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules = reactive({
|
||||||
|
ipWhiteList: [Rules.requiredInput],
|
||||||
|
apiKey: [Rules.requiredInput],
|
||||||
|
});
|
||||||
|
|
||||||
|
interface DialogProps {
|
||||||
|
apiInterfaceStatus: string;
|
||||||
|
apiKey: string;
|
||||||
|
ipWhiteList: string;
|
||||||
|
}
|
||||||
|
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||||
|
const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||||
|
form.apiInterfaceStatus = params.apiInterfaceStatus;
|
||||||
|
form.apiKey = params.apiKey;
|
||||||
|
if (params.apiKey == '') {
|
||||||
|
await generateApiKey().then((res) => {
|
||||||
|
form.apiKey = res.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
form.ipWhiteList = params.ipWhiteList;
|
||||||
|
drawerVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetApiKey = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
ElMessageBox.confirm(i18n.global.t('setting.apiKeyResetHelper'), i18n.global.t('setting.apiKeyReset'), {
|
||||||
|
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||||
|
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||||
|
})
|
||||||
|
.then(async () => {
|
||||||
|
await generateApiKey()
|
||||||
|
.then((res) => {
|
||||||
|
loading.value = false;
|
||||||
|
form.apiKey = res.data;
|
||||||
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onBind = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.validate(async (valid) => {
|
||||||
|
if (!valid) return;
|
||||||
|
let param = {
|
||||||
|
apiKey: form.apiKey,
|
||||||
|
ipWhiteList: form.ipWhiteList,
|
||||||
|
apiInterfaceStatus: form.apiInterfaceStatus,
|
||||||
|
};
|
||||||
|
loading.value = true;
|
||||||
|
await updateApiConfig(param)
|
||||||
|
.then(() => {
|
||||||
|
loading.value = false;
|
||||||
|
drawerVisible.value = false;
|
||||||
|
emit('search');
|
||||||
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
emit('search');
|
||||||
|
drawerVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
acceptParams,
|
||||||
|
});
|
||||||
|
</script>
|
@ -133,6 +133,16 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="$t('setting.apiInterface')" prop="apiInterface">
|
||||||
|
<el-switch
|
||||||
|
@change="onChangeApiInterfaceStatus"
|
||||||
|
v-model="form.apiInterfaceStatus"
|
||||||
|
active-value="enable"
|
||||||
|
inactive-value="disable"
|
||||||
|
/>
|
||||||
|
<span class="input-help">{{ $t('setting.apiInterfaceHelper') }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="$t('setting.developerMode')" prop="developerMode">
|
<el-form-item :label="$t('setting.developerMode')" prop="developerMode">
|
||||||
<el-radio-group
|
<el-radio-group
|
||||||
@change="onSave('DeveloperMode', form.developerMode)"
|
@change="onSave('DeveloperMode', form.developerMode)"
|
||||||
@ -168,6 +178,7 @@
|
|||||||
<PanelName ref="panelNameRef" @search="search()" />
|
<PanelName ref="panelNameRef" @search="search()" />
|
||||||
<SystemIP ref="systemIPRef" @search="search()" />
|
<SystemIP ref="systemIPRef" @search="search()" />
|
||||||
<Proxy ref="proxyRef" @search="search()" />
|
<Proxy ref="proxyRef" @search="search()" />
|
||||||
|
<ApiInterface ref="apiInterfaceRef" @search="search()" />
|
||||||
<Timeout ref="timeoutRef" @search="search()" />
|
<Timeout ref="timeoutRef" @search="search()" />
|
||||||
<Network ref="networkRef" @search="search()" />
|
<Network ref="networkRef" @search="search()" />
|
||||||
<HideMenu ref="hideMenuRef" @search="search()" />
|
<HideMenu ref="hideMenuRef" @search="search()" />
|
||||||
@ -177,7 +188,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive, onMounted, computed } from 'vue';
|
import { ref, reactive, onMounted, computed } from 'vue';
|
||||||
import { ElForm } from 'element-plus';
|
import { ElForm, ElMessageBox } from 'element-plus';
|
||||||
import { getSettingInfo, updateSetting, getSystemAvailable } from '@/api/modules/setting';
|
import { getSettingInfo, updateSetting, getSystemAvailable } from '@/api/modules/setting';
|
||||||
import { GlobalStore } from '@/store';
|
import { GlobalStore } from '@/store';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
@ -192,6 +203,7 @@ import Proxy from '@/views/setting/panel/proxy/index.vue';
|
|||||||
import Network from '@/views/setting/panel/default-network/index.vue';
|
import Network from '@/views/setting/panel/default-network/index.vue';
|
||||||
import HideMenu from '@/views/setting/panel/hidemenu/index.vue';
|
import HideMenu from '@/views/setting/panel/hidemenu/index.vue';
|
||||||
import ThemeColor from '@/views/setting/panel/theme-color/index.vue';
|
import ThemeColor from '@/views/setting/panel/theme-color/index.vue';
|
||||||
|
import ApiInterface from '@/views/setting/panel/api-interface/index.vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { getXpackSetting, updateXpackSettingByKey } from '@/utils/xpack';
|
import { getXpackSetting, updateXpackSettingByKey } from '@/utils/xpack';
|
||||||
import { setPrimaryColor } from '@/utils/theme';
|
import { setPrimaryColor } from '@/utils/theme';
|
||||||
@ -241,6 +253,10 @@ const form = reactive({
|
|||||||
proxyPasswdKeep: '',
|
proxyPasswdKeep: '',
|
||||||
proxyDocker: '',
|
proxyDocker: '',
|
||||||
|
|
||||||
|
apiInterfaceStatus: 'disable',
|
||||||
|
apiKey: '',
|
||||||
|
ipWhiteList: '',
|
||||||
|
|
||||||
proHideMenus: ref(i18n.t('setting.unSetting')),
|
proHideMenus: ref(i18n.t('setting.unSetting')),
|
||||||
hideMenuList: '',
|
hideMenuList: '',
|
||||||
});
|
});
|
||||||
@ -256,6 +272,7 @@ const timeoutRef = ref();
|
|||||||
const networkRef = ref();
|
const networkRef = ref();
|
||||||
const hideMenuRef = ref();
|
const hideMenuRef = ref();
|
||||||
const themeColorRef = ref();
|
const themeColorRef = ref();
|
||||||
|
const apiInterfaceRef = ref();
|
||||||
const unset = ref(i18n.t('setting.unSetting'));
|
const unset = ref(i18n.t('setting.unSetting'));
|
||||||
|
|
||||||
interface Node {
|
interface Node {
|
||||||
@ -293,6 +310,9 @@ const search = async () => {
|
|||||||
form.proxyUser = res.data.proxyUser;
|
form.proxyUser = res.data.proxyUser;
|
||||||
form.proxyPasswd = res.data.proxyPasswd;
|
form.proxyPasswd = res.data.proxyPasswd;
|
||||||
form.proxyPasswdKeep = res.data.proxyPasswdKeep;
|
form.proxyPasswdKeep = res.data.proxyPasswdKeep;
|
||||||
|
form.apiInterfaceStatus = res.data.apiInterfaceStatus;
|
||||||
|
form.apiKey = res.data.apiKey;
|
||||||
|
form.ipWhiteList = res.data.ipWhiteList;
|
||||||
|
|
||||||
const json: Node = JSON.parse(res.data.xpackHideMenu);
|
const json: Node = JSON.parse(res.data.xpackHideMenu);
|
||||||
const checkedTitles = getCheckedTitles(json);
|
const checkedTitles = getCheckedTitles(json);
|
||||||
@ -361,6 +381,41 @@ const onChangeProxy = () => {
|
|||||||
proxyDocker: form.proxyDocker,
|
proxyDocker: form.proxyDocker,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onChangeApiInterfaceStatus = () => {
|
||||||
|
if (form.apiInterfaceStatus === 'enable') {
|
||||||
|
apiInterfaceRef.value.acceptParams({
|
||||||
|
apiInterfaceStatus: form.apiInterfaceStatus,
|
||||||
|
apiKey: form.apiKey,
|
||||||
|
ipWhiteList: form.ipWhiteList,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ElMessageBox.confirm(i18n.t('setting.apiInterfaceClose'), i18n.t('setting.apiInterface'), {
|
||||||
|
confirmButtonText: i18n.t('commons.button.confirm'),
|
||||||
|
cancelButtonText: i18n.t('commons.button.cancel'),
|
||||||
|
})
|
||||||
|
.then(async () => {
|
||||||
|
loading.value = true;
|
||||||
|
await updateSetting({ key: 'ApiInterfaceStatus', value: 'disable' })
|
||||||
|
.then(() => {
|
||||||
|
loading.value = false;
|
||||||
|
search();
|
||||||
|
MsgSuccess(i18n.t('commons.msg.operationSuccess'));
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
apiInterfaceRef.value.acceptParams({
|
||||||
|
apiInterfaceStatus: 'enable',
|
||||||
|
apiKey: form.apiKey,
|
||||||
|
ipWhiteList: form.ipWhiteList,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
};
|
||||||
const onChangeNetwork = () => {
|
const onChangeNetwork = () => {
|
||||||
networkRef.value.acceptParams({ defaultNetwork: form.defaultNetwork });
|
networkRef.value.acceptParams({ defaultNetwork: form.defaultNetwork });
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user