Compare commits

..
Author SHA1 Message Date
zhengkunwang223 174d60e3d6 fix: 解决网站配置文件生成错误问题 2024-06-26 15:52:00 +08:00
ssongliu 88f19b792c fix: 解决依赖升级导致的引用问题 2024-06-25 15:45:43 +08:00
ssongliu 790e9252e7 fix: 增加系统主题变化监听事件 (#5555) 2024-06-25 14:43:42 +08:00
zhengkunwang223 3d8d18db4d feat: 优化应用升级逻辑,拉取镜像失败无需回滚 2024-06-25 14:13:08 +08:00
zhengkunwang223 297e630753 feat: 优化 WAF 配置文件生成 2024-06-24 14:54:17 +08:00
ssongliu 7583196c80 fix: 解决面板主题跟随系统失效的问题 (#5547)
Refs #5527
2024-06-24 14:44:50 +08:00
zhengkunwang a06e4060a2 feat: 优化文件上传逻辑,减少临时空间占用 (#5508)
Refs https://github.com/1Panel-dev/1Panel/issues/5184
2024-06-24 14:44:40 +08:00
ssongliu 60d484bce4 fix: 解决升级导致的计划任务未执行问题 (#5483)
Refs #5414
2024-06-24 14:42:25 +08:00
ssongliu ebc6a1bd6d fix: 解决界面设置主题色不统一的问题 (#5449) 2024-06-24 14:40:42 +08:00
zhengkunwang 9bcfce14cb feat: demo 环境适配网站监控 (#5446) 2024-06-24 14:39:20 +08:00
zhengkunwang dfd84d414e fix: 解决应用安装 services 为空报系统错误的问题 (#5445) 2024-06-24 14:39:16 +08:00
zhengkunwang 1b07314c23 feat: 优化非80端口网站开启 https 端口配置 (#5443)
Refs https://github.com/1Panel-dev/1Panel/issues/5364
2024-06-24 14:39:13 +08:00
ssongliu f7e2f2dbb8 fix: 修改终端全屏按钮样式 (#5442)
Refs #5435
2024-06-24 14:38:41 +08:00
ssongliu 1a617e71bd fix: 解决浏览器切换时部分设置未同步的问题 (#5436)
Refs #5422
2024-06-24 14:38:38 +08:00
zhengkunwang 794ebfab2b fix: 解决部分情况下打开文件中文乱码的问题 (#5425)
Refs https://github.com/1Panel-dev/1Panel/issues/5374
2024-06-24 14:37:43 +08:00
zhengkunwang d33b836d3e fix: 解决升级页面 链接点击不跳转的问题 (#5413)
Refs https://github.com/1Panel-dev/1Panel/issues/5371
2024-06-24 14:37:40 +08:00
ssongliu 408997e725 fix: 解决计划任务执行周期错误的问题 (#5412)
Refs #5404
2024-06-24 14:37:13 +08:00
Frost-ZX 3ca3949b1e fix: 修正未认证设置表单初始值 (#5383) 2024-06-24 14:37:01 +08:00
ssongliu 2e05af650a fix: 解决深色模式下版本显示问题 (#5402)
Refs #5370
2024-06-24 14:36:56 +08:00
253 changed files with 2179 additions and 12698 deletions
+1
View File
@@ -0,0 +1 @@
custom: ["https://afdian.net/a/1Panel"]
-5
View File
@@ -1,10 +1,5 @@
# Contributing
As a contributor, you should agree that:
- The producer can adjust the open-source agreement to be more strict or relaxed as deemed necessary.
- Your contributed code may be used for commercial purposes, including but not limited to its cloud business operations.
## Create pull request
PR are always welcome, even if they only contain small fixes like typos or a few lines of code. If there will be a significant effort, please document it as an issue and get a discussion going before starting to work on it.
+16 -14
View File
@@ -1,32 +1,26 @@
<p align="center"><a href="https://1panel.cn"><img src="http://1panel.oss-cn-hangzhou.aliyuncs.com/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Web-based linux server management control panel</b></p>
<p align="center"><b>现代化、开源的 Linux 服务器运维管理面板</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
<a href="https://hellogithub.com/repository/71791baf930149ac9b84e1acf186573f" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=71791baf930149ac9b84e1acf186573f&claim_uid=p8vB3kP5CMrthiL&theme=dark&theme=neutral" alt="Featured|HelloGitHub" style="width: 250px; height: 55px;" width="250" height="55" /></a>
</p>
<p align="center">
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel?color=%231890FF" alt="License: GPL v3"></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"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="GitHub Stars"></a>
<a href="https://gitee.com/fit2cloud-feizhiyun/1Panel"><img src="https://gitee.com/fit2cloud-feizhiyun/1Panel/badge/star.svg?theme=gvp" alt="Gitee Stars"></a><br>
[<a href="docs/README_EN.md">English</a>] | [<a href="docs/README_TW.md">中文(繁體)</a>] | [<a href="docs/README_JP.md">日本語</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><br>
[<a href="docs/README_TW.md">中文(繁體)</a>] | [<a href="docs/README_EN.md">English</a>] | [<a href="docs/README_JP.md">日本語</a>]
</p>
[![Watch the video](https://resource.fit2cloud.com/1panel/img/overview_video.png)](https://www.bilibili.com/video/BV1Mt421n7LZ/)
------------------------------
## 什么是 1Panel?
1Panel 是新一代的 Linux 服务器运维管理面板。
- **高效管理**:用户可以通过 Web 界面轻松管理 Linux 服务器,如主机监控、文件管理、数据库管理、容器管理等;
- **高效管理**:用户可以通过 Web 图形界面轻松管理 Linux 服务器,实现主机监控、文件管理、数据库管理、容器管理等功能;
- **快速建站**:深度集成开源建站软件 WordPress 和 [Halo](https://github.com/halo-dev/halo/),域名绑定、SSL 证书配置等操作一键搞定;
- **应用商店**:精选上架各类高质量的开源工具和应用软件,协助用户轻松安装并升级;
- **安全可靠**:基于容器管理并部署应用,实现最小的漏洞暴露面,同时提供病毒防护、防火墙和日志审计等功能;
- **安全可靠**:基于容器管理并部署应用,实现最小的漏洞暴露面,同时提供防火墙和日志审计等功能;
- **一键备份**:支持一键备份和恢复,用户可以将数据备份到各类云端存储介质,永不丢失。
1Panel 三分钟速览:https://www.bilibili.com/video/BV1Mt421n7LZ/
## 快速开始
**一键安装**
@@ -45,7 +39,15 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
- [社区论坛](https://bbs.fit2cloud.com/c/1p/7)
- [如何加入微信交流群?](https://bbs.fit2cloud.com/t/topic/2147)
## 飞致云的其他明星项目
## UI 展示
![UI展示](https://resource.fit2cloud.com/1panel/img/overview.png)
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
## 我们的其他明星项目
- [MaxKB](https://github.com/1Panel-dev/MaxKB/) - 基于 LLM 大语言模型的开源知识库问答系统
- [JumpServer](https://github.com/jumpserver/jumpserver/) - 广受欢迎的开源堡垒机
+1 -1
View File
@@ -155,7 +155,7 @@ func (b *BaseApi) GetIgnoredApp(c *gin.Context) {
// @Success 200 {object} model.AppInstall
// @Security ApiKeyAuth
// @Router /apps/install [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"安装应用 [name]","formatEN":"Install app [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[{"input_column":"name","input_value":"name","isList":false,"db":"app_installs","output_column":"app_id","output_value":"appId"},{"info":"appId","isList":false,"db":"apps","output_column":"key","output_value":"appKey"}],"formatZH":"安装应用 [appKey]-[name]","formatEN":"Install app [appKey]-[name]"}
func (b *BaseApi) InstallApp(c *gin.Context) {
var req request.AppInstallCreate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
-296
View File
@@ -1,296 +0,0 @@
package v1
import (
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/gin-gonic/gin"
)
// @Tags Clam
// @Summary Create clam
// @Description 创建扫描规则
// @Accept json
// @Param request body dto.ClamCreate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /toolbox/clam [post]
// @x-panel-log {"bodyKeys":["name","path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建扫描规则 [name][path]","formatEN":"create clam [name][path]"}
func (b *BaseApi) CreateClam(c *gin.Context) {
var req dto.ClamCreate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := clamService.Create(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Clam
// @Summary Update clam
// @Description 修改扫描规则
// @Accept json
// @Param request body dto.ClamUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /toolbox/clam/update [post]
// @x-panel-log {"bodyKeys":["name","path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改扫描规则 [name][path]","formatEN":"update clam [name][path]"}
func (b *BaseApi) UpdateClam(c *gin.Context) {
var req dto.ClamUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := clamService.Update(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Clam
// @Summary Update clam status
// @Description 修改扫描规则状态
// @Accept json
// @Param request body dto.ClamUpdateStatus true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /toolbox/clam/status/update [post]
// @x-panel-log {"bodyKeys":["id","status"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"clams","output_column":"name","output_value":"name"}],"formatZH":"修改扫描规则 [name] 状态为 [status]","formatEN":"change the status of clam [name] to [status]."}
func (b *BaseApi) UpdateClamStatus(c *gin.Context) {
var req dto.ClamUpdateStatus
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := clamService.UpdateStatus(req.ID, req.Status); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Clam
// @Summary Page clam
// @Description 获取扫描规则列表分页
// @Accept json
// @Param request body dto.SearchClamWithPage true "request"
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /toolbox/clam/search [post]
func (b *BaseApi) SearchClam(c *gin.Context) {
var req dto.SearchClamWithPage
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
total, list, err := clamService.SearchWithPage(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, dto.PageResult{
Items: list,
Total: total,
})
}
// @Tags Clam
// @Summary Load clam base info
// @Description 获取 Clam 基础信息
// @Accept json
// @Success 200 {object} dto.ClamBaseInfo
// @Security ApiKeyAuth
// @Router /toolbox/clam/base [get]
func (b *BaseApi) LoadClamBaseInfo(c *gin.Context) {
info, err := clamService.LoadBaseInfo()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, info)
}
// @Tags Clam
// @Summary Operate Clam
// @Description 修改 Clam 状态
// @Accept json
// @Param request body dto.Operate true "request"
// @Security ApiKeyAuth
// @Router /toolbox/clam/operate [post]
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operation] Clam","formatEN":"[operation] FTP"}
func (b *BaseApi) OperateClam(c *gin.Context) {
var req dto.Operate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := clamService.Operate(req.Operation); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Clam
// @Summary Clean clam record
// @Description 清空扫描报告
// @Accept json
// @Param request body dto.OperateByID true "request"
// @Security ApiKeyAuth
// @Router /toolbox/clam/record/clean [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":true,"db":"clams","output_column":"name","output_value":"name"}],"formatZH":"清空扫描报告 [name]","formatEN":"clean clam record [name]"}
func (b *BaseApi) CleanClamRecord(c *gin.Context) {
var req dto.OperateByID
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := clamService.CleanRecord(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Clam
// @Summary Page clam record
// @Description 获取扫描结果列表分页
// @Accept json
// @Param request body dto.ClamLogSearch true "request"
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /toolbox/clam/record/search [post]
func (b *BaseApi) SearchClamRecord(c *gin.Context) {
var req dto.ClamLogSearch
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
total, list, err := clamService.LoadRecords(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, dto.PageResult{
Items: list,
Total: total,
})
}
// @Tags Clam
// @Summary Load clam record detail
// @Description 获取扫描结果详情
// @Accept json
// @Param request body dto.ClamLogReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /toolbox/clam/record/log [post]
func (b *BaseApi) LoadClamRecordLog(c *gin.Context) {
var req dto.ClamLogReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
content, err := clamService.LoadRecordLog(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, content)
}
// @Tags Clam
// @Summary Load clam file
// @Description 获取扫描文件
// @Accept json
// @Param request body dto.ClamFileReq true "request"
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /toolbox/clam/file/search [post]
func (b *BaseApi) SearchClamFile(c *gin.Context) {
var req dto.ClamFileReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
content, err := clamService.LoadFile(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, content)
}
// @Tags Clam
// @Summary Update clam file
// @Description 更新病毒扫描配置文件
// @Accept json
// @Param request body dto.UpdateByNameAndFile true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /toolbox/clam/file/update [post]
func (b *BaseApi) UpdateFile(c *gin.Context) {
var req dto.UpdateByNameAndFile
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := clamService.UpdateFile(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Clam
// @Summary Delete clam
// @Description 删除扫描规则
// @Accept json
// @Param request body dto.ClamDelete true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /toolbox/clam/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"clams","output_column":"name","output_value":"names"}],"formatZH":"删除扫描规则 [names]","formatEN":"delete clam [names]"}
func (b *BaseApi) DeleteClam(c *gin.Context) {
var req dto.ClamDelete
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := clamService.Delete(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Clam
// @Summary Handle clam scan
// @Description 执行病毒扫描
// @Accept json
// @Param request body dto.OperateByID true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /toolbox/clam/handle [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":true,"db":"clams","output_column":"name","output_value":"name"}],"formatZH":"执行病毒扫描 [name]","formatEN":"handle clam scan [name]"}
func (b *BaseApi) HandleClamScan(c *gin.Context) {
var req dto.OperateByID
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := clamService.HandleOnce(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
-34
View File
@@ -7,7 +7,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"strconv"
)
// @Tags Container
@@ -347,26 +346,6 @@ func (b *BaseApi) ContainerRename(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags Container
// @Summary Commit Container
// @Description 容器提交生成新镜像
// @Accept json
// @Param request body dto.ContainerCommit true "request"
// @Success 200
// @Router /containers/commit [post]
func (b *BaseApi) ContainerCommit(c *gin.Context) {
var req dto.ContainerCommit
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := containerService.ContainerCommit(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Container
// @Summary Operate Container
// @Description 容器操作
@@ -461,19 +440,6 @@ func (b *BaseApi) ContainerLogs(c *gin.Context) {
}
}
// @Description 下载容器日志
// @Router /containers/download/log [post]
func (b *BaseApi) DownloadContainerLogs(c *gin.Context) {
var req dto.ContainerLog
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
err := containerService.DownloadContainerLogs(req.ContainerType, req.Container, req.Since, strconv.Itoa(int(req.Tail)), c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
}
}
// @Tags Container Network
// @Summary Page networks
// @Description 获取容器网络列表分页
+2 -2
View File
@@ -36,12 +36,12 @@ func (b *BaseApi) CreateCronjob(c *gin.Context) {
// @Summary Page cronjobs
// @Description 获取计划任务分页
// @Accept json
// @Param request body dto.PageCronjob true "request"
// @Param request body dto.SearchWithPage true "request"
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /cronjobs/search [post]
func (b *BaseApi) SearchCronjob(c *gin.Context) {
var req dto.PageCronjob
var req dto.SearchWithPage
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
-1
View File
@@ -38,7 +38,6 @@ var (
deviceService = service.NewIDeviceService()
fail2banService = service.NewIFail2BanService()
ftpService = service.NewIFtpService()
clamService = service.NewIClamService()
settingService = service.NewISettingService()
backupService = service.NewIBackupService()
+4 -25
View File
@@ -11,7 +11,6 @@ import (
"path/filepath"
"strconv"
"strings"
"syscall"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
@@ -337,12 +336,8 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
return
}
mode := info.Mode()
fileOp := files.NewFileOp()
stat, ok := info.Sys().(*syscall.Stat_t)
uid, gid := -1, -1
if ok {
uid, gid = int(stat.Uid), int(stat.Gid)
}
success := 0
failures := make(buserr.MultiErr)
@@ -356,7 +351,6 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
global.LOG.Error(e)
continue
}
_ = os.Chown(dstDir, uid, gid)
}
tmpFilename := dstFilename + ".tmp"
if err := c.SaveUploadedFile(file, tmpFilename); err != nil {
@@ -384,9 +378,6 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
} else {
_ = os.Chmod(dstFilename, mode)
}
if uid != -1 && gid != -1 {
_ = os.Chown(dstFilename, uid, gid)
}
success++
}
if success == 0 {
@@ -612,17 +603,9 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int,
if mode == 0 {
mode = 0755
}
uid, gid := -1, -1
if info, err := os.Stat(dstDir); err != nil {
if os.IsNotExist(err) {
if err = op.CreateDir(dstDir, mode); err != nil {
return err
}
}
} else {
stat, ok := info.Sys().(*syscall.Stat_t)
if ok {
uid, gid = int(stat.Uid), int(stat.Gid)
if _, err := os.Stat(dstDir); err != nil && os.IsNotExist(err) {
if err = op.CreateDir(dstDir, mode); err != nil {
return err
}
}
dstFileName := filepath.Join(dstDir, fileName)
@@ -632,7 +615,6 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int,
} else {
mode = 0644
}
if overwrite {
_ = os.Remove(dstFileName)
}
@@ -653,9 +635,6 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int,
}
_ = os.Remove(chunkPath)
}
if uid != -1 && gid != -1 {
_ = os.Chown(dstFileName, uid, gid)
}
return nil
}
-23
View File
@@ -94,29 +94,6 @@ func (b *BaseApi) OperatePortRule(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// OperateForwardRule
// @Tags Firewall
// @Summary Create group
// @Description 更新防火墙端口转发规则
// @Accept json
// @Param request body dto.ForwardRuleOperate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/firewall/forward [post]
// @x-panel-log {"bodyKeys":["source_port"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新端口转发规则 [source_port]","formatEN":"update port forward rules [source_port]"}
func (b *BaseApi) OperateForwardRule(c *gin.Context) {
var req dto.ForwardRuleOperate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := firewallService.OperateForwardRule(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Firewall
// @Summary Create group
// @Description 创建防火墙 IP 规则
-42
View File
@@ -778,45 +778,3 @@ func (b *BaseApi) GetDirConfig(c *gin.Context) {
}
helper.SuccessWithData(c, res)
}
// @Tags Website
// @Summary Get default html
// @Description 获取默认 html
// @Accept json
// @Success 200 {object} response.FileInfo
// @Security ApiKeyAuth
// @Router /websites/default/html/:type [get]
func (b *BaseApi) GetDefaultHtml(c *gin.Context) {
resourceType, err := helper.GetStrParamByKey(c, "type")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
return
}
fileInfo, err := websiteService.GetDefaultHtml(resourceType)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, fileInfo)
}
// @Tags Website
// @Summary Update default html
// @Description 更新默认 html
// @Accept json
// @Param request body request.WebsiteHtmlUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/default/html/update [post]
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新默认 html","formatEN":"Update default html"}
func (b *BaseApi) UpdateDefaultHtml(c *gin.Context) {
var req request.WebsiteHtmlUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := websiteService.UpdateDefaultHtml(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
-33
View File
@@ -6,9 +6,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/gin-gonic/gin"
"net/http"
"net/url"
"strconv"
)
// @Tags Website CA
@@ -145,33 +142,3 @@ func (b *BaseApi) RenewWebsiteCA(c *gin.Context) {
}
helper.SuccessWithOutData(c)
}
// @Tags Website CA
// @Summary Download CA file
// @Description 下载 CA 证书文件
// @Accept json
// @Param request body request.WebsiteResourceReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/ca/download [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_cas","output_column":"name","output_value":"name"}],"formatZH":"下载 CA 证书文件 [name]","formatEN":"download ca file [name]"}
func (b *BaseApi) DownloadCAFile(c *gin.Context) {
var req request.WebsiteResourceReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
file, err := websiteCAService.DownloadFile(req.ID)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
defer file.Close()
info, err := file.Stat()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
http.ServeContent(c.Writer, c.Request, info.Name(), info.ModTime(), file)
}
-1
View File
@@ -236,7 +236,6 @@ func (b *BaseApi) DownloadWebsiteSSL(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
defer file.Close()
info, err := file.Stat()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
-96
View File
@@ -1,96 +0,0 @@
package dto
import (
"time"
)
type SearchClamWithPage struct {
PageInfo
Info string `json:"info"`
OrderBy string `json:"orderBy" validate:"required,oneof=name status created_at"`
Order string `json:"order" validate:"required,oneof=null ascending descending"`
}
type ClamBaseInfo struct {
Version string `json:"version"`
IsActive bool `json:"isActive"`
IsExist bool `json:"isExist"`
FreshVersion string `json:"freshVersion"`
FreshIsActive bool `json:"freshIsActive"`
FreshIsExist bool `json:"freshIsExist"`
}
type ClamInfo struct {
ID uint `json:"id"`
CreatedAt time.Time `json:"createdAt"`
Name string `json:"name"`
Status string `json:"status"`
Path string `json:"path"`
InfectedStrategy string `json:"infectedStrategy"`
InfectedDir string `json:"infectedDir"`
LastHandleDate string `json:"lastHandleDate"`
Spec string `json:"spec"`
Description string `json:"description"`
}
type ClamLogSearch struct {
PageInfo
ClamID uint `json:"clamID"`
StartTime time.Time `json:"startTime"`
EndTime time.Time `json:"endTime"`
}
type ClamLogReq struct {
Tail string `json:"tail"`
ClamName string `json:"clamName"`
RecordName string `json:"recordName"`
}
type ClamFileReq struct {
Tail string `json:"tail"`
Name string `json:"name" validate:"required"`
}
type ClamLog struct {
Name string `json:"name"`
ScanDate string `json:"scanDate"`
ScanTime string `json:"scanTime"`
InfectedFiles string `json:"infectedFiles"`
TotalError string `json:"totalError"`
Status string `json:"status"`
}
type ClamCreate struct {
Name string `json:"name"`
Status string `json:"status"`
Path string `json:"path"`
InfectedStrategy string `json:"infectedStrategy"`
InfectedDir string `json:"infectedDir"`
Spec string `json:"spec"`
Description string `json:"description"`
}
type ClamUpdate struct {
ID uint `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
InfectedStrategy string `json:"infectedStrategy"`
InfectedDir string `json:"infectedDir"`
Spec string `json:"spec"`
Description string `json:"description"`
}
type ClamUpdateStatus struct {
ID uint `json:"id"`
Status string `json:"status"`
}
type ClamDelete struct {
RemoveRecord bool `json:"removeRecord"`
RemoveInfected bool `json:"removeInfected"`
Ids []uint `json:"ids" validate:"required"`
}
+3 -3
View File
@@ -1,9 +1,9 @@
package dto
type SearchCommandWithPage struct {
PageInfo
OrderBy string `json:"orderBy" validate:"required,oneof=name command created_at"`
Order string `json:"order" validate:"required,oneof=null ascending descending"`
SearchWithPage
OrderBy string `json:"orderBy"`
Order string `json:"order"`
GroupID uint `json:"groupID"`
Info string `json:"info"`
Name string `json:"name"`
+3 -1
View File
@@ -2,7 +2,9 @@ package dto
type SearchWithPage struct {
PageInfo
Info string `json:"info"`
Info string `json:"info"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
}
type PageInfo struct {
+3 -21
View File
@@ -1,15 +1,13 @@
package dto
import (
"time"
)
import "time"
type PageContainer struct {
PageInfo
Name string `json:"name"`
State string `json:"state" validate:"required,oneof=all created running paused restarting removing exited dead"`
OrderBy string `json:"orderBy" validate:"required,oneof=name state created_at"`
Order string `json:"order" validate:"required,oneof=null ascending descending"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
Filters string `json:"filters"`
ExcludeAppStore bool `json:"excludeAppStore"`
}
@@ -124,15 +122,6 @@ type ContainerRename struct {
NewName string `json:"newName" validate:"required"`
}
type ContainerCommit struct {
ContainerId string `json:"containerID" validate:"required"`
ContainerName string `json:"containerName"`
NewImageName string `json:"newImageName"`
Comment string `json:"comment"`
Author string `json:"author"`
Pause bool `json:"pause"`
}
type ContainerPrune struct {
PruneType string `json:"pruneType" validate:"required,oneof=container image volume network buildcache"`
WithTagAll bool `json:"withTagAll"`
@@ -225,10 +214,3 @@ type ComposeUpdate struct {
Path string `json:"path" validate:"required"`
Content string `json:"content" validate:"required"`
}
type ContainerLog struct {
Container string `json:"container" validate:"required"`
Since string `json:"since"`
Tail uint `json:"tail"`
ContainerType string `json:"containerType"`
}
-7
View File
@@ -4,13 +4,6 @@ import (
"time"
)
type PageCronjob struct {
PageInfo
Info string `json:"info"`
OrderBy string `json:"orderBy" validate:"required,oneof=name status created_at"`
Order string `json:"order" validate:"required,oneof=null ascending descending"`
}
type CronjobCreate struct {
Name string `json:"name" validate:"required"`
Type string `json:"type" validate:"required"`
-2
View File
@@ -30,8 +30,6 @@ type OsInfo struct {
PlatformFamily string `json:"platformFamily"`
KernelArch string `json:"kernelArch"`
KernelVersion string `json:"kernelVersion"`
DiskSize int64 `json:"diskSize"`
}
type DashboardCurrent struct {
+7 -7
View File
@@ -27,8 +27,8 @@ type MysqlDBSearch struct {
PageInfo
Info string `json:"info"`
Database string `json:"database" validate:"required"`
OrderBy string `json:"orderBy" validate:"required,oneof=name created_at"`
Order string `json:"order" validate:"required,oneof=null ascending descending"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
}
type MysqlDBInfo struct {
@@ -139,7 +139,7 @@ type MysqlVariables struct {
MaxConnections string `json:"max_connections"`
MaxHeapTableSize string `json:"max_heap_table_size"`
QueryCacheSize string `json:"query_cache_size"`
QueryCacheType string `json:"query_cache_type"`
QueryCache_type string `json:"query_cache_type"`
ReadBufferSize string `json:"read_buffer_size"`
ReadRndBufferSize string `json:"read_rnd_buffer_size"`
SortBufferSize string `json:"sort_buffer_size"`
@@ -207,8 +207,8 @@ type RedisStatus struct {
UptimeInDays string `json:"uptime_in_days"`
ConnectedClients string `json:"connected_clients"`
UsedMemory string `json:"used_memory"`
UsedMemoryRss string `json:"used_memory_rss"`
UsedMemoryPeak string `json:"used_memory_peak"`
UsedMemory_rss string `json:"used_memory_rss"`
UsedMemory_peak string `json:"used_memory_peak"`
MemFragmentationRatio string `json:"mem_fragmentation_ratio"`
TotalConnectionsReceived string `json:"total_connections_received"`
TotalCommandsProcessed string `json:"total_commands_processed"`
@@ -236,8 +236,8 @@ type DatabaseSearch struct {
PageInfo
Info string `json:"info"`
Type string `json:"type"`
OrderBy string `json:"orderBy" validate:"required,oneof=name created_at"`
Order string `json:"order" validate:"required,oneof=null ascending descending"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
}
type DatabaseInfo struct {
+2 -2
View File
@@ -6,8 +6,8 @@ type PostgresqlDBSearch struct {
PageInfo
Info string `json:"info"`
Database string `json:"database" validate:"required"`
OrderBy string `json:"orderBy" validate:"required,oneof=name created_at"`
Order string `json:"order" validate:"required,oneof=null ascending descending"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
}
type PostgresqlDBInfo struct {
-11
View File
@@ -29,17 +29,6 @@ type PortRuleOperate struct {
Description string `json:"description"`
}
type ForwardRuleOperate struct {
Rules []struct {
Operation string `json:"operation" validate:"required,oneof=add remove"`
Num string `json:"num"`
Protocol string `json:"protocol" validate:"required,oneof=tcp udp tcp/udp"`
Port string `json:"port" validate:"required"`
TargetIP string `json:"targetIP"`
TargetPort string `json:"targetPort" validate:"required"`
} `json:"rules"`
}
type UpdateFirewallDescription struct {
Type string `json:"type"`
Address string `json:"address"`
+1 -3
View File
@@ -10,8 +10,7 @@ type FileOption struct {
}
type FileContentReq struct {
Path string `json:"path" validate:"required"`
IsDetail bool `json:"isDetail"`
Path string `json:"path" validate:"required"`
}
type SearchUploadWithPage struct {
@@ -127,7 +126,6 @@ type FileReadByLineReq struct {
Type string `json:"type" validate:"required"`
ID uint `json:"ID"`
Name string `json:"name"`
Latest bool `json:"latest"`
}
type FileExistReq struct {
+3 -14
View File
@@ -7,8 +7,8 @@ import (
type WebsiteSearch struct {
dto.PageInfo
Name string `json:"name"`
OrderBy string `json:"orderBy" validate:"required,oneof=primary_domain type status created_at expire_date"`
Order string `json:"order" validate:"required,oneof=null ascending descending"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
WebsiteGroupID uint `json:"websiteGroupId"`
}
@@ -55,7 +55,7 @@ type WebsiteUpdate struct {
ID uint `json:"id" validate:"required"`
PrimaryDomain string `json:"primaryDomain" validate:"required"`
Remark string `json:"remark"`
WebsiteGroupID uint `json:"webSiteGroupID"`
WebsiteGroupID uint `json:"webSiteGroupID" validate:"required"`
ExpireDate string `json:"expireDate"`
IPV6 bool `json:"IPV6"`
}
@@ -123,7 +123,6 @@ type WebsiteHTTPSOp struct {
HttpConfig string `json:"httpConfig" validate:"oneof=HTTPSOnly HTTPAlso HTTPToHTTPS"`
SSLProtocol []string `json:"SSLProtocol"`
Algorithm string `json:"algorithm"`
Hsts bool `json:"hsts"`
}
type WebsiteNginxUpdate struct {
@@ -189,7 +188,6 @@ type WebsiteProxyConfig struct {
Content string `json:"content"`
FilePath string `json:"filePath"`
Replaces map[string]string `json:"replaces"`
SNI bool `json:"sni"`
}
type WebsiteProxyReq struct {
@@ -209,12 +207,3 @@ type WafWebsite struct {
Domains []string `json:"domains"`
Host []string `json:"host"`
}
type WebsiteHtmlReq struct {
Type string `json:"type" validate:"required"`
}
type WebsiteHtmlUpdate struct {
Type string `json:"type" validate:"required"`
Content string `json:"content" validate:"required"`
}
-6
View File
@@ -24,8 +24,6 @@ type WebsiteSSLCreate struct {
SkipDNS bool `json:"skipDNS"`
Nameserver1 string `json:"nameserver1"`
Nameserver2 string `json:"nameserver2"`
ExecShell bool `json:"execShell"`
Shell string `json:"shell"`
}
type WebsiteDNSReq struct {
@@ -89,8 +87,6 @@ type WebsiteSSLUpdate struct {
SkipDNS bool `json:"skipDNS"`
Nameserver1 string `json:"nameserver1"`
Nameserver2 string `json:"nameserver2"`
ExecShell bool `json:"execShell"`
Shell string `json:"shell"`
}
type WebsiteSSLUpload struct {
@@ -130,8 +126,6 @@ type WebsiteCAObtain struct {
Renew bool `json:"renew"`
SSLID uint `json:"sslID"`
Description string `json:"description"`
ExecShell bool `json:"execShell"`
Shell string `json:"shell"`
}
type WebsiteCARenew struct {
+4 -7
View File
@@ -15,12 +15,10 @@ type UploadInfo struct {
}
type FileTree struct {
ID string `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
IsDir bool `json:"isDir"`
Extension string `json:"extension"`
Children []FileTree `json:"children"`
ID string `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
Children []FileTree `json:"children"`
}
type DirSizeRes struct {
@@ -39,7 +37,6 @@ type FileLineContent struct {
Content string `json:"content"`
End bool `json:"end"`
Path string `json:"path"`
Total int `json:"total"`
}
type FileExist struct {
-24
View File
@@ -2,7 +2,6 @@ package response
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"time"
)
type WebsiteDTO struct {
@@ -12,24 +11,6 @@ type WebsiteDTO struct {
SitePath string `json:"sitePath"`
AppName string `json:"appName"`
RuntimeName string `json:"runtimeName"`
SiteDir string `gorm:"type:varchar;" json:"siteDir"`
}
type WebsiteRes struct {
ID uint `json:"id"`
CreatedAt time.Time `json:"createdAt"`
Protocol string `json:"protocol"`
PrimaryDomain string `json:"primaryDomain"`
Type string `json:"type"`
Alias string `json:"alias"`
Remark string `json:"remark"`
Status string `json:"status"`
ExpireDate time.Time `json:"expireDate"`
SitePath string `json:"sitePath"`
AppName string `json:"appName"`
RuntimeName string `json:"runtimeName"`
SSLExpireDate time.Time `json:"sslExpireDate"`
SSLStatus string `json:"sslStatus"`
}
type WebsiteOption struct {
@@ -56,7 +37,6 @@ type WebsiteHTTPS struct {
SSL model.WebsiteSSL `json:"SSL"`
SSLProtocol []string `json:"SSLProtocol"`
Algorithm string `json:"algorithm"`
Hsts bool `json:"hsts"`
}
type WebsiteLog struct {
@@ -82,7 +62,3 @@ type WebsiteDirConfig struct {
UserGroup string `json:"userGroup"`
Msg string `json:"msg"`
}
type WebsiteHtmlRes struct {
Content string `json:"content"`
}
-1
View File
@@ -143,7 +143,6 @@ type SnapshotInfo struct {
Message string `json:"message"`
CreatedAt time.Time `json:"createdAt"`
Version string `json:"version"`
Size int64 `json:"size"`
InterruptStep string `json:"interruptStep"`
RecoverStatus string `json:"recoverStatus"`
-14
View File
@@ -1,14 +0,0 @@
package model
type Clam struct {
BaseModel
Name string `gorm:"type:varchar(64);not null" json:"name"`
Status string `gorm:"type:varchar(64)" json:"status"`
Path string `gorm:"type:varchar(64);not null" json:"path"`
InfectedStrategy string `gorm:"type:varchar(64)" json:"infectedStrategy"`
InfectedDir string `gorm:"type:varchar(64)" json:"infectedDir"`
Spec string `gorm:"type:varchar(64)" json:"spec"`
EntryID int `gorm:"type:varchar(64)" json:"entryID"`
Description string `gorm:"type:varchar(64)" json:"description"`
}
-9
View File
@@ -10,12 +10,3 @@ type Firewall struct {
Strategy string `gorm:"type:varchar(64);not null" json:"strategy"`
Description string `gorm:"type:varchar(64);not null" json:"description"`
}
type Forward struct {
BaseModel
Protocol string `gorm:"type:varchar(64);not null" json:"protocol"`
Port string `gorm:"type:varchar(64);not null" json:"port"`
TargetIP string `gorm:"type:varchar(64);not null" json:"targetIP"`
TargetPort string `gorm:"type:varchar(64);not null" json:"targetPort"`
}
-2
View File
@@ -33,8 +33,6 @@ type WebsiteSSL struct {
Nameserver1 string `json:"nameserver1"`
Nameserver2 string `json:"nameserver2"`
DisableCNAME bool `json:"disableCNAME"`
ExecShell bool `json:"execShell"`
Shell string `json:"shell"`
AcmeAccount WebsiteAcmeAccount `json:"acmeAccount" gorm:"-:migration"`
DnsAccount WebsiteDnsAccount `json:"dnsAccount" gorm:"-:migration"`
-69
View File
@@ -1,69 +0,0 @@
package repo
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
)
type ClamRepo struct{}
type IClamRepo interface {
Page(limit, offset int, opts ...DBOption) (int64, []model.Clam, error)
Create(clam *model.Clam) error
Update(id uint, vars map[string]interface{}) error
Delete(opts ...DBOption) error
Get(opts ...DBOption) (model.Clam, error)
List(opts ...DBOption) ([]model.Clam, error)
}
func NewIClamRepo() IClamRepo {
return &ClamRepo{}
}
func (u *ClamRepo) Get(opts ...DBOption) (model.Clam, error) {
var clam model.Clam
db := global.DB
for _, opt := range opts {
db = opt(db)
}
err := db.First(&clam).Error
return clam, err
}
func (u *ClamRepo) List(opts ...DBOption) ([]model.Clam, error) {
var clam []model.Clam
db := global.DB
for _, opt := range opts {
db = opt(db)
}
err := db.Find(&clam).Error
return clam, err
}
func (u *ClamRepo) Page(page, size int, opts ...DBOption) (int64, []model.Clam, error) {
var users []model.Clam
db := global.DB.Model(&model.Clam{})
for _, opt := range opts {
db = opt(db)
}
count := int64(0)
db = db.Count(&count)
err := db.Limit(size).Offset(size * (page - 1)).Find(&users).Error
return count, users, err
}
func (u *ClamRepo) Create(clam *model.Clam) error {
return global.DB.Create(clam).Error
}
func (u *ClamRepo) Update(id uint, vars map[string]interface{}) error {
return global.DB.Model(&model.Clam{}).Where("id = ?", id).Updates(vars).Error
}
func (u *ClamRepo) Delete(opts ...DBOption) error {
db := global.DB
for _, opt := range opts {
db = opt(db)
}
return db.Delete(&model.Clam{}).Error
}
+1 -1
View File
@@ -96,7 +96,7 @@ func (w *WebsiteRepo) Page(page, size int, opts ...DBOption) (int64, []model.Web
db := getDb(opts...).Model(&model.Website{})
count := int64(0)
db = db.Count(&count)
err := db.Debug().Limit(size).Offset(size * (page - 1)).Preload("WebsiteSSL").Find(&websites).Error
err := db.Limit(size).Offset(size * (page - 1)).Preload("WebsiteSSL").Find(&websites).Error
return count, websites, err
}
+7 -3
View File
@@ -145,9 +145,6 @@ func (a AppService) GetAppTags() ([]response.TagDTO, error) {
func (a AppService) GetApp(key string) (*response.AppDTO, error) {
var appDTO response.AppDTO
if key == "postgres" {
key = "postgresql"
}
app, err := appRepo.GetFirst(appRepo.WithKey(key))
if err != nil {
return nil, err
@@ -448,6 +445,13 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
}
appInstall.Env = string(paramByte)
containerNames, err := getContainerNames(*appInstall)
if err != nil {
return
}
if len(containerNames) > 0 {
appInstall.ContainerName = strings.Join(containerNames, ",")
}
if err = appInstallRepo.Create(ctx, appInstall); err != nil {
return
}
+1 -1
View File
@@ -782,7 +782,7 @@ func updateInstallInfoInDB(appKey, appName, param string, value interface{}) err
}
case "port":
envKey = "PANEL_APP_PORT_HTTP="
default:
case "user-password":
envKey = "PANEL_DB_USER_PASSWORD="
}
files := strings.Split(string(lineBytes), "\n")
-7
View File
@@ -943,13 +943,6 @@ func upApp(appInstall *model.AppInstall, pullImages bool) {
}
exist, _ := appInstallRepo.GetFirst(commonRepo.WithByID(appInstall.ID))
if exist.ID > 0 {
containerNames, err := getContainerNames(*appInstall)
if err != nil {
return
}
if len(containerNames) > 0 {
appInstall.ContainerName = strings.Join(containerNames, ",")
}
_ = appInstallRepo.Save(context.Background(), appInstall)
}
}
+19 -11
View File
@@ -364,7 +364,7 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
dirStr = dirStr[:strings.LastIndex(dirStr, "/")]
}
if err := copyDir(oldDir, dirStr); err != nil {
_ = backupRepo.Update(req.ID, map[string]interface{}{"vars": oldVars})
_ = backupRepo.Update(req.ID, (map[string]interface{}{"vars": oldVars}))
return err
}
global.CONF.System.Backup = dirStr
@@ -414,6 +414,8 @@ func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.Cl
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo:
varMap["accessKey"] = backup.AccessKey
varMap["secretKey"] = backup.Credential
case constant.OneDrive:
varMap["accessToken"] = backup.Credential
}
backClient, err := cloud_storage.NewCloudStorageClient(backup.Type, varMap)
@@ -451,13 +453,14 @@ func (u *BackupService) loadAccessToken(backup *model.BackupAccount) error {
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
return fmt.Errorf("unmarshal backup vars failed, err: %v", err)
}
refreshToken, err := client.RefreshToken("authorization_code", "refreshToken", varMap)
token, refreshToken, err := client.RefreshToken("authorization_code", varMap)
if err != nil {
return err
}
delete(varMap, "code")
backup.Credential = token
varMap["refresh_status"] = constant.StatusSuccess
varMap["refresh_time"] = time.Now().Format(constant.DateTimeLayout)
varMap["refresh_time"] = time.Now().Format("2006-01-02 15:04:05")
varMap["refresh_token"] = refreshToken
itemVars, err := json.Marshal(varMap)
if err != nil {
@@ -584,10 +587,10 @@ func (u *BackupService) checkBackupConn(backup *model.BackupAccount) (bool, erro
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString("1Panel 备份账号测试文件。\n")
_, _ = write.WriteString("1Panel 備份賬號測試文件。\n")
_, _ = write.WriteString("1Panel Backs up account test files.\n")
_, _ = write.WriteString("1Panelアカウントのテストファイルをバックアップします。\n")
_, _ = write.WriteString(string("1Panel 备份账号测试文件。\n"))
_, _ = write.WriteString(string("1Panel 備份賬號測試文件。\n"))
_, _ = write.WriteString(string("1Panel Backs up account test files.\n"))
_, _ = write.WriteString(string("1Panelアカウントのテストファイルをバックアップします。\n"))
write.Flush()
targetPath := strings.TrimPrefix(path.Join(backup.BackupPath, "test/1panel"), "/")
@@ -596,7 +599,7 @@ func (u *BackupService) checkBackupConn(backup *model.BackupAccount) (bool, erro
func StartRefreshOneDriveToken() {
service := NewIBackupService()
oneDriveCronID, err := global.Cron.AddJob("0 3 */31 * *", service)
oneDriveCronID, err := global.Cron.AddJob("0 * * * *", service)
if err != nil {
global.LOG.Errorf("can not add OneDrive corn job: %s", err.Error())
return
@@ -610,15 +613,19 @@ func (u *BackupService) Run() {
if backupItem.ID == 0 {
return
}
if len(backupItem.Credential) == 0 {
global.LOG.Error("OneDrive configuration lacks token information, please rebind.")
return
}
global.LOG.Info("start to refresh token of OneDrive ...")
varMap := make(map[string]interface{})
if err := json.Unmarshal([]byte(backupItem.Vars), &varMap); err != nil {
global.LOG.Errorf("Failed to refresh OneDrive token, please retry, err: %v", err)
return
}
refreshToken, err := client.RefreshToken("refresh_token", "refreshToken", varMap)
token, refreshToken, err := client.RefreshToken("refresh_token", varMap)
varMap["refresh_status"] = constant.StatusSuccess
varMap["refresh_time"] = time.Now().Format(constant.DateTimeLayout)
varMap["refresh_time"] = time.Now().Format("2006-01-02 15:04:05")
if err != nil {
varMap["refresh_status"] = constant.StatusFailed
varMap["refresh_msg"] = err.Error()
@@ -631,7 +638,8 @@ func (u *BackupService) Run() {
_ = global.DB.Model(&model.BackupAccount{}).
Where("id = ?", backupItem.ID).
Updates(map[string]interface{}{
"vars": varsItem,
"credential": token,
"vars": varsItem,
}).Error
global.LOG.Info("Successfully refreshed OneDrive token.")
}
+2 -2
View File
@@ -35,7 +35,7 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) (*model.BackupRecord, er
if err != nil {
return nil, err
}
timeNow := time.Now().Format(constant.DateTimeSlimLayout)
timeNow := time.Now().Format("20060102150405")
itemDir := fmt.Sprintf("app/%s/%s", req.Name, req.DetailName)
backupDir := path.Join(localDir, itemDir)
@@ -163,7 +163,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
}
if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s_%s.tar.gz", install.Name, time.Now().Format(constant.DateTimeSlimLayout)))
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s_%s.tar.gz", install.Name, time.Now().Format("20060102150405")))
if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile), "", ""); err != nil {
return fmt.Errorf("backup app %s for rollback before recover failed, err: %v", install.Name, err)
}
+3 -4
View File
@@ -2,7 +2,6 @@ package service
import (
"fmt"
"github.com/1Panel-dev/1Panel/backend/constant"
"os"
"path"
"path/filepath"
@@ -25,7 +24,7 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
return err
}
timeNow := time.Now().Format(constant.DateTimeSlimLayout)
timeNow := time.Now().Format("20060102150405")
itemDir := fmt.Sprintf("database/%s/%s/%s", req.Type, req.Name, req.DetailName)
targetDir := path.Join(localDir, itemDir)
fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow+common.RandStrAndNum(5))
@@ -60,7 +59,7 @@ func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error {
file := req.File
fileName := path.Base(req.File)
if strings.HasSuffix(fileName, ".tar.gz") {
fileNameItem := time.Now().Format(constant.DateTimeSlimLayout)
fileNameItem := time.Now().Format("20060102150405")
dstDir := fmt.Sprintf("%s/%s", path.Dir(req.File), fileNameItem)
if _, err := os.Stat(dstDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dstDir, os.ModePerm); err != nil {
@@ -143,7 +142,7 @@ func handleMysqlRecover(req dto.CommonRecover, isRollback bool) error {
}
if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format(constant.DateTimeSlimLayout)))
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format("20060102150405")))
if err := cli.Backup(client.BackupInfo{
Name: req.DetailName,
Type: req.Type,
+3 -4
View File
@@ -2,7 +2,6 @@ package service
import (
"fmt"
"github.com/1Panel-dev/1Panel/backend/constant"
"os"
"path"
"path/filepath"
@@ -26,7 +25,7 @@ func (u *BackupService) PostgresqlBackup(req dto.CommonBackup) error {
return err
}
timeNow := time.Now().Format(constant.DateTimeSlimLayout)
timeNow := time.Now().Format("20060102150405")
itemDir := fmt.Sprintf("database/%s/%s/%s", req.Type, req.Name, req.DetailName)
targetDir := path.Join(localDir, itemDir)
fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow+common.RandStrAndNum(5))
@@ -60,7 +59,7 @@ func (u *BackupService) PostgresqlRecoverByUpload(req dto.CommonRecover) error {
file := req.File
fileName := path.Base(req.File)
if strings.HasSuffix(fileName, ".tar.gz") {
fileNameItem := time.Now().Format(constant.DateTimeSlimLayout)
fileNameItem := time.Now().Format("20060102150405")
dstDir := fmt.Sprintf("%s/%s", path.Dir(req.File), fileNameItem)
if _, err := os.Stat(dstDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dstDir, os.ModePerm); err != nil {
@@ -137,7 +136,7 @@ func handlePostgresqlRecover(req dto.CommonRecover, isRollback bool) error {
defer cli.Close()
if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format(constant.DateTimeSlimLayout)))
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format("20060102150405")))
if err := cli.Backup(client.BackupInfo{
Name: req.DetailName,
TargetDir: path.Dir(rollbackFile),
+2 -2
View File
@@ -35,7 +35,7 @@ func (u *BackupService) RedisBackup(db dto.CommonBackup) error {
}
global.LOG.Infof("appendonly in redis conf is %s", appendonly)
timeNow := time.Now().Format(constant.DateTimeSlimLayout) + common.RandStrAndNum(5)
timeNow := time.Now().Format("20060102150405") + common.RandStrAndNum(5)
fileName := fmt.Sprintf("%s.rdb", timeNow)
if appendonly == "yes" {
if strings.HasPrefix(redisInfo.Version, "6.") {
@@ -146,7 +146,7 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
suffix = "tar.gz"
}
}
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/redis/%s_%s.%s", redisInfo.Name, time.Now().Format(constant.DateTimeSlimLayout), suffix))
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/redis/%s_%s.%s", redisInfo.Name, time.Now().Format("20060102150405"), suffix))
if err := handleRedisBackup(redisInfo, path.Dir(rollbackFile), path.Base(rollbackFile), secret); err != nil {
return fmt.Errorf("backup database %s for rollback before recover failed, err: %v", redisInfo.Name, err)
}
+1 -1
View File
@@ -72,7 +72,7 @@ func handleRuntimeRecover(runtime *model.Runtime, recoverFile string, isRollback
}
if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("runtime/%s_%s.tar.gz", runtime.Name, time.Now().Format(constant.DateTimeSlimLayout)))
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("runtime/%s_%s.tar.gz", runtime.Name, time.Now().Format("20060102150405")))
if err := handleRuntimeBackup(runtime, path.Dir(rollbackFile), path.Base(rollbackFile), "", secret); err != nil {
return fmt.Errorf("backup runtime %s for rollback before recover failed, err: %v", runtime.Name, err)
}
+4 -4
View File
@@ -31,7 +31,7 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
return err
}
timeNow := time.Now().Format(constant.DateTimeSlimLayout)
timeNow := time.Now().Format("20060102150405")
itemDir := fmt.Sprintf("website/%s", req.Name)
backupDir := path.Join(localDir, itemDir)
fileName := fmt.Sprintf("%s_%s.tar.gz", website.PrimaryDomain, timeNow+common.RandStrAndNum(5))
@@ -106,7 +106,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
isOk := false
if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format(constant.DateTimeSlimLayout)))
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format("20060102150405")))
if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile), "", ""); err != nil {
return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err)
}
@@ -154,7 +154,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
if err != nil {
return err
}
if runtime.Type == constant.RuntimeNode || runtime.Type == constant.RuntimeJava || runtime.Type == constant.RuntimeGo {
if runtime.Type == constant.RuntimeNode {
if err := handleRuntimeRecover(runtime, fmt.Sprintf("%s/%s.runtime.tar.gz", tmpPath, website.Alias), true, ""); err != nil {
return err
}
@@ -225,7 +225,7 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string, exc
if err != nil {
return err
}
if runtime.Type == constant.RuntimeNode || runtime.Type == constant.RuntimeJava || runtime.Type == constant.RuntimeGo {
if runtime.Type == constant.RuntimeNode {
if err := handleRuntimeBackup(runtime, tmpDir, fmt.Sprintf("%s.runtime.tar.gz", website.Alias), excludes, ""); err != nil {
return err
}
-562
View File
@@ -1,562 +0,0 @@
package service
import (
"bufio"
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"sort"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"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/systemctl"
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
"github.com/jinzhu/copier"
"github.com/robfig/cron/v3"
"github.com/pkg/errors"
)
const (
clamServiceNameCentOs = "clamd@scan.service"
clamServiceNameUbuntu = "clamav-daemon.service"
freshClamService = "clamav-freshclam.service"
resultDir = "clamav"
)
type ClamService struct {
serviceName string
}
type IClamService interface {
LoadBaseInfo() (dto.ClamBaseInfo, error)
Operate(operate string) error
SearchWithPage(search dto.SearchClamWithPage) (int64, interface{}, error)
Create(req dto.ClamCreate) error
Update(req dto.ClamUpdate) error
UpdateStatus(id uint, status string) error
Delete(req dto.ClamDelete) error
HandleOnce(req dto.OperateByID) error
LoadFile(req dto.ClamFileReq) (string, error)
UpdateFile(req dto.UpdateByNameAndFile) error
LoadRecords(req dto.ClamLogSearch) (int64, interface{}, error)
CleanRecord(req dto.OperateByID) error
LoadRecordLog(req dto.ClamLogReq) (string, error)
}
func NewIClamService() IClamService {
return &ClamService{}
}
func (c *ClamService) LoadBaseInfo() (dto.ClamBaseInfo, error) {
var baseInfo dto.ClamBaseInfo
baseInfo.Version = "-"
baseInfo.FreshVersion = "-"
exist1, _ := systemctl.IsExist(clamServiceNameCentOs)
if exist1 {
c.serviceName = clamServiceNameCentOs
baseInfo.IsExist = true
baseInfo.IsActive, _ = systemctl.IsActive(clamServiceNameCentOs)
}
exist2, _ := systemctl.IsExist(clamServiceNameUbuntu)
if exist2 {
c.serviceName = clamServiceNameUbuntu
baseInfo.IsExist = true
baseInfo.IsActive, _ = systemctl.IsActive(clamServiceNameUbuntu)
}
freshExist, _ := systemctl.IsExist(freshClamService)
if freshExist {
baseInfo.FreshIsExist = true
baseInfo.FreshIsActive, _ = systemctl.IsActive(freshClamService)
}
if !cmd.Which("clamdscan") {
baseInfo.IsActive = false
}
if baseInfo.IsActive {
version, err := cmd.Exec("clamdscan --version")
if err == nil {
if strings.Contains(version, "/") {
baseInfo.Version = strings.TrimPrefix(strings.Split(version, "/")[0], "ClamAV ")
} else {
baseInfo.Version = strings.TrimPrefix(version, "ClamAV ")
}
}
}
if baseInfo.FreshIsActive {
version, err := cmd.Exec("freshclam --version")
if err == nil {
if strings.Contains(version, "/") {
baseInfo.FreshVersion = strings.TrimPrefix(strings.Split(version, "/")[0], "ClamAV ")
} else {
baseInfo.FreshVersion = strings.TrimPrefix(version, "ClamAV ")
}
}
}
return baseInfo, nil
}
func (c *ClamService) Operate(operate string) error {
switch operate {
case "start", "restart", "stop":
stdout, err := cmd.Execf("systemctl %s %s", operate, c.serviceName)
if err != nil {
return fmt.Errorf("%s the %s failed, err: %s", operate, c.serviceName, stdout)
}
return nil
case "fresh-start", "fresh-restart", "fresh-stop":
stdout, err := cmd.Execf("systemctl %s %s", strings.TrimPrefix(operate, "fresh-"), freshClamService)
if err != nil {
return fmt.Errorf("%s the %s failed, err: %s", operate, c.serviceName, stdout)
}
return nil
default:
return fmt.Errorf("not support such operation: %v", operate)
}
}
func (c *ClamService) SearchWithPage(req dto.SearchClamWithPage) (int64, interface{}, error) {
total, commands, err := clamRepo.Page(req.Page, req.PageSize, commonRepo.WithLikeName(req.Info), commonRepo.WithOrderRuleBy(req.OrderBy, req.Order))
if err != nil {
return 0, nil, err
}
var datas []dto.ClamInfo
for _, command := range commands {
var item dto.ClamInfo
if err := copier.Copy(&item, &command); err != nil {
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
item.LastHandleDate = "-"
datas = append(datas, item)
}
nyc, _ := time.LoadLocation(common.LoadTimeZone())
for i := 0; i < len(datas); i++ {
logPaths := loadFileByName(datas[i].Name)
sort.Slice(logPaths, func(i, j int) bool {
return logPaths[i] > logPaths[j]
})
if len(logPaths) != 0 {
t1, err := time.ParseInLocation(constant.DateTimeSlimLayout, logPaths[0], nyc)
if err != nil {
continue
}
datas[i].LastHandleDate = t1.Format(constant.DateTimeLayout)
}
}
return total, datas, err
}
func (c *ClamService) Create(req dto.ClamCreate) error {
clam, _ := clamRepo.Get(commonRepo.WithByName(req.Name))
if clam.ID != 0 {
return constant.ErrRecordExist
}
if err := copier.Copy(&clam, &req); err != nil {
return errors.WithMessage(constant.ErrStructTransform, err.Error())
}
if clam.InfectedStrategy == "none" || clam.InfectedStrategy == "remove" {
clam.InfectedDir = ""
}
if len(req.Spec) != 0 {
entryID, err := xpack.StartClam(clam, false)
if err != nil {
return err
}
clam.EntryID = entryID
clam.Status = constant.StatusEnable
}
if err := clamRepo.Create(&clam); err != nil {
return err
}
return nil
}
func (c *ClamService) Update(req dto.ClamUpdate) error {
clam, _ := clamRepo.Get(commonRepo.WithByName(req.Name))
if clam.ID == 0 {
return constant.ErrRecordNotFound
}
if req.InfectedStrategy == "none" || req.InfectedStrategy == "remove" {
req.InfectedDir = ""
}
var clamItem model.Clam
if err := copier.Copy(&clamItem, &req); err != nil {
return errors.WithMessage(constant.ErrStructTransform, err.Error())
}
clamItem.EntryID = clam.EntryID
upMap := map[string]interface{}{}
if len(clam.Spec) != 0 && clam.EntryID != 0 {
global.Cron.Remove(cron.EntryID(clamItem.EntryID))
upMap["entry_id"] = 0
}
if len(req.Spec) == 0 {
upMap["status"] = ""
upMap["entry_id"] = 0
}
if len(req.Spec) != 0 && clam.Status != constant.StatusDisable {
newEntryID, err := xpack.StartClam(clamItem, true)
if err != nil {
return err
}
upMap["entry_id"] = newEntryID
}
if len(clam.Spec) == 0 && len(req.Spec) != 0 {
upMap["status"] = constant.StatusEnable
}
upMap["name"] = req.Name
upMap["path"] = req.Path
upMap["infected_dir"] = req.InfectedDir
upMap["infected_strategy"] = req.InfectedStrategy
upMap["spec"] = req.Spec
upMap["description"] = req.Description
if err := clamRepo.Update(req.ID, upMap); err != nil {
return err
}
return nil
}
func (c *ClamService) UpdateStatus(id uint, status string) error {
clam, _ := clamRepo.Get(commonRepo.WithByID(id))
if clam.ID == 0 {
return constant.ErrRecordNotFound
}
var (
entryID int
err error
)
if status == constant.StatusEnable {
entryID, err = xpack.StartClam(clam, true)
if err != nil {
return err
}
} else {
global.Cron.Remove(cron.EntryID(clam.EntryID))
global.LOG.Infof("stop cronjob entryID: %v", clam.EntryID)
}
return clamRepo.Update(clam.ID, map[string]interface{}{"status": status, "entry_id": entryID})
}
func (c *ClamService) Delete(req dto.ClamDelete) error {
for _, id := range req.Ids {
clam, _ := clamRepo.Get(commonRepo.WithByID(id))
if clam.ID == 0 {
continue
}
if req.RemoveRecord {
_ = os.RemoveAll(path.Join(global.CONF.System.DataDir, resultDir, clam.Name))
}
if req.RemoveInfected {
_ = os.RemoveAll(path.Join(clam.InfectedDir, "1panel-infected", clam.Name))
}
if err := clamRepo.Delete(commonRepo.WithByID(id)); err != nil {
return err
}
}
return nil
}
func (c *ClamService) HandleOnce(req dto.OperateByID) error {
if cmd.Which("clamdscan") == false {
return buserr.New("ErrClamdscanNotFound")
}
clam, _ := clamRepo.Get(commonRepo.WithByID(req.ID))
if clam.ID == 0 {
return constant.ErrRecordNotFound
}
if cmd.CheckIllegal(clam.Path) {
return buserr.New(constant.ErrCmdIllegal)
}
timeNow := time.Now().Format(constant.DateTimeSlimLayout)
logFile := path.Join(global.CONF.System.DataDir, resultDir, clam.Name, timeNow)
if _, err := os.Stat(path.Dir(logFile)); err != nil {
_ = os.MkdirAll(path.Dir(logFile), os.ModePerm)
}
go func() {
strategy := ""
switch clam.InfectedStrategy {
case "remove":
strategy = "--remove"
case "move":
dir := path.Join(clam.InfectedDir, "1panel-infected", clam.Name, timeNow)
strategy = "--move=" + dir
if _, err := os.Stat(dir); err != nil {
_ = os.MkdirAll(dir, os.ModePerm)
}
case "copy":
dir := path.Join(clam.InfectedDir, "1panel-infected", clam.Name, timeNow)
strategy = "--copy=" + dir
if _, err := os.Stat(dir); err != nil {
_ = os.MkdirAll(dir, os.ModePerm)
}
}
global.LOG.Debugf("clamdscan --fdpass %s %s -l %s", strategy, clam.Path, logFile)
stdout, err := cmd.Execf("clamdscan --fdpass %s %s -l %s", strategy, clam.Path, logFile)
if err != nil {
global.LOG.Errorf("clamdscan failed, stdout: %v, err: %v", stdout, err)
}
}()
return nil
}
func (c *ClamService) LoadRecords(req dto.ClamLogSearch) (int64, interface{}, error) {
clam, _ := clamRepo.Get(commonRepo.WithByID(req.ClamID))
if clam.ID == 0 {
return 0, nil, constant.ErrRecordNotFound
}
logPaths := loadFileByName(clam.Name)
if len(logPaths) == 0 {
return 0, nil, nil
}
var filterFiles []string
nyc, _ := time.LoadLocation(common.LoadTimeZone())
for _, item := range logPaths {
t1, err := time.ParseInLocation(constant.DateTimeSlimLayout, item, nyc)
if err != nil {
continue
}
if t1.After(req.StartTime) && t1.Before(req.EndTime) {
filterFiles = append(filterFiles, item)
}
}
if len(filterFiles) == 0 {
return 0, nil, nil
}
sort.Slice(filterFiles, func(i, j int) bool {
return filterFiles[i] > filterFiles[j]
})
var records []string
total, start, end := len(filterFiles), (req.Page-1)*req.PageSize, req.Page*req.PageSize
if start > total {
records = make([]string, 0)
} else {
if end >= total {
end = total
}
records = filterFiles[start:end]
}
var datas []dto.ClamLog
for i := 0; i < len(records); i++ {
item := loadResultFromLog(path.Join(global.CONF.System.DataDir, resultDir, clam.Name, records[i]))
datas = append(datas, item)
}
return int64(total), datas, nil
}
func (c *ClamService) LoadRecordLog(req dto.ClamLogReq) (string, error) {
logPath := path.Join(global.CONF.System.DataDir, resultDir, req.ClamName, req.RecordName)
var tail string
if req.Tail != "0" {
tail = req.Tail
} else {
tail = "+1"
}
cmd := exec.Command("tail", "-n", tail, logPath)
stdout, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("tail -n %v failed, err: %v", req.Tail, err)
}
return string(stdout), nil
}
func (c *ClamService) CleanRecord(req dto.OperateByID) error {
clam, _ := clamRepo.Get(commonRepo.WithByID(req.ID))
if clam.ID == 0 {
return constant.ErrRecordNotFound
}
pathItem := path.Join(global.CONF.System.DataDir, resultDir, clam.Name)
_ = os.RemoveAll(pathItem)
return nil
}
func (c *ClamService) LoadFile(req dto.ClamFileReq) (string, error) {
filePath := ""
switch req.Name {
case "clamd":
if c.serviceName == clamServiceNameUbuntu {
filePath = "/etc/clamav/clamd.conf"
} else {
filePath = "/etc/clamd.d/scan.conf"
}
case "clamd-log":
filePath = c.loadLogPath("clamd-log")
if len(filePath) != 0 {
break
}
if c.serviceName == clamServiceNameUbuntu {
filePath = "/var/log/clamav/clamav.log"
} else {
filePath = "/var/log/clamd.scan"
}
case "freshclam":
if c.serviceName == clamServiceNameUbuntu {
filePath = "/etc/clamav/freshclam.conf"
} else {
filePath = "/etc/freshclam.conf"
}
case "freshclam-log":
filePath = c.loadLogPath("freshclam-log")
if len(filePath) != 0 {
break
}
if c.serviceName == clamServiceNameUbuntu {
filePath = "/var/log/clamav/freshclam.log"
} else {
filePath = "/var/log/freshclam.log"
}
default:
return "", fmt.Errorf("not support such type")
}
if _, err := os.Stat(filePath); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
}
var tail string
if req.Tail != "0" {
tail = req.Tail
} else {
tail = "+1"
}
cmd := exec.Command("tail", "-n", tail, filePath)
stdout, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("tail -n %v failed, err: %v", req.Tail, err)
}
return string(stdout), nil
}
func (c *ClamService) UpdateFile(req dto.UpdateByNameAndFile) error {
filePath := ""
service := ""
switch req.Name {
case "clamd":
if c.serviceName == clamServiceNameUbuntu {
service = clamServiceNameUbuntu
filePath = "/etc/clamav/clamd.conf"
} else {
service = clamServiceNameCentOs
filePath = "/etc/clamd.d/scan.conf"
}
case "freshclam":
if c.serviceName == clamServiceNameUbuntu {
filePath = "/etc/clamav/freshclam.conf"
} else {
filePath = "/etc/freshclam.conf"
}
service = "clamav-freshclam.service"
default:
return fmt.Errorf("not support such type")
}
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
return err
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString(req.File)
write.Flush()
_ = systemctl.Restart(service)
return nil
}
func loadFileByName(name string) []string {
var logPaths []string
pathItem := path.Join(global.CONF.System.DataDir, resultDir, name)
_ = filepath.Walk(pathItem, func(path string, info os.FileInfo, err error) error {
if err != nil {
return nil
}
if info.IsDir() || info.Name() == name {
return nil
}
logPaths = append(logPaths, info.Name())
return nil
})
return logPaths
}
func loadResultFromLog(pathItem string) dto.ClamLog {
var data dto.ClamLog
data.Name = path.Base(pathItem)
data.Status = constant.StatusWaiting
file, err := os.ReadFile(pathItem)
if err != nil {
return data
}
lines := strings.Split(string(file), "\n")
for _, line := range lines {
if strings.Contains(line, "- SCAN SUMMARY -") {
data.Status = constant.StatusDone
}
if data.Status != constant.StatusDone {
continue
}
switch {
case strings.HasPrefix(line, "Infected files:"):
data.InfectedFiles = strings.TrimPrefix(line, "Infected files:")
case strings.HasPrefix(line, "Total errors:"):
data.TotalError = strings.TrimPrefix(line, "Total errors:")
case strings.HasPrefix(line, "Time:"):
if strings.Contains(line, "(") {
data.ScanTime = strings.ReplaceAll(strings.Split(line, "(")[1], ")", "")
continue
}
data.ScanTime = strings.TrimPrefix(line, "Time:")
case strings.HasPrefix(line, "Start Date:"):
data.ScanDate = strings.TrimPrefix(line, "Start Date:")
}
}
return data
}
func (c *ClamService) loadLogPath(name string) string {
confPath := ""
if name == "clamd-log" {
if c.serviceName == clamServiceNameUbuntu {
confPath = "/etc/clamav/clamd.conf"
} else {
confPath = "/etc/clamd.d/scan.conf"
}
} else {
if c.serviceName == clamServiceNameUbuntu {
confPath = "/etc/clamav/freshclam.conf"
} else {
confPath = "/etc/freshclam.conf"
}
}
if _, err := os.Stat(confPath); err != nil {
return ""
}
content, err := os.ReadFile(confPath)
if err != nil {
return ""
}
lines := strings.Split(string(content), "\n")
if name == "clamd-log" {
for _, line := range lines {
if strings.HasPrefix(line, "LogFile ") {
return strings.Trim(strings.ReplaceAll(line, "LogFile ", ""), " ")
}
}
} else {
for _, line := range lines {
if strings.HasPrefix(line, "UpdateLogFile ") {
return strings.Trim(strings.ReplaceAll(line, "UpdateLogFile ", ""), " ")
}
}
}
return ""
}
+6 -113
View File
@@ -1,14 +1,11 @@
package service
import (
"bufio"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"os/exec"
"path/filepath"
@@ -20,8 +17,6 @@ import (
"time"
"unicode/utf8"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"github.com/1Panel-dev/1Panel/backend/app/dto"
@@ -65,11 +60,9 @@ type IContainerService interface {
ContainerListStats() ([]dto.ContainerListStats, error)
LoadResourceLimit() (*dto.ResourceLimit, error)
ContainerRename(req dto.ContainerRename) error
ContainerCommit(req dto.ContainerCommit) error
ContainerLogClean(req dto.OperationWithName) error
ContainerOperation(req dto.ContainerOperation) error
ContainerLogs(wsConn *websocket.Conn, containerType, container, since, tail string, follow bool) error
DownloadContainerLogs(containerType, container, since, tail string, c *gin.Context) error
ContainerStats(id string) (*dto.ContainerStats, error)
Inspect(req dto.InspectReq) (string, error)
DeleteNetwork(req dto.BatchDelete) error
@@ -190,7 +183,7 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
ports := loadContainerPort(item.Ports)
info := dto.ContainerInfo{
ContainerID: item.ID,
CreateTime: time.Unix(item.Created, 0).Format(constant.DateTimeLayout),
CreateTime: time.Unix(item.Created, 0).Format("2006-01-02 15:04:05"),
Name: item.Names[0][1:],
ImageId: strings.Split(item.ImageID, ":")[1],
ImageName: item.Image,
@@ -604,28 +597,6 @@ func (u *ContainerService) ContainerRename(req dto.ContainerRename) error {
return client.ContainerRename(ctx, req.Name, req.NewName)
}
func (u *ContainerService) ContainerCommit(req dto.ContainerCommit) error {
ctx := context.Background()
client, err := docker.NewDockerClient()
if err != nil {
return err
}
defer client.Close()
options := container.CommitOptions{
Reference: req.NewImageName,
Comment: req.Comment,
Author: req.Author,
Changes: nil,
Pause: req.Pause,
Config: nil,
}
_, err = client.ContainerCommit(ctx, req.ContainerId, options)
if err != nil {
return fmt.Errorf("failed to commit container, err: %v", err)
}
return nil
}
func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error {
var err error
ctx := context.Background()
@@ -775,79 +746,6 @@ func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, containerType,
return nil
}
func (u *ContainerService) DownloadContainerLogs(containerType, container, since, tail string, c *gin.Context) error {
if cmd.CheckIllegal(container, since, tail) {
return buserr.New(constant.ErrCmdIllegal)
}
commandName := "docker"
commandArg := []string{"logs", container}
if containerType == "compose" {
commandName = "docker-compose"
commandArg = []string{"-f", container, "logs"}
}
if tail != "0" {
commandArg = append(commandArg, "--tail")
commandArg = append(commandArg, tail)
}
if since != "all" {
commandArg = append(commandArg, "--since")
commandArg = append(commandArg, since)
}
cmd := exec.Command(commandName, commandArg...)
stdout, err := cmd.StdoutPipe()
if err != nil {
_ = cmd.Process.Signal(syscall.SIGTERM)
return err
}
cmd.Stderr = cmd.Stdout
if err := cmd.Start(); err != nil {
_ = cmd.Process.Signal(syscall.SIGTERM)
return err
}
tempFile, err := os.CreateTemp("", "cmd_output_*.txt")
if err != nil {
return err
}
defer tempFile.Close()
defer func() {
if err := os.Remove(tempFile.Name()); err != nil {
global.LOG.Errorf("os.Remove() failed: %v", err)
}
}()
errCh := make(chan error)
go func() {
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
line := scanner.Text()
if _, err := tempFile.WriteString(line + "\n"); err != nil {
errCh <- err
return
}
}
if err := scanner.Err(); err != nil {
errCh <- err
return
}
errCh <- nil
}()
select {
case err := <-errCh:
if err != nil {
global.LOG.Errorf("Error: %v", err)
}
case <-time.After(3 * time.Second):
global.LOG.Errorf("Timeout reached")
}
info, _ := tempFile.Stat()
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
http.ServeContent(c.Writer, c.Request, info.Name(), info.ModTime(), tempFile)
return nil
}
func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error) {
client, err := docker.NewDockerClient()
if err != nil {
@@ -989,12 +887,12 @@ func checkImageExist(client *client.Client, imageItem string) bool {
return false
}
func pullImages(ctx context.Context, client *client.Client, imageName string) error {
options := image.PullOptions{}
func pullImages(ctx context.Context, client *client.Client, image string) error {
options := types.ImagePullOptions{}
repos, _ := imageRepoRepo.List()
if len(repos) != 0 {
for _, repo := range repos {
if strings.HasPrefix(imageName, repo.DownloadUrl) && repo.Auth {
if strings.HasPrefix(image, repo.DownloadUrl) && repo.Auth {
authConfig := registry.AuthConfig{
Username: repo.Username,
Password: repo.Password,
@@ -1007,13 +905,8 @@ func pullImages(ctx context.Context, client *client.Client, imageName string) er
options.RegistryAuth = authStr
}
}
} else {
hasAuth, authStr := loadAuthInfo(imageName)
if hasAuth {
options.RegistryAuth = authStr
}
}
out, err := client.ImagePull(ctx, imageName, options)
out, err := client.ImagePull(ctx, image, options)
if err != nil {
return err
}
@@ -1147,7 +1040,7 @@ func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *types
}
} else {
if req.Ipv4 != "" || req.Ipv6 != "" {
return nil, nil, nil, fmt.Errorf("please set up the network")
return nil, nil, nil, fmt.Errorf("Please set up the network")
}
networkConf = network.NetworkingConfig{}
}
+9 -3
View File
@@ -59,7 +59,7 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
ContainerID: container.ID,
Name: container.Names[0][1:],
State: container.State,
CreateTime: time.Unix(container.Created, 0).Format(constant.DateTimeLayout),
CreateTime: time.Unix(container.Created, 0).Format("2006-01-02 15:04:05"),
}
if compose, has := composeMap[name]; has {
compose.ContainerNumber++
@@ -70,7 +70,7 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
workdir := container.Labels[composeWorkdirLabel]
composeItem := dto.ComposeInfo{
ContainerNumber: 1,
CreatedAt: time.Unix(container.Created, 0).Format(constant.DateTimeLayout),
CreatedAt: time.Unix(container.Created, 0).Format("2006-01-02 15:04:05"),
ConfigFile: config,
Workdir: workdir,
Containers: []dto.ComposeContainer{containerItem},
@@ -168,7 +168,7 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
return "", err
}
}
logItem := fmt.Sprintf("%s/compose_create_%s_%s.log", dockerLogDir, req.Name, time.Now().Format(constant.DateTimeSlimLayout))
logItem := fmt.Sprintf("%s/compose_create_%s_%s.log", dockerLogDir, req.Name, time.Now().Format("20060102150405"))
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return "", err
@@ -232,6 +232,12 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
write.Flush()
global.LOG.Infof("docker-compose.yml %s has been replaced, now start to docker-compose restart", req.Path)
if stdout, err := compose.Down(req.Path); err != nil {
if err := recreateCompose(string(oldFile), req.Path); err != nil {
return fmt.Errorf("update failed when handle compose down, err: %s, recreate failed: %v", string(stdout), err)
}
return fmt.Errorf("update failed when handle compose down, err: %s", string(stdout))
}
if stdout, err := compose.Up(req.Path); err != nil {
if err := recreateCompose(string(oldFile), req.Path); err != nil {
return fmt.Errorf("update failed when handle compose up, err: %s, recreate failed: %v", string(stdout), err)
@@ -21,7 +21,7 @@ import (
type CronjobService struct{}
type ICronjobService interface {
SearchWithPage(search dto.PageCronjob) (int64, interface{}, error)
SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error)
SearchRecords(search dto.SearchRecord) (int64, interface{}, error)
Create(cronjobDto dto.CronjobCreate) error
HandleOnce(id uint) error
@@ -39,7 +39,7 @@ func NewICronjobService() ICronjobService {
return &CronjobService{}
}
func (u *CronjobService) SearchWithPage(search dto.PageCronjob) (int64, interface{}, error) {
func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) {
total, cronjobs, err := cronjobRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info), commonRepo.WithOrderRuleBy(search.OrderBy, search.Order))
var dtoCronjobs []dto.CronjobInfo
for _, cronjob := range cronjobs {
@@ -49,7 +49,7 @@ func (u *CronjobService) SearchWithPage(search dto.PageCronjob) (int64, interfac
}
record, _ := cronjobRepo.RecordFirst(cronjob.ID)
if record.ID != 0 {
item.LastRecordTime = record.StartTime.Format(constant.DateTimeLayout)
item.LastRecordTime = record.StartTime.Format("2006-01-02 15:04:05")
} else {
item.LastRecordTime = "-"
}
@@ -71,7 +71,7 @@ func (u *CronjobService) SearchRecords(search dto.SearchRecord) (int64, interfac
if err := copier.Copy(&item, &record); err != nil {
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
item.StartTime = record.StartTime.Format(constant.DateTimeLayout)
item.StartTime = record.StartTime.Format("2006-01-02 15:04:05")
dtoCronjobs = append(dtoCronjobs, item)
}
return total, dtoCronjobs, err
@@ -330,7 +330,7 @@ func mkdirAndWriteFile(cronjob *model.Cronjob, startTime time.Time, msg []byte)
}
}
path := fmt.Sprintf("%s/%s.log", dir, startTime.Format(constant.DateTimeSlimLayout))
path := fmt.Sprintf("%s/%s.log", dir, startTime.Format("20060102150405"))
global.LOG.Infof("cronjob %s has generated some logs %s", cronjob.Name, path)
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
+31 -42
View File
@@ -17,20 +17,15 @@ import (
func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) error {
var apps []model.AppInstall
if strings.Contains(cronjob.AppID, "all") {
if cronjob.AppID == "all" {
apps, _ = appInstallRepo.ListBy()
} else {
appIds := strings.Split(cronjob.AppID, ",")
var idItems []uint
for i := 0; i < len(appIds); i++ {
itemID, _ := strconv.Atoi(appIds[i])
idItems = append(idItems, uint(itemID))
}
appItems, err := appInstallRepo.ListBy(commonRepo.WithIdsIn(idItems))
itemID, _ := (strconv.Atoi(cronjob.AppID))
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(uint(itemID)))
if err != nil {
return err
}
apps = appItems
apps = append(apps, app)
}
accountMap, err := loadClientMap(cronjob.BackupAccounts)
if err != nil {
@@ -45,7 +40,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) e
record.DetailName = app.Name
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name))
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format("20060102150405")+common.RandStrAndNum(5))
if err := handleAppBackup(&app, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil {
return err
}
@@ -78,7 +73,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
record.DetailName = web.Alias
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s", web.PrimaryDomain))
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", web.PrimaryDomain, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", web.PrimaryDomain, startTime.Format("20060102150405")+common.RandStrAndNum(5))
if err := handleWebsiteBackup(&web, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil {
return err
}
@@ -112,7 +107,7 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Ti
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s/%s", dbInfo.DBType, record.Name, dbInfo.Name))
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format("20060102150405")+common.RandStrAndNum(5))
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
if err := handleMysqlBackup(dbInfo.Database, dbInfo.DBType, dbInfo.Name, backupDir, record.FileName); err != nil {
return err
@@ -141,7 +136,7 @@ func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.T
if err != nil {
return err
}
fileName := fmt.Sprintf("directory%s_%s.tar.gz", strings.ReplaceAll(cronjob.SourceDir, "/", "_"), startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
fileName := fmt.Sprintf("directory%s_%s.tar.gz", strings.ReplaceAll(cronjob.SourceDir, "/", "_"), startTime.Format("20060102150405")+common.RandStrAndNum(5))
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("%s/%s", cronjob.Type, cronjob.Name))
if err := handleTar(cronjob.SourceDir, backupDir, fileName, cronjob.ExclusionRules, cronjob.Secret); err != nil {
return err
@@ -171,7 +166,7 @@ func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.T
if err != nil {
return err
}
nameItem := startTime.Format(constant.DateTimeSlimLayout) + common.RandStrAndNum(5)
nameItem := startTime.Format("20060102150405") + common.RandStrAndNum(5)
fileName := fmt.Sprintf("system_log_%s.tar.gz", nameItem)
backupDir := path.Join(global.CONF.System.TmpDir, "log", nameItem)
if err := handleBackupLogs(backupDir, fileName, cronjob.Secret); err != nil {
@@ -215,7 +210,7 @@ func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, startTime time.Ti
From: record.BackupType,
DefaultDownload: cronjob.DefaultDownload,
}
name, err := NewISnapshotService().HandleSnapshot(true, logPath, req, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5), cronjob.Secret)
name, err := NewISnapshotService().HandleSnapshot(true, logPath, req, startTime.Format("20060102150405")+common.RandStrAndNum(5), cronjob.Secret)
if err != nil {
return err
}
@@ -237,7 +232,7 @@ type databaseHelper struct {
func loadDbsForJob(cronjob model.Cronjob) []databaseHelper {
var dbs []databaseHelper
if strings.Contains(cronjob.DBName, "all") {
if cronjob.DBName == "all" {
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
mysqlItems, _ := mysqlRepo.List()
for _, mysql := range mysqlItems {
@@ -259,42 +254,36 @@ func loadDbsForJob(cronjob model.Cronjob) []databaseHelper {
}
return dbs
}
dbNames := strings.Split(cronjob.DBName, ",")
for _, name := range dbNames {
itemID, _ := strconv.Atoi(name)
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
mysqlItem, _ := mysqlRepo.Get(commonRepo.WithByID(uint(itemID)))
dbs = append(dbs, databaseHelper{
DBType: cronjob.DBType,
Database: mysqlItem.MysqlName,
Name: mysqlItem.Name,
})
} else {
pgItem, _ := postgresqlRepo.Get(commonRepo.WithByID(uint(itemID)))
dbs = append(dbs, databaseHelper{
DBType: cronjob.DBType,
Database: pgItem.PostgresqlName,
Name: pgItem.Name,
})
}
itemID, _ := (strconv.Atoi(cronjob.DBName))
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
mysqlItem, _ := mysqlRepo.Get(commonRepo.WithByID(uint(itemID)))
dbs = append(dbs, databaseHelper{
DBType: cronjob.DBType,
Database: mysqlItem.MysqlName,
Name: mysqlItem.Name,
})
} else {
pgItem, _ := postgresqlRepo.Get(commonRepo.WithByID(uint(itemID)))
dbs = append(dbs, databaseHelper{
DBType: cronjob.DBType,
Database: pgItem.PostgresqlName,
Name: pgItem.Name,
})
}
return dbs
}
func loadWebsForJob(cronjob model.Cronjob) []model.Website {
var weblist []model.Website
if strings.Contains(cronjob.Website, "all") {
if cronjob.Website == "all" {
weblist, _ = websiteRepo.List()
return weblist
}
websites := strings.Split(cronjob.Website, ",")
var idItems []uint
for i := 0; i < len(websites); i++ {
itemID, _ := strconv.Atoi(websites[i])
idItems = append(idItems, uint(itemID))
itemID, _ := (strconv.Atoi(cronjob.Website))
webItem, _ := websiteRepo.GetFirst(commonRepo.WithByID(uint(itemID)))
if webItem.ID != 0 {
weblist = append(weblist, webItem)
}
weblist, _ = websiteRepo.List(commonRepo.WithIdsIn(idItems))
return weblist
}
+5 -5
View File
@@ -124,7 +124,7 @@ func (u *CronjobService) handleNtpSync() error {
if err != nil {
return err
}
if err := ntp.UpdateSystemTime(ntime.Format(constant.DateTimeLayout)); err != nil {
if err := ntp.UpdateSystemTime(ntime.Format("2006-01-02 15:04:05")); err != nil {
return err
}
return nil
@@ -161,7 +161,7 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string, secret string)
commands := ""
if len(secret) != 0 {
extraCmd := "| openssl enc -aes-256-cbc -salt -k '" + secret + "' -out"
extraCmd := "| openssl enc -aes-256-cbc -salt -k " + secret + " -out"
commands = fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s %s %s", " -"+excludeRules, path, extraCmd, targetDir+"/"+name)
global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******"))
} else {
@@ -186,7 +186,7 @@ func handleUnTar(sourceFile, targetDir string, secret string) error {
}
commands := ""
if len(secret) != 0 {
extraCmd := "openssl enc -d -aes-256-cbc -k '" + secret + "' -in " + sourceFile + " | "
extraCmd := "openssl enc -d -aes-256-cbc -k " + secret + " -in " + sourceFile + " | "
commands = fmt.Sprintf("%s tar -zxvf - -C %s", extraCmd, targetDir+" > /dev/null 2>&1")
global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******"))
} else {
@@ -224,7 +224,7 @@ func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime t
_ = os.MkdirAll(dstLogDir, 0755)
}
dstName := fmt.Sprintf("%s_log_%s.gz", website.PrimaryDomain, startTime.Format(constant.DateTimeSlimLayout))
dstName := fmt.Sprintf("%s_log_%s.gz", website.PrimaryDomain, startTime.Format("20060102150405"))
dstFilePath := path.Join(dstLogDir, dstName)
filePaths = append(filePaths, dstFilePath)
@@ -384,7 +384,7 @@ func (u *CronjobService) generateLogsPath(cronjob model.Cronjob, startTime time.
_ = os.MkdirAll(dir, os.ModePerm)
}
path := fmt.Sprintf("%s/%s.log", dir, startTime.Format(constant.DateTimeSlimLayout))
path := fmt.Sprintf("%s/%s.log", dir, startTime.Format("20060102150405"))
return path
}
+4 -14
View File
@@ -9,7 +9,6 @@ import (
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/copier"
@@ -65,11 +64,6 @@ func (u *DashboardService) LoadOsInfo() (*dto.OsInfo, error) {
baseInfo.KernelArch = hostInfo.KernelArch
baseInfo.KernelVersion = hostInfo.KernelVersion
diskInfo, err := disk.Usage(global.CONF.System.BaseDir)
if err == nil {
baseInfo.DiskSize = int64(diskInfo.Free)
}
if baseInfo.KernelArch == "armv7l" {
baseInfo.KernelArch = "armv7"
}
@@ -100,15 +94,11 @@ func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto
return nil, err
}
baseInfo.AppInstalledNumber = len(appInstall)
postgresqlDbs, err := postgresqlRepo.List()
dbs, err := mysqlRepo.List()
if err != nil {
return nil, err
}
mysqlDbs, err := mysqlRepo.List()
if err != nil {
return nil, err
}
baseInfo.DatabaseNumber = len(mysqlDbs) + len(postgresqlDbs)
baseInfo.DatabaseNumber = len(dbs)
website, err := websiteRepo.GetBy()
if err != nil {
return nil, err
@@ -136,7 +126,7 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
var currentInfo dto.DashboardCurrent
hostInfo, _ := host.Info()
currentInfo.Uptime = hostInfo.Uptime
currentInfo.TimeSinceUptime = time.Now().Add(-time.Duration(hostInfo.Uptime) * time.Second).Format(constant.DateTimeLayout)
currentInfo.TimeSinceUptime = time.Now().Add(-time.Duration(hostInfo.Uptime) * time.Second).Format("2006-01-02 15:04:05")
currentInfo.Procs = hostInfo.Procs
currentInfo.CPUTotal, _ = cpu.Counts(true)
@@ -253,7 +243,7 @@ func loadDiskInfo() []dto.DiskInfo {
if isExclude {
continue
}
mounts = append(mounts, diskInfo{Type: fields[1], Device: fields[0], Mount: strings.Join(fields[6:], " ")})
mounts = append(mounts, diskInfo{Type: fields[1], Device: fields[0], Mount: fields[6]})
}
var (
+8 -8
View File
@@ -7,8 +7,8 @@ import (
"path"
"github.com/1Panel-dev/1Panel/backend/utils/postgresql"
pgclient "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
redisclient "github.com/1Panel-dev/1Panel/backend/utils/redis"
pg_client "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
redis_client "github.com/1Panel-dev/1Panel/backend/utils/redis"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/buserr"
@@ -118,7 +118,7 @@ func (u *DatabaseService) LoadItems(dbType string) ([]dto.DatabaseItem, error) {
func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
switch req.Type {
case constant.AppPostgresql:
_, err := postgresql.NewPostgresqlClient(pgclient.DBInfo{
_, err := postgresql.NewPostgresqlClient(pg_client.DBInfo{
From: "remote",
Address: req.Address,
Port: req.Port,
@@ -128,7 +128,7 @@ func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
})
return err == nil
case constant.AppRedis:
_, err := redisclient.NewRedisClient(redisclient.DBInfo{
_, err := redis_client.NewRedisClient(redis_client.DBInfo{
Address: req.Address,
Port: req.Port,
Password: req.Password,
@@ -165,7 +165,7 @@ func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
}
switch req.Type {
case constant.AppPostgresql:
if _, err := postgresql.NewPostgresqlClient(pgclient.DBInfo{
if _, err := postgresql.NewPostgresqlClient(pg_client.DBInfo{
From: "remote",
Address: req.Address,
Port: req.Port,
@@ -176,7 +176,7 @@ func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
return err
}
case constant.AppRedis:
if _, err := redisclient.NewRedisClient(redisclient.DBInfo{
if _, err := redis_client.NewRedisClient(redis_client.DBInfo{
Address: req.Address,
Port: req.Port,
Password: req.Password,
@@ -269,7 +269,7 @@ func (u *DatabaseService) Delete(req dto.DatabaseDelete) error {
func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
switch req.Type {
case constant.AppPostgresql:
if _, err := postgresql.NewPostgresqlClient(pgclient.DBInfo{
if _, err := postgresql.NewPostgresqlClient(pg_client.DBInfo{
From: "remote",
Address: req.Address,
Port: req.Port,
@@ -280,7 +280,7 @@ func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
return err
}
case constant.AppRedis:
if _, err := redisclient.NewRedisClient(redisclient.DBInfo{
if _, err := redis_client.NewRedisClient(redis_client.DBInfo{
Address: req.Address,
Port: req.Port,
Password: req.Password,
+2 -5
View File
@@ -196,9 +196,6 @@ func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error {
for i := 0; i < len(databases); i++ {
if strings.EqualFold(databases[i].Name, data.Name) && strings.EqualFold(databases[i].MysqlName, data.MysqlName) {
hasOld = true
if databases[i].IsDelete {
_ = mysqlRepo.Update(databases[i].ID, map[string]interface{}{"is_delete": false})
}
deleteList = append(deleteList[:i], deleteList[i+1:]...)
break
}
@@ -521,11 +518,11 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
if value, ok := statusMap["Run"]; ok {
uptime, _ := strconv.Atoi(value)
info.Run = time.Unix(time.Now().Unix()-int64(uptime), 0).Format(constant.DateTimeLayout)
info.Run = time.Unix(time.Now().Unix()-int64(uptime), 0).Format("2006-01-02 15:04:05")
} else {
if value, ok := statusMap["Uptime"]; ok {
uptime, _ := strconv.Atoi(value)
info.Run = time.Unix(time.Now().Unix()-int64(uptime), 0).Format(constant.DateTimeLayout)
info.Run = time.Unix(time.Now().Unix()-int64(uptime), 0).Format("2006-01-02 15:04:05")
}
}
@@ -222,9 +222,6 @@ func (u *PostgresqlService) LoadFromRemote(database string) error {
for i := 0; i < len(databases); i++ {
if strings.EqualFold(databases[i].Name, data.Name) && strings.EqualFold(databases[i].PostgresqlName, data.PostgresqlName) {
hasOld = true
if databases[i].IsDelete {
_ = postgresqlRepo.Update(databases[i].ID, map[string]interface{}{"is_delete": false})
}
deleteList = append(deleteList[:i], deleteList[i+1:]...)
break
}
+1 -1
View File
@@ -158,7 +158,7 @@ func (u *DeviceService) Update(key, value string) error {
if err != nil {
return err
}
ts := ntime.Format(constant.DateTimeLayout)
ts := ntime.Format("2006-01-02 15:04:05")
if err := ntp.UpdateSystemTime(ts); err != nil {
return err
}
+5 -6
View File
@@ -9,7 +9,6 @@ import (
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
@@ -73,7 +72,7 @@ func (u *DeviceService) Scan() dto.CleanData {
snapTree := loadSnapshotTree(fileOp)
snapSize := uint64(0)
for _, snap := range snapTree {
snapSize += snap.Size
snapSize += uint64(snap.Size)
}
treeData = append(treeData, dto.CleanTree{
ID: uuid.NewString(),
@@ -88,7 +87,7 @@ func (u *DeviceService) Scan() dto.CleanData {
rollBackTree := loadRollBackTree(fileOp)
rollbackSize := uint64(0)
for _, rollback := range rollBackTree {
rollbackSize += rollback.Size
rollbackSize += uint64(rollback.Size)
}
treeData = append(treeData, dto.CleanTree{
ID: uuid.NewString(),
@@ -114,7 +113,7 @@ func (u *DeviceService) Scan() dto.CleanData {
unusedTree := loadUnusedFile(fileOp)
unusedSize := uint64(0)
for _, unused := range unusedTree {
unusedSize += unused.Size
unusedSize += uint64(unused.Size)
}
treeData = append(treeData, dto.CleanTree{
ID: uuid.NewString(),
@@ -279,7 +278,7 @@ func (u *DeviceService) Clean(req []dto.Clean) {
}
}
_ = settingRepo.Update("LastCleanTime", time.Now().Format(constant.DateTimeLayout))
_ = settingRepo.Update("LastCleanTime", time.Now().Format("2006-01-02 15:04:05"))
_ = settingRepo.Update("LastCleanSize", fmt.Sprintf("%v", size))
_ = settingRepo.Update("LastCleanData", fmt.Sprintf("%v", len(req)))
@@ -343,7 +342,7 @@ func (u *DeviceService) CleanForCronjob() (string, error) {
}
}
}
timeNow := time.Now().Format(constant.DateTimeLayout)
timeNow := time.Now().Format("2006-01-02 15:04:05")
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, dockerLogPath), &logs, &size, &fileCount)
logs += fmt.Sprintf("\n%s: total clean: %s, total count: %d", timeNow, common.LoadSizeUnit2F(float64(size)), fileCount)
+19 -23
View File
@@ -129,10 +129,13 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
}
func (u *DockerService) UpdateConf(req dto.SettingUpdate) error {
err := createIfNotExistDaemonJsonFile()
if err != nil {
return err
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
return err
}
_, _ = os.Create(constant.DaemonJsonPath)
}
file, err := os.ReadFile(constant.DaemonJsonPath)
if err != nil {
return err
@@ -214,26 +217,15 @@ func (u *DockerService) UpdateConf(req dto.SettingUpdate) error {
}
return nil
}
func createIfNotExistDaemonJsonFile() error {
func (u *DockerService) UpdateLogOption(req dto.LogOption) error {
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
return err
}
var daemonFile *os.File
daemonFile, err = os.Create(constant.DaemonJsonPath)
if err != nil {
return err
}
defer daemonFile.Close()
_, _ = os.Create(constant.DaemonJsonPath)
}
return nil
}
func (u *DockerService) UpdateLogOption(req dto.LogOption) error {
err := createIfNotExistDaemonJsonFile()
if err != nil {
return err
}
file, err := os.ReadFile(constant.DaemonJsonPath)
if err != nil {
return err
@@ -262,9 +254,11 @@ func (u *DockerService) UpdateLogOption(req dto.LogOption) error {
}
func (u *DockerService) UpdateIpv6Option(req dto.Ipv6Option) error {
err := createIfNotExistDaemonJsonFile()
if err != nil {
return err
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
return err
}
_, _ = os.Create(constant.DaemonJsonPath)
}
file, err := os.ReadFile(constant.DaemonJsonPath)
@@ -306,9 +300,11 @@ func (u *DockerService) UpdateConfByFile(req dto.DaemonJsonUpdateByFile) error {
_ = os.Remove(constant.DaemonJsonPath)
return nil
}
err := createIfNotExistDaemonJsonFile()
if err != nil {
return err
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
return err
}
_, _ = os.Create(constant.DaemonJsonPath)
}
file, err := os.OpenFile(constant.DaemonJsonPath, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
-1
View File
@@ -25,7 +25,6 @@ var (
groupRepo = repo.NewIGroupRepo()
commandRepo = repo.NewICommandRepo()
ftpRepo = repo.NewIFtpRepo()
clamRepo = repo.NewIClamRepo()
settingRepo = repo.NewISettingRepo()
backupRepo = repo.NewIBackupRepo()
+17 -78
View File
@@ -17,7 +17,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"golang.org/x/net/html/charset"
"golang.org/x/sys/unix"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
@@ -52,10 +51,6 @@ type IFileService interface {
ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error)
}
var filteredPaths = []string{
"/.1panel_clash",
}
func NewIFileService() IFileService {
return &FileService{}
}
@@ -84,7 +79,7 @@ func (f *FileService) SearchUploadWithPage(req request.SearchUploadWithPage) (in
}
if !info.IsDir() {
files = append(files, response.UploadInfo{
CreatedAt: info.ModTime().Format(constant.DateTimeLayout),
CreatedAt: info.ModTime().Format("2006-01-02 15:04:05"),
Size: int(info.Size()),
Name: info.Name(),
})
@@ -105,85 +100,34 @@ func (f *FileService) SearchUploadWithPage(req request.SearchUploadWithPage) (in
func (f *FileService) GetFileTree(op request.FileOption) ([]response.FileTree, error) {
var treeArray []response.FileTree
if _, err := os.Stat(op.Path); err != nil && os.IsNotExist(err) {
return treeArray, nil
}
info, err := files.NewFileInfo(op.FileOption)
if err != nil {
return nil, err
}
node := response.FileTree{
ID: common.GetUuid(),
Name: info.Name,
Path: info.Path,
IsDir: info.IsDir,
Extension: info.Extension,
ID: common.GetUuid(),
Name: info.Name,
Path: info.Path,
}
err = f.buildFileTree(&node, info.Items, op, 2)
if err != nil {
return nil, err
for _, v := range info.Items {
if v.IsDir {
node.Children = append(node.Children, response.FileTree{
ID: common.GetUuid(),
Name: v.Name,
Path: v.Path,
})
}
}
return append(treeArray, node), nil
}
func shouldFilterPath(path string) bool {
cleanedPath := filepath.Clean(path)
for _, filteredPath := range filteredPaths {
cleanedFilteredPath := filepath.Clean(filteredPath)
if cleanedFilteredPath == cleanedPath || strings.HasPrefix(cleanedPath, cleanedFilteredPath+"/") {
return true
}
}
return false
}
// 递归构建文件树(只取当前目录以及当前目录下的第一层子节点)
func (f *FileService) buildFileTree(node *response.FileTree, items []*files.FileInfo, op request.FileOption, level int) error {
for _, v := range items {
if shouldFilterPath(v.Path) {
global.LOG.Info("File Tree: Skipping %s due to filter\n", v.Path)
continue
}
childNode := response.FileTree{
ID: common.GetUuid(),
Name: v.Name,
Path: v.Path,
IsDir: v.IsDir,
Extension: v.Extension,
}
if level > 1 && v.IsDir {
if err := f.buildChildNode(&childNode, v, op, level); err != nil {
return err
}
}
node.Children = append(node.Children, childNode)
}
return nil
}
func (f *FileService) buildChildNode(childNode *response.FileTree, fileInfo *files.FileInfo, op request.FileOption, level int) error {
op.Path = fileInfo.Path
subInfo, err := files.NewFileInfo(op.FileOption)
if err != nil {
if os.IsPermission(err) || errors.Is(err, unix.EACCES) {
global.LOG.Info("File Tree: Skipping %s due to permission denied\n", fileInfo.Path)
return nil
}
global.LOG.Errorf("File Tree: Skipping %s due to error: %s\n", fileInfo.Path, err.Error())
return nil
}
return f.buildFileTree(childNode, subInfo.Items, op, level-1)
}
func (f *FileService) Create(op request.FileCreate) error {
if files.IsInvalidChar(op.Path) {
return buserr.New("ErrInvalidChar")
}
fo := files.NewFileOp()
if fo.Stat(op.Path) {
return buserr.New(constant.ErrFileIsExist)
return buserr.New(constant.ErrFileIsExit)
}
mode := op.Mode
if mode == 0 {
@@ -273,24 +217,20 @@ func (f *FileService) ChangeOwner(req request.FileRoleUpdate) error {
func (f *FileService) Compress(c request.FileCompress) error {
fo := files.NewFileOp()
if !c.Replace && fo.Stat(filepath.Join(c.Dst, c.Name)) {
return buserr.New(constant.ErrFileIsExist)
return buserr.New(constant.ErrFileIsExit)
}
return fo.Compress(c.Files, c.Dst, c.Name, files.CompressType(c.Type), c.Secret)
}
func (f *FileService) DeCompress(c request.FileDeCompress) error {
fo := files.NewFileOp()
if c.Type == "tar" && len(c.Secret) != 0 {
c.Type = "tar.gz"
}
return fo.Decompress(c.Path, c.Dst, files.CompressType(c.Type), c.Secret)
}
func (f *FileService) GetContent(op request.FileContentReq) (response.FileInfo, error) {
info, err := files.NewFileInfo(files.FileOption{
Path: op.Path,
Expand: true,
IsDetail: op.IsDetail,
Path: op.Path,
Expand: true,
})
if err != nil {
return response.FileInfo{}, err
@@ -470,7 +410,7 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
logFilePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
}
lines, isEndOfFile, total, err := files.ReadFileByLine(logFilePath, req.Page, req.PageSize, req.Latest)
lines, isEndOfFile, err := files.ReadFileByLine(logFilePath, req.Page, req.PageSize)
if err != nil {
return nil, err
}
@@ -478,7 +418,6 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
Content: strings.Join(lines, "\n"),
End: isEndOfFile,
Path: logFilePath,
Total: total,
}
return res, nil
}
+26 -72
View File
@@ -3,7 +3,6 @@ package service
import (
"fmt"
"os"
"sort"
"strconv"
"strings"
"sync"
@@ -29,7 +28,6 @@ type IFirewallService interface {
SearchWithPage(search dto.RuleSearch) (int64, interface{}, error)
OperateFirewall(operation string) error
OperatePortRule(req dto.PortRuleOperate, reload bool) error
OperateForwardRule(req dto.ForwardRuleOperate) error
OperateAddressRule(req dto.AddrRuleOperate, reload bool) error
UpdatePortRule(req dto.PortRuleUpdate) error
UpdateAddrRule(req dto.AddrRuleUpdate) error
@@ -80,39 +78,42 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}
if err != nil {
return 0, nil, err
}
var rules []fireClient.FireInfo
switch req.Type {
case "port":
rules, err = client.ListPort()
case "forward":
rules, err = client.ListForward()
case "address":
rules, err = client.ListAddress()
}
if err != nil {
return 0, nil, err
}
if len(req.Info) != 0 {
for _, addr := range rules {
if strings.Contains(addr.Address, req.Info) ||
strings.Contains(addr.Port, req.Info) ||
strings.Contains(addr.TargetPort, req.Info) ||
strings.Contains(addr.TargetIP, req.Info) {
datas = append(datas, addr)
if req.Type == "port" {
ports, err := client.ListPort()
if err != nil {
return 0, nil, err
}
if len(req.Info) != 0 {
for _, port := range ports {
if strings.Contains(port.Port, req.Info) {
datas = append(datas, port)
}
}
} else {
datas = ports
}
} else {
datas = rules
addrs, err := client.ListAddress()
if err != nil {
return 0, nil, err
}
if len(req.Info) != 0 {
for _, addr := range addrs {
if strings.Contains(addr.Address, req.Info) {
datas = append(datas, addr)
}
}
} else {
datas = addrs
}
}
if req.Type == "port" {
apps := u.loadPortByApp()
for i := 0; i < len(datas); i++ {
datas[i].UsedStatus = checkPortUsed(datas[i].Port, datas[i].Protocol, apps)
}
}
var datasFilterStatus []fireClient.FireInfo
if len(req.Status) != 0 {
for _, data := range datas {
@@ -126,7 +127,6 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}
} else {
datasFilterStatus = datas
}
var datasFilterStrategy []fireClient.FireInfo
if len(req.Strategy) != 0 {
for _, data := range datasFilterStatus {
@@ -300,52 +300,6 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
return nil
}
func (u *FirewallService) OperateForwardRule(req dto.ForwardRuleOperate) error {
client, err := firewall.NewFirewallClient()
if err != nil {
return err
}
rules, _ := client.ListForward()
for _, rule := range rules {
for _, reqRule := range req.Rules {
if reqRule.Operation == "remove" {
continue
}
if reqRule.TargetIP == "" {
reqRule.TargetIP = "127.0.0.1"
}
if reqRule.Port == rule.Port && reqRule.TargetPort == rule.TargetPort && reqRule.TargetIP == rule.TargetIP {
return constant.ErrRecordExist
}
}
}
sort.SliceStable(req.Rules, func(i, j int) bool {
n1, _ := strconv.Atoi(req.Rules[i].Num)
n2, _ := strconv.Atoi(req.Rules[j].Num)
return n1 > n2
})
for _, r := range req.Rules {
for _, p := range strings.Split(r.Protocol, "/") {
if r.TargetIP == "" {
r.TargetIP = "127.0.0.1"
}
if err = client.PortForward(fireClient.Forward{
Num: r.Num,
Protocol: p,
Port: r.Port,
TargetIP: r.TargetIP,
TargetPort: r.TargetPort,
}, r.Operation); err != nil {
return err
}
}
}
return nil
}
func (u *FirewallService) OperateAddressRule(req dto.AddrRuleOperate, reload bool) error {
client, err := firewall.NewFirewallClient()
if err != nil {
+5 -56
View File
@@ -24,7 +24,6 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/homedir"
)
type ImageService struct{}
@@ -199,7 +198,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
return "", err
}
}
logItem := fmt.Sprintf("%s/image_build_%s_%s.log", dockerLogDir, strings.ReplaceAll(req.Name, ":", "_"), time.Now().Format(constant.DateTimeSlimLayout))
logItem := fmt.Sprintf("%s/image_build_%s_%s.log", dockerLogDir, strings.ReplaceAll(req.Name, ":", "_"), time.Now().Format("20060102150405"))
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return "", err
@@ -249,20 +248,15 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
}
}
imageItemName := strings.ReplaceAll(path.Base(req.ImageName), ":", "_")
logItem := fmt.Sprintf("%s/image_pull_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format(constant.DateTimeSlimLayout))
logItem := fmt.Sprintf("%s/image_pull_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format("20060102150405"))
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return "", err
}
options := image.PullOptions{}
if req.RepoID == 0 {
hasAuth, authStr := loadAuthInfo(req.ImageName)
if hasAuth {
options.RegistryAuth = authStr
}
go func() {
defer file.Close()
out, err := client.ImagePull(context.TODO(), req.ImageName, options)
out, err := client.ImagePull(context.TODO(), req.ImageName, types.ImagePullOptions{})
if err != nil {
global.LOG.Errorf("image %s pull failed, err: %v", req.ImageName, err)
return
@@ -277,6 +271,7 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
if err != nil {
return "", err
}
options := image.PullOptions{}
if repo.Auth {
authConfig := registry.AuthConfig{
Username: repo.Username,
@@ -403,7 +398,7 @@ func (u *ImageService) ImagePush(req dto.ImagePush) (string, error) {
}
}
imageItemName := strings.ReplaceAll(path.Base(req.Name), ":", "_")
logItem := fmt.Sprintf("%s/image_push_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format(constant.DateTimeSlimLayout))
logItem := fmt.Sprintf("%s/image_push_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format("20060102150405"))
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return "", err
@@ -469,49 +464,3 @@ func checkUsed(imageID string, containers []types.Container) bool {
}
return false
}
func loadAuthInfo(image string) (bool, string) {
if !strings.Contains(image, "/") {
return false, ""
}
homeDir := homedir.Get()
confPath := path.Join(homeDir, ".docker/config.json")
configFileBytes, err := os.ReadFile(confPath)
if err != nil {
return false, ""
}
var config dockerConfig
if err = json.Unmarshal(configFileBytes, &config); err != nil {
return false, ""
}
var (
user string
passwd string
)
imagePrefix := strings.Split(image, "/")[0]
if val, ok := config.Auths[imagePrefix]; ok {
itemByte, _ := base64.StdEncoding.DecodeString(val.Auth)
itemStr := string(itemByte)
if strings.Contains(itemStr, ":") {
user = strings.Split(itemStr, ":")[0]
passwd = strings.Split(itemStr, ":")[1]
}
}
authConfig := registry.AuthConfig{
Username: user,
Password: passwd,
}
encodedJSON, err := json.Marshal(authConfig)
if err != nil {
return false, ""
}
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
return true, authStr
}
type dockerConfig struct {
Auths map[string]authConfig `json:"auths"`
}
type authConfig struct {
Auth string `json:"auth"`
}
+7 -4
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"os"
"path"
"strings"
"time"
@@ -91,7 +92,6 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
return errors.New(string(stdout))
}
ticker := time.NewTicker(3 * time.Second)
defer ticker.Stop()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
if err := func() error {
for range ticker.C {
@@ -195,10 +195,13 @@ func (u *ImageRepoService) CheckConn(host, user, password string) error {
}
func (u *ImageRepoService) handleRegistries(newHost, delHost, handle string) error {
err := createIfNotExistDaemonJsonFile()
if err != nil {
return err
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
return err
}
_, _ = os.Create(constant.DaemonJsonPath)
}
daemonMap := make(map[string]interface{})
file, err := os.ReadFile(constant.DaemonJsonPath)
if err != nil {
+9 -9
View File
@@ -83,7 +83,7 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e
if exist != nil {
return nil, buserr.New(constant.ErrImageExist)
}
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
case constant.RuntimeNode:
if !fileOp.Stat(create.CodeDir) {
return nil, buserr.New(constant.ErrPathNotFound)
}
@@ -133,9 +133,9 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e
if err = handlePHP(create, runtime, fileOp, appVersionDir); err != nil {
return nil, err
}
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
case constant.RuntimeNode:
runtime.Port = create.Port
if err = handleNodeAndJava(create, runtime, fileOp, appVersionDir); err != nil {
if err = handleNode(create, runtime, fileOp, appVersionDir); err != nil {
return nil, err
}
}
@@ -217,7 +217,7 @@ func (r *RuntimeService) Delete(runtimeDelete request.RuntimeDelete) error {
global.LOG.Errorf("delete image id [%s] error %v", imageID, err)
}
}
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
case constant.RuntimeNode:
if out, err := compose.Down(runtime.GetComposePath()); err != nil && !runtimeDelete.ForceDelete {
if out != "" {
return errors.New(out)
@@ -300,7 +300,7 @@ func (r *RuntimeService) Get(id uint) (*response.RuntimeDTO, error) {
}
}
res.AppParams = appParams
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
case constant.RuntimeNode:
res.Params = make(map[string]interface{})
envs, err := gotenv.Unmarshal(runtime.Env)
if err != nil {
@@ -308,7 +308,7 @@ func (r *RuntimeService) Get(id uint) (*response.RuntimeDTO, error) {
}
for k, v := range envs {
switch k {
case "NODE_APP_PORT", "PANEL_APP_PORT_HTTP", "JAVA_APP_PORT", "GO_APP_PORT":
case "NODE_APP_PORT", "PANEL_APP_PORT_HTTP":
port, err := strconv.Atoi(v)
if err != nil {
return nil, err
@@ -361,7 +361,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
if exist != nil {
return buserr.New(constant.ErrImageExist)
}
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
case constant.RuntimeNode:
if runtime.Port != req.Port {
if err = checkPortExist(req.Port); err != nil {
return err
@@ -441,7 +441,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
return err
}
go buildRuntime(runtime, imageID, req.Rebuild)
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
case constant.RuntimeNode:
runtime.Version = req.Version
runtime.CodeDir = req.CodeDir
runtime.Port = req.Port
@@ -610,7 +610,7 @@ func (r *RuntimeService) SyncRuntimeStatus() error {
return err
}
for _, runtime := range runtimes {
if runtime.Type == constant.RuntimeNode || runtime.Type == constant.RuntimeJava || runtime.Type == constant.RuntimeGo {
if runtime.Type == constant.RuntimeNode {
_ = SyncRuntimeContainerStatus(&runtime)
}
}
+4 -30
View File
@@ -25,7 +25,7 @@ import (
"gopkg.in/yaml.v3"
)
func handleNodeAndJava(create request.RuntimeCreate, runtime *model.Runtime, fileOp files.FileOp, appVersionDir string) (err error) {
func handleNode(create request.RuntimeCreate, runtime *model.Runtime, fileOp files.FileOp, appVersionDir string) (err error) {
runtimeDir := path.Join(constant.RuntimeDir, create.Type)
if err = fileOp.CopyDir(appVersionDir, runtimeDir); err != nil {
return
@@ -318,23 +318,7 @@ func handleParams(create request.RuntimeCreate, projectDir string) (composeConte
}
create.Params["CONTAINER_PACKAGE_URL"] = create.Source
composeContent, err = handleCompose(env, composeContent, create, projectDir)
if err != nil {
return
}
case constant.RuntimeJava:
create.Params["CODE_DIR"] = create.CodeDir
create.Params["JAVA_VERSION"] = create.Version
create.Params["PANEL_APP_PORT_HTTP"] = create.Port
composeContent, err = handleCompose(env, composeContent, create, projectDir)
if err != nil {
return
}
case constant.RuntimeGo:
create.Params["CODE_DIR"] = create.CodeDir
create.Params["GO_VERSION"] = create.Version
create.Params["PANEL_APP_PORT_HTTP"] = create.Port
composeContent, err = handleCompose(env, composeContent, create, projectDir)
composeContent, err = handleNodeCompose(env, composeContent, create, projectDir)
if err != nil {
return
}
@@ -357,7 +341,7 @@ func handleParams(create request.RuntimeCreate, projectDir string) (composeConte
return
}
func handleCompose(env gotenv.Env, composeContent []byte, create request.RuntimeCreate, projectDir string) (composeByte []byte, err error) {
func handleNodeCompose(env gotenv.Env, composeContent []byte, create request.RuntimeCreate, projectDir string) (composeByte []byte, err error) {
existMap := make(map[string]interface{})
composeMap := make(map[string]interface{})
if err = yaml.Unmarshal(composeContent, &composeMap); err != nil {
@@ -376,17 +360,7 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime
_, ok := serviceValue["ports"].([]interface{})
if ok {
var ports []interface{}
switch create.Type {
case constant.RuntimeNode:
ports = append(ports, "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${NODE_APP_PORT}")
case constant.RuntimeJava:
ports = append(ports, "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${JAVA_APP_PORT}")
case constant.RuntimeGo:
ports = append(ports, "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${GO_APP_PORT}")
}
ports = append(ports, "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${NODE_APP_PORT}")
for i, port := range create.ExposedPorts {
containerPortStr := fmt.Sprintf("CONTAINER_PORT_%d", i)
hostPortStr := fmt.Sprintf("HOST_PORT_%d", i)
+4 -4
View File
@@ -118,7 +118,7 @@ func (u *SettingService) Update(key, value string) error {
if err != nil {
return err
}
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format(constant.DateTimeLayout)); err != nil {
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {
return err
}
case "BindDomain":
@@ -382,7 +382,7 @@ func (u *SettingService) LoadFromCert() (*dto.SSLInfo, error) {
}
data.Domain = ssl.Domains
data.SSLID = uint(id)
data.Timeout = ssl.ExpireDate.Format(constant.DateTimeLayout)
data.Timeout = ssl.ExpireDate.Format("2006-01-02 15:04:05")
}
return &data, nil
}
@@ -410,7 +410,7 @@ func (u *SettingService) HandlePasswordExpired(c *gin.Context, old, new string)
return err
}
timeout, _ := strconv.Atoi(expiredSetting.Value)
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format(constant.DateTimeLayout)); err != nil {
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {
return err
}
return nil
@@ -455,7 +455,7 @@ func loadInfoFromCert() (dto.SSLInfo, error) {
}
return dto.SSLInfo{
Domain: strings.Join(domains, ","),
Timeout: certObj.NotAfter.Format(constant.DateTimeLayout),
Timeout: certObj.NotAfter.Format("2006-01-02 15:04:05"),
RootPath: path.Join(global.CONF.System.BaseDir, "1panel/secret/server.crt"),
}, nil
}
+13 -54
View File
@@ -48,9 +48,13 @@ func NewISnapshotService() ISnapshotService {
func (u *SnapshotService) SearchWithPage(req dto.SearchWithPage) (int64, interface{}, error) {
total, systemBackups, err := snapshotRepo.Page(req.Page, req.PageSize, commonRepo.WithLikeName(req.Info))
dtoSnap, err := loadSnapSize(systemBackups)
if err != nil {
return 0, nil, err
var dtoSnap []dto.SnapshotInfo
for _, systemBackup := range systemBackups {
var item dto.SnapshotInfo
if err := copier.Copy(&item, &systemBackup); err != nil {
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
dtoSnap = append(dtoSnap, item)
}
return total, dtoSnap, err
}
@@ -119,7 +123,7 @@ type SnapshotJson struct {
}
func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
if _, err := u.HandleSnapshot(false, "", req, time.Now().Format(constant.DateTimeSlimLayout), req.Secret); err != nil {
if _, err := u.HandleSnapshot(false, "", req, time.Now().Format("20060102150405"), req.Secret); err != nil {
return err
}
return nil
@@ -132,7 +136,7 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
return err
}
if hasOs(snap.Name) && !strings.Contains(snap.Name, loadOs()) {
return fmt.Errorf("restoring snapshots(%s) between different server architectures(%s) is not supported", snap.Name, loadOs())
return fmt.Errorf("Restoring snapshots(%s) between different server architectures(%s) is not supported.", snap.Name, loadOs())
}
if !req.IsNew && len(snap.InterruptStep) != 0 && len(snap.RollbackStatus) != 0 {
return fmt.Errorf("the snapshot has been rolled back and cannot be restored again")
@@ -350,7 +354,7 @@ func updateRecoverStatus(id uint, isRecover bool, interruptStep, status, message
"interrupt_step": interruptStep,
"recover_status": status,
"recover_message": message,
"last_recovered_at": time.Now().Format(constant.DateTimeLayout),
"last_recovered_at": time.Now().Format("2006-01-02 15:04:05"),
}); err != nil {
global.LOG.Errorf("update snap recover status failed, err: %v", err)
}
@@ -365,7 +369,7 @@ func updateRecoverStatus(id uint, isRecover bool, interruptStep, status, message
"interrupt_step": "",
"rollback_status": "",
"rollback_message": "",
"last_rollbacked_at": time.Now().Format(constant.DateTimeLayout),
"last_rollbacked_at": time.Now().Format("2006-01-02 15:04:05"),
}); err != nil {
global.LOG.Errorf("update snap recover status failed, err: %v", err)
}
@@ -375,7 +379,7 @@ func updateRecoverStatus(id uint, isRecover bool, interruptStep, status, message
if err := snapshotRepo.Update(id, map[string]interface{}{
"rollback_status": status,
"rollback_message": message,
"last_rollbacked_at": time.Now().Format(constant.DateTimeLayout),
"last_rollbacked_at": time.Now().Format("2006-01-02 15:04:05"),
}); err != nil {
global.LOG.Errorf("update snap recover status failed, err: %v", err)
}
@@ -389,7 +393,7 @@ func (u *SnapshotService) handleUnTar(sourceDir, targetDir string, secret string
}
commands := ""
if len(secret) != 0 {
extraCmd := "openssl enc -d -aes-256-cbc -k '" + secret + "' -in " + sourceDir + " | "
extraCmd := "openssl enc -d -aes-256-cbc -k " + secret + " -in " + sourceDir + " | "
commands = fmt.Sprintf("%s tar -zxvf - -C %s", extraCmd, targetDir+" > /dev/null 2>&1")
global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******"))
} else {
@@ -506,48 +510,3 @@ func loadOs() string {
return hostInfo.KernelArch
}
}
func loadSnapSize(records []model.Snapshot) ([]dto.SnapshotInfo, error) {
var datas []dto.SnapshotInfo
clientMap := make(map[string]loadSizeHelper)
var wg sync.WaitGroup
for i := 0; i < len(records); i++ {
var item dto.SnapshotInfo
if err := copier.Copy(&item, &records[i]); err != nil {
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
itemPath := fmt.Sprintf("system_snapshot/%s.tar.gz", item.Name)
if _, ok := clientMap[records[i].DefaultDownload]; !ok {
backup, err := backupRepo.Get(commonRepo.WithByType(records[i].DefaultDownload))
if err != nil {
global.LOG.Errorf("load backup model %s from db failed, err: %v", records[i].DefaultDownload, err)
clientMap[records[i].DefaultDownload] = loadSizeHelper{}
datas = append(datas, item)
continue
}
client, err := NewIBackupService().NewClient(&backup)
if err != nil {
global.LOG.Errorf("load backup client %s from db failed, err: %v", records[i].DefaultDownload, err)
clientMap[records[i].DefaultDownload] = loadSizeHelper{}
datas = append(datas, item)
continue
}
item.Size, _ = client.Size(path.Join(strings.TrimLeft(backup.BackupPath, "/"), itemPath))
datas = append(datas, item)
clientMap[records[i].DefaultDownload] = loadSizeHelper{backupPath: strings.TrimLeft(backup.BackupPath, "/"), client: client, isOk: true}
continue
}
if clientMap[records[i].DefaultDownload].isOk {
wg.Add(1)
go func(index int) {
item.Size, _ = clientMap[records[index].DefaultDownload].client.Size(path.Join(clientMap[records[index].DefaultDownload].backupPath, itemPath))
datas = append(datas, item)
wg.Done()
}(i)
} else {
datas = append(datas, item)
}
}
wg.Wait()
return datas, nil
}
+1 -1
View File
@@ -256,7 +256,7 @@ func handleSnapTar(sourceDir, targetDir, name, exclusionRules string, secret str
}
commands := ""
if len(secret) != 0 {
extraCmd := "| openssl enc -aes-256-cbc -salt -k '" + secret + "' -out"
extraCmd := "| openssl enc -aes-256-cbc -salt -k " + secret + " -out"
commands = fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s %s %s", " -"+exStr, path, extraCmd, targetDir+"/"+name)
global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******"))
} else {
+3 -3
View File
@@ -73,7 +73,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
if snap.InterruptStep == "Readjson" {
req.IsNew = true
}
if isRecover && (req.IsNew || snap.InterruptStep == "AppData") {
if req.IsNew || snap.InterruptStep == "AppData" {
if err := recoverAppData(snapFileDir); err != nil {
updateRecoverStatus(snap.ID, isRecover, "DockerDir", constant.StatusFailed, fmt.Sprintf("handle recover app data failed, err: %v", err))
return
@@ -163,14 +163,14 @@ func backupBeforeRecover(snap model.Snapshot, secret string) error {
_ = os.MkdirAll(path.Join(baseDir, "1panel"), os.ModePerm)
_ = os.MkdirAll(path.Join(baseDir, "docker"), os.ModePerm)
wg.Add(4)
wg.Add(5)
itemHelper.Wg = &wg
go snapJson(itemHelper, jsonItem, baseDir)
go snapPanel(itemHelper, path.Join(baseDir, "1panel"))
go snapDaemonJson(itemHelper, path.Join(baseDir, "docker"))
go snapAppData(itemHelper, path.Join(baseDir, "docker"))
go snapBackup(itemHelper, global.CONF.System.Backup, path.Join(baseDir, "1panel"))
wg.Wait()
itemHelper.Status.AppData = constant.StatusDone
allDone, msg := checkAllDone(status)
if !allDone {
+6 -12
View File
@@ -62,9 +62,7 @@ func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) {
active, err := systemctl.IsActive(serviceName)
if !active {
data.Status = constant.StatusDisable
if err != nil {
data.Message = err.Error()
}
data.Message = err.Error()
} else {
data.Status = constant.StatusEnable
}
@@ -220,7 +218,7 @@ func (u *SSHService) GenerateSSH(req dto.GenerateSSH) error {
}
secretFile := fmt.Sprintf("%s/.ssh/id_item_%s", currentUser.HomeDir, req.EncryptionMode)
secretPubFile := fmt.Sprintf("%s/.ssh/id_item_%s.pub", currentUser.HomeDir, req.EncryptionMode)
authFilePath := currentUser.HomeDir + "/.ssh/authorized_keys"
authFile := currentUser.HomeDir + "/.ssh/authorized_keys"
command := fmt.Sprintf("ssh-keygen -t %s -f %s/.ssh/id_item_%s | echo y", req.EncryptionMode, currentUser.HomeDir, req.EncryptionMode)
if len(req.Password) != 0 {
@@ -237,12 +235,8 @@ func (u *SSHService) GenerateSSH(req dto.GenerateSSH) error {
_ = os.Remove(secretPubFile)
}()
if _, err := os.Stat(authFilePath); err != nil && errors.Is(err, os.ErrNotExist) {
authFile, err := os.Create(authFilePath)
if err != nil {
return err
}
defer authFile.Close()
if _, err := os.Stat(authFile); err != nil {
_, _ = os.Create(authFile)
}
stdout1, err := cmd.Execf("cat %s >> %s/.ssh/authorized_keys", secretPubFile, currentUser.HomeDir)
if err != nil {
@@ -551,14 +545,14 @@ func loadDate(currentYear int, DateStr string, nyc *time.Location) time.Time {
}
func analyzeDateStr(parts []string) (int, string) {
t, err := time.Parse(time.RFC3339Nano, parts[0])
t, err := time.Parse("2006-01-02T15:04:05.999999-07:00", parts[0])
if err == nil {
if len(parts) < 12 {
return 0, ""
}
return 0, t.Format("2006 Jan 2 15:04:05")
}
t, err = time.Parse(constant.DateTimeLayout, fmt.Sprintf("%s %s", parts[0], parts[1]))
t, err = time.Parse("2006-01-02 15:04:05", fmt.Sprintf("%s %s", parts[0], parts[1]))
if err == nil {
if len(parts) < 14 {
return 0, ""
+1 -1
View File
@@ -83,7 +83,7 @@ func (u *UpgradeService) LoadNotes(req dto.Upgrade) (string, error) {
func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
global.LOG.Info("start to upgrade now...")
fileOp := files.NewFileOp()
timeStr := time.Now().Format(constant.DateTimeSlimLayout)
timeStr := time.Now().Format("20060102150405")
rootDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("upgrade/upgrade_%s/downloads", timeStr))
originalDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("upgrade/upgrade_%s/original", timeStr))
if err := os.MkdirAll(rootDir, os.ModePerm); err != nil {
+20 -133
View File
@@ -53,7 +53,7 @@ type WebsiteService struct {
}
type IWebsiteService interface {
PageWebsite(req request.WebsiteSearch) (int64, []response.WebsiteRes, error)
PageWebsite(req request.WebsiteSearch) (int64, []response.WebsiteDTO, error)
GetWebsites() ([]response.WebsiteDTO, error)
CreateWebsite(create request.WebsiteCreate) error
OpWebsite(req request.WebsiteOp) error
@@ -96,18 +96,15 @@ type IWebsiteService interface {
OperateRedirect(req request.NginxRedirectReq) (err error)
GetRedirect(id uint) (res []response.NginxRedirectConfig, err error)
UpdateRedirectFile(req request.NginxRedirectUpdate) (err error)
UpdateDefaultHtml(req request.WebsiteHtmlUpdate) error
GetDefaultHtml(resourceType string) (*response.WebsiteHtmlRes, error)
}
func NewIWebsiteService() IWebsiteService {
return &WebsiteService{}
}
func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []response.WebsiteRes, error) {
func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []response.WebsiteDTO, error) {
var (
websiteDTOs []response.WebsiteRes
websiteDTOs []response.WebsiteDTO
opts []repo.DBOption
)
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
@@ -157,22 +154,11 @@ func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []respons
runtimeName = runtime.Name
}
sitePath := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "www", "sites", web.Alias)
websiteDTOs = append(websiteDTOs, response.WebsiteRes{
ID: web.ID,
CreatedAt: web.CreatedAt,
Protocol: web.Protocol,
PrimaryDomain: web.PrimaryDomain,
Type: web.Type,
Remark: web.Remark,
Status: web.Status,
Alias: web.Alias,
AppName: appName,
ExpireDate: web.ExpireDate,
SSLExpireDate: web.WebsiteSSL.ExpireDate,
SSLStatus: checkSSLStatus(web.WebsiteSSL.ExpireDate),
RuntimeName: runtimeName,
SitePath: sitePath,
websiteDTOs = append(websiteDTOs, response.WebsiteDTO{
Website: web,
AppName: appName,
RuntimeName: runtimeName,
SitePath: sitePath,
})
}
return total, websiteDTOs, nil
@@ -180,7 +166,7 @@ func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []respons
func (w WebsiteService) GetWebsites() ([]response.WebsiteDTO, error) {
var websiteDTOs []response.WebsiteDTO
websites, err := websiteRepo.List(commonRepo.WithOrderRuleBy("primary_domain", "ascending"))
websites, err := websiteRepo.List()
if err != nil {
return nil, err
}
@@ -336,7 +322,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
}
website.Proxy = proxy
}
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
case constant.RuntimeNode:
website.Proxy = fmt.Sprintf("127.0.0.1:%d", runtime.Port)
}
}
@@ -346,8 +332,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
}
if len(create.FtpUser) != 0 && len(create.FtpPassword) != 0 {
indexDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "index")
itemID, err := NewIFtpService().Create(dto.FtpCreate{User: create.FtpUser, Password: create.FtpPassword, Path: indexDir})
itemID, err := NewIFtpService().Create(dto.FtpCreate{User: create.FtpUser, Password: create.FtpPassword, Path: path.Join(global.CONF.System.BaseDir, "1panel/apps/openresty/openresty/www/sites", website.Alias, "index")})
if err != nil {
global.LOG.Errorf("create ftp for website failed, err: %v", err)
}
@@ -442,7 +427,6 @@ func (w WebsiteService) GetWebsite(id uint) (response.WebsiteDTO, error) {
res.ErrorLogPath = path.Join(sitePath, "log", "error.log")
res.AccessLogPath = path.Join(sitePath, "log", "access.log")
res.SitePath = sitePath
res.SiteDir = website.SiteDir
return res, nil
}
@@ -541,7 +525,9 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
}
for _, domain := range domainModels {
wafSite.Domains = append(wafSite.Domains, domain.Domain)
wafSite.Host = append(wafSite.Host, domain.Domain+":"+strconv.Itoa(domain.Port))
if domain.Port != 80 && domain.Port != 443 {
wafSite.Host = append(wafSite.Host, domain.Domain+":"+strconv.Itoa(domain.Port))
}
}
if len(wafSite.Host) == 0 {
wafSite.Host = []string{}
@@ -768,7 +754,7 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
} else {
res.HttpConfig = constant.HTTPToHTTPS
}
params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"ssl_protocols", "ssl_ciphers", "add_header"}, &website)
params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"ssl_protocols", "ssl_ciphers"}, &website)
if err != nil {
return res, err
}
@@ -779,9 +765,6 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
if p.Name == "ssl_ciphers" {
res.Algorithm = p.Params[0]
}
if p.Name == "add_header" && len(p.Params) > 0 && p.Params[0] == "Strict-Transport-Security" {
res.Hsts = true
}
}
return res, nil
}
@@ -799,7 +782,7 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
if err != nil {
return nil, err
}
if err = ChangeHSTSConfig(req.Hsts, nginxInstall, website); err != nil {
if err = ChangeHSTSConfig(req.Enable, nginxInstall, website); err != nil {
return nil, err
}
res.Enable = req.Enable
@@ -910,7 +893,6 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
websiteSSL.Provider = constant.Manual
websiteSSL.PrivateKey = privateKey
websiteSSL.Pem = certificate
websiteSSL.Status = constant.SSLReady
res.SSL = websiteSSL
}
@@ -1023,7 +1005,7 @@ func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.Websi
}
}
filePath := path.Join(sitePath, "log", req.LogType)
lines, end, _, err := files.ReadFileByLine(filePath, req.Page, req.PageSize, false)
lines, end, err := files.ReadFileByLine(filePath, req.Page, req.PageSize)
if err != nil {
return nil, err
}
@@ -1634,6 +1616,9 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
}
location.UpdateDirective("proxy_pass", []string{req.ProxyPass})
location.UpdateDirective("proxy_set_header", []string{"Host", req.ProxyHost})
if website.Protocol == constant.ProtocolHTTPS {
location.UpdateDirective("add_header", []string{"Strict-Transport-Security", "\"max-age=31536000\""})
}
location.ChangePath(req.Modifier, req.Match)
if req.Cache {
location.AddCache(req.CacheTime, req.CacheUnit)
@@ -1645,11 +1630,6 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
} else {
location.RemoveSubFilter()
}
if req.SNI {
location.UpdateDirective("proxy_ssl_server_name", []string{"on"})
} else {
location.UpdateDirective("proxy_ssl_server_name", []string{"off"})
}
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
}
@@ -1725,11 +1705,6 @@ func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, e
proxyConfig.Modifier = location.Modifier
proxyConfig.ProxyHost = location.Host
proxyConfig.Replaces = location.Replaces
for _, directive := range location.Directives {
if directive.GetName() == "proxy_ssl_server_name" {
proxyConfig.SNI = directive.GetParameters()[0] == "on"
}
}
res = append(res, proxyConfig)
}
return
@@ -2473,91 +2448,3 @@ func (w WebsiteService) LoadWebsiteDirConfig(req request.WebsiteCommonReq) (*res
return res, nil
}
func (w WebsiteService) GetDefaultHtml(resourceType string) (*response.WebsiteHtmlRes, error) {
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return nil, err
}
rootPath := path.Join(nginxInstall.GetPath(), "root")
fileOp := files.NewFileOp()
defaultPath := path.Join(rootPath, "default")
if !fileOp.Stat(defaultPath) {
_ = fileOp.CreateDir(defaultPath, 0755)
}
res := &response.WebsiteHtmlRes{}
switch resourceType {
case "404":
resourcePath := path.Join(defaultPath, "404.html")
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
res.Content = content
return res, nil
}
res.Content = string(nginx_conf.NotFoundHTML)
return res, nil
case "php":
resourcePath := path.Join(defaultPath, "index.php")
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
res.Content = content
return res, nil
}
res.Content = string(nginx_conf.IndexPHP)
return res, nil
case "index":
resourcePath := path.Join(defaultPath, "index.html")
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
res.Content = content
return res, nil
}
res.Content = string(nginx_conf.Index)
return res, nil
case "domain404":
resourcePath := path.Join(rootPath, "404.html")
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
res.Content = content
return res, nil
}
res.Content = string(nginx_conf.DomainNotFoundHTML)
return res, nil
case "stop":
resourcePath := path.Join(rootPath, "stop", "index.html")
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
res.Content = content
return res, nil
}
res.Content = string(nginx_conf.StopHTML)
return res, nil
}
return res, nil
}
func (w WebsiteService) UpdateDefaultHtml(req request.WebsiteHtmlUpdate) error {
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
rootPath := path.Join(nginxInstall.GetPath(), "root")
fileOp := files.NewFileOp()
defaultPath := path.Join(rootPath, "default")
if !fileOp.Stat(defaultPath) {
_ = fileOp.CreateDir(defaultPath, 0755)
}
var resourcePath string
switch req.Type {
case "404":
resourcePath = path.Join(defaultPath, "404.html")
case "php":
resourcePath = path.Join(defaultPath, "index.php")
case "index":
resourcePath = path.Join(defaultPath, "index.html")
case "domain404":
resourcePath = path.Join(rootPath, "404.html")
case "stop":
resourcePath = path.Join(rootPath, "stop", "index.html")
default:
return nil
}
return fileOp.SaveFile(resourcePath, req.Content, 0644)
}
-47
View File
@@ -15,9 +15,7 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/i18n"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
@@ -40,7 +38,6 @@ type IWebsiteCAService interface {
GetCA(id uint) (*response.WebsiteCADTO, error)
Delete(id uint) error
ObtainSSL(req request.WebsiteCAObtain) (*model.WebsiteSSL, error)
DownloadFile(id uint) (*os.File, error)
}
func NewIWebsiteCAService() IWebsiteCAService {
@@ -203,10 +200,6 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
CaID: ca.ID,
AutoRenew: req.AutoRenew,
Description: req.Description,
ExecShell: req.ExecShell,
}
if req.ExecShell {
websiteSSL.Shell = req.Shell
}
if req.PushDir {
if !files.NewFileOp().Stat(req.Dir) {
@@ -370,18 +363,6 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
logger := log.New(logFile, "", log.LstdFlags)
logger.Println(i18n.GetMsgWithMap("ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")}))
saveCertificateFile(websiteSSL, logger)
if websiteSSL.ExecShell {
workDir := constant.DataDir
if websiteSSL.PushDir {
workDir = websiteSSL.Dir
}
logger.Println(i18n.GetMsgByKey("ExecShellStart"))
if err = cmd.ExecShellWithTimeOut(websiteSSL.Shell, workDir, logger, 30*time.Minute); err != nil {
logger.Println(i18n.GetMsgWithMap("ErrExecShell", map[string]interface{}{"err": err.Error()}))
} else {
logger.Println(i18n.GetMsgByKey("ExecShellSuccess"))
}
}
return websiteSSL, nil
}
@@ -416,31 +397,3 @@ func createPrivateKey(keyType string) (privateKey any, publicKey any, privateKey
privateKeyBytes = caPrivateKeyPEM.Bytes()
return
}
func (w WebsiteCAService) DownloadFile(id uint) (*os.File, error) {
ca, err := websiteCARepo.GetFirst(commonRepo.WithByID(id))
if err != nil {
return nil, err
}
fileOp := files.NewFileOp()
dir := path.Join(global.CONF.System.BaseDir, "1panel/tmp/ssl", ca.Name)
if fileOp.Stat(dir) {
if err = fileOp.DeleteDir(dir); err != nil {
return nil, err
}
}
if err = fileOp.CreateDir(dir, 0666); err != nil {
return nil, err
}
if err = fileOp.WriteFile(path.Join(dir, "ca.csr"), strings.NewReader(ca.CSR), 0644); err != nil {
return nil, err
}
if err = fileOp.WriteFile(path.Join(dir, "private.key"), strings.NewReader(ca.PrivateKey), 0644); err != nil {
return nil, err
}
fileName := ca.Name + ".zip"
if err = fileOp.Compress([]string{path.Join(dir, "ca.csr"), path.Join(dir, "private.key")}, dir, fileName, files.SdkZip, ""); err != nil {
return nil, err
}
return os.Open(path.Join(dir, fileName))
}
+8 -58
View File
@@ -2,7 +2,6 @@ package service
import (
"context"
"crypto"
"crypto/x509"
"encoding/pem"
"fmt"
@@ -14,7 +13,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/i18n"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
@@ -128,15 +126,10 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
Nameserver2: create.Nameserver2,
SkipDNS: create.SkipDNS,
DisableCNAME: create.DisableCNAME,
ExecShell: create.ExecShell,
}
if create.ExecShell {
websiteSSL.Shell = create.Shell
}
if create.PushDir {
fileOP := files.NewFileOp()
if !fileOP.Stat(create.Dir) {
_ = fileOP.CreateDir(create.Dir, 0755)
if !files.NewFileOp().Stat(create.Dir) {
return res, buserr.New(constant.ErrLinkPathNotFound)
}
websiteSSL.Dir = create.Dir
}
@@ -233,32 +226,9 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
domains = append(domains, strings.Split(websiteSSL.Domains, ",")...)
}
var privateKey crypto.PrivateKey
if websiteSSL.PrivateKey == "" {
privateKey, err = certcrypto.GeneratePrivateKey(ssl.KeyType(websiteSSL.KeyType))
if err != nil {
return err
}
} else {
block, _ := pem.Decode([]byte(websiteSSL.PrivateKey))
if block == nil {
return buserr.New("invalid PEM block")
}
var privKey crypto.PrivateKey
keyType := ssl.KeyType(websiteSSL.KeyType)
switch keyType {
case certcrypto.EC256, certcrypto.EC384:
privKey, err = x509.ParseECPrivateKey(block.Bytes)
if err != nil {
return nil
}
case certcrypto.RSA2048, certcrypto.RSA3072, certcrypto.RSA4096:
privKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil
}
}
privateKey = privKey
privateKey, err := certcrypto.GeneratePrivateKey(ssl.KeyType(websiteSSL.KeyType))
if err != nil {
return err
}
websiteSSL.Status = constant.SSLApply
@@ -298,20 +268,6 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
websiteSSL.Status = constant.SSLReady
legoLogger.Logger.Println(i18n.GetMsgWithMap("ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")}))
saveCertificateFile(websiteSSL, logger)
if websiteSSL.ExecShell {
workDir := constant.DataDir
if websiteSSL.PushDir {
workDir = websiteSSL.Dir
}
legoLogger.Logger.Println(i18n.GetMsgByKey("ExecShellStart"))
if err = cmd.ExecShellWithTimeOut(websiteSSL.Shell, workDir, logger, 30*time.Minute); err != nil {
legoLogger.Logger.Println(i18n.GetMsgWithMap("ErrExecShell", map[string]interface{}{"err": err.Error()}))
} else {
legoLogger.Logger.Println(i18n.GetMsgByKey("ExecShellSuccess"))
}
}
err = websiteSSLRepo.Save(websiteSSL)
if err != nil {
return
@@ -426,17 +382,12 @@ func (w WebsiteSSLService) Update(update request.WebsiteSSLUpdate) error {
updateParams["primary_domain"] = update.PrimaryDomain
updateParams["description"] = update.Description
updateParams["provider"] = update.Provider
updateParams["key_type"] = update.KeyType
updateParams["push_dir"] = update.PushDir
updateParams["disable_cname"] = update.DisableCNAME
updateParams["skip_dns"] = update.SkipDNS
updateParams["nameserver1"] = update.Nameserver1
updateParams["nameserver2"] = update.Nameserver2
updateParams["exec_shell"] = update.ExecShell
if update.ExecShell {
updateParams["shell"] = update.Shell
} else {
updateParams["shell"] = ""
}
if websiteSSL.Provider != constant.SelfSigned {
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(update.AcmeAccountID))
@@ -447,9 +398,8 @@ func (w WebsiteSSLService) Update(update request.WebsiteSSLUpdate) error {
}
if update.PushDir {
fileOP := files.NewFileOp()
if !fileOP.Stat(update.Dir) {
_ = fileOP.CreateDir(update.Dir, 0755)
if !files.NewFileOp().Stat(update.Dir) {
return buserr.New(constant.ErrLinkPathNotFound)
}
updateParams["dir"] = update.Dir
}
+6 -54
View File
@@ -80,23 +80,18 @@ func createIndexFile(website *model.Website, runtime *model.Runtime) error {
if err != nil {
return err
}
var (
indexPath string
indexContent string
websiteService = NewIWebsiteService()
indexFolder = path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "index")
)
indexFolder := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "www", "sites", website.Alias, "index")
indexPath := ""
indexContent := ""
switch website.Type {
case constant.Static:
indexPath = path.Join(indexFolder, "index.html")
indexHtml, _ := websiteService.GetDefaultHtml("index")
indexContent = indexHtml.Content
indexContent = string(nginx_conf.Index)
case constant.Runtime:
if runtime.Type == constant.RuntimePHP {
indexPath = path.Join(indexFolder, "index.php")
indexPhp, _ := websiteService.GetDefaultHtml("php")
indexContent = indexPhp.Content
indexContent = string(nginx_conf.IndexPHP)
}
}
@@ -119,13 +114,6 @@ func createIndexFile(website *model.Website, runtime *model.Runtime) error {
if err := fileOp.WriteFile(indexPath, strings.NewReader(indexContent), 0755); err != nil {
return err
}
html404, _ := websiteService.GetDefaultHtml("404")
path404 := path.Join(indexFolder, "404.html")
if err := fileOp.WriteFile(path404, strings.NewReader(html404.Content), 0755); err != nil {
return err
}
return nil
}
@@ -257,14 +245,12 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
server.UpdateRootProxy([]string{proxy})
case constant.Static:
server.UpdateRoot(rootIndex)
server.UpdateDirective("error_page", []string{"404", "/404.html"})
case constant.Proxy:
nginxInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
server.UpdateDirective("include", []string{nginxInclude})
case constant.Runtime:
switch runtime.Type {
case constant.RuntimePHP:
server.UpdateDirective("error_page", []string{"404", "/404.html"})
if runtime.Resource == constant.ResourceLocal {
switch runtime.Type {
case constant.RuntimePHP:
@@ -276,7 +262,7 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
server.UpdateRoot(rootIndex)
server.UpdatePHPProxy([]string{website.Proxy}, "")
}
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
case constant.RuntimeNode:
proxy := fmt.Sprintf("http://127.0.0.1:%d", runtime.Port)
server.UpdateRootProxy([]string{proxy})
}
@@ -621,10 +607,6 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
}
}
if !req.Hsts {
server.RemoveDirective("add_header", []string{"Strict-Transport-Security", "\"max-age=31536000\""})
}
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return err
}
@@ -646,13 +628,6 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
nginxParams[i].Params = []string{req.Algorithm}
}
}
if req.Hsts {
nginxParams = append(nginxParams, dto.NginxParam{
Name: "add_header",
Params: []string{"Strict-Transport-Security", "\"max-age=31536000\""},
})
}
if err := updateNginxConfig(constant.NginxScopeServer, nginxParams, &website); err != nil {
return err
}
@@ -1092,26 +1067,3 @@ func ChangeHSTSConfig(enable bool, nginxInstall model.AppInstall, website model.
}
return nil
}
func checkSSLStatus(expireDate time.Time) string {
now := time.Now()
daysUntilExpiry := int(expireDate.Sub(now).Hours() / 24)
if daysUntilExpiry < 0 {
return "danger"
} else if daysUntilExpiry <= 10 {
return "warning"
}
return "success"
}
func getResourceContent(fileOp files.FileOp, resourcePath string) (string, error) {
if fileOp.Stat(resourcePath) {
content, err := fileOp.GetContent(resourcePath)
if err != nil {
return "", err
}
return string(content), nil
}
return "", nil
}
-5
View File
@@ -17,9 +17,4 @@ const (
TimeOut5s = 5
TimeOut20s = 20
TimeOut5m = 300
DateLayout = "2006-01-02" // or use time.DateOnly while go version >= 1.20
DefaultDate = "1970-01-01"
DateTimeLayout = "2006-01-02 15:04:05" // or use time.DateTime while go version >= 1.20
DateTimeSlimLayout = "20060102150405"
)
+1 -1
View File
@@ -95,7 +95,7 @@ var (
ErrPathNotFound = "ErrPathNotFound"
ErrMovePathFailed = "ErrMovePathFailed"
ErrLinkPathNotFound = "ErrLinkPathNotFound"
ErrFileIsExist = "ErrFileIsExist"
ErrFileIsExit = "ErrFileIsExit"
ErrFileUpload = "ErrFileUpload"
ErrFileDownloadDir = "ErrFileDownloadDir"
ErrCmdNotFound = "ErrCmdNotFound"
-2
View File
@@ -16,8 +16,6 @@ const (
RuntimePHP = "php"
RuntimeNode = "node"
RuntimeJava = "java"
RuntimeGo = "go"
RuntimeProxyUnix = "unix"
RuntimeProxyTcp = "tcp"
+4
View File
@@ -4,6 +4,10 @@ const (
WebRunning = "Running"
WebStopped = "Stopped"
DateLayout = "2006-01-02"
DateTimeLayout = "2006-01-02 15:04:05"
DefaultDate = "1970-01-01"
ProtocolHTTP = "HTTP"
ProtocolHTTPS = "HTTPS"
+1 -1
View File
@@ -94,7 +94,7 @@ func syncBeforeStart() {
global.LOG.Errorf("load remote time with [%s] failed, err: %v", ntpSite.Value, err)
return
}
ts := ntime.Format(constant.DateTimeLayout)
ts := ntime.Format("2006-01-02 15:04:05")
if err := ntp.UpdateSystemTime(ts); err != nil {
global.LOG.Errorf("failed to synchronize system time with [%s], err: %v", ntpSite.Value, err)
}
+2 -3
View File
@@ -74,7 +74,7 @@ ErrFileToLarge: "file is too large"
ErrPathNotFound: "Path is not found"
ErrMovePathFailed: "The target path cannot contain the original path!"
ErrLinkPathNotFound: "Target path does not exist!"
ErrFileIsExist: "File or directory already exists!"
ErrFileIsExit: "File already exists!"
ErrFileUpload: "Failed to upload file {{.name}} {{.detail}}"
ErrFileDownloadDir: "Download folder not supported"
ErrCmdNotFound: "{{ .name}} command does not exist, please install this command on the host first"
@@ -131,7 +131,7 @@ ErrLocalExist: "The local database already exists with that name, please modify
#redis
ErrTypeOfRedis: "The recovery file type does not match the current persistence mode. Modify the file type and try again"
#container
#container
ErrInUsed: "{{ .detail }} is in use and cannot be deleted"
ErrObjectInUsed: "This object is in use and cannot be deleted"
ErrPortRules: "The number of ports does not match, please re-enter!"
@@ -174,7 +174,6 @@ CutWebsiteLogSuccess: "{{ .name }} website log cut successfully, backup path {{
#toolbox
ErrNotExistUser: "The current user does not exist. Please modify and retry!"
ErrBanAction: "Setting failed, the current {{ .name }} service is unavailable, please check and try again!"
ErrClamdscanNotFound: "The clamdscan command was not detected, please refer to the documentation to install it!"
#waf
ErrScope: "Modification of this configuration is not supported"
+1 -2
View File
@@ -75,7 +75,7 @@ ErrFileToLarge: "文件超過10M,無法打開"
ErrPathNotFound: "目錄不存在"
ErrMovePathFailed: "目標路徑不能包含原路徑!"
ErrLinkPathNotFound: "目標路徑不存在!"
ErrFileIsExist: "文件或文件夾已存在!"
ErrFileIsExit: "文件已存在!"
ErrFileUpload: "{{ .name }} 上傳文件失敗 {{ .detail}}"
ErrFileDownloadDir: "不支持下載文件夾"
ErrCmdNotFound: "{{ .name}} 命令不存在,請先在宿主機安裝此命令"
@@ -175,7 +175,6 @@ CutWebsiteLogSuccess: "{{ .name }} 網站日誌切割成功,備份路徑 {{ .p
#toolbox
ErrNotExistUser: "當前使用者不存在,請修改後重試!"
ErrBanAction: "設置失敗,當前 {{ .name }} 服務不可用,請檢查後重試!"
ErrClamdscanNotFound: "未偵測到 clamdscan 指令,請參考文件安裝!"
#waf
ErrScope: "不支援修改此配置"
+2 -6
View File
@@ -74,7 +74,7 @@ ErrFileToLarge: "文件超过10M,无法打开"
ErrPathNotFound: "目录不存在"
ErrMovePathFailed: "目标路径不能包含原路径!"
ErrLinkPathNotFound: "目标路径不存在!"
ErrFileIsExist: "文件或文件夹已存在!"
ErrFileIsExit: "文件已存在!"
ErrFileUpload: "{{ .name }} 上传文件失败 {{ .detail}}"
ErrFileDownloadDir: "不支持下载文件夹"
ErrCmdNotFound: "{{ .name}} 命令不存在,请先在宿主机安装此命令"
@@ -120,9 +120,6 @@ ErrDefaultCA: "默认机构不能删除"
ApplyWebSiteSSLLog: "开始更新 {{ .name }} 网站证书"
ErrUpdateWebsiteSSL: "{{ .name }} 网站更新证书失败: {{ .err }}"
ApplyWebSiteSSLSuccess: "更新网站证书成功"
ErrExecShell: "执行脚本失败 {{ .err }}"
ExecShellStart: "开始执行脚本"
ExecShellSuccess: "脚本执行成功"
#mysql
ErrUserIsExist: "当前用户已存在,请重新输入"
@@ -134,7 +131,7 @@ ErrLocalExist: "本地数据库已存在该名称,请修改后重试"
#redis
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
#container
#container
ErrInUsed: "{{ .detail }} 正被使用,无法删除"
ErrObjectInUsed: "该对象正被使用,无法删除"
ErrPortRules: "端口数目不匹配,请重新输入!"
@@ -177,7 +174,6 @@ CutWebsiteLogSuccess: "{{ .name }} 网站日志切割成功,备份路径 {{ .p
#toolbox
ErrNotExistUser: "当前用户不存在,请修改后重试!"
ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后重试!"
ErrClamdscanNotFound: "未检测到 clamdscan 命令,请参考文档安装!"
#waf
ErrScope: "不支持修改此配置"
-5
View File
@@ -2,7 +2,6 @@ package app
import (
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/firewall"
"path"
"github.com/1Panel-dev/1Panel/backend/constant"
@@ -32,10 +31,6 @@ func Init() {
}
_ = docker.CreateDefaultDockerNetwork()
if f, err := firewall.NewFirewallClient(); err == nil {
_ = f.EnableForward()
}
}
func createDir(fileOp files.FileOp, dirPath string) {
+2 -6
View File
@@ -21,11 +21,9 @@ func Init() {
}
fullPath := global.CONF.System.DbPath + "/" + global.CONF.System.DbFile
if _, err := os.Stat(fullPath); err != nil {
f, err := os.Create(fullPath)
if err != nil {
if _, err := os.Create(fullPath); err != nil {
panic(fmt.Errorf("init db file failed, err: %v", err))
}
_ = f.Close()
}
newLogger := logger.New(
@@ -67,11 +65,9 @@ func initMonitorDB(newLogger logger.Interface) {
}
fullPath := path.Join(global.CONF.System.DbPath, "monitor.db")
if _, err := os.Stat(fullPath); err != nil {
f, err := os.Create(fullPath)
if err != nil {
if _, err := os.Create(fullPath); err != nil {
panic(fmt.Errorf("init db file failed, err: %v", err))
}
_ = f.Close()
}
db, err := gorm.Open(sqlite.Open(fullPath), &gorm.Config{
-4
View File
@@ -89,10 +89,6 @@ func Init() {
migrations.AddFtp,
migrations.AddProxy,
migrations.AddCronJobColumn,
migrations.AddForward,
migrations.AddShellColumn,
migrations.AddClam,
migrations.AddClamStatus,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
+1 -1
View File
@@ -109,7 +109,7 @@ var AddTableSetting = &gormigrate.Migration{
return err
}
if err := tx.Create(&model.Setting{Key: "ExpirationTime", Value: time.Now().AddDate(0, 0, 10).Format(constant.DateTimeLayout)}).Error; err != nil {
if err := tx.Create(&model.Setting{Key: "ExpirationTime", Value: time.Now().AddDate(0, 0, 10).Format("2006-01-02 15:04:05")}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "ExpirationDays", Value: "0"}).Error; err != nil {
@@ -239,16 +239,6 @@ var AddProxy = &gormigrate.Migration{
},
}
var AddForward = &gormigrate.Migration{
ID: "202400611-add-forward",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Forward{}); err != nil {
return err
}
return nil
},
}
var AddCronJobColumn = &gormigrate.Migration{
ID: "20240524-add-cronjob-command",
Migrate: func(tx *gorm.DB) error {
@@ -258,33 +248,3 @@ var AddCronJobColumn = &gormigrate.Migration{
return nil
},
}
var AddShellColumn = &gormigrate.Migration{
ID: "20240620-update-website-ssl",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.WebsiteSSL{}); err != nil {
return err
}
return nil
},
}
var AddClam = &gormigrate.Migration{
ID: "20240701-add-clam",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Clam{}); err != nil {
return err
}
return nil
},
}
var AddClamStatus = &gormigrate.Migration{
ID: "20240716-add-clam-status",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Clam{}); err != nil {
return err
}
return nil
},
}
+5 -4
View File
@@ -124,7 +124,7 @@ var AddTablePHPExtensions = &gormigrate.Migration{
if err := tx.Create(&model.PHPExtensions{Name: "默认", Extensions: "bcmath,gd,gettext,intl,pcntl,shmop,soap,sockets,sysvsem,xmlrpc,zip"}).Error; err != nil {
return err
}
if err := tx.Create(&model.PHPExtensions{Name: "WordPress", Extensions: "exif,igbinary,imagick,intl,zip,apcu,memcached,opcache,redis,bc,image,shmop,mysqli,pdo_mysql,gd"}).Error; err != nil {
if err := tx.Create(&model.PHPExtensions{Name: "WordPress", Extensions: "exif,igbinary,imagick,intl,zip,apcu,memcached,opcache,redis,bc,image,shmop,mysqli,pdo_mysql"}).Error; err != nil {
return err
}
if err := tx.Create(&model.PHPExtensions{Name: "Flarum", Extensions: "curl,gd,pdo_mysql,mysqli,bz2,exif,yaf,imap"}).Error; err != nil {
@@ -249,9 +249,9 @@ var UpdateOneDriveToken = &gormigrate.Migration{
varMap["client_secret"] = global.CONF.System.OneDriveSc
varMap["redirect_uri"] = constant.OneDriveRedirectURI
varMap["refresh_token"] = backup.Credential
refreshToken, err := client.RefreshToken("refresh_token", "refreshToken", varMap)
token, refreshToken, err := client.RefreshToken("refresh_token", varMap)
varMap["refresh_status"] = constant.StatusSuccess
varMap["refresh_time"] = time.Now().Format(constant.DateTimeLayout)
varMap["refresh_time"] = time.Now().Format("2006-01-02 15:04:05")
if err != nil {
varMap["refresh_msg"] = err.Error()
varMap["refresh_status"] = constant.StatusFailed
@@ -261,7 +261,8 @@ var UpdateOneDriveToken = &gormigrate.Migration{
if err := tx.Model(&model.BackupAccount{}).
Where("id = ?", backup.ID).
Updates(map[string]interface{}{
"vars": string(itemVars),
"credential": token,
"vars": string(itemVars),
}).Error; err != nil {
return err
}
+7 -18
View File
@@ -7,7 +7,6 @@ import (
"fmt"
"io"
"net/http"
"reflect"
"strings"
"time"
@@ -97,11 +96,10 @@ func OperationLog() gin.HandlerFunc {
if funcs.InputValue == key {
var names []string
if funcs.IsList {
query := fmt.Sprintf("SELECT %s FROM %s WHERE %s in (?)", funcs.OutputColumn, funcs.DB, funcs.InputColumn)
_ = global.DB.Raw(query, value).Scan(&names)
sql := fmt.Sprintf("SELECT %s FROM %s where %s in (?);", funcs.OutputColumn, funcs.DB, funcs.InputColumn)
_ = global.DB.Raw(sql, value).Scan(&names)
} else {
query := fmt.Sprintf("SELECT %s FROM %s WHERE %s = ?", funcs.OutputColumn, funcs.DB, funcs.InputColumn)
_ = global.DB.Raw(query, value).Scan(&names)
_ = global.DB.Raw(fmt.Sprintf("select %s from %s where %s = ?;", funcs.OutputColumn, funcs.DB, funcs.InputColumn), value).Scan(&names)
}
formatMap[funcs.OutputValue] = strings.Join(names, ",")
break
@@ -111,21 +109,12 @@ func OperationLog() gin.HandlerFunc {
}
for key, value := range formatMap {
if strings.Contains(operationDic.FormatEN, "["+key+"]") {
t := reflect.TypeOf(value)
if t.Kind() != reflect.Array && t.Kind() != reflect.Slice {
if arrays, ok := value.([]string); ok {
operationDic.FormatZH = strings.ReplaceAll(operationDic.FormatZH, "["+key+"]", fmt.Sprintf("[%v]", strings.Join(arrays, ",")))
operationDic.FormatEN = strings.ReplaceAll(operationDic.FormatEN, "["+key+"]", fmt.Sprintf("[%v]", strings.Join(arrays, ",")))
} else {
operationDic.FormatZH = strings.ReplaceAll(operationDic.FormatZH, "["+key+"]", fmt.Sprintf("[%v]", value))
operationDic.FormatEN = strings.ReplaceAll(operationDic.FormatEN, "["+key+"]", fmt.Sprintf("[%v]", value))
} else {
val := reflect.ValueOf(value)
length := val.Len()
var elements []string
for i := 0; i < length; i++ {
element := val.Index(i).Interface().(string)
elements = append(elements, element)
}
operationDic.FormatZH = strings.ReplaceAll(operationDic.FormatZH, "["+key+"]", fmt.Sprintf("[%v]", strings.Join(elements, ",")))
operationDic.FormatEN = strings.ReplaceAll(operationDic.FormatEN, "["+key+"]", fmt.Sprintf("[%v]", strings.Join(elements, ",")))
}
}
}
+1 -1
View File
@@ -31,7 +31,7 @@ func PasswordExpired() gin.HandlerFunc {
return
}
loc, _ := time.LoadLocation(common.LoadTimeZone())
expiredTime, err := time.ParseInLocation(constant.DateTimeLayout, extime.Value, loc)
expiredTime, err := time.ParseInLocation("2006-01-02 15:04:05", extime.Value, loc)
if err != nil {
helper.ErrorWithDetail(c, constant.CodePasswordExpired, constant.ErrTypePasswordExpired, err)
return
-2
View File
@@ -26,13 +26,11 @@ func (s *ContainerRouter) InitRouter(Router *gin.RouterGroup) {
baRouter.POST("/list", baseApi.ListContainer)
baRouter.GET("/list/stats", baseApi.ContainerListStats)
baRouter.GET("/search/log", baseApi.ContainerLogs)
baRouter.POST("/download/log", baseApi.DownloadContainerLogs)
baRouter.GET("/limit", baseApi.LoadResourceLimit)
baRouter.POST("/clean/log", baseApi.CleanContainerLog)
baRouter.POST("/load/log", baseApi.LoadContainerLog)
baRouter.POST("/inspect", baseApi.Inspect)
baRouter.POST("/rename", baseApi.ContainerRename)
baRouter.POST("/commit", baseApi.ContainerCommit)
baRouter.POST("/operate", baseApi.ContainerOperation)
baRouter.POST("/prune", baseApi.ContainerPrune)
-1
View File
@@ -29,7 +29,6 @@ func (s *HostRouter) InitRouter(Router *gin.RouterGroup) {
hostRouter.POST("/firewall/search", baseApi.SearchFirewallRule)
hostRouter.POST("/firewall/operate", baseApi.OperateFirewall)
hostRouter.POST("/firewall/port", baseApi.OperatePortRule)
hostRouter.POST("/firewall/forward", baseApi.OperateForwardRule)
hostRouter.POST("/firewall/ip", baseApi.OperateIPRule)
hostRouter.POST("/firewall/batch", baseApi.BatchOperateRule)
hostRouter.POST("/firewall/update/port", baseApi.UpdatePortRule)
-14
View File
@@ -45,19 +45,5 @@ func (s *ToolboxRouter) InitRouter(Router *gin.RouterGroup) {
toolboxRouter.POST("/ftp/update", baseApi.UpdateFtp)
toolboxRouter.POST("/ftp/del", baseApi.DeleteFtp)
toolboxRouter.POST("/ftp/sync", baseApi.SyncFtp)
toolboxRouter.POST("/clam/search", baseApi.SearchClam)
toolboxRouter.POST("/clam/record/search", baseApi.SearchClamRecord)
toolboxRouter.POST("/clam/record/clean", baseApi.CleanClamRecord)
toolboxRouter.POST("/clam/record/log", baseApi.LoadClamRecordLog)
toolboxRouter.POST("/clam/file/search", baseApi.SearchClamFile)
toolboxRouter.POST("/clam/file/update", baseApi.UpdateFile)
toolboxRouter.POST("/clam", baseApi.CreateClam)
toolboxRouter.POST("/clam/base", baseApi.LoadClamBaseInfo)
toolboxRouter.POST("/clam/operate", baseApi.OperateClam)
toolboxRouter.POST("/clam/update", baseApi.UpdateClam)
toolboxRouter.POST("/clam/status/update", baseApi.UpdateClamStatus)
toolboxRouter.POST("/clam/del", baseApi.DeleteClam)
toolboxRouter.POST("/clam/handle", baseApi.HandleClamScan)
}
}
+41 -44
View File
@@ -10,62 +10,59 @@ type WebsiteRouter struct {
}
func (a *WebsiteRouter) InitRouter(Router *gin.RouterGroup) {
websiteRouter := Router.Group("websites")
websiteRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth()).Use(middleware.PasswordExpired())
groupRouter := Router.Group("websites")
groupRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth()).Use(middleware.PasswordExpired())
baseApi := v1.ApiGroupApp.BaseApi
{
websiteRouter.POST("/search", baseApi.PageWebsite)
websiteRouter.GET("/list", baseApi.GetWebsites)
websiteRouter.POST("", baseApi.CreateWebsite)
websiteRouter.POST("/operate", baseApi.OpWebsite)
websiteRouter.POST("/log", baseApi.OpWebsiteLog)
websiteRouter.POST("/check", baseApi.CreateWebsiteCheck)
websiteRouter.GET("/options", baseApi.GetWebsiteOptions)
websiteRouter.POST("/update", baseApi.UpdateWebsite)
websiteRouter.GET("/:id", baseApi.GetWebsite)
websiteRouter.POST("/del", baseApi.DeleteWebsite)
websiteRouter.POST("/default/server", baseApi.ChangeDefaultServer)
groupRouter.POST("/search", baseApi.PageWebsite)
groupRouter.GET("/list", baseApi.GetWebsites)
groupRouter.POST("", baseApi.CreateWebsite)
groupRouter.POST("/operate", baseApi.OpWebsite)
groupRouter.POST("/log", baseApi.OpWebsiteLog)
groupRouter.POST("/check", baseApi.CreateWebsiteCheck)
groupRouter.GET("/options", baseApi.GetWebsiteOptions)
groupRouter.POST("/update", baseApi.UpdateWebsite)
groupRouter.GET("/:id", baseApi.GetWebsite)
groupRouter.POST("/del", baseApi.DeleteWebsite)
groupRouter.POST("/default/server", baseApi.ChangeDefaultServer)
websiteRouter.GET("/domains/:websiteId", baseApi.GetWebDomains)
websiteRouter.POST("/domains/del", baseApi.DeleteWebDomain)
websiteRouter.POST("/domains", baseApi.CreateWebDomain)
groupRouter.GET("/domains/:websiteId", baseApi.GetWebDomains)
groupRouter.POST("/domains/del", baseApi.DeleteWebDomain)
groupRouter.POST("/domains", baseApi.CreateWebDomain)
websiteRouter.GET("/:id/config/:type", baseApi.GetWebsiteNginx)
websiteRouter.POST("/config", baseApi.GetNginxConfig)
websiteRouter.POST("/config/update", baseApi.UpdateNginxConfig)
websiteRouter.POST("/nginx/update", baseApi.UpdateWebsiteNginxConfig)
groupRouter.GET("/:id/config/:type", baseApi.GetWebsiteNginx)
groupRouter.POST("/config", baseApi.GetNginxConfig)
groupRouter.POST("/config/update", baseApi.UpdateNginxConfig)
groupRouter.POST("/nginx/update", baseApi.UpdateWebsiteNginxConfig)
websiteRouter.GET("/:id/https", baseApi.GetHTTPSConfig)
websiteRouter.POST("/:id/https", baseApi.UpdateHTTPSConfig)
groupRouter.GET("/:id/https", baseApi.GetHTTPSConfig)
groupRouter.POST("/:id/https", baseApi.UpdateHTTPSConfig)
websiteRouter.GET("/php/config/:id", baseApi.GetWebsitePHPConfig)
websiteRouter.POST("/php/config", baseApi.UpdateWebsitePHPConfig)
websiteRouter.POST("/php/update", baseApi.UpdatePHPFile)
websiteRouter.POST("/php/version", baseApi.ChangePHPVersion)
groupRouter.GET("/php/config/:id", baseApi.GetWebsitePHPConfig)
groupRouter.POST("/php/config", baseApi.UpdateWebsitePHPConfig)
groupRouter.POST("/php/update", baseApi.UpdatePHPFile)
groupRouter.POST("/php/version", baseApi.ChangePHPVersion)
websiteRouter.POST("/rewrite", baseApi.GetRewriteConfig)
websiteRouter.POST("/rewrite/update", baseApi.UpdateRewriteConfig)
groupRouter.POST("/rewrite", baseApi.GetRewriteConfig)
groupRouter.POST("/rewrite/update", baseApi.UpdateRewriteConfig)
websiteRouter.POST("/dir/update", baseApi.UpdateSiteDir)
websiteRouter.POST("/dir/permission", baseApi.UpdateSiteDirPermission)
websiteRouter.POST("/dir", baseApi.GetDirConfig)
groupRouter.POST("/dir/update", baseApi.UpdateSiteDir)
groupRouter.POST("/dir/permission", baseApi.UpdateSiteDirPermission)
groupRouter.POST("/dir", baseApi.GetDirConfig)
websiteRouter.POST("/proxies", baseApi.GetProxyConfig)
websiteRouter.POST("/proxies/update", baseApi.UpdateProxyConfig)
websiteRouter.POST("/proxies/file", baseApi.UpdateProxyConfigFile)
groupRouter.POST("/proxies", baseApi.GetProxyConfig)
groupRouter.POST("/proxies/update", baseApi.UpdateProxyConfig)
groupRouter.POST("/proxies/file", baseApi.UpdateProxyConfigFile)
websiteRouter.POST("/auths", baseApi.GetAuthConfig)
websiteRouter.POST("/auths/update", baseApi.UpdateAuthConfig)
groupRouter.POST("/auths", baseApi.GetAuthConfig)
groupRouter.POST("/auths/update", baseApi.UpdateAuthConfig)
websiteRouter.POST("/leech", baseApi.GetAntiLeech)
websiteRouter.POST("/leech/update", baseApi.UpdateAntiLeech)
groupRouter.POST("/leech", baseApi.GetAntiLeech)
groupRouter.POST("/leech/update", baseApi.UpdateAntiLeech)
websiteRouter.POST("/redirect/update", baseApi.UpdateRedirectConfig)
websiteRouter.POST("/redirect", baseApi.GetRedirectConfig)
websiteRouter.POST("/redirect/file", baseApi.UpdateRedirectConfigFile)
websiteRouter.GET("/default/html/:type", baseApi.GetDefaultHtml)
websiteRouter.POST("/default/html/update", baseApi.UpdateDefaultHtml)
groupRouter.POST("/redirect/update", baseApi.UpdateRedirectConfig)
groupRouter.POST("/redirect", baseApi.GetRedirectConfig)
groupRouter.POST("/redirect/file", baseApi.UpdateRedirectConfigFile)
}
}
-1
View File
@@ -21,6 +21,5 @@ func (a *WebsiteCARouter) InitRouter(Router *gin.RouterGroup) {
groupRouter.POST("/obtain", baseApi.ObtainWebsiteCA)
groupRouter.POST("/renew", baseApi.RenewWebsiteCA)
groupRouter.GET("/:id", baseApi.GetWebsiteCA)
groupRouter.POST("/download", baseApi.DownloadCAFile)
}
}
+7 -17
View File
@@ -2,7 +2,6 @@ package client
import (
"context"
"strconv"
"time"
"github.com/1Panel-dev/1Panel/backend/utils/files"
@@ -11,11 +10,10 @@ import (
)
type kodoClient struct {
bucket string
domain string
timeout string
auth *auth.Credentials
client *storage.BucketManager
bucket string
domain string
auth *auth.Credentials
client *storage.BucketManager
}
func NewKodoClient(vars map[string]interface{}) (*kodoClient, error) {
@@ -23,17 +21,14 @@ func NewKodoClient(vars map[string]interface{}) (*kodoClient, error) {
secretKey := loadParamFromVars("secretKey", vars)
bucket := loadParamFromVars("bucket", vars)
domain := loadParamFromVars("domain", vars)
timeout := loadParamFromVars("timeout", vars)
if timeout == "" {
timeout = "1"
}
conn := auth.New(accessKey, secretKey)
cfg := storage.Config{
UseHTTPS: false,
}
bucketManager := storage.NewBucketManager(conn, &cfg)
return &kodoClient{client: bucketManager, auth: conn, bucket: bucket, domain: domain, timeout: timeout}, nil
return &kodoClient{client: bucketManager, auth: conn, bucket: bucket, domain: domain}, nil
}
func (k kodoClient) ListBuckets() ([]interface{}, error) {
@@ -71,13 +66,8 @@ func (k kodoClient) Delete(path string) (bool, error) {
}
func (k kodoClient) Upload(src, target string) (bool, error) {
int64Value, _ := strconv.ParseInt(k.timeout, 10, 64)
unixTimestamp := int64Value * 3600
putPolicy := storage.PutPolicy{
Scope: k.bucket,
Expires: uint64(unixTimestamp),
Scope: k.bucket,
}
upToken := putPolicy.UploadToken(k.auth)
cfg := storage.Config{UseHTTPS: true, UseCdnDomains: false}
+14 -22
View File
@@ -27,10 +27,7 @@ type oneDriveClient struct {
}
func NewOneDriveClient(vars map[string]interface{}) (*oneDriveClient, error) {
token, err := RefreshToken("refresh_token", "accessToken", vars)
if err != nil {
return nil, err
}
token := loadParamFromVars("accessToken", vars)
isCN := loadParamFromVars("isCN", vars)
ctx := context.Background()
ts := oauth2.StaticTokenSource(
@@ -117,7 +114,7 @@ func (o oneDriveClient) Upload(src, target string) (bool, error) {
return false, err
}
if fileInfo.IsDir() {
return false, errors.New("only file is allowed to be uploaded here")
return false, errors.New("Only file is allowed to be uploaded here.")
}
var isOk bool
if fileInfo.Size() < 4*1024*1024 {
@@ -199,7 +196,7 @@ func (o *oneDriveClient) loadIDByPath(path string) (string, error) {
return driveItem.Id, nil
}
func RefreshToken(grantType string, tokenType string, varMap map[string]interface{}) (string, error) {
func RefreshToken(grantType string, varMap map[string]interface{}) (string, string, error) {
data := url.Values{}
isCN := loadParamFromVars("isCN", varMap)
data.Set("client_id", loadParamFromVars("client_id", varMap))
@@ -219,37 +216,32 @@ func RefreshToken(grantType string, tokenType string, varMap map[string]interfac
}
req, err := http.NewRequest("POST", url, strings.NewReader(data.Encode()))
if err != nil {
return "", fmt.Errorf("new http post client for access token failed, err: %v", err)
return "", "", fmt.Errorf("new http post client for access token failed, err: %v", err)
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("request for access token failed, err: %v", err)
return "", "", fmt.Errorf("request for access token failed, err: %v", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("read data from response body failed, err: %v", err)
return "", "", fmt.Errorf("read data from response body failed, err: %v", err)
}
tokenMap := map[string]interface{}{}
if err := json.Unmarshal(respBody, &tokenMap); err != nil {
return "", fmt.Errorf("unmarshal data from response body failed, err: %v", err)
return "", "", fmt.Errorf("unmarshal data from response body failed, err: %v", err)
}
if tokenType == "accessToken" {
accessToken, ok := tokenMap["access_token"].(string)
if !ok {
return "", errors.New("no such access token in response")
}
tokenMap = nil
return accessToken, nil
accessToken, ok := tokenMap["access_token"].(string)
if !ok {
return "", "", errors.New("no such access token in response")
}
refreshToken, ok := tokenMap["refresh_token"].(string)
if !ok {
return "", errors.New("no such access token in response")
return "", "", errors.New("no such access token in response")
}
tokenMap = nil
return refreshToken, nil
return accessToken, refreshToken, nil
}
func (o *oneDriveClient) createFolder(parent string) error {
@@ -364,8 +356,8 @@ func (o *oneDriveClient) upBig(ctx context.Context, srcPath, folderID string, fi
fileSessionUploadUrl := sessionCreationResp.UploadURL
sizePerSplit := int64(5 * 1024 * 1024)
buffer := make([]byte, 5*1024*1024)
sizePerSplit := int64(3200 * 1024)
buffer := make([]byte, 3200*1024)
splitCount := fileSize / sizePerSplit
if fileSize%sizePerSplit != 0 {
splitCount += 1
+2 -26
View File
@@ -2,10 +2,7 @@ package cmd
import (
"bytes"
"context"
"errors"
"fmt"
"log"
"os"
"os/exec"
"strings"
@@ -203,27 +200,6 @@ func SudoHandleCmd() string {
}
func Which(name string) bool {
stdout, err := Execf("which %s", name)
if err != nil || (len(strings.ReplaceAll(stdout, "\n", "")) == 0 && strings.HasPrefix(stdout, "/")) {
return false
}
return true
}
func ExecShellWithTimeOut(cmdStr, workdir string, logger *log.Logger, timeout time.Duration) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
cmd.Dir = workdir
cmd.Stdout = logger.Writer()
cmd.Stderr = logger.Writer()
if err := cmd.Start(); err != nil {
return err
}
err := cmd.Wait()
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
return buserr.New(constant.ErrCmdTimeout)
}
return err
_, err := exec.LookPath(name)
return err == nil
}
+5 -9
View File
@@ -230,17 +230,13 @@ func RemoveRepeatElement(a interface{}) (ret []interface{}) {
}
func LoadSizeUnit(value float64) string {
val := int64(value)
if val%1024 != 0 {
return fmt.Sprintf("%v", val)
if value > 1048576 {
return fmt.Sprintf("%vM", value/1048576)
}
if val > 1048576 {
return fmt.Sprintf("%vM", val/1048576)
if value > 1024 {
return fmt.Sprintf("%vK", value/1024)
}
if val > 1024 {
return fmt.Sprintf("%vK", val/1024)
}
return fmt.Sprintf("%v", val)
return fmt.Sprintf("%v", value)
}
func LoadSizeUnit2F(value float64) string {
+16 -6
View File
@@ -611,15 +611,25 @@ func (f FileOp) decompressWithSDK(srcFile string, dst string, cType CompressType
}
func (f FileOp) Decompress(srcFile string, dst string, cType CompressType, secret string) error {
if cType == Tar || cType == Zip || cType == TarGz {
shellArchiver, err := NewShellArchiver(cType)
if err == nil {
if err = shellArchiver.Extract(srcFile, dst, secret); err == nil {
return nil
if err := f.decompressWithSDK(srcFile, dst, cType); err != nil {
if cType == Tar || cType == Zip || cType == TarGz {
if secret != "" {
shellArchiver, err := NewShellArchiver(TarGz)
if err != nil {
return err
}
return shellArchiver.Extract(srcFile, dst, secret)
} else {
shellArchiver, err := NewShellArchiver(cType)
if err != nil {
return err
}
return shellArchiver.Extract(srcFile, dst, secret)
}
}
return err
}
return f.decompressWithSDK(srcFile, dst, cType)
return nil
}
func ZipFile(files []archiver.File, dst afero.File) error {
+73 -134
View File
@@ -7,7 +7,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"io/fs"
"net/http"
"os"
"os/exec"
"path"
@@ -45,7 +44,6 @@ type FileInfo struct {
Items []*FileInfo `json:"items"`
ItemTotal int `json:"itemTotal"`
FavoriteID uint `json:"favoriteID"`
IsDetail bool `json:"isDetail"`
}
type FileOption struct {
@@ -59,7 +57,6 @@ type FileOption struct {
PageSize int `json:"pageSize"`
SortBy string `json:"sortBy"`
SortOrder string `json:"sortOrder"`
IsDetail bool `json:"isDetail"`
}
type FileSearchInfo struct {
@@ -92,7 +89,6 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
Gid: strconv.FormatUint(uint64(info.Sys().(*syscall.Stat_t).Gid), 10),
Group: GetGroup(info.Sys().(*syscall.Stat_t).Gid),
MimeType: GetMimeType(op.Path),
IsDetail: op.IsDetail,
}
favoriteRepo := repo.NewIFavoriteRepo()
favorite, _ := favoriteRepo.GetFirst(favoriteRepo.WithByPath(op.Path))
@@ -104,25 +100,20 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
file.LinkPath = GetSymlink(op.Path)
}
if op.Expand {
if err := handleExpansion(file, op); err != nil {
return nil, err
if file.IsDir {
if err := file.listChildren(op); err != nil {
return nil, err
}
return file, nil
} else {
if err := file.getContent(); err != nil {
return nil, err
}
}
}
return file, nil
}
func handleExpansion(file *FileInfo, op FileOption) error {
if file.IsDir {
return file.listChildren(op)
}
if !file.IsDetail {
return file.getContent()
}
return nil
}
func (f *FileInfo) search(search string, count int) (files []FileSearchInfo, total int, err error) {
cmd := exec.Command("find", f.Path, "-name", fmt.Sprintf("*%s*", search))
output, err := cmd.StdoutPipe()
@@ -208,82 +199,63 @@ func (f *FileInfo) listChildren(option FileOption) error {
return err
}
} else {
files, err = f.getFiles(afs, option)
dirFiles, err := afs.ReadDir(f.Path)
if err != nil {
return err
}
}
items, err := f.processFiles(files, option)
if err != nil {
return err
}
if option.ContainSub {
f.ItemTotal = total
}
start := (option.Page - 1) * option.PageSize
end := option.PageSize + start
var result []*FileInfo
if start < 0 || start > f.ItemTotal || end < 0 || start > end {
result = items
} else {
if end > f.ItemTotal {
result = items[start:]
} else {
result = items[start:end]
var (
dirs []FileSearchInfo
fileList []FileSearchInfo
)
for _, file := range dirFiles {
info := FileSearchInfo{
Path: f.Path,
FileInfo: file,
}
if file.IsDir() {
dirs = append(dirs, info)
} else {
fileList = append(fileList, info)
}
}
sortFileList(dirs, option.SortBy, option.SortOrder)
sortFileList(fileList, option.SortBy, option.SortOrder)
files = append(dirs, fileList...)
}
f.Items = result
return nil
}
func (f *FileInfo) getFiles(afs *afero.Afero, option FileOption) ([]FileSearchInfo, error) {
dirFiles, err := afs.ReadDir(f.Path)
if err != nil {
return nil, err
}
var (
dirs []FileSearchInfo
fileList []FileSearchInfo
)
for _, file := range dirFiles {
info := FileSearchInfo{
Path: f.Path,
FileInfo: file,
}
if file.IsDir() {
dirs = append(dirs, info)
} else {
fileList = append(fileList, info)
}
}
sortFileList(dirs, option.SortBy, option.SortOrder)
sortFileList(fileList, option.SortBy, option.SortOrder)
return append(dirs, fileList...), nil
}
func (f *FileInfo) processFiles(files []FileSearchInfo, option FileOption) ([]*FileInfo, error) {
var items []*FileInfo
for _, df := range files {
if shouldSkipFile(df, option) {
if option.Dir && !df.IsDir() {
continue
}
name, fPath := f.getFilePathAndName(option, df)
name := df.Name()
fPath := path.Join(df.Path, df.Name())
if option.Search != "" {
if option.ContainSub {
fPath = df.Path
name = strings.TrimPrefix(strings.TrimPrefix(fPath, f.Path), "/")
} else {
lowerName := strings.ToLower(name)
lowerSearch := strings.ToLower(option.Search)
if !strings.Contains(lowerName, lowerSearch) {
continue
}
}
}
if !option.ShowHidden && IsHidden(name) {
continue
}
f.ItemTotal++
isSymlink, isInvalidLink := f.checkSymlink(df)
isSymlink, isInvalidLink := false, false
if IsSymlink(df.Mode()) {
isSymlink = true
info, err := f.Fs.Stat(fPath)
if err == nil {
df.FileInfo = info
} else {
isInvalidLink = true
}
}
file := &FileInfo{
Fs: f.Fs,
@@ -318,53 +290,24 @@ func (f *FileInfo) processFiles(files []FileSearchInfo, option FileOption) ([]*F
}
items = append(items, file)
}
return items, nil
}
func shouldSkipFile(df FileSearchInfo, option FileOption) bool {
if option.Dir && !df.IsDir() {
return true
if option.ContainSub {
f.ItemTotal = total
}
if option.Search != "" && !option.ContainSub {
lowerName := strings.ToLower(df.Name())
lowerSearch := strings.ToLower(option.Search)
if !strings.Contains(lowerName, lowerSearch) {
return true
}
}
return false
}
func (f *FileInfo) getFilePathAndName(option FileOption, df FileSearchInfo) (string, string) {
name := df.Name()
fPath := path.Join(df.Path, df.Name())
if option.Search != "" && option.ContainSub {
fPath = df.Path
name = strings.TrimPrefix(strings.TrimPrefix(fPath, f.Path), "/")
}
return name, fPath
}
func (f *FileInfo) checkSymlink(df FileSearchInfo) (bool, bool) {
isSymlink := false
isInvalidLink := false
if IsSymlink(df.Mode()) {
isSymlink = true
info, err := f.Fs.Stat(path.Join(df.Path, df.Name()))
if err == nil {
df.FileInfo = info
start := (option.Page - 1) * option.PageSize
end := option.PageSize + start
var result []*FileInfo
if start < 0 || start > f.ItemTotal || end < 0 || start > end {
result = items
} else {
if end > f.ItemTotal {
result = items[start:]
} else {
isInvalidLink = true
result = items[start:end]
}
}
return isSymlink, isInvalidLink
f.Items = result
return nil
}
func (f *FileInfo) getContent() error {
@@ -387,21 +330,17 @@ func (f *FileInfo) getContent() error {
}
func DetectBinary(buf []byte) bool {
mimeType := http.DetectContentType(buf)
if !strings.HasPrefix(mimeType, "text/") {
whiteByte := 0
n := min(1024, len(buf))
for i := 0; i < n; i++ {
if (buf[i] >= 0x20) || buf[i] == 9 || buf[i] == 10 || buf[i] == 13 {
whiteByte++
} else if buf[i] <= 6 || (buf[i] >= 14 && buf[i] <= 31) {
return true
}
whiteByte := 0
n := min(1024, len(buf))
for i := 0; i < n; i++ {
if (buf[i] >= 0x20) || buf[i] == 9 || buf[i] == 10 || buf[i] == 13 {
whiteByte++
} else if buf[i] <= 6 || (buf[i] >= 14 && buf[i] <= 31) {
return true
}
return whiteByte < 1
}
return false
return whiteByte < 1
}
func min(x, y int) int {

Some files were not shown because too many files have changed in this diff Show More