From 5ad2b9d63b587e8a7fec3d35dfd5eb510aa5b371 Mon Sep 17 00:00:00 2001 From: smail Date: Tue, 22 Sep 2026 06:33:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E7=BD=B2=E9=AA=8C?= =?UTF-8?q?=E6=94=B6=E5=9B=9E=E5=BD=92=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/config/ssl_flat.go | 27 ++++++++++++++++++-------- backend/config/ssl_retention.go | 34 ++++++++++++++++----------------- backend/config/transaction.go | 27 +++++++++++++++++++++++++- 3 files changed, 61 insertions(+), 27 deletions(-) diff --git a/backend/config/ssl_flat.go b/backend/config/ssl_flat.go index 34c2e78..a16e4cd 100644 --- a/backend/config/ssl_flat.go +++ b/backend/config/ssl_flat.go @@ -126,6 +126,22 @@ func retainPreviousSSL(root string, next *SSLConfig, previous SSLConfig) { } } +func removeFlatSSLFile(directory, path string) error { + info, err := os.Lstat(path) + if err != nil { + return err + } + if info.Mode()&os.ModeSymlink != 0 || !info.Mode().IsRegular() || hasMultipleFileLinks(path) { + return ErrUnsafeSSLFile + } + storage, err := os.OpenRoot(directory) + if err != nil { + return err + } + defer storage.Close() + return storage.Remove(filepath.Base(path)) +} + func pruneFlatSSLLocked(root string, protected []SSLConfig) error { // 当前材料不可用时暂停回收,避免丢失仍可恢复的历史证书。 if len(protected) == 0 { @@ -165,11 +181,6 @@ func pruneFlatSSLLocked(root string, protected []SSLConfig) error { keep[publicPath] = true } } - storage, err := os.OpenRoot(directory) - if err != nil { - return err - } - defer storage.Close() for _, entry := range entries { publicPath := filepath.Join(directory, entry.Name()) privatePath := strings.TrimSuffix(publicPath, ".crt") + ".key" @@ -189,7 +200,7 @@ func pruneFlatSSLLocked(root string, protected []SSLConfig) error { if err != nil { // 先删私钥、后删证书;中断留下的孤立证书可在下轮安全重试。 if _, statErr := os.Lstat(privatePath); os.IsNotExist(statErr) { - if err := storage.Remove(filepath.Base(publicPath)); err != nil { + if err := removeFlatSSLFile(directory, publicPath); err != nil { return err } } @@ -209,9 +220,9 @@ func pruneFlatSSLLocked(root string, protected []SSLConfig) error { } continue } - err = storage.Remove(filepath.Base(privatePath)) + err = removeFlatSSLFile(directory, privatePath) if err == nil { - err = storage.Remove(filepath.Base(publicPath)) + err = removeFlatSSLFile(directory, publicPath) } unlock() if err := errors.Join(err, lease.Close()); err != nil { diff --git a/backend/config/ssl_retention.go b/backend/config/ssl_retention.go index 9ed0e59..e1fc9da 100644 --- a/backend/config/ssl_retention.go +++ b/backend/config/ssl_retention.go @@ -149,28 +149,26 @@ func pruneManagedSSLLocked(root string, protected []SSLConfig) error { } // 磁盘引用也必须保留,避免其他管理器实例或已提交未发布的候选被删除。 configRoot, err := os.OpenRoot(filepath.Join(root, "config")) - if err != nil { - if os.IsNotExist(err) { - return nil - } - return err - } - data, err := configRoot.ReadFile("ssl.json") - _ = configRoot.Close() if err == nil { - var section SSLSectionConfig - if err := ParseStrict(data, §ion); err != nil { - return err - } - if section.TLS.CertificateRef != "" { - protected = append(protected, section.TLS) - reference, err := resolveManagedSSLPathsAtRoot(root, section.TLS) - if err != nil { + data, readErr := configRoot.ReadFile("ssl.json") + _ = configRoot.Close() + if readErr == nil { + var section SSLSectionConfig + if err := ParseStrict(data, §ion); err != nil { return err } - if legacyManagedSSLReference(section.TLS.CertificateRef) { - keep[filepath.Dir(reference.CertificatePath)] = true + if section.TLS.CertificateRef != "" { + protected = append(protected, section.TLS) + reference, err := resolveManagedSSLPathsAtRoot(root, section.TLS) + if err != nil { + return err + } + if legacyManagedSSLReference(section.TLS.CertificateRef) { + keep[filepath.Dir(reference.CertificatePath)] = true + } } + } else if !os.IsNotExist(readErr) { + return readErr } } else if !os.IsNotExist(err) { return err diff --git a/backend/config/transaction.go b/backend/config/transaction.go index cdf9163..b1bdf89 100644 --- a/backend/config/transaction.go +++ b/backend/config/transaction.go @@ -338,7 +338,7 @@ func (s *TransactionStore) Recover() error { return ErrTransactionPhase } } - return nil + return cleanupEmptyTransactionStaging(transactions) } func (s *TransactionStore) beforePhase(phase TransactionPhase) error { @@ -619,6 +619,31 @@ func secureTransactionStagingDirectory(transactions string) (string, error) { return directory, nil } +func cleanupEmptyTransactionStaging(transactions string) error { + directory := filepath.Join(filepath.Dir(transactions), "transaction-staging") + info, err := os.Lstat(directory) + if os.IsNotExist(err) { + return nil + } + if err != nil { + return err + } + if info.Mode()&os.ModeSymlink != 0 || !info.IsDir() { + return ErrTransactionInvalid + } + entries, err := os.ReadDir(directory) + if err != nil { + return err + } + if len(entries) != 0 { + return nil + } + if err := os.Remove(directory); err != nil { + return err + } + return atomicfile.SyncDirectory(filepath.Dir(transactions)) +} + func validateTransactionDirectory(directory string) error { if err := ensureDirectory(directory); err != nil { return err