Compare commits

..
Author SHA1 Message Date
zhengkunwang ab932ae154 fix: Fixed the issue where application labels were not displayed after updating. (#7834) 2025-02-10 11:17:24 +08:00
david082321 89f969ec6e feat: Update zh-Hant translation (#7830) 2025-02-09 22:01:02 +08:00
ssongliu afa8cf22b1 feat: Add function backups by default for MySQL and MariaDB databases. (#7823) 2025-02-08 22:56:46 +08:00
ssongliu 67aa8471dc fix: Remove some comments. (#7822) 2025-02-08 08:41:27 +00:00
zhengkunwang 0617b81b3b feat: The appstore has added support for the Korean language (#7818) 2025-02-07 13:07:20 +00:00
ssongliu 98c535a12c fix: improve the backend verification for security entry settings (#7810)
Refs #7657
2025-02-06 10:15:06 +00:00
ssongliu ec46518936 feat: Improve the name of the professional version (#7807) 2025-02-06 10:13:03 +00:00
ssongliu a7b034387f fix: fix some internationalization formats (#7803) 2025-02-05 14:41:59 +00:00
endymx 7905dd00a6 fix(firewall): 删除复杂转发规则时报错 (#7791) 2025-02-05 18:37:42 +08:00
zhengkunwang 74583aa1aa feat: fix anti-leech is not work on proxy website (#7801)
Refs https://github.com/1Panel-dev/1Panel/issues/7752
2025-02-05 10:07:16 +00:00
dependabot[bot] 4be9d71edf chore(deps): bump github.com/golang/glog from 1.2.2 to 1.2.4 (#7787) 2025-01-31 13:08:01 +08:00
zhengkunwang 57bfc38eb8 feat: Application details have been enhanced with tags. (#7777)
Refs https://github.com/1Panel-dev/1Panel/issues/7774
2025-01-27 11:04:26 +00:00
zhengkunwang aaaa5980b5 feat: Added password encryption for login functionality (#7764) 2025-01-23 18:09:12 +08:00
蘭 4f57dfc76e feat: Unify the response body of the API interface (#7761) 2025-01-23 08:28:04 +00:00
wanghe-fit2cloud 2c31ffc66b feat: Enhance app redirection messages 2025-01-23 15:32:11 +08:00
王贺 b104a13b71 Update README.md (#7747) 2025-01-20 22:48:29 +08:00
maninhill 28633d2fef chore: Update README.md 2025-01-20 22:33:20 +08:00
蘭 9052386c83 feat: Korean language support (#7727)
Refs #7363
2025-01-15 10:26:30 +00:00
maninhill 7bc45f2d77 chore: Update README.md 2025-01-15 15:24:20 +08:00
wanghe-fit2cloud 2ef6ecb951 chore: Update the README.md 2025-01-15 10:40:22 +08:00
zhengkunwang ca0dc71338 feat: Enable Multi-Language Support for Application Installation Forms (#7717) 2025-01-14 19:03:22 +08:00
zhengkunwang 04a1ec9a9a feat: Add Multi-Language Support for Application Labels (#7714) 2025-01-14 16:00:09 +08:00
蘭 999e5a779a feat: Update swagger docs (#7710) 2025-01-13 15:10:04 +00:00
zhengkunwang 99f62b7230 fix(website):Fix Reverse Proxy Deletion Failure in Certain Scenarios (#7709)
Refs https://github.com/1Panel-dev/1Panel/issues/7701
2025-01-13 15:08:04 +00:00
zhengkunwang 4dee4e1cc2 feat: Update Application Name Restrictions (#7706) 2025-01-13 07:56:03 +00:00
maninhill 539addc656 chore: Update README.md 2025-01-10 23:07:15 +08:00
BugKing 1a35b307fa docs: add introduction of 1Panel Pro in README (#7699) 2025-01-10 22:32:02 +08:00
蘭 a04f4a8b96 feat: Improve international language and style (#7697)
Refs #7696
2025-01-10 10:57:45 +00:00
ssongliu 6b88e1adf2 fix: Remove redundant code (#7694) 2025-01-10 15:06:18 +08:00
87 changed files with 4724 additions and 1060 deletions
+8 -2
View File
@@ -1,5 +1,5 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Top-Rated Web-based Linux Server Management Tool</b></p>
<p align="center"><b>Top-Rated Web-based Linux Server Management Tool<br>Best VPS control panel</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
<a href="https://www.producthunt.com/posts/1panel?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-1panel" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=639696&theme=light" alt="1Panel - Top&#0045;Rated&#0032;web&#0045;based&#0032;Linux&#0032;server&#0032;management&#0032;tool | Product Hunt" style="width: 180px; height: auto;" /></a>
@@ -50,6 +50,8 @@ curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash qu
Please refer to our [documentation](https://docs.1panel.hk/quick_start/) for more details.
中国用户请使用这个 [安装脚本](https://1panel.cn/docs/installation/online_installation/),其应用数量比国际版本更丰富。
## Screenshot
![UI Display](https://resource.1panel.hk/img/1panel.png)
@@ -58,9 +60,13 @@ Please refer to our [documentation](https://docs.1panel.hk/quick_start/) for mor
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
## Pro Edition
Compared to the OSS Edition, 1Panel Pro Edition provides users with a wealth of enhanced features and technical support services. Enhanced features include WAF enhancement, website tamper protection, website monitoring, GPU monitoring, custom logo and theme color, etc. [Click to view the detailed introduction of the Pro Edition](https://1panel.hk/pricing).
## Security Information
If you discover any security issues, please contact us through: wanghe@fit2cloud.com.
If you discover any security issues, please refer to [SECURITY.md](/SECURITY.md).
## License
+3 -3
View File
@@ -22,7 +22,7 @@ func (b *BaseApi) SearchApp(c *gin.Context) {
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
list, err := appService.PageApp(req)
list, err := appService.PageApp(c, req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -75,7 +75,7 @@ func (b *BaseApi) GetApp(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
appDTO, err := appService.GetApp(appKey)
appDTO, err := appService.GetApp(c, appKey)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -173,7 +173,7 @@ func (b *BaseApi) InstallApp(c *gin.Context) {
}
func (b *BaseApi) GetAppTags(c *gin.Context) {
tags, err := appService.GetAppTags()
tags, err := appService.GetAppTags(c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
+4 -1
View File
@@ -28,7 +28,10 @@ func (b *BaseApi) SearchAppInstalled(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, list)
helper.SuccessWithData(c, dto.PageResult{
Items: list,
Total: int64(len(list)),
})
} else {
total, list, err := appInstallService.Page(req)
if err != nil {
+2 -2
View File
@@ -166,7 +166,7 @@ func (b *BaseApi) SearchBackupRecords(c *gin.Context) {
// @Summary Load backup records size
// @Accept json
// @Param request body dto.RecordSearch true "request"
// @Success 200 {array} dto.dto.BackupFile
// @Success 200 {array} dto.BackupFile
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /settings/backup/record/size [post]
@@ -215,7 +215,7 @@ func (b *BaseApi) SearchBackupRecordsByCronjob(c *gin.Context) {
// @Summary Load backup records size for cronjob
// @Accept json
// @Param request body dto.RecordSearchByCronjob true "request"
// @Success 200 {array} dto.dto.BackupFile
// @Success 200 {array} dto.BackupFile
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /settings/backup/record/size/bycronjob [post]
+5 -2
View File
@@ -12,7 +12,7 @@ import (
// @Summary Page Extensions
// @Accept json
// @Param request body request.PHPExtensionsSearch true "request"
// @Success 200 {array} response.PHPExtensionsDTO
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /runtimes/php/extensions/search [post]
@@ -27,7 +27,10 @@ func (b *BaseApi) PagePHPExtensions(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, list)
helper.SuccessWithData(c, dto.PageResult{
Total: int64(len(list)),
Items: list,
})
} else {
total, list, err := phpExtensionsService.Page(req)
if err != nil {
+16
View File
@@ -3,8 +3,10 @@ package v1
import (
"encoding/base64"
"errors"
"fmt"
"os"
"path"
"regexp"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
@@ -53,6 +55,12 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) {
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if req.Key == "SecurityEntrance" {
if checkEntrancePattern(req.Value) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("regexp match string with %s failed", req.Value))
return
}
}
if err := settingService.Update(req.Key, req.Value); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@@ -391,3 +399,11 @@ func (b *BaseApi) UpdateApiConfig(c *gin.Context) {
}
helper.SuccessWithData(c, nil)
}
func checkEntrancePattern(val string) bool {
if len(val) == 0 {
return true
}
result, _ := regexp.MatchString("^[a-zA-Z0-9]{5,116}$", val)
return result
}
+22
View File
@@ -571,6 +571,28 @@ func (b *BaseApi) GetProxyConfig(c *gin.Context) {
helper.SuccessWithData(c, res)
}
// @Tags Website
// @Summary Delete proxy conf
// @Accept json
// @Param request body request.WebsiteProxyDel true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /websites/proxies/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"删除网站 [domain] 反向代理配置","formatEN":"Delete domain [domain] proxy config"}
func (b *BaseApi) DeleteProxyConfig(c *gin.Context) {
var req request.WebsiteProxyDel
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
err := websiteService.DeleteProxy(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Website
// @Summary Update proxy conf
// @Accept json
+18 -8
View File
@@ -1,9 +1,5 @@
package dto
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
)
type AppDatabase struct {
ServiceName string `json:"PANEL_DB_HOST"`
DbName string `json:"PANEL_DB_NAME"`
@@ -62,7 +58,7 @@ type AppDefine struct {
}
type LocalAppAppDefine struct {
AppProperty model.App `json:"additionalProperties" yaml:"additionalProperties"`
AppProperty AppProperty `json:"additionalProperties" yaml:"additionalProperties"`
}
type LocalAppParam struct {
@@ -84,6 +80,7 @@ type AppProperty struct {
Tags []string `json:"tags"`
ShortDescZh string `json:"shortDescZh"`
ShortDescEn string `json:"shortDescEn"`
Description Locale `json:"description"`
Key string `json:"key"`
Required []string `json:"Required"`
CrossVersionUpdate bool `json:"crossVersionUpdate"`
@@ -104,9 +101,21 @@ type AppConfigVersion struct {
}
type Tag struct {
Key string `json:"key"`
Name string `json:"name"`
Sort int `json:"sort"`
Key string `json:"key"`
Name string `json:"name"`
Sort int `json:"sort"`
Locales Locale `json:"locales"`
}
type Locale struct {
En string `json:"en"`
Ja string `json:"ja"`
Ms string `json:"ms"`
PtBr string `json:"pt-br" yaml:"pt-br"`
Ru string `json:"ru"`
ZhHant string `json:"zh-hant" yaml:"zh-hant"`
Zh string `json:"zh"`
Ko string `json:"ko"`
}
type AppForm struct {
@@ -118,6 +127,7 @@ type AppFormFields struct {
Type string `json:"type"`
LabelZh string `json:"labelZh"`
LabelEn string `json:"labelEn"`
Label Locale `json:"label"`
Required bool `json:"required"`
Default interface{} `json:"default"`
EnvKey string `json:"envKey"`
+1 -1
View File
@@ -29,7 +29,7 @@ type Login struct {
Captcha string `json:"captcha"`
CaptchaID string `json:"captchaID"`
AuthMethod string `json:"authMethod" validate:"required,oneof=jwt session"`
Language string `json:"language" validate:"required,oneof=zh en tw ja ru ms 'pt-BR'"`
Language string `json:"language" validate:"required,oneof=zh en tw ja ko ru ms 'pt-BR'"`
}
type MFALogin struct {
+5
View File
@@ -193,6 +193,11 @@ type WebsiteProxyConfig struct {
ProxySSLName string `json:"proxySSLName"`
}
type WebsiteProxyDel struct {
ID uint `json:"id" validate:"required"`
Name string `json:"name" validate:"required"`
}
type WebsiteProxyReq struct {
ID uint `json:"id" validate:"required"`
}
+18 -17
View File
@@ -23,29 +23,30 @@ type AppUpdateRes struct {
type AppDTO struct {
model.App
Installed bool `json:"installed"`
Versions []string `json:"versions"`
Tags []model.Tag `json:"tags"`
Installed bool `json:"installed"`
Versions []string `json:"versions"`
Tags []TagDTO `json:"tags"`
}
type AppItem struct {
Name string `json:"name"`
Key string `json:"key"`
ID uint `json:"id"`
ShortDescZh string `json:"shortDescZh"`
ShortDescEn string `json:"shortDescEn"`
Icon string `json:"icon"`
Type string `json:"type"`
Status string `json:"status"`
Resource string `json:"resource"`
Installed bool `json:"installed"`
Versions []string `json:"versions"`
Limit int `json:"limit"`
Tags []model.Tag `json:"tags"`
Name string `json:"name"`
Key string `json:"key"`
ID uint `json:"id"`
Description string `json:"description"`
Icon string `json:"icon"`
Type string `json:"type"`
Status string `json:"status"`
Resource string `json:"resource"`
Installed bool `json:"installed"`
Versions []string `json:"versions"`
Limit int `json:"limit"`
Tags []TagDTO `json:"tags"`
}
type TagDTO struct {
model.Tag
ID uint `json:"id"`
Key string `json:"key"`
Name string `json:"name"`
}
type AppInstalledCheck struct {
+17 -1
View File
@@ -1,7 +1,10 @@
package model
import (
"encoding/json"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/gin-gonic/gin"
"path/filepath"
"strings"
)
@@ -12,6 +15,7 @@ type App struct {
Key string `json:"key" gorm:"type:varchar(64);not null;"`
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh" gorm:"type:longtext;"`
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn" gorm:"type:longtext;"`
Description string `json:"description"`
Icon string `json:"icon" gorm:"type:longtext;"`
Type string `json:"type" gorm:"type:varchar(64);not null"`
Status string `json:"status" gorm:"type:varchar(64);not null"`
@@ -36,8 +40,20 @@ func (i *App) IsLocalApp() bool {
}
func (i *App) GetAppResourcePath() string {
if i.IsLocalApp() {
//这里要去掉本地应用的local前缀
return filepath.Join(constant.LocalAppResourceDir, strings.TrimPrefix(i.Key, "local"))
}
return filepath.Join(constant.RemoteAppResourceDir, i.Key)
}
func (i *App) GetDescription(ctx *gin.Context) string {
var translations = make(map[string]string)
_ = json.Unmarshal([]byte(i.Description), &translations)
lang := strings.ToLower(common.GetLang(ctx))
if desc, ok := translations[lang]; ok && desc != "" {
return desc
}
if lang == "zh" {
return i.ShortDescZh
}
return i.ShortDescEn
}
+4 -3
View File
@@ -2,7 +2,8 @@ package model
type Tag struct {
BaseModel
Key string `json:"key" gorm:"type:varchar(64);not null"`
Name string `json:"name" gorm:"type:varchar(64);not null"`
Sort int `json:"sort" gorm:"type:int;not null;default:1"`
Key string `json:"key" gorm:"type:varchar(64);not null"`
Name string `json:"name" gorm:"type:varchar(64);not null"`
Translations string `json:"translations"`
Sort int `json:"sort" gorm:"type:int;not null;default:1"`
}
+7
View File
@@ -15,6 +15,7 @@ type DBOption func(*gorm.DB) *gorm.DB
type ICommonRepo interface {
WithByID(id uint) DBOption
WithByName(name string) DBOption
WithByLowerName(name string) DBOption
WithByType(tp string) DBOption
WithOrderBy(orderStr string) DBOption
WithOrderRuleBy(orderBy, order string) DBOption
@@ -45,6 +46,12 @@ func (c *CommonRepo) WithByName(name string) DBOption {
}
}
func (c *CommonRepo) WithByLowerName(name string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("LOWER(name) = LOWER(?)", name)
}
}
func (c *CommonRepo) WithByDate(startTime, endTime time.Time) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("start_time > ? AND start_time < ?", startTime, endTime)
+5
View File
@@ -16,6 +16,7 @@ type ISettingRepo interface {
Create(key, value string) error
Update(key, value string) error
WithByKey(key string) DBOption
UpdateOrCreate(key, value string) error
CreateMonitorBase(model model.MonitorBase) error
BatchCreateMonitorIO(ioList []model.MonitorIO) error
@@ -85,3 +86,7 @@ func (u *SettingRepo) DelMonitorIO(timeForDelete time.Time) error {
func (u *SettingRepo) DelMonitorNet(timeForDelete time.Time) error {
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorNetwork{}).Error
}
func (u *SettingRepo) UpdateOrCreate(key, value string) error {
return global.DB.Model(&model.Setting{}).Where("key = ?", key).Assign(model.Setting{Key: key, Value: value}).FirstOrCreate(&model.Setting{}).Error
}
+47 -33
View File
@@ -5,6 +5,7 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"os"
"path/filepath"
@@ -34,9 +35,9 @@ type AppService struct {
}
type IAppService interface {
PageApp(req request.AppSearch) (interface{}, error)
GetAppTags() ([]response.TagDTO, error)
GetApp(key string) (*response.AppDTO, error)
PageApp(ctx *gin.Context, req request.AppSearch) (interface{}, error)
GetAppTags(ctx *gin.Context) ([]response.TagDTO, error)
GetApp(ctx *gin.Context, key string) (*response.AppDTO, error)
GetAppDetail(appId uint, version, appType string) (response.AppDetailDTO, error)
Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error)
SyncAppListFromRemote() error
@@ -50,7 +51,7 @@ func NewIAppService() IAppService {
return &AppService{}
}
func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
func (a AppService) PageApp(ctx *gin.Context, req request.AppSearch) (interface{}, error) {
var opts []repo.DBOption
opts = append(opts, appRepo.OrderByRecommend())
if req.Name != "" {
@@ -90,30 +91,22 @@ func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
return nil, err
}
var appDTOs []*response.AppItem
lang := strings.ToLower(common.GetLang(ctx))
for _, ap := range apps {
appDTO := &response.AppItem{
ID: ap.ID,
Name: ap.Name,
Key: ap.Key,
Type: ap.Type,
Icon: ap.Icon,
ShortDescZh: ap.ShortDescZh,
ShortDescEn: ap.ShortDescEn,
Resource: ap.Resource,
Limit: ap.Limit,
ID: ap.ID,
Name: ap.Name,
Key: ap.Key,
Type: ap.Type,
Icon: ap.Icon,
Resource: ap.Resource,
Limit: ap.Limit,
}
appDTO.Description = ap.GetDescription(ctx)
appDTOs = append(appDTOs, appDTO)
appTags, err := appTagRepo.GetByAppId(ap.ID)
tags, err := getAppTags(ap.ID, lang)
if err != nil {
continue
}
var tagIds []uint
for _, at := range appTags {
tagIds = append(tagIds, at.TagId)
}
tags, err := tagRepo.GetByIds(tagIds)
if err != nil {
continue
return nil, err
}
appDTO.Tags = tags
installs, _ := appInstallRepo.ListBy(appInstallRepo.WithAppId(ap.ID))
@@ -125,18 +118,32 @@ func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
return res, nil
}
func (a AppService) GetAppTags() ([]response.TagDTO, error) {
func (a AppService) GetAppTags(ctx *gin.Context) ([]response.TagDTO, error) {
tags, _ := tagRepo.All()
res := make([]response.TagDTO, 0)
lang := strings.ToLower(common.GetLang(ctx))
for _, tag := range tags {
res = append(res, response.TagDTO{
Tag: tag,
})
tagDTO := response.TagDTO{
ID: tag.ID,
Key: tag.Key,
}
var translations = make(map[string]string)
_ = json.Unmarshal([]byte(tag.Translations), &translations)
if name, ok := translations[lang]; ok && name != "" {
tagDTO.Name = name
} else {
if lang == "zh" || lang == "zh-Hant" {
tagDTO.Name = tag.Name
} else {
tagDTO.Name = tag.Key
}
}
res = append(res, tagDTO)
}
return res, nil
}
func (a AppService) GetApp(key string) (*response.AppDTO, error) {
func (a AppService) GetApp(ctx *gin.Context, key string) (*response.AppDTO, error) {
var appDTO response.AppDTO
if key == "postgres" {
key = "postgresql"
@@ -146,6 +153,7 @@ func (a AppService) GetApp(key string) (*response.AppDTO, error) {
return nil, err
}
appDTO.App = app
appDTO.App.Description = app.GetDescription(ctx)
details, err := appDetailRepo.GetBy(appDetailRepo.WithAppId(app.ID))
if err != nil {
return nil, err
@@ -155,7 +163,11 @@ func (a AppService) GetApp(key string) (*response.AppDTO, error) {
versionsRaw = append(versionsRaw, detail.Version)
}
appDTO.Versions = common.GetSortedVersions(versionsRaw)
tags, err := getAppTags(app.ID, strings.ToLower(common.GetLang(ctx)))
if err != nil {
return nil, err
}
appDTO.Tags = tags
return &appDTO, nil
}
@@ -296,7 +308,8 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
err = buserr.WithDetail(constant.Err1PanelNetworkFailed, err.Error(), nil)
return
}
if list, _ := appInstallRepo.ListBy(commonRepo.WithByName(req.Name)); len(list) > 0 {
if list, _ := appInstallRepo.ListBy(commonRepo.WithByLowerName(req.Name)); len(list) > 0 {
err = buserr.New(constant.ErrAppNameExist)
return
}
@@ -827,10 +840,11 @@ func (a AppService) SyncAppListFromRemote() (err error) {
oldAppIds []uint
)
for _, t := range list.Extra.Tags {
translations, _ := json.Marshal(t.Locales)
tags = append(tags, &model.Tag{
Key: t.Key,
Name: t.Name,
Sort: t.Sort,
Key: t.Key,
Translations: string(translations),
Sort: t.Sort,
})
}
oldApps, err := appRepo.GetBy(appRepo.WithResource(constant.AppResourceRemote))
+63 -5
View File
@@ -1051,6 +1051,8 @@ func getApps(oldApps []model.App, items []dto.AppDefine) map[string]model.App {
app.Key = key
app.ShortDescZh = config.ShortDescZh
app.ShortDescEn = config.ShortDescEn
description, _ := json.Marshal(config.Description)
app.Description = string(description)
app.Website = config.Website
app.Document = config.Document
app.Github = config.Github
@@ -1150,14 +1152,32 @@ func handleLocalApp(appDir string) (app *model.App, err error) {
err = buserr.WithMap(constant.ErrFileParseApp, map[string]interface{}{"name": "data.yml", "err": err.Error()}, err)
return
}
app = &localAppDefine.AppProperty
appDefine := localAppDefine.AppProperty
app = &model.App{}
app.Name = appDefine.Name
app.TagsKey = append(appDefine.Tags, "Local")
app.Type = appDefine.Type
app.CrossVersionUpdate = appDefine.CrossVersionUpdate
app.Limit = appDefine.Limit
app.Recommend = appDefine.Recommend
app.Website = appDefine.Website
app.Github = appDefine.Github
app.Document = appDefine.Document
if appDefine.ShortDescZh != "" {
appDefine.Description.Zh = appDefine.ShortDescZh
}
if appDefine.ShortDescEn != "" {
appDefine.Description.En = appDefine.ShortDescEn
}
desc, _ := json.Marshal(appDefine.Description)
app.Description = string(desc)
app.Key = "local" + appDefine.Key
app.Resource = constant.AppResourceLocal
app.Status = constant.AppNormal
app.Recommend = 9999
app.TagsKey = append(app.TagsKey, "Local")
app.Key = "local" + app.Key
readMePath := path.Join(appDir, "README.md")
readMeByte, err := fileOp.GetContent(readMePath)
readMeByte, err := fileOp.GetContent(path.Join(appDir, "README.md"))
if err == nil {
app.ReadMe = string(readMeByte)
}
@@ -1587,3 +1607,41 @@ func RequestDownloadCallBack(downloadCallBackUrl string) {
}
_, _, _ = httpUtil.HandleGet(downloadCallBackUrl, http.MethodGet, constant.TimeOut5s)
}
func getAppTags(appID uint, lang string) ([]response.TagDTO, error) {
appTags, err := appTagRepo.GetByAppId(appID)
if err != nil {
return nil, err
}
var tagIds []uint
for _, at := range appTags {
tagIds = append(tagIds, at.TagId)
}
tags, err := tagRepo.GetByIds(tagIds)
if err != nil {
return nil, err
}
var res []response.TagDTO
for _, t := range tags {
if t.Name != "" {
tagDTO := response.TagDTO{
ID: t.ID,
Key: t.Key,
Name: t.Name,
}
res = append(res, tagDTO)
} else {
var translations = make(map[string]string)
_ = json.Unmarshal([]byte(t.Translations), &translations)
if name, ok := translations[lang]; ok {
tagDTO := response.TagDTO{
ID: t.ID,
Key: t.Key,
Name: name,
}
res = append(res, tagDTO)
}
}
}
return res, nil
}
+33 -19
View File
@@ -3,8 +3,6 @@ package service
import (
"crypto/hmac"
"encoding/base64"
"strconv"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
@@ -15,6 +13,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/pkg/errors"
"strconv"
)
type AuthService struct{}
@@ -38,16 +37,11 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*d
if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
}
passwordSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
}
pass, err := encrypt.StringDecrypt(passwordSetting.Value)
if err != nil {
if nameSetting.Value != info.Name {
return nil, constant.ErrAuth
}
if !hmac.Equal([]byte(info.Password), []byte(pass)) || nameSetting.Value != info.Name {
return nil, constant.ErrAuth
if err = checkPassword(info.Password); err != nil {
return nil, err
}
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
if err != nil {
@@ -83,17 +77,12 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin, entrance strin
if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
}
passwordSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
}
pass, err := encrypt.StringDecrypt(passwordSetting.Value)
if err != nil {
return nil, err
}
if !hmac.Equal([]byte(info.Password), []byte(pass)) || nameSetting.Value != info.Name {
if nameSetting.Value != info.Name {
return nil, constant.ErrAuth
}
if err = checkPassword(info.Password); err != nil {
return nil, err
}
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
if err != nil {
return nil, err
@@ -219,3 +208,28 @@ func (u *AuthService) IsLogin(c *gin.Context) bool {
}
return true
}
func checkPassword(password string) error {
priKey, _ := settingRepo.Get(settingRepo.WithByKey("PASSWORD_PRIVATE_KEY"))
privateKey, err := encrypt.ParseRSAPrivateKey(priKey.Value)
if err != nil {
return err
}
loginPassword, err := encrypt.DecryptPassword(password, privateKey)
if err != nil {
return err
}
passwordSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
if err != nil {
return errors.WithMessage(constant.ErrRecordNotFound, err.Error())
}
existPassword, err := encrypt.StringDecrypt(passwordSetting.Value)
if err != nil {
return err
}
if !hmac.Equal([]byte(loginPassword), []byte(existPassword)) {
return constant.ErrAuth
}
return nil
}
+47
View File
@@ -1,6 +1,8 @@
package service
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/json"
@@ -42,6 +44,7 @@ type ISettingService interface {
HandlePasswordExpired(c *gin.Context, old, new string) error
GenerateApiKey() (string, error)
UpdateApiConfig(req dto.ApiInterfaceConfig) error
GenerateRSAKey() error
}
func NewISettingService() ISettingService {
@@ -516,3 +519,47 @@ func (u *SettingService) UpdateApiConfig(req dto.ApiInterfaceConfig) error {
global.CONF.System.ApiKeyValidityTime = req.ApiKeyValidityTime
return nil
}
func exportPrivateKeyToPEM(privateKey *rsa.PrivateKey) string {
privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
privateKeyPEM := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privateKeyBytes,
})
return string(privateKeyPEM)
}
func exportPublicKeyToPEM(publicKey *rsa.PublicKey) (string, error) {
publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return "", err
}
publicKeyPEM := pem.EncodeToMemory(&pem.Block{
Type: "PUBLIC KEY",
Bytes: publicKeyBytes,
})
return string(publicKeyPEM), nil
}
func (u *SettingService) GenerateRSAKey() error {
priKey, _ := settingRepo.Get(settingRepo.WithByKey("PASSWORD_PRIVATE_KEY"))
pubKey, _ := settingRepo.Get(settingRepo.WithByKey("PASSWORD_PUBLIC_KEY"))
if priKey.Value != "" && pubKey.Value != "" {
return nil
}
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return err
}
privateKeyPEM := exportPrivateKeyToPEM(privateKey)
publicKeyPEM, err := exportPublicKeyToPEM(&privateKey.PublicKey)
err = settingRepo.UpdateOrCreate("PASSWORD_PRIVATE_KEY", privateKeyPEM)
if err != nil {
return err
}
err = settingRepo.UpdateOrCreate("PASSWORD_PUBLIC_KEY", publicKeyPEM)
if err != nil {
return err
}
return nil
}
+41 -1
View File
@@ -87,13 +87,18 @@ type IWebsiteService interface {
LoadWebsiteDirConfig(req request.WebsiteCommonReq) (*response.WebsiteDirConfig, error)
UpdateSiteDir(req request.WebsiteUpdateDir) error
UpdateSitePermission(req request.WebsiteUpdateDirPermission) error
OperateProxy(req request.WebsiteProxyConfig) (err error)
GetProxies(id uint) (res []request.WebsiteProxyConfig, err error)
UpdateProxyFile(req request.NginxProxyUpdate) (err error)
DeleteProxy(req request.WebsiteProxyDel) (err error)
GetAuthBasics(req request.NginxAuthReq) (res response.NginxAuthRes, err error)
UpdateAuthBasic(req request.NginxAuthUpdate) (err error)
GetAntiLeech(id uint) (*response.NginxAntiLeechRes, error)
UpdateAntiLeech(req request.NginxAntiLeechUpdate) (err error)
OperateRedirect(req request.NginxRedirectReq) (err error)
GetRedirect(id uint) (res []response.NginxRedirectConfig, err error)
UpdateRedirectFile(req request.NginxRedirectUpdate) (err error)
@@ -1553,6 +1558,29 @@ func (w WebsiteService) UpdateSitePermission(req request.WebsiteUpdateDirPermiss
return websiteRepo.Save(context.Background(), &website)
}
func (w WebsiteService) DeleteProxy(req request.WebsiteProxyDel) (err error) {
fileOp := files.NewFileOp()
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
return
}
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return
}
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "proxy")
if !fileOp.Stat(includeDir) {
_ = fileOp.CreateDir(includeDir, 0755)
}
fileName := fmt.Sprintf("%s.conf", req.Name)
includePath := path.Join(includeDir, fileName)
backName := fmt.Sprintf("%s.bak", req.Name)
backPath := path.Join(includeDir, backName)
_ = fileOp.DeleteFile(includePath)
_ = fileOp.DeleteFile(backPath)
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
}
func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error) {
var (
website model.Website
@@ -2043,7 +2071,19 @@ func (w WebsiteService) UpdateAntiLeech(req request.NginxAntiLeechUpdate) (err e
}
newBlock.Directives = append(newBlock.Directives, ifDir)
newDirective.Block = newBlock
block.Directives = append(block.Directives, &newDirective)
index := -1
for i, directive := range block.Directives {
if directive.GetName() == "include" {
index = i
break
}
}
if index != -1 {
block.Directives = append(block.Directives[:index], append([]components.IDirective{&newDirective}, block.Directives[index:]...)...)
} else {
block.Directives = append(block.Directives, &newDirective)
}
}
if err = nginx.WriteConfig(nginxFull.SiteConfig.Config, nginx.IndentedStyle); err != nil {
+1
View File
@@ -104,6 +104,7 @@ func Init() {
_, _ = bundle.LoadMessageFileFS(fs, "lang/ja.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/ru.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/ms.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/ko.yaml")
}
func UseI18nForCmd(lang string) {
+286
View File
@@ -0,0 +1,286 @@
ErrInvalidParams: "요청 매개변수 오류: {{ .detail }}"
ErrTokenParse: "토큰 생성 오류: {{ .detail }}"
ErrInitialPassword: "초기 비밀번호 오류"
ErrInternalServer: "서버 내부 오류: {{ .detail }}"
ErrRecordExist: "기록이 이미 존재합니다"
ErrRecordNotFound: "기록을 찾을 수 없습니다"
ErrStructTransform: "형식 변환 실패: {{ .detail }}"
ErrNotLogin: "사용자가 로그인되지 않았습니다: {{ .detail }}"
ErrPasswordExpired: "현재 비밀번호가 만료되었습니다: {{ .detail }}"
ErrNotSupportType: "시스템에서 현재 유형을 지원하지 않습니다: {{ .detail }}"
ErrApiConfigStatusInvalid: "API 인터페이스 액세스 금지: {{ .detail }}"
ErrApiConfigKeyInvalid: "API 인터페이스 키 오류: {{ .detail }}"
ErrApiConfigIPInvalid: "API 인터페이스 IP가 화이트리스트에 없습니다: {{ .detail }}"
ErrApiConfigDisable: "이 인터페이스는 API 호출을 금지합니다: {{ .detail }}"
ErrApiConfigKeyTimeInvalid: "API 인터페이스 타임스탬프 오류: {{ .detail }}"
# 공통
ErrNameIsExist: "이름이 이미 존재합니다"
ErrDemoEnvironment: "데모 서버에서는 이 작업이 금지되어 있습니다!"
ErrCmdTimeout: "명령어 실행 시간이 초과되었습니다!"
ErrCmdIllegal: "명령어에 잘못된 문자가 포함되어 있습니다. 수정 후 다시 시도하세요!"
ErrPortExist: '{{ .port }} 포트가 {{ .type }} [{{ .name }}]에 의해 이미 사용 중입니다'
TYPE_APP: "애플리케이션"
TYPE_RUNTIME: "실행 환경"
TYPE_DOMAIN: "도메인 이름"
ErrTypePort: '포트 {{ .name }} 형식 오류'
ErrTypePortRange: '포트 범위는 1-65535 사이여야 합니다'
Success: "성공"
Failed: "실패"
SystemRestart: "시스템 재시작으로 인해 작업이 중단되었습니다"
# 애플리케이션
ErrPortInUsed: "{{ .detail }} 포트가 이미 사용 중입니다"
ErrAppLimit: "앱 설치 제한을 초과했습니다"
ErrAppRequired: "{{ .detail }} 앱이 필요합니다"
ErrNotInstall: "앱이 설치되지 않았습니다"
ErrPortInOtherApp: "{{ .port }} 포트가 {{ .apps }} 앱에 의해 이미 사용 중입니다"
ErrDbUserNotValid: "데이터베이스 사용자 이름과 비밀번호가 일치하지 않습니다!"
ErrDockerComposeNotValid: "docker-compose 파일 형식 오류!"
ErrUpdateBuWebsite: "애플리케이션이 성공적으로 업데이트되었지만, 웹사이트 구성 파일 수정에 실패했습니다. 구성을 확인하세요!"
Err1PanelNetworkFailed: "기본 컨테이너 네트워크 생성 실패! {{ .detail }}"
ErrFileParse: "애플리케이션 docker-compose 파일 분석 실패!"
ErrInstallDirNotFound: "설치 디렉터리가 존재하지 않습니다"
AppStoreIsUpToDate: "최신 상태입니다"
LocalAppVersionNull: "{{.name}} 앱 버전이 동기화되지 않았습니다! 애플리케이션 목록에 추가할 수 없습니다"
LocalAppVersionErr: "{{.name}} 버전 {{.version}} 동기화 실패! {{.err}}"
ErrFileNotFound: "{{.name}} 파일이 존재하지 않습니다"
ErrFileParseApp: "{{.name}} 파일 분석 실패 {{.err}}"
ErrAppDirNull: "버전 폴더가 존재하지 않습니다"
LocalAppErr: "앱 {{.name}} 동기화 실패! {{.err}}"
ErrContainerName: "컨테이너 이름이 이미 존재합니다"
ErrAppSystemRestart: "1Panel 재시작으로 인해 작업이 중단되었습니다"
ErrCreateHttpClient: "HTTP 요청 생성 실패 {{.err}}"
ErrHttpReqTimeOut: "요청 시간이 초과되었습니다 {{.err}}"
ErrHttpReqFailed: "요청 실패 {{.err}}"
ErrHttpReqNotFound: "파일이 존재하지 않습니다"
ErrNoSuchHost: "네트워크 연결 실패"
ErrImagePullTimeOut: "이미지 가져오기 시간 초과"
ErrContainerNotFound: "{{ .name }} 컨테이너가 존재하지 않습니다"
ErrContainerMsg: "{{ .name }} 컨테이너가 비정상적입니다. 자세한 내용은 컨테이너 페이지의 로그를 확인하세요"
ErrAppBackup: "{{ .name }} 애플리케이션 백업 실패 오류 {{.err}}"
ErrImagePull: "{{ .name }} 이미지 가져오기 실패 오류 {{.err}}"
ErrVersionTooLow: "현재 1Panel 버전이 낮아 앱 스토어를 업데이트할 수 없습니다. 버전을 업그레이드하세요"
ErrAppNameExist: "앱 이름이 이미 존재합니다"
AppStoreIsSyncing: "앱 스토어가 동기화 중입니다. 나중에 다시 시도하세요"
ErrGetCompose: "docker-compose.yml 파일 가져오기 실패! {{ .detail }}"
ErrAppWarn: "비정상 상태, 로그를 확인하세요"
ErrAppParamKey: "매개변수 {{ .name }} 필드 예외"
ErrAppUpgrade: "애플리케이션 {{ .name }} 업그레이드 실패 {{ .err }}"
AppRecover: "앱 {{ .name }} 롤백 완료"
PullImageStart: "이미지 {{ .name }} 가져오기 시작"
PullImageSuccess: "이미지 가져오기 성공"
UpgradeAppStart: "애플리케이션 {{ .name }} 업그레이드 시작"
UpgradeAppSuccess: "앱 {{ .name }} 업그레이드 성공"
# 파일
ErrFileCanNotRead: "파일을 읽을 수 없습니다"
ErrFileToLarge: "파일이 너무 큽니다"
ErrPathNotFound: "경로를 찾을 수 없습니다"
ErrMovePathFailed: "대상 경로가 원래 경로를 포함할 수 없습니다!"
ErrLinkPathNotFound: "대상 경로가 존재하지 않습니다!"
ErrFileIsExist: "파일 또는 디렉터리가 이미 존재합니다!"
ErrFileUpload: "파일 업로드 실패 {{.name}} {{.detail}}"
ErrFileDownloadDir: "다운로드 폴더는 지원되지 않습니다"
ErrCmdNotFound: "{{ .name }} 명령이 존재하지 않습니다. 호스트에 이 명령을 먼저 설치하세요"
ErrSourcePathNotFound: "소스 디렉터리가 존재하지 않습니다"
ErrFavoriteExist: "이 경로는 이미 즐겨찾기에 추가되었습니다"
ErrInvalidChar: "잘못된 문자는 금지됩니다"
ErrPathNotDelete: "선택한 디렉터리는 삭제할 수 없습니다"
# 웹사이트
ErrDomainIsExist: "도메인 이름이 이미 존재합니다"
ErrAliasIsExist: "별칭이 이미 존재합니다"
ErrAppDelete: "다른 웹사이트에서 이 애플리케이션을 사용 중입니다"
ErrGroupIsUsed: "그룹이 사용 중이므로 삭제할 수 없습니다"
ErrBackupMatch: "백업 파일이 현재 웹사이트 데이터와 일치하지 않습니다: {{ .detail }}"
ErrBackupExist: "백업 파일이 원본 데이터의 일부와 일치하지 않습니다: {{ .detail }}"
ErrPHPResource: "로컬 런타임에서 전환을 지원하지 않습니다!"
ErrPathPermission: "인덱스 디렉터리에 1000:1000 권한이 아닌 폴더가 감지되었습니다. 웹사이트 액세스 시 '접근 거부' 오류가 발생할 수 있습니다. 상단의 저장 버튼을 클릭하세요"
ErrDomainIsUsed: "도메인이 웹사이트 {{ .name }}에서 이미 사용 중입니다"
ErrDomainFormat: "{{ .name }} 도메인 형식 오류"
ErrDefaultAlias: "기본은 예약된 코드 이름입니다. 다른 이름을 사용하세요"
ErrImageNotExist: "실행 환경 {{.name}} 이미지가 존재하지 않습니다. 실행 환경을 다시 편집하세요"
# SSL 관련
ErrSSLCannotDelete: "인증서 {{ .name }}은(는) 웹사이트에서 사용 중이므로 삭제할 수 없습니다."
ErrAccountCannotDelete: "계정과 연결된 인증서는 삭제할 수 없습니다."
ErrSSLApply: "인증서가 성공적으로 서명되었지만 Openresty 다시 로드에 실패했습니다. 구성을 확인하세요!"
ErrEmailIsExist: "이메일이 이미 존재합니다."
ErrSSLKeyNotFound: "개인 키 파일이 존재하지 않습니다."
ErrSSLCertificateNotFound: "인증서 파일이 존재하지 않습니다."
ErrSSLKeyFormat: "개인 키 파일 검증 오류"
ErrSSLCertificateFormat: "인증서 파일 형식 오류입니다. pem 형식을 사용하세요."
ErrEabKidOrEabHmacKeyCannotBlank: "EabKid 또는 EabHmacKey 는 비워둘 수 없습니다."
ErrOpenrestyNotFound: "HTTP 모드는 먼저 Openresty 를 설치해야 합니다."
ApplySSLStart: "인증서를 신청하기 시작합니다. 도메인 이름 [{{ .domain }}], 신청 방법 [{{ .type }}]"
dnsAccount: "DNS 자동"
dnsManual: "DNS 수동"
http: "HTTP"
ApplySSLFailed: "도메인 [{{ .domain }}] 인증서 신청 실패, {{ .detail }}"
ApplySSLSuccess: "도메인 [{{ .domain }}] 인증서 신청 성공!"
DNSAccountName: "DNS 계정 [{{ .name }}] 제조사 [{{ .type }}]"
PushDirLog: "인증서를 디렉토리 [{{ .path }}]에 푸시했습니다. {{ .status }}"
ErrDeleteCAWithSSL: "현재 조직에 발급된 인증서가 있으므로 삭제할 수 없습니다."
ErrDeleteWithPanelSSL: "패널 SSL 구성이 이 인증서를 사용 중이므로 삭제할 수 없습니다."
ErrDefaultCA: "기본 인증 기관은 삭제할 수 없습니다."
ApplyWebSiteSSLLog: "{{ .name }} 웹사이트 인증서를 업데이트하기 시작합니다."
ErrUpdateWebsiteSSL: "{{ .name }} 웹사이트 인증서 업데이트 실패: {{ .err }}"
ApplyWebSiteSSLSuccess: "웹사이트 인증서 업데이트 성공"
ErrExecShell: "스크립트 실행 실패 {{ .err }}"
ExecShellStart: "스크립트 실행 시작"
ExecShellSuccess: "스크립트 실행 성공"
StartUpdateSystemSSL: "시스템 인증서 업데이트 시작"
UpdateSystemSSLSuccess: "시스템 인증서 업데이트 성공"
# MySQL
ErrUserIsExist: "현재 사용자가 이미 존재합니다. 새로운 사용자를 입력하세요."
ErrDatabaseIsExist: "현재 데이터베이스가 이미 존재합니다. 새로운 데이터베이스를 입력하세요."
ErrExecTimeOut: "SQL 실행이 시간 초과되었습니다. 데이터베이스를 확인하세요."
ErrRemoteExist: "원격 데이터베이스에 동일한 이름이 이미 존재합니다. 이름을 수정한 후 다시 시도하세요."
ErrLocalExist: "로컬 데이터베이스에 동일한 이름이 이미 존재합니다. 이름을 수정한 후 다시 시도하세요."
# Redis
ErrTypeOfRedis: "복구 파일 형식이 현재 지속성 모드와 일치하지 않습니다. 파일 형식을 수정한 후 다시 시도하세요."
# Container
ErrInUsed: "{{ .detail }}이(가) 사용 중이므로 삭제할 수 없습니다."
ErrObjectInUsed: "이 객체는 사용 중이므로 삭제할 수 없습니다."
ErrObjectBeDependent: "이 이미지는 다른 이미지에 의해 의존되고 있어 삭제할 수 없습니다."
ErrPortRules: "포트 수가 일치하지 않습니다. 다시 입력하세요!"
ErrPgImagePull: "이미지 가져오기 시간이 초과되었습니다. 이미지 가속 구성을 설정하거나 postgres:16.0-alpine 이미지를 수동으로 가져온 후 다시 시도하세요."
# Runtime
ErrDirNotFound: "빌드 폴더가 존재하지 않습니다! 파일의 무결성을 확인하세요!"
ErrFileNotExist: "{{ .detail }} 파일이 존재하지 않습니다! 소스 파일의 무결성을 확인하세요!"
ErrImageBuildErr: "이미지 빌드 실패"
ErrImageExist: "이미지가 이미 존재합니다!"
ErrDelWithWebsite: "운영 환경이 웹사이트와 연결되어 있어 삭제할 수 없습니다."
ErrRuntimeStart: "실행 시작 실패"
ErrPackageJsonNotFound: "package.json 파일이 존재하지 않습니다."
ErrScriptsNotFound: "package.json 에서 스크립트 구성 항목을 찾을 수 없습니다."
ErrContainerNameNotFound: "컨테이너 이름을 가져올 수 없습니다. .env 파일을 확인하세요."
ErrNodeModulesNotFound: "node_modules 폴더가 존재하지 않습니다! 실행 환경을 편집하거나 실행 환경이 성공적으로 시작되기를 기다리세요."
# Setting
ErrBackupInUsed: "백업 계정이 크론 작업에 사용 중이므로 삭제할 수 없습니다."
ErrBackupCheck: "백업 계정 연결 테스트 실패 {{ .err }}"
ErrOSSConn: "최신 버전을 가져올 수 없습니다. 서버가 외부 네트워크에 연결할 수 있는지 확인하세요."
ErrEntrance: "보안 입구 정보 오류. 확인 후 다시 시도하세요!"
# Tool
ErrConfigNotFound: "구성 파일이 존재하지 않습니다."
ErrConfigParse: "구성 파일 형식 오류"
ErrConfigIsNull: "구성 파일은 비워둘 수 없습니다."
ErrConfigDirNotFound: "실행 디렉토리가 존재하지 않습니다."
ErrConfigAlreadyExist: "동일한 이름의 구성 파일이 이미 존재합니다."
ErrUserFindErr: "사용자 {{ .name }} 찾기 실패 {{ .err }}"
# SSH
ErrFirewallNone: "시스템에서 firewalld 또는 ufw 서비스를 감지하지 못했습니다. 확인 후 다시 시도하세요!"
ErrFirewallBoth: "시스템에서 firewalld 와 ufw 서비스가 모두 감지되었습니다. 충돌을 방지하려면 하나를 제거한 후 다시 시도하세요!"
# Cronjob
ErrBashExecute: "스크립트 실행 오류. 작업 출력 텍스트 영역에서 구체적인 정보를 확인하세요."
ErrCutWebsiteLog: "{{ .name }} 웹사이트 로그 자르기 실패, 오류 {{ .err }}"
CutWebsiteLogSuccess: "{{ .name }} 웹사이트 로그 자르기 성공, 백업 경로 {{ .path }}"
# Toolbox
ErrNotExistUser: "현재 사용자가 존재하지 않습니다. 수정 후 다시 시도하세요!"
ErrBanAction: "설정 실패, 현재 {{ .name }} 서비스가 사용할 수 없습니다. 확인 후 다시 시도하세요!"
ErrClamdscanNotFound: "clamdscan 명령을 감지하지 못했습니다. 설치 문서를 참조하세요!"
# WAF
ErrScope: "이 구성의 수정은 지원되지 않습니다."
ErrStateChange: "상태 수정 실패"
ErrRuleExist: "규칙이 이미 존재합니다."
ErrRuleNotExist: "규칙이 존재하지 않습니다."
ErrParseIP: "IP 형식 오류"
ErrDefaultIP: "default 는 예약된 이름입니다. 다른 이름으로 변경하세요."
ErrGroupInUse: "IP 그룹이 블랙/화이트 리스트에서 사용 중이며 삭제할 수 없습니다."
ErrGroupExist: "IP 그룹 이름이 이미 존재합니다."
ErrIPRange: "잘못된 IP 범위"
ErrIPExist: "IP가 이미 존재합니다."
# License
ErrLicense: "라이선스 형식 오류, 확인 후 다시 시도하세요!"
ErrLicenseCheck: "라이선스 검증 실패, 확인 후 다시 시도하세요!"
ErrXpackVersion: "라이선스 검증 실패, 이 라이선스는 버전 제한이 있어 성공적으로 가져올 수 없습니다. 확인 후 다시 시도하세요!"
ErrLicenseSave: "라이선스 정보 저장 실패, 오류 {{ .err }}. 다시 시도하세요!"
ErrLicenseSync: "라이선스 정보 동기화 실패, 데이터베이스에서 라이선스 정보를 감지하지 못했습니다!"
ErrXpackNotFound: "이 섹션은 전문가 버전 기능입니다. Panel 설정 - 라이선스 인터페이스에서 먼저 라이선스를 가져오세요."
ErrXpackNotActive: "이 섹션은 전문가 버전 기능입니다. Panel 설정 - 라이선스 인터페이스에서 먼저 라이선스 상태를 동기화하세요."
ErrXpackOutOfDate: "현재 라이선스가 만료되었습니다. Panel 설정 - 라이선스 인터페이스에서 라이선스를 다시 가져오세요."
ErrXpackLost: "라이선스가 최대 재시도 횟수에 도달했습니다. [설정] - [라이선스] 페이지로 이동하여 동기화 버튼을 수동으로 클릭해 전문가 버전 기능을 정상적으로 작동시키세요."
ErrXpackTimeout: "요청 시간이 초과되었습니다. 네트워크 연결이 불안정할 수 있으니 나중에 다시 시도하세요!"
# Alert
ErrAlert: "알림 정보 형식 오류, 확인 후 다시 시도하세요!"
ErrAlertPush: "알림 전송 오류, 확인 후 다시 시도하세요!"
ErrAlertSave: "알림 저장 오류, 확인 후 다시 시도하세요!"
ErrAlertSync: "알림 동기화 오류, 확인 후 다시 시도하세요!"
ErrAlertRemote: "원격 알림 오류, 확인 후 다시 시도하세요!"
# CMD
AppVersion: "앱 버전"
AppCommands: "앱 관련 명령어"
AppInit: "앱 초기화"
AppKeyVal: "앱 키 (영어만 지원)"
AppCreateFileErr: "파일 {{ .name }} 생성 실패 {{ .err }}"
AppCreateDirErr: "폴더 {{ .name }} 생성 실패 {{ .err }}"
AppMissKey: "앱 키가 없습니다. -k 옵션으로 지정하세요."
AppMissVersion: "앱 버전이 없습니다. -v 옵션으로 지정하세요."
AppVersionExist: "버전이 이미 존재합니다!"
AppCreateSuccessful: "생성 성공!"
AppWriteErr: "파일 {{ .name }} 쓰기 실패 {{ .err }}"
SudoHelper: "{{ .cmd }} 명령을 사용하거나 root 사용자로 전환하세요."
ListenIPCommands: "IP 변경"
ListenIPv4: "IPv4 에서 수신 대기"
ListenIPv6: "IPv6 에서 수신 대기"
ListenChangeSuccessful: "변경 성공! 현재 {{ .value }}에서 수신 대기 중입니다."
ResetCommands: "시스템 정보 초기화"
ResetMFA: "1Panel 이중 인증 취소"
ResetHttps: "1Panel HTTPS 로그인 취소"
ResetEntrance: "1Panel 보안 입구 취소"
ResetIPs: "1Panel 허용 IP 제한 취소"
ResetDomain: "1Panel 도메인 바인딩 취소"
RestoreCommands: "1Panel 서비스 및 데이터 복구"
RestoreNoSuchFile: "복구 가능한 파일이 없습니다."
RestoreStep1: "(1/5) {{ .name }} 디렉토리에서 1Panel 서비스 및 데이터 복구 시작..."
RestoreStep2: "(2/5) 1Panel 바이너리 복구 성공"
RestoreStep3: "(3/5) 1Panel 스크립트 복구 성공"
RestoreStep4: "(4/5) 1Panel 서비스 복구 성공"
RestoreStep5: "(5/5) 1Panel 데이터 복구 성공"
RestoreSuccessful: "복구 성공! 서비스를 다시 시작합니다. 잠시만 기다려주세요..."
UpdateCommands: "패널 정보 업데이트"
UpdateUser: "패널 사용자 업데이트"
UpdatePassword: "패널 비밀번호 업데이트"
UpdatePort: "패널 포트 업데이트"
UpdateUserNull: "오류: 패널 사용자가 비어 있습니다!"
UpdateUserBlank: "오류: 패널 사용자에 공백이 포함되어 있습니다!"
UpdateUserFormat: "오류: 잘못된 패널 사용자 형식! 영어, 중국어, 숫자, _만 지원하며 길이는 3~30자입니다."
UpdateUserErr: "오류: 패널 사용자 업데이트 실패 {{ .err }}"
UpdateSuccessful: "업데이트 성공!"
UpdateUserResult: "패널 사용자: {{ .name }}"
UpdatePasswordRead: "오류: 패널 비밀번호 정보 읽기 실패 {{ .err }}"
UpdatePasswordNull: "오류: 패널 비밀번호가 비어 있습니다!"
UpdateUPasswordBlank: "오류: 패널 비밀번호에 공백이 포함되어 있습니다!"
UpdatePasswordFormat: "오류: 패널 비밀번호는 문자, 숫자, 특수 문자 !@#$%*_,.?만 지원하며 길이는 8~30자입니다!"
UpdatePasswordLen: "오류: 6자 이상의 비밀번호를 입력하세요!"
UpdatePasswordRe: "비밀번호 확인:"
UpdatePasswordErr: "오류: 패널 비밀번호 업데이트 실패 {{ .err }}"
UpdatePasswordSame: "오류: 두 비밀번호가 일치하지 않습니다. 확인 후 다시 시도하세요!"
UpdatePasswordResult: "패널 비밀번호: {{ .name }}"
UpdatePortFormat: "오류: 입력한 포트 번호는 1~65535 사이여야 합니다!"
UpdatePortUsed: "오류: 포트 번호가 이미 사용 중입니다. 확인 후 다시 시도하세요!"
UpdatePortErr: "오류: 패널 포트 업데이트 실패 {{ .err }}"
UpdatePortResult: "패널 포트: {{ .name }}"
UpdatePortFirewallAdd: "방화벽 포트 규칙 추가 실패 {{ .err }}, 방화벽 규칙에 {{ .name }} 포트를 수동으로 추가하세요."
UpdatePortFirewallDel: "오류: 방화벽 포트 삭제 실패 {{ .err }}"
UpdatePortFirewallReload: "방화벽 다시 로드 실패 {{ .err }}, 방화벽을 수동으로 다시 로드하세요."
UserInfo: "패널 정보 가져오기"
UserInfoAddr: "패널 주소: "
UserInfoPassHelp: "팁: 비밀번호를 변경하려면 다음 명령어를 실행할 수 있습니다: "
DBConnErr: "오류: 데이터베이스 연결 초기화 실패 {{ .err }}"
SystemVersion: "버전: "
SystemMode: "모드: "
+74 -74
View File
@@ -18,7 +18,7 @@ ErrApiConfigKeyTimeInvalid: "API 介面時間戳記錯誤: {{ .detail }}"
ErrNameIsExist: "名稱已存在"
ErrDemoEnvironment: "演示伺服器,禁止此操作!"
ErrCmdTimeout: "指令執行超時!"
ErrCmdIllegal: "執行命令中存在不合法字符,請修改後重試!"
ErrCmdIllegal: "執行指令中存在不合法字元,請修改後重試!"
ErrPortExist: '{{ .port }} 埠已被 {{ .type }} [{{ .name }}] 佔用'
TYPE_APP: "應用"
TYPE_RUNTIME: "運作環境"
@@ -37,30 +37,30 @@ ErrAppRequired: "請先安裝 {{ .detail }} 應用"
ErrNotInstall: "應用未安裝"
ErrPortInOtherApp: "{{ .port }} 埠已被應用 {{ .apps }} 佔用!"
ErrDbUserNotValid: "儲存資料庫,用戶名密碼不匹配!"
ErrDockerComposeNotValid: "docker-compose 文件格式錯誤"
ErrDockerComposeNotValid: "docker-compose 檔案格式錯誤"
ErrUpdateBuWebsite: '應用更新成功,但是網站配置文件修改失敗,請檢查配置!'
Err1PanelNetworkFailed: '預設容器網路建立失敗!{{ .detail }}'
ErrFileParse: '應用 docker-compose 文件解析失敗!'
ErrFileParse: '應用 docker-compose 檔案解析失敗!'
ErrInstallDirNotFound: '安裝目錄不存在'
AppStoreIsUpToDate: '應用商店已經是最新版本'
LocalAppVersionNull: '{{.name}} 應用未同步到版本!無法添加到應用列表'
LocalAppVersionErr: '{{.name}} 同步版本 {{.version}} 失敗!{{.err}}'
ErrFileNotFound: '{{.name}} 文件不存在'
ErrFileParseApp: '{{.name}} 文件解析失敗 {{.err}}'
LocalAppVersionNull: '{{ .name }} 應用未同步到版本!無法新增到應用列表'
LocalAppVersionErr: '{{ .name }} 同步版本 {{ .version }} 失敗!{{ .err }}'
ErrFileNotFound: '{{ .name }} 檔案不存在'
ErrFileParseApp: '{{ .name }} 檔案解析失敗 {{ .err }}'
ErrAppDirNull: '版本資料夾不存在'
LocalAppErr: "應用 {{.name}} 同步失敗!{{.err}}"
LocalAppErr: "應用 {{ .name }} 同步失敗!{{ .err }}"
ErrContainerName: "容器名稱已存在"
ErrAppSystemRestart: "1Panel 重啟導致任務中斷"
ErrCreateHttpClient: "建立HTTP請求失敗 {{.err}}"
ErrHttpReqTimeOut: "請求超時 {{.err}}"
ErrHttpReqFailed: "請求失敗 {{.err}}"
ErrHttpReqNotFound: "文件不存在"
ErrNoSuchHost: "網路連接失敗"
ErrCreateHttpClient: "建立HTTP請求失敗 {{ .err }}"
ErrHttpReqTimeOut: "請求超時 {{ .err }}"
ErrHttpReqFailed: "請求失敗 {{ .err }}"
ErrHttpReqNotFound: "檔案不存在"
ErrNoSuchHost: "網路連線失敗"
ErrImagePullTimeOut: "鏡像拉取超時"
ErrContainerNotFound: '{{ .name }} 容器不存在'
ErrContainerMsg: '{{ .name }} 容器異常,具體請在容器頁面查看日誌'
ErrAppBackup: '{{ .name }} 應用備份失敗 err {{.err}}'
ErrImagePull: '{{ .name }} 鏡像拉取失敗 err {{.err}}'
ErrAppBackup: '{{ .name }} 應用備份失敗 err {{ .err }}'
ErrImagePull: '{{ .name }} 鏡像拉取失敗 err {{ .err }}'
ErrVersionTooLow: '目前 1Panel 版本過低,無法更新應用商店,請升級版本之後操作'
ErrAppNameExist: '應用名稱已存在'
AppStoreIsSyncing: '應用程式商店正在同步中,請稍後再試'
@@ -68,22 +68,22 @@ ErrGetCompose: "docker-compose.yml 檔案取得失敗!{{ .detail }}"
ErrAppWarn: "狀態異常,請查看日誌"
ErrAppParamKey: "參數 {{ .name }} 欄位異常"
ErrAppUpgrade: "應用程式 {{ .name }} 升級失敗 {{ .err }}"
AppRecover: "應用程式 {{ .name }} 回滾 "
AppRecover: "應用程式 {{ .name }} 轉返 "
PullImageStart: "開始拉取鏡像 {{ .name }}"
PullImageSuccess: "鏡像拉取成功"
UpgradeAppStart: "開始升級應用程式 {{ .name }}"
UpgradeAppSuccess: "應用程式 {{ .name }} 升級成功"
#file
ErrFileCanNotRead: "此文件不支援預覽"
ErrFileToLarge: "文件超過10M,無法打開"
ErrFileCanNotRead: "此檔案不支援預覽"
ErrFileToLarge: "檔案超過10M,無法打開"
ErrPathNotFound: "目錄不存在"
ErrMovePathFailed: "目標路徑不能包含原路徑!"
ErrLinkPathNotFound: "目標路徑不存在!"
ErrFileIsExist: "文件或資料夾已存在!"
ErrFileUpload: "{{ .name }} 上傳文件失敗 {{ .detail}}"
ErrFileIsExist: "檔案或資料夾已存在!"
ErrFileUpload: "{{ .name }} 上傳檔案失敗 {{ .detail }}"
ErrFileDownloadDir: "不支援下載資料夾"
ErrCmdNotFound: "{{ .name}} 命令不存在,請先在宿主機安裝此命令"
ErrCmdNotFound: "{{ .name}} 指令不存在,請先在宿主機安裝此指令"
ErrSourcePathNotFound: "源目錄不存在"
ErrFavoriteExist: "已收藏此路徑"
ErrPathNotDelete: "所選目錄不可刪除"
@@ -93,33 +93,33 @@ ErrDomainIsExist: "域名已存在"
ErrAliasIsExist: "代號已存在"
ErrAppDelete: '其他網站使用此應用,無法刪除'
ErrGroupIsUsed: '分組正在使用中,無法刪除'
ErrBackupMatch: '該備份文件與目前網站部分數據不匹配: {{ .detail}}'
ErrBackupExist: '該備份文件對應部分原數據不存在: {{ .detail}}'
ErrPHPResource: '本地運行環境不支援切換!'
ErrPathPermission: 'index 目錄下偵測到非 1000:1000 權限資料夾,可能導致網站存取 Access denied 錯誤,請點擊上方儲存按鈕'
ErrBackupMatch: '該備份檔案與目前網站部分資料不匹配: {{ .detail }}'
ErrBackupExist: '該備份檔案對應部分原資料不存在: {{ .detail }}'
ErrPHPResource: '本機執行環境不支援切換!'
ErrPathPermission: 'index 目錄下偵測到非 1000:1000 權限資料夾,可能導致網站存取 Access denied 錯誤,請點選上方儲存按鈕'
ErrDomainIsUsed: "域名已被網站【{{ .name }}】使用"
ErrDomainFormat: "{{ .name }} 域名格式不正確"
ErrDefaultAlias: "default 為保留代號,請使用其他代號"
ErrImageNotExist: "執行環境 {{.name}} 鏡像不存在,請重新編輯執行環境"
ErrImageNotExist: "執行環境 {{ .name }} 鏡像不存在,請重新編輯執行環境"
#ssl
ErrSSLCannotDelete: "{{ .name }} 證書正在被網站使用,無法刪除"
ErrAccountCannotDelete: "帳號關聯證書,無法刪除"
ErrSSLApply: "證書續簽成功,openresty reload失敗,請檢查配置!"
ErrEmailIsExist: '郵箱已存在'
ErrSSLKeyNotFound: '私鑰文件不存在'
ErrSSLCertificateNotFound: '證書文件不存在'
ErrSSLKeyFormat: '私鑰文件校驗錯誤'
ErrSSLCertificateFormat: '證書文件格式錯誤,請使用 pem 格式'
ErrEmailIsExist: '信箱已存在'
ErrSSLKeyNotFound: '私鑰檔案不存在'
ErrSSLCertificateNotFound: '證書檔案不存在'
ErrSSLKeyFormat: '私鑰檔案校驗錯誤'
ErrSSLCertificateFormat: '證書檔案格式錯誤,請使用 pem 格式'
ErrEabKidOrEabHmacKeyCannotBlank: 'EabKid 或 EabHmacKey 不能為空'
ErrOpenrestyNotFound: 'Http 模式需要先安裝 Openresty'
ApplySSLStart: '開始申請憑證,網域 [{{ .domain }}] 申請方式 [{{ .type }}] '
dnsAccount: "DNS 自動"
dnsManual: "DNS 手排"
http: "HTTP"
ApplySSLFailed: '申請 [{{ .domain }}] 憑證失敗, {{.detail}} '
ApplySSLFailed: '申請 [{{ .domain }}] 憑證失敗, {{ .detail }} '
ApplySSLSuccess: '申請 [{{ .domain }}] 憑證成功! ! '
DNSAccountName: 'DNS 帳號 [{{ .name }}] 廠商 [{{.type}}]'
DNSAccountName: 'DNS 帳號 [{{ .name }}] 廠商 [{{ .type }}]'
PushDirLog: '憑證推送到目錄 [{{ .path }}] {{ .status }}'
ErrDeleteCAWithSSL: "目前機構下存在已簽發證書,無法刪除"
ErrDeleteWithPanelSSL: "面板 SSL 配置使用此證書,無法刪除"
@@ -137,34 +137,34 @@ UpdateSystemSSLSuccess: "更新系統證書成功"
ErrUserIsExist: "目前用戶已存在,請重新輸入"
ErrDatabaseIsExist: "目前資料庫已存在,請重新輸入"
ErrExecTimeOut: "SQL 執行超時,請檢查資料庫"
ErrRemoteExist: "遠程資料庫已存在該名稱,請修改後重試"
ErrLocalExist: "本地資料庫已存在該名稱,請修改後重試"
ErrRemoteExist: "遠端資料庫已存在該名稱,請修改後重試"
ErrLocalExist: "本機資料庫已存在該名稱,請修改後重試"
#redis
ErrTypeOfRedis: "恢復文件類型與目前持久化方式不匹配,請修改後重試"
ErrTypeOfRedis: "復原檔案類型與目前持久化方式不匹配,請修改後重試"
#container
ErrInUsed: "{{ .detail }} 正被使用,無法刪除"
ErrObjectInUsed: "該對象正被使用,無法刪除"
ErrObjectInUsed: "該物件正被使用,無法刪除"
ErrObjectBeDependent: "該鏡像依賴於其他鏡像,無法刪除"
ErrPortRules: "埠數目不匹配,請重新輸入!"
ErrPgImagePull: "鏡像拉取超時,請配置鏡像加速或手動拉取 postgres:16.0-alpine 鏡像後重試"
#runtime
ErrDirNotFound: "build 資料夾不存在!請檢查文件完整性!"
ErrFileNotExist: "{{ .detail }} 文件不存在!請檢查源文件完整性!"
ErrDirNotFound: "build 資料夾不存在!請檢查檔案完整性!"
ErrFileNotExist: "{{ .detail }} 檔案不存在!請檢查源文件完整性!"
ErrImageBuildErr: "鏡像 build 失敗"
ErrImageExist: "鏡像已存在!"
ErrDelWithWebsite: "運行環境已經關聯網站,無法刪除"
ErrDelWithWebsite: "執行環境已經關聯網站,無法刪除"
ErrRuntimeStart: "啟動失敗"
ErrPackageJsonNotFound: "package.json 文件不存在"
ErrPackageJsonNotFound: "package.json 檔案不存在"
ErrScriptsNotFound: "沒有在 package.json 中找到 scripts 配置項"
ErrContainerNameNotFound: "無法取得容器名稱,請檢查 .env 文件"
ErrNodeModulesNotFound: "node_modules 資料夾不存在!請編輯運行環境或者等待運行環境啟動成功"
ErrContainerNameNotFound: "無法取得容器名稱,請檢查 .env 檔案"
ErrNodeModulesNotFound: "node_modules 資料夾不存在!請編輯執行環境或者等待執行環境啟動成功"
#setting
ErrBackupInUsed: "該備份帳號已在計劃任務中使用,無法刪除"
ErrBackupCheck: "備份帳號測試連接失敗 {{ .err}}"
ErrBackupCheck: "備份帳號測試連線失敗 {{ .err }}"
ErrOSSConn: "無法取得最新版本,請確認伺服器是否能夠連接外部網路。"
ErrEntrance: "安全入口資訊錯誤,請檢查後重試!"
@@ -172,16 +172,16 @@ ErrEntrance: "安全入口資訊錯誤,請檢查後重試!"
ErrConfigNotFound: "配置文件不存在"
ErrConfigParse: "配置文件格式有誤"
ErrConfigIsNull: "配置文件不允許為空"
ErrConfigDirNotFound: "運行目錄不存在"
ErrConfigDirNotFound: "執行目錄不存在"
ErrConfigAlreadyExist: "已存在同名配置文件"
ErrUserFindErr: "用戶 {{ .name }} 查找失敗 {{ .err }}"
ErrUserFindErr: "用戶 {{ .name }} 尋找失敗 {{ .err }}"
#ssh
ErrFirewallNone: "未檢測到系統 firewalld 或 ufw 服務,請檢查後重試!"
ErrFirewallBoth: "檢測到系統同時存在 firewalld 或 ufw 服務,為避免衝突,請移除後重試!"
#cronjob
ErrBashExecute: "腳本執行錯誤,請在任務輸出文本域中查看具體資訊。"
ErrBashExecute: "腳本執行錯誤,請在任務輸出文字區域中查看具體資訊。"
ErrCutWebsiteLog: "{{ .name }} 網站日誌切割失敗,錯誤 {{ .err }}"
CutWebsiteLogSuccess: "{{ .name }} 網站日誌切割成功,備份路徑 {{ .path }}"
@@ -205,67 +205,67 @@ ErrIPExist: "IP 已存在"
#license
ErrLicense: "許可證格式錯誤,請檢查後重試!"
ErrLicenseCheck: "許可證校驗失敗,請檢查後重試!"
ErrXpackVersion: "許可證校驗失敗,該許可證受版本限制,無法成功導入,請檢查後重試!"
ErrLicenseSave: "許可證資訊保存失敗,錯誤 {{ .err }}, 請重試!"
ErrXpackVersion: "許可證校驗失敗,該許可證受版本限制,無法成功匯入,請檢查後重試!"
ErrLicenseSave: "許可證資訊儲存失敗,錯誤 {{ .err }}, 請重試!"
ErrLicenseSync: "許可證資訊同步失敗,資料庫中未檢測到許可證資訊!"
ErrXpackNotFound: "該部分為專業版功能,請先在 面板設定-許可證 界面導入許可證"
ErrXpackNotActive: "該部分為專業版功能,請先在 面板設定-許可證 界面同步許可證狀態"
ErrXpackOutOfDate: "目前許可證已過期,請重新在 面板設定-許可證 界面導入許可證"
ErrXpackLost: "許可證已達到最大重試次數,請進入【面板設定】【許可證】頁面手動點擊同步按鈕,以確保專業版功能正常使用"
ErrXpackTimeout: "請求超時,網路連接可能不穩定,請稍後再試!"
ErrXpackNotFound: "該部分為專業版功能,請先在 面板設定-許可證 介面匯入許可證"
ErrXpackNotActive: "該部分為專業版功能,請先在 面板設定-許可證 介面同步許可證狀態"
ErrXpackOutOfDate: "目前許可證已過期,請重新在 面板設定-許可證 介面匯入許可證"
ErrXpackLost: "許可證已達到最大重試次數,請進入【面板設定】【許可證】頁面手動點選同步按鈕,以確保專業版功能正常使用"
ErrXpackTimeout: "請求超時,網路連線可能不穩定,請稍後再試!"
#license
ErrAlert: "告警資訊格式錯誤,請檢查後重試!"
ErrAlertPush: "告警資訊推送錯誤,請檢查後重試!"
ErrAlertSave: "告警資訊保存錯誤,請檢查後重試!"
ErrAlertSave: "告警資訊儲存錯誤,請檢查後重試!"
ErrAlertSync: "告警資訊同步錯誤,請檢查後重試!"
ErrAlertRemote: "告警資訊遠端錯誤,請檢查後重試!"
#cmd
AppVersion: "應用版本"
AppCommands: "應用相關命令"
AppCommands: "應用相關指令"
AppInit: "初始化應用"
AppKeyVal: "應用的 key(僅支援英文)"
AppCreateFileErr: "文件 {{ .name }} 建立失敗 {{ .err }}"
AppCreateFileErr: "檔案 {{ .name }} 建立失敗 {{ .err }}"
AppCreateDirErr: "資料夾 {{ .name }} 建立失敗 {{ .err }}"
AppMissKey: "應用的 key 缺失,使用 -k 指定"
AppMissVersion: "應用版本缺失,使用 -v 指定"
AppVersionExist: "版本已存在!"
AppCreateSuccessful: "建立成功!"
AppWriteErr: "文件 {{ .name }} 寫入失敗 {{ .err }}"
AppWriteErr: "檔案 {{ .name }} 寫入失敗 {{ .err }}"
SudoHelper: "請使用 {{ .cmd }} 或者切換到 root 用戶"
ListenIPCommands: "切換監聽 IP"
ListenIPv4: "監聽 IPv4"
ListenIPv6: "監聽 IPv6"
ListenChangeSuccessful: "切換成功!已切換至監聽 {{ .value }}"
ResetCommands: "重置系統資訊"
ResetCommands: "重設系統資訊"
ResetMFA: "取消 1Panel 兩步驗證"
ResetHttps: "取消 1Panel https 方式登錄"
ResetHttps: "取消 1Panel https 方式登入"
ResetEntrance: "取消 1Panel 安全入口"
ResetIPs: "取消 1Panel 授權 IP 限制"
ResetDomain: "取消 1Panel 訪問域名綁定"
RestoreCommands: "回滾 1Panel 服務及數據"
RestoreNoSuchFile: "暫無可回滾文件"
RestoreStep1: "(1/5)開始從 {{ .name }} 目錄回滾 1Panel 服務及數據... "
RestoreStep2: "(2/5)1Panel 二進制回滾成功"
RestoreStep3: "(3/5)1Panel 腳本回滾成功"
RestoreStep4: "(4/5)1Panel 服務回滾成功"
RestoreStep5: "(5/5)1Panel 數據回滾成功"
RestoreSuccessful: "回滾成功!正在重啟服務,請稍候..."
RestoreCommands: "轉返 1Panel 服務及資料"
RestoreNoSuchFile: "暫無可轉返文件"
RestoreStep1: "(1/5)開始從 {{ .name }} 目錄轉返 1Panel 服務及資料... "
RestoreStep2: "(2/5)1Panel 二進制轉返成功"
RestoreStep3: "(3/5)1Panel 腳本轉返成功"
RestoreStep4: "(4/5)1Panel 服務轉返成功"
RestoreStep5: "(5/5)1Panel 資料轉返成功"
RestoreSuccessful: "轉返成功!正在重啟服務,請稍候..."
UpdateCommands: "修改面板資訊"
UpdateUser: "修改面板用戶"
UpdatePassword: "修改面板密碼"
UpdatePort: "修改面板埠"
UpdateUserNull: "錯誤:輸入面板用戶為空!"
UpdateUserBlank: "錯誤:輸入面板用戶中包含空格字符!"
UpdateUserBlank: "錯誤:輸入面板用戶中包含空格字元!"
UpdateUserFormat: "錯誤:輸入面板用戶錯誤!僅支援英文、中文、數字和_,長度3-30"
UpdateUserErr: "錯誤:面板用戶修改失敗,{{ .err }}"
UpdateSuccessful: "修改成功!"
UpdateUserResult: "面板用戶:{{ .name }}"
UpdatePasswordRead: "錯誤:面板密碼資訊讀取錯誤,{{ .err }}"
UpdatePasswordNull: "錯誤:輸入面板密碼為空!"
UpdateUPasswordBlank: "錯誤:輸入面板密碼中包含空格字符!"
UpdatePasswordFormat: "錯誤:面板密碼僅支援字母、數字、特殊字符(!@#$%*_,.?),長度 8-30 位!"
UpdateUPasswordBlank: "錯誤:輸入面板密碼中包含空格字元!"
UpdatePasswordFormat: "錯誤:面板密碼僅支援字母、數字、特殊字元(!@#$%*_,.?),長度 8-30 位!"
UpdatePasswordLen: "錯誤:請輸入 6 位以上密碼!"
UpdatePasswordRe: "確認密碼:"
UpdatePasswordErr: "錯誤:面板密碼修改失敗,{{ .err }}"
@@ -275,12 +275,12 @@ UpdatePortFormat: "錯誤:輸入的埠號必須在 1 到 65535 之間!"
UpdatePortUsed: "錯誤:該埠號正被佔用,請檢查後重試!"
UpdatePortErr: "錯誤:面板埠修改失敗,{{ .err }}"
UpdatePortResult: "面板埠:{{ .name }}"
UpdatePortFirewallAdd: "添加防火牆埠規則失敗,{{ .err }},請您手動將 {{ .name }} 埠添加至防火牆規則中。"
UpdatePortFirewallAdd: "新增防火牆埠規則失敗,{{ .err }},請您手動將 {{ .name }} 埠新增至防火牆規則中。"
UpdatePortFirewallDel: "錯誤:防火牆埠刪除失敗,{{ .err }}"
UpdatePortFirewallReload: "防火牆重載失敗,{{ .err }},請您手動重載防火牆。"
UserInfo: "取得面板資訊"
UserInfoAddr: "面板地址:"
UserInfoPassHelp: "提示:修改密碼可執行命令:"
DBConnErr: "錯誤:初始化資料庫連接失敗,{{ .err }}"
UserInfoPassHelp: "提示:修改密碼可執行指令:"
DBConnErr: "錯誤:初始化資料庫連線失敗,{{ .err }}"
SystemVersion: "版本:"
SystemMode: "模式:"
+17 -17
View File
@@ -42,24 +42,24 @@ Err1PanelNetworkFailed: '默认容器网络创建失败!{{ .detail }}'
ErrFileParse: '应用 docker-compose 文件解析失败!'
ErrInstallDirNotFound: '安装目录不存在'
AppStoreIsUpToDate: '应用商店已经是最新版本'
LocalAppVersionNull: '{{.name}} 应用未同步到版本!无法添加到应用列表'
LocalAppVersionErr: '{{.name}} 同步版本 {{.version}} 失败!{{.err}}'
ErrFileNotFound: '{{.name}} 文件不存在'
ErrFileParseApp: '{{.name}} 文件解析失败 {{.err}}'
LocalAppVersionNull: '{{ .name }} 应用未同步到版本!无法添加到应用列表'
LocalAppVersionErr: '{{ .name }} 同步版本 {{ .version }} 失败!{{ .err }}'
ErrFileNotFound: '{{ .name }} 文件不存在'
ErrFileParseApp: '{{ .name }} 文件解析失败 {{ .err }}'
ErrAppDirNull: '版本文件夹不存在'
LocalAppErr: "应用 {{.name}} 同步失败!{{.err}}"
LocalAppErr: "应用 {{ .name }} 同步失败!{{ .err }}"
ErrContainerName: "容器名称已存在"
ErrAppSystemRestart: "1Panel 重启导致任务终止"
ErrCreateHttpClient: "创建HTTP请求失败 {{.err}}"
ErrHttpReqTimeOut: "请求超时 {{.err}}"
ErrHttpReqFailed: "请求失败 {{.err}}"
ErrCreateHttpClient: "创建HTTP请求失败 {{ .err }}"
ErrHttpReqTimeOut: "请求超时 {{ .err }}"
ErrHttpReqFailed: "请求失败 {{ .err }}"
ErrHttpReqNotFound: "文件不存在"
ErrNoSuchHost: "网络连接失败"
ErrImagePullTimeOut: '镜像拉取超时'
ErrContainerNotFound: '{{ .name }} 容器不存在'
ErrContainerMsg: '{{ .name }} 容器异常,具体请在容器页面查看日志'
ErrAppBackup: '{{ .name }} 应用备份失败 err {{.err}}'
ErrImagePull: '镜像拉取失败 {{.err}}'
ErrAppBackup: '{{ .name }} 应用备份失败 err {{ .err }}'
ErrImagePull: '镜像拉取失败 {{ .err }}'
ErrVersionTooLow: '当前 1Panel 版本过低,无法更新应用商店,请升级版本之后操作'
ErrAppNameExist: '应用名称已存在'
AppStoreIsSyncing: '应用商店正在同步中,请稍后再试'
@@ -80,7 +80,7 @@ ErrPathNotFound: "目录不存在"
ErrMovePathFailed: "目标路径不能包含原路径!"
ErrLinkPathNotFound: "目标路径不存在!"
ErrFileIsExist: "文件或文件夹已存在!"
ErrFileUpload: "{{ .name }} 上传文件失败 {{ .detail}}"
ErrFileUpload: "{{ .name }} 上传文件失败 {{ .detail }}"
ErrFileDownloadDir: "不支持下载文件夹"
ErrCmdNotFound: "{{ .name}} 命令不存在,请先在宿主机安装此命令"
ErrSourcePathNotFound: "源目录不存在"
@@ -93,14 +93,14 @@ ErrDomainIsExist: "域名已存在"
ErrAliasIsExist: "代号已存在"
ErrAppDelete: '其他网站使用此应用,无法删除'
ErrGroupIsUsed: '分组正在使用中,无法删除'
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail}}'
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail}}'
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail }}'
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail }}'
ErrPHPResource: '本地运行环境不支持切换!'
ErrPathPermission: 'index 目录下检测到非 1000:1000 权限文件夹,可能导致网站访问 Access denied 错误,请点击上方保存按钮'
ErrDomainIsUsed: "域名已被网站【{{ .name }}】使用"
ErrDomainFormat: "{{ .name }} 域名格式不正确"
ErrDefaultAlias: "default 为保留代号,请使用其他代号"
ErrImageNotExist: "运行环境 {{.name}} 镜像不存在,请重新编辑运行环境"
ErrImageNotExist: "运行环境 {{ .name }} 镜像不存在,请重新编辑运行环境"
#ssl
ErrSSLCannotDelete: "{{ .name }} 证书正在被网站使用,无法删除"
@@ -117,9 +117,9 @@ ApplySSLStart: '开始申请证书,域名 [{{ .domain }}] 申请方式 [{{ .ty
dnsAccount: "DNS 自动"
dnsManual: "DNS 手动"
http: "HTTP"
ApplySSLFailed: '申请 [{{ .domain }}] 证书失败, {{.detail}} '
ApplySSLFailed: '申请 [{{ .domain }}] 证书失败, {{ .detail }} '
ApplySSLSuccess: '申请 [{{ .domain }}] 证书成功!!'
DNSAccountName: 'DNS 账号 [{{ .name }}] 厂商 [{{.type}}]'
DNSAccountName: 'DNS 账号 [{{ .name }}] 厂商 [{{ .type }}]'
PushDirLog: '证书推送到目录 [{{ .path }}] {{ .status }}'
ErrDeleteCAWithSSL: "当前机构下存在已签发证书,无法删除"
ErrDeleteWithPanelSSL: "面板 SSL 配置使用此证书,无法删除"
@@ -164,7 +164,7 @@ ErrNodeModulesNotFound: "node_modules 文件夹不存在!请编辑运行环境
#setting
ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除"
ErrBackupCheck: "备份账号测试连接失败 {{ .err}}"
ErrBackupCheck: "备份账号测试连接失败 {{ .err }}"
ErrOSSConn: "无法获取最新版本,请确认服务器是否能够连接外部网络。"
ErrEntrance: "安全入口信息错误,请检查后重试!"
+7
View File
@@ -11,6 +11,7 @@ func Init() {
go syncInstalledApp()
go syncRuntime()
go syncSSL()
generateKey()
}
func syncApp() {
@@ -38,3 +39,9 @@ func syncSSL() {
global.LOG.Errorf("sync ssl status error : %s", err.Error())
}
}
func generateKey() {
if err := service.NewISettingService().GenerateRSAKey(); err != nil {
global.LOG.Errorf("generate rsa key error : %s", err.Error())
}
}
+3
View File
@@ -99,6 +99,9 @@ func Init() {
migrations.AddAutoRestart,
migrations.AddApiInterfaceConfig,
migrations.AddApiKeyValidityTime,
migrations.UpdateAppTag,
migrations.UpdateApp,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
@@ -360,3 +360,23 @@ var AddApiKeyValidityTime = &gormigrate.Migration{
return nil
},
}
var UpdateAppTag = &gormigrate.Migration{
ID: "20250114-update-app-tag",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Tag{}); err != nil {
return err
}
return nil
},
}
var UpdateApp = &gormigrate.Migration{
ID: "20250114-update-app",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.App{}); err != nil {
return err
}
return nil
},
}
+2 -3
View File
@@ -113,9 +113,7 @@ func setWebStatic(rootRouter *gin.RouterGroup) {
rootRouter.StaticFS("/public", http.FS(web.Favicon))
rootRouter.StaticFS("/favicon.ico", http.FS(web.Favicon))
rootRouter.Static("/api/v1/images", "./uploads")
rootRouter.Use(func(c *gin.Context) {
c.Next()
})
rootRouter.GET("/assets/*filepath", func(c *gin.Context) {
c.Writer.Header().Set("Cache-Control", fmt.Sprintf("private, max-age=%d", 3600))
staticServer := http.FileServer(http.FS(web.Assets))
@@ -158,6 +156,7 @@ func Routers() *gin.Engine {
Router.Use(middleware.WhiteAllow())
Router.Use(middleware.BindDomain())
Router.Use(middleware.SetPasswordPublicKey())
Router.NoRoute(func(c *gin.Context) {
if checkFrontendPath(c) {
+22
View File
@@ -0,0 +1,22 @@
package middleware
import (
"encoding/base64"
"github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/gin-gonic/gin"
)
func SetPasswordPublicKey() gin.HandlerFunc {
return func(c *gin.Context) {
cookieKey, _ := c.Cookie("panel_public_key")
settingRepo := repo.NewISettingRepo()
key, _ := settingRepo.Get(settingRepo.WithByKey("PASSWORD_PUBLIC_KEY"))
base64Key := base64.StdEncoding.EncodeToString([]byte(key.Value))
if base64Key == cookieKey {
c.Next()
return
}
c.SetCookie("panel_public_key", base64Key, 7*24*60*60, "/", "", false, false)
c.Next()
}
}
+1
View File
@@ -54,6 +54,7 @@ func (a *WebsiteRouter) InitRouter(Router *gin.RouterGroup) {
websiteRouter.POST("/proxies", baseApi.GetProxyConfig)
websiteRouter.POST("/proxies/update", baseApi.UpdateProxyConfig)
websiteRouter.POST("/proxies/file", baseApi.UpdateProxyConfigFile)
websiteRouter.POST("/proxies/del", baseApi.DeleteProxyConfig)
websiteRouter.POST("/auths", baseApi.GetAuthConfig)
websiteRouter.POST("/auths/update", baseApi.UpdateAuthConfig)
+77
View File
@@ -5,9 +5,14 @@ import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"io"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
@@ -102,3 +107,75 @@ func aesDecryptWithSalt(key, ciphertext []byte) ([]byte, error) {
ciphertext = unPadding(ciphertext)
return ciphertext, nil
}
func ParseRSAPrivateKey(privateKeyPEM string) (*rsa.PrivateKey, error) {
block, _ := pem.Decode([]byte(privateKeyPEM))
if block == nil || block.Type != "RSA PRIVATE KEY" {
return nil, errors.New("failed to decode PEM block containing the private key")
}
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return privateKey, nil
}
func aesDecrypt(ciphertext, key, iv []byte) ([]byte, error) {
if len(key) != 16 && len(key) != 24 && len(key) != 32 {
return nil, errors.New("invalid AES key length: must be 16, 24, or 32 bytes")
}
if len(iv) != aes.BlockSize {
return nil, errors.New("invalid IV length: must be 16 bytes")
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(ciphertext, ciphertext)
ciphertext = pkcs7Unpad(ciphertext)
return ciphertext, nil
}
func pkcs7Unpad(data []byte) []byte {
length := len(data)
padLength := int(data[length-1])
return data[:length-padLength]
}
func DecryptPassword(encryptedData string, privateKey *rsa.PrivateKey) (string, error) {
parts := strings.Split(encryptedData, ":")
if len(parts) != 3 {
return "", errors.New("encrypted data format error")
}
keyCipher := parts[0]
ivBase64 := parts[1]
ciphertextBase64 := parts[2]
encryptedAESKey, err := base64.StdEncoding.DecodeString(keyCipher)
if err != nil {
return "", errors.New("failed to decode keyCipher")
}
aesKey, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, encryptedAESKey)
if err != nil {
return "", errors.New("failed to decode AES Key")
}
ciphertext, err := base64.StdEncoding.DecodeString(ciphertextBase64)
if err != nil {
return "", errors.New("failed to decrypt the encrypted data")
}
iv, err := base64.StdEncoding.DecodeString(ivBase64)
if err != nil {
return "", errors.New("failed to decode the IV")
}
password, err := aesDecrypt(ciphertext, aesKey, iv)
if err != nil {
return "", err
}
return string(password), nil
}
+2 -1
View File
@@ -192,8 +192,9 @@ func (iptables *Iptables) NatRemove(num string, protocol, srcPort, dest, destPor
// 删除公网转发规则
if dest != "" && dest != "127.0.0.1" && dest != "localhost" {
if err := iptables.runf(NatTab, fmt.Sprintf(
"-D %s -p %s --dport %s -j DNAT MASQUERADE",
"-D %s -p %s -d %s --dport %s -j MASQUERADE",
PostRoutingChain,
dest,
protocol,
destPort,
)); err != nil {
+1 -1
View File
@@ -234,7 +234,7 @@ func (r *Local) Backup(info BackupInfo) error {
dumpCmd = "mariadb-dump"
}
global.LOG.Infof("start to %s | gzip > %s.gzip", dumpCmd, info.TargetDir+"/"+info.FileName)
cmd := exec.Command("docker", "exec", r.ContainerName, dumpCmd, "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name)
cmd := exec.Command("docker", "exec", r.ContainerName, dumpCmd, "--routines", "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name)
var stderr bytes.Buffer
cmd.Stderr = &stderr
+1 -1
View File
@@ -249,7 +249,7 @@ func (r *Remote) Backup(info BackupInfo) error {
if err != nil {
return err
}
backupCmd := fmt.Sprintf("docker run --rm --net=host -i %s /bin/bash -c '%s -h %s -P %d -u%s -p%s %s --default-character-set=%s %s'",
backupCmd := fmt.Sprintf("docker run --rm --net=host -i %s /bin/bash -c '%s --routines -h %s -P %d -u%s -p%s %s --default-character-set=%s %s'",
image, dumpCmd, r.Address, r.Port, r.User, r.Password, sslSkip(info.Version, r.Type), info.Format, info.Name)
global.LOG.Debug(strings.ReplaceAll(backupCmd, r.Password, "******"))
+274 -77
View File
@@ -10013,10 +10013,7 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/response.PHPExtensionsDTO"
}
"$ref": "#/definitions/dto.PageResult"
}
}
}
@@ -10624,6 +10621,88 @@ const docTemplate = `{
}
}
},
"/settings/backup/record/size": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"Backup Account"
],
"summary": "Load backup records size",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.RecordSearch"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/dto.BackupFile"
}
}
}
}
}
},
"/settings/backup/record/size/bycronjob": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"Backup Account"
],
"summary": "Load backup records size for cronjob",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.RecordSearchByCronjob"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/dto.BackupFile"
}
}
}
}
}
},
"/settings/backup/recover": {
"post": {
"security": [
@@ -15403,6 +15482,59 @@ const docTemplate = `{
}
}
},
"/websites/proxies/del": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"Website"
],
"summary": "Delete proxy conf",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteProxyDel"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [
{
"db": "websites",
"input_column": "id",
"input_value": "id",
"isList": false,
"output_column": "primary_domain",
"output_value": "domain"
}
],
"bodyKeys": [
"id"
],
"formatEN": "Delete domain [domain] proxy config",
"formatZH": "删除网站 [domain] 反向代理配置",
"paramKeys": []
}
}
},
"/websites/proxies/update": {
"post": {
"security": [
@@ -16618,6 +16750,9 @@ const docTemplate = `{
"crossVersionUpdate": {
"type": "boolean"
},
"description": {
"$ref": "#/definitions/dto.Locale"
},
"document": {
"type": "string"
},
@@ -16684,6 +16819,20 @@ const docTemplate = `{
}
}
},
"dto.BackupFile": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"size": {
"type": "integer"
}
}
},
"dto.BackupInfo": {
"type": "object",
"properties": {
@@ -19406,6 +19555,32 @@ const docTemplate = `{
}
}
},
"dto.Locale": {
"type": "object",
"properties": {
"en": {
"type": "string"
},
"ja": {
"type": "string"
},
"ms": {
"type": "string"
},
"pt-br": {
"type": "string"
},
"ru": {
"type": "string"
},
"zh": {
"type": "string"
},
"zh-hant": {
"type": "string"
}
}
},
"dto.LogOption": {
"type": "object",
"properties": {
@@ -19448,7 +19623,11 @@ const docTemplate = `{
"zh",
"en",
"tw",
"ru"
"ja",
"ko",
"ru",
"ms",
"pt-BR"
]
},
"name": {
@@ -21530,6 +21709,9 @@ const docTemplate = `{
"key": {
"type": "string"
},
"locales": {
"$ref": "#/definitions/dto.Locale"
},
"name": {
"type": "string"
},
@@ -21819,6 +22001,9 @@ const docTemplate = `{
"crossVersionUpdate": {
"type": "boolean"
},
"description": {
"type": "string"
},
"document": {
"type": "string"
},
@@ -22043,6 +22228,9 @@ const docTemplate = `{
"sort": {
"type": "integer"
},
"translations": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
@@ -24333,6 +24521,21 @@ const docTemplate = `{
}
}
},
"request.WebsiteProxyDel": {
"type": "object",
"required": [
"id",
"name"
],
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
},
"request.WebsiteProxyReq": {
"type": "object",
"required": [
@@ -24709,6 +24912,9 @@ const docTemplate = `{
"crossVersionUpdate": {
"type": "boolean"
},
"description": {
"type": "string"
},
"document": {
"type": "string"
},
@@ -24834,56 +25040,6 @@ const docTemplate = `{
}
}
},
"response.AppDto": {
"type": "object",
"properties": {
"icon": {
"type": "string"
},
"id": {
"type": "integer"
},
"installed": {
"type": "boolean"
},
"key": {
"type": "string"
},
"limit": {
"type": "integer"
},
"name": {
"type": "string"
},
"resource": {
"type": "string"
},
"shortDescEn": {
"type": "string"
},
"shortDescZh": {
"type": "string"
},
"status": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"$ref": "#/definitions/model.Tag"
}
},
"type": {
"type": "string"
},
"versions": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"response.AppInstalledCheck": {
"type": "object",
"properties": {
@@ -24925,6 +25081,53 @@ const docTemplate = `{
}
}
},
"response.AppItem": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"icon": {
"type": "string"
},
"id": {
"type": "integer"
},
"installed": {
"type": "boolean"
},
"key": {
"type": "string"
},
"limit": {
"type": "integer"
},
"name": {
"type": "string"
},
"resource": {
"type": "string"
},
"status": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"$ref": "#/definitions/response.TagDTO"
}
},
"type": {
"type": "string"
},
"versions": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"response.AppParam": {
"type": "object",
"properties": {
@@ -24965,7 +25168,7 @@ const docTemplate = `{
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/response.AppDto"
"$ref": "#/definitions/response.AppItem"
}
},
"total": {
@@ -25393,26 +25596,6 @@ const docTemplate = `{
}
}
},
"response.PHPExtensionsDTO": {
"type": "object",
"properties": {
"createdAt": {
"type": "string"
},
"extensions": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
}
},
"response.PackageScripts": {
"type": "object",
"properties": {
@@ -25539,6 +25722,20 @@ const docTemplate = `{
}
}
},
"response.TagDTO": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"key": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"response.WebsiteAcmeAccountDTO": {
"type": "object",
"properties": {
@@ -25965,7 +26162,7 @@ const docTemplate = `{
},
"securityDefinitions": {
"ApiKeyAuth": {
"description": "Custom Token Format, Format: md5('1panel' + API-Key + UnixTimestamp).\n` + "`" + `` + "`" + `` + "`" + `\neg:\ncurl -X GET \"http://localhost:4004/api/v1/resource\" \\\n-H \"1Panel-Token: \u003c1panel_token\u003e\" \\\n-H \"1Panel-Timestamp: \u003ccurrent_unix_timestamp\u003e\"\n` + "`" + `` + "`" + `` + "`" + `\n- ` + "`" + `1Panel-Token` + "`" + ` is the key for the panel API Key.",
"description": "Custom Token Format, Format: md5('1panel' + API-Key + UnixTimestamp).\n` + "`" + `` + "`" + `` + "`" + `\neg:\ncurl -X GET \"http://localhost:4004/api/v1/dashboard/current\" \\\n-H \"1Panel-Token: \u003c1panel_token\u003e\" \\\n-H \"1Panel-Timestamp: \u003ccurrent_unix_timestamp\u003e\"\n` + "`" + `` + "`" + `` + "`" + `\n- ` + "`" + `1Panel-Token` + "`" + ` is the key for the panel API Key.",
"type": "apiKey",
"name": "1Panel-Token",
"in": "header"
+274 -77
View File
@@ -10010,10 +10010,7 @@
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/response.PHPExtensionsDTO"
}
"$ref": "#/definitions/dto.PageResult"
}
}
}
@@ -10621,6 +10618,88 @@
}
}
},
"/settings/backup/record/size": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"Backup Account"
],
"summary": "Load backup records size",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.RecordSearch"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/dto.BackupFile"
}
}
}
}
}
},
"/settings/backup/record/size/bycronjob": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"Backup Account"
],
"summary": "Load backup records size for cronjob",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.RecordSearchByCronjob"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/dto.BackupFile"
}
}
}
}
}
},
"/settings/backup/recover": {
"post": {
"security": [
@@ -15400,6 +15479,59 @@
}
}
},
"/websites/proxies/del": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"Website"
],
"summary": "Delete proxy conf",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteProxyDel"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [
{
"db": "websites",
"input_column": "id",
"input_value": "id",
"isList": false,
"output_column": "primary_domain",
"output_value": "domain"
}
],
"bodyKeys": [
"id"
],
"formatEN": "Delete domain [domain] proxy config",
"formatZH": "删除网站 [domain] 反向代理配置",
"paramKeys": []
}
}
},
"/websites/proxies/update": {
"post": {
"security": [
@@ -16615,6 +16747,9 @@
"crossVersionUpdate": {
"type": "boolean"
},
"description": {
"$ref": "#/definitions/dto.Locale"
},
"document": {
"type": "string"
},
@@ -16681,6 +16816,20 @@
}
}
},
"dto.BackupFile": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"size": {
"type": "integer"
}
}
},
"dto.BackupInfo": {
"type": "object",
"properties": {
@@ -19403,6 +19552,32 @@
}
}
},
"dto.Locale": {
"type": "object",
"properties": {
"en": {
"type": "string"
},
"ja": {
"type": "string"
},
"ms": {
"type": "string"
},
"pt-br": {
"type": "string"
},
"ru": {
"type": "string"
},
"zh": {
"type": "string"
},
"zh-hant": {
"type": "string"
}
}
},
"dto.LogOption": {
"type": "object",
"properties": {
@@ -19445,7 +19620,11 @@
"zh",
"en",
"tw",
"ru"
"ja",
"ko",
"ru",
"ms",
"pt-BR"
]
},
"name": {
@@ -21527,6 +21706,9 @@
"key": {
"type": "string"
},
"locales": {
"$ref": "#/definitions/dto.Locale"
},
"name": {
"type": "string"
},
@@ -21816,6 +21998,9 @@
"crossVersionUpdate": {
"type": "boolean"
},
"description": {
"type": "string"
},
"document": {
"type": "string"
},
@@ -22040,6 +22225,9 @@
"sort": {
"type": "integer"
},
"translations": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
@@ -24330,6 +24518,21 @@
}
}
},
"request.WebsiteProxyDel": {
"type": "object",
"required": [
"id",
"name"
],
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
},
"request.WebsiteProxyReq": {
"type": "object",
"required": [
@@ -24706,6 +24909,9 @@
"crossVersionUpdate": {
"type": "boolean"
},
"description": {
"type": "string"
},
"document": {
"type": "string"
},
@@ -24831,56 +25037,6 @@
}
}
},
"response.AppDto": {
"type": "object",
"properties": {
"icon": {
"type": "string"
},
"id": {
"type": "integer"
},
"installed": {
"type": "boolean"
},
"key": {
"type": "string"
},
"limit": {
"type": "integer"
},
"name": {
"type": "string"
},
"resource": {
"type": "string"
},
"shortDescEn": {
"type": "string"
},
"shortDescZh": {
"type": "string"
},
"status": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"$ref": "#/definitions/model.Tag"
}
},
"type": {
"type": "string"
},
"versions": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"response.AppInstalledCheck": {
"type": "object",
"properties": {
@@ -24922,6 +25078,53 @@
}
}
},
"response.AppItem": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"icon": {
"type": "string"
},
"id": {
"type": "integer"
},
"installed": {
"type": "boolean"
},
"key": {
"type": "string"
},
"limit": {
"type": "integer"
},
"name": {
"type": "string"
},
"resource": {
"type": "string"
},
"status": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"$ref": "#/definitions/response.TagDTO"
}
},
"type": {
"type": "string"
},
"versions": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"response.AppParam": {
"type": "object",
"properties": {
@@ -24962,7 +25165,7 @@
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/response.AppDto"
"$ref": "#/definitions/response.AppItem"
}
},
"total": {
@@ -25390,26 +25593,6 @@
}
}
},
"response.PHPExtensionsDTO": {
"type": "object",
"properties": {
"createdAt": {
"type": "string"
},
"extensions": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
}
},
"response.PackageScripts": {
"type": "object",
"properties": {
@@ -25536,6 +25719,20 @@
}
}
},
"response.TagDTO": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"key": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"response.WebsiteAcmeAccountDTO": {
"type": "object",
"properties": {
@@ -25962,7 +26159,7 @@
},
"securityDefinitions": {
"ApiKeyAuth": {
"description": "Custom Token Format, Format: md5('1panel' + API-Key + UnixTimestamp).\n```\neg:\ncurl -X GET \"http://localhost:4004/api/v1/resource\" \\\n-H \"1Panel-Token: \u003c1panel_token\u003e\" \\\n-H \"1Panel-Timestamp: \u003ccurrent_unix_timestamp\u003e\"\n```\n- `1Panel-Token` is the key for the panel API Key.",
"description": "Custom Token Format, Format: md5('1panel' + API-Key + UnixTimestamp).\n```\neg:\ncurl -X GET \"http://localhost:4004/api/v1/dashboard/current\" \\\n-H \"1Panel-Token: \u003c1panel_token\u003e\" \\\n-H \"1Panel-Timestamp: \u003ccurrent_unix_timestamp\u003e\"\n```\n- `1Panel-Token` is the key for the panel API Key.",
"type": "apiKey",
"name": "1Panel-Token",
"in": "header"
+174 -51
View File
@@ -102,6 +102,8 @@ definitions:
type: array
crossVersionUpdate:
type: boolean
description:
$ref: '#/definitions/dto.Locale'
document:
type: string
github:
@@ -145,6 +147,15 @@ definitions:
version:
type: string
type: object
dto.BackupFile:
properties:
id:
type: integer
name:
type: string
size:
type: integer
type: object
dto.BackupInfo:
properties:
backupPath:
@@ -1974,6 +1985,23 @@ definitions:
- id
- type
type: object
dto.Locale:
properties:
en:
type: string
ja:
type: string
ms:
type: string
pt-br:
type: string
ru:
type: string
zh:
type: string
zh-hant:
type: string
type: object
dto.LogOption:
properties:
logMaxFile:
@@ -1999,7 +2027,11 @@ definitions:
- zh
- en
- tw
- ja
- ko
- ru
- ms
- pt-BR
type: string
name:
type: string
@@ -3417,6 +3449,8 @@ definitions:
properties:
key:
type: string
locales:
$ref: '#/definitions/dto.Locale'
name:
type: string
sort:
@@ -3606,6 +3640,8 @@ definitions:
type: string
crossVersionUpdate:
type: boolean
description:
type: string
document:
type: string
github:
@@ -3754,6 +3790,8 @@ definitions:
type: string
sort:
type: integer
translations:
type: string
updatedAt:
type: string
type: object
@@ -5291,6 +5329,16 @@ definitions:
- proxyHost
- proxyPass
type: object
request.WebsiteProxyDel:
properties:
id:
type: integer
name:
type: string
required:
- id
- name
type: object
request.WebsiteProxyReq:
properties:
id:
@@ -5544,6 +5592,8 @@ definitions:
type: string
crossVersionUpdate:
type: boolean
description:
type: string
document:
type: string
github:
@@ -5627,39 +5677,6 @@ definitions:
version:
type: string
type: object
response.AppDto:
properties:
icon:
type: string
id:
type: integer
installed:
type: boolean
key:
type: string
limit:
type: integer
name:
type: string
resource:
type: string
shortDescEn:
type: string
shortDescZh:
type: string
status:
type: string
tags:
items:
$ref: '#/definitions/model.Tag'
type: array
type:
type: string
versions:
items:
type: string
type: array
type: object
response.AppInstalledCheck:
properties:
app:
@@ -5687,6 +5704,37 @@ definitions:
version:
type: string
type: object
response.AppItem:
properties:
description:
type: string
icon:
type: string
id:
type: integer
installed:
type: boolean
key:
type: string
limit:
type: integer
name:
type: string
resource:
type: string
status:
type: string
tags:
items:
$ref: '#/definitions/response.TagDTO'
type: array
type:
type: string
versions:
items:
type: string
type: array
type: object
response.AppParam:
properties:
edit:
@@ -5714,7 +5762,7 @@ definitions:
properties:
items:
items:
$ref: '#/definitions/response.AppDto'
$ref: '#/definitions/response.AppItem'
type: array
total:
type: integer
@@ -5993,19 +6041,6 @@ definitions:
uploadMaxSize:
type: string
type: object
response.PHPExtensionsDTO:
properties:
createdAt:
type: string
extensions:
type: string
id:
type: integer
name:
type: string
updatedAt:
type: string
type: object
response.PackageScripts:
properties:
name:
@@ -6089,6 +6124,15 @@ definitions:
user:
type: string
type: object
response.TagDTO:
properties:
id:
type: integer
key:
type: string
name:
type: string
type: object
response.WebsiteAcmeAccountDTO:
properties:
createdAt:
@@ -12415,9 +12459,7 @@ paths:
"200":
description: OK
schema:
items:
$ref: '#/definitions/response.PHPExtensionsDTO'
type: array
$ref: '#/definitions/dto.PageResult'
security:
- ApiKeyAuth: []
- Timestamp: []
@@ -12765,6 +12807,54 @@ paths:
summary: Page backup records by cronjob
tags:
- Backup Account
/settings/backup/record/size:
post:
consumes:
- application/json
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.RecordSearch'
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/dto.BackupFile'
type: array
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Load backup records size
tags:
- Backup Account
/settings/backup/record/size/bycronjob:
post:
consumes:
- application/json
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.RecordSearchByCronjob'
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/dto.BackupFile'
type: array
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Load backup records size for cronjob
tags:
- Backup Account
/settings/backup/recover:
post:
consumes:
@@ -15756,6 +15846,39 @@ paths:
summary: Get proxy conf
tags:
- Website
/websites/proxies/del:
post:
consumes:
- application/json
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/request.WebsiteProxyDel'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Delete proxy conf
tags:
- Website
x-panel-log:
BeforeFunctions:
- db: websites
input_column: id
input_value: id
isList: false
output_column: primary_domain
output_value: domain
bodyKeys:
- id
formatEN: Delete domain [domain] proxy config
formatZH: 删除网站 [domain] 反向代理配置
paramKeys: []
/websites/proxies/update:
post:
consumes:
@@ -16303,7 +16426,7 @@ securityDefinitions:
Custom Token Format, Format: md5('1panel' + API-Key + UnixTimestamp).
```
eg:
curl -X GET "http://localhost:4004/api/v1/resource" \
curl -X GET "http://localhost:4004/api/v1/dashboard/current" \
-H "1Panel-Token: <1panel_token>" \
-H "1Panel-Timestamp: <current_unix_timestamp>"
```
+1 -1
View File
@@ -23,7 +23,7 @@ import (
// @description Custom Token Format, Format: md5('1panel' + API-Key + UnixTimestamp).
// @description ```
// @description eg:
// @description curl -X GET "http://localhost:4004/api/v1/resource" \
// @description curl -X GET "http://localhost:4004/api/v1/dashboard/current" \
// @description -H "1Panel-Token: <1panel_token>" \
// @description -H "1Panel-Timestamp: <current_unix_timestamp>"
// @description ```
+10 -10
View File
@@ -2,14 +2,14 @@
root = true
[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
end_of_line = lf # 控制换行类型(lf | cr | crlf)
insert_final_newline = true # 始终在文件末尾插入一个新行
indent_style = space # 缩进风格(tab | space)
indent_size = 4 # 缩进大小
max_line_length = 120 # 最大行长度
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
max_line_length = 120
[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off # 关闭最大行长度限制
trim_trailing_whitespace = false # 关闭末尾空格修剪
[*.md]
max_line_length = off
trim_trailing_whitespace = false
-5
View File
@@ -4,17 +4,12 @@ VITE_GLOB_APP_TITLE = '1Panel'
# port
VITE_PORT = 4004
# open 运行 npm run dev 时自动打开浏览器
VITE_OPEN = false
# 是否生成包预览文件
VITE_REPORT = false
# 是否开启gzip压缩
VITE_BUILD_GZIP = false
# 是否删除生产环境 console
VITE_DROP_CONSOLE = true
PANEL_XPACK = false
-4
View File
@@ -1,13 +1,9 @@
# 本地环境
NODE_ENV = 'development'
# 本地环境接口地址
VITE_API_URL = '/api/v1'
# 是否生成包预览文件
VITE_REPORT = false
# 是否开启gzip压缩
VITE_BUILD_GZIP = false
VITE_DROP_CONSOLE = true
-4
View File
@@ -1,13 +1,9 @@
# 线上环境
NODE_ENV = "production"
# 线上环境接口地址
VITE_API_URL = '/api/v1'
# 是否生成包预览文件
VITE_REPORT = true
# 是否开启gzip压缩
VITE_BUILD_GZIP = false
VITE_DROP_CONSOLE = true
+32 -40
View File
@@ -7,9 +7,7 @@ module.exports = {
node: true,
es6: true,
},
/* 指定如何解析语法 */
parser: 'vue-eslint-parser',
/* 优先级低于 parse 的语法解析配置 */
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020,
@@ -19,55 +17,49 @@ module.exports = {
jsx: true,
},
},
/* 继承某些已有的规则 */
extends: [
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
'plugin:prettier/recommended',
],
/*
* "off" 或 0 ==> 关闭规则
* "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行)
* "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错)
*/
rules: {
// eslint (http://eslint.cn/docs/rules)
'no-var': 'error', // 要求使用 let 或 const 而不是 var
'no-multiple-empty-lines': ['error', { max: 1 }], // 不允许多个空行
'no-use-before-define': 'off', // 禁止在 函数/类/变量 定义之前使用它们
'prefer-const': 'off', // 此规则旨在标记使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const
'no-irregular-whitespace': 'off', // 禁止不规则的空白
'no-var': 'error',
'no-multiple-empty-lines': ['error', { max: 1 }],
'no-use-before-define': 'off',
'prefer-const': 'off',
'no-irregular-whitespace': 'off',
// typeScript (https://typescript-eslint.io/rules)
'@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量
'@typescript-eslint/no-inferrable-types': 'off', // 可以轻松推断的显式类型可能会增加不必要的冗长
'@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。
'@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
'@typescript-eslint/ban-ts-ignore': 'off', // 禁止使用 @ts-ignore
'@typescript-eslint/ban-types': 'off', // 禁止使用特定类型
'@typescript-eslint/explicit-function-return-type': 'off', // 不允许对初始化为数字、字符串或布尔值的变量或参数进行显式类型声明
'@typescript-eslint/no-var-requires': 'off', // 不允许在 import 语句中使用 require 语句
'@typescript-eslint/no-empty-function': 'off', // 禁止空函数
'@typescript-eslint/no-use-before-define': 'off', // 禁止在变量定义之前使用它们
'@typescript-eslint/ban-ts-comment': 'off', // 禁止 @ts-<directive> 使用注释或要求在指令后进行描述
'@typescript-eslint/no-non-null-assertion': 'off', // 不允许使用后缀运算符的非空断言(!)
'@typescript-eslint/explicit-module-boundary-types': 'off', // 要求导出函数和类的公共类方法的显式返回和参数类型
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-inferrable-types': 'off',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
// vue (https://eslint.vuejs.org/rules)
'vue/no-v-html': 'off', // 禁止使用 v-html
'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的变量<template>被标记为未使用,此规则仅在启用该no-unused-vars规则时有效。
'vue/v-slot-style': 'error', // 强制执行 v-slot 指令样式
'vue/no-mutating-props': 'off', // 不允许组件 prop的改变(明天找原因)
'vue/custom-event-name-casing': 'off', // 为自定义事件名称强制使用特定大小写
'vue/attributes-order': 'off', // vue api使用顺序,强制执行属性顺序
'vue/one-component-per-file': 'off', // 强制每个组件都应该在自己的文件中
'vue/html-closing-bracket-newline': 'off', // 在标签的右括号之前要求或禁止换行
'vue/max-attributes-per-line': 'off', // 强制每行的最大属性数
'vue/multiline-html-element-content-newline': 'off', // 在多行元素的内容之前和之后需要换行符
'vue/singleline-html-element-content-newline': 'off', // 在单行元素的内容之前和之后需要换行符
'vue/attribute-hyphenation': 'off', // 对模板中的自定义组件强制执行属性命名样式
'vue/require-default-prop': 'off', // 此规则要求为每个 prop 为必填时,必须提供默认值
'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词
'vue/no-v-html': 'off',
'vue/script-setup-uses-vars': 'error',
'vue/v-slot-style': 'error',
'vue/no-mutating-props': 'off',
'vue/custom-event-name-casing': 'off',
'vue/attributes-order': 'off',
'vue/one-component-per-file': 'off',
'vue/html-closing-bracket-newline': 'off',
'vue/max-attributes-per-line': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/attribute-hyphenation': 'off',
'vue/require-default-prop': 'off',
'vue/multi-word-component-names': 'off',
},
};
-17
View File
@@ -1,37 +1,20 @@
module.exports = {
// 一行最多 120 字符
printWidth: 120,
// 使用 4 个空格缩进
tabWidth: 4,
// 不使用 tab 缩进,而使用空格
useTabs: false,
// 行尾需要有分号
semi: true,
// 使用单引号代替双引号
singleQuote: true,
// 对象的 key 仅在必要时用引号
quoteProps: 'as-needed',
// jsx 不使用单引号,而使用双引号
jsxSingleQuote: false,
// 末尾使用逗号
trailingComma: 'all',
// 大括号内的首尾需要空格 { foo: bar }
bracketSpacing: true,
// jsx 标签的反尖括号需要换行
jsxBracketSameLine: false,
// 箭头函数,只有一个参数的时候,也需要括号
arrowParens: 'always',
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: 'never',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'ignore',
// 换行符使用 lf
endOfLine: 'auto',
};
+21 -26
View File
@@ -1,41 +1,36 @@
// @see: https://stylelint.io
module.exports = {
/* 继承某些已有的规则 */
extends: [
'stylelint-config-standard', // 配置stylelint拓展插件
'stylelint-config-html/vue', // 配置 vue 中 template 样式格式化
'stylelint-config-standard-scss', // 配置stylelint scss插件
'stylelint-config-recommended-vue/scss', // 配置 vue 中 scss 样式格式化
'stylelint-config-recess-order', // 配置stylelint css属性书写顺序插件,
'stylelint-config-prettier', // 配置stylelint和prettier兼容
'stylelint-config-standard',
'stylelint-config-html/vue',
'stylelint-config-standard-scss',
'stylelint-config-recommended-vue/scss',
'stylelint-config-recess-order',
'stylelint-config-prettier',
],
overrides: [
// 扫描 .vue/html 文件中的<style>标签内的样式
{
files: ['**/*.{vue,html}'],
customSyntax: 'postcss-html',
},
],
/**
* null => 关闭该规则
*/
rules: {
'no-descending-specificity': null, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器
'function-url-quotes': 'always', // 要求或禁止 URL 的引号 "always(必须加上引号)"|"never(没有引号)"
'string-quotes': 'double', // 指定字符串使用单引号或双引号
'unit-case': null, // 指定单位的大小写 "lower(全小写)"|"upper(全大写)"
'color-hex-case': 'lower', // 指定 16 进制颜色的大小写 "lower(全小写)"|"upper(全大写)"
'color-hex-length': 'long', // 指定 16 进制颜色的简写或扩写 "short(16进制简写)"|"long(16进制扩写)"
'rule-empty-line-before': 'never', // 要求或禁止在规则之前的空行 "always(规则之前必须始终有一个空行)"|"never(规则前绝不能有空行)"|"always-multi-line(多行规则之前必须始终有一个空行)"|"never-multi-line(多行规则之前绝不能有空行。)"
'font-family-no-missing-generic-family-keyword': null, // 禁止在字体族名称列表中缺少通用字体族关键字
'block-opening-brace-space-before': 'always', // 要求在块的开大括号之前必须有一个空格或不能有空白符 "always(大括号前必须始终有一个空格)"|"never(左大括号之前绝不能有空格)"|"always-single-line(在单行块中的左大括号之前必须始终有一个空格)"|"never-single-line(在单行块中的左大括号之前绝不能有空格)"|"always-multi-line(在多行块中,左大括号之前必须始终有一个空格)"|"never-multi-line(多行块中的左大括号之前绝不能有空格)"
'property-no-unknown': null, // 禁止未知的属性(true 为不允许)
'no-empty-source': null, // 禁止空源码
'declaration-block-trailing-semicolon': null, // 要求或不允许在声明块中使用尾随分号 string:"always(必须始终有一个尾随分号)"|"never(不得有尾随分号)"
'selector-class-pattern': null, // 强制选择器类名的格式
'scss/at-import-partial-extension': null, // 解决不能引入scss文件
'value-no-vendor-prefix': null, // 关闭 vendor-prefix(为了解决多行省略 -webkit-box)
'no-descending-specificity': null,
'function-url-quotes': 'always',
'string-quotes': 'double',
'unit-case': null,
'color-hex-case': 'lower',
'color-hex-length': 'long',
'rule-empty-line-before': 'never',
'font-family-no-missing-generic-family-keyword': null,
'block-opening-brace-space-before': 'always',
'property-no-unknown': null,
'no-empty-source': null,
'declaration-block-trailing-semicolon': null,
'selector-class-pattern': null,
'scss/at-import-partial-extension': null,
'value-no-vendor-prefix': null,
'selector-pseudo-class-no-unknown': [
true,
{
+12 -9
View File
@@ -2,7 +2,7 @@
"name": "1Panel-Frontend",
"private": true,
"version": "1.10",
"description": "1Panel 前端",
"description": "1Panel Frontend",
"scripts": {
"dev": "vite",
"serve": "vite",
@@ -16,14 +16,14 @@
"lint:lint-staged": "lint-staged",
"release": "standard-version",
"commit": "git pull && git add -A && git-cz && git push",
"prettier:comment": "自动格式化当前目录下的所有文件",
"prettier:comment": "automatically format all files in the current directory",
"prettier": "prettier --write ."
},
"dependencies": {
"@codemirror/lang-html": "^6.4.9",
"@codemirror/lang-yaml": "^6.1.2",
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/lang-php": "^6.0.1",
"@codemirror/lang-yaml": "^6.1.2",
"@codemirror/language": "^6.10.2",
"@codemirror/legacy-modes": "^6.4.0",
"@codemirror/state": "^6.4.1",
@@ -37,11 +37,13 @@
"@xterm/xterm": "^5.5.0",
"axios": "^1.7.2",
"codemirror": "^6.0.1",
"crypto-js": "^4.2.0",
"echarts": "^5.5.0",
"element-plus": "^2.7.5",
"fit2cloud-ui-plus": "^1.2.0",
"highlight.js": "^11.9.0",
"js-base64": "^3.7.7",
"jsencrypt": "^3.3.2",
"md-editor-v3": "^2.11.3",
"monaco-editor": "^0.50.0",
"nprogress": "^0.2.0",
@@ -54,11 +56,12 @@
"vue-clipboard3": "^2.0.0",
"vue-codemirror": "^6.1.1",
"vue-demi": "^0.14.6",
"vue-i18n": "^10.0.5",
"vue-router": "^4.3.3"
"vue-i18n": "^9.13.1",
"vue-router": "^4.3.3",
"vue-virtual-scroller": "^2.0.0-beta.8"
},
"devDependencies": {
"@types/node": "^20.14.2",
"@types/node": "^20.15.0",
"@typescript-eslint/eslint-plugin": "^5.22.0",
"@typescript-eslint/parser": "^5.22.0",
"@vitejs/plugin-vue": "^5.0.5",
@@ -73,7 +76,7 @@
"postcss": "^8.4.31",
"postcss-html": "^1.4.1",
"prettier": "^2.6.2",
"rollup-plugin-visualizer": "^5.5.4",
"rollup-plugin-visualizer": "^5.14.0",
"sass": "^1.77.8",
"standard-version": "^9.5.0",
"stylelint": "^15.10.1",
@@ -81,7 +84,7 @@
"typescript": "^4.5.4",
"unplugin-auto-import": "^0.16.4",
"unplugin-vue-components": "^0.25.0",
"vite": "^5.2.13",
"vite": "^6.0.7",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-html": "^3.2.2",
@@ -90,7 +93,7 @@
"vue-tsc": "^0.29.8"
},
"overrides": {
"esbuild": "npm:esbuild-wasm@latest"
"esbuild": "npm:esbuild-wasm@0.24.2"
},
"config": {
"commitizen": {
+2 -2
View File
@@ -14,6 +14,7 @@ import ja from 'element-plus/es/locale/lang/ja';
import ms from 'element-plus/es/locale/lang/ms';
import ptBR from 'element-plus/es/locale/lang/pt-br';
import ru from 'element-plus/es/locale/lang/ru';
import ko from 'element-plus/es/locale/lang/ko';
import { useTheme } from '@/hooks/use-theme';
useTheme();
@@ -30,6 +31,7 @@ const i18nLocale = computed(() => {
if (globalStore.language === 'ms') return ms;
if (globalStore.language === 'ru') return ru;
if (globalStore.language === 'pt-br') return ptBR;
if (globalStore.language === 'ko') return ko;
return zhCn;
});
@@ -43,5 +45,3 @@ const reload = () => {
};
provide('reload', reload);
</script>
<style scoped lang="scss"></style>
+12
View File
@@ -8,6 +8,7 @@ export namespace App {
tags: Tag[];
shortDescZh: string;
shortDescEn: string;
description: string;
author: string;
source: string;
type: string;
@@ -58,10 +59,21 @@ export namespace App {
formFields: FromField[];
}
interface Locale {
zh: string;
en: string;
'zh-Hant': string;
ja: string;
ms: string;
'pt-br': string;
ru: string;
}
export interface FromField {
type: string;
labelZh: string;
labelEn: string;
label: Locale;
required: boolean;
default: any;
envKey: string;
+1
View File
@@ -178,6 +178,7 @@ export namespace Setting {
licenseName: string;
assigneeName: string;
productPro: string;
versionConstraint: string;
trial: boolean;
offline: boolean;
status: string;
+5
View File
@@ -356,6 +356,11 @@ export namespace Website {
id: number;
}
export interface ProxyDel {
id: number;
name: string;
}
export interface ProxyConfig {
id: number;
operate: string;
+1 -1
View File
@@ -64,7 +64,7 @@ export const AppInstalledDeleteCheck = (appInstallId: number) => {
};
export const GetAppInstalled = (search: App.AppInstalledSearch) => {
return http.post<App.AppInstalled[]>('apps/installed/search', search);
return http.post<ResPage<App.AppInstalled>>('apps/installed/search', search);
};
export const InstalledOp = (op: App.AppInstalledOp) => {
+1 -1
View File
@@ -49,7 +49,7 @@ export const SearchPHPExtensions = (req: ReqPage) => {
};
export const ListPHPExtensions = (req: Runtime.PHPExtensionsList) => {
return http.post<Runtime.PHPExtensions[]>(`/runtimes/php/extensions/search`, req);
return http.post<ResPage<Runtime.PHPExtensions>>(`/runtimes/php/extensions/search`, req);
};
export const CreatePHPExtensions = (req: Runtime.PHPExtensionsCreate) => {
+4
View File
@@ -198,6 +198,10 @@ export const UpdateProxyConfigFile = (req: Website.ProxyFileUpdate) => {
return http.post<any>(`/websites/proxies/file`, req);
};
export const DelProxy = (req: Website.ProxyDel) => {
return http.post<any>(`/websites/proxies/del`, req);
};
export const GetAuthConfig = (req: Website.AuthReq) => {
return http.post<Website.AuthConfig>(`/websites/auths`, req);
};
@@ -1,7 +1,7 @@
<template>
<el-card class="router_card p-1 sm:p-0">
<div class="flex w-full flex-col justify-start sm:items-center items-start sm:justify-between sm:flex-row">
<el-radio-group v-model="activeName" @change="handleChange">
<el-radio-group v-model="activeName" @change="handleChange" class="flex-1">
<el-radio-button
class="router_card_button"
:label="button.label"
+2
View File
@@ -6,6 +6,7 @@ import ptBr from './modules/pt-br';
import ja from './modules/ja';
import ru from './modules/ru';
import ms from './modules/ms';
import ko from './modules/ko';
const i18n = createI18n({
legacy: false,
@@ -20,6 +21,7 @@ const i18n = createI18n({
ja,
ru,
ms,
ko,
},
warnHtmlMessage: false,
});
+8 -5
View File
@@ -60,7 +60,7 @@ const message = {
copy: 'Copy',
random: 'Random',
uninstall: 'Uninstall',
fullscreen: 'Enter fullscreen',
fullscreen: 'Fullscreen',
quitFullscreen: 'Exit fullscreen',
update: 'Edit',
showAll: 'Show All',
@@ -223,7 +223,7 @@ const message = {
paramComplexity: `This field mustn't start and end with special characters and must consist of English, numbers, "{0}" characters with a length of 6-128.`,
paramUrlAndPort: 'This field must be in the format of "http(s)://(domain name/ip):(port)".',
nginxDoc: 'This field must consist of English, numbers and "." characters.',
appName: `This field mustn't start and end with "-" and "_" characters and must consist of English, numbers, "-", and "_" characters with a length of 2-30.`,
appName: 'Supports lowercase letters, numbers, -, and _, length 2-30, and cannot start or end with - or _',
containerName: 'Supports letters, numbers, -, _ and .; cannot start with - _ or .; length: 2-128',
mirror: 'The mirror acceleration address should start with http(s)://, support English letters (both uppercase and lowercase), numbers, . / and -, and should not contain blank lines.',
disableFunction: 'Only support letters ,underscores,and,',
@@ -1448,8 +1448,8 @@ const message = {
confDockerProxy: 'Configure docker proxy',
restartNowHelper: 'Configuring Docker proxy requires restarting the Docker service.',
restartNow: 'Restart immediately',
systemIPWarning: `The server address isn't currently set. Set it in the control panel first.`,
systemIPWarning1: `The current server address is set to {0}, and quick redirection isn't possible!`,
systemIPWarning: `The system address isn't currently set. Set it in the control panel first.`,
systemIPWarning1: `The current system address is set to {0}, and quick redirection isn't possible!`,
defaultNetwork: 'Network card',
syncTime: 'Server Time',
timeZone: 'Time Zone',
@@ -1709,6 +1709,9 @@ const message = {
oss: 'Open Source Software',
pro: 'Pro',
trial: 'Trial',
subscription: 'Subscription',
perpetual: 'Perpetual',
versionConstraint: '{0} Version Buyout',
office: 'Official',
trialInfo: 'Version',
authorizationId: 'Subscription authorization ID',
@@ -1942,7 +1945,7 @@ const message = {
app: 'Application',
appNew: 'New Application',
appInstalled: 'Installed application',
create: 'Create website',
create: 'Create',
delete: 'Delete Website',
deleteApp: 'Delete Application',
deleteBackup: 'Delete Backup',
+21 -17
View File
@@ -1,8 +1,8 @@
import fit2cloudEnLocale from 'fit2cloud-ui-plus/src/locale/lang/ja';
let xpackJpLocale = {};
import fit2cloudJaLocale from 'fit2cloud-ui-plus/src/locale/lang/ja';
let xpackJaLocale = {};
const xpackModules = import.meta.glob('../../xpack/lang/ja.ts', { eager: true });
if (xpackModules['../../xpack/lang/ja.ts']) {
xpackJpLocale = xpackModules['../../xpack/lang/ja.ts']['default'] || {};
xpackJaLocale = xpackModules['../../xpack/lang/ja.ts']['default'] || {};
}
const message = {
@@ -52,15 +52,15 @@ const message = {
saveAndEnable: '保存して有効にします',
import: '輸入',
search: '検索',
refresh: 'リフレッシュします',
refresh: 'リロード',
get: '得る',
upgrade: 'アップグレード',
ignore: 'アップグレードを無視します',
copy: 'コピー',
random: 'ランダム',
uninstall: 'アンインストール',
fullscreen: 'フルスクリーンを入力します',
quitFullscreen: 'フルスクリーンを終了します',
fullscreen: 'フルスクリーン',
quitFullscreen: 'フルスクリーンを終了',
update: '編集',
showAll: 'すべてを表示します',
hideSome: 'いくつかを隠します',
@@ -222,7 +222,8 @@ const message = {
paramUrlAndPort:
'このフィールドは、「http(s)://(domain name/ip):(ポート)」の形式でなければなりません。',
nginxDoc: 'このフィールドは、英語、数字、「」で構成されている必要があります。文字。',
appName: `このフィールドは、「 - 」と「_」文字で開始および終了してはなりません。英語、数字、 "、および「_」文字で2〜30の文字で構成されている必要があります。`,
appName:
'小文字の英字、数字、-および_をサポートし、長さは2〜30で、-または_で始まったり終わったりすることはできません',
containerName: '文字、数字、 - 、_および。;- _または。で始めることはできません。長さ:2-128',
mirror: 'ミラーアクセラレーションアドレスは、http(s)://、英語の文字(大文字と小文字の両方)、数字をサポートする必要があります。/および - 、そして空白の行を含めてはなりません。',
disableFunction: 'サポートレター、アンダースコア、および',
@@ -1184,7 +1185,7 @@ const message = {
editPermissions: '編集@:file.mode',
owner: '所有者',
file: 'ファイル',
remoteFile: 'リモコンからダウンロードしてください',
remoteFile: 'リモートダウンロード',
share: '共有',
sync: 'データ同期',
size: 'サイズ',
@@ -1283,9 +1284,9 @@ const message = {
clashOpenAlert: '「リサイクルビン」ボタンをクリックして、リサイクルビンディレクトリを開きます',
right: 'フォワード',
back: '戻る',
top: '戻って行きます',
refresh: 'リフレッシュします',
up: '戻って行きます',
top: '戻る',
refresh: 'リロード',
up: '戻る',
openWithVscode: 'VSコードで開く',
vscodeHelper:
'VSコードがローカルにインストールされ、SSHリモートプラグインが構成されていることを確認してください',
@@ -1419,8 +1420,8 @@ const message = {
confDockerProxy: 'Dockerプロキシを構成します',
restartNowHelper: 'Dockerプロキシの構成には、Dockerサービスを再起動する必要があります。',
restartNow: 'すぐに再起動します',
systemIPWarning: `サーバーアドレスは現在設定されていません。最初にコントロールパネルに設定します。`,
systemIPWarning1: `現在のサーバーアドレスは{0}に設定されており、クイックリダイレクトは不可能です!`,
systemIPWarning: `システムアドレスが現在設定されていません。まずコントロールパネルで設定してください。`,
systemIPWarning1: `現在のシステムアドレスは {0} に設定されており、クイックリダイレクトはできません!`,
defaultNetwork: 'ネットワークカード',
syncTime: 'サーバー時間',
timeZone: 'タイムゾーン',
@@ -1680,7 +1681,10 @@ const message = {
community: '無料',
oss: '無料',
pro: '専門',
trial: 'トライアル',
trial: '体験',
subscription: 'サブスクリプション',
perpetual: '永久ライセンス',
versionConstraint: '{0} バージョン買い取り',
office: '正式',
trialInfo: 'バージョン',
authorizationId: 'サブスクリプション承認ID',
@@ -1914,7 +1918,7 @@ const message = {
app: '応用',
appNew: '新しいアプリケーション',
appInstalled: 'インストールされたアプリケーション',
create: 'Webサイトを作成します',
create: '作成する',
delete: 'Webサイトを削除します',
deleteApp: 'アプリケーションを削除します',
deleteBackup: 'バックアップを削除します',
@@ -2489,7 +2493,7 @@ const message = {
},
};
export default {
...fit2cloudEnLocale,
...fit2cloudJaLocale,
...message,
...xpackJpLocale,
...xpackJaLocale,
};
File diff suppressed because it is too large Load Diff
+14 -11
View File
@@ -1,9 +1,9 @@
import fit2cloudEnLocale from 'fit2cloud-ui-plus/src/locale/lang/ms';
import fit2cloudMsLocale from 'fit2cloud-ui-plus/src/locale/lang/ms';
let xpackEnLocale = {};
let xpackMsLocale = {};
const xpackModules = import.meta.glob('../../xpack/lang/ms.ts', { eager: true });
if (xpackModules['../../xpack/lang/ms.ts']) {
xpackEnLocale = xpackModules['../../xpack/lang/ms.ts']['default'] || {};
xpackMsLocale = xpackModules['../../xpack/lang/ms.ts']['default'] || {};
}
const message = {
@@ -60,8 +60,8 @@ const message = {
copy: 'Salin',
random: 'Rawak',
uninstall: 'Nyahpasang',
fullscreen: 'Masuk ke skrin penuh',
quitFullscreen: 'Keluar dari skrin penuh',
fullscreen: 'Skrin Penuh',
quitFullscreen: 'Keluar Skrin Penuh',
update: 'Kemas kini',
showAll: 'Tunjukkan Semua',
hideSome: 'Sembunyikan Sebahagian',
@@ -229,7 +229,7 @@ const message = {
paramUrlAndPort: 'Ruangan ini mesti dalam format "http(s)://(nama domain/IP):(port)".',
nginxDoc: 'Ruangan ini mesti terdiri daripada aksara rumi, nombor, dan ".".',
appName:
'Ruangan ini tidak boleh bermula atau berakhir dengan "-" dan "_" dan mesti terdiri daripada aksara rumi, nombor, "-", dan "_" dengan panjang 2-30 aksara.',
'Menyokong huruf kecil, nombor, -, dan _, panjang 2-30, dan tidak boleh bermula atau berakhir dengan - atau _',
containerName:
'Menyokong huruf, nombor, -, _ dan .; tidak boleh bermula dengan -, _ atau .; panjang: 2-128 aksara.',
mirror: 'Alamat pecutan cermin mesti bermula dengan http(s)://, menyokong huruf (huruf besar dan kecil), nombor, ., / dan -, serta tidak boleh mengandungi baris kosong.',
@@ -1469,8 +1469,8 @@ const message = {
confDockerProxy: 'Konfigurasi proksi docker',
restartNowHelper: 'Mengkonfigurasi proksi Docker memerlukan memulakan semula perkhidmatan Docker.',
restartNow: 'Mulakan semula sekarang',
systemIPWarning: 'Alamat pelayan belum ditetapkan. Tetapkan di panel kawalan terlebih dahulu.',
systemIPWarning1: 'Alamat pelayan semasa ditetapkan kepada {0}, dan pengalihan cepat tidak mungkin!',
systemIPWarning: 'Alamat sistem belum ditetapkan. Tetapkannya dahulu di panel kawalan.',
systemIPWarning1: 'Alamat sistem semasa ditetapkan kepada {0}, dan pengalihan pantas tidak dapat dilakukan!',
defaultNetwork: 'Kad rangkaian',
syncTime: 'Waktu Pelayan',
timeZone: 'Zon Waktu',
@@ -1737,6 +1737,9 @@ const message = {
oss: 'Perisian Sumber Terbuka',
pro: 'Pro',
trial: 'Percubaan',
subscription: 'Langganan',
perpetual: 'Lesen Perpetual',
versionConstraint: '{0} Pembelian versi',
office: 'Rasmi',
trialInfo: 'Versi',
authorizationId: 'ID Kebenaran Langganan',
@@ -1966,7 +1969,7 @@ const message = {
app: 'Aplikasi',
appNew: 'Aplikasi Baru',
appInstalled: 'Aplikasi yang Dipasang',
create: 'Cipta laman web',
create: 'Cipta',
delete: 'Padam Laman Web',
deleteApp: 'Padam Aplikasi',
deleteBackup: 'Padam Sandaran',
@@ -2551,7 +2554,7 @@ const message = {
};
export default {
...fit2cloudEnLocale,
...fit2cloudMsLocale,
...message,
...xpackEnLocale,
...xpackMsLocale,
};
+8 -6
View File
@@ -60,7 +60,7 @@ const message = {
copy: 'Copiar',
random: 'Aleatório',
uninstall: 'Desinstalar',
fullscreen: 'Entrar em tela cheia',
fullscreen: 'Tela Cheia',
quitFullscreen: 'Sair da tela cheia',
update: 'Editar',
showAll: 'Exibir tudo',
@@ -227,7 +227,7 @@ const message = {
paramUrlAndPort: 'Este campo deve estar no formato "http(s)://(nome do domínio/IP):(porta)".',
nginxDoc: 'Este campo deve conter letras, números e ".".',
appName:
'Este campo não deve começar ou terminar com "-" ou "_" e deve conter letras, números, "-", e "_" com comprimento de 2-30.',
'Suporta letras minúsculas, números, - e _, comprimento de 2 a 30, e não pode começar ou terminar com - ou _',
containerName:
'Suporta letras, números, "-", "_" e "."; não pode começar com "-", "_" ou "."; comprimento: 2-128.',
mirror: 'O endereço de aceleração do mirror deve começar com http(s)://, suportar letras (maiúsculas e minúsculas), números, ".", "/" e "-", e não deve conter linhas em branco.',
@@ -1451,10 +1451,9 @@ const message = {
confDockerProxy: 'Configurar proxy do Docker',
restartNowHelper: 'Configurar o proxy do Docker exige reiniciar o serviço Docker.',
restartNow: 'Reiniciar imediatamente',
systemIPWarning:
'O endereço do servidor ainda não está configurado. Configure-o no painel de controle primeiro.',
systemIPWarning: 'O endereço do sistema não está definido no momento. Defina-o primeiro no painel de controle.',
systemIPWarning1:
'O endereço atual do servidor está configurado como {0}, e o redirecionamento rápido não é possível!',
'O endereço do sistema atual está definido como {0}, e o redirecionamento rápido não é possível!',
defaultNetwork: 'Placa de rede',
syncTime: 'Hora do servidor',
timeZone: 'Fuso horário',
@@ -1723,6 +1722,9 @@ const message = {
community: 'Gratuito',
pro: 'Pro',
trial: 'Teste',
subscription: 'Assinatura',
perpetual: 'Licença Perpétua',
versionConstraint: '{0} Compra do versão',
office: 'Oficial',
trialInfo: 'Versão',
authorizationId: 'ID de autorização de assinatura',
@@ -1957,7 +1959,7 @@ const message = {
app: 'Aplicativo',
appNew: 'Novo Aplicativo',
appInstalled: 'Aplicativo instalado',
create: 'Criar site',
create: 'Criar',
delete: 'Excluir site',
deleteApp: 'Excluir Aplicativo',
deleteBackup: 'Excluir Backup',
+14 -11
View File
@@ -1,9 +1,9 @@
import fit2cloudEnLocale from 'fit2cloud-ui-plus/src/locale/lang/ru';
import fit2cloudRuLocale from 'fit2cloud-ui-plus/src/locale/lang/ru';
let xpackEnLocale = {};
let xpackRuLocale = {};
const xpackModules = import.meta.glob('../../xpack/lang/ru.ts', { eager: true });
if (xpackModules['../../xpack/lang/ru.ts']) {
xpackEnLocale = xpackModules['../../xpack/lang/ru.ts']['default'] || {};
xpackRuLocale = xpackModules['../../xpack/lang/ru.ts']['default'] || {};
}
const message = {
@@ -224,7 +224,7 @@ const message = {
paramUrlAndPort: 'Это поле должно быть в формате "http(s)://(доменное имя/ip):(порт)".',
nginxDoc: 'Это поле должно состоять из английских букв, цифр и ".".',
appName:
'Это поле не должно начинаться и заканчиваться символами "-" и "_" и должно состоять из английских букв, цифр, "-" и "_" длиной 2-30.',
'Поддерживает строчные буквы, цифры, - и _, длина 2-30, и не может начинаться или заканчиваться на - или _',
containerName: 'Поддерживаются буквы, цифры, -, _ и .; не может начинаться с - _ или .; длина: 2-128',
mirror: 'Адрес ускорения зеркала должен начинаться с http(s)://, поддерживает английские буквы (как заглавные, так и строчные), цифры, . / и -, и не должен содержать пустых строк.',
disableFunction: 'Поддерживаются только буквы, подчеркивания и запятые',
@@ -1215,7 +1215,7 @@ const message = {
editPermissions: '@:file.mode',
owner: 'Владелец',
file: 'Файл',
remoteFile: 'Скачать с удаленного сервера',
remoteFile: 'Удалённая загрузка',
share: 'Поделиться',
sync: 'Синхронизация данных',
size: 'Размер',
@@ -1456,8 +1456,8 @@ const message = {
confDockerProxy: 'Настроить прокси docker',
restartNowHelper: 'Настройка прокси Docker требует перезапуска службы Docker.',
restartNow: 'Перезапустить немедленно',
systemIPWarning: 'Адрес сервера в настоящее время не задан. Сначала установите его в панели управления.',
systemIPWarning1: 'Текущий адрес сервера установлен на {0}, быстрое перенаправление невозможно!',
systemIPWarning: 'Системный адрес в настоящее время не установлен. Сначала задайте его в панели управления.',
systemIPWarning1: 'Текущий адрес системы установлен на {0}, быстрая переадресация невозможна!',
defaultNetwork: 'Сетевой интерфейс',
syncTime: 'Время сервера',
timeZone: 'Часовой пояс',
@@ -1720,7 +1720,10 @@ const message = {
community: 'OSS',
oss: 'Open Source Software',
pro: 'Pro',
trial: 'Trial',
trial: 'Пробная версия',
subscription: 'Подписка',
perpetual: 'Пожизненная лицензия',
versionConstraint: '{0} Выкуп версии',
office: 'Official',
trialInfo: 'Версия',
authorizationId: 'ID авторизации подписки',
@@ -1957,7 +1960,7 @@ const message = {
app: 'Приложение',
appNew: 'Новое приложение',
appInstalled: 'Установленное приложение',
create: 'Создать веб-сайт',
create: 'Создать',
delete: 'Удалить веб-сайт',
deleteApp: 'Удалить приложение',
deleteBackup: 'Удалить резервную копию',
@@ -2542,7 +2545,7 @@ const message = {
};
export default {
...fit2cloudEnLocale,
...fit2cloudRuLocale,
...message,
...xpackEnLocale,
...xpackRuLocale,
};
File diff suppressed because it is too large Load Diff
+8 -5
View File
@@ -59,8 +59,8 @@ const message = {
copy: '复制',
random: '随机密码',
uninstall: '卸载',
fullscreen: '网页全屏',
quitFullscreen: '退出网页全屏',
fullscreen: '全屏',
quitFullscreen: '退出全屏',
update: '编辑',
showAll: '显示所有',
hideSome: '隐藏部分',
@@ -216,7 +216,7 @@ const message = {
paramComplexity: '支持英文、数字、{0},长度6-128,特殊字符不能在首尾',
paramUrlAndPort: '格式为 http(s)://(域名/ip):(端口)',
nginxDoc: '仅支持英文大小写,数字,和.',
appName: '支持英文、数字、-和_,长度2-30,并且不能以-_开头和结尾',
appName: '支持小写英文、数字、-和_,长度2-30,并且不能以-_开头和结尾',
containerName: '支持字母、数字、_-和.,不能以-_或.开头,长度2-128',
mirror: '支持以 http(s):// 开头,英文大小写,数字,. / 和 - 的镜像加速地址,且不能有空行',
disableFunction: '仅支持字母、下划线和,',
@@ -1597,7 +1597,10 @@ const message = {
community: '社区版',
oss: '社区版',
pro: '专业版',
trial: '试用版',
trial: '试用',
subscription: '订阅',
perpetual: '永久授权',
versionConstraint: '{0} 版本买断',
office: '正式版',
trialInfo: '版本',
authorizationId: '订阅授权 ID',
@@ -1815,7 +1818,7 @@ const message = {
app: '应用',
appNew: '新装应用',
appInstalled: '已装应用',
create: '创建网站',
create: '创建',
delete: '删除网站',
deleteApp: '删除应用',
deleteBackup: '删除备份',
+63 -3
View File
@@ -3,6 +3,8 @@ import i18n from '@/lang';
import useClipboard from 'vue-clipboard3';
const { toClipboard } = useClipboard();
import { MsgError, MsgSuccess } from '@/utils/message';
import JSEncrypt from 'jsencrypt';
import CryptoJS from 'crypto-js';
export function deepCopy<T>(obj: any): T {
let newObj: any;
@@ -448,17 +450,17 @@ export function getAge(d1: string): string {
let res = '';
if (dayDiff > 0) {
res += String(dayDiff) + i18n.global.t('commons.units.day', dayDiff);
res += String(dayDiff) + ' ' + i18n.global.t('commons.units.day', dayDiff) + ' ';
if (hours <= 0) {
return res;
}
}
if (hours > 0) {
res += String(hours) + i18n.global.t('commons.units.hour', hours);
res += String(hours) + ' ' + i18n.global.t('commons.units.hour', hours) + ' ';
return res;
}
if (minutes > 0) {
res += String(minutes) + i18n.global.t('commons.units.minute', minutes);
res += String(minutes) + ' ' + i18n.global.t('commons.units.minute', minutes);
return res;
}
return i18n.global.t('app.less1Minute');
@@ -615,3 +617,61 @@ export const escapeProxyURL = (url: string): string => {
return url.replace(/[\/:?#[\]@!$&'()*+,;=%~]/g, (match) => encodeMap[match] || match);
};
function getCookie(name: string) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
function rsaEncrypt(data: string, publicKey: string) {
if (!data) {
return data;
}
const jsEncrypt = new JSEncrypt();
jsEncrypt.setPublicKey(publicKey);
return jsEncrypt.encrypt(data);
}
function aesEncrypt(data: string, key: string) {
const keyBytes = CryptoJS.enc.Utf8.parse(key);
const iv = CryptoJS.lib.WordArray.random(16);
const encrypted = CryptoJS.AES.encrypt(data, keyBytes, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return iv.toString(CryptoJS.enc.Base64) + ':' + encrypted.toString();
}
function urlDecode(value: string): string {
return decodeURIComponent(value.replace(/\+/g, ' '));
}
function generateAESKey(): string {
const keyLength = 16;
const randomBytes = new Uint8Array(keyLength);
crypto.getRandomValues(randomBytes);
return Array.from(randomBytes)
.map((b) => b.toString(16).padStart(2, '0'))
.join('');
}
export const encryptPassword = (password: string) => {
if (!password) {
return '';
}
let rsaPublicKeyText = getCookie('panel_public_key');
if (!rsaPublicKeyText) {
console.log('RSA public key not found');
return password;
}
rsaPublicKeyText = urlDecode(rsaPublicKeyText);
const aesKey = generateAESKey();
rsaPublicKeyText = rsaPublicKeyText.replaceAll('"', '');
const rsaPublicKey = atob(rsaPublicKeyText);
const keyCipher = rsaEncrypt(aesKey, rsaPublicKey);
const passwordCipher = aesEncrypt(password, aesKey);
return `${keyCipher}:${passwordCipher}`;
};
+5 -14
View File
@@ -20,7 +20,7 @@
:type="activeTag === item.key ? 'primary' : ''"
:plain="activeTag !== item.key"
>
{{ language == 'zh' || language == 'tw' ? item.name : item.key }}
{{ item.name }}
</el-button>
</div>
<div class="inline">
@@ -42,7 +42,7 @@
@click="changeTag(item.key)"
:key="item.key"
>
{{ language == 'zh' || language == 'tw' ? item.name : item.key }}
{{ item.name }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
@@ -129,17 +129,13 @@
</div>
<div class="app-desc">
<span class="desc">
{{
language == 'zh' || language == 'tw'
? app.shortDescZh
: app.shortDescEn
}}
{{ app.description }}
</span>
</div>
<div class="app-tag">
<el-tag v-for="(tag, ind) in app.tags" :key="ind" class="p-mr-5">
<span>
{{ language == 'zh' || language == 'tw' ? tag.name : tag.key }}
{{ tag.name }}
</span>
</el-tag>
<el-tag v-if="app.status === 'TakeDown'" class="p-mr-5">
@@ -177,16 +173,11 @@ import Detail from '../detail/index.vue';
import Install from '../detail/install/index.vue';
import router from '@/routers';
import { GlobalStore } from '@/store';
import { getLanguage } from '@/utils/util';
const globalStore = GlobalStore();
const mobile = computed(() => {
return globalStore.isMobile();
});
const language = getLanguage();
const paginationConfig = reactive({
cacheSizeKey: 'app-page-size',
currentPage: 1,
@@ -270,7 +261,7 @@ const changeTag = (key: string) => {
const getTagValue = (key: string) => {
const tag = tags.value.find((tag) => tag.key === key);
if (tag) {
return language == 'zh' || language == 'tw' ? tag.name : tag.key;
return tag.name;
}
};
@@ -20,7 +20,7 @@
</div>
<div class="description mb-4">
<span>
{{ language == 'zh' || language == 'tw' ? app.shortDescZh : app.shortDescEn }}
{{ app.description }}
</span>
</div>
<br />
@@ -84,13 +84,10 @@ import { ref } from 'vue';
import Install from './install/index.vue';
import router from '@/routers';
import { GlobalStore } from '@/store';
import { getLanguage } from '@/utils/util';
import { storeToRefs } from 'pinia';
const globalStore = GlobalStore();
const { isDarkTheme } = storeToRefs(globalStore);
const language = getLanguage();
const app = ref<any>({});
const appDetail = ref<any>({});
const version = ref('');
@@ -173,7 +173,7 @@ const installData = ref<InstallProps>({
});
const open = ref(false);
const rules = ref<FormRules>({
name: [Rules.paramSimple],
name: [Rules.appName],
params: [],
version: [Rules.requiredSelect],
containerName: [Rules.containerName],
@@ -248,6 +248,10 @@ const changeService = (value: string, services: App.AppService[]) => {
const getLabel = (row: ParamObj): string => {
const language = localStorage.getItem('lang') || 'zh';
let lang = language == 'tw' ? 'zh-Hant' : language;
if (row.label && row.label[lang] != '') {
return row.label[lang];
}
if (language == 'zh' || language == 'tw') {
return row.labelZh;
} else {
@@ -21,7 +21,7 @@
:type="activeTag === item.key ? 'primary' : ''"
:plain="activeTag !== item.key"
>
{{ language == 'zh' || language == 'tw' ? item.name : item.key }}
{{ item.name }}
</el-button>
</div>
<div class="inline">
@@ -81,7 +81,7 @@
prop="password"
>
<el-input
style="width: calc(100% - 167px)"
style="width: calc(100% - 205px)"
type="password"
show-password
clearable
@@ -82,7 +82,7 @@
prop="password"
>
<el-input
style="width: calc(100% - 147px)"
style="width: calc(100% - 205px)"
type="password"
show-password
clearable
@@ -68,7 +68,7 @@
<el-divider border-style="dashed" />
<el-form-item :label="$t('commons.login.password')" v-if="form.from === 'local'" prop="password">
<el-input
style="width: calc(100% - 147px)"
style="width: calc(100% - 205px)"
type="password"
show-password
clearable
+1 -3
View File
@@ -10,7 +10,7 @@
<span class="h-app-title">{{ app.name }}</span>
<div class="h-app-desc">
<span>
{{ language == 'zh' || language == 'tw' ? app.shortDescZh : app.shortDescEn }}123123
{{ app.description }}
</span>
</div>
</div>
@@ -37,11 +37,9 @@
<script lang="ts" setup>
import { App } from '@/api/interface/app';
import { SearchApp } from '@/api/modules/app';
import { getLanguage } from '@/utils/util';
import { reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
const router = useRouter();
const language = getLanguage();
let req = reactive({
name: '',
+1
View File
@@ -720,6 +720,7 @@ onBeforeUnmount(() => {
font-size: 13px !important;
border: none !important;
width: 100% !important;
line-height: normal !important;
}
.monitor-tags {
@@ -386,12 +386,12 @@
</div>
</template>
</el-table-column>
<el-table-column :label="$t('file.mode')" prop="mode" max-width="50" min-width="110px">
<el-table-column :label="$t('file.mode')" prop="mode" min-width="110">
<template #default="{ row }">
<el-link :underline="false" @click="openMode(row)">{{ row.mode }}</el-link>
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.user')" prop="user" show-overflow-tooltip>
<el-table-column :label="$t('commons.table.user')" prop="user" show-overflow-tooltip min-width="90">
<template #default="{ row }">
<el-link :underline="false" @click="openChown(row)">
{{ row.user ? row.user : '-' }} ({{ row.uid }})
@@ -405,7 +405,7 @@
</el-link>
</template>
</el-table-column>
<el-table-column :label="$t('file.size')" prop="size" max-width="50" sortable>
<el-table-column :label="$t('file.size')" prop="size" min-width="100" sortable>
<template #default="{ row, $index }">
<span v-if="row.isDir">
<el-button
@@ -62,6 +62,7 @@
</el-dropdown-item>
<el-dropdown-item command="ja">日本語</el-dropdown-item>
<el-dropdown-item command="pt-BR">Português (Brasil)</el-dropdown-item>
<el-dropdown-item command="ko">한국어</el-dropdown-item>
<el-dropdown-item command="ru">Русский</el-dropdown-item>
<el-dropdown-item command="ms">Bahasa Melayu</el-dropdown-item>
</el-dropdown-menu>
@@ -179,6 +180,7 @@ import { MsgSuccess } from '@/utils/message';
import { useI18n } from 'vue-i18n';
import { getSettingInfo } from '@/api/modules/setting';
import { Rules } from '@/global/form-rules';
import { encryptPassword } from '@/utils/util';
const i18n = useI18n();
const themeConfig = computed(() => globalStore.themeConfig);
@@ -278,6 +280,8 @@ function handleCommand(command: string) {
dropdownText.value = 'Português (Brasil)';
} else if (command === 'tw') {
dropdownText.value = '中文(繁體)';
} else if (command === 'ko') {
dropdownText.value = '한국어';
} else if (command === 'ja') {
dropdownText.value = '日本語';
} else if (command === 'ru') {
@@ -311,7 +315,7 @@ const login = (formEl: FormInstance | undefined) => {
}
let requestLoginForm = {
name: loginForm.name,
password: loginForm.password,
password: encryptPassword(loginForm.password),
ignoreCaptcha: globalStore.ignoreCaptcha,
captcha: loginForm.captcha,
captchaID: captcha.captchaID,
@@ -367,7 +371,7 @@ const mfaLogin = async (auto: boolean) => {
if ((!auto && mfaLoginForm.code) || (auto && mfaLoginForm.code.length === 6)) {
isLoggingIn = true;
mfaLoginForm.name = loginForm.name;
mfaLoginForm.password = loginForm.password;
mfaLoginForm.password = encryptPassword(loginForm.password);
const res = await mfaLoginApi(mfaLoginForm);
if (res.code === 406) {
errMfaInfo.value = true;
+18 -1
View File
@@ -36,7 +36,7 @@
{{ license.productName || '-' }}
</el-descriptions-item>
<el-descriptions-item :label="$t('license.trialInfo')">
{{ license.trial ? $t('license.trial') : $t('license.office') }}
{{ loadVersion() }}
</el-descriptions-item>
<el-descriptions-item :label="$t('license.expiresAt')">
{{ license.expiresAt || '-' }}
@@ -134,6 +134,8 @@ const license = reactive({
assigneeName: '',
productName: '',
versionConstraint: '',
productPro: '',
status: '',
message: '',
});
@@ -150,6 +152,19 @@ const loadInfo = () => {
return license.status === 'Lost' ? i18n.global.t('license.lostHelper') : i18n.global.t('license.disableHelper');
};
const loadVersion = () => {
if (license.trial) {
return i18n.global.t('license.trial');
}
if (license.productPro && license.productPro !== '0') {
return i18n.global.t('license.subscription');
}
if (license.versionConstraint) {
return i18n.global.t('license.versionConstraint', ['v' + license.versionConstraint.replace('.x', '')]);
}
return i18n.global.t('license.perpetual');
};
const onSync = async () => {
loading.value = true;
await syncLicense()
@@ -222,6 +237,8 @@ const search = async () => {
license.assigneeName = res.data.assigneeName;
license.trial = res.data.trial;
license.offline = res.data.offline;
license.productPro = res.data.productPro;
license.versionConstraint = res.data.versionConstraint;
if (res.data.productPro) {
license.productName = 'product-1panel-pro';
license.expiresAt =
+2 -1
View File
@@ -6,7 +6,7 @@
:model="form"
:label-position="mobile ? 'top' : 'left'"
label-width="auto"
class="sm:w-full md:w-4/5 lg:w-3/5 2xl:w-1/2 max-w-max"
class="sm:w-full md:w-4/5 lg:w-3/5 2xl:w-1/2 max-w-max ml-8"
>
<el-form-item :label="$t('setting.user')" prop="userName">
<el-input disabled v-model="form.userName">
@@ -324,6 +324,7 @@ const languageOptions = ref([
...(!globalStore.isIntl ? [{ value: 'en', label: 'English' }] : []),
{ value: 'ja', label: '日本語' },
{ value: 'pt-BR', label: 'Português (Brasil)' },
{ value: 'ko', label: '한국어' },
{ value: 'ru', label: 'Русский' },
{ value: 'ms', label: 'Bahasa Melayu' },
]);
+144 -153
View File
@@ -6,166 +6,157 @@
:model="form"
v-loading="loading"
:label-position="mobile ? 'top' : 'left'"
label-width="150px"
label-width="auto"
class="sm:w-full md:w-4/5 lg:w-3/5 2xl:w-1/2 max-w-max ml-8"
>
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :xs="24" :sm="20" :md="15" :lg="12" :xl="12">
<el-form-item :label="$t('setting.panelPort')" prop="serverPort">
<el-input disabled v-model.number="form.serverPort">
<template #append>
<el-button @click="onChangePort" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('setting.bindInfo')" prop="bindAddress">
<el-input disabled v-model="form.bindAddress">
<template #append>
<el-button @click="onChangeBind" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('setting.entrance')">
<el-input
type="password"
disabled
v-if="form.securityEntrance"
v-model="form.securityEntrance"
>
<template #append>
<el-button @click="onChangeEntrance" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<el-input disabled v-if="!form.securityEntrance" v-model="unset">
<template #append>
<el-button @click="onChangeEntrance" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('setting.entranceHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('setting.panelPort')" prop="serverPort">
<el-input disabled v-model.number="form.serverPort">
<template #append>
<el-button @click="onChangePort" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('setting.bindInfo')" prop="bindAddress">
<el-input disabled v-model="form.bindAddress">
<template #append>
<el-button @click="onChangeBind" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('setting.entrance')">
<el-input type="password" disabled v-if="form.securityEntrance" v-model="form.securityEntrance">
<template #append>
<el-button @click="onChangeEntrance" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<el-input disabled v-if="!form.securityEntrance" v-model="unset">
<template #append>
<el-button @click="onChangeEntrance" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('setting.entranceHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('setting.noAuthSetting')">
<el-input disabled v-model="form.noAuthSetting">
<template #append>
<el-button @click="onChangeResponse" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('setting.noAuthSetting')">
<el-input disabled v-model="form.noAuthSetting">
<template #append>
<el-button @click="onChangeResponse" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('setting.allowIPs')">
<div style="width: 100%" v-if="form.allowIPs">
<el-input
type="textarea"
:rows="3"
disabled
v-model="form.allowIPs"
style="width: calc(100% - 80px)"
/>
<el-button class="append-button" @click="onChangeAllowIPs" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</div>
<el-input disabled v-if="!form.allowIPs" v-model="unset">
<template #append>
<el-button @click="onChangeAllowIPs" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('setting.allowIPsHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('setting.allowIPs')">
<div style="width: 100%" v-if="form.allowIPs">
<el-input
type="textarea"
:rows="3"
disabled
v-model="form.allowIPs"
style="width: calc(100% - 80px)"
/>
<el-button class="append-button" @click="onChangeAllowIPs" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</div>
<el-input disabled v-if="!form.allowIPs" v-model="unset">
<template #append>
<el-button @click="onChangeAllowIPs" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('setting.allowIPsHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('setting.bindDomain')">
<el-input disabled v-if="form.bindDomain" v-model="form.bindDomain">
<template #append>
<el-button @click="onChangeBindDomain" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<el-input disabled v-if="!form.bindDomain" v-model="unset">
<template #append>
<el-button @click="onChangeBindDomain" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('setting.bindDomainHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('setting.bindDomain')">
<el-input disabled v-if="form.bindDomain" v-model="form.bindDomain">
<template #append>
<el-button @click="onChangeBindDomain" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<el-input disabled v-if="!form.bindDomain" v-model="unset">
<template #append>
<el-button @click="onChangeBindDomain" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('setting.bindDomainHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('setting.panelSSL')" prop="ssl">
<el-switch
@change="handleSSL"
v-model="form.ssl"
active-value="enable"
inactive-value="disable"
/>
<span class="input-help">{{ $t('setting.https') }}</span>
<div v-if="form.ssl === 'enable' && sslInfo">
<el-tag>{{ $t('setting.domainOrIP') }} {{ sslInfo.domain }}</el-tag>
<el-tag style="margin-left: 5px">
{{ $t('setting.timeOut') }} {{ dateFormat('', '', sslInfo.timeout) }}
</el-tag>
<div>
<el-button link type="primary" @click="handleSSL">
{{ $t('commons.button.view') }}
</el-button>
</div>
</div>
</el-form-item>
<el-form-item :label="$t('setting.panelSSL')" prop="ssl">
<el-switch
@change="handleSSL"
v-model="form.ssl"
active-value="enable"
inactive-value="disable"
/>
<span class="input-help">{{ $t('setting.https') }}</span>
<div v-if="form.ssl === 'enable' && sslInfo">
<el-tag>{{ $t('setting.domainOrIP') }} {{ sslInfo.domain }}</el-tag>
<el-tag style="margin-left: 5px">
{{ $t('setting.timeOut') }} {{ dateFormat('', '', sslInfo.timeout) }}
</el-tag>
<div>
<el-button link type="primary" @click="handleSSL">
{{ $t('commons.button.view') }}
</el-button>
</div>
</div>
</el-form-item>
<el-form-item :label="$t('setting.expirationTime')" prop="expirationTime">
<el-input disabled v-model="form.expirationTime">
<template #append>
<el-button @click="onChangeExpirationTime" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<div>
<span class="input-help" v-if="form.expirationTime !== $t('setting.unSetting')">
{{ $t('setting.timeoutHelper', [loadTimeOut()]) }}
</span>
<span class="input-help" v-else>
{{ $t('setting.noneSetting') }}
</span>
</div>
</el-form-item>
<el-form-item :label="$t('setting.complexity')" prop="complexityVerification">
<el-switch
@change="onSaveComplexity"
v-model="form.complexityVerification"
active-value="enable"
inactive-value="disable"
/>
<span class="input-help">
{{ $t('setting.complexityHelper') }}
</span>
</el-form-item>
<el-form-item :label="$t('setting.expirationTime')" prop="expirationTime">
<el-input disabled v-model="form.expirationTime">
<template #append>
<el-button @click="onChangeExpirationTime" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<div>
<span class="input-help" v-if="form.expirationTime !== $t('setting.unSetting')">
{{ $t('setting.timeoutHelper', [loadTimeOut()]) }}
</span>
<span class="input-help" v-else>
{{ $t('setting.noneSetting') }}
</span>
</div>
</el-form-item>
<el-form-item :label="$t('setting.complexity')" prop="complexityVerification">
<el-switch
@change="onSaveComplexity"
v-model="form.complexityVerification"
active-value="enable"
inactive-value="disable"
/>
<span class="input-help">
{{ $t('setting.complexityHelper') }}
</span>
</el-form-item>
<el-form-item :label="$t('setting.mfa')">
<el-switch
@change="handleMFA"
v-model="form.mfaStatus"
active-value="enable"
inactive-value="disable"
/>
<span class="input-help">
{{ $t('setting.mfaHelper') }}
</span>
</el-form-item>
</el-col>
</el-row>
<el-form-item :label="$t('setting.mfa')">
<el-switch
@change="handleMFA"
v-model="form.mfaStatus"
active-value="enable"
inactive-value="disable"
/>
<span class="input-help">
{{ $t('setting.mfaHelper') }}
</span>
</el-form-item>
</el-form>
</template>
</LayoutContent>
@@ -396,7 +396,7 @@ const listPHPExtensions = async () => {
page: 1,
pageSize: 100,
});
phpExtensions.value = res.data;
phpExtensions.value = res.data.items;
} catch (error) {}
};
@@ -1,6 +1,6 @@
<template>
<el-row :gutter="20" v-loading="loading">
<el-col :xs="24" :sm="18" :md="9" :lg="9" :xl="9">
<el-col :xs="24" :sm="18" :md="14" :lg="12" :xl="9">
<el-form ref="websiteForm" label-position="right" label-width="150px" :model="form" :rules="rules">
<el-form-item :label="$t('website.primaryDomain')" prop="primaryDomain">
<el-input v-model="form.primaryDomain"></el-input>
@@ -38,7 +38,7 @@
<script lang="ts" setup name="proxy">
import { Website } from '@/api/interface/website';
import { OperateProxyConfig, GetProxyConfig } from '@/api/modules/website';
import { OperateProxyConfig, GetProxyConfig, DelProxy } from '@/api/modules/website';
import { computed, onMounted, ref } from 'vue';
import Create from './create/index.vue';
import File from './file/index.vue';
@@ -108,6 +108,8 @@ const initData = (id: number): Website.ProxyConfig => ({
proxyPass: 'http://',
proxyHost: '$host',
replaces: {},
sni: false,
proxySSLName: '',
});
const openCreate = () => {
@@ -128,7 +130,10 @@ const openEditFile = (proxyConfig: Website.ProxyConfig) => {
};
const deleteProxy = async (proxyConfig: Website.ProxyConfig) => {
proxyConfig.operate = 'delete';
const del = {
id: proxyConfig.id,
name: proxyConfig.name,
};
opRef.value.acceptParams({
title: i18n.global.t('commons.msg.deleteTitle'),
names: [proxyConfig.name],
@@ -136,8 +141,8 @@ const deleteProxy = async (proxyConfig: Website.ProxyConfig) => {
i18n.global.t('website.proxy'),
i18n.global.t('commons.button.delete'),
]),
api: OperateProxyConfig,
params: proxyConfig,
api: DelProxy,
params: del,
});
};
@@ -505,8 +505,8 @@ const changeType = (type: string) => {
const searchAppInstalled = () => {
GetAppInstalled({ type: 'website', unused: true, all: true, page: 1, pageSize: 100 }).then((res) => {
appInstalls.value = res.data;
if (res.data && res.data.length > 0) {
appInstalls.value = res.data.items;
if (res.data.items && res.data.items.length > 0) {
website.value.appInstallId = res.data[0].id;
}
});
-3
View File
@@ -22,14 +22,11 @@
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
// 解析非相对模块名的基准目录
"baseUrl": "./",
// 模块名到基于 baseUrl的路径映射的列表。
"paths": {
"@": ["src"],
"@/*": ["src/*"]
},
// 跳过库检查,解决打包失败
"skipLibCheck": true,
"ignoreDeprecations": "5.0",
"suppressImplicitAnyIndexErrors": true
+4 -5
View File
@@ -2,10 +2,9 @@
/// <reference types="vite-svg-loader" />
interface ImportMetaEnv {
readonly VITE_API_URL: string
readonly VITE_API_URL: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv
interface ImportMeta {
readonly env: ImportMetaEnv;
}
+2 -2
View File
@@ -58,7 +58,6 @@ require (
golang.org/x/sys v0.28.0
golang.org/x/term v0.27.0
golang.org/x/text v0.21.0
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38
gopkg.in/ini.v1 v1.67.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/gorm v1.25.7
@@ -134,7 +133,7 @@ require (
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/glog v1.2.2 // indirect
github.com/golang/glog v1.2.4 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
@@ -258,6 +257,7 @@ require (
golang.org/x/sync v0.10.0 // indirect
golang.org/x/time v0.8.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/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
google.golang.org/grpc v1.67.1 // indirect
+3 -74
View File
@@ -21,9 +21,8 @@ cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUM
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v1.28.1 h1:XwPcZjgMCnU2tkwY10VleUjSAfpTj9RDn+kGrbYsi8o=
cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
@@ -77,8 +76,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/aliyun/alibaba-cloud-sdk-go v1.63.47 h1:B8ApNodSpIM5ST9INmhMG4d0rRwNY/63/XjXUDO/XIo=
github.com/aliyun/alibaba-cloud-sdk-go v1.63.47/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
github.com/aliyun/alibaba-cloud-sdk-go v1.63.72 h1:HvFZUzEbNvfe8F2Mg0wBGv90bPhWDxgVtDHR5zoBOU0=
github.com/aliyun/alibaba-cloud-sdk-go v1.63.72/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
@@ -99,56 +96,32 @@ github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm
github.com/aws/aws-sdk-go v1.50.20 h1:xfAnSDVf/azIWTVQXQODp89bubvCS85r70O3nuQ4dnE=
github.com/aws/aws-sdk-go v1.50.20/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
github.com/aws/aws-sdk-go-v2 v1.32.3 h1:T0dRlFBKcdaUPGNtkBSwHZxrtis8CQU17UpNBZYd0wk=
github.com/aws/aws-sdk-go-v2 v1.32.3/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo=
github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw=
github.com/aws/aws-sdk-go-v2 v1.32.7/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
github.com/aws/aws-sdk-go-v2/config v1.28.1 h1:oxIvOUXy8x0U3fR//0eq+RdCKimWI900+SV+10xsCBw=
github.com/aws/aws-sdk-go-v2/config v1.28.1/go.mod h1:bRQcttQJiARbd5JZxw6wG0yIK3eLeSCPdg6uqmmlIiI=
github.com/aws/aws-sdk-go-v2/config v1.28.7 h1:GduUnoTXlhkgnxTD93g1nv4tVPILbdNQOzav+Wpg7AE=
github.com/aws/aws-sdk-go-v2/config v1.28.7/go.mod h1:vZGX6GVkIE8uECSUHB6MWAUsd4ZcG2Yq/dMa4refR3M=
github.com/aws/aws-sdk-go-v2/credentials v1.17.42 h1:sBP0RPjBU4neGpIYyx8mkU2QqLPl5u9cmdTWVzIpHkM=
github.com/aws/aws-sdk-go-v2/credentials v1.17.42/go.mod h1:FwZBfU530dJ26rv9saAbxa9Ej3eF/AK0OAY86k13n4M=
github.com/aws/aws-sdk-go-v2/credentials v1.17.48 h1:IYdLD1qTJ0zanRavulofmqut4afs45mOWEI+MzZtTfQ=
github.com/aws/aws-sdk-go-v2/credentials v1.17.48/go.mod h1:tOscxHN3CGmuX9idQ3+qbkzrjVIx32lqDSU1/0d/qXs=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 h1:68jFVtt3NulEzojFesM/WVarlFpCaXLKaBxDpzkQ9OQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18/go.mod h1:Fjnn5jQVIo6VyedMc0/EhPpfNlPl7dHV916O6B+49aE=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 h1:kqOrpojG71DxJm/KDPO+Z/y1phm1JlC8/iT+5XRmAn8=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22/go.mod h1:NtSFajXVVL8TA2QNngagVZmUtXciyrHOt7xgz4faS/M=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 h1:Jw50LwEkVjuVzE1NzkhNKkBf9cRN7MtE1F/b2cOKTUM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22/go.mod h1:Y/SmAyPcOTmpeVaWSzSKiILfXTVJwrGmYZhcRbhWuEY=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 h1:I/5wmGMffY4happ8NOCuIUEWGUvvFp5NSeQcXl9RHcI=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26/go.mod h1:FR8f4turZtNy6baO0KJ5FJUmXH/cSkI9fOngs0yl6mA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 h1:981MHwBaRZM7+9QSR6XamDzF/o7ouUGxFzr+nVSIhrs=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22/go.mod h1:1RA1+aBEfn+CAB/Mh0MB6LsdCYCnjZm7tKXtnk499ZQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 h1:zXFLuEuMMUOvEARXFUVJdfqZ4bvvSgdGRq/ATcrQxzM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26/go.mod h1:3o2Wpy0bogG1kyOPrgkXA8pgIfEEv0+m19O9D5+W8y8=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 h1:qcxX0JYlgWH3hpPUnd6U0ikcl6LLA9sLkXE2w1fpMvY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3/go.mod h1:cLSNEmI45soc+Ef8K/L+8sEA3A3pYFEYf5B5UI+6bH4=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 h1:8eUsivBQzZHqe/3FE+cqwfH+0p5Jo8PFM/QYQSmeZ+M=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7/go.mod h1:kLPQvGUmxn/fqiCrDeohwG33bq2pQpGeY62yRO6Nrh0=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 h1:UTpsIf0loCIWEbrqdLb+0RxnTXfWh2vhw4nQmFi4nPc=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.3/go.mod h1:FZ9j3PFHHAR+w0BSEjK955w5YD2UwB/l/H0yAK3MJvI=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 h1:CvuUmnXI7ebaUAhbJcDy9YQx8wHR69eZ9I7q5hszt/g=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8/go.mod h1:XDeGv1opzwm8ubxddF0cgqkZWsyOtw4lr6dxwmb6YQg=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 h1:2YCmIXv3tmiItw0LlYf6v7gEHebLY45kBEnPezbUKyU=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3/go.mod h1:u19stRyNPxGhj6dRm+Cdgu6N75qnbW7+QN0q0dsAk58=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 h1:F2rBfNAL5UyswqoeWv9zs74N/NanhK16ydHW1pahX6E=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7/go.mod h1:JfyQ0g2JG8+Krq0EuZNnRwX0mU0HrwY/tG6JNfcqh4k=
github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 h1:wVnQ6tigGsRqSWDEEyH6lSAJ9OyFUsSnbaUWChuSGzs=
github.com/aws/aws-sdk-go-v2/service/sts v1.32.3/go.mod h1:VZa9yTFyj4o10YGsmDO4gbQJUvvhY72fhumT8W4LqsE=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 h1:Xgv/hyNgvLda/M9l9qxXc4UFSgppnRczLxlMs5Ae/QY=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3/go.mod h1:5Gn+d+VaaRgsjewpMvGazt0WfcFO+Md4wLOuBfGR9Bc=
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM=
github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro=
github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
@@ -206,8 +179,6 @@ github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ=
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
github.com/cloudflare/cloudflare-go v0.108.0 h1:C4Skfjd8I8X3uEOGmQUT4/iGyZcWdkIU7HwvMoLkEE0=
github.com/cloudflare/cloudflare-go v0.108.0/go.mod h1:m492eNahT/9MsN7Ppnoge8AaI7QhVFtEgVm3I9HJFeU=
github.com/cloudflare/cloudflare-go v0.112.0 h1:caFwqXdGJCl3rjVMgbPEn8iCYAg9JsRYV3dIVQE5d7g=
github.com/cloudflare/cloudflare-go v0.112.0/go.mod h1:QB55kuJ5ZTeLNFcLJePfMuBilhu/LDKpLBmKFQIoSZ0=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
@@ -329,8 +300,6 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
@@ -349,8 +318,6 @@ github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc=
github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA=
github.com/go-acme/lego/v4 v4.20.4 h1:yCQGBX9jOfMbriEQUocdYm7EBapdTp8nLXYG8k6SqSU=
github.com/go-acme/lego/v4 v4.20.4/go.mod h1:foauPlhnhoq8WUphaWx5U04uDc+JGhk4ZZtPz/Vqsjg=
github.com/go-acme/lego/v4 v4.21.0 h1:arEW+8o5p7VI8Bk1kr/PDlgD1DrxtTH1gJ4b7mehL8o=
github.com/go-acme/lego/v4 v4.21.0/go.mod h1:HrSWzm3Ckj45Ie3i+p1zKVobbQoMOaGu9m4up0dUeDI=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@@ -410,8 +377,6 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@@ -434,8 +399,8 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2V
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/glog v1.2.4 h1:CNNw5U8lSiiBk7druxtSHHTsRWcxKoac6kZKm2peBBc=
github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -580,8 +545,6 @@ github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.120 h1:i+rlH2xzkEMGbol86Fq/ioxgAaOnX2vkH4i/bLptc5s=
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.120/go.mod h1:JWz2ujO9X3oU5wb6kXp+DpR2UuDj2SldDbX8T0FSuhI=
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.128 h1:kQ2Agpfy7Ze1ajn9xCQG9G6T7XIbqv+FBDS/U98W9Mk=
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.128/go.mod h1:JWz2ujO9X3oU5wb6kXp+DpR2UuDj2SldDbX8T0FSuhI=
github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
@@ -983,8 +946,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/studio-b12/gowebdav v0.9.0 h1:1j1sc9gQnNxbXXM4M/CebPOX4aXYtr7MojAVcN4dHjU=
@@ -998,12 +959,8 @@ github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRd
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.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1034 h1:T7ewuO2DD+5R2LRpD2kTRy25aCkVDVdYkmmyUS63i08=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1034/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1065 h1:krcqtAmexnHHBm/4ge4tr2b1cn/a7JGBESVGoZYXQAE=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1065/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1034 h1:hXxv58/eSlDj80n0P0ISXh91pC/2vqurJNwn5SpXFPI=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1034/go.mod h1:hwTIplwF9IYWz5HQcyw0+R8aqJB0lEZB8sI0pIA5Htw=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1065 h1:aEFtLD1ceyeljQXB1S2BjN0zjTkf0X3XmpuxFIiC29w=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1065/go.mod h1:HWvwy09hFSMXrj9SMvVRWV4U7rZO3l+WuogyNuxiT3M=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0=
@@ -1044,8 +1001,6 @@ github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0o
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
github.com/volcengine/volc-sdk-golang v1.0.183 h1:V6M/lhgnBxZS3pLDNwMXSLw+i4VowphNCfVzai6JjWE=
github.com/volcengine/volc-sdk-golang v1.0.183/go.mod h1:u0VtPvlXWpXDTmc9IHkaW1q+5Jjwus4oAqRhNMDRInE=
github.com/volcengine/volc-sdk-golang v1.0.189 h1:VMDTHWYXakXJtZqPYn0As/h4eB0c4imvyru6mIp+o60=
github.com/volcengine/volc-sdk-golang v1.0.189/go.mod h1:u0VtPvlXWpXDTmc9IHkaW1q+5Jjwus4oAqRhNMDRInE=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
@@ -1149,8 +1104,6 @@ golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1166,8 +1119,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE=
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU=
golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
@@ -1198,8 +1149,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
@@ -1211,8 +1160,6 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1228,8 +1175,6 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1305,8 +1250,6 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.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.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@@ -1315,8 +1258,6 @@ golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1334,8 +1275,6 @@ golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1343,8 +1282,6 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1399,8 +1336,6 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
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.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1468,12 +1403,8 @@ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxH
google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U=
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 h1:pgr/4QbFyktUv9CtQ/Fq4gzEE6/Xs7iCXbktaGzLHbQ=
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@@ -1510,8 +1441,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=