diff --git a/agent/app/service/website_ca.go b/agent/app/service/website_ca.go index 3bf050544..c7c7391a9 100644 --- a/agent/app/service/website_ca.go +++ b/agent/app/service/website_ca.go @@ -212,10 +212,17 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website websiteSSL.Shell = req.Shell } if req.PushDir { - if !files.NewFileOp().Stat(req.Dir) { + dirs := certificateDirectories(req.Dir) + if len(dirs) == 0 { return nil, buserr.New("ErrLinkPathNotFound") } - websiteSSL.Dir = req.Dir + for _, dir := range dirs { + info, err := os.Stat(dir) + if err != nil || !info.IsDir() { + return nil, buserr.New("ErrLinkPathNotFound") + } + } + websiteSSL.Dir = strings.Join(dirs, "\n") } if req.Domains != "" { domainArray := strings.Split(req.Domains, "\n") @@ -348,7 +355,9 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website if websiteSSL.ExecShell { workDir := global.Dir.DataDir if websiteSSL.PushDir { - workDir = websiteSSL.Dir + if dirs := certificateDirectories(websiteSSL.Dir); len(dirs) > 0 { + workDir = dirs[0] + } } logger.Println(i18n.GetMsgByKey("ExecShellStart")) if err = runShellScriptFile(workDir, websiteSSL.Shell, logger); err != nil { diff --git a/agent/app/service/website_ssl.go b/agent/app/service/website_ssl.go index f90628fc5..29b0dc838 100644 --- a/agent/app/service/website_ssl.go +++ b/agent/app/service/website_ssl.go @@ -209,11 +209,17 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs websiteSSL.Shell = create.Shell } if create.PushDir { - fileOP := files.NewFileOp() - if !fileOP.Stat(create.Dir) { + dirs := certificateDirectories(create.Dir) + if len(dirs) == 0 { return res, buserr.New("ErrLinkPathNotFound") } - websiteSSL.Dir = create.Dir + for _, dir := range dirs { + info, err := os.Stat(dir) + if err != nil || !info.IsDir() { + return res, buserr.New("ErrLinkPathNotFound") + } + } + websiteSSL.Dir = strings.Join(dirs, "\n") } setSSLPushConfig(&websiteSSL, create.PushNode, create.Nodes) @@ -573,7 +579,9 @@ func (w WebsiteSSLService) obtainSSL(id uint, autoRenew bool) error { if websiteSSL.ExecShell { workDir := global.Dir.DataDir if websiteSSL.PushDir { - workDir = websiteSSL.Dir + if dirs := certificateDirectories(websiteSSL.Dir); len(dirs) > 0 { + workDir = dirs[0] + } } printSSLLog(logger, "ExecShellStart", nil) if err = runShellScriptFile(workDir, websiteSSL.Shell, logger); err != nil { @@ -793,11 +801,16 @@ func (w WebsiteSSLService) Update(update request.WebsiteSSLUpdate) error { } if update.PushDir { - fileOP := files.NewFileOp() - if !fileOP.Stat(update.Dir) { - _ = fileOP.CreateDir(update.Dir, constant.DirPerm) + dirs := certificateDirectories(update.Dir) + if len(dirs) == 0 { + return buserr.New("ErrLinkPathNotFound") } - updateParams["dir"] = update.Dir + for _, dir := range dirs { + if err := os.MkdirAll(dir, constant.DirPerm); err != nil { + return err + } + } + updateParams["dir"] = strings.Join(dirs, "\n") } var domains []string if update.OtherDomains != "" { diff --git a/agent/app/service/website_utils.go b/agent/app/service/website_utils.go index 7153fe6f6..65b3107f3 100644 --- a/agent/app/service/website_utils.go +++ b/agent/app/service/website_utils.go @@ -1529,26 +1529,41 @@ func checkWebsitePort(defaultHTTPsPort, port int, websiteType string) error { return nil } +// certificateDirectories accepts both legacy single paths and newline-separated paths. +func certificateDirectories(value string) []string { + var dirs []string + seen := make(map[string]bool) + for _, dir := range strings.Split(value, "\n") { + dir = strings.TrimSpace(dir) + if dir == "" { + continue + } + dir = filepath.Clean(dir) + if !seen[dir] { + seen[dir] = true + dirs = append(dirs, dir) + } + } + return dirs +} + func saveCertificateFile(websiteSSL *model.WebsiteSSL, logger *log.Logger) { - if websiteSSL.PushDir { - fileOp := files.NewFileOp() - var ( - pushErr error - MsgMap = map[string]interface{}{"path": websiteSSL.Dir, "status": i18n.GetMsgByKey("Success")} - ) - if pushErr = fileOp.SaveFile(path.Join(websiteSSL.Dir, "privkey.pem"), websiteSSL.PrivateKey, constant.FilePerm); pushErr != nil { - MsgMap["status"] = i18n.GetMsgByKey("Failed") - logger.Println(i18n.GetMsgWithMap("PushDirLog", MsgMap)) - logger.Println("Push dir failed:" + pushErr.Error()) - } - if pushErr = fileOp.SaveFile(path.Join(websiteSSL.Dir, "fullchain.pem"), websiteSSL.Pem, constant.FilePerm); pushErr != nil { - MsgMap["status"] = i18n.GetMsgByKey("Failed") - logger.Println(i18n.GetMsgWithMap("PushDirLog", MsgMap)) - logger.Println("Push dir failed:" + pushErr.Error()) - } - if pushErr == nil { - logger.Println(i18n.GetMsgWithMap("PushDirLog", MsgMap)) + if !websiteSSL.PushDir { + return + } + fileOp := files.NewFileOp() + for _, dir := range certificateDirectories(websiteSSL.Dir) { + status := i18n.GetMsgByKey("Success") + for _, file := range []struct{ name, content string }{ + {"privkey.pem", websiteSSL.PrivateKey}, + {"fullchain.pem", websiteSSL.Pem}, + } { + if err := fileOp.SaveFile(path.Join(dir, file.name), file.content, constant.FilePerm); err != nil { + status = i18n.GetMsgByKey("Failed") + logger.Printf("Push dir %s failed: %s", dir, err) + } } + logger.Println(i18n.GetMsgWithMap("PushDirLog", map[string]interface{}{"path": dir, "status": status})) } } diff --git a/frontend/src/components/file-list/index.vue b/frontend/src/components/file-list/index.vue index 0d2b69b40..8017de8aa 100644 --- a/frontend/src/components/file-list/index.vue +++ b/frontend/src/components/file-list/index.vue @@ -79,6 +79,16 @@ @row-click="handleRowClick" class="cursor-pointer dialog-file-list" > + + + + + + + {{ req.path }} + {{ $t('file.currentSelect') }} @@ -163,7 +180,11 @@ {{ $t('commons.button.cancel') }} - + {{ $t('commons.button.confirm') }} @@ -174,7 +195,7 @@