feat: support specified format on deployment to local/ssh

This commit is contained in:
Fu Diwei
2024-10-26 23:49:26 +08:00
parent e7870e2b05
commit adad5d86ba
13 changed files with 329 additions and 76 deletions

View File

@@ -2,12 +2,15 @@ package deployer
import (
"context"
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"strings"
"github.com/pocketbase/pocketbase/models"
"software.sslmate.com/src/go-pkcs12"
"github.com/usual2970/certimate/internal/applicant"
"github.com/usual2970/certimate/internal/domain"
@@ -180,3 +183,32 @@ func getDeployVariables(conf domain.DeployConfig) map[string]string {
return rs
}
func convertPemToPfx(certificate string, privateKey string, password string) ([]byte, error) {
// TODO: refactor
certBlock, _ := pem.Decode([]byte(certificate))
if certBlock == nil {
return nil, fmt.Errorf("failed to decode pem")
}
cert, err := x509.ParseCertificate(certBlock.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse pem: %w", err)
}
privkeyBlock, _ := pem.Decode([]byte(privateKey))
if privkeyBlock == nil {
return nil, fmt.Errorf("failed to decode pem")
}
privkey, err := x509.ParsePKCS1PrivateKey(privkeyBlock.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse pem: %w", err)
}
pfxData, err := pkcs12.LegacyRC2.Encode(privkey, cert, nil, password)
if err != nil {
return nil, fmt.Errorf("failed to encode as pfx %w", err)
}
return pfxData, nil
}

View File

@@ -51,10 +51,6 @@ func (d *LocalDeployer) Deploy(ctx context.Context) error {
// 写入证书和私钥文件
switch d.option.DeployConfig.GetConfigOrDefaultAsString("format", "pem") {
case "pfx":
// TODO: pfx
return fmt.Errorf("not implemented")
case "pem":
if err := fs.WriteFileString(d.option.DeployConfig.GetConfigAsString("certPath"), d.option.Certificate.Certificate); err != nil {
return fmt.Errorf("failed to save certificate file: %w", err)
@@ -67,6 +63,18 @@ func (d *LocalDeployer) Deploy(ctx context.Context) error {
}
d.infos = append(d.infos, toStr("保存私钥成功", nil))
case "pfx":
pfxData, err := convertPemToPfx(d.option.Certificate.Certificate, d.option.Certificate.PrivateKey, d.option.DeployConfig.GetConfigAsString("pfxPassword"))
if err != nil {
return fmt.Errorf("failed to convert pem to pfx %w", err)
}
if err := fs.WriteFile(d.option.DeployConfig.GetConfigAsString("certPath"), pfxData); err != nil {
return fmt.Errorf("failed to save certificate file: %w", err)
}
d.infos = append(d.infos, toStr("保存证书成功", nil))
}
// 执行命令
@@ -87,15 +95,15 @@ func (d *LocalDeployer) execCommand(command string) (string, string, error) {
var cmd *exec.Cmd
switch d.option.DeployConfig.GetConfigAsString("shell") {
case "sh":
cmd = exec.Command("sh", "-c", command)
case "cmd":
cmd = exec.Command("cmd", "/C", command)
case "powershell":
cmd = exec.Command("powershell", "-Command", command)
case "sh":
cmd = exec.Command("sh", "-c", command)
case "":
if runtime.GOOS == "windows" {
cmd = exec.Command("cmd", "/C", command)

View File

@@ -60,20 +60,34 @@ func (d *SSHDeployer) Deploy(ctx context.Context) error {
d.infos = append(d.infos, toStr("SSH 执行前置命令成功", stdout))
}
// 上传证书
if err := d.uploadFile(client, d.option.Certificate.Certificate, d.option.DeployConfig.GetConfigAsString("certPath")); err != nil {
return fmt.Errorf("failed to upload certificate file: %w", err)
// 上传证书和私钥文件
switch d.option.DeployConfig.GetConfigOrDefaultAsString("format", "pem") {
case "pem":
if err := d.writeSftpFileString(client, d.option.DeployConfig.GetConfigAsString("certPath"), d.option.Certificate.Certificate); err != nil {
return fmt.Errorf("failed to upload certificate file: %w", err)
}
d.infos = append(d.infos, toStr("SSH 上传证书成功", nil))
if err := d.writeSftpFileString(client, d.option.DeployConfig.GetConfigAsString("keyPath"), d.option.Certificate.PrivateKey); err != nil {
return fmt.Errorf("failed to upload private key file: %w", err)
}
d.infos = append(d.infos, toStr("SSH 上传私钥成功", nil))
case "pfx":
pfxData, err := convertPemToPfx(d.option.Certificate.Certificate, d.option.Certificate.PrivateKey, d.option.DeployConfig.GetConfigAsString("pfxPassword"))
if err != nil {
return fmt.Errorf("failed to convert pem to pfx %w", err)
}
if err := d.writeSftpFile(client, d.option.DeployConfig.GetConfigAsString("certPath"), pfxData); err != nil {
return fmt.Errorf("failed to upload certificate file: %w", err)
}
d.infos = append(d.infos, toStr("SSH 上传证书成功", nil))
}
d.infos = append(d.infos, toStr("SSH 上传证书成功", nil))
// 上传私钥
if err := d.uploadFile(client, d.option.Certificate.PrivateKey, d.option.DeployConfig.GetConfigAsString("keyPath")); err != nil {
return fmt.Errorf("failed to upload private key file: %w", err)
}
d.infos = append(d.infos, toStr("SSH 上传私钥成功", nil))
// 执行命令
command := d.option.DeployConfig.GetConfigAsString("command")
if command != "" {
@@ -133,7 +147,11 @@ func (d *SSHDeployer) sshExecCommand(client *ssh.Client, command string) (string
return stdoutBuf.String(), stderrBuf.String(), err
}
func (d *SSHDeployer) uploadFile(client *ssh.Client, path string, content string) error {
func (d *SSHDeployer) writeSftpFileString(client *ssh.Client, path string, content string) error {
return d.writeSftpFile(client, path, []byte(content))
}
func (d *SSHDeployer) writeSftpFile(client *ssh.Client, path string, data []byte) error {
sftpCli, err := sftp.NewClient(client)
if err != nil {
return fmt.Errorf("failed to create sftp client: %w", err)
@@ -150,7 +168,7 @@ func (d *SSHDeployer) uploadFile(client *ssh.Client, path string, content string
}
defer file.Close()
_, err = file.Write([]byte(content))
_, err = file.Write(data)
if err != nil {
return fmt.Errorf("failed to write to remote file: %w", err)
}