From 1dfb2fb777ac560de2bcf8bf0f784db28158aad0 Mon Sep 17 00:00:00 2001 From: Aarnav Tale Date: Sat, 27 Sep 2025 12:10:15 -0400 Subject: [PATCH] fix: upgrade to new tailscale go version to fix ssh --- .tool-versions | 2 +- app/routes/machines/dialogs/expire.tsx | 4 +- app/routes/ssh/hp_ssh.d.ts | 15 +++---- app/routes/ssh/xterm.client.tsx | 20 +++++---- go.mod | 8 ++-- go.sum | 16 +++---- internal/hp_ipn/ipnserver.go | 19 +++++---- internal/hp_ipn/jsmap.go | 58 +++++++++----------------- mise.toml | 2 +- vite.config.ts | 4 +- 10 files changed, 66 insertions(+), 82 deletions(-) diff --git a/.tool-versions b/.tool-versions index c06aa6a..a1e8ca8 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,4 +1,4 @@ # REMEMBER TO UPDATE mise.toml TOO pnpm 10.4.0 node 22.16 -go 1.24.4 +go 1.25.1 diff --git a/app/routes/machines/dialogs/expire.tsx b/app/routes/machines/dialogs/expire.tsx index 12f78b7..5c0863b 100644 --- a/app/routes/machines/dialogs/expire.tsx +++ b/app/routes/machines/dialogs/expire.tsx @@ -16,8 +16,8 @@ export default function Expire({ machine, isOpen, setIsOpen }: ExpireProps) { This will disconnect the machine from your Tailnet. In order to reconnect, you will need to re-authenticate from the device. - - + + ); diff --git a/app/routes/ssh/hp_ssh.d.ts b/app/routes/ssh/hp_ssh.d.ts index 8b9784b..8c43b4a 100644 --- a/app/routes/ssh/hp_ssh.d.ts +++ b/app/routes/ssh/hp_ssh.d.ts @@ -39,15 +39,16 @@ type IPNState = | 'Running'; interface XtermConfig { - Rows: number; - Cols: number; + rows: number; + cols: number; + timeout?: number; - OnStdout: (data: string) => void; - OnStderr: (data: string) => void; - OnStdin: (func: (input: string) => void) => void; + onStdout: (data: string) => void; + onStderr: (data: string) => void; + onStdin: (func: (input: string) => void) => void; - OnConnect: () => void; - OnDisconnect: () => void; + onConnect: () => void; + onDisconnect: () => void; } interface SSHSession { diff --git a/app/routes/ssh/xterm.client.tsx b/app/routes/ssh/xterm.client.tsx index 3c152e9..6313c13 100644 --- a/app/routes/ssh/xterm.client.tsx +++ b/app/routes/ssh/xterm.client.tsx @@ -81,24 +81,26 @@ export default function XTerm({ ipn, username, hostname }: XTermProps) { let onUnload: ((e: Event) => void) | null = null; const session = ipn.OpenSSH(hostname, username, { - Rows: terminal.rows, - Cols: terminal.cols, + rows: terminal.rows, + cols: terminal.cols, - OnStdout: (data) => terminal.write(data), - OnStderr: (data) => { + onStdout: (data) => terminal.write(data), + onStderr: (data) => { terminal.write(data); console.log('SSH stderr:', data); toast(data); }, - OnStdin: (func) => { + onStdin: (func) => { + console.log('SSH session is ready to receive input'); inputRef.current = func; + console.log('Stdin handler set', func); }, - OnConnect: () => { + onConnect: () => { console.log('SSH session connected'); setIsLoading(false); }, - OnDisconnect: () => { + onDisconnect: () => { ro?.disconnect(); terminal.dispose(); if (onUnload) { @@ -156,8 +158,8 @@ export default function XTerm({ ipn, username, hostname }: XTermProps) { ) : undefined}
{term.current && isResizing ? (
diff --git a/go.mod b/go.mod index 314bbca..f46a9bb 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,11 @@ module github.com/tale/headplane -go 1.24.4 +go 1.25.1 require ( go4.org/mem v0.0.0-20240501181205-ae6ca9944745 golang.org/x/crypto v0.41.0 - tailscale.com v1.86.4 + tailscale.com v1.88.2 ) require ( @@ -32,7 +32,7 @@ require ( github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect github.com/fxamacker/cbor/v2 v2.8.0 // indirect github.com/gaissmai/bart v0.18.0 // indirect - github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 // indirect + github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -61,7 +61,7 @@ require ( github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da // indirect - github.com/vishvananda/netns v0.0.4 // indirect + github.com/vishvananda/netns v0.0.5 // indirect github.com/x448/float16 v0.8.4 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect diff --git a/go.sum b/go.sum index e2368ed..92ac417 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo= github.com/gaissmai/bart v0.18.0/go.mod h1:JJzMAhNF5Rjo4SF4jWBrANuJfqY+FvsFhW7t1UZJ+XY= github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= -github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6M9UQCavhwmO6ZsrYLfG8zVFWfEfMS2MXPkSY= -github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= +github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I= +github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737 h1:cf60tHxREO3g1nroKr2osU3JWZsJzkfi7rEg+oAB0Lo= @@ -174,8 +174,8 @@ github.com/u-root/u-root v0.14.0/go.mod h1:hAyZorapJe4qzbLWlAkmSVCJGbfoU9Pu4jpJ1 github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM= github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= -github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= +github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4hOxG5YpKCzkek= @@ -216,8 +216,8 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -230,5 +230,5 @@ howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= -tailscale.com v1.86.4 h1:KHAmLyzVn50t2P5877wohBU0UPVeIMHC9XDzRw4Ycz4= -tailscale.com v1.86.4/go.mod h1:Lm8dnzU2i/Emw15r6sl3FRNp/liSQ/nYw6ZSQvIdZ1M= +tailscale.com v1.88.2 h1:S8S+gt/Vx4KDlVjNHk7spcyGihTcJflKMroSnwjp5kQ= +tailscale.com v1.88.2/go.mod h1:LHaTiwRgzebPDLgZ6RQQVzX+1SR5fbNl51fzm7UtMaw= diff --git a/internal/hp_ipn/ipnserver.go b/internal/hp_ipn/ipnserver.go index d77f290..d299b70 100644 --- a/internal/hp_ipn/ipnserver.go +++ b/internal/hp_ipn/ipnserver.go @@ -14,7 +14,7 @@ import ( "tailscale.com/ipn/ipnlocal" "tailscale.com/ipn/ipnserver" "tailscale.com/ipn/store/mem" - "tailscale.com/net/netmon" + // "tailscale.com/net/netmon" "tailscale.com/net/netns" "tailscale.com/net/tsdial" "tailscale.com/safesocket" @@ -52,30 +52,31 @@ func NewTsWasmIpn(options *TsWasmNetOptions, callbacks *TsWasmNetCallbacks) (*Ts // Base system (NewSystem() creates a bus automatically) // We supply an in-memory store sys := tsd.NewSystem() - bus := sys.Bus.Get() + // bus := sys.Bus.Get() sys.Set(new(mem.Store)) dialer := &tsdial.Dialer{Logf: logf} - netmon, err := netmon.New(bus, logf) - if err != nil { - return nil, err - } + // netmon, err := netmon.New(bus, logf) + // if err != nil { + // return nil, err + // } // Userspace Wireguard engine engine, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{ - Dialer: dialer, - NetMon: netmon, + Dialer: dialer, + // NetMon: netmon, SetSubsystem: sys.Set, ControlKnobs: sys.ControlKnobs(), HealthTracker: sys.HealthTracker(), Metrics: sys.UserMetricsRegistry(), + EventBus: sys.Bus.Get(), }) - sys.Set(engine) if err != nil { return nil, err } + sys.Set(engine) tun := sys.Tun.Get() msock := sys.MagicSock.Get() dnsman := sys.DNSManager.Get() diff --git a/internal/hp_ipn/jsmap.go b/internal/hp_ipn/jsmap.go index d0c8940..dff3046 100644 --- a/internal/hp_ipn/jsmap.go +++ b/internal/hp_ipn/jsmap.go @@ -59,12 +59,12 @@ func ParseSSHXtermConfig(obj js.Value) (*SSHXtermConfig, error) { return nil, errors.New("SSHXtermConfig cannot be undefined or null") } - timeout := safeInt("Timeout", obj) - rows := safeInt("Rows", obj) - cols := safeInt("Cols", obj) + timeout := safeInt("timeout", obj) + rows := safeInt("rows", obj) + cols := safeInt("cols", obj) if rows <= 0 || cols <= 0 { - return nil, errors.New("Rows and Cols must be positive integers") + return nil, errors.New("`rows` and `cols` must be positive integers") } if timeout <= 0 { @@ -77,63 +77,43 @@ func ParseSSHXtermConfig(obj js.Value) (*SSHXtermConfig, error) { Cols: cols, } - onStdout := obj.Get("OnStdout") - if onStdout.IsUndefined() || onStdout.IsNull() { - return nil, errors.New("OnStdout must be a function") - } - - if onStdout.Type() != js.TypeFunction { - return nil, errors.New("OnStdout must be a function") + onStdout := obj.Get("onStdout") + if onStdout.IsUndefined() || onStdout.IsNull() || (onStdout.Type() != js.TypeFunction) { + return nil, errors.New("`onStdout` is required and must be a function") } config.OnStdout = func(data string) { onStdout.Invoke(data) } - onStderr := obj.Get("OnStderr") - if onStderr.IsUndefined() || onStderr.IsNull() { - return nil, errors.New("OnStderr must be a function") - } - - if onStderr.Type() != js.TypeFunction { - return nil, errors.New("OnStderr must be a function") + onStderr := obj.Get("onStderr") + if onStderr.IsUndefined() || onStderr.IsNull() || (onStderr.Type() != js.TypeFunction) { + return nil, errors.New("`onStderr` is required and must be a function") } config.OnStderr = func(error string) { onStderr.Invoke(error) } - onStdin := obj.Get("OnStdin") - if onStdin.IsUndefined() || onStdin.IsNull() { - return nil, errors.New("OnStdin must be a function") - } - - if onStdin.Type() != js.TypeFunction { - return nil, errors.New("OnStdin must be a function") + onStdin := obj.Get("onStdin") + if onStdin.IsUndefined() || onStdin.IsNull() || (onStdin.Type() != js.TypeFunction) { + return nil, errors.New("`onStdin` is required and must be a function") } config.OnStdin = onStdin - onConnect := obj.Get("OnConnect") - if onConnect.IsUndefined() || onConnect.IsNull() { - return nil, errors.New("OnConnect must be a function") - } - - if onConnect.Type() != js.TypeFunction { - return nil, errors.New("OnConnect must be a function") + onConnect := obj.Get("onConnect") + if onConnect.IsUndefined() || onConnect.IsNull() || (onConnect.Type() != js.TypeFunction) { + return nil, errors.New("`onConnect` is required and must be a function") } config.OnConnect = func() { onConnect.Invoke() } - onDisconnect := obj.Get("OnDisconnect") - if onDisconnect.IsUndefined() || onDisconnect.IsNull() { - return nil, errors.New("OnDisconnect must be a function") - } - - if onDisconnect.Type() != js.TypeFunction { - return nil, errors.New("OnDisconnect must be a function") + onDisconnect := obj.Get("onDisconnect") + if onDisconnect.IsUndefined() || onDisconnect.IsNull() || (onDisconnect.Type() != js.TypeFunction) { + return nil, errors.New("`onDisconnect` is required and must be a function") } config.OnDisconnect = func() { diff --git a/mise.toml b/mise.toml index 345ecdf..5462207 100644 --- a/mise.toml +++ b/mise.toml @@ -1,6 +1,6 @@ [tools] # REMEMBER TO UPDATE .tool-versions TOO -go = "1.24.4" +go = "1.25.1" pnpm = "10.4.0" node = "22.16" diff --git a/vite.config.ts b/vite.config.ts index e24cd98..1e6655b 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -23,8 +23,8 @@ if (!version) { const config = await readFile('config.example.yaml', 'utf-8'); const { server } = parse(config); -export default defineConfig(({ isSsrBuild }) => ({ - base: `${prefix}/`, +export default defineConfig(({ mode, isSsrBuild }) => ({ + base: mode !== 'development' ? `${prefix}/` : undefined, plugins: [ reactRouterHonoServer(), reactRouter(),