golang.org/x/build@v0.0.0-20240506185731-218518f32b70/cmd/buildlet/ssh_windows.go (about)

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"log"
    11  
    12  	"github.com/UserExistsError/conpty"
    13  	"github.com/gliderlabs/ssh"
    14  )
    15  
    16  func startSSHServerSwarming() {
    17  	buildletSSHServer = &ssh.Server{
    18  		Addr:    "localhost:" + sshPort(),
    19  		Handler: sshHandler,
    20  		PublicKeyHandler: func(ctx ssh.Context, key ssh.PublicKey) bool {
    21  			allowed, _, _, _, err := ssh.ParseAuthorizedKey(buldletAuthKeys)
    22  			if err != nil {
    23  				log.Printf("error parsing authorized key: %s", err)
    24  				return false
    25  			}
    26  			return ssh.KeysEqual(key, allowed)
    27  		},
    28  	}
    29  	go func() {
    30  		err := buildletSSHServer.ListenAndServe()
    31  		if err != nil {
    32  			log.Printf("buildlet SSH Server stopped: %s", err)
    33  		}
    34  	}()
    35  	teardownFuncs = append(teardownFuncs, func() {
    36  		buildletSSHServer.Close()
    37  		log.Println("shutting down SSH Server")
    38  	})
    39  }
    40  
    41  func sshHandler(s ssh.Session) {
    42  	ptyReq, winCh, isPty := s.Pty()
    43  	if !isPty {
    44  		fmt.Fprint(s, "scp is not supported\n")
    45  		return
    46  	}
    47  	f, err := conpty.Start(shell(), conpty.ConPtyDimensions(ptyReq.Window.Width, ptyReq.Window.Height))
    48  	if err != nil {
    49  		fmt.Fprintf(s, "unable to start shell %q: %s\n", shell(), err)
    50  		log.Printf("unable to start shell: %s", err)
    51  		return
    52  	}
    53  	defer f.Close()
    54  	go func() {
    55  		for win := range winCh {
    56  			err := f.Resize(win.Width, win.Height)
    57  			if err != nil {
    58  				log.Printf("error resizing pty: %s", err)
    59  			}
    60  		}
    61  	}()
    62  	go io.Copy(f, s) // stdin
    63  	go io.Copy(s, f) // stdout
    64  	_, err = f.Wait(s.Context())
    65  	if err != nil {
    66  		log.Printf("Error: %s", err)
    67  		return
    68  	}
    69  }