@@ -7,36 +7,33 @@ import (
77 "io"
88 "log/slog"
99 "net/netip"
10- "os"
1110 "time"
1211
1312 "github.com/charmbracelet/huh"
14- "github.com/mattn/go-isatty"
15- "golang.org/x/crypto/ssh"
16- "golang.org/x/term"
17- "golang.org/x/xerrors"
1813 "tailscale.com/client/tailscale"
1914 "tailscale.com/net/netns"
2015 "tailscale.com/tailcfg"
2116
22- "github.com/coder/coder/v2/pty"
2317 "github.com/coder/serpent"
2418 "github.com/coder/wush/cliui"
2519 "github.com/coder/wush/overlay"
2620 "github.com/coder/wush/tsserver"
2721 xssh "github.com/coder/wush/xssh"
2822)
2923
30- func sendCmd () * serpent.Command {
24+ func sshCmd () * serpent.Command {
3125 var (
3226 authID string
3327 waitP2P bool
3428 overlayTransport string
3529 stunAddrOverride string
3630 stunAddrOverrideIP netip.Addr
31+ sshStdio bool
3732 )
3833 return & serpent.Command {
39- Use : "send" ,
34+ Use : "wush" ,
35+ Long : "Opens an SSH connection to a " + cliui .Code ("wush" ) + " peer. " +
36+ "Use " + cliui .Code ("wush receive" ) + " on the computer you would like to connect to." ,
4037 Handler : func (inv * serpent.Invocation ) error {
4138 ctx := inv .Context ()
4239 logger := slog .New (slog .NewTextHandler (io .Discard , nil ))
@@ -71,19 +68,21 @@ func sendCmd() *serpent.Command {
7168 return fmt .Errorf ("parse auth key: %w" , err )
7269 }
7370
74- fmt .Println ("Auth information:" )
75- stunStr := send .Auth .ReceiverStunAddr .String ()
76- if ! send .Auth .ReceiverStunAddr .IsValid () {
77- stunStr = "Disabled"
78- }
79- fmt .Println ("\t > Server overlay STUN address:" , cliui .Code (stunStr ))
80- derpStr := "Disabled"
81- if send .Auth .ReceiverDERPRegionID > 0 {
82- derpStr = dm .Regions [int (send .Auth .ReceiverDERPRegionID )].RegionName
71+ if ! sshStdio {
72+ fmt .Println ("Auth information:" )
73+ stunStr := send .Auth .ReceiverStunAddr .String ()
74+ if ! send .Auth .ReceiverStunAddr .IsValid () {
75+ stunStr = "Disabled"
76+ }
77+ fmt .Println ("\t > Server overlay STUN address:" , cliui .Code (stunStr ))
78+ derpStr := "Disabled"
79+ if send .Auth .ReceiverDERPRegionID > 0 {
80+ derpStr = dm .Regions [int (send .Auth .ReceiverDERPRegionID )].RegionName
81+ }
82+ fmt .Println ("\t > Server overlay DERP home: " , cliui .Code (derpStr ))
83+ fmt .Println ("\t > Server overlay public key: " , cliui .Code (send .Auth .ReceiverPublicKey .ShortString ()))
84+ fmt .Println ("\t > Server overlay auth key: " , cliui .Code (send .Auth .OverlayPrivateKey .Public ().ShortString ()))
8385 }
84- fmt .Println ("\t > Server overlay DERP home: " , cliui .Code (derpStr ))
85- fmt .Println ("\t > Server overlay public key: " , cliui .Code (send .Auth .ReceiverPublicKey .ShortString ()))
86- fmt .Println ("\t > Server overlay auth key: " , cliui .Code (send .Auth .OverlayPrivateKey .Public ().ShortString ()))
8786
8887 s , err := tsserver .NewServer (ctx , logger , send )
8988 if err != nil {
@@ -112,9 +111,9 @@ func sendCmd() *serpent.Command {
112111 ts .Logf = func (string , ... any ) {}
113112 ts .UserLogf = func (string , ... any ) {}
114113
115- fmt .Println ("Bringing Wireguard up.." )
114+ // fmt.Println("Bringing Wireguard up..")
116115 ts .Up (ctx )
117- fmt .Println ("Wireguard is ready!" )
116+ // fmt.Println("Wireguard is ready!")
118117
119118 lc , err := ts .LocalClient ()
120119 if err != nil {
@@ -133,87 +132,13 @@ func sendCmd() *serpent.Command {
133132 }
134133 }
135134
136- conn , err := ts .Dial (ctx , "tcp" , ip .String ()+ ":3" )
137- if err != nil {
138- return err
139- }
140-
141- sshConn , channels , requests , err := ssh .NewClientConn (conn , "localhost:22" , & ssh.ClientConfig {
142- HostKeyCallback : ssh .InsecureIgnoreHostKey (),
143- })
144- if err != nil {
145- return err
146- }
147-
148- sshClient := ssh .NewClient (sshConn , channels , requests )
149- sshSession , err := sshClient .NewSession ()
150- if err != nil {
151- return err
152- }
153-
154- stdinFile , validIn := inv .Stdin .(* os.File )
155- stdoutFile , validOut := inv .Stdout .(* os.File )
156- if validIn && validOut && isatty .IsTerminal (stdinFile .Fd ()) && isatty .IsTerminal (stdoutFile .Fd ()) {
157- inState , err := pty .MakeInputRaw (stdinFile .Fd ())
158- if err != nil {
159- return err
160- }
161- defer func () {
162- _ = pty .RestoreTerminal (stdinFile .Fd (), inState )
163- }()
164- outState , err := pty .MakeOutputRaw (stdoutFile .Fd ())
165- if err != nil {
166- return err
167- }
168- defer func () {
169- _ = pty .RestoreTerminal (stdoutFile .Fd (), outState )
170- }()
171-
172- windowChange := xssh .ListenWindowSize (ctx )
173- go func () {
174- for {
175- select {
176- case <- ctx .Done ():
177- return
178- case <- windowChange :
179- }
180- width , height , err := term .GetSize (int (stdoutFile .Fd ()))
181- if err != nil {
182- continue
183- }
184- _ = sshSession .WindowChange (height , width )
185- }
186- }()
187- }
188-
189- err = sshSession .RequestPty ("xterm-256color" , 128 , 128 , ssh.TerminalModes {})
190- if err != nil {
191- return xerrors .Errorf ("request pty: %w" , err )
192- }
193-
194- sshSession .Stdin = inv .Stdin
195- sshSession .Stdout = inv .Stdout
196- sshSession .Stderr = inv .Stderr
197-
198- err = sshSession .Shell ()
199- if err != nil {
200- return xerrors .Errorf ("start shell: %w" , err )
201- }
202-
203- if validOut {
204- // Set initial window size.
205- width , height , err := term .GetSize (int (stdoutFile .Fd ()))
206- if err == nil {
207- _ = sshSession .WindowChange (height , width )
208- }
209- }
210-
211- return sshSession .Wait ()
135+ return xssh .TailnetSSH (ctx , inv , ts , ip .String ()+ ":3" , sshStdio )
212136 },
213137 Options : []serpent.Option {
214138 {
215139 Flag : "auth-id" ,
216- Description : "The auth id returned by `wush receive`. If not provided, it will be asked for on startup." ,
140+ Env : "WUSH_AUTH_ID" ,
141+ Description : "The auth id returned by " + cliui .Code ("wush receive" ) + ". If not provided, it will be asked for on startup." ,
217142 Default : "" ,
218143 Value : serpent .StringOf (& authID ),
219144 },
@@ -228,6 +153,12 @@ func sendCmd() *serpent.Command {
228153 Default : "" ,
229154 Value : serpent .StringOf (& stunAddrOverride ),
230155 },
156+ {
157+ Flag : "stdio" ,
158+ Description : "Run SSH over stdin/stdout. This allows wush to be used as a transport for other programs, like rsync or regular ssh." ,
159+ Default : "false" ,
160+ Value : serpent .BoolOf (& sshStdio ),
161+ },
231162 },
232163 }
233164}
@@ -248,11 +179,11 @@ func waitUntilHasPeerHasIP(ctx context.Context, lc *tailscale.LocalClient) (neti
248179
249180 peers := stat .Peers ()
250181 if len (peers ) == 0 {
251- fmt .Println ("No peer yet" )
182+ // fmt.Println("No peer yet")
252183 continue
253184 }
254185
255- fmt .Println ("Received peer" )
186+ // fmt.Println("Received peer")
256187
257188 peer , ok := stat .Peer [peers [0 ]]
258189 if ! ok {
@@ -265,7 +196,7 @@ func waitUntilHasPeerHasIP(ctx context.Context, lc *tailscale.LocalClient) (neti
265196 continue
266197 }
267198
268- fmt .Println ("Peer active with relay" , cliui .Code (peer .Relay ))
199+ // fmt.Println("Peer active with relay", cliui.Code(peer.Relay))
269200
270201 if len (peer .TailscaleIPs ) == 0 {
271202 fmt .Println ("peer has no ips (developer error)" )
@@ -302,7 +233,7 @@ func waitUntilHasP2P(ctx context.Context, lc *tailscale.LocalClient) error {
302233 continue
303234 }
304235
305- fmt .Println ("Peer active with relay" , cliui .Code (peer .Relay ))
236+ // fmt.Println("Peer active with relay", cliui.Code(peer.Relay))
306237
307238 if len (peer .TailscaleIPs ) == 0 {
308239 fmt .Println ("peer has no ips (developer error)" )
@@ -322,7 +253,7 @@ func waitUntilHasP2P(ctx context.Context, lc *tailscale.LocalClient) error {
322253 continue
323254 }
324255
325- fmt .Println ("Peer active over p2p" , cliui .Code (pong .Endpoint ))
256+ // fmt.Println("Peer active over p2p", cliui.Code(pong.Endpoint))
326257 return nil
327258 }
328259}
0 commit comments