mirror of
https://github.com/tnb-labs/panel.git
synced 2026-08-31 01:12:17 +08:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 724610a45d | |||
| f65cf9e38e | |||
| 4a8ebfbdfa | |||
| fee0fcb998 | |||
| 1e081fcdf2 | |||
| 6c6fb09270 | |||
| 51b47818c0 | |||
| 5b393819ba | |||
| f807d0cd1a | |||
| 0d6f0f317d | |||
| 6bad7f4b5b | |||
| 7a7134b26a | |||
| 28cf7098ff | |||
| b56979147e | |||
| 2ec0d9e844 | |||
| 66641a626e | |||
| 95bfd6843b | |||
| 7e28a34b7f | |||
| b2152edeeb | |||
| 00815979d2 | |||
| c4e01b37b7 | |||
| 7907345521 | |||
| 8f32d6cdb0 | |||
| c3582903bf | |||
| 7d25d2f5aa | |||
| 46fc7b1c6a | |||
| 34ac62d1ae | |||
| 30e78ccf46 | |||
| 22f4cc7fcb | |||
| 1771ae682d | |||
| d1beb60ffd | |||
| cba5f86667 | |||
| e1d9832ce0 | |||
| 6278535902 | |||
| 32fb87243b | |||
| 5f85e7fbe0 | |||
| c36104a075 | |||
| 583f5d13c7 |
@@ -19,11 +19,9 @@ jobs:
|
||||
go-version: '1.22'
|
||||
- name: Fetch Frontend
|
||||
run: |
|
||||
sudo apt-get install -y curl jq unzip zip
|
||||
curl -sSL https://api.github.com/repos/TheTNB/panel-frontend/releases/latest | jq -r ".assets[] | select(.name | contains(\"dist\")) | .browser_download_url" | xargs curl -L -o frontend.zip
|
||||
rm -rf public
|
||||
unzip frontend.zip
|
||||
mv dist public
|
||||
mv dist/* embed/frontend/
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
name: Issue Close Question
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
issue-close-require:
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: needs more info
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: 'close-issues'
|
||||
labels: 'question'
|
||||
inactive-day: 3
|
||||
body: |
|
||||
由于该 Issue 3天未收到回应,现已被自动关闭,若有任何问题,可评论回复。
|
||||
This issue has been closed automatically because it has not had recent activity for 3 days. If you have any questions, please comment here.
|
||||
@@ -67,8 +67,3 @@ out/
|
||||
*.sublime*
|
||||
__debug_bin
|
||||
.project
|
||||
|
||||
# 前端工具链 #
|
||||
.sass-cache/*
|
||||
node_modules/
|
||||
/public
|
||||
|
||||
+2
-3
@@ -62,13 +62,12 @@ fetch:
|
||||
- apk add --no-cache curl jq unzip zip
|
||||
script:
|
||||
- curl -sSL "https://git.haozi.net/api/v4/projects/opensource%2Fpanel-frontend/releases" | jq -r '.[0].assets.links[] | select(.name | contains("dist")) | .direct_asset_url' | xargs curl -L -o frontend.zip
|
||||
- rm -rf public
|
||||
- unzip frontend.zip
|
||||
- mv dist public
|
||||
- mv dist/* embed/frontend/
|
||||
artifacts:
|
||||
name: "frontend"
|
||||
paths:
|
||||
- public
|
||||
- embed/frontend
|
||||
expire_in: 3 days
|
||||
|
||||
release:
|
||||
|
||||
@@ -40,7 +40,6 @@ archives:
|
||||
files:
|
||||
- LICENSE
|
||||
- docs/*
|
||||
- public/*
|
||||
- storage/*
|
||||
- lang/*
|
||||
- scripts/*
|
||||
|
||||
@@ -45,7 +45,6 @@ func (receiver *Monitoring) Handle(console.Context) error {
|
||||
}
|
||||
|
||||
// 将等待中的任务分发
|
||||
// TODO 有bug,需要设计一个锁机制防止重复分发
|
||||
task := services.NewTaskImpl()
|
||||
_ = task.DispatchWaiting()
|
||||
|
||||
|
||||
@@ -165,8 +165,8 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
color.Green().Printfln(translate.Get("commands.panel.getInfo.username") + ": " + user.Username)
|
||||
color.Green().Printfln(translate.Get("commands.panel.getInfo.password") + ": " + password)
|
||||
color.Green().Printfln(translate.Get("commands.panel.port") + ": " + port)
|
||||
color.Green().Printfln(translate.Get("commands.panel.entrance") + ": " + facades.Config().GetString("http.entrance"))
|
||||
color.Green().Printfln(translate.Get("commands.panel.getInfo.address") + ": " + protocol + "://" + ip + ":" + port + facades.Config().GetString("http.entrance"))
|
||||
color.Green().Printfln(translate.Get("commands.panel.entrance") + ": " + facades.Config().GetString("panel.entrance"))
|
||||
color.Green().Printfln(translate.Get("commands.panel.getInfo.address") + ": " + protocol + "://" + ip + ":" + port + facades.Config().GetString("panel.entrance"))
|
||||
|
||||
case "getPort":
|
||||
port, err := shell.Execf(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
|
||||
@@ -178,7 +178,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
color.Green().Printfln(translate.Get("commands.panel.port") + ": " + port)
|
||||
|
||||
case "getEntrance":
|
||||
color.Green().Printfln(translate.Get("commands.panel.entrance") + ": " + facades.Config().GetString("http.entrance"))
|
||||
color.Green().Printfln(translate.Get("commands.panel.entrance") + ": " + facades.Config().GetString("panel.entrance"))
|
||||
|
||||
case "deleteEntrance":
|
||||
oldEntrance, err := shell.Execf(`cat /www/panel/panel.conf | grep APP_ENTRANCE | awk -F '=' '{print $2}' | tr -d '\n'`)
|
||||
@@ -506,8 +506,8 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
Name: name,
|
||||
Status: status,
|
||||
Path: path,
|
||||
Php: php,
|
||||
Ssl: ssl,
|
||||
PHP: php,
|
||||
SSL: ssl,
|
||||
})
|
||||
if err != nil {
|
||||
color.Red().Printfln(translate.Get("commands.panel.writeSite.fail"))
|
||||
@@ -615,15 +615,13 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = website.Add(types.WebsiteAdd{
|
||||
_, err = website.Add(requests.Add{
|
||||
Name: name,
|
||||
Status: true,
|
||||
Domains: domains,
|
||||
Ports: uintPorts,
|
||||
Path: path,
|
||||
Php: php,
|
||||
Ssl: false,
|
||||
Db: false,
|
||||
PHP: php,
|
||||
DB: false,
|
||||
})
|
||||
if err != nil {
|
||||
color.Red().Printfln(err.Error())
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/facades"
|
||||
|
||||
"github.com/TheTNB/panel/internal"
|
||||
"github.com/TheTNB/panel/internal/services"
|
||||
"github.com/TheTNB/panel/pkg/io"
|
||||
)
|
||||
|
||||
type AssetController struct {
|
||||
setting internal.Setting
|
||||
}
|
||||
|
||||
func NewAssetController() *AssetController {
|
||||
return &AssetController{
|
||||
setting: services.NewSettingImpl(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *AssetController) Index(ctx http.Context) http.Response {
|
||||
entrance := facades.Config().GetString("http.entrance")
|
||||
if entrance == "/" {
|
||||
entrance = ""
|
||||
}
|
||||
|
||||
// 自动纠正 URL 格式
|
||||
if ctx.Request().Path() == entrance && ctx.Request().Path() != "/" {
|
||||
return ctx.Response().Redirect(http.StatusMovedPermanently, ctx.Request().Path()+"/")
|
||||
}
|
||||
// 拒绝访问非入口文件
|
||||
if !strings.HasPrefix(ctx.Request().Path(), entrance) {
|
||||
return Error(ctx, http.StatusNotFound, http.StatusText(http.StatusNotFound))
|
||||
}
|
||||
|
||||
path := strings.TrimPrefix(ctx.Request().Path(), entrance)
|
||||
// 设置默认首页
|
||||
if path == "/" || path == "" {
|
||||
path = "/index.html"
|
||||
}
|
||||
|
||||
if !io.Exists("public" + path) {
|
||||
return Error(ctx, http.StatusNotFound, http.StatusText(http.StatusNotFound))
|
||||
}
|
||||
|
||||
file, err := os.Open("public" + path)
|
||||
if err != nil {
|
||||
return Error(ctx, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
}
|
||||
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
return Error(ctx, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
}
|
||||
|
||||
if stat.IsDir() {
|
||||
return Error(ctx, http.StatusForbidden, http.StatusText(http.StatusForbidden))
|
||||
}
|
||||
|
||||
return ctx.Response().Header("Cache-Control", "no-cache").File("public" + path)
|
||||
}
|
||||
|
||||
func (r *AssetController) Favicon(ctx http.Context) http.Response {
|
||||
return ctx.Response().File("public/favicon.png")
|
||||
}
|
||||
|
||||
func (r *AssetController) Robots(ctx http.Context) http.Response {
|
||||
return ctx.Response().File("public/robots.txt")
|
||||
}
|
||||
|
||||
func (r *AssetController) NotFound(ctx http.Context) http.Response {
|
||||
return Error(ctx, http.StatusNotFound, http.StatusText(http.StatusNotFound))
|
||||
}
|
||||
@@ -73,6 +73,10 @@ func (r *CertController) DNSProviders(ctx http.Context) http.Response {
|
||||
"name": "DNSPod",
|
||||
"dns": acme.DnsPod,
|
||||
},
|
||||
{
|
||||
"name": "腾讯云",
|
||||
"dns": acme.Tencent,
|
||||
},
|
||||
{
|
||||
"name": "阿里云",
|
||||
"dns": acme.AliYun,
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/hashicorp/go-version"
|
||||
|
||||
"github.com/TheTNB/panel/app/models"
|
||||
"github.com/TheTNB/panel/internal"
|
||||
@@ -250,13 +251,21 @@ func (r *InfoController) InstalledDbAndPhp(ctx http.Context) http.Response {
|
||||
|
||||
// CheckUpdate 检查面板更新
|
||||
func (r *InfoController) CheckUpdate(ctx http.Context) http.Response {
|
||||
version := facades.Config().GetString("panel.version")
|
||||
remote, err := tools.GetLatestPanelVersion()
|
||||
current := facades.Config().GetString("panel.version")
|
||||
latest, err := tools.GetLatestPanelVersion()
|
||||
if err != nil {
|
||||
return Error(ctx, http.StatusInternalServerError, "获取最新版本失败")
|
||||
}
|
||||
|
||||
if tools.VersionCompare(version, remote.Version, ">=") {
|
||||
v1, err := version.NewVersion(current)
|
||||
if err != nil {
|
||||
return Error(ctx, http.StatusInternalServerError, "版本号解析失败")
|
||||
}
|
||||
v2, err := version.NewVersion(latest.Version)
|
||||
if err != nil {
|
||||
return Error(ctx, http.StatusInternalServerError, "版本号解析失败")
|
||||
}
|
||||
if v1.GreaterThanOrEqual(v2) {
|
||||
return Success(ctx, http.Json{
|
||||
"update": false,
|
||||
})
|
||||
@@ -269,17 +278,25 @@ func (r *InfoController) CheckUpdate(ctx http.Context) http.Response {
|
||||
|
||||
// UpdateInfo 获取更新信息
|
||||
func (r *InfoController) UpdateInfo(ctx http.Context) http.Response {
|
||||
version := facades.Config().GetString("panel.version")
|
||||
current, err := tools.GetLatestPanelVersion()
|
||||
current := facades.Config().GetString("panel.version")
|
||||
latest, err := tools.GetLatestPanelVersion()
|
||||
if err != nil {
|
||||
return Error(ctx, http.StatusInternalServerError, "获取最新版本失败")
|
||||
}
|
||||
|
||||
if tools.VersionCompare(version, current.Version, ">=") {
|
||||
v1, err := version.NewVersion(current)
|
||||
if err != nil {
|
||||
return Error(ctx, http.StatusInternalServerError, "版本号解析失败")
|
||||
}
|
||||
v2, err := version.NewVersion(latest.Version)
|
||||
if err != nil {
|
||||
return Error(ctx, http.StatusInternalServerError, "版本号解析失败")
|
||||
}
|
||||
if v1.GreaterThanOrEqual(v2) {
|
||||
return Error(ctx, http.StatusInternalServerError, "当前版本已是最新版本")
|
||||
}
|
||||
|
||||
versions, err := tools.GenerateVersions(version, current.Version)
|
||||
versions, err := tools.GenerateVersions(current, latest.Version)
|
||||
if err != nil {
|
||||
return Error(ctx, http.StatusInternalServerError, "获取更新信息失败")
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package controllers
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/goravel/framework/support/path"
|
||||
"github.com/spf13/cast"
|
||||
|
||||
requests "github.com/TheTNB/panel/app/http/requests/setting"
|
||||
@@ -44,13 +45,10 @@ func (r *SettingController) List(ctx http.Context) http.Response {
|
||||
return ErrorSystem(ctx)
|
||||
}
|
||||
|
||||
userID := cast.ToUint(ctx.Value("user_id"))
|
||||
var user models.User
|
||||
err = facades.Auth(ctx).User(&user)
|
||||
if err != nil {
|
||||
facades.Log().Request(ctx.Request()).Tags("面板", "面板设置").With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Info("获取用户信息失败")
|
||||
return ErrorSystem(ctx)
|
||||
if err = facades.Orm().Query().Where("id", userID).Get(&user); err != nil {
|
||||
return Error(ctx, http.StatusInternalServerError, "获取用户信息失败")
|
||||
}
|
||||
|
||||
port, err := shell.Execf(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
|
||||
@@ -64,7 +62,7 @@ func (r *SettingController) List(ctx http.Context) http.Response {
|
||||
return Success(ctx, http.Json{
|
||||
"name": r.setting.Get(models.SettingKeyName),
|
||||
"language": facades.Config().GetString("app.locale"),
|
||||
"entrance": facades.Config().GetString("http.entrance"),
|
||||
"entrance": facades.Config().GetString("panel.entrance"),
|
||||
"ssl": facades.Config().GetBool("panel.ssl"),
|
||||
"website_path": r.setting.Get(models.SettingKeyWebsitePath),
|
||||
"backup_path": r.setting.Get(models.SettingKeyBackupPath),
|
||||
@@ -128,11 +126,12 @@ func (r *SettingController) Update(ctx http.Context) http.Response {
|
||||
return ErrorSystem(ctx)
|
||||
}
|
||||
|
||||
userID := cast.ToUint(ctx.Value("user_id"))
|
||||
var user models.User
|
||||
err = facades.Auth(ctx).User(&user)
|
||||
if err != nil {
|
||||
return ErrorSystem(ctx)
|
||||
if err = facades.Orm().Query().Where("id", userID).Get(&user); err != nil {
|
||||
return Error(ctx, http.StatusInternalServerError, "获取用户信息失败")
|
||||
}
|
||||
|
||||
user.Username = updateRequest.UserName
|
||||
user.Email = updateRequest.Email
|
||||
if len(updateRequest.Password) > 0 {
|
||||
@@ -270,10 +269,10 @@ func (r *SettingController) UpdateHttps(ctx http.Context) http.Response {
|
||||
if _, err := cert.ParseKey(httpsRequest.Key); err != nil {
|
||||
return Error(ctx, http.StatusBadRequest, "密钥格式错误")
|
||||
}
|
||||
if err := io.Write(facades.App().ExecutablePath("storage/ssl.crt"), httpsRequest.Cert, 0700); err != nil {
|
||||
if err := io.Write(path.Executable("storage/ssl.crt"), httpsRequest.Cert, 0700); err != nil {
|
||||
return ErrorSystem(ctx)
|
||||
}
|
||||
if err := io.Write(facades.App().ExecutablePath("storage/ssl.key"), httpsRequest.Key, 0700); err != nil {
|
||||
if err := io.Write(path.Executable("storage/ssl.key"), httpsRequest.Key, 0700); err != nil {
|
||||
return ErrorSystem(ctx)
|
||||
}
|
||||
if out, err := shell.Execf("sed -i 's/APP_SSL=false/APP_SSL=true/g' /www/panel/panel.conf"); err != nil {
|
||||
|
||||
@@ -2,7 +2,6 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/swaggo/http-swagger/v2"
|
||||
|
||||
_ "github.com/TheTNB/panel/docs"
|
||||
@@ -25,10 +24,6 @@ func NewSwaggerController() *SwaggerController {
|
||||
// @Failure 500
|
||||
// @Router /swagger [get]
|
||||
func (r *SwaggerController) Index(ctx http.Context) http.Response {
|
||||
if !facades.Config().GetBool("app.debug") {
|
||||
return Error(ctx, http.StatusNotFound, http.StatusText(http.StatusNotFound))
|
||||
}
|
||||
|
||||
handler := httpSwagger.Handler()
|
||||
handler(ctx.Response().Writer(), ctx.Request().Origin())
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package controllers
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/spf13/cast"
|
||||
|
||||
"github.com/TheTNB/panel/app/http/requests/user"
|
||||
"github.com/TheTNB/panel/app/models"
|
||||
@@ -20,16 +21,15 @@ func NewUserController() *UserController {
|
||||
|
||||
// Login
|
||||
//
|
||||
// @Summary 登录
|
||||
// @Description 通过用户名和密码获取访问令牌
|
||||
// @Tags 用户鉴权
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body requests.Login true "request"
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Failure 403 {object} ErrorResponse "用户名或密码错误"
|
||||
// @Failure 500 {object} ErrorResponse "系统内部错误
|
||||
// @Router /panel/user/login [post]
|
||||
// @Summary 登录
|
||||
// @Tags 用户鉴权
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body requests.Login true "request"
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Failure 403 {object} ErrorResponse "用户名或密码错误"
|
||||
// @Failure 500 {object} ErrorResponse "系统内部错误
|
||||
// @Router /panel/user/login [post]
|
||||
func (r *UserController) Login(ctx http.Context) http.Response {
|
||||
var loginRequest requests.Login
|
||||
sanitize := SanitizeRequest(ctx, &loginRequest)
|
||||
@@ -60,32 +60,53 @@ func (r *UserController) Login(ctx http.Context) http.Response {
|
||||
}
|
||||
}
|
||||
|
||||
token, loginErr := facades.Auth(ctx).LoginUsingID(user.ID)
|
||||
if loginErr != nil {
|
||||
facades.Log().Request(ctx.Request()).Tags("面板", "用户").With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Info("登录失败")
|
||||
return ErrorSystem(ctx)
|
||||
ctx.Request().Session().Put("user_id", user.ID)
|
||||
return Success(ctx, nil)
|
||||
}
|
||||
|
||||
// Logout
|
||||
//
|
||||
// @Summary 登出
|
||||
// @Tags 用户鉴权
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Router /panel/user/logout [post]
|
||||
func (r *UserController) Logout(ctx http.Context) http.Response {
|
||||
if ctx.Request().HasSession() {
|
||||
ctx.Request().Session().Forget("user_id")
|
||||
}
|
||||
|
||||
return Success(ctx, http.Json{
|
||||
"access_token": token,
|
||||
})
|
||||
return Success(ctx, nil)
|
||||
}
|
||||
|
||||
// IsLogin
|
||||
//
|
||||
// @Summary 是否登录
|
||||
// @Tags 用户鉴权
|
||||
// @Produce json
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Router /panel/user/isLogin [get]
|
||||
func (r *UserController) IsLogin(ctx http.Context) http.Response {
|
||||
if !ctx.Request().HasSession() {
|
||||
return Success(ctx, false)
|
||||
}
|
||||
|
||||
return Success(ctx, ctx.Request().Session().Has("user_id"))
|
||||
}
|
||||
|
||||
// Info
|
||||
//
|
||||
// @Summary 用户信息
|
||||
// @Description 获取当前登录用户信息
|
||||
// @Tags 用户鉴权
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Router /panel/user/info [get]
|
||||
// @Summary 用户信息
|
||||
// @Tags 用户鉴权
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Router /panel/user/info [get]
|
||||
func (r *UserController) Info(ctx http.Context) http.Response {
|
||||
userID := cast.ToUint(ctx.Value("user_id"))
|
||||
var user models.User
|
||||
err := facades.Auth(ctx).User(&user)
|
||||
if err != nil {
|
||||
if err := facades.Orm().Query().Where("id", userID).Get(&user); err != nil {
|
||||
facades.Log().Request(ctx.Request()).Tags("面板", "用户").With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Info("获取用户信息失败")
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"github.com/TheTNB/panel/pkg/shell"
|
||||
"github.com/TheTNB/panel/pkg/str"
|
||||
"github.com/TheTNB/panel/pkg/systemctl"
|
||||
"github.com/TheTNB/panel/pkg/types"
|
||||
)
|
||||
|
||||
type WebsiteController struct {
|
||||
@@ -55,7 +54,7 @@ func (r *WebsiteController) List(ctx http.Context) http.Response {
|
||||
facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Info("获取网站列表失败")
|
||||
return ErrorSystem(ctx)
|
||||
return Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return Success(ctx, http.Json{
|
||||
@@ -85,27 +84,12 @@ func (r *WebsiteController) Add(ctx http.Context) http.Response {
|
||||
addRequest.Path = r.setting.Get(models.SettingKeyWebsitePath) + "/" + addRequest.Name
|
||||
}
|
||||
|
||||
website := types.WebsiteAdd{
|
||||
Name: addRequest.Name,
|
||||
Status: true,
|
||||
Domains: addRequest.Domains,
|
||||
Ports: addRequest.Ports,
|
||||
Path: addRequest.Path,
|
||||
Php: addRequest.Php,
|
||||
Ssl: false,
|
||||
Db: addRequest.Db,
|
||||
DbType: addRequest.DbType,
|
||||
DbName: addRequest.DbName,
|
||||
DbUser: addRequest.DbUser,
|
||||
DbPassword: addRequest.DbPassword,
|
||||
}
|
||||
|
||||
_, err := r.website.Add(website)
|
||||
_, err := r.website.Add(addRequest)
|
||||
if err != nil {
|
||||
facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Info("添加网站失败")
|
||||
return ErrorSystem(ctx)
|
||||
return Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return Success(ctx, nil)
|
||||
@@ -181,14 +165,14 @@ func (r *WebsiteController) SaveDefaultConfig(ctx http.Context) http.Response {
|
||||
facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Info("保存默认首页配置失败")
|
||||
return ErrorSystem(ctx)
|
||||
return Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
if err := io.Write("/www/server/openresty/html/stop.html", stop, 0644); err != nil {
|
||||
facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Info("保存默认停止页配置失败")
|
||||
return ErrorSystem(ctx)
|
||||
return Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return Success(ctx, nil)
|
||||
@@ -217,7 +201,7 @@ func (r *WebsiteController) GetConfig(ctx http.Context) http.Response {
|
||||
"id": idRequest.ID,
|
||||
"error": err.Error(),
|
||||
}).Info("获取网站配置失败")
|
||||
return ErrorSystem(ctx)
|
||||
return Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return Success(ctx, config)
|
||||
@@ -335,7 +319,7 @@ func (r *WebsiteController) BackupList(ctx http.Context) http.Response {
|
||||
facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Info("获取备份列表失败")
|
||||
return ErrorSystem(ctx)
|
||||
return Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
paged, total := Paginate(ctx, backups)
|
||||
@@ -412,7 +396,7 @@ func (r *WebsiteController) UploadBackup(ctx http.Context) http.Response {
|
||||
facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Info("上传备份失败")
|
||||
return ErrorSystem(ctx)
|
||||
return Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return Success(ctx, nil)
|
||||
@@ -506,7 +490,7 @@ func (r *WebsiteController) ResetConfig(ctx http.Context) http.Response {
|
||||
}
|
||||
|
||||
website.Status = true
|
||||
website.Ssl = false
|
||||
website.SSL = false
|
||||
if err := facades.Orm().Query().Save(&website); err != nil {
|
||||
facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{
|
||||
"id": idRequest.ID,
|
||||
@@ -575,7 +559,7 @@ server
|
||||
error_log /www/wwwlogs/%s.log;
|
||||
}
|
||||
|
||||
`, website.Path, website.Php, website.Name, website.Name, website.Name, website.Name)
|
||||
`, website.Path, website.PHP, website.Name, website.Name, website.Name, website.Name)
|
||||
if err := io.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -650,7 +634,7 @@ func (r *WebsiteController) Status(ctx http.Context) http.Response {
|
||||
}
|
||||
|
||||
if err = io.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644); err != nil {
|
||||
return ErrorSystem(ctx)
|
||||
return Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
if err = systemctl.Reload("openresty"); err != nil {
|
||||
_, err = shell.Execf("openresty -t")
|
||||
|
||||
@@ -2,6 +2,7 @@ package http
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
sessionmiddleware "github.com/goravel/framework/session/middleware"
|
||||
|
||||
"github.com/TheTNB/panel/app/http/middleware"
|
||||
)
|
||||
@@ -13,7 +14,10 @@ type Kernel struct {
|
||||
// These middleware are run during every request to your application.
|
||||
func (kernel Kernel) Middleware() []http.Middleware {
|
||||
return []http.Middleware{
|
||||
sessionmiddleware.StartSession(),
|
||||
middleware.Log(),
|
||||
middleware.Status(),
|
||||
middleware.Entrance(),
|
||||
middleware.Static(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
func Entrance() http.Middleware {
|
||||
return func(ctx http.Context) {
|
||||
translate := facades.Lang(ctx)
|
||||
|
||||
if !ctx.Request().HasSession() {
|
||||
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
|
||||
"message": translate.Get("auth.session.missing"),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
entrance := facades.Config().GetString("panel.entrance")
|
||||
if ctx.Request().Path() == entrance {
|
||||
ctx.Request().Session().Put("verify_entrance", true)
|
||||
_ = ctx.Response().Redirect(http.StatusFound, "/login").Render()
|
||||
ctx.Request().AbortWithStatus(http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
if !facades.Config().GetBool("app.debug") &&
|
||||
(ctx.Request().Session().Missing("verify_entrance") || !cast.ToBool(ctx.Request().Session().Get("verify_entrance"))) &&
|
||||
ctx.Request().Path() != "/robots.txt" {
|
||||
ctx.Request().AbortWithStatusJson(http.StatusTeapot, http.Json{
|
||||
"message": "请通过正确的入口访问",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Request().Next()
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/goravel/framework/auth"
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/facades"
|
||||
)
|
||||
|
||||
// Jwt 确保通过 JWT 鉴权
|
||||
func Jwt() http.Middleware {
|
||||
return func(ctx http.Context) {
|
||||
translate := facades.Lang(ctx)
|
||||
token := ctx.Request().Header("Authorization", ctx.Request().Header("Sec-WebSocket-Protocol"))
|
||||
if len(token) == 0 {
|
||||
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
|
||||
"message": translate.Get("auth.token.missing"),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// JWT 鉴权
|
||||
if _, err := facades.Auth(ctx).Parse(token); err != nil {
|
||||
if errors.Is(err, auth.ErrorTokenExpired) {
|
||||
token, err = facades.Auth(ctx).Refresh()
|
||||
if err != nil {
|
||||
// 到达刷新时间上限
|
||||
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
|
||||
"message": translate.Get("auth.token.expired"),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
token = "Bearer " + token
|
||||
} else {
|
||||
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
|
||||
"message": translate.Get("auth.token.expired"),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Response().Header("Authorization", token)
|
||||
ctx.Request().Next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
// Session 确保通过 JWT 鉴权
|
||||
func Session() http.Middleware {
|
||||
return func(ctx http.Context) {
|
||||
translate := facades.Lang(ctx)
|
||||
|
||||
if !ctx.Request().HasSession() {
|
||||
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
|
||||
"message": translate.Get("auth.session.missing"),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Request().Session().Missing("user_id") {
|
||||
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
|
||||
"message": translate.Get("auth.session.expired"),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
userID := cast.ToUint(ctx.Request().Session().Get("user_id"))
|
||||
if userID == 0 {
|
||||
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
|
||||
"message": translate.Get("auth.session.invalid"),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 刷新会话
|
||||
/*if err := ctx.Request().Session().Regenerate(); err == nil {
|
||||
ctx.Response().Cookie(http.Cookie{
|
||||
Name: ctx.Request().Session().GetName(),
|
||||
Value: ctx.Request().Session().GetID(),
|
||||
MaxAge: facades.Config().GetInt("session.lifetime") * 60,
|
||||
Path: facades.Config().GetString("session.path"),
|
||||
Domain: facades.Config().GetString("session.domain"),
|
||||
Secure: facades.Config().GetBool("session.secure"),
|
||||
HttpOnly: facades.Config().GetBool("session.http_only"),
|
||||
SameSite: facades.Config().GetString("session.same_site"),
|
||||
})
|
||||
}*/
|
||||
|
||||
ctx.WithValue("user_id", userID)
|
||||
ctx.Request().Next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gin-contrib/static"
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/gin"
|
||||
|
||||
"github.com/TheTNB/panel/embed"
|
||||
)
|
||||
|
||||
func Static() http.Middleware {
|
||||
return func(ctx http.Context) {
|
||||
static.Serve("/", static.EmbedFolder(embed.PublicFS, "frontend"))(ctx.(*gin.Context).Instance())
|
||||
ctx.Request().Next()
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
)
|
||||
|
||||
type CertDeploy struct {
|
||||
ID uint `form:"id" json:"id" filter:"uint"`
|
||||
WebsiteID uint `form:"website_id" json:"website_id" filter:"uint"`
|
||||
ID uint `form:"id" json:"id"`
|
||||
WebsiteID uint `form:"website_id" json:"website_id"`
|
||||
}
|
||||
|
||||
func (r *CertDeploy) Authorize(ctx http.Context) error {
|
||||
@@ -22,7 +22,10 @@ func (r *CertDeploy) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
|
||||
func (r *CertDeploy) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
return map[string]string{
|
||||
"id": "uint",
|
||||
"website_id": "uint",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *CertDeploy) Messages(ctx http.Context) map[string]string {
|
||||
|
||||
@@ -9,9 +9,9 @@ type CertStore struct {
|
||||
Type string `form:"type" json:"type"`
|
||||
Domains []string `form:"domains" json:"domains"`
|
||||
AutoRenew bool `form:"auto_renew" json:"auto_renew"`
|
||||
UserID uint `form:"user_id" json:"user_id" filter:"uint"`
|
||||
DNSID uint `form:"dns_id" json:"dns_id" filter:"uint"`
|
||||
WebsiteID uint `form:"website_id" json:"website_id" filter:"uint"`
|
||||
UserID uint `form:"user_id" json:"user_id"`
|
||||
DNSID uint `form:"dns_id" json:"dns_id"`
|
||||
WebsiteID uint `form:"website_id" json:"website_id"`
|
||||
}
|
||||
|
||||
func (r *CertStore) Authorize(ctx http.Context) error {
|
||||
@@ -30,7 +30,11 @@ func (r *CertStore) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
|
||||
func (r *CertStore) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
return map[string]string{
|
||||
"user_id": "uint",
|
||||
"dns_id": "uint",
|
||||
"website_id": "uint",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *CertStore) Messages(ctx http.Context) map[string]string {
|
||||
|
||||
@@ -10,9 +10,9 @@ type CertUpdate struct {
|
||||
Type string `form:"type" json:"type"`
|
||||
Domains []string `form:"domains" json:"domains"`
|
||||
AutoRenew bool `form:"auto_renew" json:"auto_renew"`
|
||||
UserID uint `form:"user_id" json:"user_id" filter:"uint"`
|
||||
DNSID uint `form:"dns_id" json:"dns_id" filter:"uint"`
|
||||
WebsiteID uint `form:"website_id" json:"website_id" filter:"uint"`
|
||||
UserID uint `form:"user_id" json:"user_id"`
|
||||
DNSID uint `form:"dns_id" json:"dns_id"`
|
||||
WebsiteID uint `form:"website_id" json:"website_id"`
|
||||
}
|
||||
|
||||
func (r *CertUpdate) Authorize(ctx http.Context) error {
|
||||
@@ -32,7 +32,11 @@ func (r *CertUpdate) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
|
||||
func (r *CertUpdate) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
return map[string]string{
|
||||
"user_id": "uint",
|
||||
"dns_id": "uint",
|
||||
"website_id": "uint",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *CertUpdate) Messages(ctx http.Context) map[string]string {
|
||||
|
||||
@@ -19,13 +19,13 @@ func (r *DNSStore) Authorize(ctx http.Context) error {
|
||||
|
||||
func (r *DNSStore) Rules(ctx http.Context) map[string]string {
|
||||
return map[string]string{
|
||||
"type": "required|in:dnspod,aliyun,cloudflare",
|
||||
"type": "required|in:dnspod,tencent,aliyun,cloudflare",
|
||||
"name": "required",
|
||||
"data": "required",
|
||||
"data.id": "required_if:type,dnspod",
|
||||
"data.token": "required_if:type,dnspod",
|
||||
"data.access_key": "required_if:type,aliyun",
|
||||
"data.secret_key": "required_if:type,aliyun",
|
||||
"data.access_key": "required_if:type,aliyun,tencent",
|
||||
"data.secret_key": "required_if:type,aliyun,tencent",
|
||||
"data.api_key": "required_if:type,cloudflare",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
)
|
||||
|
||||
type Paginate struct {
|
||||
Page int `form:"page" json:"page" filter:"int"`
|
||||
Limit int `form:"limit" json:"limit" filter:"int"`
|
||||
Page int `form:"page" json:"page"`
|
||||
Limit int `form:"limit" json:"limit"`
|
||||
}
|
||||
|
||||
func (r *Paginate) Authorize(ctx http.Context) error {
|
||||
@@ -22,7 +22,10 @@ func (r *Paginate) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
|
||||
func (r *Paginate) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
return map[string]string{
|
||||
"page": "int",
|
||||
"limit": "int",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Paginate) Messages(ctx http.Context) map[string]string {
|
||||
|
||||
@@ -23,9 +23,9 @@ type ContainerCreate struct {
|
||||
OpenStdin bool `form:"openStdin" json:"open_stdin"`
|
||||
PublishAllPorts bool `form:"publish_all_ports" json:"publish_all_ports"`
|
||||
Tty bool `form:"tty" json:"tty"`
|
||||
CPUShares int64 `form:"cpu_shares" json:"cpu_shares" filter:"int"`
|
||||
CPUs int64 `form:"cpus" json:"cpus" filter:"int"`
|
||||
Memory int64 `form:"memory" json:"memory" filter:"int"`
|
||||
CPUShares int64 `form:"cpu_shares" json:"cpu_shares"`
|
||||
CPUs int64 `form:"cpus" json:"cpus"`
|
||||
Memory int64 `form:"memory" json:"memory"`
|
||||
}
|
||||
|
||||
func (r *ContainerCreate) Authorize(ctx http.Context) error {
|
||||
@@ -65,7 +65,11 @@ func (r *ContainerCreate) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
|
||||
func (r *ContainerCreate) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
return map[string]string{
|
||||
"cpu_shares": "int",
|
||||
"cpus": "int",
|
||||
"memory": "int",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ContainerCreate) Messages(ctx http.Context) map[string]string {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
type Update struct {
|
||||
Name string `form:"name" json:"name"`
|
||||
Language string `form:"language" json:"language"`
|
||||
Port uint `form:"port" json:"port" filter:"uint"`
|
||||
Port uint `form:"port" json:"port"`
|
||||
BackupPath string `form:"backup_path" json:"backup_path"`
|
||||
WebsitePath string `form:"website_path" json:"website_path"`
|
||||
Entrance string `form:"entrance" json:"entrance"`
|
||||
@@ -36,7 +36,9 @@ func (r *Update) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
|
||||
func (r *Update) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
return map[string]string{
|
||||
"port": "uint",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Update) Messages(ctx http.Context) map[string]string {
|
||||
|
||||
@@ -10,12 +10,12 @@ type Add struct {
|
||||
Domains []string `form:"domains" json:"domains"`
|
||||
Ports []uint `form:"ports" json:"ports"`
|
||||
Path string `form:"path" json:"path"`
|
||||
Php string `form:"php" json:"php"`
|
||||
Db bool `form:"db" json:"db"`
|
||||
DbType string `form:"db_type" json:"db_type"`
|
||||
DbName string `form:"db_name" json:"db_name"`
|
||||
DbUser string `form:"db_user" json:"db_user"`
|
||||
DbPassword string `form:"db_password" json:"db_password"`
|
||||
PHP string `form:"php" json:"php"`
|
||||
DB bool `form:"db" json:"db"`
|
||||
DBType string `form:"db_type" json:"db_type"`
|
||||
DBName string `form:"db_name" json:"db_name"`
|
||||
DBUser string `form:"db_user" json:"db_user"`
|
||||
DBPassword string `form:"db_password" json:"db_password"`
|
||||
}
|
||||
|
||||
func (r *Add) Authorize(ctx http.Context) error {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
type Delete struct {
|
||||
ID uint `form:"id" json:"id" filter:"uint"`
|
||||
ID uint `form:"id" json:"id"`
|
||||
Path bool `form:"path" json:"path"`
|
||||
DB bool `form:"db" json:"db"`
|
||||
}
|
||||
@@ -24,7 +24,9 @@ func (r *Delete) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
|
||||
func (r *Delete) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
return map[string]string{
|
||||
"id": "uint",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Delete) Messages(ctx http.Context) map[string]string {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
type ID struct {
|
||||
ID uint `form:"id" json:"id" filter:"uint"`
|
||||
ID uint `form:"id" json:"id"`
|
||||
}
|
||||
|
||||
func (r *ID) Authorize(ctx http.Context) error {
|
||||
@@ -20,7 +20,9 @@ func (r *ID) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
|
||||
func (r *ID) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
return map[string]string{
|
||||
"id": "uint",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ID) Messages(ctx http.Context) map[string]string {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
type RestoreBackup struct {
|
||||
ID uint `form:"id" json:"id" filter:"uint"`
|
||||
ID uint `form:"id" json:"id"`
|
||||
Name string `form:"name" json:"name"`
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@ func (r *RestoreBackup) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
|
||||
func (r *RestoreBackup) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
return map[string]string{
|
||||
"id": "uint",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RestoreBackup) Messages(ctx http.Context) map[string]string {
|
||||
|
||||
@@ -6,13 +6,15 @@ import (
|
||||
)
|
||||
|
||||
type SaveConfig struct {
|
||||
ID uint `form:"id" json:"id" filter:"uint"`
|
||||
ID uint `form:"id" json:"id"`
|
||||
Domains []string `form:"domains" json:"domains"`
|
||||
Ports []uint `form:"ports" json:"ports"`
|
||||
TLSPorts []uint `form:"tls_ports" json:"tls_ports"`
|
||||
Hsts bool `form:"hsts" json:"hsts"`
|
||||
Ssl bool `form:"ssl" json:"ssl"`
|
||||
HttpRedirect bool `form:"http_redirect" json:"http_redirect"`
|
||||
SSLPorts []uint `form:"ssl_ports" json:"ssl_ports"`
|
||||
QUICPorts []uint `form:"quic_ports" json:"quic_ports"`
|
||||
OCSP bool `form:"ocsp" json:"ocsp"`
|
||||
HSTS bool `form:"hsts" json:"hsts"`
|
||||
SSL bool `form:"ssl" json:"ssl"`
|
||||
HTTPRedirect bool `form:"http_redirect" json:"http_redirect"`
|
||||
OpenBasedir bool `form:"open_basedir" json:"open_basedir"`
|
||||
Waf bool `form:"waf" json:"waf"`
|
||||
WafCache string `form:"waf_cache" json:"waf_cache"`
|
||||
@@ -23,9 +25,9 @@ type SaveConfig struct {
|
||||
Root string `form:"root" json:"root"`
|
||||
Raw string `form:"raw" json:"raw"`
|
||||
Rewrite string `form:"rewrite" json:"rewrite"`
|
||||
Php int `form:"php" json:"php" filter:"int"`
|
||||
SslCertificate string `form:"ssl_certificate" json:"ssl_certificate"`
|
||||
SslCertificateKey string `form:"ssl_certificate_key" json:"ssl_certificate_key"`
|
||||
PHP int `form:"php" json:"php"`
|
||||
SSLCertificate string `form:"ssl_certificate" json:"ssl_certificate"`
|
||||
SSLCertificateKey string `form:"ssl_certificate_key" json:"ssl_certificate_key"`
|
||||
}
|
||||
|
||||
func (r *SaveConfig) Authorize(ctx http.Context) error {
|
||||
@@ -37,7 +39,9 @@ func (r *SaveConfig) Rules(ctx http.Context) map[string]string {
|
||||
"id": "required|exists:websites,id",
|
||||
"domains": "required|slice",
|
||||
"ports": "required|slice",
|
||||
"tls_ports": "required_if:ssl,true|slice|not_in:80",
|
||||
"ssl_ports": "slice|not_in:80",
|
||||
"quic_ports": "slice|not_in:80",
|
||||
"ocsp": "bool",
|
||||
"hsts": "bool",
|
||||
"ssl": "bool",
|
||||
"http_redirect": "bool",
|
||||
@@ -58,7 +62,10 @@ func (r *SaveConfig) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
|
||||
func (r *SaveConfig) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
return map[string]string{
|
||||
"id": "uint",
|
||||
"php": "int",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *SaveConfig) Messages(ctx http.Context) map[string]string {
|
||||
|
||||
@@ -39,6 +39,15 @@ func (receiver *ProcessTask) Handle(args ...any) error {
|
||||
"task_id": taskID,
|
||||
}).Infof("开始执行任务")
|
||||
|
||||
task.Status = models.TaskStatusRunning
|
||||
if err := facades.Orm().Query().Save(&task); err != nil {
|
||||
facades.Log().Tags("面板", "异步任务").With(map[string]any{
|
||||
"task_id": taskID,
|
||||
"error": err.Error(),
|
||||
}).Infof("更新任务状态失败")
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := shell.Execf(task.Shell); err != nil {
|
||||
task.Status = models.TaskStatusFailed
|
||||
_ = facades.Orm().Query().Save(&task)
|
||||
@@ -50,7 +59,13 @@ func (receiver *ProcessTask) Handle(args ...any) error {
|
||||
}
|
||||
|
||||
task.Status = models.TaskStatusSuccess
|
||||
_ = facades.Orm().Query().Save(&task)
|
||||
if err := facades.Orm().Query().Save(&task); err != nil {
|
||||
facades.Log().Tags("面板", "异步任务").With(map[string]any{
|
||||
"task_id": taskID,
|
||||
"error": err.Error(),
|
||||
}).Infof("更新任务状态失败")
|
||||
return nil
|
||||
}
|
||||
|
||||
facades.Log().Tags("面板", "异步任务").With(map[string]any{
|
||||
"task_id": taskID,
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
type CertDNS struct {
|
||||
orm.Model
|
||||
Name string `gorm:"not null" json:"name"` // 备注名称
|
||||
Type string `gorm:"not null" json:"type"` // DNS 提供商 (dnspod, aliyun, cloudflare)
|
||||
Type string `gorm:"not null" json:"type"` // DNS 提供商 (dnspod, tencent, aliyun, cloudflare)
|
||||
Data acme.DNSParam `gorm:"not null;serializer:json" json:"dns_param"`
|
||||
|
||||
Certs []*Cert `gorm:"foreignKey:DNSID" json:"-"`
|
||||
|
||||
@@ -7,8 +7,8 @@ type Website struct {
|
||||
Name string `gorm:"not null;unique" json:"name"`
|
||||
Status bool `gorm:"not null;default:true" json:"status"`
|
||||
Path string `gorm:"not null" json:"path"`
|
||||
Php int `gorm:"not null" json:"php"`
|
||||
Ssl bool `gorm:"not null" json:"ssl"`
|
||||
PHP int `gorm:"not null" json:"php"`
|
||||
SSL bool `gorm:"not null" json:"ssl"`
|
||||
Remark string `gorm:"not null" json:"remark"`
|
||||
|
||||
Cert *Cert `gorm:"foreignKey:WebsiteID" json:"cert"`
|
||||
|
||||
+5
-2
@@ -17,7 +17,9 @@ import (
|
||||
"github.com/goravel/framework/queue"
|
||||
"github.com/goravel/framework/route"
|
||||
"github.com/goravel/framework/schedule"
|
||||
"github.com/goravel/framework/session"
|
||||
"github.com/goravel/framework/support/carbon"
|
||||
"github.com/goravel/framework/support/path"
|
||||
"github.com/goravel/framework/testing"
|
||||
"github.com/goravel/framework/translation"
|
||||
"github.com/goravel/framework/validation"
|
||||
@@ -37,7 +39,7 @@ func init() {
|
||||
// This value is the name of your application. This value is used when the
|
||||
// framework needs to place the application's name in a notification or
|
||||
// any other location as required by the application or its pkg.
|
||||
"name": "Panel",
|
||||
"name": "耗子面板",
|
||||
|
||||
// Application Environment
|
||||
//
|
||||
@@ -74,7 +76,7 @@ func init() {
|
||||
//
|
||||
// The path to the language files for the application. You may change
|
||||
// the path to a different directory if you would like to customize it.
|
||||
"lang_path": facades.App().ExecutablePath("lang"),
|
||||
"lang_path": path.Executable("lang"),
|
||||
|
||||
// Encryption Key
|
||||
//
|
||||
@@ -103,6 +105,7 @@ func init() {
|
||||
&crypt.ServiceProvider{},
|
||||
&filesystem.ServiceProvider{},
|
||||
&validation.ServiceProvider{},
|
||||
&session.ServiceProvider{},
|
||||
&translation.ServiceProvider{},
|
||||
&testing.ServiceProvider{},
|
||||
&providers.AppServiceProvider{},
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/goravel/framework/support/path"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -14,7 +15,7 @@ func init() {
|
||||
"connections": map[string]any{
|
||||
"panel": map[string]any{
|
||||
"driver": "sqlite",
|
||||
"database": config.Env("DB_FILE", facades.App().ExecutablePath("storage/panel.db")),
|
||||
"database": config.Env("DB_FILE", path.Executable("storage/panel.db")),
|
||||
"prefix": "",
|
||||
"singular": false, // Table name is singular
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/goravel/framework/support/path"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -24,7 +25,7 @@ func init() {
|
||||
"disks": map[string]any{
|
||||
"local": map[string]any{
|
||||
"driver": "local",
|
||||
"root": facades.App().ExecutablePath("storage"),
|
||||
"root": path.Executable("storage"),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
+3
-4
@@ -3,6 +3,7 @@ package config
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/route"
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/goravel/framework/support/path"
|
||||
ginfacades "github.com/goravel/gin/facades"
|
||||
)
|
||||
|
||||
@@ -28,8 +29,6 @@ func init() {
|
||||
"host": "",
|
||||
// HTTP Port
|
||||
"port": config.Env("APP_PORT", "8888"),
|
||||
// HTTP Entrance
|
||||
"entrance": config.Env("APP_ENTRANCE", "/"),
|
||||
// HTTPS Configuration
|
||||
"tls": map[string]any{
|
||||
// HTTPS Host
|
||||
@@ -39,9 +38,9 @@ func init() {
|
||||
// SSL Certificate
|
||||
"ssl": map[string]any{
|
||||
// ca.pem
|
||||
"cert": config.Env("APP_SSL_CERT", facades.App().ExecutablePath("storage/ssl.crt")),
|
||||
"cert": config.Env("APP_SSL_CERT", path.Executable("storage/ssl.crt")),
|
||||
// ca.key
|
||||
"key": config.Env("APP_SSL_KEY", facades.App().ExecutablePath("storage/ssl.key")),
|
||||
"key": config.Env("APP_SSL_KEY", path.Executable("storage/ssl.key")),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
+4
-3
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/goravel/framework/support/path"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -26,20 +27,20 @@ func init() {
|
||||
},
|
||||
"single": map[string]any{
|
||||
"driver": "single",
|
||||
"path": "storage/logs/panel.log",
|
||||
"path": path.Executable("storage/logs/panel.log"),
|
||||
"level": "info",
|
||||
"print": true,
|
||||
},
|
||||
"daily": map[string]any{
|
||||
"driver": "daily",
|
||||
"path": "storage/logs/panel.log",
|
||||
"path": path.Executable("storage/logs/panel.log"),
|
||||
"level": "info",
|
||||
"days": 7,
|
||||
"print": true,
|
||||
},
|
||||
"http": map[string]any{
|
||||
"driver": "daily",
|
||||
"path": "storage/logs/http.log",
|
||||
"path": path.Executable("storage/logs/http.log"),
|
||||
"level": "info",
|
||||
"days": 7,
|
||||
"print": false,
|
||||
|
||||
+3
-1
@@ -8,7 +8,9 @@ func init() {
|
||||
config := facades.Config()
|
||||
config.Add("panel", map[string]any{
|
||||
"name": "耗子面板",
|
||||
"version": "v2.2.18",
|
||||
"version": "v2.2.25",
|
||||
"ssl": config.Env("APP_SSL", false),
|
||||
// 安全入口
|
||||
"entrance": config.Env("APP_ENTRANCE", "/"),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/goravel/framework/support/path"
|
||||
)
|
||||
|
||||
func init() {
|
||||
config := facades.Config()
|
||||
config.Add("session", map[string]any{
|
||||
// Default Session Driver
|
||||
//
|
||||
// This option controls the default session "driver" that will be used on
|
||||
// requests. By default, we will use the lightweight file session driver, but you
|
||||
// may specify any of the other wonderful drivers provided here.
|
||||
//
|
||||
// Supported: "file"
|
||||
"driver": config.Env("SESSION_DRIVER", "file"),
|
||||
|
||||
// Session Lifetime
|
||||
//
|
||||
// Here you may specify the number of minutes that you wish the session
|
||||
// to be allowed to remain idle before it expires. If you want them
|
||||
// to immediately expire when the browser is closed, then you may
|
||||
// indicate that via the expire_on_close configuration option.
|
||||
"lifetime": config.Env("SESSION_LIFETIME", 120),
|
||||
|
||||
"expire_on_close": config.Env("SESSION_EXPIRE_ON_CLOSE", false),
|
||||
|
||||
// Session File Location
|
||||
//
|
||||
// When using the file session driver, we need a location where the
|
||||
// session files may be stored. A default has been set for you, but a
|
||||
// different location may be specified. This is only needed for file sessions.
|
||||
"files": path.Executable("storage/framework/sessions"),
|
||||
|
||||
// Session Sweeping Lottery
|
||||
//
|
||||
// Some session drivers must manually sweep their storage location to get
|
||||
// rid of old sessions from storage. Here are the chances out of 100 that
|
||||
// the sweeper will sweep the storage location. The default is 2 out of 100.
|
||||
"lottery": []int{2, 100},
|
||||
|
||||
// Session Cookie Name
|
||||
//
|
||||
// Here you may change the name of the cookie used to identify a session
|
||||
// in the application. The name specified here will get used every time
|
||||
// a new session cookie is created by the framework for every driver.
|
||||
"cookie": config.Env("SESSION_COOKIE", "panel_session"),
|
||||
|
||||
// Session Cookie Path
|
||||
//
|
||||
// The session cookie path determines the path for which the cookie will
|
||||
// be regarded as available.Typically, this will be the root path of
|
||||
// your application, but you are free to change this when necessary.
|
||||
"path": config.Env("SESSION_PATH", "/"),
|
||||
|
||||
// Session Cookie Domain
|
||||
//
|
||||
// Here you may change the domain of the cookie used to identify a session
|
||||
// in your application.This will determine which domains the cookie is
|
||||
// available to in your application.A sensible default has been set.
|
||||
"domain": config.Env("SESSION_DOMAIN", ""),
|
||||
|
||||
// HTTPS Only Cookies
|
||||
//
|
||||
// By setting this option to true, session cookies will only be sent back
|
||||
// to the server if the browser has an HTTPS connection. This will keep
|
||||
// the cookie from being sent to you if it cannot be done securely.
|
||||
"secure": config.Env("SESSION_SECURE", false),
|
||||
|
||||
// HTTP Access Only
|
||||
//
|
||||
// Setting this to true will prevent JavaScript from accessing the value of
|
||||
// the cookie, and the cookie will only be accessible through the HTTP protocol.
|
||||
"http_only": config.Env("SESSION_HTTP_ONLY", true),
|
||||
|
||||
// Same-Site Cookies
|
||||
//
|
||||
// This option determines how your cookies behave when cross-site requests
|
||||
// take place, and can be used to mitigate CSRF attacks.By default, we
|
||||
// will set this value to "lax" since this is a secure default value.
|
||||
"same_site": config.Env("SESSION_SAME_SITE", "lax"),
|
||||
})
|
||||
}
|
||||
+25
-3
@@ -3235,7 +3235,6 @@ const docTemplate = `{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "获取当前登录用户信息",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -3255,7 +3254,6 @@ const docTemplate = `{
|
||||
},
|
||||
"/panel/user/login": {
|
||||
"post": {
|
||||
"description": "通过用户名和密码获取访问令牌",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -3299,6 +3297,30 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/panel/user/logout": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"用户鉴权"
|
||||
],
|
||||
"summary": "登出",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/panel/website/backupList": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -5158,7 +5180,7 @@ const docTemplate = `{
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "DNS 提供商 (dnspod, aliyun, cloudflare)",
|
||||
"description": "DNS 提供商 (dnspod, tencent, aliyun, cloudflare)",
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
|
||||
+25
-3
@@ -3228,7 +3228,6 @@
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "获取当前登录用户信息",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -3248,7 +3247,6 @@
|
||||
},
|
||||
"/panel/user/login": {
|
||||
"post": {
|
||||
"description": "通过用户名和密码获取访问令牌",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -3292,6 +3290,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/panel/user/logout": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"用户鉴权"
|
||||
],
|
||||
"summary": "登出",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/panel/website/backupList": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -5151,7 +5173,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "DNS 提供商 (dnspod, aliyun, cloudflare)",
|
||||
"description": "DNS 提供商 (dnspod, tencent, aliyun, cloudflare)",
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
|
||||
+15
-3
@@ -148,7 +148,7 @@ definitions:
|
||||
description: 备注名称
|
||||
type: string
|
||||
type:
|
||||
description: DNS 提供商 (dnspod, aliyun, cloudflare)
|
||||
description: DNS 提供商 (dnspod, tencent, aliyun, cloudflare)
|
||||
type: string
|
||||
updated_at:
|
||||
$ref: '#/definitions/github_com_goravel_framework_support_carbon.DateTime'
|
||||
@@ -2645,7 +2645,6 @@ paths:
|
||||
- 系统
|
||||
/panel/user/info:
|
||||
get:
|
||||
description: 获取当前登录用户信息
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -2662,7 +2661,6 @@ paths:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 通过用户名和密码获取访问令牌
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
@@ -2688,6 +2686,20 @@ paths:
|
||||
summary: 登录
|
||||
tags:
|
||||
- 用户鉴权
|
||||
/panel/user/logout:
|
||||
post:
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 登出
|
||||
tags:
|
||||
- 用户鉴权
|
||||
/panel/website/backupList:
|
||||
get:
|
||||
parameters:
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package embed
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed frontend/*
|
||||
var PublicFS embed.FS
|
||||
|
||||
//go:embed website/*
|
||||
var WebsiteFS embed.FS
|
||||
@@ -0,0 +1 @@
|
||||
*
|
||||
@@ -0,0 +1,55 @@
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>404 Not Found</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #f9f9f9;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 2em auto;
|
||||
background-color: #ffffff;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
h1 {
|
||||
font-size: 2.5em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
border-bottom: 2px solid #ddd;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
p {
|
||||
color: #555;
|
||||
line-height: 1.8;
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #007bff;
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.container {
|
||||
padding: 15px;
|
||||
margin: 2em 15px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>404 Not Found</h1>
|
||||
<p>由 <a target="_blank" href="https://panel.haozi.net">耗子面板</a> 强力驱动</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>耗子面板</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #f9f9f9;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 2em auto;
|
||||
background-color: #ffffff;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
h1 {
|
||||
font-size: 2.5em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
border-bottom: 2px solid #ddd;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
p {
|
||||
color: #555;
|
||||
line-height: 1.8;
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #007bff;
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.container {
|
||||
padding: 15px;
|
||||
margin: 2em 15px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>耗子面板</h1>
|
||||
<p>这是耗子面板的网站默认页面!</p>
|
||||
<p>当您看到此页面,说明您的网站已创建成功。</p>
|
||||
<p>由 <a target="_blank" href="https://panel.haozi.net">耗子面板</a> 强力驱动</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,20 +3,23 @@ module github.com/TheTNB/panel
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/docker/docker v27.0.2+incompatible
|
||||
github.com/docker/docker v27.0.3+incompatible
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/gin-contrib/static v1.1.2
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.1.2
|
||||
github.com/go-resty/resty/v2 v2.13.1
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
github.com/gookit/validate v1.5.2
|
||||
github.com/goravel/framework v1.14.1-0.20240627172353-91c3c46cf333
|
||||
github.com/goravel/gin v1.2.1
|
||||
github.com/goravel/framework v1.14.1-0.20240712145335-f1b118b0ca43
|
||||
github.com/goravel/gin v1.2.3-0.20240712065957-fe9e02c7125d
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/hashicorp/go-version v1.7.0
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/libdns/alidns v1.0.3
|
||||
github.com/libdns/cloudflare v0.1.1
|
||||
github.com/libdns/dnspod v0.0.3
|
||||
github.com/libdns/libdns v0.2.2
|
||||
github.com/libdns/tencentcloud v1.0.0
|
||||
github.com/mholt/acmez/v2 v2.0.1
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
@@ -25,9 +28,9 @@ require (
|
||||
github.com/swaggo/http-swagger/v2 v2.0.2
|
||||
github.com/swaggo/swag v1.16.3
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.24.0
|
||||
golang.org/x/net v0.26.0
|
||||
gorm.io/gorm v1.25.10
|
||||
golang.org/x/crypto v0.25.0
|
||||
golang.org/x/net v0.27.0
|
||||
gorm.io/gorm v1.25.11
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -52,13 +55,13 @@ require (
|
||||
github.com/catppuccin/go v0.2.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/charmbracelet/bubbles v0.18.0 // indirect
|
||||
github.com/charmbracelet/bubbletea v0.26.3 // indirect
|
||||
github.com/charmbracelet/huh v0.4.2 // indirect
|
||||
github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0 // indirect
|
||||
github.com/charmbracelet/lipgloss v0.11.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a // indirect
|
||||
github.com/charmbracelet/x/input v0.1.1 // indirect
|
||||
github.com/charmbracelet/bubbletea v0.26.4 // indirect
|
||||
github.com/charmbracelet/huh v0.5.1 // indirect
|
||||
github.com/charmbracelet/huh/spinner v0.0.0-20240711191530-dbf5a5ac0510 // indirect
|
||||
github.com/charmbracelet/lipgloss v0.12.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.1.3 // indirect
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240617190524-788ec55faed1 // indirect
|
||||
github.com/charmbracelet/x/input v0.1.2 // indirect
|
||||
github.com/charmbracelet/x/term v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/windows v0.1.2 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
@@ -106,7 +109,6 @@ require (
|
||||
github.com/gookit/filter v1.2.1 // indirect
|
||||
github.com/gookit/goutil v0.6.15 // indirect
|
||||
github.com/goravel/file-rotatelogs/v2 v2.4.2 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
@@ -130,6 +132,7 @@ require (
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/microsoft/go-mssqldb v1.6.0 // indirect
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
@@ -141,7 +144,6 @@ require (
|
||||
github.com/nwaples/rardecode v1.1.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.16 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
@@ -157,7 +159,7 @@ require (
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/samber/do/v2 v2.0.0-beta.7 // indirect
|
||||
github.com/samber/go-type-to-string v1.7.0 // indirect
|
||||
github.com/samber/go-type-to-string v1.4.0 // indirect
|
||||
github.com/savioxavier/termlink v1.3.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
@@ -167,12 +169,13 @@ require (
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/swaggo/files/v2 v2.0.0 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.597 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/ulikunitz/xz v0.5.11 // indirect
|
||||
github.com/unrolled/secure v1.14.0 // indirect
|
||||
github.com/unrolled/secure v1.15.0 // indirect
|
||||
github.com/urfave/cli/v2 v2.27.2 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
@@ -187,15 +190,15 @@ require (
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 // indirect
|
||||
golang.org/x/mod v0.19.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/term v0.21.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/term v0.22.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
|
||||
google.golang.org/grpc v1.64.0 // indirect
|
||||
golang.org/x/tools v0.23.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
|
||||
google.golang.org/grpc v1.65.0 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
@@ -209,3 +212,5 @@ require (
|
||||
modernc.org/memory v1.7.2 // indirect
|
||||
modernc.org/sqlite v1.28.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/mholt/archiver/v3 => github.com/anchore/archiver/v3 v3.5.2
|
||||
|
||||
@@ -61,6 +61,8 @@ github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi
|
||||
github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/anchore/archiver/v3 v3.5.2 h1:Bjemm2NzuRhmHy3m0lRe5tNoClB9A4zYyDV58PaB6aA=
|
||||
github.com/anchore/archiver/v3 v3.5.2/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
@@ -70,7 +72,6 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4=
|
||||
github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs=
|
||||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||
@@ -86,22 +87,22 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0=
|
||||
github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw=
|
||||
github.com/charmbracelet/bubbletea v0.26.3 h1:iXyGvI+FfOWqkB2V07m1DF3xxQijxjY2j8PqiXYqasg=
|
||||
github.com/charmbracelet/bubbletea v0.26.3/go.mod h1:bpZHfDHTYJC5g+FBK+ptJRCQotRC+Dhh3AoMxa/2+3Q=
|
||||
github.com/charmbracelet/huh v0.4.2 h1:5wLkwrA58XDAfEZsJzNQlfJ+K8N9+wYwvR5FOM7jXFM=
|
||||
github.com/charmbracelet/huh v0.4.2/go.mod h1:g9OXBgtY3zRV4ahnVih9bZE+1yGYN+y2C9Q6L2P+WM0=
|
||||
github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0 h1:79JTuYRirtyCn9ac6rzPt5AQKtBDFc1gKxpw0wBrI+Y=
|
||||
github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0/go.mod h1:Zxt9FH6togK9kY71pRJGtmyNkJ1eIWdK1gRaXrS/FKA=
|
||||
github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g=
|
||||
github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8=
|
||||
github.com/charmbracelet/x/ansi v0.1.1 h1:CGAduulr6egay/YVbGc8Hsu8deMg1xZ/bkaXTPi1JDk=
|
||||
github.com/charmbracelet/x/ansi v0.1.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a h1:lOpqe2UvPmlln41DGoii7wlSZ/q8qGIon5JJ8Biu46I=
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
|
||||
github.com/charmbracelet/bubbletea v0.26.4 h1:2gDkkzLZaTjMl/dQBpNVtnvcCxsh/FCkimep7FC9c40=
|
||||
github.com/charmbracelet/bubbletea v0.26.4/go.mod h1:P+r+RRA5qtI1DOHNFn0otoNwB4rn+zNAzSj/EXz6xU0=
|
||||
github.com/charmbracelet/huh v0.5.1 h1:t5j6g9sMjAE2a9AQuc4lNL7pf/0X4WdHiiMGkL8v/aM=
|
||||
github.com/charmbracelet/huh v0.5.1/go.mod h1:gs7b2brpzXkY0PBWUqJrlzvOowTCL0vNAR6OTItc+kA=
|
||||
github.com/charmbracelet/huh/spinner v0.0.0-20240711191530-dbf5a5ac0510 h1:+mSQLejKRzoK3bzK6ZXuA8fwrZMd3GthHn5/Gj9BGo4=
|
||||
github.com/charmbracelet/huh/spinner v0.0.0-20240711191530-dbf5a5ac0510/go.mod h1:CrXBZnOWs3zpyppOZZS7lu2CpLq2jx6U5chL/frRG/E=
|
||||
github.com/charmbracelet/lipgloss v0.12.0 h1:k2RgmrgUjrWWu9FaMERoYK1iiPiwg+SSqGYu9t8/k4Y=
|
||||
github.com/charmbracelet/lipgloss v0.12.0/go.mod h1:beLlcmkF7MWA+5UrKKIRo/VJ21xGXr7YJ9miWfdMRIU=
|
||||
github.com/charmbracelet/x/ansi v0.1.3 h1:RBh/eleNWML5R524mjUF0yVRePTwqN9tPtV+DPgO5Lw=
|
||||
github.com/charmbracelet/x/ansi v0.1.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240617190524-788ec55faed1 h1:VZIQzjwFE0EamzG2v8HfemeisB8X02Tl0BZBnJ0PeU8=
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240617190524-788ec55faed1/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
|
||||
github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a h1:k/s6UoOSVynWiw7PlclyGO2VdVs5ZLbMIHiGp4shFZE=
|
||||
github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a/go.mod h1:YBotIGhfoWhHDlnUpJMkjebGV2pdGRCn1Y4/Nk/vVcU=
|
||||
github.com/charmbracelet/x/input v0.1.1 h1:YDOJaTUKCqtGnq9PHzx3pkkl4pXDOANUHmhH3DqMtM4=
|
||||
github.com/charmbracelet/x/input v0.1.1/go.mod h1:jvdTVUnNWj/RD6hjC4FsoB0SeZCJ2ZBkiuFP9zXvZI0=
|
||||
github.com/charmbracelet/x/input v0.1.2 h1:QJAZr33eOhDowkkEQ24rsJy4Llxlm+fRDf/cQrmqJa0=
|
||||
github.com/charmbracelet/x/input v0.1.2/go.mod h1:LGBim0maUY4Pitjn/4fHnuXb4KirU3DODsyuHuXdOyA=
|
||||
github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI=
|
||||
github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw=
|
||||
github.com/charmbracelet/x/windows v0.1.2 h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg=
|
||||
@@ -134,8 +135,8 @@ github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/docker/docker v27.0.2+incompatible h1:mNhCtgXNV1fIRns102grG7rdzIsGGCq1OlOD0KunZos=
|
||||
github.com/docker/docker v27.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v27.0.3+incompatible h1:aBGI9TeQ4MPlhquTQKq9XbK79rKFVwXNUAYz9aXyEBE=
|
||||
github.com/docker/docker v27.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
@@ -164,6 +165,8 @@ github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSe
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-contrib/static v1.1.2 h1:c3kT4bFkUJn2aoRU3s6XnMjJT8J6nNWJkR0NglqmlZ4=
|
||||
github.com/gin-contrib/static v1.1.2/go.mod h1:Fw90ozjHCmZBWbgrsqrDvO28YbhKEKzKp8GixhR4yLw=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
|
||||
@@ -172,8 +175,6 @@ github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GM
|
||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.1.2 h1:F/d1hpHbRAvKezziV2CC5KUE82cVe9zTgHSBoOOZ4CY=
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.1.2/go.mod h1:9nHVX6z3FCMCQPA7PThGcA55t22yKQfK/Dnsf5i7hUo=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
@@ -205,7 +206,6 @@ github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
@@ -276,16 +276,14 @@ github.com/gookit/validate v1.5.2 h1:i5I2OQ7WYHFRPRATGu9QarR9snnNHydvwSuHXaRWAV0
|
||||
github.com/gookit/validate v1.5.2/go.mod h1:yuPy2WwDlwGRa06fFJ5XIO8QEwhRnTC2LmxmBa5SE14=
|
||||
github.com/goravel/file-rotatelogs/v2 v2.4.2 h1:g68AzbePXcm0V2CpUMc9j4qVzcDn7+7aoWSjZ51C0m4=
|
||||
github.com/goravel/file-rotatelogs/v2 v2.4.2/go.mod h1:23VuSW8cBS4ax5cmbV+5AaiLpq25b8UJ96IhbAkdo8I=
|
||||
github.com/goravel/framework v1.14.1-0.20240627172353-91c3c46cf333 h1:hOj1S1TQQ/19ng0JzpbTfscB128L5E5dIcx/mU1zofc=
|
||||
github.com/goravel/framework v1.14.1-0.20240627172353-91c3c46cf333/go.mod h1:8Fz0+JHyqwnOLy8rFkFWPQXv0Bkk3JEB43OV/Wx7xCA=
|
||||
github.com/goravel/gin v1.2.1 h1:lnQX3NKUEaSx8x7AAJpoeVkXgi+MVQ9FXy4QywHQElo=
|
||||
github.com/goravel/gin v1.2.1/go.mod h1:Qt3NJysg/eoxXL4y/swwFUcfcIT7XG+xb0rWChweZfY=
|
||||
github.com/goravel/framework v1.14.1-0.20240712145335-f1b118b0ca43 h1:v59SXxwRQdZo1ebLE7zrThesp8CY3prA7eka9msJZY4=
|
||||
github.com/goravel/framework v1.14.1-0.20240712145335-f1b118b0ca43/go.mod h1:jN5WkMgoGLHaC3yl9MRnzxnyfCsA0OJV3giBjzYRnkk=
|
||||
github.com/goravel/gin v1.2.3-0.20240712065957-fe9e02c7125d h1:ABY2IKc+t28SWkvGVbXriG+HiFa5o5wvBn4jTxhGpD8=
|
||||
github.com/goravel/gin v1.2.3-0.20240712065957-fe9e02c7125d/go.mod h1:QaA/LN6JTinQzYQaF0KJMZs71Max3CquGQZp0yxm+Bc=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
@@ -295,6 +293,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
@@ -335,7 +335,6 @@ github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQ
|
||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
@@ -361,6 +360,8 @@ github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSO
|
||||
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||
github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
|
||||
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||
github.com/libdns/tencentcloud v1.0.0 h1:u4LXnYu/lu/9P5W+MCVPeSDnwI+6w+DxYhQ1wSnQOuU=
|
||||
github.com/libdns/tencentcloud v1.0.0/go.mod h1:NlCgPumzUsZWSOo1+Q/Hfh8G6TNRAaTUeWQdg6LbtUI=
|
||||
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
|
||||
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
@@ -378,10 +379,10 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mholt/acmez/v2 v2.0.1 h1:3/3N0u1pLjMK4sNEAFSI+bcvzbPhRpY383sy1kLHJ6k=
|
||||
github.com/mholt/acmez/v2 v2.0.1/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGoe67e1U=
|
||||
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||
github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc=
|
||||
github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
@@ -411,9 +412,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
@@ -421,7 +419,6 @@ github.com/pierrec/lz4/v4 v4.1.16 h1:kQPfno+wyx6C5572ABwV+Uo3pDFzQ7yhyGchSyRda0c
|
||||
github.com/pierrec/lz4/v4 v4.1.16/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -461,15 +458,14 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/samber/do/v2 v2.0.0-beta.7 h1:tmdLOVSCbTA6uGWLU5poi/nZvMRh5QxXFJ9vHytU+Jk=
|
||||
github.com/samber/do/v2 v2.0.0-beta.7/go.mod h1:+LpV3vu4L81Q1JMZNSkMvSkW9lt4e5eJoXoZHkeBS4c=
|
||||
github.com/samber/go-type-to-string v1.7.0 h1:FiSstaAikHMUSLt5bhVlsvCnD7bbQzC8L0UkkGS3Bj8=
|
||||
github.com/samber/go-type-to-string v1.7.0/go.mod h1:jpU77vIDoIxkahknKDoEx9C8bQ1ADnh2sotZ8I4QqBU=
|
||||
github.com/samber/go-type-to-string v1.4.0 h1:KXphToZgiFdnJQxryU25brhlh/CqY/cwJVeX2rfmow0=
|
||||
github.com/samber/go-type-to-string v1.4.0/go.mod h1:jpU77vIDoIxkahknKDoEx9C8bQ1ADnh2sotZ8I4QqBU=
|
||||
github.com/savioxavier/termlink v1.3.0 h1:3Gl4FzQjUyiHzmoEDfmWEhgIwDiJY4poOQHP+k8ReA4=
|
||||
github.com/savioxavier/termlink v1.3.0/go.mod h1:5T5ePUlWbxCHIwyF8/Ez1qufOoGM89RCg9NvG+3G3gc=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
@@ -483,12 +479,10 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
@@ -509,6 +503,8 @@ github.com/swaggo/http-swagger/v2 v2.0.2 h1:FKCdLsl+sFCx60KFsyM0rDarwiUSZ8DqbfSy
|
||||
github.com/swaggo/http-swagger/v2 v2.0.2/go.mod h1:r7/GBkAWIfK6E/OLnE8fXnviHiDeAHmgIyooa4xm3AQ=
|
||||
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
|
||||
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.597 h1:C0GHdLTfikLVoEzfhgPfrZ7LwlG0xiCmk6iwNKE+xs0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.597/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
@@ -521,8 +517,8 @@ github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oW
|
||||
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
||||
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/unrolled/secure v1.14.0 h1:u9vJTU/pR4Bny0ntLUMxdfLtmIRGvQf2sEFuA0TG9AE=
|
||||
github.com/unrolled/secure v1.14.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
|
||||
github.com/unrolled/secure v1.15.0 h1:q7x+pdp8jAHnbzxu6UheP8fRlG/rwYTb8TPuQ3rn9Og=
|
||||
github.com/unrolled/secure v1.15.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
|
||||
github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
|
||||
github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||
@@ -559,16 +555,12 @@ go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v0.11.0 h1:cLDgIBTf4lLOlztkhzAEdQsJ4Lj+i5Wc9k6Nn0K1VyU=
|
||||
go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
@@ -587,23 +579,22 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w=
|
||||
golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -627,8 +618,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -646,7 +637,6 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -658,7 +648,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -672,8 +661,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -686,8 +675,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
@@ -707,7 +696,6 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
@@ -715,8 +703,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -725,25 +713,23 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
|
||||
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
|
||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -759,7 +745,6 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
@@ -784,8 +769,8 @@ gorm.io/driver/sqlserver v1.5.3 h1:rjupPS4PVw+rjJkfvr8jn2lJ8BMhT4UW5FwuJY0P3Z0=
|
||||
gorm.io/driver/sqlserver v1.5.3/go.mod h1:B+CZ0/7oFJ6tAlefsKoyxdgDCXJKSgwS2bMOQZT0I00=
|
||||
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
|
||||
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
|
||||
gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
gorm.io/plugin/dbresolver v1.5.2 h1:Iut7lW4TXNoVs++I+ra3zxjSxTRj4ocIeFEVp4lLhII=
|
||||
gorm.io/plugin/dbresolver v1.5.2/go.mod h1:jPh59GOQbO7v7v28ZKZPd45tr+u3vyT+8tHdfdfOWcU=
|
||||
gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
|
||||
|
||||
@@ -165,7 +165,7 @@ func (s *BackupImpl) MysqlBackup(database string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := shell.Execf("/www/server/mysql/bin/mysqldump -uroot " + database + " > " + backupPath + "/" + backupFile); err != nil {
|
||||
if _, err := shell.Execf("mysqldump -uroot " + database + " > " + backupPath + "/" + backupFile); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := shell.Execf("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile); err != nil {
|
||||
@@ -219,7 +219,7 @@ func (s *BackupImpl) MysqlRestore(database string, backupFile string) error {
|
||||
return errors.New("无法找到备份文件")
|
||||
}
|
||||
|
||||
if _, err = shell.Execf("/www/server/mysql/bin/mysql -uroot " + database + " < " + filepath.Join(tempDir, backupFile)); err != nil {
|
||||
if _, err = shell.Execf("mysql -uroot " + database + " < " + filepath.Join(tempDir, backupFile)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package services
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/goravel/framework/database/orm"
|
||||
"github.com/goravel/framework/facades"
|
||||
|
||||
"github.com/TheTNB/panel/app/jobs"
|
||||
@@ -20,9 +19,7 @@ func NewTaskImpl() *TaskImpl {
|
||||
}
|
||||
|
||||
func (r *TaskImpl) Process(taskID uint) error {
|
||||
if err := r.markAsRunning(taskID); err != nil {
|
||||
return err
|
||||
}
|
||||
taskMap.Store(taskID, true)
|
||||
return facades.Queue().Job(&jobs.ProcessTask{}, []any{taskID}).Dispatch()
|
||||
}
|
||||
|
||||
@@ -43,16 +40,3 @@ func (r *TaskImpl) DispatchWaiting() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *TaskImpl) markAsRunning(taskID uint) error {
|
||||
task := models.Task{
|
||||
Model: orm.Model{ID: taskID},
|
||||
Status: models.TaskStatusRunning,
|
||||
}
|
||||
if _, err := facades.Orm().Query().Where("id", taskID).Update(&task); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
taskMap.Store(taskID, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
+86
-181
@@ -4,6 +4,7 @@ package services
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TheTNB/panel/embed"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"slices"
|
||||
@@ -47,14 +48,13 @@ func (r *WebsiteImpl) List(page, limit int) (int64, []models.Website, error) {
|
||||
}
|
||||
|
||||
// Add 添加网站
|
||||
func (r *WebsiteImpl) Add(website types.WebsiteAdd) (models.Website, error) {
|
||||
func (r *WebsiteImpl) Add(website requests.Add) (models.Website, error) {
|
||||
w := models.Website{
|
||||
Name: website.Name,
|
||||
Status: website.Status,
|
||||
Status: true,
|
||||
Path: website.Path,
|
||||
Php: cast.ToInt(website.Php),
|
||||
Ssl: website.Ssl,
|
||||
Remark: website.Remark,
|
||||
PHP: cast.ToInt(website.PHP),
|
||||
SSL: false,
|
||||
}
|
||||
if err := facades.Orm().Query().Create(&w); err != nil {
|
||||
return models.Website{}, err
|
||||
@@ -64,122 +64,19 @@ func (r *WebsiteImpl) Add(website types.WebsiteAdd) (models.Website, error) {
|
||||
return models.Website{}, err
|
||||
}
|
||||
|
||||
index := `<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>耗子面板</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #f9f9f9;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 2em auto;
|
||||
background-color: #ffffff;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
h1 {
|
||||
font-size: 2.5em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
border-bottom: 2px solid #ddd;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
p {
|
||||
color: #555;
|
||||
line-height: 1.8;
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.container {
|
||||
padding: 15px;
|
||||
margin: 2em 15px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>耗子面板</h1>
|
||||
<p>这是耗子面板的网站默认页面!</p>
|
||||
<p>当您看到此页面,说明您的网站已创建成功。</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
`
|
||||
if err := io.Write(website.Path+"/index.html", index, 0644); err != nil {
|
||||
index, err := embed.WebsiteFS.ReadFile(filepath.Join("website", "index.html"))
|
||||
if err != nil {
|
||||
return models.Website{}, fmt.Errorf("获取index模板文件失败: %w", err)
|
||||
}
|
||||
if err = io.Write(website.Path+"/index.html", string(index), 0644); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
|
||||
notFound := `<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>404 Not Found</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #f9f9f9;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 2em auto;
|
||||
background-color: #ffffff;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
h1 {
|
||||
font-size: 2.5em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
border-bottom: 2px solid #ddd;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
p {
|
||||
color: #555;
|
||||
line-height: 1.8;
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #007bff;
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.container {
|
||||
padding: 15px;
|
||||
margin: 2em 15px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>404 Not Found</h1>
|
||||
<p>由 <a target="_blank" href="https://github.com/TheTNB/panel">耗子面板</a> 强力驱动</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
`
|
||||
if err := io.Write(website.Path+"/404.html", notFound, 0644); err != nil {
|
||||
notFound, err := embed.WebsiteFS.ReadFile(filepath.Join("website", "404.html"))
|
||||
if err != nil {
|
||||
return models.Website{}, fmt.Errorf("获取404模板文件失败: %w", err)
|
||||
}
|
||||
if err = io.Write(website.Path+"/404.html", string(notFound), 0644); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
|
||||
@@ -265,58 +162,58 @@ server
|
||||
access_log /www/wwwlogs/%s.log;
|
||||
error_log /www/wwwlogs/%s.log;
|
||||
}
|
||||
`, portList, domainList, website.Path, website.Php, website.Name, website.Name, website.Name, website.Name)
|
||||
`, portList, domainList, website.Path, website.PHP, website.Name, website.Name, website.Name, website.Name)
|
||||
|
||||
if err := io.Write("/www/server/vhost/"+website.Name+".conf", nginxConf, 0644); err != nil {
|
||||
if err = io.Write("/www/server/vhost/"+website.Name+".conf", nginxConf, 0644); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
if err := io.Write("/www/server/vhost/rewrite/"+website.Name+".conf", "", 0644); err != nil {
|
||||
if err = io.Write("/www/server/vhost/rewrite/"+website.Name+".conf", "", 0644); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
if err := io.Write("/www/server/vhost/acme/"+website.Name+".conf", "", 0644); err != nil {
|
||||
if err = io.Write("/www/server/vhost/acme/"+website.Name+".conf", "", 0644); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
if err := io.Write("/www/server/vhost/ssl/"+website.Name+".pem", "", 0644); err != nil {
|
||||
if err = io.Write("/www/server/vhost/ssl/"+website.Name+".pem", "", 0644); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
if err := io.Write("/www/server/vhost/ssl/"+website.Name+".key", "", 0644); err != nil {
|
||||
if err = io.Write("/www/server/vhost/ssl/"+website.Name+".key", "", 0644); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
|
||||
if err := io.Chmod(website.Path, 0755); err != nil {
|
||||
if err = io.Chmod(website.Path, 0755); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
if err := io.Chown(website.Path, "www", "www"); err != nil {
|
||||
if err = io.Chown(website.Path, "www", "www"); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
|
||||
if err := systemctl.Reload("openresty"); err != nil {
|
||||
if err = systemctl.Reload("openresty"); err != nil {
|
||||
_, err = shell.Execf("openresty -t")
|
||||
return models.Website{}, err
|
||||
}
|
||||
|
||||
rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
if website.Db && website.DbType == "mysql" {
|
||||
if website.DB && website.DBType == "mysql" {
|
||||
mysql, err := db.NewMySQL("root", rootPassword, "/tmp/mysql.sock", "unix")
|
||||
if err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
if err = mysql.DatabaseCreate(website.DbName); err != nil {
|
||||
if err = mysql.DatabaseCreate(website.DBName); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
if err = mysql.UserCreate(website.DbUser, website.DbPassword); err != nil {
|
||||
if err = mysql.UserCreate(website.DBUser, website.DBPassword); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
if err = mysql.PrivilegesGrant(website.DbUser, website.DbName); err != nil {
|
||||
if err = mysql.PrivilegesGrant(website.DBUser, website.DBName); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
}
|
||||
if website.Db && website.DbType == "postgresql" {
|
||||
_, _ = shell.Execf(`echo "CREATE DATABASE '%s';" | su - postgres -c "psql"`, website.DbName)
|
||||
_, _ = shell.Execf(`echo "CREATE USER '%s' WITH PASSWORD '%s';" | su - postgres -c "psql"`, website.DbUser, website.DbPassword)
|
||||
_, _ = shell.Execf(`echo "ALTER DATABASE '%s' OWNER TO '%s';" | su - postgres -c "psql"`, website.DbName, website.DbUser)
|
||||
_, _ = shell.Execf(`echo "GRANT ALL PRIVILEGES ON DATABASE '%s' TO '%s';" | su - postgres -c "psql"`, website.DbName, website.DbUser)
|
||||
userConfig := "host " + website.DbName + " " + website.DbUser + " 127.0.0.1/32 scram-sha-256"
|
||||
if website.DB && website.DBType == "postgresql" {
|
||||
_, _ = shell.Execf(`echo "CREATE DATABASE '%s';" | su - postgres -c "psql"`, website.DBName)
|
||||
_, _ = shell.Execf(`echo "CREATE USER '%s' WITH PASSWORD '%s';" | su - postgres -c "psql"`, website.DBUser, website.DBPassword)
|
||||
_, _ = shell.Execf(`echo "ALTER DATABASE '%s' OWNER TO '%s';" | su - postgres -c "psql"`, website.DBName, website.DBUser)
|
||||
_, _ = shell.Execf(`echo "GRANT ALL PRIVILEGES ON DATABASE '%s' TO '%s';" | su - postgres -c "psql"`, website.DBName, website.DBUser)
|
||||
userConfig := "host " + website.DBName + " " + website.DBUser + " 127.0.0.1/32 scram-sha-256"
|
||||
_, _ = shell.Execf(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`)
|
||||
_ = systemctl.Reload("postgresql")
|
||||
}
|
||||
@@ -381,9 +278,11 @@ func (r *WebsiteImpl) SaveConfig(config requests.SaveConfig) error {
|
||||
for _, port := range ports {
|
||||
https := ""
|
||||
quic := false
|
||||
if slices.Contains(config.TLSPorts, port) {
|
||||
if slices.Contains(config.SSLPorts, port) {
|
||||
https = " ssl"
|
||||
quic = true
|
||||
if slices.Contains(config.QUICPorts, port) {
|
||||
quic = true
|
||||
}
|
||||
}
|
||||
|
||||
portConf.WriteString(fmt.Sprintf(" listen %d%s;\n", port, https))
|
||||
@@ -431,12 +330,12 @@ func (r *WebsiteImpl) SaveConfig(config requests.SaveConfig) error {
|
||||
root += "/"
|
||||
}
|
||||
if config.OpenBasedir {
|
||||
if err := io.Write(root+".user.ini", "open_basedir="+path+":/tmp/", 0644); err != nil {
|
||||
if err = io.Write(root+".user.ini", "open_basedir="+path+":/tmp/", 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if io.Exists(root + ".user.ini") {
|
||||
if err := io.Remove(root + ".user.ini"); err != nil {
|
||||
if err = io.Remove(root + ".user.ini"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -465,20 +364,20 @@ func (r *WebsiteImpl) SaveConfig(config requests.SaveConfig) error {
|
||||
raw = strings.Replace(raw, "# waf标记位开始", wafConfig, -1)
|
||||
|
||||
// SSL
|
||||
ssl := config.Ssl
|
||||
website.Ssl = ssl
|
||||
ssl := config.SSL
|
||||
website.SSL = ssl
|
||||
if ssl {
|
||||
if _, err = cert.ParseCert(config.SslCertificate); err != nil {
|
||||
if _, err = cert.ParseCert(config.SSLCertificate); err != nil {
|
||||
return errors.New("TLS证书格式错误")
|
||||
}
|
||||
if _, err = cert.ParseKey(config.SslCertificateKey); err != nil {
|
||||
if _, err = cert.ParseKey(config.SSLCertificateKey); err != nil {
|
||||
return errors.New("TLS私钥格式错误")
|
||||
}
|
||||
}
|
||||
if err = io.Write("/www/server/vhost/ssl/"+website.Name+".pem", config.SslCertificate, 0644); err != nil {
|
||||
if err = io.Write("/www/server/vhost/ssl/"+website.Name+".pem", config.SSLCertificate, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = io.Write("/www/server/vhost/ssl/"+website.Name+".key", config.SslCertificateKey, 0644); err != nil {
|
||||
if err = io.Write("/www/server/vhost/ssl/"+website.Name+".key", config.SSLCertificateKey, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
if ssl {
|
||||
@@ -492,7 +391,7 @@ func (r *WebsiteImpl) SaveConfig(config requests.SaveConfig) error {
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_early_data on;
|
||||
`
|
||||
if config.HttpRedirect {
|
||||
if config.HTTPRedirect {
|
||||
sslConfig += `# http重定向标记位开始
|
||||
if ($server_port !~ 443){
|
||||
return 301 https://$host$request_uri;
|
||||
@@ -501,10 +400,17 @@ func (r *WebsiteImpl) SaveConfig(config requests.SaveConfig) error {
|
||||
# http重定向标记位结束
|
||||
`
|
||||
}
|
||||
if config.Hsts {
|
||||
if config.HSTS {
|
||||
sslConfig += `# hsts标记位开始
|
||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||
# hsts标记位结束
|
||||
`
|
||||
}
|
||||
if config.OCSP {
|
||||
sslConfig += `# ocsp标记位开始
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
# ocsp标记位结束
|
||||
`
|
||||
}
|
||||
sslConfigOld := str.Cut(raw, "# ssl标记位开始", "# ssl标记位结束")
|
||||
@@ -519,25 +425,25 @@ func (r *WebsiteImpl) SaveConfig(config requests.SaveConfig) error {
|
||||
}
|
||||
}
|
||||
|
||||
if website.Php != config.Php {
|
||||
website.Php = config.Php
|
||||
if website.PHP != config.PHP {
|
||||
website.PHP = config.PHP
|
||||
phpConfigOld := str.Cut(raw, "# php标记位开始", "# php标记位结束")
|
||||
phpConfig := `
|
||||
include enable-php-` + strconv.Itoa(website.Php) + `.conf;
|
||||
include enable-php-` + strconv.Itoa(website.PHP) + `.conf;
|
||||
`
|
||||
if len(strings.TrimSpace(phpConfigOld)) != 0 {
|
||||
raw = strings.Replace(raw, phpConfigOld, phpConfig, -1)
|
||||
}
|
||||
}
|
||||
|
||||
if err := facades.Orm().Query().Save(&website); err != nil {
|
||||
if err = facades.Orm().Query().Save(&website); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := io.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644); err != nil {
|
||||
if err = io.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := io.Write("/www/server/vhost/rewrite/"+website.Name+".conf", config.Rewrite, 0644); err != nil {
|
||||
if err = io.Write("/www/server/vhost/rewrite/"+website.Name+".conf", config.Rewrite, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -608,12 +514,12 @@ func (r *WebsiteImpl) GetConfig(id uint) (types.WebsiteSetting, error) {
|
||||
var setting types.WebsiteSetting
|
||||
setting.Name = website.Name
|
||||
setting.Path = website.Path
|
||||
setting.Ssl = website.Ssl
|
||||
setting.Php = strconv.Itoa(website.Php)
|
||||
setting.SSL = website.SSL
|
||||
setting.PHP = strconv.Itoa(website.PHP)
|
||||
setting.Raw = config
|
||||
|
||||
ports := str.Cut(config, "# port标记位开始", "# port标记位结束")
|
||||
matches := regexp.MustCompile(`listen\s+([^;]*);?`).FindAllStringSubmatch(ports, -1)
|
||||
portStr := str.Cut(config, "# port标记位开始", "# port标记位结束")
|
||||
matches := regexp.MustCompile(`listen\s+([^;]*);?`).FindAllStringSubmatch(portStr, -1)
|
||||
for _, match := range matches {
|
||||
if len(match) < 2 {
|
||||
continue
|
||||
@@ -625,11 +531,16 @@ func (r *WebsiteImpl) GetConfig(id uint) (types.WebsiteSetting, error) {
|
||||
|
||||
// 处理 443 ssl 之类的情况
|
||||
ports := strings.Fields(match[1])
|
||||
if len(ports) == 1 {
|
||||
setting.Ports = append(setting.Ports, cast.ToUint(ports[0]))
|
||||
} else if len(ports) > 1 && ports[1] == "ssl" {
|
||||
setting.Ports = append(setting.Ports, cast.ToUint(ports[0]))
|
||||
setting.TLSPorts = append(setting.TLSPorts, cast.ToUint(ports[0]))
|
||||
if len(ports) == 0 {
|
||||
continue
|
||||
}
|
||||
if !slices.Contains(setting.Ports, ports[0]) {
|
||||
setting.Ports = append(setting.Ports, ports[0])
|
||||
}
|
||||
if len(ports) > 1 && ports[1] == "ssl" {
|
||||
setting.SSLPorts = append(setting.SSLPorts, ports[0])
|
||||
} else if len(ports) > 1 && ports[1] == "quic" {
|
||||
setting.QUICPorts = append(setting.QUICPorts, ports[0])
|
||||
}
|
||||
}
|
||||
serverName := str.Cut(config, "# server_name标记位开始", "# server_name标记位结束")
|
||||
@@ -652,33 +563,27 @@ func (r *WebsiteImpl) GetConfig(id uint) (types.WebsiteSetting, error) {
|
||||
userIni, _ := io.Read(filepath.Join(setting.Root, ".user.ini"))
|
||||
if strings.Contains(userIni, "open_basedir") {
|
||||
setting.OpenBasedir = true
|
||||
} else {
|
||||
setting.OpenBasedir = false
|
||||
}
|
||||
} else {
|
||||
setting.OpenBasedir = false
|
||||
}
|
||||
|
||||
crt, _ := io.Read("/www/server/vhost/ssl/" + website.Name + ".pem")
|
||||
setting.SslCertificate = crt
|
||||
setting.SSLCertificate = crt
|
||||
key, _ := io.Read("/www/server/vhost/ssl/" + website.Name + ".key")
|
||||
setting.SslCertificateKey = key
|
||||
if setting.Ssl {
|
||||
setting.SSLCertificateKey = key
|
||||
if setting.SSL {
|
||||
ssl := str.Cut(config, "# ssl标记位开始", "# ssl标记位结束")
|
||||
setting.HttpRedirect = strings.Contains(ssl, "# http重定向标记位")
|
||||
setting.Hsts = strings.Contains(ssl, "# hsts标记位")
|
||||
} else {
|
||||
setting.HttpRedirect = false
|
||||
setting.Hsts = false
|
||||
setting.HTTPRedirect = strings.Contains(ssl, "# http重定向标记位")
|
||||
setting.HSTS = strings.Contains(ssl, "# hsts标记位")
|
||||
setting.OCSP = strings.Contains(ssl, "# ocsp标记位")
|
||||
}
|
||||
|
||||
// 解析证书信息
|
||||
if decode, err := cert.ParseCert(crt); err == nil {
|
||||
setting.SslNotBefore = decode.NotBefore.Format("2006-01-02 15:04:05")
|
||||
setting.SslNotAfter = decode.NotAfter.Format("2006-01-02 15:04:05")
|
||||
setting.SslIssuer = decode.Issuer.CommonName
|
||||
setting.SslOCSPServer = decode.OCSPServer
|
||||
setting.SSlDNSNames = decode.DNSNames
|
||||
setting.SSLNotBefore = decode.NotBefore.Format("2006-01-02 15:04:05")
|
||||
setting.SSLNotAfter = decode.NotAfter.Format("2006-01-02 15:04:05")
|
||||
setting.SSLIssuer = decode.Issuer.CommonName
|
||||
setting.SSLOCSPServer = decode.OCSPServer
|
||||
setting.SSLDNSNames = decode.DNSNames
|
||||
}
|
||||
|
||||
waf := str.Cut(config, "# waf标记位开始", "# waf标记位结束")
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
type Website interface {
|
||||
List(page int, limit int) (int64, []models.Website, error)
|
||||
Add(website types.WebsiteAdd) (models.Website, error)
|
||||
Add(website requests.Add) (models.Website, error)
|
||||
SaveConfig(config requests.SaveConfig) error
|
||||
Delete(id requests.Delete) error
|
||||
GetConfig(id uint) (types.WebsiteSetting, error)
|
||||
|
||||
+4
-3
@@ -1,8 +1,9 @@
|
||||
{
|
||||
"auth": {
|
||||
"token": {
|
||||
"expired": "login has expired",
|
||||
"missing": "not logged in"
|
||||
"session": {
|
||||
"expired": "session has expired",
|
||||
"missing": "Please enable cookies and try again",
|
||||
"invalid": "invalid session"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
|
||||
+4
-3
@@ -1,8 +1,9 @@
|
||||
{
|
||||
"auth": {
|
||||
"token": {
|
||||
"expired": "登录已过期",
|
||||
"missing": "未登录"
|
||||
"session": {
|
||||
"expired": "会话已过期",
|
||||
"missing": "请启用 Cookie 后再试",
|
||||
"invalid": "会话无效"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
|
||||
@@ -7,3 +7,4 @@ APP_SSL=false
|
||||
APP_LOCALE=zh_CN
|
||||
|
||||
JWT_SECRET=
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/libdns/cloudflare"
|
||||
"github.com/libdns/dnspod"
|
||||
"github.com/libdns/libdns"
|
||||
"github.com/libdns/tencentcloud"
|
||||
"github.com/mholt/acmez/v2/acme"
|
||||
"golang.org/x/net/publicsuffix"
|
||||
|
||||
@@ -125,6 +126,11 @@ func (s dnsSolver) getDNSProvider() (DNSProvider, error) {
|
||||
dns = &dnspod.Provider{
|
||||
APIToken: s.param.ID + "," + s.param.Token,
|
||||
}
|
||||
case Tencent:
|
||||
dns = &tencentcloud.Provider{
|
||||
SecretId: s.param.AccessKey,
|
||||
SecretKey: s.param.SecretKey,
|
||||
}
|
||||
case AliYun:
|
||||
dns = &alidns.Provider{
|
||||
AccKeyID: s.param.AccessKey,
|
||||
@@ -145,6 +151,7 @@ type DnsType string
|
||||
|
||||
const (
|
||||
DnsPod DnsType = "dnspod"
|
||||
Tencent DnsType = "tencent"
|
||||
AliYun DnsType = "aliyun"
|
||||
CloudFlare DnsType = "cloudflare"
|
||||
)
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ func (m *MySQL) UserCreate(user, password string) error {
|
||||
}
|
||||
|
||||
func (m *MySQL) UserDrop(user string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("DROP USER IF EXISTS '%s'@'localhost'", user))
|
||||
_, err := m.Exec(fmt.Sprintf("DROP USER IF EXISTS '%s'", user))
|
||||
m.flushPrivileges()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
"github.com/TheTNB/panel/pkg/io"
|
||||
"github.com/TheTNB/panel/pkg/shell"
|
||||
"github.com/TheTNB/panel/pkg/systemctl"
|
||||
"github.com/TheTNB/panel/pkg/types"
|
||||
)
|
||||
|
||||
type Postgres struct {
|
||||
db *sql.DB
|
||||
username string
|
||||
password string
|
||||
address string
|
||||
port uint
|
||||
}
|
||||
|
||||
func NewPostgres(username, password, address string, port uint) (*Postgres, error) {
|
||||
dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=postgres sslmode=disable", address, port, username, password)
|
||||
if password == "" {
|
||||
dsn = fmt.Sprintf("host=%s port=%d user=%s dbname=postgres sslmode=disable", address, port, username)
|
||||
}
|
||||
db, err := sql.Open("postgres", dsn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("初始化Postgres连接失败: %w", err)
|
||||
}
|
||||
if db.Ping() != nil {
|
||||
return nil, fmt.Errorf("连接Postgres失败: %w", err)
|
||||
}
|
||||
return &Postgres{
|
||||
db: db,
|
||||
username: username,
|
||||
password: password,
|
||||
address: address,
|
||||
port: port,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Postgres) Close() error {
|
||||
return m.db.Close()
|
||||
}
|
||||
|
||||
func (m *Postgres) Ping() error {
|
||||
return m.db.Ping()
|
||||
}
|
||||
|
||||
func (m *Postgres) Query(query string, args ...any) (*sql.Rows, error) {
|
||||
return m.db.Query(query, args...)
|
||||
}
|
||||
|
||||
func (m *Postgres) QueryRow(query string, args ...any) *sql.Row {
|
||||
return m.db.QueryRow(query, args...)
|
||||
}
|
||||
|
||||
func (m *Postgres) Exec(query string, args ...any) (sql.Result, error) {
|
||||
return m.db.Exec(query, args...)
|
||||
}
|
||||
|
||||
func (m *Postgres) Prepare(query string) (*sql.Stmt, error) {
|
||||
return m.db.Prepare(query)
|
||||
}
|
||||
|
||||
func (m *Postgres) DatabaseCreate(name string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("CREATE DATABASE %s", name))
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *Postgres) DatabaseDrop(name string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", name))
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *Postgres) UserCreate(user, password string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("CREATE USER %s WITH PASSWORD '%s'", user, password))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Postgres) UserDrop(user string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("DROP USER IF EXISTS %s", user))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, _ = shell.Execf(`sed -i '/` + user + `/d' /www/server/postgresql/data/pg_hba.conf`)
|
||||
return systemctl.Reload("postgresql")
|
||||
}
|
||||
|
||||
func (m *Postgres) UserPassword(user, password string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("ALTER USER %s WITH PASSWORD '%s'", user, password))
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *Postgres) PrivilegesGrant(user, database string) error {
|
||||
if _, err := m.Exec(fmt.Sprintf("ALTER DATABASE %s OWNER TO %s", database, user)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := m.Exec(fmt.Sprintf("GRANT ALL PRIVILEGES ON DATABASE %s TO %s", database, user)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Postgres) PrivilegesRevoke(user, database string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("REVOKE ALL PRIVILEGES ON DATABASE %s FROM %s", database, user))
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *Postgres) HostAdd(database, user, host string) error {
|
||||
config := fmt.Sprintf("host %s %s %s scram-sha-256", database, user, host)
|
||||
if err := io.WriteAppend("/www/server/postgresql/data/pg_hba.conf", config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return systemctl.Reload("postgresql")
|
||||
}
|
||||
|
||||
func (m *Postgres) HostRemove(database, user, host string) error {
|
||||
regex := fmt.Sprintf(`host\s+%s\s+%s\s+%s`, database, user, host)
|
||||
if _, err := shell.Execf(`sed -i '/` + regex + `/d' /www/server/postgresql/data/pg_hba.conf`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return systemctl.Reload("postgresql")
|
||||
}
|
||||
|
||||
func (m *Postgres) Users() ([]types.PostgresUser, error) {
|
||||
query := `
|
||||
SELECT rolname,
|
||||
rolsuper,
|
||||
rolcreaterole,
|
||||
rolcreatedb,
|
||||
rolreplication,
|
||||
rolbypassrls
|
||||
FROM pg_roles
|
||||
WHERE rolcanlogin = true;
|
||||
`
|
||||
rows, err := m.Query(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var users []types.PostgresUser
|
||||
for rows.Next() {
|
||||
var user types.PostgresUser
|
||||
var super, canCreateRole, canCreateDb, replication, bypassRls bool
|
||||
if err = rows.Scan(&user.Role, &super, &canCreateRole, &canCreateDb, &replication, &bypassRls); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
permissions := map[string]bool{
|
||||
"超级用户": super,
|
||||
"创建角色": canCreateRole,
|
||||
"创建数据库": canCreateDb,
|
||||
"可以复制": replication,
|
||||
"绕过行级安全": bypassRls,
|
||||
}
|
||||
for perm, enabled := range permissions {
|
||||
if enabled {
|
||||
user.Attributes = append(user.Attributes, perm)
|
||||
}
|
||||
}
|
||||
|
||||
if len(user.Attributes) == 0 {
|
||||
user.Attributes = append(user.Attributes, "无")
|
||||
}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (m *Postgres) Databases() ([]types.PostgresDatabase, error) {
|
||||
query := `
|
||||
SELECT d.datname, pg_catalog.pg_get_userbyid(d.datdba), pg_catalog.pg_encoding_to_char(d.encoding)
|
||||
FROM pg_catalog.pg_database d
|
||||
WHERE datistemplate = false;
|
||||
`
|
||||
rows, err := m.Query(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var databases []types.PostgresDatabase
|
||||
for rows.Next() {
|
||||
var db types.PostgresDatabase
|
||||
if err := rows.Scan(&db.Name, &db.Owner, &db.Encoding); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
databases = append(databases, db)
|
||||
}
|
||||
|
||||
return databases, nil
|
||||
}
|
||||
@@ -66,35 +66,6 @@ func GetMonitoringInfo() MonitoringInfo {
|
||||
return res
|
||||
}
|
||||
|
||||
// VersionCompare 版本比较
|
||||
func VersionCompare(ver1, ver2, operator string) bool {
|
||||
v1 := strings.TrimPrefix(ver1, "v")
|
||||
v2 := strings.TrimPrefix(ver2, "v")
|
||||
|
||||
v1s := strings.Split(v1, ".")
|
||||
v2s := strings.Split(v2, ".")
|
||||
|
||||
for len(v1s) < len(v2s) {
|
||||
v1s = append(v1s, "0")
|
||||
}
|
||||
|
||||
for len(v2s) < len(v1s) {
|
||||
v2s = append(v2s, "0")
|
||||
}
|
||||
|
||||
for i := 0; i < len(v1s); i++ {
|
||||
v1i := cast.ToInt(v1s[i])
|
||||
v2i := cast.ToInt(v2s[i])
|
||||
|
||||
if v1i > v2i {
|
||||
return operator == ">" || operator == ">=" || operator == "!="
|
||||
} else if v1i < v2i {
|
||||
return operator == "<" || operator == "<=" || operator == "!="
|
||||
}
|
||||
}
|
||||
return operator == "==" || operator == ">=" || operator == "<="
|
||||
}
|
||||
|
||||
// GenerateVersions 获取版本列表
|
||||
func GenerateVersions(start, end string) ([]string, error) {
|
||||
var versions []string
|
||||
|
||||
@@ -18,36 +18,6 @@ func (s *HelperTestSuite) TestGetMonitoringInfo() {
|
||||
s.NotNil(GetMonitoringInfo())
|
||||
}
|
||||
|
||||
func (s *HelperTestSuite) TestVersionCompare() {
|
||||
s.True(VersionCompare("1.0.0", "1.0.0", "=="))
|
||||
s.True(VersionCompare("1.0.0", "1.0.0", ">="))
|
||||
s.True(VersionCompare("1.0.0", "1.0.0", "<="))
|
||||
s.False(VersionCompare("1.0.0", "1.0.0", ">"))
|
||||
s.False(VersionCompare("1.0.0", "1.0.0", "<"))
|
||||
s.False(VersionCompare("1.0.0", "1.0.0", "!="))
|
||||
|
||||
s.True(VersionCompare("1.0.0", "1.0.1", "<"))
|
||||
s.True(VersionCompare("1.0.0", "1.0.1", "<="))
|
||||
s.True(VersionCompare("1.0.0", "1.0.1", "!="))
|
||||
s.False(VersionCompare("1.0.0", "1.0.1", "=="))
|
||||
s.False(VersionCompare("1.0.0", "1.0.1", ">="))
|
||||
s.False(VersionCompare("1.0.0", "1.0.1", ">"))
|
||||
|
||||
s.True(VersionCompare("1.0.1", "1.0.0", ">"))
|
||||
s.True(VersionCompare("1.0.1", "1.0.0", ">="))
|
||||
s.True(VersionCompare("1.0.1", "1.0.0", "!="))
|
||||
s.False(VersionCompare("1.0.1", "1.0.0", "=="))
|
||||
s.False(VersionCompare("1.0.1", "1.0.0", "<="))
|
||||
s.False(VersionCompare("1.0.1", "1.0.0", "<"))
|
||||
|
||||
s.True(VersionCompare("v1.0.0", "1.0.0", "=="))
|
||||
s.True(VersionCompare("1.0.0", "v1.0.0", "=="))
|
||||
s.True(VersionCompare("v1.0.0", "v1.0.0", "=="))
|
||||
s.False(VersionCompare("v2.2.9", "v2.2.10", ">="))
|
||||
s.True(VersionCompare("v2.2.10", "v2.2.9", ">="))
|
||||
|
||||
}
|
||||
|
||||
func (s *HelperTestSuite) TestGenerateVersions() {
|
||||
versions, err := GenerateVersions("1.0.0", "1.0.3")
|
||||
s.NoError(err)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package types
|
||||
|
||||
type PostgresUser struct {
|
||||
Role string `json:"role"`
|
||||
Attributes []string `json:"attributes"`
|
||||
}
|
||||
|
||||
type PostgresDatabase struct {
|
||||
Name string `json:"name"`
|
||||
Owner string `json:"owner"`
|
||||
Encoding string `json:"encoding"`
|
||||
}
|
||||
+15
-29
@@ -1,42 +1,28 @@
|
||||
package types
|
||||
|
||||
type WebsiteAdd struct {
|
||||
Name string `json:"name"`
|
||||
Status bool `json:"status"`
|
||||
Domains []string `json:"domains"`
|
||||
Ports []uint `json:"ports"`
|
||||
Path string `json:"path"`
|
||||
Php string `json:"php"`
|
||||
Ssl bool `json:"ssl"`
|
||||
Remark string `json:"remark"`
|
||||
Db bool `json:"db"`
|
||||
DbType string `json:"db_type"`
|
||||
DbName string `json:"db_name"`
|
||||
DbUser string `json:"db_user"`
|
||||
DbPassword string `json:"db_password"`
|
||||
}
|
||||
|
||||
// WebsiteSetting 网站设置
|
||||
type WebsiteSetting struct {
|
||||
Name string `json:"name"`
|
||||
Domains []string `json:"domains"`
|
||||
Ports []uint `json:"ports"`
|
||||
TLSPorts []uint `json:"tls_ports"`
|
||||
Ports []string `json:"ports"`
|
||||
SSLPorts []string `json:"ssl_ports"`
|
||||
QUICPorts []string `json:"quic_ports"`
|
||||
Root string `json:"root"`
|
||||
Path string `json:"path"`
|
||||
Index string `json:"index"`
|
||||
Php string `json:"php"`
|
||||
PHP string `json:"php"`
|
||||
OpenBasedir bool `json:"open_basedir"`
|
||||
Ssl bool `json:"ssl"`
|
||||
SslCertificate string `json:"ssl_certificate"`
|
||||
SslCertificateKey string `json:"ssl_certificate_key"`
|
||||
SslNotBefore string `json:"ssl_not_before"`
|
||||
SslNotAfter string `json:"ssl_not_after"`
|
||||
SSlDNSNames []string `json:"ssl_dns_names"`
|
||||
SslIssuer string `json:"ssl_issuer"`
|
||||
SslOCSPServer []string `json:"ssl_ocsp_server"`
|
||||
HttpRedirect bool `json:"http_redirect"`
|
||||
Hsts bool `json:"hsts"`
|
||||
SSL bool `json:"ssl"`
|
||||
SSLCertificate string `json:"ssl_certificate"`
|
||||
SSLCertificateKey string `json:"ssl_certificate_key"`
|
||||
SSLNotBefore string `json:"ssl_not_before"`
|
||||
SSLNotAfter string `json:"ssl_not_after"`
|
||||
SSLDNSNames []string `json:"ssl_dns_names"`
|
||||
SSLIssuer string `json:"ssl_issuer"`
|
||||
SSLOCSPServer []string `json:"ssl_ocsp_server"`
|
||||
HTTPRedirect bool `json:"http_redirect"`
|
||||
HSTS bool `json:"hsts"`
|
||||
OCSP bool `json:"ocsp"`
|
||||
Waf bool `json:"waf"`
|
||||
WafMode string `json:"waf_mode"`
|
||||
WafCcDeny string `json:"waf_cc_deny"`
|
||||
|
||||
+4
-1
@@ -13,7 +13,10 @@
|
||||
"packageRules": [
|
||||
{
|
||||
"description": "Automerge non-major updates",
|
||||
"matchUpdateTypes": ["minor", "patch"],
|
||||
"matchUpdateTypes": [
|
||||
"minor",
|
||||
"patch"
|
||||
],
|
||||
"matchCurrentVersion": "!/^0/",
|
||||
"automerge": true
|
||||
}
|
||||
|
||||
+35
-37
@@ -1,12 +1,16 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/contracts/route"
|
||||
"github.com/goravel/framework/facades"
|
||||
frameworkmiddleware "github.com/goravel/framework/http/middleware"
|
||||
|
||||
"github.com/TheTNB/panel/app/http/controllers"
|
||||
"github.com/TheTNB/panel/app/http/middleware"
|
||||
"github.com/TheTNB/panel/embed"
|
||||
)
|
||||
|
||||
func Api() {
|
||||
@@ -14,29 +18,31 @@ func Api() {
|
||||
r.Prefix("info").Group(func(r route.Router) {
|
||||
infoController := controllers.NewInfoController()
|
||||
r.Get("panel", infoController.Panel)
|
||||
r.Middleware(middleware.Jwt()).Get("homePlugins", infoController.HomePlugins)
|
||||
r.Middleware(middleware.Jwt()).Get("nowMonitor", infoController.NowMonitor)
|
||||
r.Middleware(middleware.Jwt()).Get("systemInfo", infoController.SystemInfo)
|
||||
r.Middleware(middleware.Jwt()).Get("countInfo", infoController.CountInfo)
|
||||
r.Middleware(middleware.Jwt()).Get("installedDbAndPhp", infoController.InstalledDbAndPhp)
|
||||
r.Middleware(middleware.Jwt()).Get("checkUpdate", infoController.CheckUpdate)
|
||||
r.Middleware(middleware.Jwt()).Get("updateInfo", infoController.UpdateInfo)
|
||||
r.Middleware(middleware.Jwt()).Post("update", infoController.Update)
|
||||
r.Middleware(middleware.Jwt()).Post("restart", infoController.Restart)
|
||||
r.Middleware(middleware.Session()).Get("homePlugins", infoController.HomePlugins)
|
||||
r.Middleware(middleware.Session()).Get("nowMonitor", infoController.NowMonitor)
|
||||
r.Middleware(middleware.Session()).Get("systemInfo", infoController.SystemInfo)
|
||||
r.Middleware(middleware.Session()).Get("countInfo", infoController.CountInfo)
|
||||
r.Middleware(middleware.Session()).Get("installedDbAndPhp", infoController.InstalledDbAndPhp)
|
||||
r.Middleware(middleware.Session()).Get("checkUpdate", infoController.CheckUpdate)
|
||||
r.Middleware(middleware.Session()).Get("updateInfo", infoController.UpdateInfo)
|
||||
r.Middleware(middleware.Session()).Post("update", infoController.Update)
|
||||
r.Middleware(middleware.Session()).Post("restart", infoController.Restart)
|
||||
})
|
||||
r.Prefix("user").Group(func(r route.Router) {
|
||||
userController := controllers.NewUserController()
|
||||
r.Middleware(frameworkmiddleware.Throttle("login")).Post("login", userController.Login)
|
||||
r.Middleware(middleware.Jwt()).Get("info", userController.Info)
|
||||
r.Post("logout", userController.Logout)
|
||||
r.Get("isLogin", userController.IsLogin)
|
||||
r.Middleware(middleware.Session()).Get("info", userController.Info)
|
||||
})
|
||||
r.Prefix("task").Middleware(middleware.Jwt()).Group(func(r route.Router) {
|
||||
r.Prefix("task").Middleware(middleware.Session()).Group(func(r route.Router) {
|
||||
taskController := controllers.NewTaskController()
|
||||
r.Get("status", taskController.Status)
|
||||
r.Get("list", taskController.List)
|
||||
r.Get("log", taskController.Log)
|
||||
r.Post("delete", taskController.Delete)
|
||||
})
|
||||
r.Prefix("website").Middleware(middleware.Jwt(), middleware.MustInstall()).Group(func(r route.Router) {
|
||||
r.Prefix("website").Middleware(middleware.Session(), middleware.MustInstall()).Group(func(r route.Router) {
|
||||
websiteController := controllers.NewWebsiteController()
|
||||
r.Get("defaultConfig", websiteController.GetDefaultConfig)
|
||||
r.Post("defaultConfig", websiteController.SaveDefaultConfig)
|
||||
@@ -44,7 +50,7 @@ func Api() {
|
||||
r.Put("uploadBackup", websiteController.UploadBackup)
|
||||
r.Delete("deleteBackup", websiteController.DeleteBackup)
|
||||
})
|
||||
r.Prefix("websites").Middleware(middleware.Jwt(), middleware.MustInstall()).Group(func(r route.Router) {
|
||||
r.Prefix("websites").Middleware(middleware.Session(), middleware.MustInstall()).Group(func(r route.Router) {
|
||||
websiteController := controllers.NewWebsiteController()
|
||||
r.Get("/", websiteController.List)
|
||||
r.Post("/", websiteController.Add)
|
||||
@@ -58,7 +64,7 @@ func Api() {
|
||||
r.Post("{id}/resetConfig", websiteController.ResetConfig)
|
||||
r.Post("{id}/status", websiteController.Status)
|
||||
})
|
||||
r.Prefix("cert").Middleware(middleware.Jwt()).Group(func(r route.Router) {
|
||||
r.Prefix("cert").Middleware(middleware.Session()).Group(func(r route.Router) {
|
||||
certController := controllers.NewCertController()
|
||||
r.Get("caProviders", certController.CAProviders)
|
||||
r.Get("dnsProviders", certController.DNSProviders)
|
||||
@@ -83,7 +89,7 @@ func Api() {
|
||||
r.Post("manualDNS", certController.ManualDNS)
|
||||
r.Post("deploy", certController.Deploy)
|
||||
})
|
||||
r.Prefix("plugin").Middleware(middleware.Jwt()).Group(func(r route.Router) {
|
||||
r.Prefix("plugin").Middleware(middleware.Session()).Group(func(r route.Router) {
|
||||
pluginController := controllers.NewPluginController()
|
||||
r.Get("list", pluginController.List)
|
||||
r.Post("install", pluginController.Install)
|
||||
@@ -92,7 +98,7 @@ func Api() {
|
||||
r.Post("updateShow", pluginController.UpdateShow)
|
||||
r.Get("isInstalled", pluginController.IsInstalled)
|
||||
})
|
||||
r.Prefix("cron").Middleware(middleware.Jwt()).Group(func(r route.Router) {
|
||||
r.Prefix("cron").Middleware(middleware.Session()).Group(func(r route.Router) {
|
||||
cronController := controllers.NewCronController()
|
||||
r.Get("list", cronController.List)
|
||||
r.Get("{id}", cronController.Script)
|
||||
@@ -102,7 +108,7 @@ func Api() {
|
||||
r.Post("status", cronController.Status)
|
||||
r.Get("log/{id}", cronController.Log)
|
||||
})
|
||||
r.Prefix("safe").Middleware(middleware.Jwt()).Group(func(r route.Router) {
|
||||
r.Prefix("safe").Middleware(middleware.Session()).Group(func(r route.Router) {
|
||||
safeController := controllers.NewSafeController()
|
||||
r.Get("firewallStatus", safeController.GetFirewallStatus)
|
||||
r.Post("firewallStatus", safeController.SetFirewallStatus)
|
||||
@@ -116,7 +122,7 @@ func Api() {
|
||||
r.Get("pingStatus", safeController.GetPingStatus)
|
||||
r.Post("pingStatus", safeController.SetPingStatus)
|
||||
})
|
||||
r.Prefix("container").Middleware(middleware.Jwt(), middleware.MustInstall()).Group(func(r route.Router) {
|
||||
r.Prefix("container").Middleware(middleware.Session(), middleware.MustInstall()).Group(func(r route.Router) {
|
||||
containerController := controllers.NewContainerController()
|
||||
r.Get("list", containerController.ContainerList)
|
||||
r.Get("search", containerController.ContainerSearch)
|
||||
@@ -164,7 +170,7 @@ func Api() {
|
||||
r.Post("prune", containerController.VolumePrune)
|
||||
})
|
||||
})
|
||||
r.Prefix("file").Middleware(middleware.Jwt()).Group(func(r route.Router) {
|
||||
r.Prefix("file").Middleware(middleware.Session()).Group(func(r route.Router) {
|
||||
fileController := controllers.NewFileController()
|
||||
r.Post("create", fileController.Create)
|
||||
r.Get("content", fileController.Content)
|
||||
@@ -182,7 +188,7 @@ func Api() {
|
||||
r.Post("search", fileController.Search)
|
||||
r.Get("list", fileController.List)
|
||||
})
|
||||
r.Prefix("monitor").Middleware(middleware.Jwt()).Group(func(r route.Router) {
|
||||
r.Prefix("monitor").Middleware(middleware.Session()).Group(func(r route.Router) {
|
||||
monitorController := controllers.NewMonitorController()
|
||||
r.Post("switch", monitorController.Switch)
|
||||
r.Post("saveDays", monitorController.SaveDays)
|
||||
@@ -190,20 +196,20 @@ func Api() {
|
||||
r.Get("list", monitorController.List)
|
||||
r.Get("switchAndDays", monitorController.SwitchAndDays)
|
||||
})
|
||||
r.Prefix("ssh").Middleware(middleware.Jwt()).Group(func(r route.Router) {
|
||||
r.Prefix("ssh").Middleware(middleware.Session()).Group(func(r route.Router) {
|
||||
sshController := controllers.NewSshController()
|
||||
r.Get("info", sshController.GetInfo)
|
||||
r.Post("info", sshController.UpdateInfo)
|
||||
r.Get("session", sshController.Session)
|
||||
})
|
||||
r.Prefix("setting").Middleware(middleware.Jwt()).Group(func(r route.Router) {
|
||||
r.Prefix("setting").Middleware(middleware.Session()).Group(func(r route.Router) {
|
||||
settingController := controllers.NewSettingController()
|
||||
r.Get("list", settingController.List)
|
||||
r.Post("update", settingController.Update)
|
||||
r.Get("https", settingController.GetHttps)
|
||||
r.Post("https", settingController.UpdateHttps)
|
||||
})
|
||||
r.Prefix("system").Middleware(middleware.Jwt()).Group(func(r route.Router) {
|
||||
r.Prefix("system").Middleware(middleware.Session()).Group(func(r route.Router) {
|
||||
controller := controllers.NewSystemController()
|
||||
r.Get("service/status", controller.ServiceStatus)
|
||||
r.Get("service/isEnabled", controller.ServiceIsEnabled)
|
||||
@@ -218,19 +224,11 @@ func Api() {
|
||||
|
||||
// 文档
|
||||
swaggerController := controllers.NewSwaggerController()
|
||||
facades.Route().Get("swagger/*any", swaggerController.Index)
|
||||
facades.Route().Middleware(middleware.Session()).Get("swagger/*any", swaggerController.Index)
|
||||
|
||||
// 静态文件
|
||||
entrance := facades.Config().GetString("http.entrance")
|
||||
if entrance == "/" {
|
||||
entrance = ""
|
||||
}
|
||||
assetController := controllers.NewAssetController()
|
||||
facades.Route().Get("favicon.png", assetController.Favicon)
|
||||
facades.Route().Get("robots.txt", assetController.Robots)
|
||||
facades.Route().Get(entrance+"/assets/{any}", assetController.Index)
|
||||
facades.Route().Get(entrance+"/loading/{any}", assetController.Index)
|
||||
facades.Route().Get(entrance+"/{any}", assetController.Index)
|
||||
facades.Route().Get(entrance+"/", assetController.Index)
|
||||
facades.Route().Fallback(assetController.NotFound)
|
||||
// 404
|
||||
facades.Route().Fallback(func(ctx http.Context) http.Response {
|
||||
index, _ := embed.PublicFS.ReadFile(filepath.Join("frontend", "index.html"))
|
||||
return ctx.Response().Data(http.StatusOK, "text/html; charset=utf-8", index)
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
// Plugin 加载插件路由
|
||||
func Plugin() {
|
||||
facades.Route().Prefix("api/plugins").Middleware(middleware.Jwt(), middleware.MustInstall()).Group(func(r route.Router) {
|
||||
facades.Route().Prefix("api/plugins").Middleware(middleware.Session(), middleware.MustInstall()).Group(func(r route.Router) {
|
||||
r.Prefix("openresty").Group(func(route route.Router) {
|
||||
openRestyController := plugins.NewOpenrestyController()
|
||||
route.Get("load", openRestyController.Load)
|
||||
|
||||
@@ -151,14 +151,14 @@ Prepare_System() {
|
||||
# Rocky Linux
|
||||
/usr/bin/crb enable
|
||||
dnf makecache -y
|
||||
dnf install -y curl wget zip unzip tar p7zip p7zip-plugins git jq git-core dos2unix rsyslog
|
||||
dnf install -y bash curl wget zip unzip tar p7zip p7zip-plugins git jq git-core dos2unix rsyslog make
|
||||
elif [ "${OS}" == "debian" ]; then
|
||||
if ${inChina}; then
|
||||
sed -i 's/deb.debian.org/mirrors.tencent.com/g' /etc/apt/sources.list
|
||||
sed -i 's/security.debian.org/mirrors.tencent.com/g' /etc/apt/sources.list
|
||||
fi
|
||||
apt-get update -y
|
||||
apt-get install -y curl wget zip unzip tar p7zip p7zip-full git jq git dos2unix rsyslog
|
||||
apt-get install -y bash curl wget zip unzip tar p7zip p7zip-full git jq git dos2unix rsyslog make
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
@@ -309,28 +309,7 @@ Init_Panel() {
|
||||
exit 1
|
||||
fi
|
||||
# 写入服务文件
|
||||
cat > /etc/systemd/system/panel.service << EOF
|
||||
[Unit]
|
||||
Description=HaoZi Panel
|
||||
After=syslog.target network.target
|
||||
Wants=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=${setup_Path}/panel/
|
||||
ExecStart=/www/panel/panel --env="/www/panel/panel.conf"
|
||||
ExecReload=kill -s HUP \$MAINPID
|
||||
ExecStop=kill -s QUIT \$MAINPID
|
||||
User=root
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
LimitNOFILE=1048576
|
||||
LimitNPROC=1048576
|
||||
Delegate=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
cp -f ${setup_Path}/panel/scripts/panel.service /etc/systemd/system/panel.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable panel.service
|
||||
systemctl start panel.service
|
||||
|
||||
@@ -59,6 +59,11 @@ else
|
||||
echo "错误:耗子面板不支持该系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装依赖软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mysqlUserCheck=$(cat /etc/passwd | grep mysql)
|
||||
if [ "${mysqlUserCheck}" == "" ]; then
|
||||
|
||||
@@ -42,6 +42,11 @@ else
|
||||
echo "错误:耗子面板不支持该系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装依赖软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 准备目录
|
||||
rm -rf ${openrestyPath}
|
||||
@@ -434,6 +439,11 @@ cat > ${openrestyPath}/html/index.html << EOF
|
||||
p {
|
||||
color: #555;
|
||||
line-height: 1.8;
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #007bff;
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.container {
|
||||
@@ -451,6 +461,7 @@ cat > ${openrestyPath}/html/index.html << EOF
|
||||
<h1>耗子面板</h1>
|
||||
<p>这是耗子面板的 OpenResty 默认页面!</p>
|
||||
<p>当您看到此页面,说明无法在服务器上找到该域名对应的站点。</p>
|
||||
<p>由 <a target="_blank" href="https://panel.haozi.net">耗子面板</a> 强力驱动</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -490,6 +501,11 @@ cat > ${openrestyPath}/html/stop.html << EOF
|
||||
p {
|
||||
color: #555;
|
||||
line-height: 1.8;
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #007bff;
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.container {
|
||||
@@ -507,6 +523,7 @@ cat > ${openrestyPath}/html/stop.html << EOF
|
||||
<h1>耗子面板</h1>
|
||||
<p>该网站已被管理员停止访问!</p>
|
||||
<p>当您看到此页面,说明该网站已被服务器管理员停止对外访问。</p>
|
||||
<p>由 <a target="_blank" href="https://panel.haozi.net">耗子面板</a> 强力驱动</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -546,6 +563,11 @@ cat > ${openrestyPath}/html/block.html << EOF
|
||||
p {
|
||||
color: #555;
|
||||
line-height: 1.8;
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #007bff;
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.container {
|
||||
@@ -564,6 +586,7 @@ cat > ${openrestyPath}/html/block.html << EOF
|
||||
<p>本次请求判断为危险的攻击请求,已被拦截!</p>
|
||||
<p>可能您的请求中包含了危险的攻击内容,或者您的请求被误判为攻击请求。</p>
|
||||
<p>如果您认为这是误判,请联系服务器管理员解决。</p>
|
||||
<p>由 <a target="_blank" href="https://panel.haozi.net">耗子面板</a> 强力驱动</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,8 +7,8 @@ Wants=network.target
|
||||
Type=simple
|
||||
WorkingDirectory=/www/panel/
|
||||
ExecStart=/www/panel/panel --env="/www/panel/panel.conf"
|
||||
ExecReload=kill -s HUP \$MAINPID
|
||||
ExecStop=kill -s QUIT \$MAINPID
|
||||
ExecReload=kill -s HUP $MAINPID
|
||||
ExecStop=kill -s QUIT $MAINPID
|
||||
User=root
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
@@ -53,6 +53,11 @@ else
|
||||
echo "错误:耗子面板不支持该系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装依赖软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 准备安装目录
|
||||
rm -rf ${phpPath}
|
||||
|
||||
@@ -53,6 +53,11 @@ else
|
||||
echo "错误:耗子面板不支持该系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装依赖软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
postgresqlUserCheck=$(cat /etc/passwd | grep postgres)
|
||||
if [ "${postgresqlUserCheck}" == "" ]; then
|
||||
|
||||
@@ -45,6 +45,11 @@ else
|
||||
echo "错误:耗子面板不支持该系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装依赖软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 准备目录
|
||||
rm -rf ${redisPath}
|
||||
|
||||
@@ -30,6 +30,11 @@ else
|
||||
echo "错误:不支持的操作系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 写入配置
|
||||
cat > /etc/rsyncd.conf << EOF
|
||||
|
||||
@@ -30,5 +30,10 @@ else
|
||||
echo "错误:不支持的操作系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
panel writePlugin s3fs 1.9
|
||||
|
||||
@@ -35,5 +35,10 @@ else
|
||||
echo "错误:不支持的操作系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
panel writePlugin supervisor 4.2.5
|
||||
|
||||
@@ -143,6 +143,12 @@ if version_lt "$oldVersion" "2.2.16"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if version_lt "$oldVersion" "2.2.20"; then
|
||||
echo "更新面板到 v2.2.20 ..."
|
||||
echo "Update panel to v2.2.20 ..."
|
||||
echo "SESSION_LIFETIME=120" >> $panelPath/panel.conf
|
||||
fi
|
||||
|
||||
echo $HR
|
||||
echo "更新结束"
|
||||
echo "Update finished"
|
||||
|
||||
Reference in New Issue
Block a user