mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
feat: create naive ui for ssh key passphrases
This isn't quite as reactive as the other methods, but it does attempt to use publickey without a passphrase, then attempt to use the password as the passphrase, and finally prompting the user for a passphrase. The problem with this approach is that if multiple keys are used and they all have passphrases, they need to all be checked up front. In practice, this will not happen often, but it is something to be aware of.
This commit is contained in:
parent
747a2b784a
commit
89906d21d4
@ -6,9 +6,10 @@ package remote
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/user"
|
||||
@ -34,23 +35,39 @@ func (uice UserInputCancelError) Error() string {
|
||||
return uice.Err.Error()
|
||||
}
|
||||
|
||||
func createPublicKeyAuth(identityFile string, passphrase string) (ssh.AuthMethod, error) {
|
||||
func createPublicKeyAuth(identityFile string, passphrase string) (ssh.Signer, error) {
|
||||
privateKey, err := os.ReadFile(base.ExpandHomeDir(identityFile))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read ssh key file. err: %+v", err)
|
||||
}
|
||||
signer, err := ssh.ParsePrivateKey(privateKey)
|
||||
if err != nil {
|
||||
if errors.Is(err, &ssh.PassphraseMissingError{}) {
|
||||
signer, err = ssh.ParsePrivateKeyWithPassphrase(privateKey, []byte(passphrase))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse private ssh key with passphrase. err: %+v", err)
|
||||
if err == nil {
|
||||
return signer, err
|
||||
}
|
||||
} else {
|
||||
if _, ok := err.(*ssh.PassphraseMissingError); !ok {
|
||||
return nil, fmt.Errorf("failed to parse private ssh key. err: %+v", err)
|
||||
}
|
||||
|
||||
signer, err = ssh.ParsePrivateKeyWithPassphrase(privateKey, []byte(passphrase))
|
||||
if err == nil {
|
||||
return signer, err
|
||||
}
|
||||
return ssh.PublicKeys(signer), nil
|
||||
if err != x509.IncorrectPasswordError && err.Error() != "bcrypt_pbkdf: empty password" {
|
||||
log.Printf("qwerty: %+v", err)
|
||||
return nil, fmt.Errorf("failed to parse private ssh key. err: %+v", err)
|
||||
}
|
||||
request := &sstore.UserInputRequestType{
|
||||
ResponseType: "text",
|
||||
QueryText: fmt.Sprintf("Enter passphrase for the SSH key: %s", identityFile),
|
||||
Title: "Publickey Auth + Passphrase",
|
||||
}
|
||||
ctx, cancelFn := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancelFn()
|
||||
response, err := sstore.MainBus.GetUserInput(ctx, request)
|
||||
if err != nil {
|
||||
return nil, UserInputCancelError{Err: err}
|
||||
}
|
||||
return ssh.ParsePrivateKeyWithPassphrase(privateKey, []byte(response.Text))
|
||||
}
|
||||
|
||||
func createDefaultPasswordCallbackPrompt(password string) func() (secret string, err error) {
|
||||
@ -406,9 +423,9 @@ func ConnectToClient(opts *sstore.SSHOpts) (*ssh.Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
var authMethods []ssh.AuthMethod
|
||||
publicKeyAuth, err := createPublicKeyAuth(identityFile, opts.SSHPassword)
|
||||
publicKeySigner, err := createPublicKeyAuth(identityFile, opts.SSHPassword)
|
||||
if err == nil {
|
||||
authMethods = append(authMethods, publicKeyAuth)
|
||||
authMethods = append(authMethods, ssh.PublicKeys(publicKeySigner))
|
||||
}
|
||||
authMethods = append(authMethods, ssh.RetryableAuthMethod(ssh.KeyboardInteractive(createCombinedKbdInteractiveChallenge(opts.SSHPassword)), 2))
|
||||
authMethods = append(authMethods, ssh.RetryableAuthMethod(ssh.PasswordCallback(createCombinedPasswordCallbackPrompt(opts.SSHPassword)), 2))
|
||||
|
Loading…
Reference in New Issue
Block a user