diff --git a/agent/app/api/v2/website_ssl.go b/agent/app/api/v2/website_ssl.go index 6a546cc10..c46b0b1e5 100644 --- a/agent/app/api/v2/website_ssl.go +++ b/agent/app/api/v2/website_ssl.go @@ -1,6 +1,7 @@ package v2 import ( + "github.com/1Panel-dev/1Panel/agent/app/model" "net/http" "net/url" "reflect" @@ -245,3 +246,15 @@ func (b *BaseApi) DownloadWebsiteSSL(c *gin.Context) { c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name())) http.ServeContent(c.Writer, c.Request, info.Name(), info.ModTime(), file) } + +func (b *BaseApi) ImportMasterSSL(c *gin.Context) { + var req model.WebsiteSSL + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + if err := websiteSSLService.ImportMasterSSL(req); err != nil { + helper.InternalServer(c, err) + return + } + helper.Success(c) +} diff --git a/agent/app/dto/request/website_ssl.go b/agent/app/dto/request/website_ssl.go index 06a662607..a08b5ea9c 100644 --- a/agent/app/dto/request/website_ssl.go +++ b/agent/app/dto/request/website_ssl.go @@ -9,24 +9,26 @@ type WebsiteSSLSearch struct { } type WebsiteSSLCreate struct { - PrimaryDomain string `json:"primaryDomain" validate:"required"` - OtherDomains string `json:"otherDomains"` - Provider string `json:"provider" validate:"required"` - AcmeAccountID uint `json:"acmeAccountId" validate:"required"` - DnsAccountID uint `json:"dnsAccountId"` - AutoRenew bool `json:"autoRenew"` - KeyType string `json:"keyType"` - Apply bool `json:"apply"` - PushDir bool `json:"pushDir"` - Dir string `json:"dir"` - ID uint `json:"id"` - Description string `json:"description"` - DisableCNAME bool `json:"disableCNAME"` - SkipDNS bool `json:"skipDNS"` - Nameserver1 string `json:"nameserver1"` - Nameserver2 string `json:"nameserver2"` - ExecShell bool `json:"execShell"` - Shell string `json:"shell"` + PrimaryDomain string `json:"primaryDomain" validate:"required"` + OtherDomains string `json:"otherDomains"` + Provider string `json:"provider" validate:"required"` + AcmeAccountID uint `json:"acmeAccountId" validate:"required"` + DnsAccountID uint `json:"dnsAccountId"` + AutoRenew bool `json:"autoRenew"` + KeyType string `json:"keyType"` + Apply bool `json:"apply"` + PushDir bool `json:"pushDir"` + Dir string `json:"dir"` + ID uint `json:"id"` + Description string `json:"description"` + DisableCNAME bool `json:"disableCNAME"` + SkipDNS bool `json:"skipDNS"` + Nameserver1 string `json:"nameserver1"` + Nameserver2 string `json:"nameserver2"` + ExecShell bool `json:"execShell"` + Shell string `json:"shell"` + PushNode bool `json:"pushNode"` + Nodes []string `json:"nodes"` } type WebsiteDNSReq struct { diff --git a/agent/app/model/website_ssl.go b/agent/app/model/website_ssl.go index a3c6591a2..99a0d201e 100644 --- a/agent/app/model/website_ssl.go +++ b/agent/app/model/website_ssl.go @@ -36,6 +36,9 @@ type WebsiteSSL struct { DisableCNAME bool `json:"disableCNAME"` ExecShell bool `json:"execShell"` Shell string `json:"shell"` + MasterSSLID uint `json:"masterSslId"` + Nodes string `json:"nodes"` + PushNode bool `json:"pushNode"` AcmeAccount WebsiteAcmeAccount `json:"acmeAccount" gorm:"-:migration"` DnsAccount WebsiteDnsAccount `json:"dnsAccount" gorm:"-:migration"` diff --git a/agent/app/repo/website_ssl.go b/agent/app/repo/website_ssl.go index fbb4e3ebd..63fe27ac8 100644 --- a/agent/app/repo/website_ssl.go +++ b/agent/app/repo/website_ssl.go @@ -17,6 +17,7 @@ type ISSLRepo interface { WithByDnsAccountId(dnsAccountId uint) DBOption WithByCAID(caID uint) DBOption WithByDomain(domain string) DBOption + WithByMasterSSLID(sslID uint) DBOption Page(page, size int, opts ...DBOption) (int64, []model.WebsiteSSL, error) GetFirst(opts ...DBOption) (*model.WebsiteSSL, error) List(opts ...DBOption) ([]model.WebsiteSSL, error) @@ -52,12 +53,19 @@ func (w WebsiteSSLRepo) WithByCAID(caID uint) DBOption { return db.Where("ca_id = ?", caID) } } + func (w WebsiteSSLRepo) WithByDomain(domain string) DBOption { return func(db *gorm.DB) *gorm.DB { return db.Where("primary_domain Like ? or domains Like ?", "%"+domain+"%", "%"+domain+"%") } } +func (w WebsiteSSLRepo) WithByMasterSSLID(sslID uint) DBOption { + return func(db *gorm.DB) *gorm.DB { + return db.Where("master_ssl_id = ?", sslID) + } +} + func (w WebsiteSSLRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteSSL, error) { var sslList []model.WebsiteSSL db := getDb(opts...).Model(&model.WebsiteSSL{}) diff --git a/agent/app/service/website_ssl.go b/agent/app/service/website_ssl.go index 0266f1aa4..4bfee04ea 100644 --- a/agent/app/service/website_ssl.go +++ b/agent/app/service/website_ssl.go @@ -5,6 +5,7 @@ import ( "crypto/x509" "encoding/pem" "fmt" + "github.com/1Panel-dev/1Panel/agent/utils/xpack" "github.com/go-acme/lego/v4/certificate" "log" "os" @@ -46,6 +47,7 @@ type IWebsiteSSLService interface { ObtainSSL(apply request.WebsiteSSLApply) error SyncForRestart() error DownloadFile(id uint) (*os.File, error) + ImportMasterSSL(create model.WebsiteSSL) error } func NewIWebsiteSSLService() IWebsiteSSLService { @@ -146,6 +148,10 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs } websiteSSL.Dir = create.Dir } + if create.PushNode && global.IsMaster && len(create.Nodes) > 0 { + websiteSSL.PushNode = true + websiteSSL.Nodes = strings.Join(create.Nodes, ",") + } var domains []string if create.OtherDomains != "" { @@ -207,7 +213,7 @@ func printSSLLog(logger *log.Logger, msgKey string, params map[string]interface{ } func reloadSystemSSL(websiteSSL *model.WebsiteSSL, logger *log.Logger) { - if global.CoreDB == nil { + if !global.IsMaster { return } systemSSLEnable, sslID := GetSystemSSL() @@ -387,6 +393,14 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error { printSSLLog(logger, "ApplyWebSiteSSLSuccess", nil, apply.DisableLog) } reloadSystemSSL(websiteSSL, logger) + if websiteSSL.PushNode { + printSSLLog(logger, "StartPushSSLToNode", nil, apply.DisableLog) + if err = xpack.PushSSLToNode(websiteSSL); err != nil { + printSSLLog(logger, "PushSSLToNodeFailed", map[string]interface{}{"err": err.Error()}, apply.DisableLog) + return + } + printSSLLog(logger, "PushSSLToNodeSuccess", nil, apply.DisableLog) + } }() return nil @@ -712,3 +726,55 @@ func (w WebsiteSSLService) SyncForRestart() error { } return nil } + +func (w WebsiteSSLService) ImportMasterSSL(create model.WebsiteSSL) error { + websiteSSL, _ := websiteSSLRepo.GetFirst(websiteSSLRepo.WithByMasterSSLID(create.ID)) + if websiteSSL == nil { + websiteSSL = &model.WebsiteSSL{ + Status: constant.SSLReady, + Provider: constant.FromMaster, + PrimaryDomain: create.PrimaryDomain, + StartDate: create.StartDate, + ExpireDate: create.ExpireDate, + KeyType: create.KeyType, + Description: create.Description, + MasterSSLID: create.ID, + PrivateKey: create.PrivateKey, + Pem: create.Pem, + Type: create.Type, + Organization: create.Organization, + } + if err := websiteSSLRepo.Create(context.TODO(), websiteSSL); err != nil { + return err + } + } else { + websiteSSL.PrimaryDomain = create.PrimaryDomain + websiteSSL.StartDate = create.StartDate + websiteSSL.ExpireDate = create.ExpireDate + websiteSSL.KeyType = create.KeyType + websiteSSL.Description = create.Description + websiteSSL.PrivateKey = create.PrivateKey + websiteSSL.Pem = create.Pem + websiteSSL.Type = create.Type + websiteSSL.Organization = create.Organization + if err := websiteSSLRepo.Save(websiteSSL); err != nil { + return err + } + } + websites, _ := websiteRepo.GetBy(websiteRepo.WithWebsiteSSLID(websiteSSL.ID)) + if len(websites) == 0 { + return nil + } + for _, website := range websites { + if err := createPemFile(website, *websiteSSL); err != nil { + continue + } + } + nginxInstall, err := getAppInstallByKey(constant.AppOpenresty) + if err == nil { + if err := opNginx(nginxInstall.ContainerName, constant.NginxReload); err != nil { + return err + } + } + return nil +} diff --git a/agent/constant/website.go b/agent/constant/website.go index 7e96e16af..e4a3d059d 100644 --- a/agent/constant/website.go +++ b/agent/constant/website.go @@ -25,6 +25,7 @@ const ( Http = "http" Manual = "manual" SelfSigned = "selfSigned" + FromMaster = "fromMaster" StartWeb = "start" StopWeb = "stop" diff --git a/agent/i18n/lang/en.yaml b/agent/i18n/lang/en.yaml index 58b0fe4bf..e820a677c 100644 --- a/agent/i18n/lang/en.yaml +++ b/agent/i18n/lang/en.yaml @@ -162,6 +162,9 @@ StartUpdateSystemSSL: 'Start updating system certificate' UpdateSystemSSLSuccess: 'Update system certificate successfully' ErrWildcardDomain: 'Unable to apply for wildcard domain name certificate in HTTP mode' ErrApplySSLCanNotDelete: "The certificate {{.name}} being applied for cannot be deleted, please try again later." +StartPushSSLToNode: "Starting to push certificate to node" +PushSSLToNodeFailed: "Failed to push certificate to node: {{ .err }}" +PushSSLToNodeSuccess: "Successfully pushed certificate to node" #mysql ErrUserIsExist: 'The current user already exists, please re-enter' diff --git a/agent/i18n/lang/ja.yaml b/agent/i18n/lang/ja.yaml index a2d31519e..73ff924aa 100644 --- a/agent/i18n/lang/ja.yaml +++ b/agent/i18n/lang/ja.yaml @@ -162,6 +162,9 @@ StartUpdateSystemSSL: 'システム証明書の更新を開始します' UpdateSystemSSLSuccess: 'システム証明書を正常に更新しました' ErrWildcardDomain: 'HTTP モードでワイルドカード ドメイン名証明書を申請できません' ErrApplySSLCanNotDelete: "申請中の証明書 {{.name}} は削除できません。しばらくしてからもう一度お試しください。" +StartPushSSLToNode: "証明書をノードにプッシュ開始" +PushSSLToNodeFailed: "ノードに証明書をプッシュ失敗: {{ .err }}" +PushSSLToNodeSuccess: "ノードに証明書をプッシュ成功" #mysql ErrUserIsExist: '現在のユーザーは既に存在します。再入力してください' diff --git a/agent/i18n/lang/ko.yaml b/agent/i18n/lang/ko.yaml index a07e2fc85..109cbb4c6 100644 --- a/agent/i18n/lang/ko.yaml +++ b/agent/i18n/lang/ko.yaml @@ -162,6 +162,9 @@ StartUpdateSystemSSL: '시스템 인증서 업데이트 시작' UpdateSystemSSLSuccess: '시스템 인증서 업데이트가 성공적으로 완료되었습니다.' ErrWildcardDomain: 'HTTP 모드에서 와일드카드 도메인 이름 인증서를 신청할 수 없습니다' ErrApplySSLCanNotDelete: "신청 중인 인증서 {{.name}}는 삭제할 수 없습니다. 나중에 다시 시도해 주세요." +StartPushSSLToNode: "인증서를 노드로 푸시 시작" +PushSSLToNodeFailed: "노드로 인증서 푸시 실패: {{ .err }}" +PushSSLToNodeSuccess: "노드로 인증서 푸시 성공" #마이SQL ErrUserIsExist: '현재 사용자가 이미 존재합니다. 다시 입력하세요' diff --git a/agent/i18n/lang/ms.yaml b/agent/i18n/lang/ms.yaml index 5e7a2b573..45a95acf8 100644 --- a/agent/i18n/lang/ms.yaml +++ b/agent/i18n/lang/ms.yaml @@ -14,6 +14,9 @@ ErrApiConfigKeyInvalid: 'Ralat kunci antara muka API: {{ .detail }}' ErrApiConfigIPInvalid: 'IP yang digunakan untuk memanggil antara muka API tiada dalam senarai putih: {{ .detail }}' ErrApiConfigDisable: 'Antara muka ini melarang penggunaan panggilan antara muka API: {{ .detail }}' ErrApiConfigKeyTimeInvalid: 'Ralat cap masa antara muka API: {{ .detail }}' +StartPushSSLToNode: "Mula menolak sijil ke nod" +PushSSLToNodeFailed: "Gagal menolak sijil ke nod: {{ .err }}" +PushSSLToNodeSuccess: "Berjaya menolak sijil ke nod" #biasa ErrUsernameIsExist: 'Nama pengguna sudah wujud' diff --git a/agent/i18n/lang/pt-BR.yaml b/agent/i18n/lang/pt-BR.yaml index 345eb762f..23464540a 100644 --- a/agent/i18n/lang/pt-BR.yaml +++ b/agent/i18n/lang/pt-BR.yaml @@ -14,6 +14,9 @@ ErrApiConfigKeyInvalid: 'Erro de chave da interface da API: {{ .detail }}' ErrApiConfigIPInvalid: 'O IP usado para chamar a interface da API não está na lista de permissões: {{ .detail }}' ErrApiConfigDisable: 'Esta interface proíbe o uso de chamadas de interface de API: {{ .detail }}' ErrApiConfigKeyTimeInvalid: 'Erro de registro de data e hora da interface da API: {{ .detail }}' +StartPushSSLToNode: "Iniciando o envio do certificado para o nó" +PushSSLToNodeFailed: "Falha ao enviar o certificado para o nó: {{ .err }}" +PushSSLToNodeSuccess: "Certificado enviado com sucesso para o nó" #comum ErrUsernameIsExist: 'Nome de usuário já existe' diff --git a/agent/i18n/lang/ru.yaml b/agent/i18n/lang/ru.yaml index 8ee75aeaa..386704f63 100644 --- a/agent/i18n/lang/ru.yaml +++ b/agent/i18n/lang/ru.yaml @@ -14,6 +14,9 @@ ErrApiConfigKeyInvalid: 'Ошибка ключа интерфейса API: {{ .d ErrApiConfigIPInvalid: 'IP-адрес, используемый для вызова интерфейса API, отсутствует в белом списке: {{ .detail }}' ErrApiConfigDisable: 'Этот интерфейс запрещает использование вызовов интерфейса API: {{ .detail }}' ErrApiConfigKeyTimeInvalid: 'Ошибка временной метки интерфейса API: {{ .detail }}' +StartPushSSLToNode: "Начало отправки сертификата на узел" +PushSSLToNodeFailed: "Не удалось отправить сертификат на узел: {{ .err }}" +PushSSLToNodeSuccess: "Сертификат успешно отправлен на узел" #общий ErrUsernameIsExist: 'Имя пользователя уже существует' diff --git a/agent/i18n/lang/tr.yaml b/agent/i18n/lang/tr.yaml index 1d9949b37..6d0fcaf24 100644 --- a/agent/i18n/lang/tr.yaml +++ b/agent/i18n/lang/tr.yaml @@ -14,6 +14,9 @@ ErrApiConfigKeyInvalid: 'API arayüz anahtarı hatası: {{ .detail }}' ErrApiConfigIPInvalid: 'API arayüzünü çağırmak için kullanılan IP beyaz listede değil: {{ .detail }}' ErrApiConfigDisable: 'Bu arayüz API arayüz çağrılarının kullanımını yasaklıyor: {{ .detail }}' ErrApiConfigKeyTimeInvalid: 'API arayüz zaman damgası hatası: {{ .detail }}' +StartPushSSLToNode: "Sertifika düğüme gönderilmeye başlandı" +PushSSLToNodeFailed: "Sertifika düğüme gönderilemedi: {{ .err }}" +PushSSLToNodeSuccess: "Sertifika düğüme başarıyla gönderildi" #common ErrUsernameIsExist: 'Kullanıcı adı zaten mevcut' diff --git a/agent/i18n/lang/zh-Hant.yaml b/agent/i18n/lang/zh-Hant.yaml index edd4498a3..a336c9f1c 100644 --- a/agent/i18n/lang/zh-Hant.yaml +++ b/agent/i18n/lang/zh-Hant.yaml @@ -161,6 +161,9 @@ StartUpdateSystemSSL: '開始更新系統憑證' UpdateSystemSSLSuccess: '更新系統憑證成功' ErrWildcardDomain: 'HTTP 模式無法申請泛網域憑證' ErrApplySSLCanNotDelete: "正在申請的證書 {{.name}} 無法刪除,請稍後再試" +StartPushSSLToNode: "開始推送證書到節點" +PushSSLToNodeFailed: "推送證書到節點失敗: {{ .err }}" +PushSSLToNodeSuccess: "推送證書到節點成功" #mysql ErrUserIsExist: '目前使用者已存在,請重新輸入' diff --git a/agent/i18n/lang/zh.yaml b/agent/i18n/lang/zh.yaml index c3aa9923d..7b4992c9b 100644 --- a/agent/i18n/lang/zh.yaml +++ b/agent/i18n/lang/zh.yaml @@ -161,6 +161,9 @@ StartUpdateSystemSSL: "开始更新系统证书" UpdateSystemSSLSuccess: "更新系统证书成功" ErrWildcardDomain: "HTTP 模式无法申请泛域名证书" ErrApplySSLCanNotDelete: "正在申请的证书{{.name}}无法删除,请稍后再试" +StartPushSSLToNode: "开始推送证书到节点" +PushSSLToNodeFailed: "推送证书到节点失败: {{ .err }}" +PushSSLToNodeSuccess: "推送证书到节点成功" #mysql ErrUserIsExist: "当前用户已存在,请重新输入" diff --git a/agent/init/migration/migrate.go b/agent/init/migration/migrate.go index 306bee2ed..dceebff39 100644 --- a/agent/init/migration/migrate.go +++ b/agent/init/migration/migrate.go @@ -36,6 +36,7 @@ func InitAgentDB() { migrations.UpdateMcpServer, migrations.InitCronjobGroup, migrations.AddColumnToAlert, + migrations.UpdateWebsiteSSL, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/agent/init/migration/migrations/init.go b/agent/init/migration/migrations/init.go index f07adb005..4b6e9764b 100644 --- a/agent/init/migration/migrations/init.go +++ b/agent/init/migration/migrations/init.go @@ -461,3 +461,13 @@ var AddColumnToAlert = &gormigrate.Migration{ return nil }, } + +var UpdateWebsiteSSL = &gormigrate.Migration{ + ID: "20250819-update-website-ssl", + Migrate: func(tx *gorm.DB) error { + if err := tx.AutoMigrate(&model.WebsiteSSL{}); err != nil { + return err + } + return nil + }, +} diff --git a/agent/router/ro_website_ssl.go b/agent/router/ro_website_ssl.go index beb7d3b69..fcb194063 100644 --- a/agent/router/ro_website_ssl.go +++ b/agent/router/ro_website_ssl.go @@ -23,5 +23,6 @@ func (a *WebsiteSSLRouter) InitRouter(Router *gin.RouterGroup) { groupRouter.POST("/upload", baseApi.UploadWebsiteSSL) groupRouter.POST("/obtain", baseApi.ApplyWebsiteSSL) groupRouter.POST("/download", baseApi.DownloadWebsiteSSL) + groupRouter.POST("/import", baseApi.ImportMasterSSL) } } diff --git a/agent/utils/ssl/acme.go b/agent/utils/ssl/acme.go index aec5ebc97..b4d25db1a 100644 --- a/agent/utils/ssl/acme.go +++ b/agent/utils/ssl/acme.go @@ -181,7 +181,8 @@ func getCaDirURL(accountType, customCaURL string) string { var caDirURL string switch accountType { case "letsencrypt": - caDirURL = "https://acme-v02.api.letsencrypt.org/directory" + //caDirURL = "https://acme-v02.api.letsencrypt.org/directory" + caDirURL = "https://acme-staging-v02.api.letsencrypt.org/directory" case "zerossl": caDirURL = "https://acme.zerossl.com/v2/DV90" case "buypass": diff --git a/agent/utils/xpack/xpack.go b/agent/utils/xpack/xpack.go index efee272ec..6ba1c2520 100644 --- a/agent/utils/xpack/xpack.go +++ b/agent/utils/xpack/xpack.go @@ -85,3 +85,7 @@ func LoadRequestTransport() *http.Transport { func ValidateCertificate(c *gin.Context) bool { return true } + +func PushSSLToNode(websiteSSL *model.WebsiteSSL) error { + return nil +} diff --git a/core/i18n/lang/en.yaml b/core/i18n/lang/en.yaml index e40bcbe87..12f8c4ef4 100644 --- a/core/i18n/lang/en.yaml +++ b/core/i18n/lang/en.yaml @@ -227,4 +227,7 @@ ErrMasterDelete: "Unable to delete the master node, please delete the slave node ClusterNameIsExist: "Cluster name already exists." AppStatusUnHealthy: "Application status acquisition is abnormal, please check the installation node status in the node list." MasterNodePortNotAvailable: "Node {{ .name }} port {{ .port }} connectivity verification failed, please check firewall/security group settings and master node status." -ClusterMasterNotExist: "The master node of the cluster is disconnected, please delete the child nodes." \ No newline at end of file +ClusterMasterNotExist: "The master node of the cluster is disconnected, please delete the child nodes." + +#ssl +ErrReqFailed: "{{.name}} request failed: {{ .err }}" \ No newline at end of file diff --git a/core/i18n/lang/ja.yaml b/core/i18n/lang/ja.yaml index 67a6c9f56..c8c744f39 100644 --- a/core/i18n/lang/ja.yaml +++ b/core/i18n/lang/ja.yaml @@ -228,4 +228,7 @@ ErrMasterDelete: "マスターノードを削除できません。スレーブ ClusterNameIsExist: "クラスタ名は既に存在します。" AppStatusUnHealthy: "アプリケーションのステータス取得が異常です。ノードリストでインストールノードのステータスを確認してください。" MasterNodePortNotAvailable: "ノード {{ .name }} のポート {{ .port }} の接続性検証が失敗しました。ファイアウォール/セキュリティグループの設定とマスターノードのステータスを確認してください。" -ClusterMasterNotExist: "クラスタのマスターノードが切断されています。子ノードを削除してください。" \ No newline at end of file +ClusterMasterNotExist: "クラスタのマスターノードが切断されています。子ノードを削除してください。" + +#ssl +ErrReqFailed: "{{.name}} リクエスト失敗: {{ .err }}" \ No newline at end of file diff --git a/core/i18n/lang/ko.yaml b/core/i18n/lang/ko.yaml index bad73bdd6..d9053e45c 100644 --- a/core/i18n/lang/ko.yaml +++ b/core/i18n/lang/ko.yaml @@ -227,4 +227,7 @@ ErrMasterDelete: "마스터 노드를 삭제할 수 없습니다. 슬레이브 ClusterNameIsExist: "클러스터 이름이 이미 존재합니다." AppStatusUnHealthy: "애플리케이션 상태 획득이 비정상입니다. 노드 목록에서 설치 노드 상태를 확인하세요." MasterNodePortNotAvailable: "노드 {{ .name }} 포트 {{ .port }} 연결성 검증에 실패했습니다. 방화벽/보안 그룹 설정 및 마스터 노드 상태를 확인하세요." -ClusterMasterNotExist: "클러스터의 마스터 노드가 연결이 끊어졌습니다. 자식 노드를 삭제하세요." \ No newline at end of file +ClusterMasterNotExist: "클러스터의 마스터 노드가 연결이 끊어졌습니다. 자식 노드를 삭제하세요." + +#ssl +ErrReqFailed: "{{.name}} 요청 실패: {{ .err }}" \ No newline at end of file diff --git a/core/i18n/lang/ms.yml b/core/i18n/lang/ms.yml index 49fa2d14e..cee732e03 100644 --- a/core/i18n/lang/ms.yml +++ b/core/i18n/lang/ms.yml @@ -222,4 +222,7 @@ ErrMasterDelete: "Tidak dapat menghapus nod utama, sila hapuskan nod perantara d ClusterNameIsExist: "Nama kluster sudah wujud." AppStatusUnHealthy: "Pengambilan status aplikasi tidak normal, sila periksa status nod pemasangan dalam senarai nod." MasterNodePortNotAvailable: "Pengesahan kesambungan pelabuhan {{ .name }} nod {{ .port }} gagal, sila periksa tetapan firewall/kumpulan keselamatan dan status nod utama." -ClusterMasterNotExist: "Node utama kluster terputus, sila padamkan nod anak." \ No newline at end of file +ClusterMasterNotExist: "Node utama kluster terputus, sila padamkan nod anak." + +#ssl +ErrReqFailed: "{{.name}} permintaan gagal: {{ .err }}" \ No newline at end of file diff --git a/core/i18n/lang/pt-BR.yaml b/core/i18n/lang/pt-BR.yaml index 1500f54b8..ee5dd6d94 100644 --- a/core/i18n/lang/pt-BR.yaml +++ b/core/i18n/lang/pt-BR.yaml @@ -227,4 +227,7 @@ ErrMasterDelete: "Não é possível excluir o nó mestre, exclua os nós escravo ClusterNameIsExist: "O nome do cluster já existe." AppStatusUnHealthy: "A aquisição do status do aplicativo está anormal, verifique o status dos nós de instalação na lista de nós." MasterNodePortNotAvailable: "A verificação de conectividade da porta {{ .port }} do nó {{ .name }} falhou, verifique as configurações de firewall/grupo de segurança e o status do nó mestre." -ClusterMasterNotExist: "O nó mestre do cluster está desconectado, por favor, exclua os nós filhos." \ No newline at end of file +ClusterMasterNotExist: "O nó mestre do cluster está desconectado, por favor, exclua os nós filhos." + +#ssl +ErrReqFailed: "{{.name}} solicitação falhou: {{ .err }} \ No newline at end of file diff --git a/core/i18n/lang/ru.yaml b/core/i18n/lang/ru.yaml index 426ffac9f..ae43df935 100644 --- a/core/i18n/lang/ru.yaml +++ b/core/i18n/lang/ru.yaml @@ -227,4 +227,7 @@ ErrMasterDelete: "Невозможно удалить основной узел, ClusterNameIsExist: "Имя кластера уже существует." AppStatusUnHealthy: "Получение статуса приложения аномально, пожалуйста, проверьте статус узлов установки в списке узлов." MasterNodePortNotAvailable: "Проверка подключения порта {{ .port }} узла {{ .name }} не удалась, пожалуйста, проверьте настройки брандмауэра/группы безопасности и статус главного узла." -ClusterMasterNotExist: "Основной узел кластера отключен, пожалуйста, удалите дочерние узлы." \ No newline at end of file +ClusterMasterNotExist: "Основной узел кластера отключен, пожалуйста, удалите дочерние узлы." + +#ssl +ErrReqFailed: "{{.name}} запрос не удался: {{ .err }}" \ No newline at end of file diff --git a/core/i18n/lang/tr.yaml b/core/i18n/lang/tr.yaml index 0d64d3881..cdc140645 100644 --- a/core/i18n/lang/tr.yaml +++ b/core/i18n/lang/tr.yaml @@ -226,4 +226,7 @@ ErrMasterDelete: "Ana düğümü silinemiyor, lütfen önce alt düğümleri sil ClusterNameIsExist: "Küme adı zaten var." AppStatusUnHealthy: "Uygulama durumu alımı anormal, lütfen düğüm listesindeki yükleme düğümü durumunu kontrol edin." MasterNodePortNotAvailable: "Düğüm {{ .name }} portu {{ .port }} bağlantı doğrulaması başarısız oldu, lütfen güvenlik duvarı/güvenlik grubu ayarlarını ve ana düğüm durumunu kontrol edin." -ClusterMasterNotExist: "Küme ana düğümü bağlantısı kesildi, lütfen alt düğümleri silin." \ No newline at end of file +ClusterMasterNotExist: "Küme ana düğümü bağlantısı kesildi, lütfen alt düğümleri silin." + +#ssl +ErrReqFailed: "{{.name}} istek başarısız: {{ .err }}" \ No newline at end of file diff --git a/core/i18n/lang/zh-Hant.yaml b/core/i18n/lang/zh-Hant.yaml index ef75db1aa..a665ccd98 100644 --- a/core/i18n/lang/zh-Hant.yaml +++ b/core/i18n/lang/zh-Hant.yaml @@ -236,4 +236,7 @@ ErrMasterDelete: "無法刪除主節點,請先刪除從節點。" ClusterNameIsExist: "集群名稱已存在。" AppStatusUnHealthy: "應用獲取狀態異常,請在節點列表檢查安裝節點狀態。" MasterNodePortNotAvailable: "節點 {{ .name }} 端口 {{ .port }} 連通性校驗失敗,請檢查防火牆/安全組設置和主節點狀態。" -ClusterMasterNotExist: "集群主節點失聯,請刪除子節點。" \ No newline at end of file +ClusterMasterNotExist: "集群主節點失聯,請刪除子節點。" + +#ssl +ErrReqFailed: "{{.name}} 請求失敗: {{ .err }}" \ No newline at end of file diff --git a/core/i18n/lang/zh.yaml b/core/i18n/lang/zh.yaml index cb5f97eb2..a35aff9b8 100644 --- a/core/i18n/lang/zh.yaml +++ b/core/i18n/lang/zh.yaml @@ -236,4 +236,7 @@ ErrMasterDelete: "无法删除主节点,请先删除从节点" ClusterNameIsExist: "集群名称已存在" AppStatusUnHealthy: "应用获取状态异常,请在节点列表检查安装节点状态" MasterNodePortNotAvailable: "节点 {{ .name }} 端口 {{ .port }} 连通性校验失败,请检查防火墙/安全组设置和主节点状态" -ClusterMasterNotExist: "集群主节点失联,请删除子节点" \ No newline at end of file +ClusterMasterNotExist: "集群主节点失联,请删除子节点" + +#ssl +ErrReqFailed: "{{.name}} 请求失败: {{ .err }}" \ No newline at end of file diff --git a/core/init/router/proxy.go b/core/init/router/proxy.go index a05fada8a..c122f62ee 100644 --- a/core/init/router/proxy.go +++ b/core/init/router/proxy.go @@ -44,7 +44,7 @@ func Proxy() gin.HandlerFunc { apiReq := c.GetBool("API_AUTH") - if !apiReq && strings.HasPrefix(c.Request.URL.Path, "/api/v2/") && !checkSession(c) { + if !apiReq && strings.HasPrefix(c.Request.URL.Path, "/api/v2/") && !isLocalAPI(c.Request.URL.Path) && !checkSession(c) { data, _ := res.ErrorMsg.ReadFile("html/401.html") c.Data(401, "text/html; charset=utf-8", data) c.Abort() @@ -89,3 +89,7 @@ func checkSession(c *gin.Context) bool { _ = global.SESSION.Set(c, psession, httpsSetting.Value == constant.StatusEnable, lifeTime) return true } + +func isLocalAPI(urlPath string) bool { + return urlPath == "/api/v2/core/xpack/sync/ssl" +} diff --git a/frontend/src/components/drawer-pro/index.vue b/frontend/src/components/drawer-pro/index.vue index 07705d6c5..0a3138596 100644 --- a/frontend/src/components/drawer-pro/index.vue +++ b/frontend/src/components/drawer-pro/index.vue @@ -146,7 +146,11 @@ const handleClose = () => { }; const beforeClose = (done: () => void) => { - emit('beforeClose', done); + if (!props.confirmBeforeClose) { + done(); + } else { + emit('beforeClose', done); + } }; function toggleFullscreen() { diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 717ad3d55..02bcbdef1 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -2669,6 +2669,9 @@ const message = { customAcme: 'Custom ACME Service', customAcmeURL: 'ACME Service URL', baiduCloud: 'Baidu Cloud', + pushNode: 'Sync to Other Nodes', + pushNodeHelper: 'Push to selected nodes after application/renewal', + fromMaster: 'Master Node Push', }, firewall: { create: 'Create rule', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index f713cb1fd..e79d32c03 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -2582,6 +2582,9 @@ const message = { customAcme: 'カスタム ACME サービス', customAcmeURL: 'ACME サービス URL', baiduCloud: '百度クラウド', + pushNode: '他のノードに同期', + pushNodeHelper: '申請/更新後に選択したノードにプッシュ', + fromMaster: 'マスターノードからのプッシュ', }, firewall: { create: 'ルールを作成します', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 1c46fd8d3..f25b31baf 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -2535,6 +2535,9 @@ const message = { customAcme: '사용자 정의 ACME 서비스', customAcmeURL: 'ACME 서비스 URL', baiduCloud: '바이두 클라우드', + pushNode: '다른 노드에 동기화', + pushNodeHelper: '신청/갱신 후 선택한 노드로 푸시', + fromMaster: '마스터 노드에서 푸시', }, firewall: { create: '규칙 만들기', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index ef446f853..574951767 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -2642,6 +2642,9 @@ const message = { customAcme: 'Perkhidmatan ACME Tersuai', customAcmeURL: 'URL Perkhidmatan ACME', baiduCloud: 'Baidu Cloud', + pushNode: 'Segerakan ke Nod Lain', + pushNodeHelper: 'Tolak ke nod terpilih selepas permohonan/pembaharuan', + fromMaster: 'Tolak dari Nod Utama', }, firewall: { create: 'Buat peraturan', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index 45951ed0f..14807b088 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -2643,6 +2643,9 @@ const message = { customAcme: 'Serviço ACME Personalizado', customAcmeURL: 'URL do Serviço ACME', baiduCloud: 'Baidu Cloud', + pushNode: 'Sincronizar com Outros Nós', + pushNodeHelper: 'Enviar para os nós selecionados após a aplicação/renovação', + fromMaster: 'Envio do Nó Mestre', }, firewall: { create: 'Criar regra', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index dbee0e4f5..c5171cb42 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -2638,6 +2638,9 @@ const message = { customAcme: 'Пользовательская служба ACME', customAcmeURL: 'URL службы ACME', baiduCloud: 'Baidu Cloud', + pushNode: 'Синхронизация с другими узлами', + pushNodeHelper: 'Отправить на выбранные узлы после заявки/продления', + fromMaster: 'Отправка с главного узла', }, firewall: { create: 'Создать правило', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 1f6f33f6a..aea9a25bc 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -2702,6 +2702,9 @@ const message = { customAcme: 'Özel ACME Servisi', customAcmeURL: 'ACME Servis URL’si', baiduCloud: 'Baidu Cloud', + pushNode: 'Diğer Düğümlere Senkronize Et', + pushNodeHelper: 'Başvuru/yenilemeden sonra seçilen düğümlere gönder', + fromMaster: 'Ana Düğümden Gönder', }, firewall: { create: 'Kural oluştur', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 96a79504f..4176d12f9 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -2489,6 +2489,9 @@ const message = { customAcme: '自訂 ACME 服務', customAcmeURL: 'ACME 服務 URL', baiduCloud: '百度雲', + pushNode: '同步到其他節點', + pushNodeHelper: '申請/續期之後推送到選擇的節點', + fromMaster: '主節點推送', }, firewall: { create: '創建規則', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 314111e59..1bb0da1f1 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -2479,6 +2479,9 @@ const message = { customAcme: '自定义 ACME 服务', customAcmeURL: 'ACME 服务 URL', baiduCloud: '百度云', + pushNode: '同步到其他节点', + pushNodeHelper: '申请/续期之后推送到选择的节点', + fromMaster: '主节点推送', }, firewall: { create: '创建规则', diff --git a/frontend/src/utils/util.ts b/frontend/src/utils/util.ts index 97dddea2f..70cf13dbe 100644 --- a/frontend/src/utils/util.ts +++ b/frontend/src/utils/util.ts @@ -440,6 +440,8 @@ export function getProvider(provider: string): string { return 'HTTP'; case 'selfSigned': return i18n.global.t('ssl.selfSigned'); + case 'fromMaster': + return i18n.global.t('ssl.fromMaster'); default: return i18n.global.t('ssl.manualCreate'); } diff --git a/frontend/src/views/ai/model/del/index.vue b/frontend/src/views/ai/model/del/index.vue index d50157857..bd2e5e2e8 100644 --- a/frontend/src/views/ai/model/del/index.vue +++ b/frontend/src/views/ai/model/del/index.vue @@ -39,7 +39,7 @@ import { deleteOllamaModel } from '@/api/modules/ai'; import i18n from '@/lang'; import { MsgSuccess } from '@/utils/message'; import { CheckboxValueType } from 'element-plus'; -import { onMounted, ref } from 'vue'; +import { ref } from 'vue'; defineOptions({ name: 'OpDialog' }); @@ -97,8 +97,6 @@ const handleClose = () => { open.value = false; }; -onMounted(() => {}); - defineExpose({ acceptParams, }); diff --git a/frontend/src/views/app-store/apps/index.vue b/frontend/src/views/app-store/apps/index.vue index 001b6509f..f8bb83f71 100644 --- a/frontend/src/views/app-store/apps/index.vue +++ b/frontend/src/views/app-store/apps/index.vue @@ -258,14 +258,6 @@ onMounted(async () => { padding-bottom: 10px; } -// .tag-button { -// margin-right: 10px; -// &.no-active { -// background: none; -// border: none; -// } -// } - @media only screen and (min-width: 768px) and (max-width: 1200px) { .app-col-12 { max-width: 50%; diff --git a/frontend/src/views/website/ssl/create/index.vue b/frontend/src/views/website/ssl/create/index.vue index e97cd5ff5..4f8dd96db 100644 --- a/frontend/src/views/website/ssl/create/index.vue +++ b/frontend/src/views/website/ssl/create/index.vue @@ -94,28 +94,6 @@ - - - - - - - - - {{ $t('ssl.pushDirHelper') }} - - - - - - - - - {{ $t('ssl.shellHelper') }} - -
@@ -141,6 +119,35 @@ {{ $t('ssl.nameserverHelper') }} + + + + + + + + + {{ $t('ssl.pushDirHelper') }} + + + + + + + + + {{ $t('ssl.shellHelper') }} + + +