This commit is contained in:
Fu Diwei
2026-06-22 17:41:43 +08:00
committed by RHQYZ
parent 7ca2ef3112
commit e948ca5f79
6 changed files with 102 additions and 25 deletions
@@ -3,12 +3,15 @@ package internal
import (
"context"
"fmt"
"log/slog"
"path/filepath"
"github.com/go-acme/lego/v5/challenge"
"github.com/go-acme/lego/v5/challenge/http01"
"github.com/go-acme/lego/v5/log"
"github.com/certimate-go/certimate/internal/tools/ftp"
xfilepath "github.com/certimate-go/certimate/pkg/utils/filepath"
)
var _ challenge.Provider = (*HTTPProvider)(nil)
@@ -37,6 +40,10 @@ func NewHTTPProviderConfig(config *Config) (*HTTPProvider, error) {
return nil, fmt.Errorf("the configuration of the acme challenge provider is nil")
}
if config.WebRootPath == "" {
return nil, fmt.Errorf("ftp: webroot path must be set")
}
return &HTTPProvider{
config: config,
}, nil
@@ -48,10 +55,14 @@ func (p *HTTPProvider) Present(ctx context.Context, domain, token, keyAuth strin
return fmt.Errorf("ftp: failed to create FTP client: %w", err)
}
defer client.Quit()
log.Info("ftp: ftp connected")
defer func() {
client.Quit()
log.Info("ftp: ftp closed")
}()
challengePath := filepath.Join(p.config.WebRootPath, http01.ChallengePath(token))
challengeDir := filepath.Dir(challengePath)
challengePath := xfilepath.Join(p.config.WebRootPath, http01.ChallengePath(token))
challengeDir := xfilepath.Dir(challengePath)
challengeFile := filepath.Base(challengePath)
if err := client.MkdirAll(ctx, challengeDir); err != nil {
return fmt.Errorf("ftp: failed to create the \".well-known\" directory: %w", err)
@@ -63,6 +74,8 @@ func (p *HTTPProvider) Present(ctx context.Context, domain, token, keyAuth strin
return fmt.Errorf("ftp: failed to write file for HTTP challenge: %w", err)
}
log.Info("ftp: authz file uploaded", slog.String("path", challengePath))
return nil
}
@@ -72,10 +85,14 @@ func (p *HTTPProvider) CleanUp(ctx context.Context, domain, token, keyAuth strin
return fmt.Errorf("ftp: failed to create FTP client: %w", err)
}
defer client.Quit()
log.Info("ftp: ftp connected")
defer func() {
client.Quit()
log.Info("ftp: ftp closed")
}()
challengePath := filepath.Join(p.config.WebRootPath, http01.ChallengePath(token))
challengeDir := filepath.Dir(challengePath)
challengePath := xfilepath.Join(p.config.WebRootPath, http01.ChallengePath(token))
challengeDir := xfilepath.Dir(challengePath)
challengeFile := filepath.Base(challengePath)
if err := client.ChangeDir(ctx, challengeDir); err != nil {
return fmt.Errorf("ftp: failed to change to the \".well-known\" directory: %w", err)
@@ -84,6 +101,8 @@ func (p *HTTPProvider) CleanUp(ctx context.Context, domain, token, keyAuth strin
return fmt.Errorf("ftp: failed to remove file after HTTP challenge: %w", err)
}
log.Info("ftp: authz file removed", slog.String("path", challengePath))
return nil
}
@@ -18,6 +18,10 @@ func NewChallenger(config *ChallengerConfig) (core.ACMEChallenger, error) {
return nil, fmt.Errorf("the configuration of the acme challenge provider is nil")
}
if config.WebRootPath == "" {
return nil, fmt.Errorf("local: webroot path must be set")
}
provider, err := webroot.NewHTTPProvider(config.WebRootPath)
if err != nil {
return nil, err
@@ -3,10 +3,12 @@ package internal
import (
"context"
"fmt"
"log/slog"
"strings"
"github.com/go-acme/lego/v5/challenge"
"github.com/go-acme/lego/v5/challenge/http01"
"github.com/go-acme/lego/v5/log"
"github.com/certimate-go/certimate/internal/tools/s3"
)
@@ -52,6 +54,8 @@ func (p *HTTPProvider) Present(ctx context.Context, domain, token, keyAuth strin
return fmt.Errorf("s3: failed to upload file for HTTP challenge: %w", err)
}
log.Info("s3: authz file uploaded", slog.String("bucket", p.config.Bucket), slog.String("object", objectKey))
return nil
}
@@ -66,6 +70,8 @@ func (p *HTTPProvider) CleanUp(ctx context.Context, domain, token, keyAuth strin
return fmt.Errorf("s3: failed to remove file after HTTP challenge: %w", err)
}
log.Info("s3: authz file removed", slog.String("bucket", p.config.Bucket), slog.String("object", objectKey))
return nil
}
@@ -3,12 +3,14 @@ package internal
import (
"context"
"fmt"
"path/filepath"
"log/slog"
"github.com/go-acme/lego/v5/challenge"
"github.com/go-acme/lego/v5/challenge/http01"
"github.com/go-acme/lego/v5/log"
"github.com/certimate-go/certimate/internal/tools/ssh"
xfilepath "github.com/certimate-go/certimate/pkg/utils/filepath"
xssh "github.com/certimate-go/certimate/pkg/utils/ssh"
)
@@ -25,9 +27,8 @@ func NewDefaultConfig() *Config {
defaultCfg := ssh.NewDefaultConfig()
return &Config{
Config: *defaultCfg,
UseSCP: false,
WebRootPath: "/var/www/html",
Config: *defaultCfg,
UseSCP: false,
}
}
@@ -40,6 +41,10 @@ func NewHTTPProviderConfig(config *Config) (*HTTPProvider, error) {
return nil, fmt.Errorf("the configuration of the acme challenge provider is nil")
}
if config.WebRootPath == "" {
return nil, fmt.Errorf("ssh: webroot path must be set")
}
return &HTTPProvider{
config: config,
}, nil
@@ -51,13 +56,19 @@ func (p *HTTPProvider) Present(ctx context.Context, domain, token, keyAuth strin
return fmt.Errorf("ssh: failed to create SSH client: %w", err)
}
defer client.Close()
log.Info("ssh: ssh connected")
defer func() {
client.Close()
log.Info("ssh: ssh closed")
}()
challengePath := filepath.Join(p.config.WebRootPath, http01.ChallengePath(token))
challengePath := xfilepath.Join(p.config.WebRootPath, http01.ChallengePath(token))
if err := xssh.WriteRemoteString(client.RawClient(), challengePath, keyAuth, p.config.UseSCP); err != nil {
return fmt.Errorf("ssh: failed to write file for HTTP challenge: %w", err)
}
log.Info("ssh: authz file uploaded", slog.String("path", challengePath))
return nil
}
@@ -67,14 +78,20 @@ func (p *HTTPProvider) CleanUp(ctx context.Context, domain, token, keyAuth strin
return fmt.Errorf("ssh: failed to create SSH client: %w", err)
}
defer client.Close()
log.Info("ssh: ssh connected")
defer func() {
client.Close()
log.Info("ssh: ssh closed")
}()
// 删除质询文件
challengePath := filepath.Join(p.config.WebRootPath, http01.ChallengePath(token))
challengePath := xfilepath.Join(p.config.WebRootPath, http01.ChallengePath(token))
if err := xssh.RemoveRemote(client.RawClient(), challengePath, p.config.UseSCP); err != nil {
return fmt.Errorf("ssh: failed to remove file after HTTP challenge: %w", err)
}
log.Info("ssh: authz file removed", slog.String("path", challengePath))
return nil
}
@@ -65,6 +65,7 @@ func NewChallenger(config *ChallengerConfig) (core.ACMEChallenger, error) {
}
providerConfig.JumpServers = append(providerConfig.JumpServers, jumpServerCfg)
}
providerConfig.WebRootPath = config.WebRootPath
provider, err := internal.NewHTTPProviderConfig(providerConfig)
if err != nil {
+41 -11
View File
@@ -5,6 +5,11 @@ import (
"strings"
)
const (
separatorOnWindows = "\\"
separatorOnUnix = "/"
)
// 与标准库中的 [filepath.Dir] 类似,但会尝试保留原有的路径分隔符。
//
// 入参:
@@ -13,21 +18,46 @@ import (
// 出参:
// - 目录路径。
func Dir(path string) string {
const SEP_WIN = "\\"
const SEP_UNIX = "/"
sep := SEP_UNIX
if strings.Contains(path, SEP_WIN) && !strings.Contains(path, SEP_UNIX) {
sep = SEP_WIN
sep := string(stdfilepath.Separator)
if strings.Contains(path, separatorOnWindows) && !strings.Contains(path, separatorOnUnix) {
sep = separatorOnWindows
} else if strings.Contains(path, separatorOnUnix) && !strings.Contains(path, separatorOnWindows) {
sep = separatorOnUnix
}
dir := stdfilepath.Dir(path)
return normalizePath(sep, dir)
}
if sep != SEP_UNIX && strings.Contains(dir, SEP_UNIX) {
dir = strings.ReplaceAll(dir, SEP_UNIX, sep)
} else if sep != SEP_WIN && strings.Contains(dir, SEP_WIN) {
dir = strings.ReplaceAll(dir, SEP_WIN, sep)
// 与标准库中的 [filepath.Join] 类似,但会尝试保留原有的路径分隔符。
//
// 入参:
// - elem: 路径元素。
//
// 出参:
// - 连接后的路径。
func Join(elem ...string) string {
sep := string(stdfilepath.Separator)
for _, e := range elem {
if strings.Contains(e, separatorOnWindows) && !strings.Contains(e, separatorOnUnix) {
sep = separatorOnWindows
break
} else if strings.Contains(e, separatorOnUnix) && !strings.Contains(e, separatorOnWindows) {
sep = separatorOnUnix
break
}
}
return dir
path := stdfilepath.Join(elem...)
return normalizePath(sep, path)
}
func normalizePath(separator, path string) string {
if separator != separatorOnUnix && strings.Contains(path, separatorOnUnix) {
path = strings.ReplaceAll(path, separatorOnUnix, separator)
} else if separator != separatorOnWindows && strings.Contains(path, separatorOnWindows) {
path = strings.ReplaceAll(path, separatorOnWindows, separator)
}
return path
}