mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-09 16:00:29 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab523b6879 | ||
|
|
740b4c52d2 | ||
|
|
dbb94942df | ||
|
|
1e4ea2f8c3 | ||
|
|
8083837333 | ||
|
|
dd89933613 | ||
|
|
5101dace59 | ||
|
|
81c56a740c | ||
|
|
27cc3bcccd | ||
|
|
8ddaa26a57 | ||
|
|
3a848428c3 | ||
|
|
4c18f3aa1d | ||
|
|
be6278c0b7 | ||
|
|
d5e08d5db2 | ||
|
|
2d321b4a79 | ||
|
|
fcd764d521 | ||
|
|
7d4a8782d8 | ||
|
|
eea28e8481 | ||
|
|
71d679d426 | ||
|
|
2b23523bec | ||
|
|
149c26728c | ||
|
|
8c5c2440fe | ||
|
|
f22caed20c | ||
|
|
ed3e7e7c26 | ||
|
|
54bc33a1a2 | ||
|
|
900e141297 | ||
|
|
ca1eca476c | ||
|
|
c4d2593a42 | ||
|
|
932811c167 | ||
|
|
95ad101a08 | ||
|
|
a0c329019f | ||
|
|
8a92913230 | ||
|
|
5a8deddc63 | ||
|
|
2a1e60da44 | ||
|
|
6ca3deeac1 | ||
|
|
1b2edbb79a | ||
|
|
49c9929a53 | ||
|
|
8ce73a38dd | ||
|
|
28ebf7a0cc | ||
|
|
4f168656fc | ||
|
|
7f1f758e60 | ||
|
|
f8ab71953d | ||
|
|
eb50ee1c03 | ||
|
|
a184cb9bc4 | ||
|
|
0b50a10fb8 | ||
|
|
9bafdc1b0b | ||
|
|
63af54353b | ||
|
|
b67739af13 | ||
|
|
40633619ca | ||
|
|
e672d1d896 | ||
|
|
c69d162f5a | ||
|
|
2fd97b1753 | ||
|
|
5f893929da | ||
|
|
1c06b7b608 | ||
|
|
3ac64d65b6 | ||
|
|
f4f83283d3 | ||
|
|
aed4a55655 | ||
|
|
5f55a56a9e | ||
|
|
e95e79b572 | ||
|
|
15c0d0074b | ||
|
|
f4716cb62f | ||
|
|
1f2dfce7d1 | ||
|
|
c679631440 | ||
|
|
c62fd4841a | ||
|
|
a073113817 | ||
|
|
09d462b829 | ||
|
|
379b171f0a | ||
|
|
c424e22924 | ||
|
|
18e171446e | ||
|
|
c0a1555c73 | ||
|
|
3b0c844f33 | ||
|
|
566a4f3568 | ||
|
|
2c8b19bff2 | ||
|
|
292dca6419 | ||
|
|
ebe0f98209 | ||
|
|
eba1e5495f | ||
|
|
0ebd04f012 | ||
|
|
c5e8a3fa04 | ||
|
|
42b76fd82d | ||
|
|
bbf610569d | ||
|
|
eeb5fa81a1 | ||
|
|
f65ca6678f | ||
|
|
680f48dcba | ||
|
|
8947e00302 | ||
|
|
b42cf32326 | ||
|
|
5b68332b9a | ||
|
|
d7f53862e9 | ||
|
|
7887bf96de | ||
|
|
db2aa35b2f | ||
|
|
936b0e59ab | ||
|
|
6e3923d0da | ||
|
|
4377575206 | ||
|
|
0c09b12680 | ||
|
|
8a32d8032f | ||
|
|
9f12a91f4a | ||
|
|
dd0ca4bcaf | ||
|
|
14cc97eb44 | ||
|
|
2d31c5b005 | ||
|
|
05e7506f61 | ||
|
|
37806f1113 | ||
|
|
79622f324b | ||
|
|
34e84081e3 | ||
|
|
edf07be281 | ||
|
|
1208514f37 | ||
|
|
bfd857ec4b | ||
|
|
9435290bb6 | ||
|
|
acf64dcf25 | ||
|
|
2dd88364f8 | ||
|
|
d900b52a50 | ||
|
|
bd8d96be4d | ||
|
|
17dd07fe32 | ||
|
|
a06e5f28b3 | ||
|
|
d5f400670c |
@@ -13,9 +13,9 @@
|
||||
1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。1Panel 的功能和优势包括:
|
||||
|
||||
- **快速建站**:深度集成 Wordpress 和 [Halo](https://github.com/halo-dev/halo/),域名绑定、SSL 证书配置等一键搞定;
|
||||
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括应用管理、主机监控、文件管理、数据库管理、容器管理等;
|
||||
- **安全可靠**:最小漏洞暴露面,提供防火墙和安全审计等功能;
|
||||
- **一键备份**:支持一键备份和恢复,备份数据云端存储,永不丢失。
|
||||
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括主机监控、文件管理、数据库管理、容器管理等;
|
||||
- **安全可靠**:基于容器来管理和部署应用,最小漏洞暴露面,提供防火墙和日志审计等功能;
|
||||
- **一键备份**:支持一键备份和恢复,备份数据到各类云端存储,永不丢失。
|
||||
|
||||
## UI 展示
|
||||
|
||||
@@ -41,12 +41,9 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
||||
|
||||
- [在线文档](https://1panel.cn/docs/)
|
||||
- [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
|
||||
- [社区论坛](https://bbs.fit2cloud.com/c/1p/7)
|
||||
|
||||
## 社区
|
||||
|
||||
如果您在使用过程中有任何疑问或对建议,欢迎提交 GitHub Issue 或加入到我们微信交流群进行交流沟通。
|
||||
|
||||
**微信交流群**
|
||||
**加入微信交流群**
|
||||
|
||||
<img src="https://1panel.cn/img/wechat-group.jpg" width="156" height="156"/>
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
如果您发现安全问题,请直接联系我们:
|
||||
|
||||
- wanghe@fit2cloud.com
|
||||
- zhengkun@fit2cloud.com
|
||||
- support@fit2cloud.com
|
||||
- 400-052-0755
|
||||
|
||||
@@ -13,6 +14,7 @@
|
||||
All security bugs should be reported to the contact as below:
|
||||
|
||||
- wanghe@fit2cloud.com
|
||||
- zhengkun@fit2cloud.com
|
||||
- support@fit2cloud.com
|
||||
- 400-052-0755
|
||||
|
||||
|
||||
@@ -38,14 +38,15 @@ func (b *BaseApi) SearchApp(c *gin.Context) {
|
||||
// @Router /apps/sync [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"应用商店同步","formatEN":"App store synchronization"}
|
||||
func (b *BaseApi) SyncApp(c *gin.Context) {
|
||||
appService.SyncAppListFromLocal()
|
||||
global.LOG.Infof("sync app list start ...")
|
||||
if err := appService.SyncAppListFromRemote(); err != nil {
|
||||
global.LOG.Errorf("sync app list error [%s]", err.Error())
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
global.LOG.Infof("sync app list success!")
|
||||
go appService.SyncAppListFromLocal()
|
||||
go func() {
|
||||
global.LOG.Infof("sync app list start ...")
|
||||
if err := appService.SyncAppListFromRemote(); err != nil {
|
||||
global.LOG.Errorf("sync app list error [%s]", err.Error())
|
||||
} else {
|
||||
global.LOG.Infof("sync app list success!")
|
||||
}
|
||||
}()
|
||||
helper.SuccessWithData(c, "")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
@@ -28,7 +26,7 @@ func (b *BaseApi) Login(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if req.AuthMethod != "jwt" {
|
||||
if req.AuthMethod != "jwt" && !req.IgnoreCaptcha {
|
||||
if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -102,71 +100,10 @@ func (b *BaseApi) Captcha(c *gin.Context) {
|
||||
// @Summary Load safety status
|
||||
// @Description 获取系统安全登录状态
|
||||
// @Success 200
|
||||
// @Failure 402
|
||||
// @Router /auth/status [get]
|
||||
func (b *BaseApi) GetSafetyStatus(c *gin.Context) {
|
||||
if err := authService.SafetyStatus(c); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) SafeEntrance(c *gin.Context) {
|
||||
code, exist := c.Params.Get("code")
|
||||
if !exist {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, errors.New("missing code"))
|
||||
return
|
||||
}
|
||||
ok, err := authService.VerifyCode(code)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, errors.New("missing code"))
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, errors.New("missing code"))
|
||||
return
|
||||
}
|
||||
if err := authService.SafeEntrance(c, code); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, errors.New("missing code"))
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Auth
|
||||
// @Summary Check is First login
|
||||
// @Description 判断是否为首次登录
|
||||
// @Success 200
|
||||
// @Router /auth/status [get]
|
||||
func (b *BaseApi) CheckIsFirstLogin(c *gin.Context) {
|
||||
helper.SuccessWithData(c, authService.CheckIsFirst())
|
||||
}
|
||||
|
||||
// @Tags Auth
|
||||
// @Summary Init user
|
||||
// @Description 初始化用户
|
||||
// @Accept json
|
||||
// @Param request body dto.InitUser true "request"
|
||||
// @Success 200
|
||||
// @Router /auth/init [post]
|
||||
func (b *BaseApi) InitUserInfo(c *gin.Context) {
|
||||
var req dto.InitUser
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := global.VALID.Struct(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := authService.InitUser(c, req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
// @Router /auth/issafety [get]
|
||||
func (b *BaseApi) CheckIsSafety(c *gin.Context) {
|
||||
code := c.DefaultQuery("code", "")
|
||||
helper.SuccessWithData(c, authService.CheckIsSafety(code))
|
||||
}
|
||||
|
||||
// @Tags Auth
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"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/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -77,8 +78,9 @@ func (b *BaseApi) SearchJobRecords(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.StartTime = req.StartTime.Add(8 * time.Hour)
|
||||
req.EndTime = req.EndTime.Add(8 * time.Hour)
|
||||
loc, _ := time.LoadLocation(common.LoadTimeZone())
|
||||
req.StartTime = req.StartTime.In(loc)
|
||||
req.EndTime = req.EndTime.In(loc)
|
||||
|
||||
total, list, err := cronjobService.SearchRecords(req)
|
||||
if err != nil {
|
||||
|
||||
@@ -186,7 +186,29 @@ func (b *BaseApi) ChangeFileMode(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Change file owner
|
||||
// @Description 修改文件用户/组
|
||||
// @Accept json
|
||||
// @Param request body request.FileRoleUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /files/owner [post]
|
||||
// @x-panel-log {"bodyKeys":["path","user","group"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改用户/组 [paths] => [user]/[group]","formatEN":"Change owner [paths] => [user]/[group]"}
|
||||
func (b *BaseApi) ChangeFileOwner(c *gin.Context) {
|
||||
var req request.FileRoleUpdate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := fileService.ChangeOwner(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
@@ -498,7 +520,6 @@ func (b *BaseApi) Size(c *gin.Context) {
|
||||
// @Success 200 {string} content
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /files/loadfile [post]
|
||||
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"读取文件 [path]","formatEN":"Read file [path]"}
|
||||
func (b *BaseApi) LoadFromFile(c *gin.Context) {
|
||||
var req dto.FilePath
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"github.com/shirou/gopsutil/v3/net"
|
||||
@@ -24,8 +25,9 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.StartTime = req.StartTime.Add(8 * time.Hour)
|
||||
req.EndTime = req.EndTime.Add(8 * time.Hour)
|
||||
loc, _ := time.LoadLocation(common.LoadTimeZone())
|
||||
req.StartTime = req.StartTime.In(loc)
|
||||
req.EndTime = req.EndTime.In(loc)
|
||||
|
||||
var backdatas []dto.MonitorData
|
||||
if req.Param == "all" || req.Param == "cpu" || req.Param == "memory" || req.Param == "load" {
|
||||
|
||||
@@ -92,6 +92,48 @@ func (b *BaseApi) UpdatePassword(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Update system ssl
|
||||
// @Description 修改系统 ssl 登录
|
||||
// @Accept json
|
||||
// @Param request body dto.SSLUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/ssl/update [post]
|
||||
// @x-panel-log {"bodyKeys":["ssl"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统 ssl => [ssl]","formatEN":"update system ssl => [ssl]"}
|
||||
func (b *BaseApi) UpdateSSL(c *gin.Context) {
|
||||
var req dto.SSLUpdate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := global.VALID.Struct(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := settingService.UpdateSSL(c, req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Load system cert info
|
||||
// @Description 获取证书信息
|
||||
// @Success 200 {object} dto.SettingInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/ssl/info [get]
|
||||
func (b *BaseApi) LoadFromCert(c *gin.Context) {
|
||||
info, err := settingService.LoadFromCert()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, info)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Update system port
|
||||
// @Description 更新系统端口
|
||||
@@ -154,7 +196,7 @@ func (b *BaseApi) HandlePasswordExpired(c *gin.Context) {
|
||||
// @Router /settings/time/sync [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"系统时间同步","formatEN":"sync system time"}
|
||||
func (b *BaseApi) SyncTime(c *gin.Context) {
|
||||
ntime, err := ntp.Getremotetime()
|
||||
ntime, err := ntp.GetRemoteTime()
|
||||
if err != nil {
|
||||
helper.SuccessWithData(c, time.Now().Format("2006-01-02 15:04:05 MST -0700"))
|
||||
return
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -107,14 +108,15 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
defer wsConn.Close()
|
||||
commands := fmt.Sprintf("docker exec -it %s redis-cli", redisConf.ContainerName)
|
||||
commands := "redis-cli"
|
||||
if len(redisConf.Requirepass) != 0 {
|
||||
commands = fmt.Sprintf("docker exec -it %s redis-cli -a %s --no-auth-warning", redisConf.ContainerName, redisConf.Requirepass)
|
||||
commands = fmt.Sprintf("redis-cli -a %s --no-auth-warning", redisConf.Requirepass)
|
||||
}
|
||||
slave, err := terminal.NewCommand(commands)
|
||||
slave, err := terminal.NewCommand(fmt.Sprintf("docker exec -it %s %s", redisConf.ContainerName, commands))
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
defer killBash(redisConf.ContainerName, commands)
|
||||
defer slave.Close()
|
||||
|
||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
|
||||
@@ -177,6 +179,7 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
defer killBash(containerID, command)
|
||||
defer slave.Close()
|
||||
|
||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
|
||||
@@ -216,6 +219,15 @@ func wshandleError(ws *websocket.Conn, err error) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func killBash(containerID, comm string) {
|
||||
sudo := ""
|
||||
if cmd.HasNoPasswordSudo() {
|
||||
sudo = "sudo"
|
||||
}
|
||||
command := exec.Command("sh", "-c", fmt.Sprintf("%s kill -9 $(docker top %s -eo pid,command | grep '%s' | awk '{print $1}')", sudo, containerID, comm))
|
||||
_, _ = command.CombinedOutput()
|
||||
}
|
||||
|
||||
var upGrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024 * 1024 * 10,
|
||||
|
||||
@@ -648,3 +648,113 @@ func (b *BaseApi) UpdateSiteDirPermission(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Get proxy conf
|
||||
// @Description 获取反向代理配置
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteProxyReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/proxies [post]
|
||||
func (b *BaseApi) GetProxyConfig(c *gin.Context) {
|
||||
var req request.WebsiteProxyReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
res, err := websiteService.GetProxies(req.ID)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Update proxy conf
|
||||
// @Description 修改反向代理配置
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteProxyConfig true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/proxies/update [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"修改网站 [domain] 反向代理配置 ","formatEN":"Update domain [domain] proxy config"}
|
||||
func (b *BaseApi) UpdateProxyConfig(c *gin.Context) {
|
||||
var req request.WebsiteProxyConfig
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
err := websiteService.OperateProxy(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Update proxy file
|
||||
// @Description 更新反向代理文件
|
||||
// @Accept json
|
||||
// @Param request body request.NginxProxyUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/proxy/file [post]
|
||||
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteID","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新反向代理文件 [domain]","formatEN":"Nginx conf proxy file update [domain]"}
|
||||
func (b *BaseApi) UpdateProxyConfigFile(c *gin.Context) {
|
||||
var req request.NginxProxyUpdate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := websiteService.UpdateProxyFile(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Get AuthBasic conf
|
||||
// @Description 获取密码访问配置
|
||||
// @Accept json
|
||||
// @Param request body request.NginxAuthReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/auths [post]
|
||||
func (b *BaseApi) GetAuthConfig(c *gin.Context) {
|
||||
var req request.NginxAuthReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
res, err := websiteService.GetAuthBasics(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Get AuthBasic conf
|
||||
// @Description 更新密码访问配置
|
||||
// @Accept json
|
||||
// @Param request body request.NginxAuthUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/auths/update [post]
|
||||
func (b *BaseApi) UpdateAuthConfig(c *gin.Context) {
|
||||
var req request.NginxAuthUpdate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := websiteService.UpdateAuthBasic(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
+6
-10
@@ -17,11 +17,12 @@ type MfaCredential struct {
|
||||
}
|
||||
|
||||
type Login struct {
|
||||
Name string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
Captcha string `json:"captcha"`
|
||||
CaptchaID string `json:"captchaID"`
|
||||
AuthMethod string `json:"authMethod"`
|
||||
Name string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
IgnoreCaptcha bool `json:"ignoreCaptcha"`
|
||||
Captcha string `json:"captcha"`
|
||||
CaptchaID string `json:"captchaID"`
|
||||
AuthMethod string `json:"authMethod"`
|
||||
}
|
||||
|
||||
type MFALogin struct {
|
||||
@@ -30,8 +31,3 @@ type MFALogin struct {
|
||||
Code string `json:"code"`
|
||||
AuthMethod string `json:"authMethod"`
|
||||
}
|
||||
|
||||
type InitUser struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ type PageInfo struct {
|
||||
|
||||
type UpdateDescription struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Description string `json:"description"`
|
||||
Description string `json:"description" validate:"max=256"`
|
||||
}
|
||||
|
||||
type OperationWithName struct {
|
||||
|
||||
@@ -22,6 +22,10 @@ type ContainerInfo struct {
|
||||
State string `json:"state"`
|
||||
RunTime string `json:"runTime"`
|
||||
|
||||
CPUPercent float64 `json:"cpuPercent"`
|
||||
MemoryPercent float64 `json:"memoryPercent"`
|
||||
Ports []string `json:"ports"`
|
||||
|
||||
IsFromApp bool `json:"isFromApp"`
|
||||
IsFromCompose bool `json:"isFromCompose"`
|
||||
}
|
||||
@@ -59,8 +63,10 @@ type VolumeHelper struct {
|
||||
Mode string `json:"mode"`
|
||||
}
|
||||
type PortHelper struct {
|
||||
ContainerPort int `json:"containerPort"`
|
||||
HostPort int `json:"hostPort"`
|
||||
HostIP string `json:"hostIP"`
|
||||
HostPort string `json:"hostPort"`
|
||||
ContainerPort string `json:"containerPort"`
|
||||
Protocol string `json:"protocol"`
|
||||
}
|
||||
|
||||
type ContainerLog struct {
|
||||
@@ -140,6 +146,7 @@ type ComposeOperation struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Path string `json:"path" validate:"required"`
|
||||
Operation string `json:"operation" validate:"required,oneof=start stop down"`
|
||||
WithFile bool `json:"withFile"`
|
||||
}
|
||||
type ComposeUpdate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
|
||||
@@ -28,13 +28,20 @@ type NginxParam struct {
|
||||
Params []string
|
||||
}
|
||||
|
||||
type NginxAuth struct {
|
||||
Username string `json:"username"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type NginxKey string
|
||||
|
||||
const (
|
||||
Index NginxKey = "index"
|
||||
LimitConn NginxKey = "limit-conn"
|
||||
SSL NginxKey = "ssl"
|
||||
HttpPer NginxKey = "http-per"
|
||||
Index NginxKey = "index"
|
||||
LimitConn NginxKey = "limit-conn"
|
||||
SSL NginxKey = "ssl"
|
||||
CACHE NginxKey = "cache"
|
||||
HttpPer NginxKey = "http-per"
|
||||
ProxyCache NginxKey = "proxy-cache"
|
||||
)
|
||||
|
||||
var ScopeKeyMap = map[NginxKey][]string{
|
||||
@@ -46,5 +53,7 @@ var ScopeKeyMap = map[NginxKey][]string{
|
||||
|
||||
var StaticFileKeyMap = map[NginxKey]struct {
|
||||
}{
|
||||
SSL: {},
|
||||
SSL: {},
|
||||
CACHE: {},
|
||||
ProxyCache: {},
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ type FileCreate struct {
|
||||
IsLink bool `json:"isLink"`
|
||||
IsSymlink bool `json:"isSymlink"`
|
||||
LinkPath string `json:"linkPath"`
|
||||
Sub bool `json:"sub"`
|
||||
}
|
||||
|
||||
type FileDelete struct {
|
||||
@@ -88,3 +89,10 @@ type DirSizeReq struct {
|
||||
type FileProcessReq struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
type FileRoleUpdate struct {
|
||||
Path string `json:"path" validate:"required"`
|
||||
User string `json:"user" validate:"required"`
|
||||
Group string `json:"group" validate:"required"`
|
||||
Sub bool `json:"sub" validate:"required"`
|
||||
}
|
||||
|
||||
@@ -30,3 +30,21 @@ type NginxRewriteUpdate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Content string `json:"content" validate:"required"`
|
||||
}
|
||||
|
||||
type NginxProxyUpdate struct {
|
||||
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||
Content string `json:"content" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
}
|
||||
|
||||
type NginxAuthUpdate struct {
|
||||
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||
Operate string `json:"operate" validate:"required"`
|
||||
Username string `json:"username" validate:"required"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type NginxAuthReq struct {
|
||||
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||
}
|
||||
|
||||
@@ -156,3 +156,24 @@ type WebsiteUpdateDirPermission struct {
|
||||
User string `json:"user" validate:"required"`
|
||||
Group string `json:"group" validate:"required"`
|
||||
}
|
||||
|
||||
type WebsiteProxyConfig struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Operate string `json:"operate" validate:"required"`
|
||||
Enable bool `json:"enable" validate:"required"`
|
||||
Cache bool `json:"cache" validate:"required"`
|
||||
CacheTime int `json:"cacheTime" validate:"required"`
|
||||
CacheUnit string `json:"cacheUnit" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Modifier string `json:"modifier" validate:"required"`
|
||||
Match string `json:"match" validate:"required"`
|
||||
ProxyPass string `json:"proxyPass" validate:"required"`
|
||||
ProxyHost string `json:"proxyHost" validate:"required"`
|
||||
Content string `json:"content"`
|
||||
FilePath string `json:"filePath"`
|
||||
Replaces map[string]string `json:"replaces"`
|
||||
}
|
||||
|
||||
type WebsiteProxyReq struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package response
|
||||
|
||||
import "github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
|
||||
type NginxStatus struct {
|
||||
Active string `json:"active"`
|
||||
Accepts string `json:"accepts"`
|
||||
@@ -14,3 +16,8 @@ type NginxParam struct {
|
||||
Name string `json:"name"`
|
||||
Params []string `json:"params"`
|
||||
}
|
||||
|
||||
type NginxAuthRes struct {
|
||||
Enable bool `json:"enable"`
|
||||
Items []dto.NginxAuth `json:"items"`
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ type SettingInfo struct {
|
||||
Language string `json:"language"`
|
||||
|
||||
ServerPort string `json:"serverPort"`
|
||||
SSL string `json:"ssl"`
|
||||
SSLType string `json:"sslType"`
|
||||
SecurityEntrance string `json:"securityEntrance"`
|
||||
ExpirationDays string `json:"expirationDays"`
|
||||
ExpirationTime string `json:"expirationTime"`
|
||||
@@ -39,6 +41,23 @@ type SettingUpdate struct {
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type SSLUpdate struct {
|
||||
SSLType string `json:"sslType"`
|
||||
Domain string `json:"domain"`
|
||||
SSL string `json:"ssl" validate:"required,oneof=enable disable"`
|
||||
Cert string `json:"cert"`
|
||||
Key string `json:"key"`
|
||||
SSLID uint `json:"sslID"`
|
||||
}
|
||||
type SSLInfo struct {
|
||||
Domain string `json:"domain"`
|
||||
Timeout string `json:"timeout"`
|
||||
RootPath string `json:"rootPath"`
|
||||
Cert string `json:"cert"`
|
||||
Key string `json:"key"`
|
||||
SSLID uint `json:"sslID"`
|
||||
}
|
||||
|
||||
type PasswordUpdate struct {
|
||||
OldPassword string `json:"oldPassword" validate:"required"`
|
||||
NewPassword string `json:"newPassword" validate:"required"`
|
||||
@@ -50,7 +69,7 @@ type PortUpdate struct {
|
||||
|
||||
type SnapshotCreate struct {
|
||||
From string `json:"from" validate:"required,oneof=OSS S3 SFTP MINIO COS KODO"`
|
||||
Description string `json:"description"`
|
||||
Description string `json:"description" validate:"max=256"`
|
||||
}
|
||||
type SnapshotRecover struct {
|
||||
IsNew bool `json:"isNew"`
|
||||
@@ -60,12 +79,12 @@ type SnapshotRecover struct {
|
||||
type SnapshotImport struct {
|
||||
From string `json:"from"`
|
||||
Names []string `json:"names"`
|
||||
Description string `json:"description"`
|
||||
Description string `json:"description" validate:"max=256"`
|
||||
}
|
||||
type SnapshotInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Description string `json:"description" validate:"max=256"`
|
||||
From string `json:"from"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
|
||||
@@ -343,13 +343,6 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
||||
}
|
||||
go upApp(appInstall)
|
||||
go updateToolApp(appInstall)
|
||||
ports := []int{appInstall.HttpPort}
|
||||
if appInstall.HttpsPort > 0 {
|
||||
ports = append(ports, appInstall.HttpsPort)
|
||||
}
|
||||
go func() {
|
||||
_ = OperateFirewallPort(nil, ports)
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -226,6 +226,10 @@ func upgradeInstall(installId uint, detailId uint) error {
|
||||
}
|
||||
|
||||
detailDir := path.Join(constant.ResourceDir, "apps", install.App.Key, "versions", detail.Version)
|
||||
if install.App.Resource == constant.AppResourceLocal {
|
||||
detailDir = path.Join(constant.ResourceDir, "localApps", strings.TrimPrefix(install.App.Key, "local"), "versions", detail.Version)
|
||||
}
|
||||
|
||||
cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rf %s/* %s", detailDir, install.GetPath()))
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
@@ -566,6 +570,9 @@ func getAppFromRepo(downloadPath, version string) error {
|
||||
func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]response.AppInstalledDTO, error) {
|
||||
var res []response.AppInstalledDTO
|
||||
for _, installed := range appInstallList {
|
||||
if updated && installed.App.Type == "php" {
|
||||
continue
|
||||
}
|
||||
installDTO := response.AppInstalledDTO{
|
||||
AppInstall: installed,
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
@@ -19,11 +17,8 @@ import (
|
||||
type AuthService struct{}
|
||||
|
||||
type IAuthService interface {
|
||||
SafetyStatus(c *gin.Context) error
|
||||
CheckIsFirst() bool
|
||||
InitUser(c *gin.Context, req dto.InitUser) error
|
||||
CheckIsSafety(code string) bool
|
||||
VerifyCode(code string) (bool, error)
|
||||
SafeEntrance(c *gin.Context, code string) error
|
||||
Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error)
|
||||
LogOut(c *gin.Context) error
|
||||
MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLoginInfo, error)
|
||||
@@ -33,22 +28,6 @@ func NewIAuthService() IAuthService {
|
||||
return &AuthService{}
|
||||
}
|
||||
|
||||
func (u *AuthService) SafeEntrance(c *gin.Context, code string) error {
|
||||
codeWithMD5 := encrypt.Md5(code)
|
||||
cookieValue, _ := encrypt.StringEncrypt(codeWithMD5)
|
||||
c.SetCookie(codeWithMD5, cookieValue, 604800, "", "", false, false)
|
||||
|
||||
expiredSetting, err := settingRepo.Get(settingRepo.WithByKey("ExpirationDays"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
timeout, _ := strconv.Atoi(expiredSetting.Value)
|
||||
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error) {
|
||||
nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName"))
|
||||
if err != nil {
|
||||
@@ -164,57 +143,13 @@ func (u *AuthService) VerifyCode(code string) (bool, error) {
|
||||
return setting.Value == code, nil
|
||||
}
|
||||
|
||||
func (u *AuthService) SafetyStatus(c *gin.Context) error {
|
||||
setting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
|
||||
func (u *AuthService) CheckIsSafety(code string) bool {
|
||||
status, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
|
||||
if err != nil {
|
||||
return err
|
||||
return false
|
||||
}
|
||||
codeWithEcrypt, err := c.Cookie(encrypt.Md5(setting.Value))
|
||||
if err != nil {
|
||||
return err
|
||||
if len(status.Value) == 0 {
|
||||
return true
|
||||
}
|
||||
code, err := encrypt.StringDecrypt(codeWithEcrypt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if code != encrypt.Md5(setting.Value) {
|
||||
return errors.New("code not match")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *AuthService) CheckIsFirst() bool {
|
||||
user, _ := settingRepo.Get(settingRepo.WithByKey("UserName"))
|
||||
pass, _ := settingRepo.Get(settingRepo.WithByKey("Password"))
|
||||
return len(user.Value) == 0 || len(pass.Value) == 0
|
||||
}
|
||||
|
||||
func (u *AuthService) InitUser(c *gin.Context, req dto.InitUser) error {
|
||||
user, _ := settingRepo.Get(settingRepo.WithByKey("UserName"))
|
||||
pass, _ := settingRepo.Get(settingRepo.WithByKey("Password"))
|
||||
if len(user.Value) == 0 || len(pass.Value) == 0 {
|
||||
newPass, err := encrypt.StringEncrypt(req.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.Update("UserName", req.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.Update("Password", newPass); err != nil {
|
||||
return err
|
||||
}
|
||||
expiredSetting, err := settingRepo.Get(settingRepo.WithByKey("ExpirationDays"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
timeout, _ := strconv.Atoi(expiredSetting.Value)
|
||||
if timeout != 0 {
|
||||
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("can't init user because user %s is in system", user.Value)
|
||||
return status.Value == code
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
fileUtils "github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -223,7 +223,7 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
|
||||
if strings.HasSuffix(dirStr, "/") {
|
||||
dirStr = dirStr[:strings.LastIndex(dirStr, "/")]
|
||||
}
|
||||
if err := updateBackupDir(dirStr, oldDir); err != nil {
|
||||
if err := copyDir(oldDir, dirStr); err != nil {
|
||||
_ = backupRepo.Update(req.ID, (map[string]interface{}{"vars": oldVars}))
|
||||
return err
|
||||
}
|
||||
@@ -309,18 +309,33 @@ func loadLocalDir() (string, error) {
|
||||
return "", fmt.Errorf("error type dir: %T", varMap["dir"])
|
||||
}
|
||||
|
||||
func updateBackupDir(dir, oldDir string) error {
|
||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||
return err
|
||||
func copyDir(src, dst string) error {
|
||||
srcInfo, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = os.MkdirAll(dst, srcInfo.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
files, err := os.ReadDir(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fileOP := fileUtils.NewFileOp()
|
||||
for _, file := range files {
|
||||
srcPath := fmt.Sprintf("%s/%s", src, file.Name())
|
||||
dstPath := fmt.Sprintf("%s/%s", dst, file.Name())
|
||||
if file.IsDir() {
|
||||
if err = copyDir(srcPath, dstPath); err != nil {
|
||||
global.LOG.Errorf("copy dir %s to %s failed, err: %v", srcPath, dstPath, err)
|
||||
}
|
||||
} else {
|
||||
if err := fileOP.CopyFile(srcPath, dst); err != nil {
|
||||
global.LOG.Errorf("copy file %s to %s failed, err: %v", srcPath, dstPath, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(oldDir, "/") {
|
||||
oldDir = oldDir[:strings.LastIndex(oldDir, "/")]
|
||||
}
|
||||
stdout, err := cmd.Execf("cp -r %s/* %s", oldDir, dir)
|
||||
if err != nil {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
@@ -97,27 +98,45 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
records = list[start:end]
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(records))
|
||||
for _, container := range records {
|
||||
IsFromCompose := false
|
||||
if _, ok := container.Labels[composeProjectLabel]; ok {
|
||||
IsFromCompose = true
|
||||
}
|
||||
IsFromApp := false
|
||||
if created, ok := container.Labels[composeCreatedBy]; ok && created == "Apps" {
|
||||
IsFromApp = true
|
||||
}
|
||||
backDatas = append(backDatas, dto.ContainerInfo{
|
||||
ContainerID: container.ID,
|
||||
CreateTime: time.Unix(container.Created, 0).Format("2006-01-02 15:04:05"),
|
||||
Name: container.Names[0][1:],
|
||||
ImageId: strings.Split(container.ImageID, ":")[1],
|
||||
ImageName: container.Image,
|
||||
State: container.State,
|
||||
RunTime: container.Status,
|
||||
IsFromApp: IsFromApp,
|
||||
IsFromCompose: IsFromCompose,
|
||||
})
|
||||
go func(item types.Container) {
|
||||
IsFromCompose := false
|
||||
if _, ok := item.Labels[composeProjectLabel]; ok {
|
||||
IsFromCompose = true
|
||||
}
|
||||
IsFromApp := false
|
||||
if created, ok := item.Labels[composeCreatedBy]; ok && created == "Apps" {
|
||||
IsFromApp = true
|
||||
}
|
||||
|
||||
var ports []string
|
||||
for _, port := range item.Ports {
|
||||
if port.IP == "::" || port.PublicPort == 0 {
|
||||
continue
|
||||
}
|
||||
ports = append(ports, fmt.Sprintf("%v:%v/%s", port.PublicPort, port.PrivatePort, port.Type))
|
||||
}
|
||||
cpu, mem := loadCpuAndMem(client, item.ID)
|
||||
backDatas = append(backDatas, dto.ContainerInfo{
|
||||
ContainerID: item.ID,
|
||||
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,
|
||||
State: item.State,
|
||||
RunTime: item.Status,
|
||||
CPUPercent: cpu,
|
||||
MemoryPercent: mem,
|
||||
Ports: ports,
|
||||
IsFromApp: IsFromApp,
|
||||
IsFromCompose: IsFromCompose,
|
||||
})
|
||||
wg.Done()
|
||||
}(container)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
return int64(total), backDatas, nil
|
||||
}
|
||||
@@ -147,24 +166,27 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
|
||||
}
|
||||
|
||||
func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
||||
if len(req.ExposedPorts) != 0 {
|
||||
for _, port := range req.ExposedPorts {
|
||||
if common.ScanPort(port.HostPort) {
|
||||
return buserr.WithDetail(constant.ErrPortInUsed, port.HostPort, nil)
|
||||
}
|
||||
}
|
||||
portMap, err := checkPortStats(req.ExposedPorts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exposeds := make(nat.PortSet)
|
||||
for port := range portMap {
|
||||
exposeds[port] = struct{}{}
|
||||
}
|
||||
config := &container.Config{
|
||||
Image: req.Image,
|
||||
Cmd: req.Cmd,
|
||||
Env: req.Env,
|
||||
Labels: stringsToMap(req.Labels),
|
||||
Tty: true,
|
||||
OpenStdin: true,
|
||||
Image: req.Image,
|
||||
Cmd: req.Cmd,
|
||||
Env: req.Env,
|
||||
Labels: stringsToMap(req.Labels),
|
||||
Tty: true,
|
||||
OpenStdin: true,
|
||||
ExposedPorts: exposeds,
|
||||
}
|
||||
hostConf := &container.HostConfig{
|
||||
AutoRemove: req.AutoRemove,
|
||||
@@ -181,11 +203,7 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
||||
hostConf.Memory = req.Memory
|
||||
}
|
||||
if len(req.ExposedPorts) != 0 {
|
||||
hostConf.PortBindings = make(nat.PortMap)
|
||||
for _, port := range req.ExposedPorts {
|
||||
bindItem := nat.PortBinding{HostPort: strconv.Itoa(port.HostPort)}
|
||||
hostConf.PortBindings[nat.Port(fmt.Sprintf("%d/tcp", port.ContainerPort))] = []nat.PortBinding{bindItem}
|
||||
}
|
||||
hostConf.PortBindings = portMap
|
||||
}
|
||||
if len(req.Volumes) != 0 {
|
||||
config.Volumes = make(map[string]struct{})
|
||||
@@ -270,16 +288,16 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainterStats, erro
|
||||
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
res.Body.Close()
|
||||
return nil, err
|
||||
}
|
||||
res.Body.Close()
|
||||
var stats *types.StatsJSON
|
||||
if err := json.Unmarshal(body, &stats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var data dto.ContainterStats
|
||||
previousCPU := stats.PreCPUStats.CPUUsage.TotalUsage
|
||||
previousSystem := stats.PreCPUStats.SystemUsage
|
||||
data.CPUPercent = calculateCPUPercentUnix(previousCPU, previousSystem, stats)
|
||||
data.CPUPercent = calculateCPUPercentUnix(stats)
|
||||
data.IORead, data.IOWrite = calculateBlockIO(stats.BlkioStats)
|
||||
data.Memory = float64(stats.MemoryStats.Usage) / 1024 / 1024
|
||||
if cache, ok := stats.MemoryStats.Stats["cache"]; ok {
|
||||
@@ -294,25 +312,36 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainterStats, erro
|
||||
func stringsToMap(list []string) map[string]string {
|
||||
var lableMap = make(map[string]string)
|
||||
for _, label := range list {
|
||||
sps := strings.Split(label, "=")
|
||||
if len(sps) > 1 {
|
||||
if strings.Contains(label, "=") {
|
||||
sps := strings.SplitN(label, "=", 2)
|
||||
lableMap[sps[0]] = sps[1]
|
||||
}
|
||||
}
|
||||
return lableMap
|
||||
}
|
||||
func calculateCPUPercentUnix(previousCPU, previousSystem uint64, v *types.StatsJSON) float64 {
|
||||
var (
|
||||
cpuPercent = 0.0
|
||||
cpuDelta = float64(v.CPUStats.CPUUsage.TotalUsage) - float64(previousCPU)
|
||||
systemDelta = float64(v.CPUStats.SystemUsage) - float64(previousSystem)
|
||||
)
|
||||
|
||||
func calculateCPUPercentUnix(stats *types.StatsJSON) float64 {
|
||||
cpuPercent := 0.0
|
||||
cpuDelta := float64(stats.CPUStats.CPUUsage.TotalUsage) - float64(stats.PreCPUStats.CPUUsage.TotalUsage)
|
||||
systemDelta := float64(stats.CPUStats.SystemUsage) - float64(stats.PreCPUStats.SystemUsage)
|
||||
|
||||
if systemDelta > 0.0 && cpuDelta > 0.0 {
|
||||
cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CPUStats.CPUUsage.PercpuUsage)) * 100.0
|
||||
cpuPercent = (cpuDelta / systemDelta) * 100.0
|
||||
if len(stats.CPUStats.CPUUsage.PercpuUsage) != 0 {
|
||||
cpuPercent = cpuPercent * float64(len(stats.CPUStats.CPUUsage.PercpuUsage))
|
||||
}
|
||||
}
|
||||
return cpuPercent
|
||||
}
|
||||
func calculateMemPercentUnix(memStats types.MemoryStats) float64 {
|
||||
memPercent := 0.0
|
||||
memUsage := float64(memStats.Usage - memStats.Stats["cache"])
|
||||
memLimit := float64(memStats.Limit)
|
||||
if memUsage > 0.0 && memLimit > 0.0 {
|
||||
memPercent = (memUsage / memLimit) * 100.0
|
||||
}
|
||||
return memPercent
|
||||
}
|
||||
func calculateBlockIO(blkio types.BlkioStats) (blkRead float64, blkWrite float64) {
|
||||
for _, bioEntry := range blkio.IoServiceBytesRecursive {
|
||||
switch strings.ToLower(bioEntry.Op) {
|
||||
@@ -363,3 +392,71 @@ func pullImages(ctx context.Context, client *client.Client, image string) error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadCpuAndMem(client *client.Client, container string) (float64, float64) {
|
||||
res, err := client.ContainerStats(context.Background(), container, false)
|
||||
if err != nil {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
res.Body.Close()
|
||||
return 0, 0
|
||||
}
|
||||
res.Body.Close()
|
||||
var stats *types.StatsJSON
|
||||
if err := json.Unmarshal(body, &stats); err != nil {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
CPUPercent := calculateCPUPercentUnix(stats)
|
||||
MemPercent := calculateMemPercentUnix(stats.MemoryStats)
|
||||
return CPUPercent, MemPercent
|
||||
}
|
||||
|
||||
func checkPortStats(ports []dto.PortHelper) (nat.PortMap, error) {
|
||||
portMap := make(nat.PortMap)
|
||||
if len(ports) == 0 {
|
||||
return portMap, nil
|
||||
}
|
||||
for _, port := range ports {
|
||||
if strings.Contains(port.ContainerPort, "-") {
|
||||
if !strings.Contains(port.HostPort, "-") {
|
||||
return portMap, buserr.New(constant.ErrPortRules)
|
||||
}
|
||||
hostStart, _ := strconv.Atoi(strings.Split(port.HostPort, "-")[0])
|
||||
hostEnd, _ := strconv.Atoi(strings.Split(port.HostPort, "-")[1])
|
||||
containerStart, _ := strconv.Atoi(strings.Split(port.ContainerPort, "-")[0])
|
||||
containerEnd, _ := strconv.Atoi(strings.Split(port.ContainerPort, "-")[1])
|
||||
if (hostEnd-hostStart) <= 0 || (containerEnd-containerStart) <= 0 {
|
||||
return portMap, buserr.New(constant.ErrPortRules)
|
||||
}
|
||||
if (containerEnd - containerStart) != (hostEnd - hostStart) {
|
||||
return portMap, buserr.New(constant.ErrPortRules)
|
||||
}
|
||||
for i := 0; i <= hostEnd-hostStart; i++ {
|
||||
bindItem := nat.PortBinding{HostPort: strconv.Itoa(hostStart + i), HostIP: port.HostIP}
|
||||
portMap[nat.Port(fmt.Sprintf("%d/%s", containerStart+i, port.Protocol))] = []nat.PortBinding{bindItem}
|
||||
}
|
||||
for i := hostStart; i <= hostEnd; i++ {
|
||||
if common.ScanPort(i) {
|
||||
return portMap, buserr.WithDetail(constant.ErrPortInUsed, i, nil)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
portItem := 0
|
||||
if strings.Contains(port.HostPort, "-") {
|
||||
portItem, _ = strconv.Atoi(strings.Split(port.HostPort, "-")[0])
|
||||
} else {
|
||||
portItem, _ = strconv.Atoi(port.HostPort)
|
||||
}
|
||||
if common.ScanPort(portItem) {
|
||||
return portMap, buserr.WithDetail(constant.ErrPortInUsed, portItem, nil)
|
||||
}
|
||||
bindItem := nat.PortBinding{HostPort: strconv.Itoa(portItem), HostIP: port.HostIP}
|
||||
portMap[nat.Port(fmt.Sprintf("%s/%s", port.ContainerPort, port.Protocol))] = []nat.PortBinding{bindItem}
|
||||
}
|
||||
}
|
||||
return portMap, nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
@@ -154,9 +155,10 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
|
||||
go func() {
|
||||
defer file.Close()
|
||||
cmd := exec.Command("docker-compose", "-f", req.Path, "up", "-d")
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
_, _ = file.Write(stdout)
|
||||
if err != nil {
|
||||
multiWriter := io.MultiWriter(os.Stdout, file)
|
||||
cmd.Stdout = multiWriter
|
||||
cmd.Stderr = multiWriter
|
||||
if err := cmd.Run(); err != nil {
|
||||
global.LOG.Errorf("docker-compose up %s failed, err: %v", req.Name, err)
|
||||
_, _ = compose.Down(req.Path)
|
||||
_, _ = file.WriteString("docker-compose up failed!")
|
||||
@@ -180,7 +182,9 @@ func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
|
||||
global.LOG.Infof("docker-compose %s %s successful", req.Operation, req.Name)
|
||||
if req.Operation == "down" {
|
||||
_ = composeRepo.DeleteRecord(commonRepo.WithByName(req.Name))
|
||||
_ = os.RemoveAll(strings.ReplaceAll(req.Path, "/docker-compose.yml", ""))
|
||||
if req.WithFile {
|
||||
_ = os.RemoveAll(path.Dir(req.Path))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -211,15 +215,7 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
|
||||
}
|
||||
|
||||
func (u *ContainerService) loadPath(req *dto.ComposeCreate) error {
|
||||
if req.From == "template" {
|
||||
template, err := composeRepo.Get(commonRepo.WithByID(req.Template))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.From = "edit"
|
||||
req.File = template.Content
|
||||
}
|
||||
if req.From == "edit" {
|
||||
if req.From == "template" || req.From == "edit" {
|
||||
dir := fmt.Sprintf("%s/docker/compose/%s", constant.DataDir, req.Name)
|
||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||
|
||||
@@ -29,7 +29,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||
if len(cronjob.Script) == 0 {
|
||||
return
|
||||
}
|
||||
stdout, errExec := cmd.ExecWithTimeOut(cronjob.Script, 5*time.Minute)
|
||||
stdout, errExec := cmd.ExecCronjobWithTimeOut(cronjob.Script, 5*time.Minute)
|
||||
if errExec != nil {
|
||||
err = errExec
|
||||
}
|
||||
|
||||
@@ -518,12 +518,12 @@ func excSQL(containerName, password, command string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(ctx, "docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
|
||||
err := cmd.Run()
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
return buserr.WithDetail(constant.ErrExecTimeOut, containerName, nil)
|
||||
}
|
||||
if err != nil {
|
||||
stdStr := strings.ReplaceAll(err.Error(), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
||||
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
||||
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
|
||||
return errors.New(stdStr)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -39,6 +39,7 @@ type IFileService interface {
|
||||
ChangeName(req request.FileRename) error
|
||||
Wget(w request.FileWget) (string, error)
|
||||
MvFile(m request.FileMove) error
|
||||
ChangeOwner(req request.FileRoleUpdate) error
|
||||
}
|
||||
|
||||
func NewIFileService() IFileService {
|
||||
@@ -159,7 +160,16 @@ func (f *FileService) BatchDelete(op request.FileBatchDelete) error {
|
||||
|
||||
func (f *FileService) ChangeMode(op request.FileCreate) error {
|
||||
fo := files.NewFileOp()
|
||||
return fo.Chmod(op.Path, fs.FileMode(op.Mode))
|
||||
if op.Sub {
|
||||
return fo.ChmodR(op.Path, op.Mode)
|
||||
} else {
|
||||
return fo.Chmod(op.Path, fs.FileMode(op.Mode))
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FileService) ChangeOwner(req request.FileRoleUpdate) error {
|
||||
fo := files.NewFileOp()
|
||||
return fo.ChownR(req.Path, req.User, req.Group, req.Sub)
|
||||
}
|
||||
|
||||
func (f *FileService) Compress(c request.FileCompress) error {
|
||||
|
||||
@@ -161,6 +161,10 @@ func getNginxParamsFromStaticFile(scope dto.NginxKey, newParams []dto.NginxParam
|
||||
switch scope {
|
||||
case dto.SSL:
|
||||
newConfig = parser.NewStringParser(string(nginx_conf.SSL)).Parse()
|
||||
case dto.CACHE:
|
||||
newConfig = parser.NewStringParser(string(nginx_conf.Cache)).Parse()
|
||||
case dto.ProxyCache:
|
||||
newConfig = parser.NewStringParser(string(nginx_conf.ProxyCache)).Parse()
|
||||
}
|
||||
for _, dir := range newConfig.GetDirectives() {
|
||||
addParam := dto.NginxParam{
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
@@ -12,6 +18,8 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -22,6 +30,8 @@ type ISettingService interface {
|
||||
Update(key, value string) error
|
||||
UpdatePassword(c *gin.Context, old, new string) error
|
||||
UpdatePort(port uint) error
|
||||
UpdateSSL(c *gin.Context, req dto.SSLUpdate) error
|
||||
LoadFromCert() (*dto.SSLInfo, error)
|
||||
HandlePasswordExpired(c *gin.Context, old, new string) error
|
||||
}
|
||||
|
||||
@@ -90,6 +100,135 @@ func (u *SettingService) UpdatePort(port uint) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error {
|
||||
secretDir := global.CONF.System.BaseDir + "/1panel/secret/"
|
||||
if req.SSL == "disable" {
|
||||
if err := settingRepo.Update("SSL", "disable"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.Update("SSLType", "self"); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = os.Remove(secretDir + "server.crt")
|
||||
_ = os.Remove(secretDir + "server.key")
|
||||
go func() {
|
||||
_, err := cmd.Exec("systemctl restart 1panel.service")
|
||||
if err != nil {
|
||||
global.LOG.Errorf("restart system failed, err: %v", err)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := os.Stat(secretDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(secretDir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := settingRepo.Update("SSLType", req.SSLType); err != nil {
|
||||
return err
|
||||
}
|
||||
if req.SSLType == "self" {
|
||||
if len(req.Domain) == 0 {
|
||||
return fmt.Errorf("load domain failed")
|
||||
}
|
||||
if err := ssl.GenerateSSL(req.Domain); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if req.SSLType == "select" {
|
||||
sslInfo, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Cert = sslInfo.Pem
|
||||
req.Key = sslInfo.PrivateKey
|
||||
req.SSLType = "import"
|
||||
if err := settingRepo.Update("SSLID", strconv.Itoa(int(req.SSLID))); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if req.SSLType == "import" {
|
||||
cert, err := os.OpenFile(secretDir+"server.crt.tmp", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cert.Close()
|
||||
if _, err := cert.WriteString(req.Cert); err != nil {
|
||||
return err
|
||||
}
|
||||
key, err := os.OpenFile(secretDir+"server.key.tmp", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := key.WriteString(req.Key); err != nil {
|
||||
return err
|
||||
}
|
||||
defer key.Close()
|
||||
}
|
||||
if err := checkCertValid(req.Domain); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fileOp := files.NewFileOp()
|
||||
if err := fileOp.Rename(secretDir+"server.crt.tmp", secretDir+"server.crt"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fileOp.Rename(secretDir+"server.key.tmp", secretDir+"server.key"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.Update("SSL", req.SSL); err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
_, err := cmd.Exec("systemctl restart 1panel.service")
|
||||
if err != nil {
|
||||
global.LOG.Errorf("restart system failed, err: %v", err)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *SettingService) LoadFromCert() (*dto.SSLInfo, error) {
|
||||
ssl, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ssl.Value == "disable" {
|
||||
return &dto.SSLInfo{}, nil
|
||||
}
|
||||
sslType, err := settingRepo.Get(settingRepo.WithByKey("SSLType"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := loadInfoFromCert()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch sslType.Value {
|
||||
case "import":
|
||||
if _, err := os.Stat(global.CONF.System.BaseDir + "/1panel/secret/server.crt"); err != nil {
|
||||
return nil, fmt.Errorf("load server.crt file failed, err: %v", err)
|
||||
}
|
||||
certFile, _ := os.ReadFile(global.CONF.System.BaseDir + "/1panel/secret/server.crt")
|
||||
data.Cert = string(certFile)
|
||||
|
||||
if _, err := os.Stat(global.CONF.System.BaseDir + "/1panel/secret/server.key"); err != nil {
|
||||
return nil, fmt.Errorf("load server.key file failed, err: %v", err)
|
||||
}
|
||||
keyFile, _ := os.ReadFile(global.CONF.System.BaseDir + "/1panel/secret/server.key")
|
||||
data.Key = string(keyFile)
|
||||
case "select":
|
||||
sslID, err := settingRepo.Get(settingRepo.WithByKey("SSLID"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, _ := strconv.Atoi(sslID.Value)
|
||||
data.SSLID = uint(id)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (u *SettingService) HandlePasswordExpired(c *gin.Context, old, new string) error {
|
||||
setting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
|
||||
if err != nil {
|
||||
@@ -128,3 +267,60 @@ func (u *SettingService) UpdatePassword(c *gin.Context, old, new string) error {
|
||||
_ = global.SESSION.Clean()
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadInfoFromCert() (*dto.SSLInfo, error) {
|
||||
var info dto.SSLInfo
|
||||
certFile := global.CONF.System.BaseDir + "/1panel/secret/server.crt"
|
||||
if _, err := os.Stat(certFile); err != nil {
|
||||
return &info, err
|
||||
}
|
||||
certData, err := os.ReadFile(certFile)
|
||||
if err != nil {
|
||||
return &info, err
|
||||
}
|
||||
certBlock, _ := pem.Decode(certData)
|
||||
if certBlock == nil {
|
||||
return &info, err
|
||||
}
|
||||
certObj, err := x509.ParseCertificate(certBlock.Bytes)
|
||||
if err != nil {
|
||||
return &info, err
|
||||
}
|
||||
var domains []string
|
||||
if len(certObj.IPAddresses) != 0 {
|
||||
for _, ip := range certObj.IPAddresses {
|
||||
domains = append(domains, ip.String())
|
||||
}
|
||||
}
|
||||
if len(certObj.DNSNames) != 0 {
|
||||
domains = append(domains, certObj.DNSNames...)
|
||||
}
|
||||
return &dto.SSLInfo{
|
||||
Domain: strings.Join(domains, ","),
|
||||
Timeout: certObj.NotAfter.Format("2006-01-02 15:04:05"),
|
||||
RootPath: global.CONF.System.BaseDir + "/1panel/secret/server.crt",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func checkCertValid(domain string) error {
|
||||
certificate, err := os.ReadFile(global.CONF.System.BaseDir + "/1panel/secret/server.crt.tmp")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key, err := os.ReadFile(global.CONF.System.BaseDir + "/1panel/secret/server.key.tmp")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tls.X509KeyPair(certificate, key); err != nil {
|
||||
return err
|
||||
}
|
||||
certBlock, _ := pem.Decode(certificate)
|
||||
if certBlock == nil {
|
||||
return err
|
||||
}
|
||||
if _, err := x509.ParseCertificate(certBlock.Bytes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+443
-10
@@ -10,12 +10,18 @@ import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser"
|
||||
"github.com/1Panel-dev/1Panel/cmd/server/nginx_conf"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -64,6 +70,11 @@ type IWebsiteService interface {
|
||||
UpdateRewriteConfig(req request.NginxRewriteUpdate) error
|
||||
UpdateSiteDir(req request.WebsiteUpdateDir) error
|
||||
UpdateSitePermission(req request.WebsiteUpdateDirPermission) error
|
||||
OperateProxy(req request.WebsiteProxyConfig) (err error)
|
||||
GetProxies(id uint) (res []request.WebsiteProxyConfig, err error)
|
||||
UpdateProxyFile(req request.NginxProxyUpdate) (err error)
|
||||
GetAuthBasics(req request.NginxAuthReq) (res response.NginxAuthRes, err error)
|
||||
UpdateAuthBasic(req request.NginxAuthUpdate) (err error)
|
||||
}
|
||||
|
||||
func NewIWebsiteService() IWebsiteService {
|
||||
@@ -75,6 +86,13 @@ func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []respons
|
||||
websiteDTOs []response.WebsiteDTO
|
||||
opts []repo.DBOption
|
||||
)
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return 0, nil, nil
|
||||
}
|
||||
return 0, nil, err
|
||||
}
|
||||
opts = append(opts, commonRepo.WithOrderBy("created_at desc"))
|
||||
if req.Name != "" {
|
||||
opts = append(opts, websiteRepo.WithDomainLike(req.Name))
|
||||
@@ -105,10 +123,12 @@ 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.WebsiteDTO{
|
||||
Website: web,
|
||||
AppName: appName,
|
||||
RuntimeName: runtimeName,
|
||||
SitePath: sitePath,
|
||||
})
|
||||
}
|
||||
return total, websiteDTOs, nil
|
||||
@@ -393,10 +413,16 @@ func (w WebsiteService) DeleteWebsite(req request.WebsiteDelete) error {
|
||||
}
|
||||
|
||||
func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate) (model.WebsiteDomain, error) {
|
||||
var domainModel model.WebsiteDomain
|
||||
var ports []int
|
||||
var domains []string
|
||||
|
||||
var (
|
||||
domainModel model.WebsiteDomain
|
||||
ports []int
|
||||
domains []string
|
||||
)
|
||||
if create.Port != 80 {
|
||||
if common.ScanPort(create.Port) {
|
||||
return domainModel, buserr.WithDetail(constant.ErrPortInUsed, create.Port, nil)
|
||||
}
|
||||
}
|
||||
website, err := websiteRepo.GetFirst(commonRepo.WithByID(create.WebsiteID))
|
||||
if err != nil {
|
||||
return domainModel, err
|
||||
@@ -413,6 +439,11 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
||||
Port: create.Port,
|
||||
WebsiteID: create.WebsiteID,
|
||||
}
|
||||
if create.Port != 80 {
|
||||
go func() {
|
||||
_ = OperateFirewallPort(nil, []int{create.Port})
|
||||
}()
|
||||
}
|
||||
return domainModel, websiteDomainRepo.Create(context.TODO(), &domainModel)
|
||||
}
|
||||
|
||||
@@ -443,7 +474,11 @@ func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error {
|
||||
domains = append(domains, webSiteDomain.Domain)
|
||||
}
|
||||
if len(ports) > 0 || len(domains) > 0 {
|
||||
if err := deleteListenAndServerName(website, ports, domains); err != nil {
|
||||
stringBinds := make([]string, len(ports))
|
||||
for i := 0; i < len(ports); i++ {
|
||||
stringBinds[i] = strconv.Itoa(ports[i])
|
||||
}
|
||||
if err := deleteListenAndServerName(website, stringBinds, domains); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -590,14 +625,28 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
|
||||
if !req.Enable {
|
||||
website.Protocol = constant.ProtocolHTTP
|
||||
website.WebsiteSSLID = 0
|
||||
if err := deleteListenAndServerName(website, []int{443}, []string{}); err != nil {
|
||||
if err := deleteListenAndServerName(website, []string{"443", "[::]:443"}, []string{}); err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
}
|
||||
nginxParams := getNginxParamsFromStaticFile(dto.SSL, nil)
|
||||
nginxParams = append(nginxParams, dto.NginxParam{
|
||||
Name: "if",
|
||||
Params: []string{"($scheme", "=", "http)"},
|
||||
})
|
||||
nginxParams = append(nginxParams,
|
||||
dto.NginxParam{
|
||||
Name: "if",
|
||||
Params: []string{"($scheme", "=", "http)"},
|
||||
},
|
||||
dto.NginxParam{
|
||||
Name: "ssl_certificate",
|
||||
},
|
||||
dto.NginxParam{
|
||||
Name: "ssl_certificate_key",
|
||||
},
|
||||
dto.NginxParam{
|
||||
Name: "ssl_protocols",
|
||||
},
|
||||
dto.NginxParam{
|
||||
Name: "ssl_ciphers",
|
||||
},
|
||||
)
|
||||
if err := deleteNginxConfig(constant.NginxScopeServer, nginxParams, &website); err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
}
|
||||
@@ -1105,3 +1154,387 @@ func (w WebsiteService) UpdateSitePermission(req request.WebsiteUpdateDirPermiss
|
||||
website.Group = req.Group
|
||||
return websiteRepo.Save(context.Background(), &website)
|
||||
}
|
||||
|
||||
func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error) {
|
||||
var (
|
||||
website model.Website
|
||||
params []response.NginxParam
|
||||
nginxInstall model.AppInstall
|
||||
par *parser.Parser
|
||||
oldContent []byte
|
||||
)
|
||||
|
||||
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
params, err = getNginxParamsByKeys(constant.NginxScopeHttp, []string{"proxy_cache"}, &website)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fileOp := files.NewFileOp()
|
||||
if len(params) == 0 || len(params[0].Params) == 0 {
|
||||
commonDir := path.Join(nginxInstall.GetPath(), "www", "common", "proxy")
|
||||
proxyTempPath := path.Join(commonDir, "proxy_temp_dir")
|
||||
if !fileOp.Stat(proxyTempPath) {
|
||||
_ = fileOp.CreateDir(proxyTempPath, 0755)
|
||||
}
|
||||
proxyCacheDir := path.Join(commonDir, "proxy_temp_dir")
|
||||
if !fileOp.Stat(proxyCacheDir) {
|
||||
_ = fileOp.CreateDir(proxyCacheDir, 0755)
|
||||
}
|
||||
nginxParams := getNginxParamsFromStaticFile(dto.CACHE, nil)
|
||||
if err = updateNginxConfig(constant.NginxScopeHttp, nginxParams, &website); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "proxy")
|
||||
if !fileOp.Stat(includeDir) {
|
||||
_ = fileOp.CreateDir(includeDir, 0755)
|
||||
}
|
||||
fileName := fmt.Sprintf("%s.conf", req.Name)
|
||||
includePath := path.Join(includeDir, fileName)
|
||||
backName := fmt.Sprintf("%s.bak", req.Name)
|
||||
backPath := path.Join(includeDir, backName)
|
||||
|
||||
if req.Operate == "create" && (fileOp.Stat(includePath) || fileOp.Stat(backPath)) {
|
||||
err = buserr.New(constant.ErrNameIsExist)
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
switch req.Operate {
|
||||
case "create":
|
||||
_ = fileOp.DeleteFile(includePath)
|
||||
case "edit":
|
||||
_ = fileOp.WriteFile(includePath, bytes.NewReader(oldContent), 0755)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var config *components.Config
|
||||
|
||||
switch req.Operate {
|
||||
case "create":
|
||||
config = parser.NewStringParser(string(nginx_conf.Proxy)).Parse()
|
||||
case "edit":
|
||||
par, err = parser.NewParser(includePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
config = par.Parse()
|
||||
oldContent, err = fileOp.GetContent(includePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case "delete":
|
||||
_ = fileOp.DeleteFile(includePath)
|
||||
_ = fileOp.DeleteFile(backPath)
|
||||
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
||||
case "disable":
|
||||
_ = fileOp.Rename(includePath, backPath)
|
||||
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
||||
case "enable":
|
||||
_ = fileOp.Rename(backPath, includePath)
|
||||
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
||||
}
|
||||
config.FilePath = includePath
|
||||
directives := config.Directives
|
||||
location, ok := directives[0].(*components.Location)
|
||||
if !ok {
|
||||
err = errors.New("error")
|
||||
return
|
||||
}
|
||||
location.UpdateDirective("proxy_pass", []string{req.ProxyPass})
|
||||
location.UpdateDirective("proxy_set_header", []string{"Host", req.ProxyHost})
|
||||
location.ChangePath(req.Modifier, req.Match)
|
||||
if req.Cache {
|
||||
location.AddCache(req.CacheTime, req.CacheUnit)
|
||||
} else {
|
||||
location.RemoveCache()
|
||||
}
|
||||
if len(req.Replaces) > 0 {
|
||||
location.AddSubFilter(req.Replaces)
|
||||
} else {
|
||||
location.RemoveSubFilter()
|
||||
}
|
||||
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
||||
}
|
||||
nginxInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
|
||||
if err = updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "include", Params: []string{nginxInclude}}}, &website); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, err error) {
|
||||
var (
|
||||
website model.Website
|
||||
nginxInstall model.AppInstall
|
||||
fileList response.FileInfo
|
||||
)
|
||||
website, err = websiteRepo.GetFirst(commonRepo.WithByID(id))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "proxy")
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(includeDir) {
|
||||
return
|
||||
}
|
||||
fileList, err = NewIFileService().GetFileList(request.FileOption{FileOption: files.FileOption{Path: includeDir, Expand: true, Page: 1, PageSize: 100}})
|
||||
if len(fileList.Items) == 0 {
|
||||
return
|
||||
}
|
||||
var (
|
||||
content []byte
|
||||
config *components.Config
|
||||
)
|
||||
for _, configFile := range fileList.Items {
|
||||
proxyConfig := request.WebsiteProxyConfig{
|
||||
ID: website.ID,
|
||||
}
|
||||
parts := strings.Split(configFile.Name, ".")
|
||||
proxyConfig.Name = parts[0]
|
||||
if parts[1] == "conf" {
|
||||
proxyConfig.Enable = true
|
||||
} else {
|
||||
proxyConfig.Enable = false
|
||||
}
|
||||
proxyConfig.FilePath = configFile.Path
|
||||
content, err = fileOp.GetContent(configFile.Path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
proxyConfig.Content = string(content)
|
||||
config = parser.NewStringParser(string(content)).Parse()
|
||||
directives := config.GetDirectives()
|
||||
|
||||
location, ok := directives[0].(*components.Location)
|
||||
if !ok {
|
||||
err = errors.New("error")
|
||||
return
|
||||
}
|
||||
proxyConfig.ProxyPass = location.ProxyPass
|
||||
proxyConfig.Cache = location.Cache
|
||||
if location.CacheTime > 0 {
|
||||
proxyConfig.CacheTime = location.CacheTime
|
||||
proxyConfig.CacheUnit = location.CacheUint
|
||||
}
|
||||
proxyConfig.Match = location.Match
|
||||
proxyConfig.Modifier = location.Modifier
|
||||
proxyConfig.ProxyHost = location.Host
|
||||
proxyConfig.Replaces = location.Replaces
|
||||
res = append(res, proxyConfig)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w WebsiteService) UpdateProxyFile(req request.NginxProxyUpdate) (err error) {
|
||||
var (
|
||||
website model.Website
|
||||
nginxFull dto.NginxFull
|
||||
oldRewriteContent []byte
|
||||
)
|
||||
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nginxFull, err = getNginxFull(&website)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
includePath := fmt.Sprintf("/www/sites/%s/proxy/%s.conf", website.Alias, req.Name)
|
||||
absolutePath := path.Join(nginxFull.Install.GetPath(), includePath)
|
||||
fileOp := files.NewFileOp()
|
||||
oldRewriteContent, err = fileOp.GetContent(absolutePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = fileOp.WriteFile(absolutePath, strings.NewReader(req.Content), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = fileOp.WriteFile(absolutePath, bytes.NewReader(oldRewriteContent), 0755)
|
||||
}
|
||||
}()
|
||||
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
||||
}
|
||||
|
||||
func (w WebsiteService) UpdateAuthBasic(req request.NginxAuthUpdate) (err error) {
|
||||
var (
|
||||
website model.Website
|
||||
nginxInstall model.AppInstall
|
||||
params []dto.NginxParam
|
||||
authContent []byte
|
||||
authArray []string
|
||||
)
|
||||
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
authPath := fmt.Sprintf("/www/sites/%s/auth_basic/auth.pass", website.Alias)
|
||||
absoluteAuthPath := path.Join(nginxInstall.GetPath(), authPath)
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(path.Dir(absoluteAuthPath)) {
|
||||
_ = fileOp.CreateDir(path.Dir(absoluteAuthPath), 0755)
|
||||
}
|
||||
if !fileOp.Stat(absoluteAuthPath) {
|
||||
_ = fileOp.CreateFile(absoluteAuthPath)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
switch req.Operate {
|
||||
case "create":
|
||||
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
params = append(params, dto.NginxParam{Name: "auth_basic", Params: []string{`"Authentication"`}})
|
||||
params = append(params, dto.NginxParam{Name: "auth_basic_user_file", Params: []string{authPath}})
|
||||
authContent, err = fileOp.GetContent(absoluteAuthPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
authArray = strings.Split(string(authContent), "\n")
|
||||
switch req.Operate {
|
||||
case "disable":
|
||||
return deleteNginxConfig(constant.NginxScopeServer, params, &website)
|
||||
case "enable":
|
||||
return updateNginxConfig(constant.NginxScopeServer, params, &website)
|
||||
case "create":
|
||||
for _, line := range authArray {
|
||||
authParams := strings.Split(line, ":")
|
||||
username := authParams[0]
|
||||
if username == req.Username {
|
||||
err = buserr.New(constant.ErrUsernameIsExist)
|
||||
return
|
||||
}
|
||||
}
|
||||
var passwdHash []byte
|
||||
passwdHash, err = bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
line := fmt.Sprintf("%s:%s\n", req.Username, passwdHash)
|
||||
if req.Remark != "" {
|
||||
line = fmt.Sprintf("%s:%s:%s\n", req.Username, passwdHash, req.Remark)
|
||||
}
|
||||
authArray = append(authArray, line)
|
||||
case "edit":
|
||||
userExist := false
|
||||
for index, line := range authArray {
|
||||
authParams := strings.Split(line, ":")
|
||||
username := authParams[0]
|
||||
if username == req.Username {
|
||||
userExist = true
|
||||
var passwdHash []byte
|
||||
passwdHash, err = bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
userPasswd := fmt.Sprintf("%s:%s\n", req.Username, passwdHash)
|
||||
if req.Remark != "" {
|
||||
userPasswd = fmt.Sprintf("%s:%s:%s\n", req.Username, passwdHash, req.Remark)
|
||||
}
|
||||
authArray[index] = userPasswd
|
||||
}
|
||||
}
|
||||
if !userExist {
|
||||
err = buserr.New(constant.ErrUsernameIsNotExist)
|
||||
return
|
||||
}
|
||||
case "delete":
|
||||
deleteIndex := -1
|
||||
for index, line := range authArray {
|
||||
authParams := strings.Split(line, ":")
|
||||
username := authParams[0]
|
||||
if username == req.Username {
|
||||
deleteIndex = index
|
||||
}
|
||||
}
|
||||
if deleteIndex < 0 {
|
||||
return
|
||||
}
|
||||
authArray = append(authArray[:deleteIndex], authArray[deleteIndex+1:]...)
|
||||
}
|
||||
|
||||
var passFile *os.File
|
||||
passFile, err = os.Create(absoluteAuthPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer passFile.Close()
|
||||
writer := bufio.NewWriter(passFile)
|
||||
for _, line := range authArray {
|
||||
_, err = writer.WriteString(line + "\n")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = writer.Flush()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w WebsiteService) GetAuthBasics(req request.NginxAuthReq) (res response.NginxAuthRes, err error) {
|
||||
var (
|
||||
website model.Website
|
||||
nginxInstall model.AppInstall
|
||||
authContent []byte
|
||||
nginxParams []response.NginxParam
|
||||
)
|
||||
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
authPath := fmt.Sprintf("/www/sites/%s/auth_basic/auth.pass", website.Alias)
|
||||
absoluteAuthPath := path.Join(nginxInstall.GetPath(), authPath)
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(absoluteAuthPath) {
|
||||
return
|
||||
}
|
||||
nginxParams, err = getNginxParamsByKeys(constant.NginxScopeServer, []string{"auth_basic"}, &website)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res.Enable = len(nginxParams[0].Params) > 0
|
||||
authContent, err = fileOp.GetContent(absoluteAuthPath)
|
||||
authArray := strings.Split(string(authContent), "\n")
|
||||
for _, line := range authArray {
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
params := strings.Split(line, ":")
|
||||
auth := dto.NginxAuth{
|
||||
Username: params[0],
|
||||
}
|
||||
if len(params) == 3 {
|
||||
auth.Remark = params[2]
|
||||
}
|
||||
res.Items = append(res.Items, auth)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -84,6 +86,40 @@ func createIndexFile(website *model.Website, runtime *model.Runtime) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func createProxyFile(website *model.Website, runtime *model.Runtime) error {
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
proxyFolder := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "www", "sites", website.Alias, "proxy")
|
||||
filePath := path.Join(proxyFolder, "root.conf")
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(proxyFolder) {
|
||||
if err := fileOp.CreateDir(proxyFolder, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !fileOp.Stat(filePath) {
|
||||
if err := fileOp.CreateFile(filePath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
config := parser.NewStringParser(string(nginx_conf.Proxy)).Parse()
|
||||
config.FilePath = filePath
|
||||
directives := config.Directives
|
||||
location, ok := directives[0].(*components.Location)
|
||||
if !ok {
|
||||
return errors.New("error")
|
||||
}
|
||||
location.ChangePath("^~", "/")
|
||||
location.UpdateDirective("proxy_pass", []string{website.Proxy})
|
||||
location.UpdateDirective("proxy_set_header", []string{"Host", "$host"})
|
||||
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createWebsiteFolder(nginxInstall model.AppInstall, website *model.Website, runtime *model.Runtime) error {
|
||||
nginxFolder := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name)
|
||||
siteFolder := path.Join(nginxFolder, "www", "sites", website.Alias)
|
||||
@@ -123,6 +159,11 @@ func createWebsiteFolder(nginxInstall model.AppInstall, website *model.Website,
|
||||
return err
|
||||
}
|
||||
}
|
||||
if website.Type == constant.Proxy {
|
||||
if err := createProxyFile(website, runtime); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return fileOp.CopyDir(path.Join(nginxFolder, "www", "common", "waf", "rules"), path.Join(siteFolder, "waf"))
|
||||
}
|
||||
@@ -167,9 +208,9 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
|
||||
server.UpdateRootProxy([]string{proxy})
|
||||
case constant.Static:
|
||||
server.UpdateRoot(rootIndex)
|
||||
//server.UpdateRootLocation()
|
||||
case constant.Proxy:
|
||||
server.UpdateRootProxy([]string{website.Proxy})
|
||||
nginxInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
|
||||
server.UpdateDirective("include", []string{nginxInclude})
|
||||
case constant.Runtime:
|
||||
if runtime.Resource == constant.ResourceLocal {
|
||||
switch runtime.Type {
|
||||
@@ -192,7 +233,6 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
|
||||
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := opNginx(nginxInstall.ContainerName, constant.NginxCheck); err != nil {
|
||||
_ = deleteWebsiteFolder(nginxInstall, website)
|
||||
return err
|
||||
@@ -261,7 +301,7 @@ func addListenAndServerName(website model.Website, ports []int, domains []string
|
||||
return nginxCheckAndReload(nginxConfig.OldContent, nginxConfig.FilePath, nginxFull.Install.ContainerName)
|
||||
}
|
||||
|
||||
func deleteListenAndServerName(website model.Website, ports []int, domains []string) error {
|
||||
func deleteListenAndServerName(website model.Website, binds []string, domains []string) error {
|
||||
nginxFull, err := getNginxFull(&website)
|
||||
if err != nil {
|
||||
return nil
|
||||
@@ -269,8 +309,8 @@ func deleteListenAndServerName(website model.Website, ports []int, domains []str
|
||||
nginxConfig := nginxFull.SiteConfig
|
||||
config := nginxFull.SiteConfig.Config
|
||||
server := config.FindServers()[0]
|
||||
for _, port := range ports {
|
||||
server.DeleteListen(strconv.Itoa(port))
|
||||
for _, bind := range binds {
|
||||
server.DeleteListen(bind)
|
||||
}
|
||||
for _, domain := range domains {
|
||||
server.DeleteServerName(domain)
|
||||
@@ -332,16 +372,20 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
|
||||
config := nginxFull.SiteConfig.Config
|
||||
server := config.FindServers()[0]
|
||||
server.UpdateListen("443", false, "ssl")
|
||||
server.UpdateListen("[::]:443", false, "ssl")
|
||||
|
||||
switch req.HttpConfig {
|
||||
case constant.HTTPSOnly:
|
||||
server.RemoveListenByBind("80")
|
||||
server.RemoveListenByBind("[::]:80")
|
||||
server.RemoveDirective("if", []string{"($scheme"})
|
||||
case constant.HTTPToHTTPS:
|
||||
server.UpdateListen("80", website.DefaultServer)
|
||||
server.UpdateListen("[::]:80", false)
|
||||
server.AddHTTP2HTTPS()
|
||||
case constant.HTTPAlso:
|
||||
server.UpdateListen("80", website.DefaultServer)
|
||||
server.UpdateListen("[::]:80", false)
|
||||
server.RemoveDirective("if", []string{"($scheme"})
|
||||
}
|
||||
|
||||
@@ -453,16 +497,32 @@ func opWebsite(website *model.Website, operate string) error {
|
||||
}
|
||||
server := servers[0]
|
||||
if operate == constant.StopWeb {
|
||||
if website.Type == constant.Deployment || website.Type == constant.Static || website.Type == constant.Proxy {
|
||||
server.RemoveDirective("location", []string{"", "/"})
|
||||
}
|
||||
if website.Type == constant.Runtime {
|
||||
proxyInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
|
||||
server.RemoveDirective("include", []string{proxyInclude})
|
||||
rewriteInclude := fmt.Sprintf("/www/sites/%s/rewrite/%s.conf", website.Alias, website.Alias)
|
||||
server.RemoveDirective("include", []string{rewriteInclude})
|
||||
|
||||
switch website.Type {
|
||||
case constant.Deployment:
|
||||
server.RemoveDirective("location", []string{"/"})
|
||||
case constant.Runtime:
|
||||
server.RemoveDirective("location", []string{"~", "[^/]\\.php(/|$)"})
|
||||
}
|
||||
server.UpdateRoot("/usr/share/nginx/html/stop")
|
||||
website.Status = constant.WebStopped
|
||||
}
|
||||
if operate == constant.StartWeb {
|
||||
proxyInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
|
||||
absoluteIncludeDir := path.Join(nginxInstall.Install.GetPath(), fmt.Sprintf("/www/sites/%s/proxy", website.Alias))
|
||||
if files.NewFileOp().Stat(absoluteIncludeDir) {
|
||||
server.UpdateDirective("include", []string{proxyInclude})
|
||||
}
|
||||
server.UpdateDirective("include", []string{proxyInclude})
|
||||
rewriteInclude := fmt.Sprintf("/www/sites/%s/rewrite/%s.conf", website.Alias, website.Alias)
|
||||
absoluteRewritePath := path.Join(nginxInstall.Install.GetPath(), rewriteInclude)
|
||||
if files.NewFileOp().Stat(absoluteRewritePath) {
|
||||
server.UpdateDirective("include", []string{rewriteInclude})
|
||||
}
|
||||
switch website.Type {
|
||||
case constant.Deployment:
|
||||
server.RemoveDirective("root", nil)
|
||||
@@ -477,7 +537,6 @@ func opWebsite(website *model.Website, operate string) error {
|
||||
server.UpdateRootLocation()
|
||||
case constant.Proxy:
|
||||
server.RemoveDirective("root", nil)
|
||||
server.UpdateRootProxy([]string{website.Proxy})
|
||||
case constant.Runtime:
|
||||
rootIndex := path.Join("/www/sites", website.Alias, "index")
|
||||
server.UpdateRoot(rootIndex)
|
||||
|
||||
@@ -2,6 +2,7 @@ package configs
|
||||
|
||||
type System struct {
|
||||
Port string `mapstructure:"port"`
|
||||
SSL string `mapstructure:"ssl"`
|
||||
DbFile string `mapstructure:"db_file"`
|
||||
DbPath string `mapstructure:"db_path"`
|
||||
LogPath string `mapstructure:"log_path"`
|
||||
@@ -14,5 +15,8 @@ type System struct {
|
||||
Mode string `mapstructure:"mode"`
|
||||
RepoUrl string `mapstructure:"repo_url"`
|
||||
Version string `mapstructure:"version"`
|
||||
Username string `mapstructure:"username"`
|
||||
Password string `mapstructure:"password"`
|
||||
Entrance string `mapstructure:"entrance"`
|
||||
IsDemo bool `mapstructure:"is_demo"`
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ var (
|
||||
ErrTypeNotSafety = "ErrNotSafety"
|
||||
ErrNameIsExist = "ErrNameIsExist"
|
||||
ErrDemoEnvironment = "ErrDemoEnvironment"
|
||||
ErrInitUser = "ErrInitUser"
|
||||
)
|
||||
|
||||
// app
|
||||
@@ -65,10 +66,12 @@ var (
|
||||
|
||||
// website
|
||||
var (
|
||||
ErrDomainIsExist = "ErrDomainIsExist"
|
||||
ErrAliasIsExist = "ErrAliasIsExist"
|
||||
ErrAppDelete = "ErrAppDelete"
|
||||
ErrGroupIsUsed = "ErrGroupIsUsed"
|
||||
ErrDomainIsExist = "ErrDomainIsExist"
|
||||
ErrAliasIsExist = "ErrAliasIsExist"
|
||||
ErrAppDelete = "ErrAppDelete"
|
||||
ErrGroupIsUsed = "ErrGroupIsUsed"
|
||||
ErrUsernameIsExist = "ErrUsernameIsExist"
|
||||
ErrUsernameIsNotExist = "ErrUsernameIsNotExist"
|
||||
)
|
||||
|
||||
// ssl
|
||||
@@ -104,6 +107,7 @@ var (
|
||||
var (
|
||||
ErrInUsed = "ErrInUsed"
|
||||
ErrObjectInUsed = "ErrObjectInUsed"
|
||||
ErrPortRules = "ErrPortRules"
|
||||
)
|
||||
|
||||
// runtime
|
||||
|
||||
@@ -5,8 +5,9 @@ const (
|
||||
NginxScopeHttp = "http"
|
||||
NginxScopeOut = "out"
|
||||
|
||||
NginxReload = "reload"
|
||||
NginxCheck = "check"
|
||||
NginxReload = "reload"
|
||||
NginxCheck = "check"
|
||||
NginxRestart = "restart"
|
||||
|
||||
ConfigNew = "add"
|
||||
ConfigUpdate = "update"
|
||||
|
||||
@@ -9,22 +9,20 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/cron/job"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
func Run() {
|
||||
nyc, _ := time.LoadLocation("Asia/Shanghai")
|
||||
nyc, _ := time.LoadLocation(common.LoadTimeZone())
|
||||
Cron := cron.New(cron.WithLocation(nyc), cron.WithChain(cron.Recover(cron.DefaultLogger)), cron.WithChain(cron.DelayIfStillRunning(cron.DefaultLogger)))
|
||||
_, err := Cron.AddJob("@every 5m", job.NewMonitorJob())
|
||||
if err != nil {
|
||||
if _, err := Cron.AddJob("@every 5m", job.NewMonitorJob()); err != nil {
|
||||
global.LOG.Errorf("can not add monitor corn job: %s", err.Error())
|
||||
}
|
||||
_, err = Cron.AddJob("@daily", job.NewWebsiteJob())
|
||||
if err != nil {
|
||||
if _, err := Cron.AddJob("@daily", job.NewWebsiteJob()); err != nil {
|
||||
global.LOG.Errorf("can not add website corn job: %s", err.Error())
|
||||
}
|
||||
_, err = Cron.AddJob("@daily", job.NewSSLJob())
|
||||
if err != nil {
|
||||
if _, err := Cron.AddJob("@daily", job.NewSSLJob()); err != nil {
|
||||
global.LOG.Errorf("can not add ssl corn job: %s", err.Error())
|
||||
}
|
||||
Cron.Start()
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/service"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -18,13 +19,14 @@ func (ssl *ssl) Run() {
|
||||
sslRepo := repo.NewISSLRepo()
|
||||
sslService := service.NewIWebsiteSSLService()
|
||||
sslList, _ := sslRepo.List()
|
||||
nyc, _ := time.LoadLocation(common.LoadTimeZone())
|
||||
global.LOG.Info("The scheduled certificate update task is currently in progress ...")
|
||||
now := time.Now().Add(10 * time.Second)
|
||||
for _, s := range sslList {
|
||||
if !s.AutoRenew || s.Provider == "manual" || s.Provider == "dnsManual" {
|
||||
continue
|
||||
}
|
||||
expireDate := s.ExpireDate.In(time.Now().Location())
|
||||
expireDate := s.ExpireDate.In(nyc)
|
||||
sub := expireDate.Sub(now)
|
||||
if sub.Hours() < 720 {
|
||||
global.LOG.Errorf("Update the SSL certificate for the [%s] domain", s.PrimaryDomain)
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/service"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -18,9 +19,10 @@ func NewWebsiteJob() *website {
|
||||
}
|
||||
|
||||
func (w *website) Run() {
|
||||
nyc, _ := time.LoadLocation(common.LoadTimeZone())
|
||||
websites, _ := repo.NewIWebsiteRepo().List()
|
||||
global.LOG.Info("website cron job start...")
|
||||
now := time.Now().Add(10 * time.Second)
|
||||
global.LOG.Info("Website scheduled task in progress ...")
|
||||
now := time.Now().Add(10 * time.Minute)
|
||||
if len(websites) > 0 {
|
||||
neverExpireDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
|
||||
var wg sync.WaitGroup
|
||||
@@ -28,27 +30,33 @@ func (w *website) Run() {
|
||||
if site.Status != constant.WebRunning || neverExpireDate.Equal(site.ExpireDate) {
|
||||
continue
|
||||
}
|
||||
expireDate, _ := time.ParseInLocation(constant.DateTimeLayout, site.ExpireDate.String(), time.Now().Location())
|
||||
expireDate, err := time.ParseInLocation(constant.DateLayout, site.ExpireDate.Format(constant.DateLayout), nyc)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("time parse err %v", err)
|
||||
continue
|
||||
}
|
||||
if expireDate.Before(now) {
|
||||
wg.Add(1)
|
||||
go func(ws model.Website) {
|
||||
stopWebsite(ws.ID, &wg)
|
||||
stopWebsite(ws.ID, ws.PrimaryDomain, &wg)
|
||||
}(site)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
global.LOG.Info("website cron job end...")
|
||||
global.LOG.Info("Website scheduled task has completed")
|
||||
}
|
||||
|
||||
func stopWebsite(websiteId uint, wg *sync.WaitGroup) {
|
||||
func stopWebsite(websiteId uint, websiteName string, wg *sync.WaitGroup) {
|
||||
websiteService := service.NewIWebsiteService()
|
||||
req := request.WebsiteOp{
|
||||
ID: websiteId,
|
||||
Operate: constant.StopWeb,
|
||||
}
|
||||
if err := websiteService.OpWebsite(req); err != nil {
|
||||
global.LOG.Errorf("stop website err: %s", err.Error())
|
||||
global.LOG.Errorf("Website [%s] seop failed err %v", websiteName, err)
|
||||
} else {
|
||||
global.LOG.Infof("Website [%s] stopped successfully", websiteName)
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ ErrRepoNotValid: "Remote repository verification failed!"
|
||||
ErrNameIsExist: "Name is already exist"
|
||||
ErrDemoEnvironment: "Demo server, prohibit this operation!"
|
||||
ErrCmdTimeout: "Command execution timed out!"
|
||||
ErrInitUser: "The user initialization has been completed by the system. Please do not repeat the operation!"
|
||||
|
||||
#app
|
||||
ErrPortInUsed: "{{ .detail }} port already in use"
|
||||
@@ -43,6 +44,8 @@ ErrDomainIsExist: "Domain is already exist"
|
||||
ErrAliasIsExist: "Alias is already exist"
|
||||
ErrAppDelete: 'Other Website use this App'
|
||||
ErrGroupIsUsed: 'The group is in use and cannot be deleted'
|
||||
ErrUsernameIsExist: 'Username is already exist'
|
||||
ErrUsernameIsNotExist: 'Username is not exist'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "The certificate is being used by the website and cannot be removed"
|
||||
@@ -61,6 +64,7 @@ ErrTypeOfRedis: "The recovery file type does not match the current persistence m
|
||||
#container
|
||||
ErrInUsed: "{{ .detail }} is in use and cannot be deleted"
|
||||
ErrObjectInUsed: "This object is in use and cannot be deleted"
|
||||
ErrPortRules: "Invalid port specification"
|
||||
|
||||
#runtime
|
||||
ErrDirNotFound: "The build folder does not exist! Please check file integrity!"
|
||||
|
||||
@@ -17,6 +17,7 @@ ErrRepoNotValid: "远程仓库校验失败!"
|
||||
ErrNameIsExist: "名称已存在"
|
||||
ErrDemoEnvironment: "演示服务器,禁止此操作!"
|
||||
ErrCmdTimeout: "命令执行超时!"
|
||||
ErrInitUser: "系统已完成用户初始化,请勿重复操作!"
|
||||
|
||||
#app
|
||||
ErrPortInUsed: "{{ .detail }} 端口已被占用!"
|
||||
@@ -43,6 +44,8 @@ ErrDomainIsExist: "域名已存在"
|
||||
ErrAliasIsExist: "代号已存在"
|
||||
ErrAppDelete: '其他网站使用此应用,无法删除'
|
||||
ErrGroupIsUsed: '分组正在使用中,无法删除'
|
||||
ErrUsernameIsExist: '用户名已存在'
|
||||
ErrUsernameIsNotExist: '用户不存在'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "证书正在被网站使用,无法删除"
|
||||
@@ -61,6 +64,7 @@ ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后
|
||||
#container
|
||||
ErrInUsed: "{{ .detail }} 正被使用,无法删除"
|
||||
ErrObjectInUsed: "该对象正被使用,无法删除"
|
||||
ErrPortRules: "无效的端口规格"
|
||||
|
||||
#runtime
|
||||
ErrDirNotFound: "build 文件夹不存在!请检查文件完整性!"
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/dgraph-io/badger/v3"
|
||||
"github.com/dgraph-io/badger/v4"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/init/cache/badger_db"
|
||||
"github.com/dgraph-io/badger/v3"
|
||||
"github.com/dgraph-io/badger/v4"
|
||||
)
|
||||
|
||||
func Init() {
|
||||
|
||||
@@ -17,6 +17,11 @@ func Init() {
|
||||
global.LOG.Errorf("load service encrypt key from setting failed, err: %v", err)
|
||||
}
|
||||
global.CONF.System.EncryptKey = enptrySetting.Value
|
||||
sslSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load service ssl from setting failed, err: %v", err)
|
||||
}
|
||||
global.CONF.System.SSL = sslSetting.Value
|
||||
|
||||
if _, err := settingRepo.Get(settingRepo.WithByKey("SystemStatus")); err != nil {
|
||||
_ = settingRepo.Create("SystemStatus", "Free")
|
||||
|
||||
@@ -25,6 +25,7 @@ func Init() {
|
||||
migrations.UpdateTableApp,
|
||||
migrations.UpdateTableHost,
|
||||
migrations.UpdateTableWebsite,
|
||||
migrations.AddEntranceAndSSL,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
||||
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
"gorm.io/gorm"
|
||||
@@ -61,10 +62,13 @@ var AddTableSetting = &gormigrate.Migration{
|
||||
if err := tx.AutoMigrate(&model.Setting{}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "UserName", Value: ""}).Error; err != nil {
|
||||
encryptKey := common.RandStr(16)
|
||||
if err := tx.Create(&model.Setting{Key: "UserName", Value: global.CONF.System.Username}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "Password", Value: ""}).Error; err != nil {
|
||||
global.CONF.System.EncryptKey = encryptKey
|
||||
pass, _ := encrypt.StringEncrypt(global.CONF.System.Password)
|
||||
if err := tx.Create(&model.Setting{Key: "Password", Value: pass}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "Email", Value: ""}).Error; err != nil {
|
||||
@@ -91,13 +95,13 @@ var AddTableSetting = &gormigrate.Migration{
|
||||
if err := tx.Create(&model.Setting{Key: "ServerPort", Value: global.CONF.System.Port}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "SecurityEntrance", Value: "onepanel"}).Error; err != nil {
|
||||
if err := tx.Create(&model.Setting{Key: "SecurityEntrance", Value: global.CONF.System.Entrance}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "JWTSigningKey", Value: common.RandStr(16)}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "EncryptKey", Value: common.RandStr(16)}).Error; err != nil {
|
||||
if err := tx.Create(&model.Setting{Key: "EncryptKey", Value: encryptKey}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -287,3 +291,24 @@ var UpdateTableWebsite = &gormigrate.Migration{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddEntranceAndSSL = &gormigrate.Migration{
|
||||
ID: "20230414-add-entrance-and-ssl",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.Model(&model.Setting{}).
|
||||
Where("key = ? AND value = ?", "SecurityEntrance", "onepanel").
|
||||
Updates(map[string]interface{}{"value": ""}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "SSLType", Value: "self"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "SSLID", Value: "0"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "SSL", Value: "disable"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.AutoMigrate(&model.Website{})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/gin-contrib/gzip"
|
||||
|
||||
v1 "github.com/1Panel-dev/1Panel/backend/app/api/v1"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/i18n"
|
||||
"github.com/1Panel-dev/1Panel/backend/middleware"
|
||||
@@ -40,43 +39,31 @@ func setWebStatic(rootRouter *gin.Engine) {
|
||||
|
||||
func Routers() *gin.Engine {
|
||||
Router := gin.Default()
|
||||
|
||||
Router.Use(middleware.OperationLog())
|
||||
// Router.Use(middleware.CSRF())
|
||||
// Router.Use(middleware.LoadCsrfToken())
|
||||
|
||||
if global.CONF.System.IsDemo {
|
||||
Router.Use(middleware.DemoHandle())
|
||||
}
|
||||
|
||||
Router.Use(gzip.Gzip(gzip.DefaultCompression))
|
||||
setWebStatic(Router)
|
||||
|
||||
Router.Use(i18n.GinI18nLocalize())
|
||||
Router.GET("/api/v1/info", v1.ApiGroupApp.BaseApi.GetSafetyStatus)
|
||||
Router.GET("/api/v1/:code", v1.ApiGroupApp.BaseApi.SafeEntrance)
|
||||
|
||||
Router.SetFuncMap(template.FuncMap{
|
||||
"Localize": ginI18n.GetMessage,
|
||||
})
|
||||
Router.Use(middleware.JwtAuth())
|
||||
|
||||
systemRouter := rou.RouterGroupApp
|
||||
|
||||
swaggerRouter := Router.Group("1panel")
|
||||
docs.SwaggerInfo.BasePath = "/api/v1"
|
||||
swaggerRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth()).GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
|
||||
|
||||
PublicGroup := Router.Group("")
|
||||
{
|
||||
PublicGroup.GET("/health", func(c *gin.Context) {
|
||||
c.JSON(200, "ok")
|
||||
})
|
||||
}
|
||||
|
||||
PrivateGroup := Router.Group("/api/v1")
|
||||
PrivateGroup.Use(middleware.GlobalLoading())
|
||||
//PrivateGroup.Use(middleware.SafetyAuth())
|
||||
{
|
||||
systemRouter.InitBaseRouter(PrivateGroup)
|
||||
systemRouter.InitDashboardRouter(PrivateGroup)
|
||||
|
||||
+31
-13
@@ -21,6 +21,7 @@ func Init() {
|
||||
port := "9999"
|
||||
mode := ""
|
||||
version := "v1.0.0"
|
||||
username, password, entrance := "", "", ""
|
||||
fileOp := files.NewFileOp()
|
||||
v := viper.NewWithOptions()
|
||||
v.SetConfigType("yaml")
|
||||
@@ -40,8 +41,11 @@ func Init() {
|
||||
}
|
||||
} else {
|
||||
baseDir = loadParams("BASE_DIR")
|
||||
port = loadParams("PANEL_PORT")
|
||||
version = loadParams("ORIGINAL_INSTALLED_VERSION")
|
||||
port = loadParams("ORIGINAL_PORT")
|
||||
version = loadParams("ORIGINAL_VERSION")
|
||||
username = loadParams("ORIGINAL_USERNAME")
|
||||
password = loadParams("ORIGINAL_PASSWORD")
|
||||
entrance = loadParams("ORIGINAL_ENTRANCE")
|
||||
|
||||
if strings.HasSuffix(baseDir, "/") {
|
||||
baseDir = baseDir[:strings.LastIndex(baseDir, "/")]
|
||||
@@ -60,14 +64,25 @@ func Init() {
|
||||
if err := v.Unmarshal(&serverConfig); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if mode == "dev" && fileOp.Stat("/opt/1panel/conf/app.yaml") && serverConfig.System.BaseDir != "" {
|
||||
baseDir = serverConfig.System.BaseDir
|
||||
}
|
||||
if mode == "dev" && fileOp.Stat("/opt/1panel/conf/app.yaml") && serverConfig.System.Port != "" {
|
||||
port = serverConfig.System.Port
|
||||
}
|
||||
if mode == "dev" && fileOp.Stat("/opt/1panel/conf/app.yaml") && serverConfig.System.Version != "" {
|
||||
version = serverConfig.System.Version
|
||||
if mode == "dev" && fileOp.Stat("/opt/1panel/conf/app.yaml") {
|
||||
if serverConfig.System.BaseDir != "" {
|
||||
baseDir = serverConfig.System.BaseDir
|
||||
}
|
||||
if serverConfig.System.Port != "" {
|
||||
port = serverConfig.System.Port
|
||||
}
|
||||
if serverConfig.System.Version != "" {
|
||||
version = serverConfig.System.Version
|
||||
}
|
||||
if serverConfig.System.Username != "" {
|
||||
username = serverConfig.System.Username
|
||||
}
|
||||
if serverConfig.System.Password != "" {
|
||||
password = serverConfig.System.Password
|
||||
}
|
||||
if serverConfig.System.Entrance != "" {
|
||||
entrance = serverConfig.System.Entrance
|
||||
}
|
||||
}
|
||||
|
||||
global.CONF = serverConfig
|
||||
@@ -81,6 +96,9 @@ func Init() {
|
||||
global.CONF.System.TmpDir = global.CONF.System.DataDir + "/tmp"
|
||||
global.CONF.System.Port = port
|
||||
global.CONF.System.Version = version
|
||||
global.CONF.System.Username = username
|
||||
global.CONF.System.Password = password
|
||||
global.CONF.System.Entrance = entrance
|
||||
global.Viper = v
|
||||
}
|
||||
|
||||
@@ -89,9 +107,9 @@ func loadParams(param string) string {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
baseDir := strings.ReplaceAll(stdout, "\n", "")
|
||||
if len(baseDir) == 0 {
|
||||
info := strings.ReplaceAll(stdout, "\n", "")
|
||||
if len(info) == 0 || info == `""` {
|
||||
panic(fmt.Sprintf("error `%s` find in /usr/bin/1pctl", param))
|
||||
}
|
||||
return baseDir
|
||||
return info
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -29,7 +30,8 @@ func PasswordExpired() gin.HandlerFunc {
|
||||
helper.ErrorWithDetail(c, constant.CodePasswordExpired, constant.ErrTypePasswordExpired, err)
|
||||
return
|
||||
}
|
||||
expiredTime, err := time.Parse("2006-01-02 15:04:05", extime.Value)
|
||||
loc, _ := time.LoadLocation(common.LoadTimeZone())
|
||||
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
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/service"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SafetyAuth() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if err := service.NewIAuthService().SafetyStatus(c); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, nil)
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,7 @@ func (s *BaseRouter) InitBaseRouter(Router *gin.RouterGroup) {
|
||||
baseRouter.GET("/captcha", baseApi.Captcha)
|
||||
baseRouter.POST("/mfalogin", baseApi.MFALogin)
|
||||
baseRouter.POST("/login", baseApi.Login)
|
||||
baseRouter.GET("/status", baseApi.CheckIsFirstLogin)
|
||||
baseRouter.POST("/init", baseApi.InitUserInfo)
|
||||
baseRouter.GET("/issafety", baseApi.CheckIsSafety)
|
||||
baseRouter.POST("/logout", baseApi.LogOut)
|
||||
baseRouter.GET("/demo", baseApi.CheckIsDemo)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
|
||||
fileRouter.POST("/del", baseApi.DeleteFile)
|
||||
fileRouter.POST("/batch/del", baseApi.BatchDeleteFile)
|
||||
fileRouter.POST("/mode", baseApi.ChangeFileMode)
|
||||
fileRouter.POST("/owner", baseApi.ChangeFileOwner)
|
||||
fileRouter.POST("/compress", baseApi.CompressFile)
|
||||
fileRouter.POST("/decompress", baseApi.DeCompressFile)
|
||||
fileRouter.POST("/content", baseApi.GetContent)
|
||||
|
||||
@@ -23,6 +23,8 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
|
||||
settingRouter.GET("/search/available", baseApi.GetSystemAvailable)
|
||||
settingRouter.POST("/update", baseApi.UpdateSetting)
|
||||
settingRouter.POST("/port/update", baseApi.UpdatePort)
|
||||
settingRouter.POST("/ssl/update", baseApi.UpdateSSL)
|
||||
settingRouter.GET("/ssl/info", baseApi.LoadFromCert)
|
||||
settingRouter.POST("/password/update", baseApi.UpdatePassword)
|
||||
settingRouter.POST("/time/sync", baseApi.SyncTime)
|
||||
settingRouter.POST("/monitor/clean", baseApi.CleanMonitor)
|
||||
|
||||
@@ -51,5 +51,12 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
|
||||
|
||||
groupRouter.POST("/dir/update", baseApi.UpdateSiteDir)
|
||||
groupRouter.POST("/dir/permission", baseApi.UpdateSiteDirPermission)
|
||||
|
||||
groupRouter.POST("/proxies", baseApi.GetProxyConfig)
|
||||
groupRouter.POST("/proxies/update", baseApi.UpdateProxyConfig)
|
||||
groupRouter.POST("/proxies/file", baseApi.UpdateProxyConfigFile)
|
||||
|
||||
groupRouter.POST("/auths", baseApi.GetAuthConfig)
|
||||
groupRouter.POST("/auths/update", baseApi.UpdateAuthConfig)
|
||||
}
|
||||
}
|
||||
|
||||
+38
-15
@@ -1,8 +1,11 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/init/app"
|
||||
@@ -43,22 +46,42 @@ func Start() {
|
||||
|
||||
rootRouter := router.Routers()
|
||||
address := fmt.Sprintf(":%s", global.CONF.System.Port)
|
||||
s := initServer(address, rootRouter)
|
||||
global.LOG.Infof("server run success on %s", global.CONF.System.Port)
|
||||
if err := s.ListenAndServe(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type server interface {
|
||||
ListenAndServe() error
|
||||
}
|
||||
|
||||
func initServer(address string, router *gin.Engine) server {
|
||||
s := endless.NewServer(address, router)
|
||||
s := endless.NewServer(address, rootRouter)
|
||||
s.ReadHeaderTimeout = 20 * time.Second
|
||||
s.WriteTimeout = 60 * time.Second
|
||||
s.MaxHeaderBytes = 1 << 20
|
||||
return s
|
||||
|
||||
if global.CONF.System.SSL == "disable" {
|
||||
global.LOG.Infof("server run success on %s with http", global.CONF.System.Port)
|
||||
if err := s.ListenAndServe(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
certificate, err := os.ReadFile(global.CONF.System.BaseDir + "/1panel/secret/server.crt")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
key, err := os.ReadFile(global.CONF.System.BaseDir + "/1panel/secret/server.key")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cert, err := tls.X509KeyPair(certificate, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s := &http.Server{
|
||||
Addr: address,
|
||||
Handler: rootRouter,
|
||||
TLSConfig: &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
},
|
||||
}
|
||||
|
||||
global.LOG.Infof("server run success on %s with https", global.CONF.System.Port)
|
||||
if err := s.ListenAndServeTLS("", ""); err != nil {
|
||||
global.LOG.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,32 @@ func ExecWithTimeOut(cmdStr string, timeout time.Duration) (string, error) {
|
||||
return stdout.String(), nil
|
||||
}
|
||||
|
||||
func ExecCronjobWithTimeOut(cmdStr string, timeout time.Duration) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
cmd := exec.Command("bash", "-c", cmdStr)
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
err := cmd.Run()
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
return "", buserr.New(constant.ErrCmdTimeout)
|
||||
}
|
||||
|
||||
errMsg := ""
|
||||
if len(stderr.String()) != 0 {
|
||||
errMsg = fmt.Sprintf("stderr:\n %s", stderr.String())
|
||||
}
|
||||
if len(stdout.String()) != 0 {
|
||||
if len(errMsg) != 0 {
|
||||
errMsg = fmt.Sprintf("%s \n\n; stdout:\n %s", errMsg, stdout.String())
|
||||
} else {
|
||||
errMsg = fmt.Sprintf("stdout\n: %s", stdout.String())
|
||||
}
|
||||
}
|
||||
return errMsg, err
|
||||
}
|
||||
|
||||
func Execf(cmdStr string, a ...interface{}) (string, error) {
|
||||
cmd := exec.Command("bash", "-c", fmt.Sprintf(cmdStr, a...))
|
||||
var stdout, stderr bytes.Buffer
|
||||
@@ -91,11 +117,6 @@ func Execf(cmdStr string, a ...interface{}) (string, error) {
|
||||
}
|
||||
|
||||
func HasNoPasswordSudo() bool {
|
||||
cmd := exec.Command("sudo", "-v")
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
cmd2 := exec.Command("sudo", "-n", "ls")
|
||||
err2 := cmd2.Run()
|
||||
return err2 == nil
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CompareVersion(version1 string, version2 string) bool {
|
||||
@@ -134,3 +135,11 @@ func LoadSizeUnit(value float64) string {
|
||||
}
|
||||
return fmt.Sprintf("%v", value)
|
||||
}
|
||||
|
||||
func LoadTimeZone() string {
|
||||
loc := time.Now().Location()
|
||||
if _, err := time.LoadLocation(loc.String()); err != nil {
|
||||
return "Asia/Shanghai"
|
||||
}
|
||||
return loc.String()
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
@@ -106,7 +107,7 @@ func (f FileOp) SaveFile(dst string, content string, mode fs.FileMode) error {
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(string(content))
|
||||
_, _ = write.WriteString(content)
|
||||
write.Flush()
|
||||
return nil
|
||||
}
|
||||
@@ -119,6 +120,37 @@ func (f FileOp) Chown(dst string, uid int, gid int) error {
|
||||
return f.Fs.Chown(dst, uid, gid)
|
||||
}
|
||||
|
||||
func (f FileOp) ChownR(dst string, uid string, gid string, sub bool) error {
|
||||
cmdStr := fmt.Sprintf("chown %s:%s %s", uid, gid, dst)
|
||||
if sub {
|
||||
cmdStr = fmt.Sprintf("chown -R %s:%s %s", uid, gid, dst)
|
||||
}
|
||||
if cmd.HasNoPasswordSudo() {
|
||||
cmdStr = fmt.Sprintf("sudo %s", cmdStr)
|
||||
}
|
||||
if msg, err := cmd.ExecWithTimeOut(cmdStr, 2*time.Second); err != nil {
|
||||
if msg != "" {
|
||||
return errors.New(msg)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f FileOp) ChmodR(dst string, mode int64) error {
|
||||
cmdStr := fmt.Sprintf("chmod -R %v %s", fmt.Sprintf("%04o", mode), dst)
|
||||
if cmd.HasNoPasswordSudo() {
|
||||
cmdStr = fmt.Sprintf("sudo %s", cmdStr)
|
||||
}
|
||||
if msg, err := cmd.ExecWithTimeOut(cmdStr, 2*time.Second); err != nil {
|
||||
if msg != "" {
|
||||
return errors.New(msg)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f FileOp) Rename(oldName string, newName string) error {
|
||||
return f.Fs.Rename(oldName, newName)
|
||||
}
|
||||
@@ -322,17 +354,21 @@ func (f FileOp) CopyFile(src, dst string) error {
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
srcInfo, err := f.Fs.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dstPath := path.Join(dst, srcInfo.Name())
|
||||
if src == dstPath {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = f.Fs.MkdirAll(filepath.Dir(dst), 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
srcInfo, err := f.Fs.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dstFile, err := f.Fs.OpenFile(path.Join(dst, srcInfo.Name()), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
|
||||
dstFile, err := f.Fs.OpenFile(dstPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -446,6 +482,9 @@ func (f FileOp) Decompress(srcFile string, dst string, cType CompressType) error
|
||||
|
||||
handler := func(ctx context.Context, archFile archiver.File) error {
|
||||
info := archFile.FileInfo
|
||||
if strings.HasPrefix(archFile.NameInArchive, "__MACOSX") {
|
||||
return nil
|
||||
}
|
||||
filePath := filepath.Join(dst, archFile.NameInArchive)
|
||||
if archFile.FileInfo.IsDir() {
|
||||
if err := f.Fs.MkdirAll(filePath, info.Mode()); err != nil {
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
@@ -73,6 +76,8 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
|
||||
Extension: filepath.Ext(info.Name()),
|
||||
IsHidden: IsHidden(op.Path),
|
||||
Mode: fmt.Sprintf("%04o", info.Mode().Perm()),
|
||||
User: GetUsername(info.Sys().(*syscall.Stat_t).Uid),
|
||||
Group: GetGroup(info.Sys().(*syscall.Stat_t).Gid),
|
||||
MimeType: GetMimeType(op.Path),
|
||||
}
|
||||
if file.IsSymlink {
|
||||
@@ -93,35 +98,38 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func (f *FileInfo) search(dir, showHidden bool, af afero.Afero, search string, count int) ([]FileSearchInfo, error) {
|
||||
var files []FileSearchInfo
|
||||
if err := afero.Walk(af, f.Path, func(path string, info fs.FileInfo, err error) error {
|
||||
if info != nil {
|
||||
|
||||
if dir && !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if !showHidden && IsHidden(info.Name()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
lowerName := strings.ToLower(info.Name())
|
||||
lowerSearch := strings.ToLower(search)
|
||||
if strings.Contains(lowerName, lowerSearch) {
|
||||
files = append(files, FileSearchInfo{
|
||||
Path: path,
|
||||
FileInfo: info,
|
||||
})
|
||||
if len(files) > count {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
func (f *FileInfo) search(search string, count int) (files []FileSearchInfo, total int, err error) {
|
||||
cmd := exec.Command("find", f.Path, "-name", search)
|
||||
output, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return files, nil
|
||||
if err = cmd.Start(); err != nil {
|
||||
return
|
||||
}
|
||||
defer cmd.Wait()
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
scanner := bufio.NewScanner(output)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
info, err := os.Stat(line)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
total++
|
||||
if total > count {
|
||||
continue
|
||||
}
|
||||
files = append(files, FileSearchInfo{
|
||||
Path: line,
|
||||
FileInfo: info,
|
||||
})
|
||||
}
|
||||
if err = scanner.Err(); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string, page, pageSize int) error {
|
||||
@@ -129,10 +137,11 @@ func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string,
|
||||
var (
|
||||
files []FileSearchInfo
|
||||
err error
|
||||
total int
|
||||
)
|
||||
|
||||
if search != "" && containSub {
|
||||
files, err = f.search(dir, showHidden, *afs, search, page*pageSize)
|
||||
files, total, err = f.search(search, page*pageSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -149,17 +158,13 @@ func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string,
|
||||
}
|
||||
}
|
||||
|
||||
f.ItemTotal = 0
|
||||
|
||||
var items []*FileInfo
|
||||
for _, df := range files {
|
||||
if dir && !df.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
name := df.Name()
|
||||
fPath := path.Join(df.Path, df.Name())
|
||||
|
||||
if search != "" {
|
||||
if containSub {
|
||||
fPath = df.Path
|
||||
@@ -172,12 +177,10 @@ func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !showHidden && IsHidden(name) {
|
||||
continue
|
||||
}
|
||||
f.ItemTotal++
|
||||
|
||||
isSymlink, isInvalidLink := false, false
|
||||
if IsSymlink(df.Mode()) {
|
||||
isSymlink = true
|
||||
@@ -201,19 +204,24 @@ func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string,
|
||||
Extension: filepath.Ext(name),
|
||||
Path: fPath,
|
||||
Mode: fmt.Sprintf("%04o", df.Mode().Perm()),
|
||||
MimeType: GetMimeType(fPath),
|
||||
User: GetUsername(df.Sys().(*syscall.Stat_t).Uid),
|
||||
Group: GetGroup(df.Sys().(*syscall.Stat_t).Gid),
|
||||
}
|
||||
|
||||
if isSymlink {
|
||||
file.LinkPath = GetSymlink(fPath)
|
||||
}
|
||||
|
||||
if df.Size() > 0 {
|
||||
file.MimeType = GetMimeType(fPath)
|
||||
}
|
||||
if isInvalidLink {
|
||||
file.Type = "invalid_link"
|
||||
}
|
||||
items = append(items, file)
|
||||
}
|
||||
|
||||
if containSub {
|
||||
f.ItemTotal = total
|
||||
}
|
||||
start := (page - 1) * pageSize
|
||||
end := pageSize + start
|
||||
var result []*FileInfo
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"github.com/gabriel-vasile/mimetype"
|
||||
"github.com/spf13/afero"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -13,11 +15,19 @@ func IsSymlink(mode os.FileMode) bool {
|
||||
}
|
||||
|
||||
func GetMimeType(path string) string {
|
||||
mime, err := mimetype.DetectFile(path)
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return mime.String()
|
||||
defer file.Close()
|
||||
|
||||
buffer := make([]byte, 512)
|
||||
_, err = file.Read(buffer)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
mimeType := http.DetectContentType(buffer)
|
||||
return mimeType
|
||||
}
|
||||
|
||||
func GetSymlink(path string) string {
|
||||
@@ -28,6 +38,22 @@ func GetSymlink(path string) string {
|
||||
return linkPath
|
||||
}
|
||||
|
||||
func GetUsername(uid uint32) string {
|
||||
usr, err := user.LookupId(strconv.Itoa(int(uid)))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return usr.Username
|
||||
}
|
||||
|
||||
func GetGroup(gid uint32) string {
|
||||
usr, err := user.LookupGroupId(strconv.Itoa(int(gid)))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return usr.Name
|
||||
}
|
||||
|
||||
func ScanDir(fs afero.Fs, path string, dirMap *sync.Map, wg *sync.WaitGroup) {
|
||||
afs := &afero.Afero{Fs: fs}
|
||||
files, _ := afs.ReadDir(path)
|
||||
|
||||
@@ -62,41 +62,6 @@ func (b *Block) UpdateDirective(key string, params []string) {
|
||||
b.Directives = directives
|
||||
}
|
||||
|
||||
//func (b *Block) UpdateDirectiveBySecondKey(name string, key string, directive Directive) {
|
||||
//
|
||||
// directives := b.GetDirectives()
|
||||
//
|
||||
// index := -1
|
||||
// for i, dir := range directives {
|
||||
// if dir.GetName() == name && dir.GetParameters()[0] == key {
|
||||
// index = i
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// if index > -1 {
|
||||
// directives[index] = &directive
|
||||
// } else {
|
||||
// directives = append(directives, &directive)
|
||||
// }
|
||||
// b.Directives = directives
|
||||
//}
|
||||
|
||||
//func (b *Block) RemoveDirectives(names []string) {
|
||||
// nameMaps := make(map[string]struct{}, len(names))
|
||||
// for _, name := range names {
|
||||
// nameMaps[name] = struct{}{}
|
||||
// }
|
||||
// directives := b.GetDirectives()
|
||||
// var newDirectives []IDirective
|
||||
// for _, dir := range directives {
|
||||
// if _, ok := nameMaps[dir.GetName()]; ok {
|
||||
// continue
|
||||
// }
|
||||
// newDirectives = append(newDirectives, dir)
|
||||
// }
|
||||
// b.Directives = newDirectives
|
||||
//}
|
||||
|
||||
func (b *Block) RemoveDirective(key string, params []string) {
|
||||
directives := b.GetDirectives()
|
||||
var newDirectives []IDirective
|
||||
|
||||
@@ -46,6 +46,7 @@ var repeatKeys = map[string]struct {
|
||||
"proxy_set_header": {},
|
||||
"location": {},
|
||||
"include": {},
|
||||
"sub_filter": {},
|
||||
}
|
||||
|
||||
func IsRepeatKey(key string) bool {
|
||||
|
||||
@@ -1,32 +1,240 @@
|
||||
package components
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Location struct {
|
||||
*Directive
|
||||
Modifier string
|
||||
Match string
|
||||
Modifier string
|
||||
Match string
|
||||
Cache bool
|
||||
ProxyPass string
|
||||
Host string
|
||||
CacheTime int
|
||||
CacheUint string
|
||||
Comment string
|
||||
Directives []IDirective
|
||||
Line int
|
||||
Parameters []string
|
||||
Replaces map[string]string
|
||||
}
|
||||
|
||||
func NewLocation(directive *Directive) *Location {
|
||||
func NewLocation(directive IDirective) *Location {
|
||||
location := &Location{
|
||||
Modifier: "",
|
||||
Match: "",
|
||||
Directive: directive,
|
||||
Modifier: "",
|
||||
Match: "",
|
||||
}
|
||||
if directive.GetBlock() != nil {
|
||||
directive.Comment = directive.GetBlock().GetComment()
|
||||
}
|
||||
|
||||
if len(directive.Parameters) == 0 {
|
||||
directives := make([]IDirective, 0)
|
||||
if len(directive.GetParameters()) == 0 {
|
||||
panic("no enough parameter for location")
|
||||
}
|
||||
|
||||
if len(directive.Parameters) == 1 {
|
||||
location.Match = directive.Parameters[0]
|
||||
return location
|
||||
} else if len(directive.Parameters) == 2 {
|
||||
location.Match = directive.Parameters[1]
|
||||
location.Modifier = directive.Parameters[0]
|
||||
return location
|
||||
for _, dir := range directive.GetBlock().GetDirectives() {
|
||||
directives = append(directives, dir)
|
||||
params := dir.GetParameters()
|
||||
switch dir.GetName() {
|
||||
case "proxy_pass":
|
||||
location.ProxyPass = params[0]
|
||||
case "proxy_set_header":
|
||||
if params[0] == "Host" {
|
||||
location.Host = params[1]
|
||||
}
|
||||
case "proxy_cache":
|
||||
location.Cache = true
|
||||
case "if":
|
||||
if params[0] == "(" && params[1] == "$uri" && params[2] == "~*" {
|
||||
dirs := dir.GetBlock().GetDirectives()
|
||||
for _, di := range dirs {
|
||||
if di.GetName() == "expires" {
|
||||
re := regexp.MustCompile(`^(\d+)(\w+)$`)
|
||||
matches := re.FindStringSubmatch(di.GetParameters()[0])
|
||||
if matches == nil {
|
||||
continue
|
||||
}
|
||||
cacheTime, err := strconv.Atoi(matches[1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
unit := matches[2]
|
||||
location.CacheUint = unit
|
||||
location.CacheTime = cacheTime
|
||||
}
|
||||
}
|
||||
}
|
||||
case "sub_filter":
|
||||
if location.Replaces == nil {
|
||||
location.Replaces = make(map[string]string, 0)
|
||||
}
|
||||
location.Replaces[strings.Trim(params[0], "\"")] = strings.Trim(params[1], "\"")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
params := directive.GetParameters()
|
||||
if len(params) == 1 {
|
||||
location.Match = params[0]
|
||||
} else if len(params) == 2 {
|
||||
location.Match = params[1]
|
||||
location.Modifier = params[0]
|
||||
}
|
||||
location.Parameters = directive.GetParameters()
|
||||
location.Line = directive.GetLine()
|
||||
location.Comment = directive.GetComment()
|
||||
location.Directives = directives
|
||||
return location
|
||||
}
|
||||
|
||||
func (l *Location) GetName() string {
|
||||
return "location"
|
||||
}
|
||||
|
||||
func (l *Location) GetParameters() []string {
|
||||
return l.Parameters
|
||||
}
|
||||
|
||||
func (l *Location) GetBlock() IBlock {
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *Location) GetComment() string {
|
||||
return l.Comment
|
||||
}
|
||||
|
||||
func (l *Location) GetLine() int {
|
||||
return l.Line
|
||||
}
|
||||
|
||||
func (l *Location) GetDirectives() []IDirective {
|
||||
return l.Directives
|
||||
}
|
||||
|
||||
func (l *Location) FindDirectives(directiveName string) []IDirective {
|
||||
directives := make([]IDirective, 0)
|
||||
for _, directive := range l.Directives {
|
||||
if directive.GetName() == directiveName {
|
||||
directives = append(directives, directive)
|
||||
}
|
||||
if directive.GetBlock() != nil {
|
||||
directives = append(directives, directive.GetBlock().FindDirectives(directiveName)...)
|
||||
}
|
||||
}
|
||||
return directives
|
||||
}
|
||||
|
||||
func (l *Location) UpdateDirective(key string, params []string) {
|
||||
if key == "" || len(params) == 0 {
|
||||
return
|
||||
}
|
||||
directives := l.Directives
|
||||
index := -1
|
||||
for i, dir := range directives {
|
||||
if dir.GetName() == key {
|
||||
if IsRepeatKey(key) {
|
||||
oldParams := dir.GetParameters()
|
||||
if !(len(oldParams) > 0 && oldParams[0] == params[0]) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
newDirective := &Directive{
|
||||
Name: key,
|
||||
Parameters: params,
|
||||
}
|
||||
if index > -1 {
|
||||
directives[index] = newDirective
|
||||
} else {
|
||||
directives = append(directives, newDirective)
|
||||
}
|
||||
l.Directives = directives
|
||||
}
|
||||
|
||||
func (l *Location) RemoveDirective(key string, params []string) {
|
||||
directives := l.Directives
|
||||
var newDirectives []IDirective
|
||||
for _, dir := range directives {
|
||||
if dir.GetName() == key {
|
||||
if len(params) > 0 {
|
||||
oldParams := dir.GetParameters()
|
||||
if oldParams[0] == params[0] {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
newDirectives = append(newDirectives, dir)
|
||||
}
|
||||
l.Directives = newDirectives
|
||||
}
|
||||
|
||||
func (l *Location) ChangePath(Modifier string, Match string) {
|
||||
if Match != "" && Modifier != "" {
|
||||
l.Parameters = []string{Modifier, Match}
|
||||
}
|
||||
if Match != "" && Modifier == "" {
|
||||
l.Parameters = []string{Match}
|
||||
}
|
||||
l.Modifier = Modifier
|
||||
l.Match = Match
|
||||
}
|
||||
|
||||
func (l *Location) AddCache(cacheTime int, cacheUint string) {
|
||||
l.RemoveDirective("add_header", []string{"Cache-Control", "no-cache"})
|
||||
l.RemoveDirective("if", []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2)$"`, ")"})
|
||||
directives := l.GetDirectives()
|
||||
newDir := &Directive{
|
||||
Name: "if",
|
||||
Parameters: []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2)$"`, ")"},
|
||||
Block: &Block{},
|
||||
}
|
||||
block := &Block{}
|
||||
block.Directives = append(block.Directives, &Directive{
|
||||
Name: "expires",
|
||||
Parameters: []string{strconv.Itoa(cacheTime) + cacheUint},
|
||||
})
|
||||
newDir.Block = block
|
||||
directives = append(directives, newDir)
|
||||
l.Directives = directives
|
||||
l.UpdateDirective("proxy_ignore_headers", []string{"Set-Cookie", "Cache-Control", "expires"})
|
||||
l.UpdateDirective("proxy_cache", []string{"proxy_cache_panel"})
|
||||
l.UpdateDirective("proxy_cache_key", []string{"$host$uri$is_args$args"})
|
||||
l.UpdateDirective("proxy_cache_valid", []string{"200", "304", "301", "302", "10m"})
|
||||
l.Cache = true
|
||||
l.CacheTime = cacheTime
|
||||
l.CacheUint = cacheUint
|
||||
}
|
||||
|
||||
func (l *Location) RemoveCache() {
|
||||
l.RemoveDirective("if", []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2)$"`, ")"})
|
||||
l.RemoveDirective("proxy_ignore_headers", []string{"Set-Cookie"})
|
||||
l.RemoveDirective("proxy_cache", []string{"proxy_cache_panel"})
|
||||
l.RemoveDirective("proxy_cache_key", []string{"$host$uri$is_args$args"})
|
||||
l.RemoveDirective("proxy_cache_valid", []string{"200"})
|
||||
|
||||
l.UpdateDirective("add_header", []string{"Cache-Control", "no-cache"})
|
||||
|
||||
l.CacheTime = 0
|
||||
l.CacheUint = ""
|
||||
l.Cache = false
|
||||
}
|
||||
|
||||
func (l *Location) AddSubFilter(subFilters map[string]string) {
|
||||
l.RemoveDirective("sub_filter", []string{})
|
||||
l.Replaces = subFilters
|
||||
for k, v := range subFilters {
|
||||
l.UpdateDirective("sub_filter", []string{fmt.Sprintf(`"%s"`, k), fmt.Sprintf(`"%s"`, v)})
|
||||
}
|
||||
l.UpdateDirective("proxy_set_header", []string{"Accept-Encoding", `""`})
|
||||
l.UpdateDirective("sub_filter_once", []string{"off"})
|
||||
}
|
||||
|
||||
func (l *Location) RemoveSubFilter() {
|
||||
l.RemoveDirective("sub_filter", []string{})
|
||||
l.RemoveDirective("proxy_set_header", []string{"Accept-Encoding", `""`})
|
||||
l.RemoveDirective("sub_filter_once", []string{"off"})
|
||||
l.Replaces = nil
|
||||
}
|
||||
|
||||
@@ -116,22 +116,14 @@ func (s *Server) RemoveDirective(key string, params []string) {
|
||||
directives := s.Directives
|
||||
var newDirectives []IDirective
|
||||
for _, dir := range directives {
|
||||
if key == "location" {
|
||||
if location, ok := dir.(*Location); ok {
|
||||
if len(params) == 2 && location.Match == params[1] && location.Modifier == params[0] {
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if dir.GetName() == key {
|
||||
if len(params) > 0 {
|
||||
oldParams := dir.GetParameters()
|
||||
if oldParams[0] == params[0] {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if dir.GetName() == key {
|
||||
if len(params) > 0 {
|
||||
oldParams := dir.GetParameters()
|
||||
if oldParams[0] == params[0] {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
newDirectives = append(newDirectives, dir)
|
||||
@@ -319,5 +311,4 @@ func (s *Server) AddHTTP2HTTPS() {
|
||||
})
|
||||
newDir.Block = block
|
||||
s.UpdateDirectiveBySecondKey("if", "($scheme", newDir)
|
||||
|
||||
}
|
||||
|
||||
@@ -74,7 +74,6 @@ func DumpBlock(b components.IBlock, style *Style, startLine int) string {
|
||||
}
|
||||
|
||||
directives := b.GetDirectives()
|
||||
|
||||
for i, directive := range directives {
|
||||
|
||||
if directive.GetLine() > line {
|
||||
|
||||
@@ -84,7 +84,6 @@ func (p *Parser) Parse() *components.Config {
|
||||
}
|
||||
|
||||
func (p *Parser) parseBlock() *components.Block {
|
||||
|
||||
context := &components.Block{
|
||||
Comment: "",
|
||||
Directives: make([]components.IDirective, 0),
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
)
|
||||
|
||||
const ntpEpochOffset = 2208988800
|
||||
@@ -30,7 +30,7 @@ type packet struct {
|
||||
TxTimeFrac uint32
|
||||
}
|
||||
|
||||
func Getremotetime() (time.Time, error) {
|
||||
func GetRemoteTime() (time.Time, error) {
|
||||
conn, err := net.Dial("udp", "pool.ntp.org:123")
|
||||
if err != nil {
|
||||
return time.Time{}, fmt.Errorf("failed to connect: %v", err)
|
||||
@@ -62,10 +62,10 @@ func Getremotetime() (time.Time, error) {
|
||||
func UpdateSystemDate(dateTime string) error {
|
||||
system := runtime.GOOS
|
||||
if system == "linux" {
|
||||
if _, err := gproc.ShellExec(`date -s "` + dateTime + `"`); err != nil {
|
||||
if _, err := cmd.Execf(`date -s "` + dateTime + `"`); err != nil {
|
||||
return fmt.Errorf("update system date failed, err: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("The current system architecture does not support synchronization")
|
||||
return fmt.Errorf("the current system architecture %v does not support synchronization", system)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package ssl
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
)
|
||||
|
||||
func GenerateSSL(domain string) error {
|
||||
rootPrivateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
|
||||
ipItem := net.ParseIP(domain)
|
||||
isIP := false
|
||||
if len(ipItem) != 0 {
|
||||
isIP = true
|
||||
}
|
||||
|
||||
rootTemplate := x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{CommonName: "1Panel Root CA"},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(10, 0, 0),
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
KeyUsage: x509.KeyUsageCertSign,
|
||||
}
|
||||
if isIP {
|
||||
rootTemplate.IPAddresses = []net.IP{ipItem}
|
||||
} else {
|
||||
rootTemplate.DNSNames = []string{domain}
|
||||
}
|
||||
|
||||
rootCertBytes, _ := x509.CreateCertificate(rand.Reader, &rootTemplate, &rootTemplate, &rootPrivateKey.PublicKey, rootPrivateKey)
|
||||
rootCertBlock := &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: rootCertBytes,
|
||||
}
|
||||
|
||||
interPrivateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
|
||||
interTemplate := x509.Certificate{
|
||||
SerialNumber: big.NewInt(2),
|
||||
Subject: pkix.Name{CommonName: "1Panel Intermediate CA"},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(10, 0, 0),
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
KeyUsage: x509.KeyUsageCertSign,
|
||||
}
|
||||
if isIP {
|
||||
interTemplate.IPAddresses = []net.IP{ipItem}
|
||||
} else {
|
||||
interTemplate.DNSNames = []string{domain}
|
||||
}
|
||||
|
||||
interCertBytes, _ := x509.CreateCertificate(rand.Reader, &interTemplate, &rootTemplate, &interPrivateKey.PublicKey, rootPrivateKey)
|
||||
interCertBlock := &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: interCertBytes,
|
||||
}
|
||||
|
||||
clientPrivateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
|
||||
clientTemplate := x509.Certificate{
|
||||
SerialNumber: big.NewInt(3),
|
||||
Subject: pkix.Name{CommonName: domain},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(10, 0, 0),
|
||||
KeyUsage: x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
if isIP {
|
||||
clientTemplate.IPAddresses = []net.IP{ipItem}
|
||||
} else {
|
||||
clientTemplate.DNSNames = []string{domain}
|
||||
}
|
||||
|
||||
clientCertBytes, _ := x509.CreateCertificate(rand.Reader, &clientTemplate, &interTemplate, &clientPrivateKey.PublicKey, interPrivateKey)
|
||||
clientCertBlock := &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: clientCertBytes,
|
||||
}
|
||||
|
||||
pemBytes := []byte{}
|
||||
pemBytes = append(pemBytes, pem.EncodeToMemory(clientCertBlock)...)
|
||||
pemBytes = append(pemBytes, pem.EncodeToMemory(interCertBlock)...)
|
||||
pemBytes = append(pemBytes, pem.EncodeToMemory(rootCertBlock)...)
|
||||
certOut, err := os.OpenFile(global.CONF.System.BaseDir+"/1panel/secret/server.crt.tmp", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer certOut.Close()
|
||||
if _, err := certOut.Write(pemBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keyOut, err := os.OpenFile(global.CONF.System.BaseDir+"/1panel/secret/server.key.tmp", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer keyOut.Close()
|
||||
if err := pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(clientPrivateKey)}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -21,9 +21,8 @@ type LocalCommand struct {
|
||||
closeSignal syscall.Signal
|
||||
closeTimeout time.Duration
|
||||
|
||||
cmd *exec.Cmd
|
||||
pty *os.File
|
||||
ptyClosed chan struct{}
|
||||
cmd *exec.Cmd
|
||||
pty *os.File
|
||||
}
|
||||
|
||||
func NewCommand(commands string) (*LocalCommand, error) {
|
||||
@@ -33,15 +32,13 @@ func NewCommand(commands string) (*LocalCommand, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to start command")
|
||||
}
|
||||
ptyClosed := make(chan struct{})
|
||||
|
||||
lcmd := &LocalCommand{
|
||||
closeSignal: DefaultCloseSignal,
|
||||
closeTimeout: DefaultCloseTimeout,
|
||||
|
||||
cmd: cmd,
|
||||
pty: pty,
|
||||
ptyClosed: ptyClosed,
|
||||
cmd: cmd,
|
||||
pty: pty,
|
||||
}
|
||||
|
||||
return lcmd, nil
|
||||
@@ -57,16 +54,10 @@ func (lcmd *LocalCommand) Write(p []byte) (n int, err error) {
|
||||
|
||||
func (lcmd *LocalCommand) Close() error {
|
||||
if lcmd.cmd != nil && lcmd.cmd.Process != nil {
|
||||
_ = lcmd.cmd.Process.Signal(lcmd.closeSignal)
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-lcmd.ptyClosed:
|
||||
return nil
|
||||
case <-lcmd.closeTimeoutC():
|
||||
_ = lcmd.cmd.Process.Signal(syscall.SIGKILL)
|
||||
}
|
||||
_ = lcmd.cmd.Process.Kill()
|
||||
}
|
||||
_ = lcmd.pty.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lcmd *LocalCommand) ResizeTerminal(width int, height int) error {
|
||||
@@ -100,11 +91,3 @@ func (lcmd *LocalCommand) Wait(quitChan chan bool) {
|
||||
setQuit(quitChan)
|
||||
}
|
||||
}
|
||||
|
||||
func (lcmd *LocalCommand) closeTimeoutC() <-chan time.Time {
|
||||
if lcmd.closeTimeout >= 0 {
|
||||
return time.After(lcmd.closeTimeout)
|
||||
}
|
||||
|
||||
return make(chan time.Time)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(resetMFACmd)
|
||||
RootCmd.AddCommand(resetSSLCmd)
|
||||
RootCmd.AddCommand(resetEntranceCmd)
|
||||
}
|
||||
|
||||
var resetMFACmd = &cobra.Command{
|
||||
Use: "reset-mfa",
|
||||
Short: "关闭 1Panel 两步验证",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
db, err := loadDBConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return setSettingByKey(db, "MFAStatus", "disable")
|
||||
},
|
||||
}
|
||||
|
||||
var resetSSLCmd = &cobra.Command{
|
||||
Use: "reset-https",
|
||||
Short: "取消 1Panel https 方式登录",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
db, err := loadDBConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return setSettingByKey(db, "SSL", "disable")
|
||||
},
|
||||
}
|
||||
var resetEntranceCmd = &cobra.Command{
|
||||
Use: "reset-entrance",
|
||||
Short: "取消 1Panel 安全入口",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
db, err := loadDBConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return setSettingByKey(db, "SecurityEntrance", "")
|
||||
},
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/server"
|
||||
cmdUtils "github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/spf13/cobra"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -28,8 +32,32 @@ type setting struct {
|
||||
About string `json:"about" gorm:"type:longText"`
|
||||
}
|
||||
|
||||
func loadDBConn() (*gorm.DB, error) {
|
||||
stdout, err := cmdUtils.Exec("grep '^BASE_DIR=' /usr/bin/1pctl | cut -d'=' -f2")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("handle load `BASE_DIR` failed, err: %v", err)
|
||||
}
|
||||
baseDir := strings.ReplaceAll(stdout, "\n", "")
|
||||
if len(baseDir) == 0 {
|
||||
return nil, fmt.Errorf("error `BASE_DIR` find in /usr/bin/1pctl \n")
|
||||
}
|
||||
if strings.HasSuffix(baseDir, "/") {
|
||||
baseDir = baseDir[:strings.LastIndex(baseDir, "/")]
|
||||
}
|
||||
|
||||
db, err := gorm.Open(sqlite.Open(baseDir+"/1panel/db/1Panel.db"), &gorm.Config{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("init my db conn failed, err: %v \n", err)
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func getSettingByKey(db *gorm.DB, key string) string {
|
||||
var setting setting
|
||||
_ = db.Where("key = ?", key).First(&setting).Error
|
||||
return setting.Value
|
||||
}
|
||||
|
||||
func setSettingByKey(db *gorm.DB, key, value string) error {
|
||||
return db.Model(&setting{}).Where("key = ?", key).Updates(map[string]interface{}{"value": value}).Error
|
||||
}
|
||||
|
||||
@@ -2,14 +2,10 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
cmdUtils "github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
||||
"github.com/spf13/cobra"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -20,25 +16,15 @@ var userinfoCmd = &cobra.Command{
|
||||
Use: "user-info",
|
||||
Short: "获取用户信息",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
stdout, err := cmdUtils.Exec("grep '^BASE_DIR=' /usr/bin/1pctl | cut -d'=' -f2")
|
||||
db, err := loadDBConn()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
baseDir := strings.ReplaceAll(stdout, "\n", "")
|
||||
if len(baseDir) == 0 {
|
||||
fmt.Printf("error `BASE_DIR` find in /usr/bin/1pctl \n")
|
||||
}
|
||||
if strings.HasSuffix(baseDir, "/") {
|
||||
baseDir = baseDir[:strings.LastIndex(baseDir, "/")]
|
||||
}
|
||||
|
||||
db, err := gorm.Open(sqlite.Open(baseDir+"/1panel/db/1Panel.db"), &gorm.Config{})
|
||||
if err != nil {
|
||||
fmt.Printf("init my db conn failed, err: %v \n", err)
|
||||
return fmt.Errorf("init my db conn failed, err: %v \n", err)
|
||||
}
|
||||
user := getSettingByKey(db, "UserName")
|
||||
password := getSettingByKey(db, "Password")
|
||||
port := getSettingByKey(db, "ServerPort")
|
||||
ssl := getSettingByKey(db, "SSL")
|
||||
entrance := getSettingByKey(db, "SecurityEntrance")
|
||||
enptrySetting := getSettingByKey(db, "EncryptKey")
|
||||
|
||||
p := ""
|
||||
@@ -52,6 +38,8 @@ var userinfoCmd = &cobra.Command{
|
||||
fmt.Printf("username: %s\n", user)
|
||||
fmt.Printf("password: %s\n", p)
|
||||
fmt.Printf("port: %s\n", port)
|
||||
fmt.Printf("ssl: %s\n", ssl)
|
||||
fmt.Printf("entrance: %s\n", entrance)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
+12
-18
@@ -2,12 +2,12 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
cmdUtils "github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/configs"
|
||||
"github.com/1Panel-dev/1Panel/cmd/server/conf"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -18,27 +18,21 @@ var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "获取系统版本信息",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
stdout, err := cmdUtils.Exec("grep '^BASE_DIR=' /usr/bin/1pctl | cut -d'=' -f2")
|
||||
db, err := loadDBConn()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
baseDir := strings.ReplaceAll(stdout, "\n", "")
|
||||
if len(baseDir) == 0 {
|
||||
fmt.Printf("error `BASE_DIR` find in /usr/bin/1pctl \n")
|
||||
}
|
||||
if strings.HasSuffix(baseDir, "/") {
|
||||
baseDir = baseDir[:strings.LastIndex(baseDir, "/")]
|
||||
}
|
||||
|
||||
db, err := gorm.Open(sqlite.Open(baseDir+"/1panel/db/1Panel.db"), &gorm.Config{})
|
||||
if err != nil {
|
||||
fmt.Printf("init my db conn failed, err: %v \n", err)
|
||||
return err
|
||||
}
|
||||
version := getSettingByKey(db, "SystemVersion")
|
||||
appStoreVersion := getSettingByKey(db, "AppStoreVersion")
|
||||
|
||||
fmt.Printf("1panel version: %s\n", version)
|
||||
fmt.Printf("appstore version: %s\n", appStoreVersion)
|
||||
config := configs.ServerConfig{}
|
||||
if err := yaml.Unmarshal(conf.AppYaml, &config); err != nil {
|
||||
return fmt.Errorf("unmarshal conf.App.Yaml failed, errL %v", err)
|
||||
} else {
|
||||
fmt.Printf("mode: %s\n", config.System.Mode)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ system:
|
||||
repo_url: https://resource.fit2cloud.com/1panel/package
|
||||
is_demo: false
|
||||
port: 9999
|
||||
username: admin
|
||||
password: admin123
|
||||
|
||||
log:
|
||||
level: debug
|
||||
|
||||
+608
-53
@@ -799,27 +799,13 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/init": {
|
||||
"post": {
|
||||
"description": "初始化用户",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"/auth/issafety": {
|
||||
"get": {
|
||||
"description": "获取系统安全登录状态",
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Init user",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.InitUser"
|
||||
}
|
||||
}
|
||||
],
|
||||
"summary": "Load safety status",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
@@ -908,20 +894,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/status": {
|
||||
"get": {
|
||||
"description": "判断是否为首次登录",
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Check is First login",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/containers": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -4522,6 +4494,50 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/owner": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改文件用户/组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "Change file owner",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.FileRoleUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"path",
|
||||
"user",
|
||||
"group"
|
||||
],
|
||||
"formatEN": "Change owner [paths] =\u003e [user]/[group]",
|
||||
"formatZH": "修改用户/组 [paths] =\u003e [user]/[group]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/rename": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -7384,6 +7400,70 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/ssl/info": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取证书信息",
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Load system cert info",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SettingInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/ssl/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改系统 ssl 登录",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Update system ssl",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SSLUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"ssl"
|
||||
],
|
||||
"formatEN": "update system ssl =\u003e [ssl]",
|
||||
"formatZH": "修改系统 ssl =\u003e [ssl]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/time/sync": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -7857,6 +7937,72 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/auths": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取密码访问配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Get AuthBasic conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.NginxAuthReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/auths/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新密码访问配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Get AuthBasic conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.NginxAuthUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/check": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -8083,6 +8229,57 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/dir/permission": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新网站目录权限",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Update Site Dir permission",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteUpdateDirPermission"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "websites",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "primary_domain",
|
||||
"output_value": "domain"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "Update domain [domain] dir permission",
|
||||
"formatZH": "更新网站 [domain] 目录权限",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/dir/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -8111,7 +8308,7 @@ var doc = `{
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
@@ -8773,6 +8970,141 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/proxies": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取反向代理配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Get proxy conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteProxyReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/proxies/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改反向代理配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Update proxy conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteProxyConfig"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "websites",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "primary_domain",
|
||||
"output_value": "domain"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "Update domain [domain] proxy config",
|
||||
"formatZH": "修改网站 [domain] 反向代理配置 ",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/proxy/file": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新反向代理文件",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Update proxy file",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.NginxProxyUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "websites",
|
||||
"input_colume": "id",
|
||||
"input_value": "websiteID",
|
||||
"isList": false,
|
||||
"output_colume": "primary_domain",
|
||||
"output_value": "domain"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"websiteID"
|
||||
],
|
||||
"formatEN": "Nginx conf proxy file update [domain]",
|
||||
"formatZH": "更新反向代理文件 [domain]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/rewrite": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -9659,6 +9991,9 @@ var doc = `{
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"withFile": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10696,21 +11031,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.InitUser": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.InspectReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -10734,6 +11054,9 @@ var doc = `{
|
||||
"captchaID": {
|
||||
"type": "string"
|
||||
},
|
||||
"ignoreCaptcha": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -11122,10 +11445,16 @@ var doc = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"containerPort": {
|
||||
"type": "integer"
|
||||
"type": "string"
|
||||
},
|
||||
"hostIP": {
|
||||
"type": "string"
|
||||
},
|
||||
"hostPort": {
|
||||
"type": "integer"
|
||||
"type": "string"
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -11351,6 +11680,36 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SSLUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ssl"
|
||||
],
|
||||
"properties": {
|
||||
"cert": {
|
||||
"type": "string"
|
||||
},
|
||||
"domain": {
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"ssl": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"enable",
|
||||
"disable"
|
||||
]
|
||||
},
|
||||
"sslID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sslType": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SearchForTree": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -11530,6 +11889,12 @@ var doc = `{
|
||||
"sessionTimeout": {
|
||||
"type": "string"
|
||||
},
|
||||
"ssl": {
|
||||
"type": "string"
|
||||
},
|
||||
"sslType": {
|
||||
"type": "string"
|
||||
},
|
||||
"systemVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -11565,7 +11930,8 @@ var doc = `{
|
||||
],
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"maxLength": 256
|
||||
},
|
||||
"from": {
|
||||
"type": "string",
|
||||
@@ -11584,7 +11950,8 @@ var doc = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"maxLength": 256
|
||||
},
|
||||
"from": {
|
||||
"type": "string"
|
||||
@@ -11621,7 +11988,8 @@ var doc = `{
|
||||
],
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"maxLength": 256
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
@@ -11942,6 +12310,9 @@ var doc = `{
|
||||
"expireDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"httpConfig": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -11981,6 +12352,9 @@ var doc = `{
|
||||
"updatedAt": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
},
|
||||
"webSiteGroupId": {
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -12315,6 +12689,9 @@ var doc = `{
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"sub": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12469,6 +12846,29 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.FileRoleUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group",
|
||||
"path",
|
||||
"sub",
|
||||
"user"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"sub": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.FileWget": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -12503,6 +12903,43 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxAuthReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"websiteID"
|
||||
],
|
||||
"properties": {
|
||||
"websiteID": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxAuthUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"operate",
|
||||
"password",
|
||||
"username",
|
||||
"websiteID"
|
||||
],
|
||||
"properties": {
|
||||
"operate": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"remark": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"websiteID": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxConfigFileUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -12540,6 +12977,25 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxProxyUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"content",
|
||||
"name",
|
||||
"websiteID"
|
||||
],
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"websiteID": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxRewriteReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -13044,6 +13500,80 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteProxyConfig": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"cache",
|
||||
"cacheTime",
|
||||
"cacheUnit",
|
||||
"enable",
|
||||
"id",
|
||||
"match",
|
||||
"modifier",
|
||||
"name",
|
||||
"operate",
|
||||
"proxyHost",
|
||||
"proxyPass"
|
||||
],
|
||||
"properties": {
|
||||
"cache": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"cacheTime": {
|
||||
"type": "integer"
|
||||
},
|
||||
"cacheUnit": {
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"enable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"filePath": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"match": {
|
||||
"type": "string"
|
||||
},
|
||||
"modifier": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"operate": {
|
||||
"type": "string"
|
||||
},
|
||||
"proxyHost": {
|
||||
"type": "string"
|
||||
},
|
||||
"proxyPass": {
|
||||
"type": "string"
|
||||
},
|
||||
"replaces": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteProxyReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteResourceReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -13186,6 +13716,25 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteUpdateDirPermission": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group",
|
||||
"id",
|
||||
"user"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteWafReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -13572,6 +14121,9 @@ var doc = `{
|
||||
"expireDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"httpConfig": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -13617,6 +14169,9 @@ var doc = `{
|
||||
"updatedAt": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
},
|
||||
"webSiteGroupId": {
|
||||
"type": "integer"
|
||||
},
|
||||
|
||||
+608
-53
@@ -785,27 +785,13 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/init": {
|
||||
"post": {
|
||||
"description": "初始化用户",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"/auth/issafety": {
|
||||
"get": {
|
||||
"description": "获取系统安全登录状态",
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Init user",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.InitUser"
|
||||
}
|
||||
}
|
||||
],
|
||||
"summary": "Load safety status",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
@@ -894,20 +880,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/status": {
|
||||
"get": {
|
||||
"description": "判断是否为首次登录",
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Check is First login",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/containers": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -4508,6 +4480,50 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/owner": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改文件用户/组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "Change file owner",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.FileRoleUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"path",
|
||||
"user",
|
||||
"group"
|
||||
],
|
||||
"formatEN": "Change owner [paths] =\u003e [user]/[group]",
|
||||
"formatZH": "修改用户/组 [paths] =\u003e [user]/[group]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/rename": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -7370,6 +7386,70 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/ssl/info": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取证书信息",
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Load system cert info",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SettingInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/ssl/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改系统 ssl 登录",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Update system ssl",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SSLUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"ssl"
|
||||
],
|
||||
"formatEN": "update system ssl =\u003e [ssl]",
|
||||
"formatZH": "修改系统 ssl =\u003e [ssl]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/time/sync": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -7843,6 +7923,72 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/auths": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取密码访问配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Get AuthBasic conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.NginxAuthReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/auths/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新密码访问配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Get AuthBasic conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.NginxAuthUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/check": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -8069,6 +8215,57 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/dir/permission": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新网站目录权限",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Update Site Dir permission",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteUpdateDirPermission"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "websites",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "primary_domain",
|
||||
"output_value": "domain"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "Update domain [domain] dir permission",
|
||||
"formatZH": "更新网站 [domain] 目录权限",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/dir/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -8097,7 +8294,7 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
@@ -8759,6 +8956,141 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/proxies": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取反向代理配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Get proxy conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteProxyReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/proxies/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改反向代理配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Update proxy conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteProxyConfig"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "websites",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "primary_domain",
|
||||
"output_value": "domain"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "Update domain [domain] proxy config",
|
||||
"formatZH": "修改网站 [domain] 反向代理配置 ",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/proxy/file": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新反向代理文件",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Update proxy file",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.NginxProxyUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "websites",
|
||||
"input_colume": "id",
|
||||
"input_value": "websiteID",
|
||||
"isList": false,
|
||||
"output_colume": "primary_domain",
|
||||
"output_value": "domain"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"websiteID"
|
||||
],
|
||||
"formatEN": "Nginx conf proxy file update [domain]",
|
||||
"formatZH": "更新反向代理文件 [domain]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/rewrite": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -9645,6 +9977,9 @@
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"withFile": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10682,21 +11017,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.InitUser": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.InspectReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -10720,6 +11040,9 @@
|
||||
"captchaID": {
|
||||
"type": "string"
|
||||
},
|
||||
"ignoreCaptcha": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -11108,10 +11431,16 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"containerPort": {
|
||||
"type": "integer"
|
||||
"type": "string"
|
||||
},
|
||||
"hostIP": {
|
||||
"type": "string"
|
||||
},
|
||||
"hostPort": {
|
||||
"type": "integer"
|
||||
"type": "string"
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -11337,6 +11666,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SSLUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ssl"
|
||||
],
|
||||
"properties": {
|
||||
"cert": {
|
||||
"type": "string"
|
||||
},
|
||||
"domain": {
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"ssl": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"enable",
|
||||
"disable"
|
||||
]
|
||||
},
|
||||
"sslID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sslType": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SearchForTree": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -11516,6 +11875,12 @@
|
||||
"sessionTimeout": {
|
||||
"type": "string"
|
||||
},
|
||||
"ssl": {
|
||||
"type": "string"
|
||||
},
|
||||
"sslType": {
|
||||
"type": "string"
|
||||
},
|
||||
"systemVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -11551,7 +11916,8 @@
|
||||
],
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"maxLength": 256
|
||||
},
|
||||
"from": {
|
||||
"type": "string",
|
||||
@@ -11570,7 +11936,8 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"maxLength": 256
|
||||
},
|
||||
"from": {
|
||||
"type": "string"
|
||||
@@ -11607,7 +11974,8 @@
|
||||
],
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"maxLength": 256
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
@@ -11928,6 +12296,9 @@
|
||||
"expireDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"httpConfig": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -11967,6 +12338,9 @@
|
||||
"updatedAt": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
},
|
||||
"webSiteGroupId": {
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -12301,6 +12675,9 @@
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"sub": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12455,6 +12832,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.FileRoleUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group",
|
||||
"path",
|
||||
"sub",
|
||||
"user"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"sub": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.FileWget": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -12489,6 +12889,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxAuthReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"websiteID"
|
||||
],
|
||||
"properties": {
|
||||
"websiteID": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxAuthUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"operate",
|
||||
"password",
|
||||
"username",
|
||||
"websiteID"
|
||||
],
|
||||
"properties": {
|
||||
"operate": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"remark": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"websiteID": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxConfigFileUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -12526,6 +12963,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxProxyUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"content",
|
||||
"name",
|
||||
"websiteID"
|
||||
],
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"websiteID": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxRewriteReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -13030,6 +13486,80 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteProxyConfig": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"cache",
|
||||
"cacheTime",
|
||||
"cacheUnit",
|
||||
"enable",
|
||||
"id",
|
||||
"match",
|
||||
"modifier",
|
||||
"name",
|
||||
"operate",
|
||||
"proxyHost",
|
||||
"proxyPass"
|
||||
],
|
||||
"properties": {
|
||||
"cache": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"cacheTime": {
|
||||
"type": "integer"
|
||||
},
|
||||
"cacheUnit": {
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"enable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"filePath": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"match": {
|
||||
"type": "string"
|
||||
},
|
||||
"modifier": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"operate": {
|
||||
"type": "string"
|
||||
},
|
||||
"proxyHost": {
|
||||
"type": "string"
|
||||
},
|
||||
"proxyPass": {
|
||||
"type": "string"
|
||||
},
|
||||
"replaces": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteProxyReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteResourceReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -13172,6 +13702,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteUpdateDirPermission": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group",
|
||||
"id",
|
||||
"user"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteWafReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -13558,6 +14107,9 @@
|
||||
"expireDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"httpConfig": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -13603,6 +14155,9 @@
|
||||
"updatedAt": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
},
|
||||
"webSiteGroupId": {
|
||||
"type": "integer"
|
||||
},
|
||||
|
||||
+399
-35
@@ -202,6 +202,8 @@ definitions:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
withFile:
|
||||
type: boolean
|
||||
required:
|
||||
- name
|
||||
- operation
|
||||
@@ -902,16 +904,6 @@ definitions:
|
||||
- sourceID
|
||||
- targetName
|
||||
type: object
|
||||
dto.InitUser:
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- password
|
||||
type: object
|
||||
dto.InspectReq:
|
||||
properties:
|
||||
id:
|
||||
@@ -927,6 +919,8 @@ definitions:
|
||||
type: string
|
||||
captchaID:
|
||||
type: string
|
||||
ignoreCaptcha:
|
||||
type: boolean
|
||||
name:
|
||||
type: string
|
||||
password:
|
||||
@@ -1185,9 +1179,13 @@ definitions:
|
||||
dto.PortHelper:
|
||||
properties:
|
||||
containerPort:
|
||||
type: integer
|
||||
type: string
|
||||
hostIP:
|
||||
type: string
|
||||
hostPort:
|
||||
type: integer
|
||||
type: string
|
||||
protocol:
|
||||
type: string
|
||||
type: object
|
||||
dto.PortRuleOperate:
|
||||
properties:
|
||||
@@ -1338,6 +1336,26 @@ definitions:
|
||||
used_memory_rss:
|
||||
type: string
|
||||
type: object
|
||||
dto.SSLUpdate:
|
||||
properties:
|
||||
cert:
|
||||
type: string
|
||||
domain:
|
||||
type: string
|
||||
key:
|
||||
type: string
|
||||
ssl:
|
||||
enum:
|
||||
- enable
|
||||
- disable
|
||||
type: string
|
||||
sslID:
|
||||
type: integer
|
||||
sslType:
|
||||
type: string
|
||||
required:
|
||||
- ssl
|
||||
type: object
|
||||
dto.SearchForTree:
|
||||
properties:
|
||||
info:
|
||||
@@ -1457,6 +1475,10 @@ definitions:
|
||||
type: string
|
||||
sessionTimeout:
|
||||
type: string
|
||||
ssl:
|
||||
type: string
|
||||
sslType:
|
||||
type: string
|
||||
systemVersion:
|
||||
type: string
|
||||
theme:
|
||||
@@ -1478,6 +1500,7 @@ definitions:
|
||||
dto.SnapshotCreate:
|
||||
properties:
|
||||
description:
|
||||
maxLength: 256
|
||||
type: string
|
||||
from:
|
||||
enum:
|
||||
@@ -1494,6 +1517,7 @@ definitions:
|
||||
dto.SnapshotImport:
|
||||
properties:
|
||||
description:
|
||||
maxLength: 256
|
||||
type: string
|
||||
from:
|
||||
type: string
|
||||
@@ -1516,6 +1540,7 @@ definitions:
|
||||
dto.UpdateDescription:
|
||||
properties:
|
||||
description:
|
||||
maxLength: 256
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
@@ -1728,6 +1753,8 @@ definitions:
|
||||
type: boolean
|
||||
expireDate:
|
||||
type: string
|
||||
group:
|
||||
type: string
|
||||
httpConfig:
|
||||
type: string
|
||||
id:
|
||||
@@ -1754,6 +1781,8 @@ definitions:
|
||||
type: string
|
||||
updatedAt:
|
||||
type: string
|
||||
user:
|
||||
type: string
|
||||
webSiteGroupId:
|
||||
type: integer
|
||||
webSiteSSL:
|
||||
@@ -1974,6 +2003,8 @@ definitions:
|
||||
type: integer
|
||||
path:
|
||||
type: string
|
||||
sub:
|
||||
type: boolean
|
||||
required:
|
||||
- mode
|
||||
- path
|
||||
@@ -2079,6 +2110,22 @@ definitions:
|
||||
- newName
|
||||
- oldName
|
||||
type: object
|
||||
request.FileRoleUpdate:
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
sub:
|
||||
type: boolean
|
||||
user:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- path
|
||||
- sub
|
||||
- user
|
||||
type: object
|
||||
request.FileWget:
|
||||
properties:
|
||||
name:
|
||||
@@ -2102,6 +2149,31 @@ definitions:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
type: object
|
||||
request.NginxAuthReq:
|
||||
properties:
|
||||
websiteID:
|
||||
type: integer
|
||||
required:
|
||||
- websiteID
|
||||
type: object
|
||||
request.NginxAuthUpdate:
|
||||
properties:
|
||||
operate:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
remark:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
websiteID:
|
||||
type: integer
|
||||
required:
|
||||
- operate
|
||||
- password
|
||||
- username
|
||||
- websiteID
|
||||
type: object
|
||||
request.NginxConfigFileUpdate:
|
||||
properties:
|
||||
backup:
|
||||
@@ -2127,6 +2199,19 @@ definitions:
|
||||
required:
|
||||
- websiteId
|
||||
type: object
|
||||
request.NginxProxyUpdate:
|
||||
properties:
|
||||
content:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
websiteID:
|
||||
type: integer
|
||||
required:
|
||||
- content
|
||||
- name
|
||||
- websiteID
|
||||
type: object
|
||||
request.NginxRewriteReq:
|
||||
properties:
|
||||
name:
|
||||
@@ -2465,6 +2550,58 @@ definitions:
|
||||
- id
|
||||
- type
|
||||
type: object
|
||||
request.WebsiteProxyConfig:
|
||||
properties:
|
||||
cache:
|
||||
type: boolean
|
||||
cacheTime:
|
||||
type: integer
|
||||
cacheUnit:
|
||||
type: string
|
||||
content:
|
||||
type: string
|
||||
enable:
|
||||
type: boolean
|
||||
filePath:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
match:
|
||||
type: string
|
||||
modifier:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
operate:
|
||||
type: string
|
||||
proxyHost:
|
||||
type: string
|
||||
proxyPass:
|
||||
type: string
|
||||
replaces:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- cache
|
||||
- cacheTime
|
||||
- cacheUnit
|
||||
- enable
|
||||
- id
|
||||
- match
|
||||
- modifier
|
||||
- name
|
||||
- operate
|
||||
- proxyHost
|
||||
- proxyPass
|
||||
type: object
|
||||
request.WebsiteProxyReq:
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
request.WebsiteResourceReq:
|
||||
properties:
|
||||
id:
|
||||
@@ -2560,6 +2697,19 @@ definitions:
|
||||
- id
|
||||
- siteDir
|
||||
type: object
|
||||
request.WebsiteUpdateDirPermission:
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
user:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- id
|
||||
- user
|
||||
type: object
|
||||
request.WebsiteWafReq:
|
||||
properties:
|
||||
key:
|
||||
@@ -2816,6 +2966,8 @@ definitions:
|
||||
type: string
|
||||
expireDate:
|
||||
type: string
|
||||
group:
|
||||
type: string
|
||||
httpConfig:
|
||||
type: string
|
||||
id:
|
||||
@@ -2846,6 +2998,8 @@ definitions:
|
||||
type: string
|
||||
updatedAt:
|
||||
type: string
|
||||
user:
|
||||
type: string
|
||||
webSiteGroupId:
|
||||
type: integer
|
||||
webSiteSSL:
|
||||
@@ -3392,22 +3546,13 @@ paths:
|
||||
summary: Check System isDemo
|
||||
tags:
|
||||
- Auth
|
||||
/auth/init:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 初始化用户
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.InitUser'
|
||||
/auth/issafety:
|
||||
get:
|
||||
description: 获取系统安全登录状态
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
summary: Init user
|
||||
summary: Load safety status
|
||||
tags:
|
||||
- Auth
|
||||
/auth/login:
|
||||
@@ -3461,15 +3606,6 @@ paths:
|
||||
summary: User login with mfa
|
||||
tags:
|
||||
- Auth
|
||||
/auth/status:
|
||||
get:
|
||||
description: 判断是否为首次登录
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
summary: Check is First login
|
||||
tags:
|
||||
- Auth
|
||||
/containers:
|
||||
post:
|
||||
consumes:
|
||||
@@ -5761,6 +5897,35 @@ paths:
|
||||
formatEN: Move [oldPaths] => [newPath]
|
||||
formatZH: 移动文件 [oldPaths] => [newPath]
|
||||
paramKeys: []
|
||||
/files/owner:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 修改文件用户/组
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.FileRoleUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Change file owner
|
||||
tags:
|
||||
- File
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- path
|
||||
- user
|
||||
- group
|
||||
formatEN: Change owner [paths] => [user]/[group]
|
||||
formatZH: 修改用户/组 [paths] => [user]/[group]
|
||||
paramKeys: []
|
||||
/files/rename:
|
||||
post:
|
||||
consumes:
|
||||
@@ -7578,6 +7743,46 @@ paths:
|
||||
summary: Page system snapshot
|
||||
tags:
|
||||
- System Setting
|
||||
/settings/ssl/info:
|
||||
get:
|
||||
description: 获取证书信息
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SettingInfo'
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Load system cert info
|
||||
tags:
|
||||
- System Setting
|
||||
/settings/ssl/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 修改系统 ssl 登录
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SSLUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update system ssl
|
||||
tags:
|
||||
- System Setting
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- ssl
|
||||
formatEN: update system ssl => [ssl]
|
||||
formatZH: 修改系统 ssl => [ssl]
|
||||
paramKeys: []
|
||||
/settings/time/sync:
|
||||
post:
|
||||
description: 系统时间同步
|
||||
@@ -7879,6 +8084,46 @@ paths:
|
||||
summary: Page website acme accounts
|
||||
tags:
|
||||
- Website Acme
|
||||
/websites/auths:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取密码访问配置
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.NginxAuthReq'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Get AuthBasic conf
|
||||
tags:
|
||||
- Website
|
||||
/websites/auths/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新密码访问配置
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.NginxAuthUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Get AuthBasic conf
|
||||
tags:
|
||||
- Website
|
||||
/websites/check:
|
||||
post:
|
||||
consumes:
|
||||
@@ -8023,6 +8268,39 @@ paths:
|
||||
formatEN: Delete website [domain]
|
||||
formatZH: 删除网站 [domain]
|
||||
paramKeys: []
|
||||
/websites/dir/permission:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新网站目录权限
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.WebsiteUpdateDirPermission'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update Site Dir permission
|
||||
tags:
|
||||
- Website
|
||||
x-panel-log:
|
||||
BeforeFuntions:
|
||||
- db: websites
|
||||
input_colume: id
|
||||
input_value: id
|
||||
isList: false
|
||||
output_colume: primary_domain
|
||||
output_value: domain
|
||||
bodyKeys:
|
||||
- id
|
||||
formatEN: Update domain [domain] dir permission
|
||||
formatZH: 更新网站 [domain] 目录权限
|
||||
paramKeys: []
|
||||
/websites/dir/update:
|
||||
post:
|
||||
consumes:
|
||||
@@ -8037,7 +8315,7 @@ paths:
|
||||
$ref: '#/definitions/request.WebsiteUpdateDir'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update Site Dir
|
||||
@@ -8464,6 +8742,92 @@ paths:
|
||||
formatEN: Nginx conf update [domain]
|
||||
formatZH: php 配置修改 [domain]
|
||||
paramKeys: []
|
||||
/websites/proxies:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取反向代理配置
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.WebsiteProxyReq'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Get proxy conf
|
||||
tags:
|
||||
- Website
|
||||
/websites/proxies/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 修改反向代理配置
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.WebsiteProxyConfig'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update proxy conf
|
||||
tags:
|
||||
- Website
|
||||
x-panel-log:
|
||||
BeforeFuntions:
|
||||
- db: websites
|
||||
input_colume: id
|
||||
input_value: id
|
||||
isList: false
|
||||
output_colume: primary_domain
|
||||
output_value: domain
|
||||
bodyKeys:
|
||||
- id
|
||||
formatEN: Update domain [domain] proxy config
|
||||
formatZH: '修改网站 [domain] 反向代理配置 '
|
||||
paramKeys: []
|
||||
/websites/proxy/file:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新反向代理文件
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.NginxProxyUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update proxy file
|
||||
tags:
|
||||
- Website
|
||||
x-panel-log:
|
||||
BeforeFuntions:
|
||||
- db: websites
|
||||
input_colume: id
|
||||
input_value: websiteID
|
||||
isList: false
|
||||
output_colume: primary_domain
|
||||
output_value: domain
|
||||
bodyKeys:
|
||||
- websiteID
|
||||
formatEN: Nginx conf proxy file update [domain]
|
||||
formatZH: 更新反向代理文件 [domain]
|
||||
paramKeys: []
|
||||
/websites/rewrite:
|
||||
post:
|
||||
consumes:
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
proxy_temp_path /www/common/proxy/proxy_temp_dir;
|
||||
proxy_cache_path /www/common/proxy/proxy_cache_dir levels=1:2 keys_zone=proxy_cache_panel:20m inactive=1d max_size=5g;
|
||||
client_body_buffer_size 512k;
|
||||
proxy_connect_timeout 60;
|
||||
proxy_read_timeout 60;
|
||||
proxy_send_timeout 60;
|
||||
proxy_buffer_size 32k;
|
||||
proxy_buffers 4 64k;
|
||||
proxy_busy_buffers_size 128k;
|
||||
proxy_temp_file_write_size 128k;
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_503 http_404;
|
||||
proxy_cache proxy_cache_panel;
|
||||
@@ -19,3 +19,12 @@ var IndexPHP []byte
|
||||
|
||||
//go:embed rewrite/*
|
||||
var Rewrites embed.FS
|
||||
|
||||
//go:embed cache.conf
|
||||
var Cache []byte
|
||||
|
||||
//go:embed proxy.conf
|
||||
var Proxy []byte
|
||||
|
||||
//go:embed proxy_cache.conf
|
||||
var ProxyCache []byte
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
location ^~ /test {
|
||||
proxy_pass http://1panel.cloud/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_http_version 1.1;
|
||||
|
||||
add_header X-Cache $upstream_cache_status;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
proxy_ignore_headers Set-Cookie Cache-Control expires;
|
||||
proxy_cache cache_one;
|
||||
proxy_cache_key $host$uri$is_args$args;
|
||||
proxy_cache_valid 200 304 301 302 10m;
|
||||
@@ -0,0 +1,10 @@
|
||||
set $static_fileg 0;
|
||||
if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
|
||||
{
|
||||
set $static_fileg 1;
|
||||
expires 1m;
|
||||
}
|
||||
if ( $static_fileg = 0 )
|
||||
{
|
||||
add_header Cache-Control no-cache;
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
rewrite ^/vod-(.*)$ /index.php?m=vod-$1 break;
|
||||
rewrite ^/art-(.*)$ /index.php?m=art-$1 break;
|
||||
rewrite ^/gbook-(.*)$ /index.php?m=gbook-$1 break;
|
||||
rewrite ^/label-(.*)$ /index.php?m=label-$1 break;
|
||||
rewrite ^/map-(.*)$ /index.php?m=map-$1 break;
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^/index.php(.*)$ /index.php?s=$1 break;
|
||||
# MacCMS要求强制修改后台文件名称 所以需要手动修改下方这条重写规则 将admin修改为你修改后的文件名即可
|
||||
rewrite ^/admin.php(.*)$ /admin.php?s=$1 break;
|
||||
rewrite ^/api.php(.*)$ /api.php?s=$1 break;
|
||||
rewrite ^/(.*)$ /index.php?s=$1 break;
|
||||
rewrite ^/vod-(.*)$ /index.php?m=vod-$1 break;
|
||||
rewrite ^/art-(.*)$ /index.php?m=art-$1 break;
|
||||
rewrite ^/gbook-(.*)$ /index.php?m=gbook-$1 break;
|
||||
rewrite ^/label-(.*)$ /index.php?m=label-$1 break;
|
||||
rewrite ^/map-(.*)$ /index.php?m=map-$1 break;
|
||||
}
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
@@ -1,5 +1,7 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
server_name ko.wp-1.com;
|
||||
|
||||
index index.php index.html index.htm default.php default.htm default.html;
|
||||
|
||||
Binary file not shown.
Vendored
+1
@@ -90,6 +90,7 @@ declare module 'vue' {
|
||||
TableSetting: typeof import('./src/components/table-setting/index.vue')['default']
|
||||
Terminal: typeof import('./src/components/terminal/index.vue')['default']
|
||||
Tooltip: typeof import('./src/components/tooltip/index.vue')['default']
|
||||
Unsafe: typeof import('./src/components/error-message/unsafe.vue')['default']
|
||||
Upload: typeof import('./src/components/upload/index.vue')['default']
|
||||
VCharts: typeof import('./src/components/v-charts/index.vue')['default']
|
||||
}
|
||||
|
||||
Generated
+2567
-2090
File diff suppressed because it is too large
Load Diff
@@ -29,8 +29,8 @@
|
||||
"axios": "^0.27.2",
|
||||
"echarts": "^5.3.0",
|
||||
"echarts-liquidfill": "^3.1.0",
|
||||
"element-plus": "^2.2.32",
|
||||
"fit2cloud-ui-plus": "^1.0.4",
|
||||
"element-plus": "^2.3.4",
|
||||
"fit2cloud-ui-plus": "^1.0.7",
|
||||
"js-base64": "^3.7.2",
|
||||
"js-md5": "^0.7.3",
|
||||
"md-editor-v3": "^2.7.2",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import i18n from '@/lang';
|
||||
import router from '@/routers';
|
||||
import { MsgError } from '@/utils/message';
|
||||
import { GlobalStore } from '@/store';
|
||||
const globalStore = GlobalStore();
|
||||
|
||||
export const checkStatus = (status: number, msg: string): void => {
|
||||
switch (status) {
|
||||
@@ -11,7 +13,8 @@ export const checkStatus = (status: number, msg: string): void => {
|
||||
MsgError(msg ? msg : i18n.global.t('commons.res.notFound'));
|
||||
break;
|
||||
case 403:
|
||||
router.replace({ path: '/login' });
|
||||
globalStore.setLogStatus(false);
|
||||
router.replace({ name: 'entrance', params: { code: globalStore.entrance } });
|
||||
MsgError(msg ? msg : i18n.global.t('commons.res.forbidden'));
|
||||
break;
|
||||
case 500:
|
||||
|
||||
@@ -26,7 +26,6 @@ class RequestHttp {
|
||||
...config.headers,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...config,
|
||||
};
|
||||
@@ -43,17 +42,13 @@ class RequestHttp {
|
||||
globalStore.setCsrfToken(response.headers['x-csrf-token']);
|
||||
}
|
||||
if (data.code == ResultEnum.OVERDUE || data.code == ResultEnum.FORBIDDEN) {
|
||||
router.replace({
|
||||
path: '/login',
|
||||
globalStore.setLogStatus(false);
|
||||
router.push({
|
||||
name: 'entrance',
|
||||
params: { code: globalStore.entrance },
|
||||
});
|
||||
return Promise.reject(data);
|
||||
}
|
||||
if (data.code == ResultEnum.UNSAFETY) {
|
||||
router.replace({
|
||||
path: '/login',
|
||||
});
|
||||
return data;
|
||||
}
|
||||
if (data.code == ResultEnum.EXPIRED) {
|
||||
router.push({ name: 'Expired' });
|
||||
return data;
|
||||
|
||||
@@ -2,6 +2,7 @@ export namespace Login {
|
||||
export interface ReqLoginForm {
|
||||
name: string;
|
||||
password: string;
|
||||
ignoreCaptcha: boolean;
|
||||
captcha: string;
|
||||
captchaID: string;
|
||||
authMethod: string;
|
||||
@@ -17,10 +18,6 @@ export namespace Login {
|
||||
token: string;
|
||||
mfaStatus: string;
|
||||
}
|
||||
export interface InitUser {
|
||||
name: string;
|
||||
password: string;
|
||||
}
|
||||
export interface ResCaptcha {
|
||||
imagePath: string;
|
||||
captchaID: string;
|
||||
|
||||
@@ -27,8 +27,11 @@ export namespace Container {
|
||||
restartPolicy: string;
|
||||
}
|
||||
export interface Port {
|
||||
containerPort: number;
|
||||
hostPort: number;
|
||||
host: string;
|
||||
hostIP: string;
|
||||
containerPort: string;
|
||||
hostPort: string;
|
||||
protocol: string;
|
||||
}
|
||||
export interface Volume {
|
||||
sourceDir: string;
|
||||
@@ -42,7 +45,9 @@ export namespace Container {
|
||||
createTime: string;
|
||||
state: string;
|
||||
runTime: string;
|
||||
|
||||
cpuPercent: number;
|
||||
memoryPercent: number;
|
||||
ports: Array<string>;
|
||||
isFromApp: boolean;
|
||||
isFromCompose: boolean;
|
||||
}
|
||||
@@ -203,6 +208,7 @@ export namespace Container {
|
||||
name: string;
|
||||
operation: string;
|
||||
path: string;
|
||||
withFile: boolean;
|
||||
}
|
||||
export interface ComposeUpdate {
|
||||
name: string;
|
||||
|
||||
@@ -54,6 +54,8 @@ export namespace File {
|
||||
isLink?: boolean;
|
||||
isSymlink?: boolean;
|
||||
linkPath?: boolean;
|
||||
sub?: boolean;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface FileDelete {
|
||||
@@ -90,6 +92,13 @@ export namespace File {
|
||||
newName: string;
|
||||
}
|
||||
|
||||
export interface FileOwner {
|
||||
path: string;
|
||||
user: string;
|
||||
group: string;
|
||||
sub: boolean;
|
||||
}
|
||||
|
||||
export interface FileWget {
|
||||
path: string;
|
||||
name: string;
|
||||
|
||||
@@ -15,6 +15,8 @@ export namespace Setting {
|
||||
language: string;
|
||||
|
||||
serverPort: number;
|
||||
ssl: string;
|
||||
sslType: string;
|
||||
securityEntrance: string;
|
||||
expirationDays: number;
|
||||
expirationTime: string;
|
||||
@@ -34,6 +36,22 @@ export namespace Setting {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
export interface SSLUpdate {
|
||||
ssl: string;
|
||||
domain: string;
|
||||
sslType: string;
|
||||
cert: string;
|
||||
key: string;
|
||||
sslID: number;
|
||||
}
|
||||
export interface SSLInfo {
|
||||
domain: string;
|
||||
timeout: string;
|
||||
rootPath: string;
|
||||
cert: string;
|
||||
key: string;
|
||||
sslID: number;
|
||||
}
|
||||
export interface PasswordUpdate {
|
||||
oldPassword: string;
|
||||
newPassword: string;
|
||||
|
||||
@@ -307,4 +307,57 @@ export namespace Website {
|
||||
user: string;
|
||||
group: string;
|
||||
}
|
||||
|
||||
export interface ProxyReq {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface ProxyConfig {
|
||||
id: number;
|
||||
operate: string;
|
||||
enable: boolean;
|
||||
cache: boolean;
|
||||
cacheTime: number;
|
||||
cacheUnit: string;
|
||||
name: string;
|
||||
modifier: string;
|
||||
match: string;
|
||||
proxyPass: string;
|
||||
proxyHost: string;
|
||||
filePath?: string;
|
||||
replaces?: ProxReplace;
|
||||
content?: string;
|
||||
}
|
||||
|
||||
export interface ProxReplace {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface ProxyFileUpdate {
|
||||
websiteID: number;
|
||||
name: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface AuthReq {
|
||||
websiteID: number;
|
||||
}
|
||||
|
||||
export interface NginxAuth {
|
||||
username: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
export interface AuthConfig {
|
||||
enable: boolean;
|
||||
items: NginxAuth[];
|
||||
}
|
||||
|
||||
export interface NginxAuthConfig {
|
||||
websiteID: number;
|
||||
operate: string;
|
||||
username: string;
|
||||
password: string;
|
||||
remark: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ export const GetAppInstalled = (search: App.AppInstalledSearch) => {
|
||||
};
|
||||
|
||||
export const InstalledOp = (op: App.AppInstalledOp) => {
|
||||
return http.post<any>('apps/installed/op', op);
|
||||
return http.post<any>('apps/installed/op', op, 40000);
|
||||
};
|
||||
|
||||
export const SyncInstalledApp = () => {
|
||||
|
||||
@@ -25,12 +25,8 @@ export const loginStatus = () => {
|
||||
return http.get<any>('/info');
|
||||
};
|
||||
|
||||
export const checkIsFirst = () => {
|
||||
return http.get<boolean>('/auth/status');
|
||||
};
|
||||
|
||||
export const initUser = (params: Login.InitUser) => {
|
||||
return http.post(`/auth/init`, params);
|
||||
export const checkIsSafety = (code: string) => {
|
||||
return http.get<boolean>(`/auth/issafety?code=${code}`);
|
||||
};
|
||||
|
||||
export const checkIsDemo = () => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ResPage, SearchWithPage } from '../interface';
|
||||
import { Container } from '../interface/container';
|
||||
|
||||
export const searchContainer = (params: Container.ContainerSearch) => {
|
||||
return http.post<ResPage<Container.ContainerInfo>>(`/containers/search`, params);
|
||||
return http.post<ResPage<Container.ContainerInfo>>(`/containers/search`, params, 400000);
|
||||
};
|
||||
export const createContainer = (params: Container.ContainerCreate) => {
|
||||
return http.post(`/containers`, params, 3000000);
|
||||
|
||||
@@ -67,6 +67,10 @@ export const RenameRile = (params: File.FileRename) => {
|
||||
return http.post<File.File>('files/rename', params);
|
||||
};
|
||||
|
||||
export const ChangeOwner = (params: File.FileOwner) => {
|
||||
return http.post<File.File>('files/owner', params);
|
||||
};
|
||||
|
||||
export const WgetFile = (params: File.FileWget) => {
|
||||
return http.post<File.FileWgetRes>('files/wget', params);
|
||||
};
|
||||
|
||||
@@ -24,6 +24,13 @@ export const updatePort = (param: Setting.PortUpdate) => {
|
||||
return http.post(`/settings/port/update`, param);
|
||||
};
|
||||
|
||||
export const updateSSL = (param: Setting.SSLUpdate) => {
|
||||
return http.post(`/settings/ssl/update`, param);
|
||||
};
|
||||
export const loadSSLInfo = () => {
|
||||
return http.get<Setting.SSLInfo>(`/settings/ssl/info`);
|
||||
};
|
||||
|
||||
export const handleExpired = (param: Setting.PasswordUpdate) => {
|
||||
return http.post(`/settings/expired/handle`, param);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import http from '@/api';
|
||||
import { ReqPage, ResPage } from '../interface';
|
||||
import { Website } from '../interface/Website';
|
||||
import { Website } from '../interface/website';
|
||||
import { File } from '../interface/file';
|
||||
|
||||
export const SearchWebsites = (req: Website.WebSiteSearch) => {
|
||||
@@ -186,3 +186,23 @@ export const UpdateWebsiteDir = (req: Website.DirUpdate) => {
|
||||
export const UpdateWebsiteDirPermission = (req: Website.DirPermissionUpdate) => {
|
||||
return http.post<any>(`/websites/dir/permission`, req);
|
||||
};
|
||||
|
||||
export const GetProxyConfig = (req: Website.ProxyReq) => {
|
||||
return http.post<Website.ProxyConfig[]>(`/websites/proxies`, req);
|
||||
};
|
||||
|
||||
export const OperateProxyConfig = (req: Website.ProxyReq) => {
|
||||
return http.post<any>(`/websites/proxies/update`, req);
|
||||
};
|
||||
|
||||
export const UpdateProxyConfigFile = (req: Website.ProxyFileUpdate) => {
|
||||
return http.post<any>(`/websites/proxies/file`, req);
|
||||
};
|
||||
|
||||
export const GetAuthConfig = (req: Website.AuthReq) => {
|
||||
return http.post<Website.AuthConfig>(`/websites/auths`, req);
|
||||
};
|
||||
|
||||
export const OperateAuthConfig = (req: Website.NginxAuthConfig) => {
|
||||
return http.post<any>(`/websites/auths/update`, req);
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user