MCPcopy
hub / github.com/wavetermdev/waveterm / createPublicKeyCallback

Function createPublicKeyCallback

pkg/remote/sshclient.go:276–383  ·  view source on GitHub ↗

This is a workaround to only process one identity file at a time, even if they have passphrases. It must be combined with retryable authentication to work properly Despite returning an array of signers, we only ever provide one since it allows proper user interaction in between attempts A signific

(connCtx context.Context, sshKeywords *wconfig.ConnKeywords, authSockSignersExt []ssh.Signer, agentClient agent.ExtendedAgent, debugInfo *ConnectionDebugInfo)

Source from the content-addressed store, hash-verified

274// keys from being attempted. But if there's an error because of a dummy
275// file, the library can still try again with a new key.
276func createPublicKeyCallback(connCtx context.Context, sshKeywords *wconfig.ConnKeywords, authSockSignersExt []ssh.Signer, agentClient agent.ExtendedAgent, debugInfo *ConnectionDebugInfo) func() ([]ssh.Signer, error) {
277 var identityFiles []string
278 existingKeys := make(map[string][]byte)
279
280 // checking the file early prevents us from needing to send a
281 // dummy signer if there's a problem with the signer
282 for _, identityFile := range sshKeywords.SshIdentityFile {
283 filePath, err := wavebase.ExpandHomeDir(identityFile)
284 if err != nil {
285 continue
286 }
287 privateKey, err := os.ReadFile(filePath)
288 if err != nil {
289 // skip this key and try with the next
290 continue
291 }
292 existingKeys[identityFile] = privateKey
293 identityFiles = append(identityFiles, identityFile)
294 }
295 // require pointer to modify list in closure
296 identityFilesPtr := &identityFiles
297
298 var authSockSigners []ssh.Signer
299 authSockSigners = append(authSockSigners, authSockSignersExt...)
300 authSockSignersPtr := &authSockSigners
301
302 return func() (outSigner []ssh.Signer, outErr error) {
303 defer func() {
304 panicErr := panichandler.PanicHandler("sshclient:publickey-callback", recover())
305 if panicErr != nil {
306 outErr = panicErr
307 }
308 }()
309 // try auth sock
310 if len(*authSockSignersPtr) != 0 {
311 authSockSigner := (*authSockSignersPtr)[0]
312 *authSockSignersPtr = (*authSockSignersPtr)[1:]
313 return []ssh.Signer{authSockSigner}, nil
314 }
315
316 if len(*identityFilesPtr) == 0 {
317 return nil, ConnectionError{ConnectionDebugInfo: debugInfo, Err: fmt.Errorf("no identity files remaining")}
318 }
319 identityFile := (*identityFilesPtr)[0]
320 blocklogger.Infof(connCtx, "[conndebug] trying keyfile %q...\n", identityFile)
321 *identityFilesPtr = (*identityFilesPtr)[1:]
322 privateKey, ok := existingKeys[identityFile]
323 if !ok {
324 log.Printf("error with existingKeys, this should never happen")
325 // skip this key and try with the next
326 return createDummySigner()
327 }
328
329 unencryptedPrivateKey, err := ssh.ParseRawPrivateKey(privateKey)
330 if err == nil {
331 signer, err := ssh.NewSignerFromKey(unencryptedPrivateKey)
332 if err == nil {
333 if utilfn.SafeDeref(sshKeywords.SshAddKeysToAgent) && agentClient != nil {

Callers 1

createClientConfigFunction · 0.85

Calls 8

ExpandHomeDirFunction · 0.92
PanicHandlerFunction · 0.92
InfofFunction · 0.92
SafeDerefFunction · 0.92
GetUserInputFunction · 0.92
MakeCodedErrorFunction · 0.92
createDummySignerFunction · 0.85
ReadFileMethod · 0.80

Tested by

no test coverage detected