Skip to content

Instantly share code, notes, and snippets.

@josephspurrier
Last active September 10, 2022 02:23
Show Gist options
  • Save josephspurrier/e83bcdbf9e6865500004 to your computer and use it in GitHub Desktop.
Save josephspurrier/e83bcdbf9e6865500004 to your computer and use it in GitHub Desktop.
Golang SSH Client
package main
import (
"bufio"
"io/ioutil"
"os/signal"
//"syscall"
"fmt"
"log"
"os"
"strings"
//"code.google.com/p/go.crypto/ssh"
//"code.google.com/p/go.crypto/ssh/terminal"
"golang.org/x/crypto/ssh"
//"github.com/fatih/color"
"github.com/shiena/ansicolor"
)
type password string
func (p password) Password(user string) (password string, err error) {
return string(p), nil
}
func PublicKeyFile(file string) (ssh.AuthMethod, error) {
buffer, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
key, err := ssh.ParsePrivateKey(buffer)
if err != nil {
return nil, err
}
return ssh.PublicKeys(key), nil
}
func init() {
// Verbose logging with file name and line number
log.SetFlags(log.Lshortfile)
}
func main() {
fmt.Print("Remote host: ")
server := scanConfig()
fmt.Print("Port: ")
port := scanConfig()
server = server + ":" + port
//fmt.Print("UserName?: ")
//user := scanConfig()
user := "ubuntu"
//fmt.Print("Password?: ")
//p := scanConfig()
publicKey, err := PublicKeyFile(`privatekey.pem`)
if err != nil {
log.Println(err)
return
}
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
//ssh.Password(p),
publicKey,
},
}
conn, err := ssh.Dial("tcp", server, config)
if err != nil {
panic("Failed to dial: " + err.Error())
}
defer conn.Close()
// Each ClientConn can support multiple interactive sessions,
// represented by a Session.
session, err := conn.NewSession()
if err != nil {
panic("Failed to create session: " + err.Error())
}
defer session.Close()
// Set IO
session.Stdout = ansicolor.NewAnsiColorWriter(os.Stdout)
session.Stderr = ansicolor.NewAnsiColorWriter(os.Stderr)
in, _ := session.StdinPipe()
// Set up terminal modes
// https://net-ssh.github.io/net-ssh/classes/Net/SSH/Connection/Term.html
// https://www.ietf.org/rfc/rfc4254.txt
// https://godoc.org/golang.org/x/crypto/ssh
// THIS IS THE TITLE
// https://pythonhosted.org/ANSIColors-balises/ANSIColors.html
modes := ssh.TerminalModes{
ssh.ECHO: 0, // Disable echoing
ssh.IGNCR: 1, // Ignore CR on input.
}
// Request pseudo terminal
//if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
//if err := session.RequestPty("xterm-256color", 80, 40, modes); err != nil {
if err := session.RequestPty("vt100", 80, 40, modes); err != nil {
//if err := session.RequestPty("vt220", 80, 40, modes); err != nil {
log.Fatalf("request for pseudo terminal failed: %s", err)
}
// Start remote shell
if err := session.Shell(); err != nil {
log.Fatalf("failed to start shell: %s", err)
}
// Handle control + C
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
for {
<-c
fmt.Println("^C")
fmt.Fprint(in, "\n")
//fmt.Fprint(in, '\t')
}
}()
var b []byte = make([]byte, 1)
// Accepting commands
for {
//reader := bufio.NewReader(os.Stdin)
//str, _ := reader.ReadString('\n')
fmt.Fprint(in, str)
}
}
func scanConfig() string {
config, _ := bufio.NewReader(os.Stdin).ReadString('\n')
config = strings.TrimSpace(config)
return config
}
@imfht
Copy link

imfht commented Oct 31, 2018

don't working. stop try.

@DuGites
Copy link

DuGites commented Nov 16, 2018

where is LINE_ENDING defined?

@newkedison
Copy link

use config = strings.TrimSpace(config) instead

@josephspurrier
Copy link
Author

I fixed that - thanks.

@JustinGrote
Copy link

Thanks for this! The Ansi Color Writer is clever and part of what I was missing.

@josephspurrier
Copy link
Author

Great, I'm glad I could help!

@shencan
Copy link

shencan commented Sep 15, 2020

this code can record input command line?

@josephspurrier
Copy link
Author

this code can record input command line?

Yes, that's correct and then send it to a server via SSH.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment