mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-12 16:00:33 +00:00
Compare commits
16
Commits
v1.10.31-lts
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20b89a8fdd | ||
|
|
8def011e63 | ||
|
|
7c5b2f41e3 | ||
|
|
abd3c24562 | ||
|
|
f4e64ca8b3 | ||
|
|
97fde371d9 | ||
|
|
85bbb9cb15 | ||
|
|
1d34b4aff7 | ||
|
|
dc8c50c07a | ||
|
|
4ac490c6b4 | ||
|
|
0d548c7df9 | ||
|
|
8ec5a5bd4b | ||
|
|
2e8bcc09e6 | ||
|
|
29a304e2c8 | ||
|
|
b1adc37920 | ||
|
|
03fac3ec06 |
@@ -12,7 +12,7 @@ jobs:
|
|||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.2'
|
node-version: '22.19.0'
|
||||||
- name: Build Web
|
- name: Build Web
|
||||||
run: |
|
run: |
|
||||||
cd frontend && npm install && npm run build:pro
|
cd frontend && npm install && npm run build:pro
|
||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.24'
|
||||||
- name: Build Release
|
- name: Build Release
|
||||||
uses: goreleaser/goreleaser-action@v6
|
uses: goreleaser/goreleaser-action@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.2'
|
node-version: '22.19.0'
|
||||||
- name: Build Web
|
- name: Build Web
|
||||||
run: |
|
run: |
|
||||||
cd frontend && npm install && npm run build:pro
|
cd frontend && npm install && npm run build:pro
|
||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.24'
|
||||||
- name: Build Release
|
- name: Build Release
|
||||||
uses: goreleaser/goreleaser-action@v6
|
uses: goreleaser/goreleaser-action@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -31,4 +31,4 @@ build_backend_on_darwin:
|
|||||||
|
|
||||||
build_all: build_frontend build_backend_on_linux
|
build_all: build_frontend build_backend_on_linux
|
||||||
|
|
||||||
build_on_local: clean_assets build_frontend build_backend_on_darwin upx_bin
|
build_on_local: clean_assets build_frontend build_backend_on_darwin
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ package v1
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/captcha"
|
"github.com/1Panel-dev/1Panel/backend/utils/captcha"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,7 +28,9 @@ func (b *BaseApi) Login(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.AuthMethod != "jwt" && !req.IgnoreCaptcha {
|
ip := common.GetRealClientIP(c)
|
||||||
|
needCaptcha := global.IPTracker.NeedCaptcha(ip)
|
||||||
|
if needCaptcha {
|
||||||
if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil {
|
if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
@@ -48,9 +52,11 @@ func (b *BaseApi) Login(c *gin.Context) {
|
|||||||
user, err := authService.Login(c, req, string(entrance))
|
user, err := authService.Login(c, req, string(entrance))
|
||||||
go saveLoginLogs(c, err)
|
go saveLoginLogs(c, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
global.IPTracker.SetNeedCaptcha(ip)
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
global.IPTracker.Clear(ip)
|
||||||
helper.SuccessWithData(c, user)
|
helper.SuccessWithData(c, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,16 +140,21 @@ func (b *BaseApi) CheckIsIntl(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Auth
|
// @Tags Auth
|
||||||
// @Summary Load System Language
|
// @Summary Load System Setting for login
|
||||||
// @Success 200 {string} language
|
// @Success 200 {object} dto.LoginSetting
|
||||||
// @Router /auth/language [get]
|
// @Router /auth/setting [get]
|
||||||
func (b *BaseApi) GetLanguage(c *gin.Context) {
|
func (b *BaseApi) GetAuthSetting(c *gin.Context) {
|
||||||
settingInfo, err := settingService.GetSettingInfo()
|
settingInfo, err := settingService.GetSettingInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, settingInfo.Language)
|
ip := common.GetRealClientIP(c)
|
||||||
|
needCaptcha := global.IPTracker.NeedCaptcha(ip)
|
||||||
|
helper.SuccessWithData(c, dto.LoginSetting{
|
||||||
|
NeedCaptcha: needCaptcha,
|
||||||
|
Language: settingInfo.Language,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveLoginLogs(c *gin.Context, err error) {
|
func saveLoginLogs(c *gin.Context, err error) {
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ func (b *BaseApi) CheckRepoStatus(c *gin.Context) {
|
|||||||
// @Tags Container Image-repo
|
// @Tags Container Image-repo
|
||||||
// @Summary Create image repo
|
// @Summary Create image repo
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ImageRepoDelete true "request"
|
// @Param request body dto.ImageRepoCreate true "request"
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
@@ -99,20 +99,20 @@ func (b *BaseApi) CreateRepo(c *gin.Context) {
|
|||||||
// @Tags Container Image-repo
|
// @Tags Container Image-repo
|
||||||
// @Summary Delete image repo
|
// @Summary Delete image repo
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ImageRepoDelete true "request"
|
// @Param request body dto.OperateByID true "request"
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/repo/del [post]
|
// @Router /containers/repo/del [post]
|
||||||
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"image_repos","output_column":"name","output_value":"names"}],"formatZH":"删除镜像仓库 [names]","formatEN":"delete image repo [names]"}
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"image_repos","output_column":"name","output_value":"name"}],"formatZH":"删除镜像仓库 [name]","formatEN":"delete image repo [name]"}
|
||||||
func (b *BaseApi) DeleteRepo(c *gin.Context) {
|
func (b *BaseApi) DeleteRepo(c *gin.Context) {
|
||||||
var req dto.ImageRepoDelete
|
var req dto.OperateByID
|
||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := imageRepoService.BatchDelete(req); err != nil {
|
if err := imageRepoService.Delete(req); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-7
@@ -23,13 +23,12 @@ type MfaCredential struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Login struct {
|
type Login struct {
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
Password string `json:"password" validate:"required"`
|
Password string `json:"password" validate:"required"`
|
||||||
IgnoreCaptcha bool `json:"ignoreCaptcha"`
|
Captcha string `json:"captcha"`
|
||||||
Captcha string `json:"captcha"`
|
CaptchaID string `json:"captchaID"`
|
||||||
CaptchaID string `json:"captchaID"`
|
AuthMethod string `json:"authMethod" validate:"required,oneof=jwt session"`
|
||||||
AuthMethod string `json:"authMethod" validate:"required,oneof=jwt session"`
|
Language string `json:"language" validate:"required,oneof=zh en tw ja ko ru ms 'pt-BR'"`
|
||||||
Language string `json:"language" validate:"required,oneof=zh en tw ja ko ru ms 'pt-BR'"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MFALogin struct {
|
type MFALogin struct {
|
||||||
@@ -38,3 +37,8 @@ type MFALogin struct {
|
|||||||
Code string `json:"code" validate:"required"`
|
Code string `json:"code" validate:"required"`
|
||||||
AuthMethod string `json:"authMethod"`
|
AuthMethod string `json:"authMethod"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LoginSetting struct {
|
||||||
|
NeedCaptcha bool `json:"needCaptcha"`
|
||||||
|
Language string `json:"language"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -442,17 +442,14 @@ func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, f
|
|||||||
return appInstallResourceRepo.DeleteBy(ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
return appInstallResourceRepo.DeleteBy(ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string, error) {
|
func handleUpgradeCompose(install model.AppInstall, detail model.AppDetail) (map[string]interface{}, error) {
|
||||||
if detail.DockerCompose == "" {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
composeMap := make(map[string]interface{})
|
composeMap := make(map[string]interface{})
|
||||||
if err := yaml.Unmarshal([]byte(detail.DockerCompose), &composeMap); err != nil {
|
if err := yaml.Unmarshal([]byte(detail.DockerCompose), &composeMap); err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
value, ok := composeMap["services"]
|
value, ok := composeMap["services"]
|
||||||
if !ok || value == nil {
|
if !ok || value == nil {
|
||||||
return "", buserr.New(constant.ErrFileParse)
|
return nil, buserr.New("ErrFileParse")
|
||||||
}
|
}
|
||||||
servicesMap := value.(map[string]interface{})
|
servicesMap := value.(map[string]interface{})
|
||||||
if len(servicesMap) == 1 {
|
if len(servicesMap) == 1 {
|
||||||
@@ -470,6 +467,34 @@ func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string
|
|||||||
delete(servicesMap, oldServiceName)
|
delete(servicesMap, oldServiceName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
serviceValue := servicesMap[install.ServiceName].(map[string]interface{})
|
||||||
|
|
||||||
|
oldComposeMap := make(map[string]interface{})
|
||||||
|
if err := yaml.Unmarshal([]byte(install.DockerCompose), &oldComposeMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
oldValue, ok := oldComposeMap["services"]
|
||||||
|
if !ok || oldValue == nil {
|
||||||
|
return nil, buserr.New("ErrFileParse")
|
||||||
|
}
|
||||||
|
oldValueMap := oldValue.(map[string]interface{})
|
||||||
|
oldServiceValue := oldValueMap[install.ServiceName].(map[string]interface{})
|
||||||
|
if oldServiceValue["deploy"] != nil {
|
||||||
|
serviceValue["deploy"] = oldServiceValue["deploy"]
|
||||||
|
}
|
||||||
|
servicesMap[install.ServiceName] = serviceValue
|
||||||
|
composeMap["services"] = servicesMap
|
||||||
|
return composeMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string, error) {
|
||||||
|
if detail.DockerCompose == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
composeMap, err := handleUpgradeCompose(install, detail)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
envs := make(map[string]interface{})
|
envs := make(map[string]interface{})
|
||||||
if err := json.Unmarshal([]byte(install.Env), &envs); err != nil {
|
if err := json.Unmarshal([]byte(install.Env), &envs); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|||||||
@@ -413,9 +413,9 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
|
|||||||
if strings.HasSuffix(dirStr, "/") && dirStr != "/" {
|
if strings.HasSuffix(dirStr, "/") && dirStr != "/" {
|
||||||
dirStr = dirStr[:strings.LastIndex(dirStr, "/")]
|
dirStr = dirStr[:strings.LastIndex(dirStr, "/")]
|
||||||
}
|
}
|
||||||
if err := copyDir(oldDir, dirStr); err != nil {
|
if err := changeLocalBackup(oldDir, dirStr); err != nil {
|
||||||
_ = backupRepo.Update(req.ID, map[string]interface{}{"vars": oldVars})
|
_ = backupRepo.Update(req.ID, map[string]interface{}{"vars": oldVars})
|
||||||
return err
|
return fmt.Errorf("copy dir from %s to %s failed, err: %v", oldDir, dirStr, err)
|
||||||
}
|
}
|
||||||
global.CONF.System.Backup = dirStr
|
global.CONF.System.Backup = dirStr
|
||||||
}
|
}
|
||||||
@@ -677,3 +677,44 @@ func (u *BackupService) Run() {
|
|||||||
}).Error
|
}).Error
|
||||||
global.LOG.Info("Successfully refreshed OneDrive token.")
|
global.LOG.Info("Successfully refreshed OneDrive token.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func changeLocalBackup(oldPath, newPath string) error {
|
||||||
|
fileOp := fileUtils.NewFileOp()
|
||||||
|
if fileOp.Stat(path.Join(oldPath, "app")) {
|
||||||
|
if err := fileOp.CopyDir(path.Join(oldPath, "app"), newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fileOp.Stat(path.Join(oldPath, "database")) {
|
||||||
|
if err := fileOp.CopyDir(path.Join(oldPath, "database"), newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fileOp.Stat(path.Join(oldPath, "directory")) {
|
||||||
|
if err := fileOp.CopyDir(path.Join(oldPath, "directory"), newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fileOp.Stat(path.Join(oldPath, "system_snapshot")) {
|
||||||
|
if err := fileOp.CopyDir(path.Join(oldPath, "system_snapshot"), newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fileOp.Stat(path.Join(oldPath, "website")) {
|
||||||
|
if err := fileOp.CopyDir(path.Join(oldPath, "website"), newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fileOp.Stat(path.Join(oldPath, "log")) {
|
||||||
|
if err := fileOp.CopyDir(path.Join(oldPath, "log"), newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "app"))
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "database"))
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "directory"))
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "system_snapshot"))
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "website"))
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "log"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
|
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@@ -27,7 +26,7 @@ type IImageRepoService interface {
|
|||||||
Login(req dto.OperateByID) error
|
Login(req dto.OperateByID) error
|
||||||
Create(req dto.ImageRepoCreate) error
|
Create(req dto.ImageRepoCreate) error
|
||||||
Update(req dto.ImageRepoUpdate) error
|
Update(req dto.ImageRepoUpdate) error
|
||||||
BatchDelete(req dto.ImageRepoDelete) error
|
Delete(req dto.OperateByID) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIImageRepoService() IImageRepoService {
|
func NewIImageRepoService() IImageRepoService {
|
||||||
@@ -90,30 +89,7 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
|
|||||||
if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil {
|
if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil {
|
||||||
return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err)
|
return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err)
|
||||||
}
|
}
|
||||||
if err := validateDockerConfig(); err != nil {
|
if err := stopBeforeUpdateRepo(); err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := restartDocker(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ticker := time.NewTicker(3 * time.Second)
|
|
||||||
defer ticker.Stop()
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
|
|
||||||
if err := func() error {
|
|
||||||
for range ticker.C {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
cancel()
|
|
||||||
return errors.New("the docker service cannot be restarted")
|
|
||||||
default:
|
|
||||||
if ok, _ := systemctl.IsActive("docker"); ok {
|
|
||||||
global.LOG.Info("docker restart with new conf successful!")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}(); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,15 +107,32 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
|
|||||||
return imageRepoRepo.Create(&imageRepo)
|
return imageRepoRepo.Create(&imageRepo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ImageRepoService) BatchDelete(req dto.ImageRepoDelete) error {
|
func (u *ImageRepoService) Delete(req dto.OperateByID) error {
|
||||||
for _, id := range req.Ids {
|
if req.ID == 1 {
|
||||||
if id == 1 {
|
return errors.New("The default value cannot be edit !")
|
||||||
return errors.New("The default value cannot be edit !")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err := imageRepoRepo.Delete(commonRepo.WithIdsIn(req.Ids)); err != nil {
|
itemRepo, _ := imageRepoRepo.Get(commonRepo.WithByID(req.ID))
|
||||||
|
if itemRepo.ID == 0 {
|
||||||
|
return buserr.New("ErrRecordNotFound")
|
||||||
|
}
|
||||||
|
if itemRepo.Auth {
|
||||||
|
_, _ = cmd.Execf("docker logout -i %s", itemRepo.DownloadUrl)
|
||||||
|
}
|
||||||
|
if itemRepo.Protocol == "https" {
|
||||||
|
return imageRepoRepo.Delete(commonRepo.WithByID(req.ID))
|
||||||
|
}
|
||||||
|
if err := u.handleRegistries("", itemRepo.DownloadUrl, "delete"); err != nil {
|
||||||
|
return fmt.Errorf("delete registry %s failed, err: %v", itemRepo.DownloadUrl, err)
|
||||||
|
}
|
||||||
|
if err := validateDockerConfig(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := imageRepoRepo.Delete(commonRepo.WithByID(req.ID)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
_ = restartDocker()
|
||||||
|
}()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,37 +147,39 @@ func (u *ImageRepoService) Update(req dto.ImageRepoUpdate) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
needRestart := false
|
||||||
if repo.Protocol == "http" && req.Protocol == "https" {
|
if repo.Protocol == "http" && req.Protocol == "https" {
|
||||||
if err := u.handleRegistries("", repo.DownloadUrl, "delete"); err != nil {
|
if err := u.handleRegistries("", repo.DownloadUrl, "delete"); err != nil {
|
||||||
return fmt.Errorf("delete registry %s failed, err: %v", repo.DownloadUrl, err)
|
return fmt.Errorf("delete registry %s failed, err: %v", repo.DownloadUrl, err)
|
||||||
}
|
}
|
||||||
|
needRestart = true
|
||||||
}
|
}
|
||||||
if repo.Protocol == "http" && req.Protocol == "http" {
|
if repo.Protocol == "http" && req.Protocol == "http" {
|
||||||
if err := u.handleRegistries(req.DownloadUrl, repo.DownloadUrl, "update"); err != nil {
|
if repo.DownloadUrl != req.DownloadUrl {
|
||||||
return fmt.Errorf("update registry %s => %s failed, err: %v", repo.DownloadUrl, req.DownloadUrl, err)
|
if err := u.handleRegistries(req.DownloadUrl, repo.DownloadUrl, "update"); err != nil {
|
||||||
|
return fmt.Errorf("update registry %s => %s failed, err: %v", repo.DownloadUrl, req.DownloadUrl, err)
|
||||||
|
}
|
||||||
|
needRestart = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if repo.Protocol == "https" && req.Protocol == "http" {
|
if repo.Protocol == "https" && req.Protocol == "http" {
|
||||||
if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil {
|
if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil {
|
||||||
return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err)
|
return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err)
|
||||||
}
|
}
|
||||||
|
needRestart = true
|
||||||
}
|
}
|
||||||
if repo.Auth != req.Auth || repo.DownloadUrl != req.DownloadUrl {
|
if needRestart {
|
||||||
if repo.Auth {
|
if err := stopBeforeUpdateRepo(); err != nil {
|
||||||
_, _ = cmd.ExecWithCheck("docker", "logout", repo.DownloadUrl)
|
return err
|
||||||
}
|
|
||||||
if req.Auth {
|
|
||||||
if err := u.CheckConn(req.DownloadUrl, req.Username, req.Password); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if repo.Auth {
|
||||||
if err := validateDockerConfig(); err != nil {
|
_, _ = cmd.Execf("docker logout -i %s", repo.DownloadUrl)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
if err := restartDocker(); err != nil {
|
if req.Auth {
|
||||||
return err
|
if err := u.CheckConn(req.DownloadUrl, req.Username, req.Password); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
upMap := make(map[string]interface{})
|
upMap := make(map[string]interface{})
|
||||||
@@ -256,3 +251,34 @@ func (u *ImageRepoService) handleRegistries(newHost, delHost, handle string) err
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stopBeforeUpdateRepo() error {
|
||||||
|
if err := validateDockerConfig(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := restartDocker(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ticker := time.NewTicker(3 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
||||||
|
if err := func() error {
|
||||||
|
for range ticker.C {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
cancel()
|
||||||
|
return errors.New("the docker service cannot be restarted")
|
||||||
|
default:
|
||||||
|
stdout, err := cmd.Exec("systemctl is-active docker")
|
||||||
|
if string(stdout) == "active\n" && err == nil {
|
||||||
|
global.LOG.Info("docker restart with new conf successful!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package global
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1Panel-dev/1Panel/backend/configs"
|
"github.com/1Panel-dev/1Panel/backend/configs"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/init/auth"
|
||||||
"github.com/1Panel-dev/1Panel/backend/init/cache/badger_db"
|
"github.com/1Panel-dev/1Panel/backend/init/cache/badger_db"
|
||||||
"github.com/1Panel-dev/1Panel/backend/init/session/psession"
|
"github.com/1Panel-dev/1Panel/backend/init/session/psession"
|
||||||
"github.com/dgraph-io/badger/v4"
|
"github.com/dgraph-io/badger/v4"
|
||||||
@@ -28,6 +29,8 @@ var (
|
|||||||
MonitorCronID cron.EntryID
|
MonitorCronID cron.EntryID
|
||||||
OneDriveCronID cron.EntryID
|
OneDriveCronID cron.EntryID
|
||||||
|
|
||||||
|
IPTracker *auth.IPTracker
|
||||||
|
|
||||||
I18n *i18n.Localizer
|
I18n *i18n.Localizer
|
||||||
I18nForCmd *i18n.Localizer
|
I18nForCmd *i18n.Localizer
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MaxIPCount = 100
|
||||||
|
ExpireDuration = 30 * time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
type IPRecord struct {
|
||||||
|
NeedCaptcha bool
|
||||||
|
LastUpdate time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type IPTracker struct {
|
||||||
|
records map[string]*IPRecord
|
||||||
|
ipOrder []string
|
||||||
|
mu sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIPTracker() *IPTracker {
|
||||||
|
return &IPTracker{
|
||||||
|
records: make(map[string]*IPRecord),
|
||||||
|
ipOrder: make([]string, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *IPTracker) NeedCaptcha(ip string) bool {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
|
||||||
|
record, exists := t.records[ip]
|
||||||
|
if !exists {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if time.Since(record.LastUpdate) > ExpireDuration {
|
||||||
|
t.removeIPUnsafe(ip)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return record.NeedCaptcha
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *IPTracker) SetNeedCaptcha(ip string) {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
|
||||||
|
if record, exists := t.records[ip]; exists {
|
||||||
|
if time.Since(record.LastUpdate) > ExpireDuration {
|
||||||
|
t.removeIPUnsafe(ip)
|
||||||
|
} else {
|
||||||
|
record.NeedCaptcha = true
|
||||||
|
record.LastUpdate = time.Now()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(t.records) >= MaxIPCount {
|
||||||
|
t.removeOldestUnsafe()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.records[ip] = &IPRecord{
|
||||||
|
NeedCaptcha: true,
|
||||||
|
LastUpdate: time.Now(),
|
||||||
|
}
|
||||||
|
t.ipOrder = append(t.ipOrder, ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *IPTracker) Clear(ip string) {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
|
||||||
|
t.removeIPUnsafe(ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *IPTracker) removeIPUnsafe(ip string) {
|
||||||
|
delete(t.records, ip)
|
||||||
|
|
||||||
|
for i, storedIP := range t.ipOrder {
|
||||||
|
if storedIP == ip {
|
||||||
|
t.ipOrder = append(t.ipOrder[:i], t.ipOrder[i+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *IPTracker) removeOldestUnsafe() {
|
||||||
|
if len(t.ipOrder) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
oldestIP := t.ipOrder[0]
|
||||||
|
delete(t.records, oldestIP)
|
||||||
|
t.ipOrder = t.ipOrder[1:]
|
||||||
|
}
|
||||||
@@ -109,6 +109,8 @@ func Init() {
|
|||||||
|
|
||||||
migrations.AddMcpServer,
|
migrations.AddMcpServer,
|
||||||
migrations.AddPbootCMSPHPExtensions,
|
migrations.AddPbootCMSPHPExtensions,
|
||||||
|
migrations.DeleteV2Openresty,
|
||||||
|
migrations.UpdateOnedrive,
|
||||||
})
|
})
|
||||||
if err := m.Migrate(); err != nil {
|
if err := m.Migrate(); err != nil {
|
||||||
global.LOG.Error(err)
|
global.LOG.Error(err)
|
||||||
|
|||||||
@@ -485,3 +485,27 @@ var AddPbootCMSPHPExtensions = &gormigrate.Migration{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var DeleteV2Openresty = &gormigrate.Migration{
|
||||||
|
ID: "20250701-delete-v2-openresty",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
return tx.Where("version = '1.27.1.2-0-1-focal'").Delete(&model.AppDetail{}).Error
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var UpdateOnedrive = &gormigrate.Migration{
|
||||||
|
ID: "20250704-update-onedrive",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
if err := tx.Model(&model.Setting{}).
|
||||||
|
Where("key = ?", "OneDriveID").
|
||||||
|
Update("value", "NTQ0NmNmZTMtNGM3OS00N2EwLWFlMjUtZmM2NDU0NzhlMmQ5").Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := tx.Model(&model.Setting{}).
|
||||||
|
Where("key = ?", "OneDriveSc").
|
||||||
|
Update("value", "bGRlOFF+WEVrR1M0b25Vb1VsRWpMYzE2MW9rTXZEM25KdnZ1MGN6MA==").Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,14 +3,15 @@ package router
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/service"
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
|
||||||
"github.com/1Panel-dev/1Panel/cmd/server/res"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/service"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/cmd/server/res"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/i18n"
|
"github.com/1Panel-dev/1Panel/backend/i18n"
|
||||||
"github.com/1Panel-dev/1Panel/backend/middleware"
|
"github.com/1Panel-dev/1Panel/backend/middleware"
|
||||||
@@ -160,7 +161,7 @@ func setWebStatic(rootRouter *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Routers() *gin.Engine {
|
func Routers() *gin.Engine {
|
||||||
Router = gin.Default()
|
Router = gin.New()
|
||||||
Router.Use(middleware.OperationLog())
|
Router.Use(middleware.OperationLog())
|
||||||
// Router.Use(middleware.CSRF())
|
// Router.Use(middleware.CSRF())
|
||||||
// Router.Use(middleware.LoadCsrfToken())
|
// Router.Use(middleware.LoadCsrfToken())
|
||||||
|
|||||||
@@ -8,11 +8,17 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func WhiteAllow() gin.HandlerFunc {
|
func WhiteAllow() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
clientIP := common.GetRealClientIP(c)
|
||||||
|
if common.IsPrivateIP(clientIP) {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
settingRepo := repo.NewISettingRepo()
|
settingRepo := repo.NewISettingRepo()
|
||||||
status, err := settingRepo.Get(settingRepo.WithByKey("AllowIPs"))
|
status, err := settingRepo.Get(settingRepo.WithByKey("AllowIPs"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -24,7 +30,6 @@ func WhiteAllow() gin.HandlerFunc {
|
|||||||
c.Next()
|
c.Next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
clientIP := c.ClientIP()
|
|
||||||
for _, ip := range strings.Split(status.Value, ",") {
|
for _, ip := range strings.Split(status.Value, ",") {
|
||||||
if len(ip) == 0 {
|
if len(ip) == 0 {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func (s *BaseRouter) InitRouter(Router *gin.RouterGroup) {
|
|||||||
baseRouter.POST("/login", baseApi.Login)
|
baseRouter.POST("/login", baseApi.Login)
|
||||||
baseRouter.POST("/logout", baseApi.LogOut)
|
baseRouter.POST("/logout", baseApi.LogOut)
|
||||||
baseRouter.GET("/demo", baseApi.CheckIsDemo)
|
baseRouter.GET("/demo", baseApi.CheckIsDemo)
|
||||||
baseRouter.GET("/language", baseApi.GetLanguage)
|
baseRouter.GET("/setting", baseApi.GetAuthSetting)
|
||||||
baseRouter.GET("/intl", baseApi.CheckIsIntl)
|
baseRouter.GET("/intl", baseApi.CheckIsIntl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/i18n"
|
"github.com/1Panel-dev/1Panel/backend/i18n"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/init/app"
|
"github.com/1Panel-dev/1Panel/backend/init/app"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/init/auth"
|
||||||
"github.com/1Panel-dev/1Panel/backend/init/business"
|
"github.com/1Panel-dev/1Panel/backend/init/business"
|
||||||
"github.com/1Panel-dev/1Panel/backend/init/lang"
|
"github.com/1Panel-dev/1Panel/backend/init/lang"
|
||||||
|
|
||||||
@@ -52,6 +53,7 @@ func Start() {
|
|||||||
business.Init()
|
business.Init()
|
||||||
|
|
||||||
rootRouter := router.Routers()
|
rootRouter := router.Routers()
|
||||||
|
global.IPTracker = auth.NewIPTracker()
|
||||||
|
|
||||||
tcpItem := "tcp4"
|
tcpItem := "tcp4"
|
||||||
if global.CONF.System.Ipv6 == "enable" {
|
if global.CONF.System.Ipv6 == "enable" {
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ import (
|
|||||||
var store = base64Captcha.DefaultMemStore
|
var store = base64Captcha.DefaultMemStore
|
||||||
|
|
||||||
func VerifyCode(codeID string, code string) error {
|
func VerifyCode(codeID string, code string) error {
|
||||||
if codeID == "" {
|
|
||||||
return constant.ErrCaptchaCode
|
|
||||||
}
|
|
||||||
vv := store.Get(codeID, true)
|
vv := store.Get(codeID, true)
|
||||||
vv = strings.TrimSpace(vv)
|
vv = strings.TrimSpace(vv)
|
||||||
code = strings.TrimSpace(code)
|
code = strings.TrimSpace(code)
|
||||||
|
|
||||||
|
if codeID == "" || code == "" {
|
||||||
|
return constant.ErrCaptchaCode
|
||||||
|
}
|
||||||
if strings.EqualFold(vv, code) {
|
if strings.EqualFold(vv, code) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -426,3 +426,19 @@ func HandleIPList(content string) ([]string, error) {
|
|||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetRealClientIP(c *gin.Context) string {
|
||||||
|
addr := c.Request.RemoteAddr
|
||||||
|
if ip, _, err := net.SplitHostPort(addr); err == nil {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsPrivateIP(ipStr string) bool {
|
||||||
|
ip := net.ParseIP(ipStr)
|
||||||
|
if ip == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return ip.IsPrivate() || ip.IsLoopback()
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,14 +3,10 @@ package ssl
|
|||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/go-acme/lego/v4/providers/dns/westcn"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/providers/dns/freemyip"
|
|
||||||
"github.com/go-acme/lego/v4/providers/dns/rainyun"
|
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/go-acme/lego/v4/acme"
|
"github.com/go-acme/lego/v4/acme"
|
||||||
"github.com/go-acme/lego/v4/acme/api"
|
"github.com/go-acme/lego/v4/acme/api"
|
||||||
@@ -23,13 +19,17 @@ import (
|
|||||||
"github.com/go-acme/lego/v4/providers/dns/cloudflare"
|
"github.com/go-acme/lego/v4/providers/dns/cloudflare"
|
||||||
"github.com/go-acme/lego/v4/providers/dns/cloudns"
|
"github.com/go-acme/lego/v4/providers/dns/cloudns"
|
||||||
"github.com/go-acme/lego/v4/providers/dns/dnspod"
|
"github.com/go-acme/lego/v4/providers/dns/dnspod"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/freemyip"
|
||||||
"github.com/go-acme/lego/v4/providers/dns/godaddy"
|
"github.com/go-acme/lego/v4/providers/dns/godaddy"
|
||||||
"github.com/go-acme/lego/v4/providers/dns/huaweicloud"
|
"github.com/go-acme/lego/v4/providers/dns/huaweicloud"
|
||||||
"github.com/go-acme/lego/v4/providers/dns/namecheap"
|
"github.com/go-acme/lego/v4/providers/dns/namecheap"
|
||||||
"github.com/go-acme/lego/v4/providers/dns/namedotcom"
|
"github.com/go-acme/lego/v4/providers/dns/namedotcom"
|
||||||
"github.com/go-acme/lego/v4/providers/dns/namesilo"
|
"github.com/go-acme/lego/v4/providers/dns/namesilo"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/porkbun"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/rainyun"
|
||||||
"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
|
"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
|
||||||
"github.com/go-acme/lego/v4/providers/dns/volcengine"
|
"github.com/go-acme/lego/v4/providers/dns/volcengine"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/westcn"
|
||||||
"github.com/go-acme/lego/v4/providers/http/webroot"
|
"github.com/go-acme/lego/v4/providers/http/webroot"
|
||||||
"github.com/go-acme/lego/v4/registration"
|
"github.com/go-acme/lego/v4/registration"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -87,6 +87,7 @@ const (
|
|||||||
HuaweiCloud DnsType = "HuaweiCloud"
|
HuaweiCloud DnsType = "HuaweiCloud"
|
||||||
RainYun DnsType = "RainYun"
|
RainYun DnsType = "RainYun"
|
||||||
WestCN DnsType = "WestCN"
|
WestCN DnsType = "WestCN"
|
||||||
|
PorkBun DnsType = "PorkBun"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DNSParam struct {
|
type DNSParam struct {
|
||||||
@@ -244,6 +245,14 @@ func (c *AcmeClient) UseDns(dnsType DnsType, params string, websiteSSL model.Web
|
|||||||
westcnConfig.PollingInterval = pollingInterval
|
westcnConfig.PollingInterval = pollingInterval
|
||||||
westcnConfig.TTL = ttl
|
westcnConfig.TTL = ttl
|
||||||
p, err = westcn.NewDNSProviderConfig(westcnConfig)
|
p, err = westcn.NewDNSProviderConfig(westcnConfig)
|
||||||
|
case PorkBun:
|
||||||
|
porkbunConfig := porkbun.NewDefaultConfig()
|
||||||
|
porkbunConfig.APIKey = param.APIkey
|
||||||
|
porkbunConfig.SecretAPIKey = param.SecretKey
|
||||||
|
porkbunConfig.PropagationTimeout = propagationTimeout
|
||||||
|
porkbunConfig.PollingInterval = pollingInterval
|
||||||
|
porkbunConfig.TTL = ttl
|
||||||
|
p, err = porkbun.NewDNSProviderConfig(porkbunConfig)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
+5
-5
@@ -6,18 +6,18 @@ command -v wget >/dev/null || {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if [ ! -f "1pctl" ]; then
|
if [ ! -f "1pctl" ]; then
|
||||||
wget https://github.com/1Panel-dev/installer/raw/main/1pctl
|
wget https://github.com/1Panel-dev/installer/raw/v1/1pctl
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f "install.sh" ]; then
|
if [ ! -f "install.sh" ]; then
|
||||||
wget https://github.com/1Panel-dev/installer/raw/main/install.sh
|
wget https://github.com/1Panel-dev/installer/raw/v1/install.sh
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -d "initscript" ]; then
|
if [ ! -d "initscript" ]; then
|
||||||
wget https://github.com/1Panel-dev/installer/raw/main/initscript/1panel.service
|
wget https://github.com/1Panel-dev/installer/raw/v1/initscript/1panel.service
|
||||||
mkdir -p initscript && cd initscript
|
mkdir -p initscript && cd initscript
|
||||||
for file in 1panel.service 1paneld.init 1paneld.openrc 1paneld.procd; do
|
for file in 1panel.service 1paneld.init 1paneld.openrc 1paneld.procd; do
|
||||||
wget -q https://github.com/1Panel-dev/installer/raw/main/initscript/$file
|
wget -q https://github.com/1Panel-dev/installer/raw/v1/initscript/$file
|
||||||
done
|
done
|
||||||
cd ..
|
cd ..
|
||||||
fi
|
fi
|
||||||
@@ -25,7 +25,7 @@ fi
|
|||||||
if [ ! -d "lang" ]; then
|
if [ ! -d "lang" ]; then
|
||||||
mkdir -p lang && cd lang
|
mkdir -p lang && cd lang
|
||||||
for lang in en fa pt-BR ru zh; do
|
for lang in en fa pt-BR ru zh; do
|
||||||
wget -q https://github.com/1Panel-dev/installer/raw/main/lang/$lang.sh
|
wget -q https://github.com/1Panel-dev/installer/raw/v1/lang/$lang.sh
|
||||||
done
|
done
|
||||||
cd ..
|
cd ..
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -38,8 +38,9 @@
|
|||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
"codemirror": "^6.0.1",
|
"codemirror": "^6.0.1",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
|
"dompurify": "^3.3.1",
|
||||||
"echarts": "^5.5.0",
|
"echarts": "^5.5.0",
|
||||||
"element-plus": "^2.7.5",
|
"element-plus": "2.9.9",
|
||||||
"fit2cloud-ui-plus": "^1.2.0",
|
"fit2cloud-ui-plus": "^1.2.0",
|
||||||
"highlight.js": "^11.9.0",
|
"highlight.js": "^11.9.0",
|
||||||
"js-base64": "^3.7.7",
|
"js-base64": "^3.7.7",
|
||||||
@@ -64,8 +65,8 @@
|
|||||||
"@types/node": "^20.15.0",
|
"@types/node": "^20.15.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.22.0",
|
"@typescript-eslint/eslint-plugin": "^5.22.0",
|
||||||
"@typescript-eslint/parser": "^5.22.0",
|
"@typescript-eslint/parser": "^5.22.0",
|
||||||
"@vitejs/plugin-vue": "^5.0.5",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@vitejs/plugin-vue-jsx": "^4.0.0",
|
"@vitejs/plugin-vue-jsx": "^5.1.1",
|
||||||
"autoprefixer": "^10.4.7",
|
"autoprefixer": "^10.4.7",
|
||||||
"commitizen": "^4.2.4",
|
"commitizen": "^4.2.4",
|
||||||
"eslint": "^8.43.0",
|
"eslint": "^8.43.0",
|
||||||
@@ -84,7 +85,7 @@
|
|||||||
"typescript": "^4.5.4",
|
"typescript": "^4.5.4",
|
||||||
"unplugin-auto-import": "^0.16.4",
|
"unplugin-auto-import": "^0.16.4",
|
||||||
"unplugin-vue-components": "^0.25.0",
|
"unplugin-vue-components": "^0.25.0",
|
||||||
"vite": "^6.0.7",
|
"vite": "^7.1.5",
|
||||||
"vite-plugin-compression": "^0.5.1",
|
"vite-plugin-compression": "^0.5.1",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-plugin-html": "^3.2.2",
|
"vite-plugin-html": "^3.2.2",
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ export namespace Login {
|
|||||||
export interface ReqLoginForm {
|
export interface ReqLoginForm {
|
||||||
name: string;
|
name: string;
|
||||||
password: string;
|
password: string;
|
||||||
ignoreCaptcha: boolean;
|
|
||||||
captcha: string;
|
captcha: string;
|
||||||
captchaID: string;
|
captchaID: string;
|
||||||
authMethod: string;
|
authMethod: string;
|
||||||
@@ -26,4 +25,8 @@ export namespace Login {
|
|||||||
export interface ResAuthButtons {
|
export interface ResAuthButtons {
|
||||||
[propName: string]: any;
|
[propName: string]: any;
|
||||||
}
|
}
|
||||||
|
export interface LoginSetting {
|
||||||
|
language: string;
|
||||||
|
needCaptcha: boolean;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,9 +212,6 @@ export namespace Container {
|
|||||||
password: string;
|
password: string;
|
||||||
auth: boolean;
|
auth: boolean;
|
||||||
}
|
}
|
||||||
export interface RepoDelete {
|
|
||||||
ids: Array<number>;
|
|
||||||
}
|
|
||||||
export interface RepoInfo {
|
export interface RepoInfo {
|
||||||
id: number;
|
id: number;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ export const checkIsDemo = () => {
|
|||||||
return http.get<boolean>('/auth/demo');
|
return http.get<boolean>('/auth/demo');
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getLanguage = () => {
|
export const getAuthSetting = () => {
|
||||||
return http.get<string>(`/auth/language`);
|
return http.get<Login.LoginSetting>(`/auth/setting`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const checkIsIntl = () => {
|
export const checkIsIntl = () => {
|
||||||
|
|||||||
@@ -135,8 +135,8 @@ export const createImageRepo = (params: Container.RepoCreate) => {
|
|||||||
export const updateImageRepo = (params: Container.RepoUpdate) => {
|
export const updateImageRepo = (params: Container.RepoUpdate) => {
|
||||||
return http.post(`/containers/repo/update`, params, TimeoutEnum.T_40S);
|
return http.post(`/containers/repo/update`, params, TimeoutEnum.T_40S);
|
||||||
};
|
};
|
||||||
export const deleteImageRepo = (params: Container.RepoDelete) => {
|
export const deleteImageRepo = (id: Number) => {
|
||||||
return http.post(`/containers/repo/del`, params, TimeoutEnum.T_40S);
|
return http.post(`/containers/repo/del`, { id: id }, TimeoutEnum.T_40S);
|
||||||
};
|
};
|
||||||
|
|
||||||
// composeTemplate
|
// composeTemplate
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<template>
|
||||||
|
<MdEditor previewOnly v-model="sanitizedReadMe" :theme="isDarkTheme ? 'dark' : 'light'" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import MdEditor from 'md-editor-v3';
|
||||||
|
import 'md-editor-v3/lib/style.css';
|
||||||
|
import DOMPurify from 'dompurify';
|
||||||
|
import { GlobalStore } from '@/store';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
const globalStore = GlobalStore();
|
||||||
|
const { isDarkTheme } = storeToRefs(globalStore);
|
||||||
|
const props = defineProps({
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const sanitizedReadMe = computed(() => {
|
||||||
|
return DOMPurify.sanitize(props.content);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
{{ upgradeInfo.testVersion }}
|
{{ upgradeInfo.testVersion }}
|
||||||
</el-radio>
|
</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
<MdEditor v-model="upgradeInfo.releaseNote" previewOnly :theme="isDarkTheme ? 'dark' : 'light'" />
|
<MarkDownEditor :content="upgradeInfo.releaseNote" />
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
@@ -81,10 +81,10 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||||
|
import MarkDownEditor from '@/components/mkdown-editor/index.vue';
|
||||||
|
|
||||||
import { getSettingInfo, loadReleaseNotes, loadUpgradeInfo, upgrade } from '@/api/modules/setting';
|
import { getSettingInfo, loadReleaseNotes, loadUpgradeInfo, upgrade } from '@/api/modules/setting';
|
||||||
import MdEditor from 'md-editor-v3';
|
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import 'md-editor-v3/lib/style.css';
|
|
||||||
import { MsgSuccess } from '@/utils/message';
|
import { MsgSuccess } from '@/utils/message';
|
||||||
import { copyText } from '@/utils/util';
|
import { copyText } from '@/utils/util';
|
||||||
import { onMounted, ref, computed } from 'vue';
|
import { onMounted, ref, computed } from 'vue';
|
||||||
@@ -93,7 +93,7 @@ import { ElMessageBox } from 'element-plus';
|
|||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
const globalStore = GlobalStore();
|
const globalStore = GlobalStore();
|
||||||
const { isDarkTheme, docsUrl } = storeToRefs(globalStore);
|
const { docsUrl } = storeToRefs(globalStore);
|
||||||
|
|
||||||
const mobile = computed(() => {
|
const mobile = computed(() => {
|
||||||
return globalStore.isMobile();
|
return globalStore.isMobile();
|
||||||
|
|||||||
@@ -212,6 +212,10 @@ export const DNSTypes = [
|
|||||||
label: i18n.global.t('website.westCN'),
|
label: i18n.global.t('website.westCN'),
|
||||||
value: 'WestCN',
|
value: 'WestCN',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'PorkBun',
|
||||||
|
value: 'PorkBun',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: i18n.global.t('website.volcengine'),
|
label: i18n.global.t('website.volcengine'),
|
||||||
value: 'Volcengine',
|
value: 'Volcengine',
|
||||||
|
|||||||
@@ -333,6 +333,7 @@ const message = {
|
|||||||
ssl: 'Certificate | Certificates',
|
ssl: 'Certificate | Certificates',
|
||||||
database: 'Database | Databases',
|
database: 'Database | Databases',
|
||||||
ai_tools: 'AI',
|
ai_tools: 'AI',
|
||||||
|
mcp: 'MCP',
|
||||||
container: 'Container | Containers',
|
container: 'Container | Containers',
|
||||||
cronjob: 'Cron Job | Cron Jobs',
|
cronjob: 'Cron Job | Cron Jobs',
|
||||||
host: 'Host | Hosts',
|
host: 'Host | Hosts',
|
||||||
@@ -833,7 +834,7 @@ const message = {
|
|||||||
|
|
||||||
repo: 'Registries',
|
repo: 'Registries',
|
||||||
createRepo: 'Add',
|
createRepo: 'Add',
|
||||||
createRepoHelper: 'Adding an HTTP-type repository requires restarting the Docker service.',
|
httpRepoHelper: 'Operating an HTTP-type repository requires restarting the Docker service.',
|
||||||
httpRepo: 'Choosing HTTP protocol requires restarting the Docker service to add it into insecure registries.',
|
httpRepo: 'Choosing HTTP protocol requires restarting the Docker service to add it into insecure registries.',
|
||||||
delInsecure: 'Deletion of credit',
|
delInsecure: 'Deletion of credit',
|
||||||
delInsecureHelper:
|
delInsecureHelper:
|
||||||
|
|||||||
@@ -333,6 +333,7 @@ const message = {
|
|||||||
ssl: '証明書|証明書',
|
ssl: '証明書|証明書',
|
||||||
database: 'データベース|データベース',
|
database: 'データベース|データベース',
|
||||||
ai_tools: 'AI',
|
ai_tools: 'AI',
|
||||||
|
mcp: 'MCP',
|
||||||
container: 'コンテナ|コンテナ',
|
container: 'コンテナ|コンテナ',
|
||||||
cronjob: 'クロンジョブ|クロンの仕事',
|
cronjob: 'クロンジョブ|クロンの仕事',
|
||||||
host: 'ホスト|ホスト',
|
host: 'ホスト|ホスト',
|
||||||
@@ -829,7 +830,7 @@ const message = {
|
|||||||
|
|
||||||
repo: 'レジストリ',
|
repo: 'レジストリ',
|
||||||
createRepo: '追加',
|
createRepo: '追加',
|
||||||
createRepoHelper: 'HTTPタイプのリポジトリを追加するにはDockerサービスの再起動が必要です。',
|
httpRepoHelper: 'HTTPタイプのリポジトリを操作するにはDockerサービスの再起動が必要です。',
|
||||||
httpRepo:
|
httpRepo:
|
||||||
'HTTPプロトコルを選択するには、Dockerサービスを再起動して不安定なレジストリに追加する必要があります。',
|
'HTTPプロトコルを選択するには、Dockerサービスを再起動して不安定なレジストリに追加する必要があります。',
|
||||||
delInsecure: 'クレジットの削除',
|
delInsecure: 'クレジットの削除',
|
||||||
|
|||||||
@@ -334,6 +334,7 @@ const message = {
|
|||||||
ssl: '인증서 | 인증서들',
|
ssl: '인증서 | 인증서들',
|
||||||
database: '데이터베이스 | 데이터베이스들',
|
database: '데이터베이스 | 데이터베이스들',
|
||||||
ai_tools: 'AI',
|
ai_tools: 'AI',
|
||||||
|
mcp: 'MCP',
|
||||||
container: '컨테이너 | 컨테이너들',
|
container: '컨테이너 | 컨테이너들',
|
||||||
cronjob: '크론 작업 | 크론 작업들',
|
cronjob: '크론 작업 | 크론 작업들',
|
||||||
host: '호스트 | 호스트들',
|
host: '호스트 | 호스트들',
|
||||||
@@ -819,7 +820,7 @@ const message = {
|
|||||||
|
|
||||||
repo: '레지스트리',
|
repo: '레지스트리',
|
||||||
createRepo: '추가',
|
createRepo: '추가',
|
||||||
createRepoHelper: 'HTTP 타입 저장소 추가 시 Docker 서비스 재시작이 필요합니다.',
|
httpRepoHelper: 'HTTP 타입 저장소 작업 시 Docker 서비스 재시작이 필요합니다.',
|
||||||
httpRepo: 'HTTP 프로토콜을 선택하면 Docker 서비스를 재시작하여 불안정한 레지스트리에 추가해야 합니다.',
|
httpRepo: 'HTTP 프로토콜을 선택하면 Docker 서비스를 재시작하여 불안정한 레지스트리에 추가해야 합니다.',
|
||||||
delInsecure: '신뢰할 수 없는 항목 삭제',
|
delInsecure: '신뢰할 수 없는 항목 삭제',
|
||||||
delInsecureHelper:
|
delInsecureHelper:
|
||||||
|
|||||||
@@ -340,6 +340,7 @@ const message = {
|
|||||||
ssl: 'Certificate | Certificates',
|
ssl: 'Certificate | Certificates',
|
||||||
database: 'Database | Databases',
|
database: 'Database | Databases',
|
||||||
ai_tools: 'AI',
|
ai_tools: 'AI',
|
||||||
|
mcp: 'MCP',
|
||||||
container: 'Container | Containers',
|
container: 'Container | Containers',
|
||||||
cronjob: 'Cron Job | Cron Jobs',
|
cronjob: 'Cron Job | Cron Jobs',
|
||||||
host: 'Host | Hosts',
|
host: 'Host | Hosts',
|
||||||
@@ -845,7 +846,7 @@ const message = {
|
|||||||
|
|
||||||
repo: 'Pendaftaran',
|
repo: 'Pendaftaran',
|
||||||
createRepo: 'Tambah',
|
createRepo: 'Tambah',
|
||||||
createRepoHelper: 'Menambah repositori jenis HTTP memerlukan mulakan semula perkhidmatan Docker.',
|
httpRepoHelper: 'Mengoperasikan repositori jenis HTTP memerlukan mulakan semula perkhidmatan Docker.',
|
||||||
httpRepo:
|
httpRepo:
|
||||||
'Memilih protokol HTTP memerlukan memulakan semula perkhidmatan Docker untuk menambahkannya ke pendaftaran tidak selamat.',
|
'Memilih protokol HTTP memerlukan memulakan semula perkhidmatan Docker untuk menambahkannya ke pendaftaran tidak selamat.',
|
||||||
delInsecure: 'Padamkan pendaftaran tidak selamat',
|
delInsecure: 'Padamkan pendaftaran tidak selamat',
|
||||||
|
|||||||
@@ -338,6 +338,7 @@ const message = {
|
|||||||
ssl: 'Certificado | Certificados',
|
ssl: 'Certificado | Certificados',
|
||||||
database: 'Banco de Dados | Bancos de Dados',
|
database: 'Banco de Dados | Bancos de Dados',
|
||||||
ai_tools: 'AI',
|
ai_tools: 'AI',
|
||||||
|
mcp: 'MCP',
|
||||||
container: 'Container | Containers',
|
container: 'Container | Containers',
|
||||||
cronjob: 'Tarefa Cron | Tarefas Cron',
|
cronjob: 'Tarefa Cron | Tarefas Cron',
|
||||||
host: 'Host | Hosts',
|
host: 'Host | Hosts',
|
||||||
@@ -841,7 +842,7 @@ const message = {
|
|||||||
|
|
||||||
repo: 'Registries',
|
repo: 'Registries',
|
||||||
createRepo: 'Adicionar',
|
createRepo: 'Adicionar',
|
||||||
createRepoHelper: 'Adicionar um repositório do tipo HTTP requer reinicialização do serviço Docker.',
|
httpRepoHelper: 'Operar um repositório do tipo HTTP requer reinicialização do serviço Docker.',
|
||||||
httpRepo:
|
httpRepo:
|
||||||
'Escolher o protocolo HTTP requer reiniciar o serviço Docker para adicioná-lo a registries inseguros.',
|
'Escolher o protocolo HTTP requer reiniciar o serviço Docker para adicioná-lo a registries inseguros.',
|
||||||
delInsecure: 'Remover da lista de segurança',
|
delInsecure: 'Remover da lista de segurança',
|
||||||
|
|||||||
@@ -334,6 +334,7 @@ const message = {
|
|||||||
ssl: 'Сертификат | Сертификаты',
|
ssl: 'Сертификат | Сертификаты',
|
||||||
database: 'База данных | Базы данных',
|
database: 'База данных | Базы данных',
|
||||||
ai_tools: 'AI',
|
ai_tools: 'AI',
|
||||||
|
mcp: 'MCP',
|
||||||
container: 'Контейнер | Контейнеры',
|
container: 'Контейнер | Контейнеры',
|
||||||
cronjob: 'Cron | Задачи Cron',
|
cronjob: 'Cron | Задачи Cron',
|
||||||
host: 'Хост | Хосты',
|
host: 'Хост | Хосты',
|
||||||
@@ -843,7 +844,7 @@ const message = {
|
|||||||
|
|
||||||
repo: 'Реестры',
|
repo: 'Реестры',
|
||||||
createRepo: 'Добавить',
|
createRepo: 'Добавить',
|
||||||
createRepoHelper: 'Добавление репозитория HTTP-типа требует перезапуска службы Docker.',
|
httpRepoHelper: 'Работа с репозиторием HTTP-типа требует перезапуска службы Docker.',
|
||||||
httpRepo: 'Выбор HTTP протокола требует перезапуска службы Docker для добавления в небезопасные реестры.',
|
httpRepo: 'Выбор HTTP протокола требует перезапуска службы Docker для добавления в небезопасные реестры.',
|
||||||
delInsecure: 'Удаление учетных данных',
|
delInsecure: 'Удаление учетных данных',
|
||||||
delInsecureHelper: 'Это перезапустит службу Docker для удаления из небезопасных реестров. Хотите продолжить?',
|
delInsecureHelper: 'Это перезапустит службу Docker для удаления из небезопасных реестров. Хотите продолжить?',
|
||||||
|
|||||||
@@ -327,6 +327,7 @@ const message = {
|
|||||||
ssl: '證書',
|
ssl: '證書',
|
||||||
database: '資料庫',
|
database: '資料庫',
|
||||||
ai_tools: 'AI',
|
ai_tools: 'AI',
|
||||||
|
mcp: 'MCP',
|
||||||
container: '容器',
|
container: '容器',
|
||||||
cronjob: '計劃任務',
|
cronjob: '計劃任務',
|
||||||
host: '主機',
|
host: '主機',
|
||||||
@@ -804,7 +805,7 @@ const message = {
|
|||||||
|
|
||||||
repo: '倉庫',
|
repo: '倉庫',
|
||||||
createRepo: '新增倉庫',
|
createRepo: '新增倉庫',
|
||||||
createRepoHelper: '添加 HTTP 類型倉庫需要重啟 Docker 服務。',
|
httpRepoHelper: '操作 HTTP 類型倉庫需要重啟 Docker 服務。',
|
||||||
downloadUrl: '下載網址',
|
downloadUrl: '下載網址',
|
||||||
imageRepo: '鏡像倉庫',
|
imageRepo: '鏡像倉庫',
|
||||||
repoHelper: '是否包含鏡像倉庫/組織/項目?',
|
repoHelper: '是否包含鏡像倉庫/組織/項目?',
|
||||||
|
|||||||
@@ -326,6 +326,7 @@ const message = {
|
|||||||
ssl: '证书',
|
ssl: '证书',
|
||||||
database: '数据库',
|
database: '数据库',
|
||||||
ai_tools: 'AI',
|
ai_tools: 'AI',
|
||||||
|
mcp: 'MCP',
|
||||||
container: '容器',
|
container: '容器',
|
||||||
cronjob: '计划任务',
|
cronjob: '计划任务',
|
||||||
host: '主机',
|
host: '主机',
|
||||||
@@ -806,7 +807,7 @@ const message = {
|
|||||||
|
|
||||||
repo: '仓库',
|
repo: '仓库',
|
||||||
createRepo: '添加仓库',
|
createRepo: '添加仓库',
|
||||||
createRepoHelper: '添加 http 类型仓库需要重启 Docker 服务。',
|
httpRepoHelper: '操作 http 类型仓库需要重启 Docker 服务。',
|
||||||
downloadUrl: '下载地址',
|
downloadUrl: '下载地址',
|
||||||
imageRepo: '镜像仓库',
|
imageRepo: '镜像仓库',
|
||||||
repoHelper: '是否包含镜像仓库/组织/项目?',
|
repoHelper: '是否包含镜像仓库/组织/项目?',
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const databaseRouter = {
|
|||||||
name: 'MCPServer',
|
name: 'MCPServer',
|
||||||
component: () => import('@/views/ai/mcp/server/index.vue'),
|
component: () => import('@/views/ai/mcp/server/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'MCP',
|
title: 'menu.mcp',
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -72,21 +72,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<MdEditor previewOnly v-model="app.readMe" :theme="isDarkTheme ? 'dark' : 'light'" />
|
<MarkDownEditor :content="app.readMe" />
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
<Install ref="installRef"></Install>
|
<Install ref="installRef"></Install>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import MarkDownEditor from '@/components/mkdown-editor/index.vue';
|
||||||
|
|
||||||
import { GetApp, GetAppDetail } from '@/api/modules/app';
|
import { GetApp, GetAppDetail } from '@/api/modules/app';
|
||||||
import MdEditor from 'md-editor-v3';
|
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import Install from './install/index.vue';
|
import Install from './install/index.vue';
|
||||||
import router from '@/routers';
|
import router from '@/routers';
|
||||||
import { GlobalStore } from '@/store';
|
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
const globalStore = GlobalStore();
|
|
||||||
const { isDarkTheme } = storeToRefs(globalStore);
|
|
||||||
|
|
||||||
const app = ref<any>({});
|
const app = ref<any>({});
|
||||||
const appDetail = ref<any>({});
|
const appDetail = ref<any>({});
|
||||||
|
|||||||
@@ -61,8 +61,9 @@
|
|||||||
</template>
|
</template>
|
||||||
</LayoutContent>
|
</LayoutContent>
|
||||||
|
|
||||||
<OpDialog ref="opRef" @search="search" />
|
<OpDialog ref="opRef" @search="search" @submit="submitDelete" />
|
||||||
<OperatorDialog @search="search" ref="dialogRef" />
|
<OperatorDialog @search="search" ref="dialogRef" />
|
||||||
|
<ConfirmDialog ref="confirmDialog" @confirm="submitDelete" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -87,6 +88,8 @@ const paginationConfig = reactive({
|
|||||||
const searchName = ref();
|
const searchName = ref();
|
||||||
|
|
||||||
const opRef = ref();
|
const opRef = ref();
|
||||||
|
const confirmDialog = ref();
|
||||||
|
const currentRepo = ref();
|
||||||
|
|
||||||
const dockerStatus = ref('Running');
|
const dockerStatus = ref('Running');
|
||||||
const loadStatus = async () => {
|
const loadStatus = async () => {
|
||||||
@@ -141,7 +144,16 @@ const onOpenDialog = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onDelete = async (row: Container.RepoInfo) => {
|
const onDelete = async (row: Container.RepoInfo) => {
|
||||||
let ids = [row.id];
|
currentRepo.value = row.id;
|
||||||
|
if (row.protocol === 'http') {
|
||||||
|
let params = {
|
||||||
|
header: i18n.global.t('container.repo'),
|
||||||
|
operationInfo: i18n.global.t('container.httpRepoHelper'),
|
||||||
|
submitInputInfo: i18n.global.t('database.restartNow'),
|
||||||
|
};
|
||||||
|
confirmDialog.value!.acceptParams(params);
|
||||||
|
return;
|
||||||
|
}
|
||||||
opRef.value.acceptParams({
|
opRef.value.acceptParams({
|
||||||
title: i18n.global.t('commons.button.delete'),
|
title: i18n.global.t('commons.button.delete'),
|
||||||
names: [row.name],
|
names: [row.name],
|
||||||
@@ -149,11 +161,23 @@ const onDelete = async (row: Container.RepoInfo) => {
|
|||||||
i18n.global.t('container.repo'),
|
i18n.global.t('container.repo'),
|
||||||
i18n.global.t('commons.button.delete'),
|
i18n.global.t('commons.button.delete'),
|
||||||
]),
|
]),
|
||||||
api: deleteImageRepo,
|
api: null,
|
||||||
params: { ids: ids },
|
params: null,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const submitDelete = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
await deleteImageRepo(currentRepo.value)
|
||||||
|
.then(() => {
|
||||||
|
loading.value = false;
|
||||||
|
search();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const onCheckConn = async (row: Container.RepoInfo) => {
|
const onCheckConn = async (row: Container.RepoInfo) => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await checkRepoStatus(row.id)
|
await checkRepoStatus(row.id)
|
||||||
|
|||||||
@@ -108,9 +108,13 @@ const dialogData = ref<DialogProps>({
|
|||||||
title: '',
|
title: '',
|
||||||
});
|
});
|
||||||
const confirmDialog = ref();
|
const confirmDialog = ref();
|
||||||
|
const oldUrl = ref();
|
||||||
|
const oldProto = ref();
|
||||||
|
|
||||||
const acceptParams = (params: DialogProps): void => {
|
const acceptParams = (params: DialogProps): void => {
|
||||||
dialogData.value = params;
|
dialogData.value = params;
|
||||||
|
oldUrl.value = params.rowData.downloadUrl;
|
||||||
|
oldProto.value = params.rowData.protocol;
|
||||||
title.value = i18n.global.t('commons.button.' + dialogData.value.title);
|
title.value = i18n.global.t('commons.button.' + dialogData.value.title);
|
||||||
drawerVisible.value = true;
|
drawerVisible.value = true;
|
||||||
};
|
};
|
||||||
@@ -147,13 +151,23 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
|||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate(async (valid) => {
|
formEl.validate(async (valid) => {
|
||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
if (dialogData.value.rowData.protocol === 'https') {
|
let newProto = dialogData.value.rowData.protocol;
|
||||||
|
if (newProto === 'https' && dialogData.value.title === 'add') {
|
||||||
submit();
|
submit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (newProto === oldProto.value) {
|
||||||
|
if (
|
||||||
|
(oldProto.value === 'http' && dialogData.value.rowData.downloadUrl === oldUrl.value) ||
|
||||||
|
oldProto.value === 'https'
|
||||||
|
) {
|
||||||
|
submit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
let params = {
|
let params = {
|
||||||
header: i18n.global.t('container.imageRepo'),
|
header: i18n.global.t('container.repo'),
|
||||||
operationInfo: i18n.global.t('container.createRepoHelper'),
|
operationInfo: i18n.global.t('container.httpRepoHelper'),
|
||||||
submitInputInfo: i18n.global.t('database.restartNow'),
|
submitInputInfo: i18n.global.t('database.restartNow'),
|
||||||
};
|
};
|
||||||
confirmDialog.value!.acceptParams(params);
|
confirmDialog.value!.acceptParams(params);
|
||||||
|
|||||||
@@ -289,6 +289,7 @@ const chartOption = ref('network');
|
|||||||
let timer: NodeJS.Timer | null = null;
|
let timer: NodeJS.Timer | null = null;
|
||||||
let isInit = ref<boolean>(true);
|
let isInit = ref<boolean>(true);
|
||||||
let isActive = ref(true);
|
let isActive = ref(true);
|
||||||
|
let isCurrentActive = ref(true);
|
||||||
|
|
||||||
const ioReadBytes = ref<Array<number>>([]);
|
const ioReadBytes = ref<Array<number>>([]);
|
||||||
const ioWriteBytes = ref<Array<number>>([]);
|
const ioWriteBytes = ref<Array<number>>([]);
|
||||||
@@ -426,12 +427,20 @@ const onLoadBaseInfo = async (isInit: boolean, range: string) => {
|
|||||||
currentInfo.value.uptime = resData.uptime;
|
currentInfo.value.uptime = resData.uptime;
|
||||||
|
|
||||||
loadAppCurrentInfo();
|
loadAppCurrentInfo();
|
||||||
statusRef.value.acceptParams(currentInfo.value, baseInfo.value);
|
statusRef.value?.acceptParams(currentInfo.value, baseInfo.value);
|
||||||
appRef.value.acceptParams();
|
appRef.value?.acceptParams();
|
||||||
if (isInit) {
|
if (isInit) {
|
||||||
timer = setInterval(async () => {
|
timer = setInterval(async () => {
|
||||||
if (isActive.value && !globalStore.isOnRestart) {
|
try {
|
||||||
loadAppCurrentInfo();
|
if (!isCurrentActive.value) {
|
||||||
|
throw new Error('jump out');
|
||||||
|
}
|
||||||
|
if (isActive.value && !globalStore.isOnRestart) {
|
||||||
|
await loadAppCurrentInfo();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
clearInterval(Number(timer));
|
||||||
|
timer = null;
|
||||||
}
|
}
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
@@ -439,7 +448,7 @@ const onLoadBaseInfo = async (isInit: boolean, range: string) => {
|
|||||||
|
|
||||||
const loadAppCurrentInfo = async () => {
|
const loadAppCurrentInfo = async () => {
|
||||||
await Promise.all([onLoadCurrentInfo('gpu'), onLoadCurrentInfo('basic'), onLoadCurrentInfo('ioNet')]);
|
await Promise.all([onLoadCurrentInfo('gpu'), onLoadCurrentInfo('basic'), onLoadCurrentInfo('ioNet')]);
|
||||||
statusRef.value.acceptParams(currentInfo.value, baseInfo.value);
|
statusRef.value?.acceptParams(currentInfo.value, baseInfo.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onLoadCurrentInfo = async (scope: string) => {
|
const onLoadCurrentInfo = async (scope: string) => {
|
||||||
@@ -661,6 +670,7 @@ onMounted(() => {
|
|||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.removeEventListener('focus', onFocus);
|
window.removeEventListener('focus', onFocus);
|
||||||
window.removeEventListener('blur', onBlur);
|
window.removeEventListener('blur', onBlur);
|
||||||
|
isCurrentActive.value = false;
|
||||||
clearInterval(Number(timer));
|
clearInterval(Number(timer));
|
||||||
timer = null;
|
timer = null;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -176,7 +176,7 @@
|
|||||||
import { ref, reactive, onMounted, computed, nextTick } from 'vue';
|
import { ref, reactive, onMounted, computed, nextTick } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import type { ElForm } from 'element-plus';
|
import type { ElForm } from 'element-plus';
|
||||||
import { loginApi, getCaptcha, mfaLoginApi, checkIsDemo, getLanguage, checkIsIntl } from '@/api/modules/auth';
|
import { loginApi, getCaptcha, mfaLoginApi, checkIsDemo, getAuthSetting, checkIsIntl } from '@/api/modules/auth';
|
||||||
import { GlobalStore, MenuStore, TabsStore } from '@/store';
|
import { GlobalStore, MenuStore, TabsStore } from '@/store';
|
||||||
import { MsgSuccess } from '@/utils/message';
|
import { MsgSuccess } from '@/utils/message';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
@@ -318,7 +318,6 @@ const login = (formEl: FormInstance | undefined) => {
|
|||||||
let requestLoginForm = {
|
let requestLoginForm = {
|
||||||
name: loginForm.name,
|
name: loginForm.name,
|
||||||
password: encryptPassword(loginForm.password),
|
password: encryptPassword(loginForm.password),
|
||||||
ignoreCaptcha: globalStore.ignoreCaptcha,
|
|
||||||
captcha: loginForm.captcha,
|
captcha: loginForm.captcha,
|
||||||
captchaID: captcha.captchaID,
|
captchaID: captcha.captchaID,
|
||||||
authMethod: 'session',
|
authMethod: 'session',
|
||||||
@@ -400,11 +399,12 @@ const checkIsSystemDemo = async () => {
|
|||||||
isDemo.value = res.data;
|
isDemo.value = res.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadLanguage = async () => {
|
const loadLoginSetting = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await getLanguage();
|
const res = await getAuthSetting();
|
||||||
loginForm.language = res.data;
|
loginForm.language = res.data.language;
|
||||||
handleCommand(res.data);
|
globalStore.ignoreCaptcha = !res.data.needCaptcha;
|
||||||
|
handleCommand(loginForm.language);
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -426,7 +426,7 @@ onMounted(() => {
|
|||||||
globalStore.isOnRestart = false;
|
globalStore.isOnRestart = false;
|
||||||
checkIsSystemIntl();
|
checkIsSystemIntl();
|
||||||
loginVerify();
|
loginVerify();
|
||||||
loadLanguage();
|
loadLoginSetting();
|
||||||
document.title = globalStore.themeConfig.panelName;
|
document.title = globalStore.themeConfig.panelName;
|
||||||
loginForm.agreeLicense = globalStore.agreeLicense;
|
loginForm.agreeLicense = globalStore.agreeLicense;
|
||||||
checkIsSystemDemo();
|
checkIsSystemDemo();
|
||||||
|
|||||||
@@ -138,6 +138,14 @@
|
|||||||
<el-input v-model.trim="account.authorization['password']"></el-input>
|
<el-input v-model.trim="account.authorization['password']"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="account.type === 'PorkBun'">
|
||||||
|
<el-form-item label="API Key" prop="authorization.apiKey">
|
||||||
|
<el-input v-model.trim="account.authorization['apiKey']"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="Secret Key" prop="authorization.secretKey">
|
||||||
|
<el-input v-model.trim="account.authorization['secretKey']"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|||||||
@@ -52,8 +52,6 @@ require (
|
|||||||
github.com/swaggo/files v1.0.1
|
github.com/swaggo/files v1.0.1
|
||||||
github.com/swaggo/gin-swagger v1.6.0
|
github.com/swaggo/gin-swagger v1.6.0
|
||||||
github.com/swaggo/swag v1.16.3
|
github.com/swaggo/swag v1.16.3
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cloudapp v1.0.1115
|
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1115
|
|
||||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.46
|
github.com/tencentyun/cos-go-sdk-v5 v0.7.46
|
||||||
github.com/xlzd/gotp v0.1.0
|
github.com/xlzd/gotp v0.1.0
|
||||||
go4.org v0.0.0-20230225012048-214862532bf5
|
go4.org v0.0.0-20230225012048-214862532bf5
|
||||||
@@ -64,7 +62,6 @@ require (
|
|||||||
golang.org/x/sys v0.30.0
|
golang.org/x/sys v0.30.0
|
||||||
golang.org/x/term v0.29.0
|
golang.org/x/term v0.29.0
|
||||||
golang.org/x/text v0.22.0
|
golang.org/x/text v0.22.0
|
||||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38
|
|
||||||
gopkg.in/ini.v1 v1.67.0
|
gopkg.in/ini.v1 v1.67.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
gorm.io/gorm v1.25.7
|
gorm.io/gorm v1.25.7
|
||||||
@@ -203,6 +200,7 @@ require (
|
|||||||
github.com/nrdcg/freemyip v0.3.0 // indirect
|
github.com/nrdcg/freemyip v0.3.0 // indirect
|
||||||
github.com/nrdcg/mailinabox v0.2.0 // indirect
|
github.com/nrdcg/mailinabox v0.2.0 // indirect
|
||||||
github.com/nrdcg/namesilo v0.2.1 // indirect
|
github.com/nrdcg/namesilo v0.2.1 // indirect
|
||||||
|
github.com/nrdcg/porkbun v0.4.0 // indirect
|
||||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||||
@@ -226,6 +224,7 @@ require (
|
|||||||
github.com/spf13/cast v1.6.0 // indirect
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/stretchr/testify v1.10.0 // indirect
|
github.com/stretchr/testify v1.10.0 // indirect
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1115 // indirect
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1065 // indirect
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1065 // indirect
|
||||||
github.com/therootcompany/xz v1.0.1 // indirect
|
github.com/therootcompany/xz v1.0.1 // indirect
|
||||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||||
@@ -263,6 +262,7 @@ require (
|
|||||||
golang.org/x/mod v0.22.0 // indirect
|
golang.org/x/mod v0.22.0 // indirect
|
||||||
golang.org/x/time v0.8.0 // indirect
|
golang.org/x/time v0.8.0 // indirect
|
||||||
golang.org/x/tools v0.28.0 // indirect
|
golang.org/x/tools v0.28.0 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
|
||||||
google.golang.org/grpc v1.67.1 // indirect
|
google.golang.org/grpc v1.67.1 // indirect
|
||||||
|
|||||||
@@ -762,6 +762,8 @@ github.com/nrdcg/mailinabox v0.2.0 h1:IKq8mfKiVwNW2hQii/ng1dJ4yYMMv3HAP3fMFIq2CF
|
|||||||
github.com/nrdcg/mailinabox v0.2.0/go.mod h1:0yxqeYOiGyxAu7Sb94eMxHPIOsPYXAjTeA9ZhePhGnc=
|
github.com/nrdcg/mailinabox v0.2.0/go.mod h1:0yxqeYOiGyxAu7Sb94eMxHPIOsPYXAjTeA9ZhePhGnc=
|
||||||
github.com/nrdcg/namesilo v0.2.1 h1:kLjCjsufdW/IlC+iSfAqj0iQGgKjlbUUeDJio5Y6eMg=
|
github.com/nrdcg/namesilo v0.2.1 h1:kLjCjsufdW/IlC+iSfAqj0iQGgKjlbUUeDJio5Y6eMg=
|
||||||
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
|
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
|
||||||
|
github.com/nrdcg/porkbun v0.4.0 h1:rWweKlwo1PToQ3H+tEO9gPRW0wzzgmI/Ob3n2Guticw=
|
||||||
|
github.com/nrdcg/porkbun v0.4.0/go.mod h1:/QMskrHEIM0IhC/wY7iTCUgINsxdT2WcOphktJ9+Q54=
|
||||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 h1:e3mzJFJs4k83GXBEiTaQ5HgSc/kOK8q0rDaRO0MPaOk=
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 h1:e3mzJFJs4k83GXBEiTaQ5HgSc/kOK8q0rDaRO0MPaOk=
|
||||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.2/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
@@ -962,8 +964,6 @@ github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+z
|
|||||||
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
|
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
|
||||||
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
|
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/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cloudapp v1.0.1115 h1:y0GrxBKOgY697oJbybR+WBrukZb/RB9bU06BtlPSWVA=
|
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cloudapp v1.0.1115/go.mod h1:V1xvKmdqEnfD9cfA3z4v/XKxftR4Gdz7Jyp3Oi+UAtM=
|
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1065/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1065/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1115 h1:lYeFC379r76seyzN7PHmSxv1ji9knmsXQJglDB/K0WE=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1115 h1:lYeFC379r76seyzN7PHmSxv1ji9knmsXQJglDB/K0WE=
|
||||||
|
|||||||
Reference in New Issue
Block a user