diff --git a/agent/app/api/v2/nginx.go b/agent/app/api/v2/nginx.go index 051de488e..e9b5f2e4c 100644 --- a/agent/app/api/v2/nginx.go +++ b/agent/app/api/v2/nginx.go @@ -161,13 +161,13 @@ func (b *BaseApi) GetNginxModules(c *gin.Context) { // @Tags OpenResty // @Summary Operate default HTTPs // @Accept json -// @Param request body request.NginxOperateReq true "request" +// @Param request body request.NginxDefaultHTTPSUpdate true "request" // @Success 200 // @Security ApiKeyAuth // @Security Timestamp // @Router /openresty/https [post] func (b *BaseApi) OperateDefaultHTTPs(c *gin.Context) { - var req request.NginxOperateReq + var req request.NginxDefaultHTTPSUpdate if err := helper.CheckBindAndValidate(&req, c); err != nil { return } diff --git a/agent/app/dto/request/nginx.go b/agent/app/dto/request/nginx.go index c8c8e9cae..7c70613b9 100644 --- a/agent/app/dto/request/nginx.go +++ b/agent/app/dto/request/nginx.go @@ -130,3 +130,8 @@ type NginxModuleUpdate struct { type NginxOperateReq struct { Operate string `json:"operate" validate:"required,oneof=enable disable"` } + +type NginxDefaultHTTPSUpdate struct { + Operate string `json:"operate" validate:"required,oneof=enable disable"` + SSLRejectHandshake bool `json:"sslRejectHandshake"` +} diff --git a/agent/app/dto/response/nginx.go b/agent/app/dto/response/nginx.go index 68a9b74b3..1e0b0e0a9 100644 --- a/agent/app/dto/response/nginx.go +++ b/agent/app/dto/response/nginx.go @@ -82,5 +82,6 @@ type NginxBuildConfig struct { } type NginxConfigRes struct { - Https bool `json:"https"` + Https bool `json:"https"` + SSLRejectHandshake bool `json:"sslRejectHandshake"` } diff --git a/agent/app/service/app_utils.go b/agent/app/service/app_utils.go index 697207fef..608ac45dd 100644 --- a/agent/app/service/app_utils.go +++ b/agent/app/service/app_utils.go @@ -1997,7 +1997,7 @@ func handleOpenrestyFile(appInstall *model.AppInstall) error { break } } - if err := handleSSLConfig(appInstall, hasDefaultWebsite); err != nil { + if err := handleSSLConfig(appInstall, hasDefaultWebsite, true); err != nil { return err } if len(websites) == 0 { @@ -2026,34 +2026,37 @@ func handleDefaultServer(appInstall *model.AppInstall) error { return nil } -func handleSSLConfig(appInstall *model.AppInstall, hasDefaultWebsite bool) error { +func handleSSLConfig(appInstall *model.AppInstall, hasDefaultWebsite bool, sslRejectHandshake bool) error { sslDir := path.Join(appInstall.GetPath(), "conf", "ssl") fileOp := files.NewFileOp() if !fileOp.Stat(sslDir) { return errors.New("ssl dir not found") } - ca, _ := websiteCARepo.GetFirst(repo.WithByName("1Panel")) - if ca.ID == 0 { - global.LOG.Errorf("create openresty default ssl failed ca not found") - return nil + hasDefaultSSL := fileOp.Stat(path.Join(sslDir, "fullchain.pem")) && fileOp.Stat(path.Join(sslDir, "privkey.pem")) && fileOp.Stat(path.Join(sslDir, "root_ssl.conf")) + if !hasDefaultSSL { + ca, _ := websiteCARepo.GetFirst(repo.WithByName("1Panel")) + if ca.ID == 0 { + global.LOG.Errorf("create openresty default ssl failed ca not found") + return nil + } + caService := NewIWebsiteCAService() + caRequest := request.WebsiteCAObtain{ + ID: ca.ID, + Domains: "localhost", + KeyType: "4096", + Time: 99, + Unit: "year", + Dir: sslDir, + PushDir: true, + } + websiteSSL, err := caService.ObtainSSL(caRequest) + if err != nil { + return err + } + defer func() { + _ = NewIWebsiteSSLService().Delete([]uint{websiteSSL.ID}) + }() } - caService := NewIWebsiteCAService() - caRequest := request.WebsiteCAObtain{ - ID: ca.ID, - Domains: "localhost", - KeyType: "4096", - Time: 99, - Unit: "year", - Dir: sslDir, - PushDir: true, - } - websiteSSL, err := caService.ObtainSSL(caRequest) - if err != nil { - return err - } - defer func() { - _ = NewIWebsiteSSLService().Delete([]uint{websiteSSL.ID}) - }() defaultConfigPath := path.Join(appInstall.GetPath(), "conf", "default", "00.default.conf") content, err := os.ReadFile(defaultConfigPath) if err != nil { @@ -2068,6 +2071,11 @@ func handleSSLConfig(appInstall *model.AppInstall, hasDefaultWebsite bool) error updateDefaultServer(defaultServer, appInstall.HttpPort, appInstall.HttpsPort, !hasDefaultWebsite, true) defaultServer.UpdateDirective("include", []string{"/usr/local/openresty/nginx/conf/ssl/root_ssl.conf"}) defaultServer.UpdateDirective("http2", []string{"on"}) + if sslRejectHandshake { + defaultServer.UpdateDirective("ssl_reject_handshake", []string{"on"}) + } else { + defaultServer.RemoveDirective("ssl_reject_handshake", []string{}) + } if err = nginx.WriteConfig(defaultConfig, nginx.IndentedStyle); err != nil { return err } diff --git a/agent/app/service/nginx.go b/agent/app/service/nginx.go index dbe1a9b35..eb425bd55 100644 --- a/agent/app/service/nginx.go +++ b/agent/app/service/nginx.go @@ -45,7 +45,7 @@ type INginxService interface { GetModules() (*response.NginxBuildConfig, error) UpdateModule(req request.NginxModuleUpdate) error - OperateDefaultHTTPs(req request.NginxOperateReq) error + OperateDefaultHTTPs(req request.NginxDefaultHTTPSUpdate) error GetDefaultHttpsStatus() (*response.NginxConfigRes, error) } @@ -354,7 +354,7 @@ func (n NginxService) UpdateModule(req request.NginxModuleUpdate) error { return fileOp.SaveFileWithByte(moduleConfigPath, moduleByte, constant.DirPerm) } -func (n NginxService) OperateDefaultHTTPs(req request.NginxOperateReq) error { +func (n NginxService) OperateDefaultHTTPs(req request.NginxDefaultHTTPSUpdate) error { appInstall, err := getAppInstallByKey(constant.AppOpenresty) if err != nil { return err @@ -372,11 +372,18 @@ func (n NginxService) OperateDefaultHTTPs(req request.NginxOperateReq) error { if err != nil { return err } - if req.Operate == "enable" { - if err := handleSSLConfig(&appInstall, hasDefaultWebsite); err != nil { + switch req.Operate { + case "enable": + if req.SSLRejectHandshake { + defaultWebsite, _ := websiteRepo.GetFirst(websiteRepo.WithDefaultServer()) + if defaultWebsite.ID > 0 { + return buserr.New("ErrDefaultWebsite") + } + } + if err := handleSSLConfig(&appInstall, hasDefaultWebsite, req.SSLRejectHandshake); err != nil { return err } - } else if req.Operate == "disable" { + case "disable": defaultConfig, err := parser.NewStringParser(string(content)).Parse() if err != nil { return err @@ -387,6 +394,7 @@ func (n NginxService) OperateDefaultHTTPs(req request.NginxOperateReq) error { defaultServer.RemoveListen(fmt.Sprintf("[::]:%d", appInstall.HttpsPort)) defaultServer.RemoveDirective("include", []string{"/usr/local/openresty/nginx/conf/ssl/root_ssl.conf"}) defaultServer.RemoveDirective("http2", []string{"on"}) + defaultServer.RemoveDirective("ssl_reject_handshake", []string{"on"}) if err = nginx.WriteConfig(defaultConfig, nginx.IndentedStyle); err != nil { return err } @@ -413,9 +421,11 @@ func (n NginxService) GetDefaultHttpsStatus() (*response.NginxConfigRes, error) res := &response.NginxConfigRes{} for _, directive := range defaultServer.GetDirectives() { if directive.GetName() == "include" && directive.GetParameters()[0] == "/usr/local/openresty/nginx/conf/ssl/root_ssl.conf" { - return &response.NginxConfigRes{ - Https: true, - }, nil + res.Https = true + } + if directive.GetName() == "ssl_reject_handshake" && directive.GetParameters()[0] == "on" { + res.Https = true + res.SSLRejectHandshake = true } } return res, nil diff --git a/agent/app/service/nginx_utils.go b/agent/app/service/nginx_utils.go index ebb661149..3a77f5060 100644 --- a/agent/app/service/nginx_utils.go +++ b/agent/app/service/nginx_utils.go @@ -121,9 +121,11 @@ func updateDefaultServerConfig(enable bool) error { includeSSL := false for _, dir := range defaultServer.GetDirectives() { + if dir.GetName() == "ssl_reject_handshake" && dir.GetParameters()[0] == "on" { + defaultServer.RemoveDirective("ssl_reject_handshake", []string{"on"}) + } if dir.GetName() == "include" && dir.GetParameters()[0] == "/usr/local/openresty/nginx/conf/ssl/root_ssl.conf" { includeSSL = true - break } } updateDefaultServer(defaultServer, nginxInstall.HttpPort, nginxInstall.HttpsPort, enable, includeSSL) diff --git a/agent/i18n/lang/en.yaml b/agent/i18n/lang/en.yaml index b42da231c..755f773a4 100644 --- a/agent/i18n/lang/en.yaml +++ b/agent/i18n/lang/en.yaml @@ -147,6 +147,7 @@ Status: 'Status' start: 'Start' stop: 'Stop' delete: 'Delete' +ErrDefaultWebsite: 'Default website has been set, please cancel it before setting!' #ssl ErrSSLCannotDelete: 'The {{ .name }} certificate is being used by a website and cannot be deleted' diff --git a/agent/i18n/lang/es-ES.yaml b/agent/i18n/lang/es-ES.yaml index 2fca2fe29..f578f6e32 100644 --- a/agent/i18n/lang/es-ES.yaml +++ b/agent/i18n/lang/es-ES.yaml @@ -146,6 +146,7 @@ Status: 'Estado' start: 'Iniciar' stop: 'Detener' delete: 'Eliminar' +ErrDefaultWebsite: 'El sitio web predeterminado ya está configurado, ¡cancélelo antes de configurar!' #ssl ErrSSLCannotDelete: 'El certificado {{ .name }} está siendo utilizado por un sitio web y no puede eliminarse' diff --git a/agent/i18n/lang/ja.yaml b/agent/i18n/lang/ja.yaml index 68885a5c3..5114437ef 100644 --- a/agent/i18n/lang/ja.yaml +++ b/agent/i18n/lang/ja.yaml @@ -146,6 +146,7 @@ Status: 'ステータス' start: '開始' stop: '停止' delete: '削除' +ErrDefaultWebsite: 'デフォルト Web サイトが既に設定されています。設定する前にキャンセルしてください!' #ssl ErrSSLCannotDelete: '{{ .name }} 証明書は Web サイトで使用されているため、削除できません' diff --git a/agent/i18n/lang/ko.yaml b/agent/i18n/lang/ko.yaml index 14b89adce..0585ea1d2 100644 --- a/agent/i18n/lang/ko.yaml +++ b/agent/i18n/lang/ko.yaml @@ -147,6 +147,7 @@ Status: '상태' start: '시작' stop: '중지' delete: '삭제' +ErrDefaultWebsite: '기본 웹사이트가 이미 설정되었습니다. 설정하기 전에 취소하세요!' #SSL인증 ErrSSLCannotDelete: '{{ .name }} 인증서는 웹사이트에서 사용 중이므로 삭제할 수 없습니다.' diff --git a/agent/i18n/lang/ms.yaml b/agent/i18n/lang/ms.yaml index bbf4238bd..f1e53f407 100644 --- a/agent/i18n/lang/ms.yaml +++ b/agent/i18n/lang/ms.yaml @@ -150,6 +150,7 @@ Status: 'Status' start: 'Mulakan' stop: 'Berhenti' delete: 'Padam' +ErrDefaultWebsite: 'Laman web lalai telah ditetapkan, sila batalkan sebelum menetapkan!' #ssl ErrSSLCannotDelete: 'Sijil {{ .name }} sedang digunakan oleh tapak web dan tidak boleh dipadamkan' diff --git a/agent/i18n/lang/pt-BR.yaml b/agent/i18n/lang/pt-BR.yaml index 90f1cea01..8c4dc918f 100644 --- a/agent/i18n/lang/pt-BR.yaml +++ b/agent/i18n/lang/pt-BR.yaml @@ -150,6 +150,7 @@ Status: 'Status' start: 'Iniciar' stop: 'Parar' delete: 'Excluir' +ErrDefaultWebsite: 'O site padrão já foi definido, cancele-o antes de definir!' #ssl ErrSSLCannotDelete: 'O certificado {{ .name }} está sendo usado por um site e não pode ser excluído' diff --git a/agent/i18n/lang/ru.yaml b/agent/i18n/lang/ru.yaml index 7dd2c2fd6..9bc621867 100644 --- a/agent/i18n/lang/ru.yaml +++ b/agent/i18n/lang/ru.yaml @@ -150,6 +150,7 @@ Status: 'Статус' start: 'Запустить' stop: 'Остановить' delete: 'Удалить' +ErrDefaultWebsite: 'Веб-сайт по умолчанию уже установлен, отмените его перед настройкой!' #ssl ErrSSLCannotDelete: 'Сертификат {{ .name }} используется веб-сайтом и не может быть удален' diff --git a/agent/i18n/lang/zh-Hant.yaml b/agent/i18n/lang/zh-Hant.yaml index 78fb5a5d9..9e554a4ee 100644 --- a/agent/i18n/lang/zh-Hant.yaml +++ b/agent/i18n/lang/zh-Hant.yaml @@ -146,6 +146,7 @@ Status: '狀態' start: '開啟' stop: '關閉' delete: '刪除' +ErrDefaultWebsite: '已經設置默認網站,請取消後再設置!' #ssl ErrSSLCannotDelete: '{{ .name }} 憑證正在被網站使用,無法刪除' diff --git a/agent/i18n/lang/zh.yaml b/agent/i18n/lang/zh.yaml index 106bb6ab4..9dbb00b0b 100644 --- a/agent/i18n/lang/zh.yaml +++ b/agent/i18n/lang/zh.yaml @@ -146,6 +146,7 @@ Status: '状态' start: '开启' stop: '关闭' delete: '删除' +ErrDefaultWebsite: "已经设置默认网站,请取消后再设置!" #ssl ErrSSLCannotDelete: "{{ .name }} 证书正在被网站使用,无法删除" diff --git a/frontend/src/api/interface/nginx.ts b/frontend/src/api/interface/nginx.ts index 554983eb8..0a1b6d48a 100644 --- a/frontend/src/api/interface/nginx.ts +++ b/frontend/src/api/interface/nginx.ts @@ -53,9 +53,14 @@ export namespace Nginx { export interface NginxHttpsStatus { https: boolean; + sslRejectHandshake: boolean; } export interface NginxOperateReq { operate: string; } + + export interface NginxHttpsOperateReq extends NginxOperateReq { + sslRejectHandshake: boolean; + } } diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index b9911c75d..26159509d 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -2731,6 +2731,9 @@ const message = { 'Click build after adding/modifying a module. OpenResty will automatically restart upon successful build.', defaultHttps: 'HTTPS Anti-tampering', defaultHttpsHelper1: 'Enabling this can resolve HTTPS tampering issues.', + sslRejectHandshake: 'Reject default SSL handshake', + sslRejectHandshakeHelper: + 'Enabling this can avoid certificate leakage, setting a default website will invalidate this setting', }, ssl: { create: 'Request', diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts index 594466957..bea30a879 100644 --- a/frontend/src/lang/modules/es-es.ts +++ b/frontend/src/lang/modules/es-es.ts @@ -2709,6 +2709,9 @@ const message = { 'Haz clic en compilar después de agregar/modificar un módulo. OpenResty se reiniciará automáticamente tras una compilación exitosa.', defaultHttps: 'HTTPS Anti-manipulación', defaultHttpsHelper1: 'Habilitar esto puede resolver problemas de manipulación de HTTPS.', + sslRejectHandshake: 'Rechazar handshake SSL predeterminado', + sslRejectHandshakeHelper: + 'Habilitar esto puede evitar la fuga de certificados, establecer un sitio web predeterminado invalidará esta configuración', }, ssl: { create: 'Solicitar', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index 2f999e223..3c08fa667 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -2648,6 +2648,9 @@ const message = { 'モジュールの追加/変更後にビルドをクリックします。ビルドが成功すると、OpenRestyは自動的に再起動します。', defaultHttps: 'HTTPS 改ざん防止', defaultHttpsHelper1: 'これを有効にすると、HTTPS 改ざん問題を解決できます。', + sslRejectHandshake: 'デフォルト SSL ハンドシェイクを拒否', + sslRejectHandshakeHelper: + '有効にすると証明書の漏洩を防げますが、デフォルト Web サイトを設定するとこの設定は無効になります', }, ssl: { create: 'リクエスト', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 9628b7a71..4fd8d4b80 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -2600,6 +2600,9 @@ const message = { buildHelper: '모듈 추가/수정 후 빌드를 클릭하세요. 빌드가 성공하면 OpenResty가 자동으로 재시작됩니다.', defaultHttps: 'HTTPS 변조 방지', defaultHttpsHelper1: '이를 활성화하면 HTTPS 변조 문제를 해결할 수 있습니다.', + sslRejectHandshake: '기본 SSL 핸드셰이크 거부', + sslRejectHandshakeHelper: + '활성화하면 인증서 누출을 방지할 수 있지만, 기본 웹사이트를 설정하면 이 설정이 무효화됩니다', }, ssl: { create: '요청', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 78f3bcb2d..f2a5924a2 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -2711,6 +2711,9 @@ const message = { 'Klik Bina selepas menambah/mengubah suai modul. Pembinaan yang berjaya akan memulakan semula OpenResty secara automatik.', defaultHttps: 'HTTPS Anti-tampering', defaultHttpsHelper1: 'Mengaktifkan ini dapat menyelesaikan masalah tampering HTTPS.', + sslRejectHandshake: 'Tolak jabat tangan SSL lalai', + sslRejectHandshakeHelper: + 'Mengaktifkan ini boleh mengelakkan kebocoran sijil, menetapkan laman web lalai akan membatalkan tetapan ini', }, ssl: { create: 'Permintaan', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index 7d8aa05f3..e369e590b 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -2715,6 +2715,9 @@ const message = { 'Clique em Construir após adicionar/modificar um módulo. Construção bem-sucedida reiniciará automaticamente o OpenResty.', defaultHttps: 'HTTPS Anti-tampering', defaultHttpsHelper1: 'A ativação desta opção pode resolver problemas de adulteração HTTPS.', + sslRejectHandshake: 'Rejeitar handshake SSL padrão', + sslRejectHandshakeHelper: + 'Ativar isso pode evitar vazamento de certificados, definir um site padrão invalidará esta configuração', }, ssl: { create: 'Solicitar', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index b64a0a69f..e9316df41 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -2712,6 +2712,9 @@ const message = { 'Нажмите Сборка после добавления/изменения модуля. Успешная сборка автоматически перезапустит OpenResty.', defaultHttps: 'HTTPS Анти-вмешательство', defaultHttpsHelper1: 'Включение этого параметра может решить проблему вмешательства в HTTPS.', + sslRejectHandshake: 'Отклонить стандартное SSL-рукопожатие', + sslRejectHandshakeHelper: + 'Включение этого может предотвратить утечку сертификатов, установка веб-сайта по умолчанию сделает эту настройку недействительной', }, ssl: { create: 'Запросить', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 9ed2cda79..d2a3e7633 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -2768,6 +2768,9 @@ const message = { 'Modül ekledikten/düzenledikten sonra oluştur’a tıklayın. OpenResty, başarılı oluşturma üzerine otomatik olarak yeniden başlatılacaktır.', defaultHttps: 'HTTPS Anti-sızdırma', defaultHttpsHelper1: 'Bu özelliği etkinleştirerek HTTPS sızdırma sorunlarını çözebilirsiniz.', + sslRejectHandshake: 'Varsayılan SSL el sıkışmasını reddet', + sslRejectHandshakeHelper: + 'Etkinleştirilmesi sertifika sızıntısını önleyebilir, varsayılan bir web sitesi ayarlamak bu ayarı geçersiz kılar', }, ssl: { create: 'İstek', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 952a3b993..1912ff9fc 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -2540,6 +2540,8 @@ const message = { buildHelper: '新增/修改模組後點擊構建,構建成功後會自動重啟 OpenResty', defaultHttps: 'HTTPS 防竄站', defaultHttpsHelper1: '開啟後可以解決 HTTPS 竄站問題', + sslRejectHandshake: '拒絕默認 SSL 握手', + sslRejectHandshakeHelper: '開啟之後可以避免證書洩露,設置默認網站會讓此設置失效', }, ssl: { create: '申請證書', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 6e902ce14..db6e48810 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -2532,6 +2532,8 @@ const message = { buildHelper: '添加/修改模块之后点击构建,构建成功后会自动重启 OpenResty', defaultHttps: 'HTTPS 防窜站', defaultHttpsHelper1: '开启后可以解决 HTTPS 窜站问题', + sslRejectHandshake: '拒绝默认 SSL 握手', + sslRejectHandshakeHelper: '开启之后可以避免证书泄露,设置默认网站会让此设置失效', }, ssl: { create: '申请证书', diff --git a/frontend/src/views/website/website/nginx/other/https/index.vue b/frontend/src/views/website/website/nginx/other/https/index.vue new file mode 100644 index 000000000..d4d3319cf --- /dev/null +++ b/frontend/src/views/website/website/nginx/other/https/index.vue @@ -0,0 +1,61 @@ + + + diff --git a/frontend/src/views/website/website/nginx/other/index.vue b/frontend/src/views/website/website/nginx/other/index.vue index 61f998428..95bbe442e 100644 --- a/frontend/src/views/website/website/nginx/other/index.vue +++ b/frontend/src/views/website/website/nginx/other/index.vue @@ -1,43 +1,15 @@