mirror of
https://github.com/allinssl/allinssl.git
synced 2025-12-21 10:14:03 +08:00
Add files via upload
This commit is contained in:
163
backend/internal/cert/deploy/ssh.go
Normal file
163
backend/internal/cert/deploy/ssh.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/internal/access"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"path"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type SSHConfig struct {
|
||||
User string
|
||||
Password string // 可选
|
||||
PrivateKey string // 可选
|
||||
Host string
|
||||
Port string
|
||||
}
|
||||
|
||||
type RemoteFile struct {
|
||||
Path string
|
||||
Content string
|
||||
}
|
||||
|
||||
func buildAuthMethods(password, privateKey string) ([]ssh.AuthMethod, error) {
|
||||
var methods []ssh.AuthMethod
|
||||
|
||||
if privateKey != "" {
|
||||
signer, err := ssh.ParsePrivateKey([]byte(privateKey))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse private key: %v", err)
|
||||
}
|
||||
methods = append(methods, ssh.PublicKeys(signer))
|
||||
}
|
||||
|
||||
if password != "" {
|
||||
methods = append(methods, ssh.Password(password))
|
||||
}
|
||||
|
||||
if len(methods) == 0 {
|
||||
return nil, fmt.Errorf("no authentication methods provided")
|
||||
}
|
||||
|
||||
return methods, nil
|
||||
}
|
||||
|
||||
func writeMultipleFilesViaSSH(config SSHConfig, files []RemoteFile, preCmd, postCmd string) error {
|
||||
addr := fmt.Sprintf("%s:%s", config.Host, config.Port)
|
||||
|
||||
authMethods, err := buildAuthMethods(config.Password, config.PrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: config.User,
|
||||
Auth: authMethods,
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
}
|
||||
|
||||
client, err := ssh.Dial("tcp", addr, sshConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to dial: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
session, err := client.NewSession()
|
||||
if err != nil {
|
||||
return fmt.Errorf("会话创建失败: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
var script bytes.Buffer
|
||||
|
||||
if preCmd != "" {
|
||||
script.WriteString(preCmd + " && ")
|
||||
}
|
||||
|
||||
for i, file := range files {
|
||||
if i > 0 {
|
||||
script.WriteString(" && ")
|
||||
}
|
||||
|
||||
dirCmd := fmt.Sprintf("mkdir -p $(dirname %q)", file.Path)
|
||||
writeCmd := fmt.Sprintf("printf %%s '%s' > %s", file.Content, file.Path)
|
||||
|
||||
script.WriteString(dirCmd + " && " + writeCmd)
|
||||
}
|
||||
|
||||
if postCmd != "" {
|
||||
script.WriteString(" && " + postCmd)
|
||||
}
|
||||
|
||||
cmd := script.String()
|
||||
|
||||
if err := session.Run(cmd); err != nil {
|
||||
return fmt.Errorf("运行出错: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeploySSH(cfg map[string]any) error {
|
||||
cert, ok := cfg["certificate"].(map[string]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书不存在")
|
||||
}
|
||||
// 设置证书
|
||||
keyPem, ok := cert["key"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:key")
|
||||
}
|
||||
certPem, ok := cert["cert"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:cert")
|
||||
}
|
||||
var providerID string
|
||||
switch v := cfg["provider_id"].(type) {
|
||||
case float64:
|
||||
providerID = strconv.Itoa(int(v))
|
||||
case string:
|
||||
providerID = v
|
||||
default:
|
||||
return fmt.Errorf("参数错误:provider_id")
|
||||
}
|
||||
dir, ok := cfg["path"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:path")
|
||||
}
|
||||
beforeCmd, ok := cfg["beforeCmd"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:beforeCmd")
|
||||
}
|
||||
afterCmd, ok := cfg["afterCmd"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:afterCmd")
|
||||
}
|
||||
providerData, err := access.GetAccess(providerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerConfigStr, ok := providerData["config"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("api配置错误")
|
||||
}
|
||||
// 解析 JSON 配置
|
||||
var providerConfig SSHConfig
|
||||
err = json.Unmarshal([]byte(providerConfigStr), &providerConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 自动创建多级目录
|
||||
files := []RemoteFile{
|
||||
{Path: path.Join(dir, "cert.pem"), Content: certPem},
|
||||
{Path: path.Join(dir, "key.pem"), Content: keyPem},
|
||||
}
|
||||
err = writeMultipleFilesViaSSH(providerConfig, files, beforeCmd, afterCmd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("SSH 部署失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user