bitbot/bot/sshclient.go

186 lines
3.8 KiB
Go

package bot
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"os"
"strings"
"golang.org/x/crypto/ssh"
)
const (
privateKeyPath = "private_key.pem"
publicKeyPath = "public_key.pub"
bits = 2048
)
func GenerateAndSaveSSHKeyPairIfNotExist() error {
if KeyFilesExist(privateKeyPath, publicKeyPath) {
return nil
}
privateKey, publicKey, err := GenerateSSHKeyPair(bits)
if err != nil {
return err
}
err = SavePrivateKeyToFile(privateKeyPath, privateKey)
if err != nil {
return err
}
err = SavePublicKeyToFile(publicKeyPath, publicKey)
if err != nil {
return err
}
return nil
}
func GenerateAndSaveSSHKeyPair() error {
privateKey, publicKey, err := GenerateSSHKeyPair(bits)
if err != nil {
return err
}
err = SavePrivateKeyToFile(privateKeyPath, privateKey)
if err != nil {
return err
}
err = SavePublicKeyToFile(publicKeyPath, publicKey)
if err != nil {
return err
}
return nil
}
func KeyFilesExist(privateKeyPath, publicKeyPath string) bool {
_, privateKeyErr := os.Stat(privateKeyPath)
_, publicKeyErr := os.Stat(publicKeyPath)
return !os.IsNotExist(privateKeyErr) && !os.IsNotExist(publicKeyErr)
}
func GenerateSSHKeyPair(bits int) (*rsa.PrivateKey, ssh.PublicKey, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, nil, err
}
publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey)
if err != nil {
return nil, nil, err
}
return privateKey, publicKey, nil
}
func SavePrivateKeyToFile(filename string, privateKey *rsa.PrivateKey) error {
privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
privateKeyPEM := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privateKeyBytes,
}
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
err = pem.Encode(file, privateKeyPEM)
if err != nil {
return err
}
return nil
}
func SavePublicKeyToFile(filename string, publicKey ssh.PublicKey) error {
publicKeyBytes := ssh.MarshalAuthorizedKey(publicKey)
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString(string(publicKeyBytes))
if err != nil {
return err
}
return nil
}
func SSHConnectToRemoteServer(connectionDetails string) error {
privateKey, err := LoadPrivateKey(privateKeyPath)
if err != nil {
return err
}
config := &ssh.ClientConfig{
User: "username", // You will replace this with the actual username extracted from connectionDetails
Auth: []ssh.AuthMethod{
ssh.PublicKeys(privateKey),
},
// Other configuration options like HostKeyCallback, etc.
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
// Extract username, host, and port from connectionDetails
parts := strings.Split(connectionDetails, "@")
if len(parts) != 2 {
return errors.New("invalid connection format")
}
username := parts[0]
hostPort := parts[1]
config.User = username // Set the actual username
// Connect to the remote server
client, err := ssh.Dial("tcp", hostPort, config)
if err != nil {
return err
}
defer client.Close()
// Now you have a connected SSH client to the remote server.
// You can use this client to perform remote commands or file transfers.
return nil
}
func LoadPrivateKey(path string) (ssh.Signer, error) {
keyBytes, err := os.ReadFile(path)
if err != nil {
return nil, err
}
privateKeyBlock, _ := pem.Decode(keyBytes)
if privateKeyBlock == nil || privateKeyBlock.Type != "RSA PRIVATE KEY" {
return nil, errors.New("failed to decode valid private key")
}
privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyBlock.Bytes)
if err != nil {
return nil, err
}
return ssh.NewSignerFromKey(privateKey)
}
func GetPublicKey() (string, error) {
publicKeyBytes, err := os.ReadFile(publicKeyPath)
if err != nil {
return "", err
}
return string(publicKeyBytes), nil
}