Compare commits

...
27 Commits
Author SHA1 Message Date
zhengkunwang223 53756c382d feat: 取消网站 ipv6 的默认设置 (#1099) 2023-05-22 11:44:49 +08:00
zhengkunwang223 8533a71670 fix: 解决首页控制台报错的问题 (#1087) 2023-05-21 22:16:53 +08:00
zhengkunwang223 6b3c06a057 fix: 解决伪静态页面光标丢失的问题 (#1086) 2023-05-21 22:16:50 +08:00
zhengkunwang223 4fd87568cd fix: 解决搜索子目录模糊查询失败的问题 (#1085)
Refs https://github.com/1Panel-dev/1Panel/issues/1049
2023-05-21 22:16:44 +08:00
zhengkunwang223 56f8caf561 fix: 解决打开编辑文件页面确认按钮可能看不到的问题 (#1084)
Refs https://github.com/1Panel-dev/1Panel/issues/1042
2023-05-21 22:16:40 +08:00
zhengkunwang223 7d2f7a8d3b fix: 解决反向代理 1Panel 并启用 auth_basic 的时候无法登录的问题 (#1083)
Refs https://github.com/1Panel-dev/1Panel/issues/1082
2023-05-21 22:16:36 +08:00
xin.yang 01a9589be9 修复首页推荐应用处在窄窗口时显示异常的问题 2023-05-21 22:15:45 +08:00
zhengkunwang223 72eb02fd39 feat: 升级 distribution 版本到 v2.8.2 (#1067) 2023-05-21 22:15:16 +08:00
ssongliu c1332235a0 fix: 右侧抽屉宽度调整 (#1047) 2023-05-15 02:36:47 +00:00
ssongliu 212c8634ea fix: 容器配置界面样式调整 (#1045) 2023-05-15 02:22:47 +00:00
zhengkunwang223 b966ab3e11 fix: 解决创建数据库超时问题 (#1037) 2023-05-14 01:34:31 +00:00
zhengkunwang223 25c2246782 fix: 解决默认网站开启 https 443 端口没有设置 default_server 的问题 (#1034) 2023-05-14 01:04:31 +00:00
ssongliu 2ae1db4730 fix: 解决 ssl 启用和端口修改跳转问题 (#1030) 2023-05-13 12:20:30 +00:00
ssongliu 43652b2a54 fix: 解决数据库上传备份恢复失败的问题 (#1027) 2023-05-13 07:32:28 +00:00
ssongliu 574a504ec3 fix: 增加初始化逻辑 (#1026) 2023-05-13 04:20:29 +00:00
zhengkunwang223 52a8331c78 fix: 解决网站设置 https 情况下,设置默认网站失败的问题 (#1023) 2023-05-12 15:08:28 +00:00
ssongliu afa9eecf35 fix: 补全 swagger 文档 (#1022) 2023-05-12 22:30:50 +08:00
ssongliu 46e13d754f fix: 解决计划任务未勾选同步到本地造成的备份恢复问题 (#1021) 2023-05-12 22:30:26 +08:00
zhengkunwang223 0157326d61 fix: 限制应用失败情况下启动应用 (#1020) 2023-05-12 22:30:02 +08:00
ssongliu 7d08875f95 fix: 解决数据库用户指定多个 ip 无效的问题 (#1019) 2023-05-12 17:48:31 +08:00
zhengkunwang223 bd2a49e299 fix: 解决网站设置切换到 HTTPS 控制台报错的问题 (#1016)
fix https://github.com/1Panel-dev/1Panel/issues/672
2023-05-12 07:08:23 +00:00
ssongliu 06f1d03b93 fix: 端口校验正则表达式修改 (#1009) 2023-05-12 03:36:23 +00:00
Mystery0 M 4c39955f2f fix: 获取网站日志时,先检查一下日志文件大小,超过10M时直接报错 (#1011)
#### What this PR does / why we need it?

修复网站日志文件较大时,在界面上查看日志会导致系统短时间卡住的问题

相关Issue https://github.com/1Panel-dev/1Panel/issues/495
该提交可优化这个Issue的问题

#### Summary of your change

在获取文件内容之前,通过os.Stat获取文件的信息,并对文件大小进行判断,如果过大(目前是>10MB),则抛出错误中止流程

#### Please indicate you've done the following:

- [ ] Made sure tests are passing and test coverage is added if needed.
- [x] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/).
- [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.
2023-05-12 02:54:23 +00:00
maninhill 56f92310f8 Update README.md (#1005) 2023-05-11 23:27:01 +08:00
maninhill cb47806fd6 Update README.md 2023-05-11 21:28:57 +08:00
maninhill 16ae193e9f Update README.md 2023-05-11 15:33:17 +08:00
fossabot 8770939328 Add license scan report and status
Signed off by: fossabot <badges@fossa.com>
2023-05-11 15:33:17 +08:00
54 changed files with 469 additions and 176 deletions
+5
View File
@@ -6,6 +6,7 @@
<a href="https://app.codacy.com/gh/1Panel-dev/1Panel?utm_source=github.com&utm_medium=referral&utm_content=1Panel-dev/1Panel&utm_campaign=Badge_Grade_Dashboard"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a> <a href="https://app.codacy.com/gh/1Panel-dev/1Panel?utm_source=github.com&utm_medium=referral&utm_content=1Panel-dev/1Panel&utm_campaign=Badge_Grade_Dashboard"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a>
<a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a> <a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a>
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a> <a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a>
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel?ref=badge_shield"><img src="https://app.fossa.com/api/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel.svg?type=shield" alt="FOSSA Status"></a>
</p> </p>
------------------------------ ------------------------------
@@ -58,6 +59,10 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date) [![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
## FOSSA Status
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel?ref=badge_large)
## License ## License
Copyright (c) 2014-2023 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved. Copyright (c) 2014-2023 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
+10
View File
@@ -2,6 +2,8 @@ package v1
import ( import (
"encoding/base64" "encoding/base64"
"fmt"
"path"
"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/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
@@ -356,6 +358,14 @@ func (b *BaseApi) Recover(c *gin.Context) {
return return
} }
if req.Source != "LOCAL" {
downloadPath, err := backupService.DownloadRecord(dto.DownloadRecord{Source: req.Source, FileDir: path.Dir(req.File), FileName: path.Base(req.File)})
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("download file failed, err: %v", err))
return
}
req.File = downloadPath
}
switch req.Type { switch req.Type {
case "mysql": case "mysql":
if err := backupService.MysqlRecover(req); err != nil { if err := backupService.MysqlRecover(req); err != nil {
+2 -2
View File
@@ -138,7 +138,7 @@ func (b *BaseApi) OperateIPRule(c *gin.Context) {
// @Param request body dto.BatchRuleOperate true "request" // @Param request body dto.BatchRuleOperate true "request"
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /hosts/firewall/ip [post] // @Router /hosts/firewall/batch [post]
func (b *BaseApi) BatchOperateRule(c *gin.Context) { func (b *BaseApi) BatchOperateRule(c *gin.Context) {
var req dto.BatchRuleOperate var req dto.BatchRuleOperate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -188,7 +188,7 @@ func (b *BaseApi) UpdatePortRule(c *gin.Context) {
// @Param request body dto.AddrRuleUpdate true "request" // @Param request body dto.AddrRuleUpdate true "request"
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /hosts/firewall/update/ip [post] // @Router /hosts/firewall/update/addr [post]
func (b *BaseApi) UpdateAddrRule(c *gin.Context) { func (b *BaseApi) UpdateAddrRule(c *gin.Context) {
var req dto.AddrRuleUpdate var req dto.AddrRuleUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
+1
View File
@@ -36,6 +36,7 @@ type CommonBackup struct {
DetailName string `json:"detailName"` DetailName string `json:"detailName"`
} }
type CommonRecover struct { type CommonRecover struct {
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO"`
Type string `json:"type" validate:"required,oneof=app mysql redis website"` Type string `json:"type" validate:"required,oneof=app mysql redis website"`
Name string `json:"name"` Name string `json:"name"`
DetailName string `json:"detailName"` DetailName string `json:"detailName"`
+9 -8
View File
@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"path"
"strings" "strings"
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
@@ -109,15 +110,15 @@ func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error)
if err != nil { if err != nil {
return "", fmt.Errorf("new cloud storage client failed, err: %v", err) return "", fmt.Errorf("new cloud storage client failed, err: %v", err)
} }
tempPath := fmt.Sprintf("%sdownload%s", constant.DataDir, info.FileDir) targetPath := fmt.Sprintf("%s/download/%s/%s", constant.DataDir, info.FileDir, info.FileName)
if _, err := os.Stat(tempPath); err != nil && os.IsNotExist(err) { if _, err := os.Stat(path.Dir(targetPath)); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(tempPath, os.ModePerm); err != nil { if err = os.MkdirAll(path.Dir(targetPath), os.ModePerm); err != nil {
global.LOG.Errorf("mkdir %s failed, err: %v", tempPath, err) global.LOG.Errorf("mkdir %s failed, err: %v", path.Dir(targetPath), err)
} }
} }
targetPath := tempPath + info.FileName srcPath := fmt.Sprintf("%s/%s", info.FileDir, info.FileName)
if _, err = os.Stat(targetPath); err != nil && os.IsNotExist(err) { if exist, _ := backClient.Exist(srcPath); exist {
isOK, err := backClient.Download(info.FileName, targetPath) isOK, err := backClient.Download(srcPath, targetPath)
if !isOK { if !isOK {
return "", fmt.Errorf("cloud storage download failed, err: %v", err) return "", fmt.Errorf("cloud storage download failed, err: %v", err)
} }
@@ -179,7 +180,7 @@ func (u *BackupService) BatchDeleteRecord(ids []uint) error {
global.LOG.Errorf("remove file %s failed, err: %v", record.FileDir+record.FileName, err) global.LOG.Errorf("remove file %s failed, err: %v", record.FileDir+record.FileName, err)
} }
} else { } else {
backupAccount, err := backupRepo.Get(commonRepo.WithByName(record.Source)) backupAccount, err := backupRepo.Get(commonRepo.WithByType(record.Source))
if err != nil { if err != nil {
return err return err
} }
+69 -30
View File
@@ -14,6 +14,7 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/buserr" "github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global" "github.com/1Panel-dev/1Panel/backend/global"
@@ -99,22 +100,7 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
} }
return nil, err return nil, err
} }
tmpPermission := req.Permission if err := u.createUser(app, req); err != nil {
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("create user '%s'@'%s' identified by '%s';", req.Username, tmpPermission, req.Password)); err != nil {
_ = excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database `%s`", req.Name))
if strings.Contains(err.Error(), "ERROR 1396") {
return nil, buserr.New(constant.ErrUserIsExist)
}
return nil, err
}
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to '%s'@'%s'", req.Name, req.Username, tmpPermission)
if req.Name == "*" {
grantStr = fmt.Sprintf("grant all privileges on *.* to '%s'@'%s'", mysql.Username, tmpPermission)
}
if app.Version == "5.7.39" {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, req.Password)
}
if err := excSQL(app.ContainerName, app.Password, grantStr); err != nil {
return nil, err return nil, err
} }
@@ -271,6 +257,9 @@ func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
if err != nil { if err != nil {
return err return err
} }
if info.Value == mysql.Permission {
return nil
}
} }
app, err := appInstallRepo.LoadBaseInfo("mysql", "") app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil { if err != nil {
@@ -284,24 +273,30 @@ func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
} }
if info.Value != mysql.Permission { if info.Value != mysql.Permission {
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", mysql.Username, mysql.Permission)); err != nil { var userlist []string
return err if strings.Contains(mysql.Permission, ",") {
userlist = strings.Split(mysql.Permission, ",")
} else {
userlist = append(userlist, mysql.Permission)
}
for _, user := range userlist {
if len(user) != 0 {
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", mysql.Username, user)); err != nil {
return err
}
}
} }
if info.ID == 0 { if info.ID == 0 {
return nil return nil
} }
} }
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("create user if not exists '%s'@'%s' identified by '%s';", mysql.Username, info.Value, mysql.Password)); err != nil {
return err if err := u.createUser(app, dto.MysqlDBCreate{
} Username: mysql.Username,
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to '%s'@'%s'", mysql.Name, mysql.Username, info.Value) Name: mysql.Name,
if mysql.Name == "*" { Permission: info.Value,
grantStr = fmt.Sprintf("grant all privileges on *.* to '%s'@'%s'", mysql.Username, info.Value) Password: mysql.Password,
} }); err != nil {
if app.Version == "5.7.39" {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, mysql.Password)
}
if err := excuteSql(app.ContainerName, app.Password, grantStr); err != nil {
return err return err
} }
if err := excuteSql(app.ContainerName, app.Password, "flush privileges"); err != nil { if err := excuteSql(app.ContainerName, app.Password, "flush privileges"); err != nil {
@@ -475,6 +470,50 @@ func (u *MysqlService) LoadStatus() (*dto.MysqlStatus, error) {
return &info, nil return &info, nil
} }
func (u *MysqlService) createUser(app *repo.RootInfo, req dto.MysqlDBCreate) error {
var userlist []string
if strings.Contains(req.Permission, ",") {
ips := strings.Split(req.Permission, ",")
for _, ip := range ips {
if len(ip) != 0 {
userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", req.Username, ip))
}
}
} else {
userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", req.Username, req.Permission))
}
for _, user := range userlist {
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("create user %s identified by '%s';", user, req.Password)); err != nil {
handleCreateError(req.Name, userlist, app)
if strings.Contains(err.Error(), "ERROR 1396") {
return buserr.New(constant.ErrUserIsExist)
}
return err
}
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to %s", req.Name, user)
if req.Name == "*" {
grantStr = fmt.Sprintf("grant all privileges on *.* to %s", user)
}
if app.Version == "5.7.39" {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, req.Password)
}
if err := excSQL(app.ContainerName, app.Password, grantStr); err != nil {
handleCreateError(req.Name, userlist, app)
return err
}
}
return nil
}
func handleCreateError(dbName string, userlist []string, app *repo.RootInfo) {
_ = excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database `%s`", dbName))
for _, user := range userlist {
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists %s", user)); err != nil {
global.LOG.Errorf("drop user failed, err: %v", err)
}
}
}
func excuteSqlForMaps(containerName, password, command string) (map[string]string, error) { func excuteSqlForMaps(containerName, password, command string) (map[string]string, error) {
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command) cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
@@ -515,7 +554,7 @@ func excuteSql(containerName, password, command string) error {
} }
func excSQL(containerName, password, command string) error { func excSQL(containerName, password, command string) error {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel() defer cancel()
cmd := exec.CommandContext(ctx, "docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command) cmd := exec.CommandContext(ctx, "docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
+49 -3
View File
@@ -854,7 +854,16 @@ func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.Websi
return res, nil return res, nil
} }
} }
content, err := os.ReadFile(path.Join(sitePath, "log", req.LogType)) filePath := path.Join(sitePath, "log", req.LogType)
fileInfo, err := os.Stat(filePath)
if err != nil {
return nil, err
}
if fileInfo.Size() > 10<<20 {
return nil, buserr.New(constant.ErrFileToLarge)
}
fileInfo.Size()
content, err := os.ReadFile(filePath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -903,7 +912,23 @@ func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.Websi
func (w WebsiteService) ChangeDefaultServer(id uint) error { func (w WebsiteService) ChangeDefaultServer(id uint) error {
defaultWebsite, _ := websiteRepo.GetFirst(websiteRepo.WithDefaultServer()) defaultWebsite, _ := websiteRepo.GetFirst(websiteRepo.WithDefaultServer())
if defaultWebsite.ID > 0 { if defaultWebsite.ID > 0 {
if err := updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "listen", Params: []string{"80"}}}, &defaultWebsite); err != nil { params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"listen"}, &defaultWebsite)
if err != nil {
return err
}
var changeParams []dto.NginxParam
for _, param := range params {
paramLen := len(param.Params)
var newParam []string
if paramLen > 1 && param.Params[paramLen-1] == components.DefaultServer {
newParam = param.Params[:paramLen-1]
}
changeParams = append(changeParams, dto.NginxParam{
Name: param.Name,
Params: newParam,
})
}
if err := updateNginxConfig(constant.NginxScopeServer, changeParams, &defaultWebsite); err != nil {
return err return err
} }
defaultWebsite.DefaultServer = false defaultWebsite.DefaultServer = false
@@ -916,7 +941,28 @@ func (w WebsiteService) ChangeDefaultServer(id uint) error {
if err != nil { if err != nil {
return err return err
} }
if err := updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "listen", Params: []string{"80", "default_server"}}}, &website); err != nil { params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"listen"}, &website)
if err != nil {
return err
}
var changeParams []dto.NginxParam
for _, param := range params {
paramLen := len(param.Params)
bind := param.Params[0]
var newParam []string
if bind == "80" || bind == "443" || bind == "[::]:80" || bind == "[::]:443" {
if param.Params[paramLen-1] == components.DefaultServer {
newParam = param.Params
} else {
newParam = append(param.Params, components.DefaultServer)
}
}
changeParams = append(changeParams, dto.NginxParam{
Name: param.Name,
Params: newParam,
})
}
if err := updateNginxConfig(constant.NginxScopeServer, changeParams, &website); err != nil {
return err return err
} }
website.DefaultServer = true website.DefaultServer = true
+1 -4
View File
@@ -371,8 +371,7 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
} }
config := nginxFull.SiteConfig.Config config := nginxFull.SiteConfig.Config
server := config.FindServers()[0] server := config.FindServers()[0]
server.UpdateListen("443", false, "ssl") server.UpdateListen("443", website.DefaultServer, "ssl")
server.UpdateListen("[::]:443", false, "ssl")
switch req.HttpConfig { switch req.HttpConfig {
case constant.HTTPSOnly: case constant.HTTPSOnly:
@@ -381,11 +380,9 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
server.RemoveDirective("if", []string{"($scheme"}) server.RemoveDirective("if", []string{"($scheme"})
case constant.HTTPToHTTPS: case constant.HTTPToHTTPS:
server.UpdateListen("80", website.DefaultServer) server.UpdateListen("80", website.DefaultServer)
server.UpdateListen("[::]:80", false)
server.AddHTTP2HTTPS() server.AddHTTP2HTTPS()
case constant.HTTPAlso: case constant.HTTPAlso:
server.UpdateListen("80", website.DefaultServer) server.UpdateListen("80", website.DefaultServer)
server.UpdateListen("[::]:80", false)
server.RemoveDirective("if", []string{"($scheme"}) server.RemoveDirective("if", []string{"($scheme"})
} }
+19 -18
View File
@@ -1,22 +1,23 @@
package configs package configs
type System struct { type System struct {
Port string `mapstructure:"port"` Port string `mapstructure:"port"`
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"`
ChangeUserInfo bool `mapstructure:"change_user_info"`
} }
+1 -1
View File
@@ -5,7 +5,7 @@ const (
SessionName = "psession" SessionName = "psession"
AuthMethodJWT = "jwt" AuthMethodJWT = "jwt"
JWTHeaderName = "Authorization" JWTHeaderName = "PanelAuthorization"
JWTBufferTime = 3600 JWTBufferTime = 3600
JWTIssuer = "1Panel" JWTIssuer = "1Panel"
+23 -1
View File
@@ -3,6 +3,9 @@ package hook
import ( import (
"github.com/1Panel-dev/1Panel/backend/app/repo" "github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/global" "github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
) )
func Init() { func Init() {
@@ -27,6 +30,25 @@ func Init() {
_ = settingRepo.Create("SystemStatus", "Free") _ = settingRepo.Create("SystemStatus", "Free")
} }
if err := settingRepo.Update("SystemStatus", "Free"); err != nil { if err := settingRepo.Update("SystemStatus", "Free"); err != nil {
global.LOG.Fatalf("init service before start failed, err: %v", "Free") global.LOG.Fatalf("init service before start failed, err: %v", err)
}
if global.CONF.System.ChangeUserInfo {
if err := settingRepo.Update("UserName", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init username before start failed, err: %v", err)
}
pass, _ := encrypt.StringEncrypt(common.RandStrAndNum(10))
if err := settingRepo.Update("Password", pass); err != nil {
global.LOG.Fatalf("init password before start failed, err: %v", err)
}
if err := settingRepo.Update("SecurityEntrance", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init entrance before start failed, err: %v", err)
}
if cmd.HasNoPasswordSudo() {
_, _ = cmd.Exec("sudo sed -i '/CHANGE_USER_INFO=true/d' /usr/local/bin/1pctl")
} else {
_, _ = cmd.Exec("sed -i '/CHANGE_USER_INFO=true/d' /usr/local/bin/1pctl")
}
} }
} }
+9
View File
@@ -99,6 +99,7 @@ func Init() {
global.CONF.System.Username = username global.CONF.System.Username = username
global.CONF.System.Password = password global.CONF.System.Password = password
global.CONF.System.Entrance = entrance global.CONF.System.Entrance = entrance
global.CONF.System.ChangeUserInfo = loadChange()
global.Viper = v global.Viper = v
} }
@@ -113,3 +114,11 @@ func loadParams(param string) string {
} }
return info return info
} }
func loadChange() bool {
stdout, err := cmd.Exec("grep '^CHANGE_USER_INFO=' /usr/bin/1pctl | cut -d'=' -f2")
if err != nil {
return false
}
return stdout == "true\n"
}
+4 -3
View File
@@ -67,10 +67,11 @@ func (cos cosClient) Exist(path string) (bool, error) {
if err != nil { if err != nil {
return false, err return false, err
} }
if _, err := client.Object.IsExist(context.Background(), path); err != nil { exist, err := client.Object.IsExist(context.Background(), path)
return true, err if err != nil {
return false, err
} }
return false, nil return exist, nil
} }
func (cos cosClient) Delete(path string) (bool, error) { func (cos cosClient) Delete(path string) (bool, error) {
+2 -2
View File
@@ -59,9 +59,9 @@ func (kodo kodoClient) Exist(path string) (bool, error) {
return false, err return false, err
} }
if _, err := kodo.client.Stat(bucket, path); err != nil { if _, err := kodo.client.Stat(bucket, path); err != nil {
return true, err return false, err
} }
return false, nil return true, nil
} }
func (kodo kodoClient) Delete(path string) (bool, error) { func (kodo kodoClient) Delete(path string) (bool, error) {
+2 -2
View File
@@ -81,9 +81,9 @@ func (minIo minIoClient) Exist(path string) (bool, error) {
if _, ok := minIo.Vars["bucket"]; ok { if _, ok := minIo.Vars["bucket"]; ok {
_, err := minIo.client.GetObject(context.Background(), minIo.Vars["bucket"].(string), path, minio.GetObjectOptions{}) _, err := minIo.client.GetObject(context.Background(), minIo.Vars["bucket"].(string), path, minio.GetObjectOptions{})
if err != nil { if err != nil {
return true, err return false, err
} }
return false, nil return true, nil
} else { } else {
return false, constant.ErrInvalidParams return false, constant.ErrInvalidParams
} }
@@ -1,40 +0,0 @@
package client
import (
"encoding/json"
"fmt"
"testing"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/init/db"
"github.com/1Panel-dev/1Panel/backend/init/log"
"github.com/1Panel-dev/1Panel/backend/init/viper"
)
func TestMinio(t *testing.T) {
viper.Init()
log.Init()
db.Init()
var backup model.BackupAccount
if err := global.DB.Where("id = ?", 3).First(&backup).Error; err != nil {
fmt.Println(err)
}
varMap := make(map[string]interface{})
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
fmt.Println(err)
}
varMap["type"] = backup.Type
varMap["bucket"] = backup.Bucket
switch backup.Type {
case constant.Sftp:
varMap["password"] = backup.Credential
case constant.OSS, constant.S3, constant.MinIo:
varMap["secretKey"] = backup.Credential
}
client, _ := NewMinIoClient(varMap)
_, _ = client.ListObjects("directory/directory-test-minio/")
}
+10
View File
@@ -83,6 +83,16 @@ func RandStr(n int) string {
return string(b) return string(b)
} }
func RandStrAndNum(n int) string {
mathRand.Seed(time.Now().UnixNano())
const charset = "abcdefghijklmnopqrstuvwxyz0123456789"
b := make([]byte, 10)
for i := range b {
b[i] = charset[mathRand.Int63()%int64(len(charset))]
}
return (string(b))
}
func ScanPort(port int) bool { func ScanPort(port int) bool {
ln, err := net.Listen("tcp", ":"+strconv.Itoa(port)) ln, err := net.Listen("tcp", ":"+strconv.Itoa(port))
if err != nil { if err != nil {
+1 -1
View File
@@ -99,7 +99,7 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
} }
func (f *FileInfo) search(search string, count int) (files []FileSearchInfo, total int, err error) { func (f *FileInfo) search(search string, count int) (files []FileSearchInfo, total int, err error) {
cmd := exec.Command("find", f.Path, "-name", search) cmd := exec.Command("find", f.Path, "-name", fmt.Sprintf("*%s*", search))
output, err := cmd.StdoutPipe() output, err := cmd.StdoutPipe()
if err != nil { if err != nil {
return return
+17 -7
View File
@@ -65,7 +65,19 @@ func (s *Server) FindDirectives(directiveName string) []IDirective {
directives = append(directives, directive.GetBlock().FindDirectives(directiveName)...) directives = append(directives, directive.GetBlock().FindDirectives(directiveName)...)
} }
} }
if directiveName == "listen" {
for _, listen := range s.Listens {
params := []string{listen.Bind}
params = append(params, listen.Parameters...)
if listen.DefaultServer != "" {
params = append(params, DefaultServer)
}
directives = append(directives, &Directive{
Name: "listen",
Parameters: params,
})
}
}
return directives return directives
} }
@@ -75,14 +87,12 @@ func (s *Server) UpdateDirective(key string, params []string) {
} }
if key == "listen" { if key == "listen" {
defaultServer := false defaultServer := false
if len(params) > 1 && params[1] == "default_server" { paramLen := len(params)
if paramLen > 0 && params[paramLen-1] == "default_server" {
params = params[:paramLen-1]
defaultServer = true defaultServer = true
} }
if len(params) > 2 { s.UpdateListen(params[0], defaultServer, params[1:]...)
s.UpdateListen(params[0], defaultServer, params[2:]...)
} else {
s.UpdateListen(params[0], defaultServer)
}
return return
} }
@@ -52,8 +52,8 @@ func (sl *ServerListen) GetBlock() IBlock {
func (sl *ServerListen) GetParameters() []string { func (sl *ServerListen) GetParameters() []string {
params := []string{sl.Bind} params := []string{sl.Bind}
params = append(params, sl.DefaultServer)
params = append(params, sl.Parameters...) params = append(params, sl.Parameters...)
params = append(params, sl.DefaultServer)
return params return params
} }
+45 -2
View File
@@ -5377,7 +5377,7 @@ var doc = `{
} }
} }
}, },
"/hosts/firewall/ip": { "/hosts/firewall/batch": {
"post": { "post": {
"security": [ "security": [
{ {
@@ -5410,6 +5410,49 @@ var doc = `{
} }
} }
}, },
"/hosts/firewall/ip": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "创建防火墙 IP 规则",
"consumes": [
"application/json"
],
"tags": [
"Firewall"
],
"summary": "Create group",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.AddrRuleOperate"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"x-panel-log": {
"BeforeFuntions": [],
"bodyKeys": [
"strategy",
"address"
],
"formatEN": "create address rules [strategy][address]",
"formatZH": "添加 ip 规则 [strategy] [address]",
"paramKeys": []
}
}
},
"/hosts/firewall/operate": { "/hosts/firewall/operate": {
"post": { "post": {
"security": [ "security": [
@@ -5534,7 +5577,7 @@ var doc = `{
} }
} }
}, },
"/hosts/firewall/update/ip": { "/hosts/firewall/update/addr": {
"post": { "post": {
"security": [ "security": [
{ {
+45 -2
View File
@@ -5363,7 +5363,7 @@
} }
} }
}, },
"/hosts/firewall/ip": { "/hosts/firewall/batch": {
"post": { "post": {
"security": [ "security": [
{ {
@@ -5396,6 +5396,49 @@
} }
} }
}, },
"/hosts/firewall/ip": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "创建防火墙 IP 规则",
"consumes": [
"application/json"
],
"tags": [
"Firewall"
],
"summary": "Create group",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.AddrRuleOperate"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"x-panel-log": {
"BeforeFuntions": [],
"bodyKeys": [
"strategy",
"address"
],
"formatEN": "create address rules [strategy][address]",
"formatZH": "添加 ip 规则 [strategy] [address]",
"paramKeys": []
}
}
},
"/hosts/firewall/operate": { "/hosts/firewall/operate": {
"post": { "post": {
"security": [ "security": [
@@ -5520,7 +5563,7 @@
} }
} }
}, },
"/hosts/firewall/update/ip": { "/hosts/firewall/update/addr": {
"post": { "post": {
"security": [ "security": [
{ {
+30 -2
View File
@@ -6461,7 +6461,7 @@ paths:
summary: Load firewall base info summary: Load firewall base info
tags: tags:
- Firewall - Firewall
/hosts/firewall/ip: /hosts/firewall/batch:
post: post:
consumes: consumes:
- application/json - application/json
@@ -6481,6 +6481,34 @@ paths:
summary: Create group summary: Create group
tags: tags:
- Firewall - Firewall
/hosts/firewall/ip:
post:
consumes:
- application/json
description: 创建防火墙 IP 规则
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.AddrRuleOperate'
responses:
"200":
description: ""
security:
- ApiKeyAuth: []
summary: Create group
tags:
- Firewall
x-panel-log:
BeforeFuntions: []
bodyKeys:
- strategy
- address
formatEN: create address rules [strategy][address]
formatZH: 添加 ip 规则 [strategy] [address]
paramKeys: []
/hosts/firewall/operate: /hosts/firewall/operate:
post: post:
consumes: consumes:
@@ -6560,7 +6588,7 @@ paths:
summary: Page firewall rules summary: Page firewall rules
tags: tags:
- Firewall - Firewall
/hosts/firewall/update/ip: /hosts/firewall/update/addr:
post: post:
consumes: consumes:
- application/json - application/json
@@ -1,7 +1,5 @@
server { server {
listen 80; listen 80;
listen [::]:80;
server_name ko.wp-1.com; server_name ko.wp-1.com;
index index.php index.html index.htm default.php default.htm default.html; index index.php index.html index.htm default.php default.htm default.html;
+1
View File
@@ -49,6 +49,7 @@ export namespace Backup {
detailName: string; detailName: string;
} }
export interface Recover { export interface Recover {
source: string;
type: string; type: string;
name: string; name: string;
detailName: string; detailName: string;
+1
View File
@@ -124,6 +124,7 @@ const onBackup = async () => {
const onRecover = async (row: Backup.RecordInfo) => { const onRecover = async (row: Backup.RecordInfo) => {
let params = { let params = {
source: row.source,
type: type.value, type: type.value,
name: name.value, name: name.value,
detailName: detailName.value, detailName: detailName.value,
+1
View File
@@ -149,6 +149,7 @@ const search = async () => {
const onRecover = async (row: File.File) => { const onRecover = async (row: File.File) => {
let params = { let params = {
source: 'LOCAL',
type: type.value, type: type.value,
name: name.value, name: name.value,
detailName: detailName.value, detailName: detailName.value,
+7 -4
View File
@@ -300,7 +300,7 @@ const message = {
loadBackup: 'Import', loadBackup: 'Import',
setting: 'Settings', setting: 'Settings',
remoteAccess: 'Remote access', remoteAccess: 'Remote access',
remoteHelper: 'One in a row, for example:\n172.16.10.111\n172.16.10.112', remoteHelper: 'Multiple IP comma-delimited, example: 172.16.10.111, 172.16.10.112',
remoteConnHelper: remoteConnHelper:
'Remote connection to mysql as user root may have security risks. Therefore, perform this operation with caution.', 'Remote connection to mysql as user root may have security risks. Therefore, perform this operation with caution.',
changePassword: 'Password', changePassword: 'Password',
@@ -540,8 +540,10 @@ const message = {
imageRepo: 'Image repo', imageRepo: 'Image repo',
repoHelper: 'Does it include a mirror repository/organization/project?', repoHelper: 'Does it include a mirror repository/organization/project?',
auth: 'Auth', auth: 'Auth',
mirrorHelper: 'One in a row, for example:\nhttps://hub-mirror.c.163.com \nhttps://reg-mirror.qiniu.com', mirrorHelper:
registrieHelper: 'One in a row, for example:\n172.16.10.111:8081 \n172.16.10.112:8081', 'If there are multiple mirrors, newlines must be displayed, for example:\nhttps://hub-mirror.c.163.com \nhttps://reg-mirror.qiniu.com',
registrieHelper:
'If multiple private repositories exist, newlines must be displayed, for example:\n172.16.10.111:8081 \n172.16.10.112:8081',
compose: 'Compose', compose: 'Compose',
fromChangeHelper: 'Switching the source will clear the current edited content. Do you want to continue?', fromChangeHelper: 'Switching the source will clear the current edited content. Do you want to continue?',
@@ -576,7 +578,8 @@ const message = {
daemonJsonPathHelper: 'Ensure that the configuration path is the same as that specified in docker.service.', daemonJsonPathHelper: 'Ensure that the configuration path is the same as that specified in docker.service.',
mirrors: 'Registry mirrors', mirrors: 'Registry mirrors',
mirrorsHelper: mirrorsHelper:
'Redirecting requests for a Docker image repository to a specified image accelerator can improve the download speed of the image', 'The acceleration URL is preferred to perform operations. If this parameter is set to empty, mirror acceleration is disabled.',
mirrorsHelper2: 'For details, see the official documents, ',
registries: 'Insecure registries', registries: 'Insecure registries',
liveHelper: liveHelper:
'Allows the running container state to be preserved in case of unexpected shutdown or crash of the Docker daemon', 'Allows the running container state to be preserved in case of unexpected shutdown or crash of the Docker daemon',
+6 -4
View File
@@ -314,7 +314,7 @@ const message = {
loadBackup: '导入备份', loadBackup: '导入备份',
setting: '设置', setting: '设置',
remoteAccess: '远程访问', remoteAccess: '远程访问',
remoteHelper: '一行一个,例:\n172.16.10.111\n172.16.10.112', remoteHelper: '多个 ip 以逗号分隔,例:172.16.10.111,172.16.10.112',
remoteConnHelper: 'root 帐号远程连接 mysql 有安全风险,开启需谨慎!', remoteConnHelper: 'root 帐号远程连接 mysql 有安全风险,开启需谨慎!',
changePassword: '改密', changePassword: '改密',
changePasswordHelper: '当前数据库已经关联应用,修改密码将同步修改应用中数据库密码,修改后重启生效。', changePasswordHelper: '当前数据库已经关联应用,修改密码将同步修改应用中数据库密码,修改后重启生效。',
@@ -558,8 +558,9 @@ const message = {
imageRepo: '镜像仓库', imageRepo: '镜像仓库',
repoHelper: '是否包含镜像仓库/组织/项目?', repoHelper: '是否包含镜像仓库/组织/项目?',
auth: '认证', auth: '认证',
mirrorHelper: '一行一个,例:\nhttps://hub-mirror.c.163.com \nhttps://reg-mirror.qiniu.com', mirrorHelper:
registrieHelper: '一行一个,例:\n172.16.10.111:8081 \n172.16.10.112:8081', '当存在多个加速器时,需要换行显示,例: \nhttp://xxxxxx.m.daocloud.io \nhttps://xxxxxx.mirror.aliyuncs.com',
registrieHelper: '当存在多个私有仓库时,需要换行显示,例:\n172.16.10.111:8081 \n172.16.10.112:8081',
compose: '编排', compose: '编排',
fromChangeHelper: '切换来源将清空当前已编辑内容,是否继续?', fromChangeHelper: '切换来源将清空当前已编辑内容,是否继续?',
@@ -590,7 +591,8 @@ const message = {
dockerStatus: 'Docker 服务', dockerStatus: 'Docker 服务',
daemonJsonPathHelper: '请保证配置路径与 docker.service 中指定的配置路径保持一致。', daemonJsonPathHelper: '请保证配置路径与 docker.service 中指定的配置路径保持一致。',
mirrors: '镜像加速', mirrors: '镜像加速',
mirrorsHelper: '将 Docker 镜像库的请求重定向到指定的镜像加速器,从而提高镜像的下载速度', mirrorsHelper: '优先使用加速 URL 执行操作,设置为空则取消镜像加速。',
mirrorsHelper2: '具体操作配置请参照官方文档,',
registries: '私有仓库', registries: '私有仓库',
liveHelper: '允许在 Docker 守护进程发生意外停机或崩溃时保留正在运行的容器状态', liveHelper: '允许在 Docker 守护进程发生意外停机或崩溃时保留正在运行的容器状态',
liveWithSwarmHelper: 'live-restore 守护进程配置与 Swarm 模式不兼容', liveWithSwarmHelper: 'live-restore 守护进程配置与 Swarm 模式不兼容',
+1 -1
View File
@@ -171,7 +171,7 @@ export function checkPort(value: string): boolean {
if (Number(value) <= 0) { if (Number(value) <= 0) {
return true; return true;
} }
const reg = /^([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])$/; const reg = /^([1-9](\d{0,3}))$|^([1-5]\d{4})$|^(6[0-4]\d{3})$|^(65[0-4]\d{2})$|^(655[0-2]\d)$|^(6553[0-5])$/;
if (!reg.test(value) && value !== '') { if (!reg.test(value) && value !== '') {
return true; return true;
} else { } else {
@@ -9,11 +9,15 @@
</template> </template>
</Header> </Header>
</template> </template>
<el-descriptions border :column="1" v-if="!edit"> <el-row v-if="!edit">
<el-descriptions-item v-for="(param, key) in params" :label="getLabel(param)" :key="key"> <el-col :span="22" :offset="1">
<span>{{ param.showValue && param.showValue != '' ? param.showValue : param.value }}</span> <el-descriptions border :column="1">
</el-descriptions-item> <el-descriptions-item v-for="(param, key) in params" :label="getLabel(param)" :key="key">
</el-descriptions> <span>{{ param.showValue && param.showValue != '' ? param.showValue : param.value }}</span>
</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
<el-row v-else v-loading="loading"> <el-row v-else v-loading="loading">
<el-col :span="22" :offset="1"> <el-col :span="22" :offset="1">
<el-alert :title="$t('app.updateHelper')" type="warning" :closable="false" /> <el-alert :title="$t('app.updateHelper')" type="warning" :closable="false" />
@@ -347,7 +347,7 @@ const buttons = [
openOperate(row, 'start'); openOperate(row, 'start');
}, },
disabled: (row: any) => { disabled: (row: any) => {
return row.status === 'Running'; return row.status === 'Running' || row.status === 'Error';
}, },
}, },
{ {
@@ -1,5 +1,5 @@
<template> <template>
<el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%"> <el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header> <template #header>
<DrawerHeader :header="$t('container.exportImage')" :back="handleClose" /> <DrawerHeader :header="$t('container.exportImage')" :back="handleClose" />
</template> </template>
@@ -1,5 +1,5 @@
<template> <template>
<el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%"> <el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header> <template #header>
<DrawerHeader :header="$t('container.imageTag')" :resource="form.itemName" :back="handleClose" /> <DrawerHeader :header="$t('container.imageTag')" :resource="form.itemName" :back="handleClose" />
</template> </template>
@@ -1,5 +1,5 @@
<template> <template>
<el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%"> <el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header> <template #header>
<DrawerHeader :header="$t('container.createNetwork')" :back="handleClose" /> <DrawerHeader :header="$t('container.createNetwork')" :back="handleClose" />
</template> </template>
@@ -174,6 +174,9 @@ const onCheckConn = async (row: Container.RepoInfo) => {
const buttons = [ const buttons = [
{ {
label: i18n.global.t('commons.button.sync'), label: i18n.global.t('commons.button.sync'),
disabled: (row: Container.RepoInfo) => {
return row.downloadUrl === 'docker.io';
},
click: (row: Container.RepoInfo) => { click: (row: Container.RepoInfo) => {
onCheckConn(row); onCheckConn(row);
}, },
@@ -1,5 +1,5 @@
<template> <template>
<el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%"> <el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header> <template #header>
<DrawerHeader <DrawerHeader
:header="title + $t('container.repo')" :header="title + $t('container.repo')"
+16 -1
View File
@@ -44,7 +44,7 @@
<el-row style="margin-top: 20px" v-if="confShowType === 'base'"> <el-row style="margin-top: 20px" v-if="confShowType === 'base'">
<el-col :span="1"><br /></el-col> <el-col :span="1"><br /></el-col>
<el-col :span="10"> <el-col :span="10">
<el-form :model="form" label-position="left" ref="formRef" label-width="120px"> <el-form :model="form" label-position="left" ref="formRef" label-width="150px">
<el-form-item :label="$t('container.mirrors')" prop="mirrors"> <el-form-item :label="$t('container.mirrors')" prop="mirrors">
<el-input <el-input
type="textarea" type="textarea"
@@ -53,6 +53,17 @@
v-model="form.mirrors" v-model="form.mirrors"
/> />
<span class="input-help">{{ $t('container.mirrorsHelper') }}</span> <span class="input-help">{{ $t('container.mirrorsHelper') }}</span>
<span class="input-help">
{{ $t('container.mirrorsHelper2') }}
<el-link
style="font-size: 12px; margin-left: 5px"
icon="Position"
@click="toDoc()"
type="primary"
>
{{ $t('firewall.quickJump') }}
</el-link>
</span>
</el-form-item> </el-form-item>
<el-form-item :label="$t('container.registries')" prop="registries"> <el-form-item :label="$t('container.registries')" prop="registries">
<el-input <el-input
@@ -219,6 +230,10 @@ const onSaveFile = async () => {
confirmDialogRef.value!.acceptParams(params); confirmDialogRef.value!.acceptParams(params);
}; };
const toDoc = () => {
window.open('https://1panel.cn/docs/user_manual/containers/setting/', '_blank');
};
const onChangeIptables = () => { const onChangeIptables = () => {
if (!form.iptables) { if (!form.iptables) {
iptablesVisiable.value = true; iptablesVisiable.value = true;
@@ -1,5 +1,5 @@
<template> <template>
<el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%"> <el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header> <template #header>
<DrawerHeader :header="$t('container.createVolume')" :back="handleClose" /> <DrawerHeader :header="$t('container.createVolume')" :back="handleClose" />
</template> </template>
@@ -1,5 +1,5 @@
<template> <template>
<el-drawer v-model="createVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%"> <el-drawer v-model="createVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header> <template #header>
<DrawerHeader :header="$t('database.create')" :back="handleClose" /> <DrawerHeader :header="$t('database.create')" :back="handleClose" />
</template> </template>
@@ -37,7 +37,13 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item v-if="form.permission === 'ip'" prop="permissionIPs"> <el-form-item v-if="form.permission === 'ip'" prop="permissionIPs">
<el-input clearable v-model="form.permissionIPs" /> <el-input
clearable
:autosize="{ minRows: 2, maxRows: 5 }"
type="textarea"
v-model="form.permissionIPs"
/>
<span class="input-help">{{ $t('database.remoteHelper') }}</span>
</el-form-item> </el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description"> <el-form-item :label="$t('commons.table.description')" prop="description">
<el-input type="textarea" clearable v-model="form.description" /> <el-input type="textarea" clearable v-model="form.description" />
@@ -131,6 +137,10 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
createVisiable.value = false; createVisiable.value = false;
}) })
.catch(() => { .catch(() => {
if (form.permission != '%') {
form.permissionIPs = form.permission;
form.permission = 'ip';
}
loading.value = false; loading.value = false;
}); });
}); });
@@ -38,12 +38,12 @@
:rules="Rules.requiredInput" :rules="Rules.requiredInput"
> >
<el-input <el-input
:placeholder="$t('database.remoteHelper')"
clearable clearable
:autosize="{ minRows: 2, maxRows: 5 }" :autosize="{ minRows: 2, maxRows: 5 }"
type="textarea" type="textarea"
v-model="changeForm.privilegeIPs" v-model="changeForm.privilegeIPs"
/> />
<span class="input-help">{{ $t('database.remoteHelper') }}</span>
</el-form-item> </el-form-item>
</div> </div>
</el-col> </el-col>
@@ -158,7 +158,7 @@ const submitChangeInfo = async (formEl: FormInstance | undefined) => {
if (changeForm.privilege !== 'ip') { if (changeForm.privilege !== 'ip') {
param.value = changeForm.privilege; param.value = changeForm.privilege;
} else { } else {
param.value = changeForm.privilegeIPs.replaceAll('/n', ','); param.value = changeForm.privilegeIPs;
} }
loading.value = true; loading.value = true;
await updateMysqlAccess(param) await updateMysqlAccess(param)
@@ -1,5 +1,5 @@
<template> <template>
<el-drawer v-model="dialogVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="40%"> <el-drawer v-model="dialogVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header> <template #header>
<DrawerHeader :header="$t('database.remoteAccess')" :back="handleClose" /> <DrawerHeader :header="$t('database.remoteAccess')" :back="handleClose" />
</template> </template>
@@ -201,6 +201,7 @@ const onBackup = async () => {
}; };
const onRecover = async () => { const onRecover = async () => {
let param = { let param = {
source: currentRow.value.source,
type: 'redis', type: 'redis',
name: '', name: '',
detailName: '', detailName: '',
+2
View File
@@ -87,8 +87,10 @@ defineExpose({
.h-app-card { .h-app-card {
cursor: pointer; cursor: pointer;
padding: 10px 15px; padding: 10px 15px;
margin-right: 10px;
.h-app-content { .h-app-content {
padding-left: 15px;
.h-app-title { .h-app-title {
font-weight: 500; font-weight: 500;
font-size: 15px; font-size: 15px;
+3 -1
View File
@@ -290,7 +290,9 @@ const freshChart = (chartName: string, Title: string, Data: number) => {
}, },
], ],
}; };
myChart.setOption(option, true); nextTick(function () {
myChart.setOption(option, true);
});
}; };
function loadStatus(val: number) { function loadStatus(val: number) {
@@ -6,6 +6,7 @@
destroy-on-close destroy-on-close
width="70%" width="70%"
@opened="onOpen" @opened="onOpen"
:top="'5vh'"
> >
<el-form :inline="true" :model="config"> <el-form :inline="true" :model="config">
<el-form-item :label="$t('file.theme')"> <el-form-item :label="$t('file.theme')">
@@ -24,8 +25,8 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div class="coder-editor" v-loading="loading"> <div v-loading="loading">
<div id="codeBox" style="height: 60vh"></div> <div id="codeBox" style="height: 55vh"></div>
</div> </div>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
@@ -214,8 +215,8 @@ onBeforeUnmount(() => {
defineExpose({ acceptParams }); defineExpose({ acceptParams });
</script> </script>
<style lang="scss"> <style>
.coder-editor { .dialog-top {
margin-top: 10px; top: 0;
} }
</style> </style>
@@ -90,7 +90,7 @@
clearable clearable
@clear="search()" @clear="search()"
@keydown.enter="search()" @keydown.enter="search()"
:placeholder="req.containSub ? $t('file.searchHelper') : $t('file.search')" :placeholder="$t('file.search')"
> >
<template #prepend> <template #prepend>
<el-checkbox v-model="req.containSub"> <el-checkbox v-model="req.containSub">
@@ -31,6 +31,8 @@ import { MsgSuccess } from '@/utils/message';
import { updatePort } from '@/api/modules/setting'; import { updatePort } from '@/api/modules/setting';
import { ElMessageBox, FormInstance } from 'element-plus'; import { ElMessageBox, FormInstance } from 'element-plus';
import { Rules } from '@/global/form-rules'; import { Rules } from '@/global/form-rules';
import { GlobalStore } from '@/store';
const globalStore = GlobalStore();
interface DialogProps { interface DialogProps {
serverPort: number; serverPort: number;
@@ -66,9 +68,10 @@ const onSavePort = async (formEl: FormInstance | undefined) => {
.then(() => { .then(() => {
loading.value = false; loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess')); MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
globalStore.isLogin = false;
let href = window.location.href; let href = window.location.href;
let ip = href.split('//')[1].split(':')[0]; let ip = href.split('//')[1].split(':')[0];
window.open(`${href.split('//')[0]}//${ip}:${form.serverPort}/`, '_self'); window.open(`${href.split('//')[0]}//${ip}:${form.serverPort}/${globalStore.entrance}`, '_self');
}) })
.catch(() => { .catch(() => {
loading.value = false; loading.value = false;
@@ -5,7 +5,7 @@
:destroy-on-close="true" :destroy-on-close="true"
@close="handleClose" @close="handleClose"
:close-on-click-modal="false" :close-on-click-modal="false"
size="50%" size="30%"
> >
<template #header> <template #header>
<DrawerHeader header="https" :back="handleClose" /> <DrawerHeader header="https" :back="handleClose" />
@@ -112,6 +112,8 @@ import { DownloadByPath } from '@/api/modules/files';
import { Rules } from '@/global/form-rules'; import { Rules } from '@/global/form-rules';
import { ElMessageBox, FormInstance } from 'element-plus'; import { ElMessageBox, FormInstance } from 'element-plus';
import { Setting } from '@/api/interface/setting'; import { Setting } from '@/api/interface/setting';
import { GlobalStore } from '@/store';
const globalStore = GlobalStore();
const loading = ref(); const loading = ref();
const drawerVisiable = ref(); const drawerVisiable = ref();
@@ -207,8 +209,10 @@ const onSaveSSL = async (formEl: FormInstance | undefined) => {
await updateSSL(param).then(() => { await updateSSL(param).then(() => {
MsgSuccess(i18n.global.t('commons.msg.operationSuccess')); MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
let href = window.location.href; let href = window.location.href;
globalStore.isLogin = false;
let address = href.split('://')[1]; let address = href.split('://')[1];
window.open(`https://${address}/`, '_self'); address = address.replaceAll('settings/safe', globalStore.entrance);
window.open(`https://${address}`, '_self');
}); });
}); });
}); });
@@ -1,6 +1,6 @@
<template> <template>
<div v-loading="loading"> <div v-loading="loading">
<el-drawer v-model="drawerVisiable" size="50%"> <el-drawer v-model="drawerVisiable" size="30%">
<template #header> <template #header>
<DrawerHeader :header="$t('setting.importSnapshot')" :back="handleClose" /> <DrawerHeader :header="$t('setting.importSnapshot')" :back="handleClose" />
</template> </template>
@@ -184,7 +184,7 @@ const get = () => {
if (res.data.httpConfig != '') { if (res.data.httpConfig != '') {
form.httpConfig = res.data.httpConfig; form.httpConfig = res.data.httpConfig;
} }
if (res.data.SSLProtocol.length > 0) { if (res.data.SSLProtocol && res.data.SSLProtocol.length > 0) {
form.SSLProtocol = res.data.SSLProtocol; form.SSLProtocol = res.data.SSLProtocol;
} }
if (res.data.algorithm != '') { if (res.data.algorithm != '') {
@@ -1,5 +1,5 @@
<template> <template>
<div v-loading="loading"> <div>
<el-form-item :label="$t('website.rewriteMode')"> <el-form-item :label="$t('website.rewriteMode')">
<el-select v-model="req.name" filterable @change="getRewriteConfig(req.name)"> <el-select v-model="req.name" filterable @change="getRewriteConfig(req.name)">
<el-option :label="$t('website.current')" :value="'current'"></el-option> <el-option :label="$t('website.current')" :value="'current'"></el-option>
@@ -11,8 +11,9 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<Codemirror
<codemirror ref="codeRef"
v-loading="loading"
:autofocus="true" :autofocus="true"
placeholder="" placeholder=""
:indent-with-tab="true" :indent-with-tab="true"
@@ -37,7 +38,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onMounted, reactive, ref } from 'vue'; import { computed, nextTick, onMounted, reactive, ref } from 'vue';
import { Codemirror } from 'vue-codemirror'; import { Codemirror } from 'vue-codemirror';
import { oneDark } from '@codemirror/theme-one-dark'; import { oneDark } from '@codemirror/theme-one-dark';
import { StreamLanguage } from '@codemirror/language'; import { StreamLanguage } from '@codemirror/language';
@@ -48,8 +49,9 @@ import { MsgSuccess } from '@/utils/message';
import i18n from '@/lang'; import i18n from '@/lang';
const loading = ref(false); const loading = ref(false);
const content = ref(''); const content = ref(' ');
const extensions = [StreamLanguage.define(nginx), oneDark]; const extensions = [StreamLanguage.define(nginx), oneDark];
const codeRef = ref();
const props = defineProps({ const props = defineProps({
id: { id: {
@@ -69,7 +71,7 @@ const req = reactive({
const update = reactive({ const update = reactive({
websiteID: id.value, websiteID: id.value,
content: '', content: 'd',
name: '', name: '',
}); });
@@ -80,12 +82,24 @@ const getRewriteConfig = async (rewrite: string) => {
try { try {
const res = await GetRewriteConfig(req); const res = await GetRewriteConfig(req);
content.value = res.data.content; content.value = res.data.content;
if (res.data.content == '') {
content.value = ' ';
}
setCursorPosition();
} catch (error) { } catch (error) {
} finally { } finally {
loading.value = false; loading.value = false;
} }
}; };
const setCursorPosition = () => {
nextTick(() => {
const codeMirrorInstance = codeRef.value?.codemirror;
codeMirrorInstance?.setCursor(0, 0);
});
};
const submit = async () => { const submit = async () => {
update.name = req.name; update.name = req.name;
update.websiteID = id.value; update.websiteID = id.value;
+1 -1
View File
@@ -93,7 +93,7 @@ require (
github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/distribution/distribution/v3 v3.0.0-20230223072852-e5d5810851d1 // indirect github.com/distribution/distribution/v3 v3.0.0-20230223072852-e5d5810851d1 // indirect
github.com/docker/buildx v0.10.4 // indirect github.com/docker/buildx v0.10.4 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-metrics v0.0.1 // indirect
+2
View File
@@ -201,6 +201,8 @@ github.com/docker/compose/v2 v2.17.2/go.mod h1:h5uld3t0RsL5h8rtkRaJtrFLJ3TJ9GOKd
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho= github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho=
github.com/docker/docker v23.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v23.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=