merge branch 'main' into sylvie/ssh-agent

This commit is contained in:
Sylvia Crowe 2024-09-17 13:37:28 -07:00
commit 0d10632c62
4 changed files with 57 additions and 23 deletions

View File

@ -134,14 +134,28 @@ github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaD
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=

View File

@ -20,9 +20,9 @@ require (
github.com/sashabaranov/go-openai v1.9.0
github.com/sawka/txwrap v0.1.2
github.com/wavetermdev/waveterm/waveshell v0.0.0
golang.org/x/crypto v0.17.0
golang.org/x/crypto v0.24.0
golang.org/x/mod v0.10.0
golang.org/x/sys v0.15.0
golang.org/x/sys v0.21.0
mvdan.cc/sh/v3 v3.7.0
)
@ -30,6 +30,7 @@ require (
github.com/google/go-querystring v1.1.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/skeema/knownhosts v1.3.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
)

View File

@ -53,6 +53,8 @@ github.com/sashabaranov/go-openai v1.9.0 h1:NoiO++IISxxJ1pRc0n7uZvMGMake0G+FJ1XP
github.com/sashabaranov/go-openai v1.9.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
github.com/sawka/txwrap v0.1.2 h1:v8xS0Z1LE7/6vMZA81PYihI+0TSR6Zm1MalzzBIuXKc=
github.com/sawka/txwrap v0.1.2/go.mod h1:T3nlw2gVpuolo6/XEetvBbk1oMXnY978YmBFy1UyHvw=
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
@ -63,11 +65,15 @@ go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -22,6 +22,7 @@ import (
"time"
"github.com/kevinburke/ssh_config"
"github.com/skeema/knownhosts"
"github.com/wavetermdev/waveterm/waveshell/pkg/base"
"github.com/wavetermdev/waveterm/waveshell/pkg/utilfn"
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbus"
@ -29,13 +30,15 @@ import (
"github.com/wavetermdev/waveterm/wavesrv/pkg/userinput"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
"golang.org/x/crypto/ssh/knownhosts"
xknownhosts "golang.org/x/crypto/ssh/knownhosts"
)
type UserInputCancelError struct {
Err error
}
type HostKeyAlgorithms = func(hostWithPort string) (algos []string)
func (uice UserInputCancelError) Error() string {
return uice.Err.Error()
}
@ -407,7 +410,7 @@ func lineContainsMatch(line []byte, matches [][]byte) bool {
return false
}
func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, error) {
func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, HostKeyAlgorithms, error) {
ssh_config.ReloadConfigs()
rawUserKnownHostsFiles, _ := ssh_config.GetStrict(opts.SSHHost, "UserKnownHostsFile")
userKnownHostsFiles := strings.Fields(rawUserKnownHostsFiles) // TODO - smarter splitting escaped spaces and quotes
@ -416,7 +419,7 @@ func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, error) {
osUser, err := user.Current()
if err != nil {
return nil, err
return nil, nil, err
}
var unexpandedKnownHostsFiles []string
if osUser.Username == "root" {
@ -432,7 +435,7 @@ func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, error) {
// there are no good known hosts files
if len(knownHostsFiles) == 0 {
return nil, fmt.Errorf("no known_hosts files provided by ssh. defaults are overridden")
return nil, nil, fmt.Errorf("no known_hosts files provided by ssh. defaults are overridden")
}
var unreadableFiles []string
@ -441,9 +444,10 @@ func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, error) {
// incorrectly. if a problem file is found, it is removed from our list
// and we try again
var basicCallback ssh.HostKeyCallback
var hostKeyAlgorithms HostKeyAlgorithms
for basicCallback == nil && len(knownHostsFiles) > 0 {
var err error
basicCallback, err = knownhosts.New(knownHostsFiles...)
keyDb, err := knownhosts.NewDB(knownHostsFiles...)
if serr, ok := err.(*os.PathError); ok {
badFile := serr.Path
unreadableFiles = append(unreadableFiles, badFile)
@ -454,18 +458,26 @@ func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, error) {
}
}
if len(okFiles) >= len(knownHostsFiles) {
return nil, fmt.Errorf("problem file (%s) doesn't exist. this should not be possible", badFile)
return nil, nil, fmt.Errorf("problem file (%s) doesn't exist. this should not be possible", badFile)
}
knownHostsFiles = okFiles
} else if err != nil {
// TODO handle obscure problems if possible
return nil, fmt.Errorf("known_hosts formatting error: %+v", err)
return nil, nil, fmt.Errorf("known_hosts formatting error: %+v", err)
} else {
basicCallback = keyDb.HostKeyCallback()
hostKeyAlgorithms = keyDb.HostKeyAlgorithms
}
}
if basicCallback == nil {
basicCallback = func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return &knownhosts.KeyError{}
return &xknownhosts.KeyError{}
}
// need to return nil here to avoid null pointer from attempting to call
// the one provided by the db if nothing was found
hostKeyAlgorithms = func(hostWithPort string) (algos []string) {
return nil
}
}
@ -474,21 +486,21 @@ func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, error) {
if err == nil {
// success
return nil
} else if _, ok := err.(*knownhosts.RevokedError); ok {
} else if _, ok := err.(*xknownhosts.RevokedError); ok {
// revoked credentials are refused outright
return err
} else if _, ok := err.(*knownhosts.KeyError); !ok {
} else if _, ok := err.(*xknownhosts.KeyError); !ok {
// this is an unknown error (note the !ok is opposite of usual)
return err
}
serr, _ := err.(*knownhosts.KeyError)
serr, _ := err.(*xknownhosts.KeyError)
if len(serr.Want) == 0 {
// the key was not found
// try to write to a file that could be read
err := fmt.Errorf("placeholder, should not be returned") // a null value here can cause problems with empty slice
for _, filename := range knownHostsFiles {
newLine := knownhosts.Line([]string{knownhosts.Normalize(hostname)}, key)
newLine := xknownhosts.Line([]string{xknownhosts.Normalize(hostname)}, key)
getUserVerification := createUnknownKeyVerifier(filename, hostname, remote.String(), key)
err = writeToKnownHosts(filename, newLine, getUserVerification)
if err == nil {
@ -503,7 +515,7 @@ func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, error) {
// should catch cases where there is no known_hosts file
if err != nil {
for _, filename := range unreadableFiles {
newLine := knownhosts.Line([]string{knownhosts.Normalize(hostname)}, key)
newLine := xknownhosts.Line([]string{xknownhosts.Normalize(hostname)}, key)
getUserVerification := createMissingKnownHostsVerifier(filename, hostname, remote.String(), key)
err = writeToKnownHosts(filename, newLine, getUserVerification)
if err == nil {
@ -553,7 +565,7 @@ func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, error) {
return fmt.Errorf("remote host identification has changed")
}
updatedCallback, err := knownhosts.New(knownHostsFiles...)
updatedCallback, err := xknownhosts.New(knownHostsFiles...)
if err != nil {
return err
}
@ -561,7 +573,7 @@ func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, error) {
return updatedCallback(hostname, remote, key)
}
return waveHostKeyCallback, nil
return waveHostKeyCallback, hostKeyAlgorithms, nil
}
func DialContext(ctx context.Context, network string, addr string, config *ssh.ClientConfig) (*ssh.Client, error) {
@ -637,17 +649,18 @@ func ConnectToClient(connCtx context.Context, opts *sstore.SSHOpts, remoteDispla
authMethods = append(authMethods, authMethod)
}
hostKeyCallback, err := createHostKeyCallback(opts)
hostKeyCallback, hostKeyAlgorithms, err := createHostKeyCallback(opts)
if err != nil {
return nil, err
}
networkAddr := sshKeywords.HostName + ":" + sshKeywords.Port
clientConfig := &ssh.ClientConfig{
User: sshKeywords.User,
Auth: authMethods,
HostKeyCallback: hostKeyCallback,
HostKeyAlgorithms: hostKeyAlgorithms(networkAddr),
}
networkAddr := sshKeywords.HostName + ":" + sshKeywords.Port
return DialContext(connCtx, "tcp", networkAddr, clientConfig)
}