101 lines
2.3 KiB
Go
101 lines
2.3 KiB
Go
package ssh
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mirivlad/sshkeeper/internal/model"
|
|
)
|
|
|
|
// GenerateConfig creates OpenSSH config content from server profiles
|
|
func GenerateConfig(servers []*model.Server) (string, error) {
|
|
var sb strings.Builder
|
|
|
|
sb.WriteString("# Generated by sshkeeper. Do not edit manually.\n")
|
|
sb.WriteString(fmt.Sprintf("# Generated at: %s\n\n", time.Now().Format(time.RFC3339)))
|
|
|
|
for _, s := range servers {
|
|
sb.WriteString(fmt.Sprintf("Host %s\n", s.Alias))
|
|
sb.WriteString(fmt.Sprintf(" HostName %s\n", s.Host))
|
|
if s.Port != 22 {
|
|
sb.WriteString(fmt.Sprintf(" Port %d\n", s.Port))
|
|
}
|
|
if s.User != "" {
|
|
sb.WriteString(fmt.Sprintf(" User %s\n", s.User))
|
|
}
|
|
if s.IdentityFile != "" && s.AuthMethod != model.AuthPassword {
|
|
sb.WriteString(fmt.Sprintf(" IdentityFile %s\n", s.IdentityFile))
|
|
}
|
|
if s.ProxyJump != "" {
|
|
sb.WriteString(fmt.Sprintf(" ProxyJump %s\n", s.ProxyJump))
|
|
}
|
|
sb.WriteString("\n")
|
|
}
|
|
|
|
return sb.String(), nil
|
|
}
|
|
|
|
// WriteConfig writes the generated config to ~/.ssh/config.d/sshkeeper.conf
|
|
func WriteConfig(servers []*model.Server) error {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
configD := home + "/.ssh/config.d"
|
|
if err := os.MkdirAll(configD, 0700); err != nil {
|
|
return err
|
|
}
|
|
|
|
content, err := GenerateConfig(servers)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
configFile := configD + "/sshkeeper.conf"
|
|
tmpFile := configFile + ".tmp"
|
|
|
|
if err := os.WriteFile(tmpFile, []byte(content), 0600); err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.Rename(tmpFile, configFile)
|
|
}
|
|
|
|
// InstallInclude adds "Include ~/.ssh/config.d/*.conf" to ~/.ssh/config
|
|
func InstallInclude() error {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sshDir := home + "/.ssh"
|
|
configD := sshDir + "/config.d"
|
|
mainConfig := sshDir + "/config"
|
|
|
|
if err := os.MkdirAll(configD, 0700); err != nil {
|
|
return err
|
|
}
|
|
|
|
includeLine := "Include ~/.ssh/config.d/*.conf"
|
|
|
|
// Check if already included
|
|
if data, err := os.ReadFile(mainConfig); err == nil {
|
|
if strings.Contains(string(data), "Include ~/.ssh/config.d") {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Prepend include line
|
|
f, err := os.OpenFile(mainConfig, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
_, err = f.WriteString("\n" + includeLine + "\n")
|
|
return err
|
|
}
|