diff --git a/src/app/(remote-access)/peer/ssh/page.tsx b/src/app/(remote-access)/peer/ssh/page.tsx index 23db5bce..5f9fca90 100644 --- a/src/app/(remote-access)/peer/ssh/page.tsx +++ b/src/app/(remote-access)/peer/ssh/page.tsx @@ -108,6 +108,7 @@ function SSHTerminal({ username, port, peer }: Props) { if (!peer.id) return; if (connected.current) return; connected.current = true; + try { const aclPort = isNativeSSHSupported(peer.version) ? "22022" : port; const rules = [`tcp/${aclPort}`]; @@ -121,7 +122,7 @@ function SSHTerminal({ username, port, peer }: Props) { sshConnectedOnce.current = true; } } catch (error) { - console.error("Connection failed:", error); + console.error("Connection error:", error); } }; diff --git a/src/modules/remote-access/ssh/useSSH.ts b/src/modules/remote-access/ssh/useSSH.ts index dfb7b362..121d68ad 100644 --- a/src/modules/remote-access/ssh/useSSH.ts +++ b/src/modules/remote-access/ssh/useSSH.ts @@ -24,6 +24,8 @@ export enum SSHStatus { export const SSH_DOCS_LINK = "https://docs.netbird.io/how-to/browser-client#ssh-connection"; +const SSH_DETECTION_TIMEOUT_MS = 20000; + export const useSSH = (client: any) => { const [status, setStatus] = useState(SSHStatus.DISCONNECTED); const [config, setConfig] = useState(null); @@ -38,12 +40,31 @@ export const useSSH = (client: any) => { setStatus(SSHStatus.CONNECTING); setConfig(config); + setError(""); try { - const requiresJwt = await client.detectSSHServerType( - config.hostname, - config.port, - ); + let requiresJwt = false; + try { + requiresJwt = await client.detectSSHServerType( + config.hostname, + config.port, + SSH_DETECTION_TIMEOUT_MS, + ); + console.log("Detection:", { requiresJwt, hasToken: !!accessToken }); + } catch (detectionErr) { + console.error( + "Detection failed, falling back to pubkey:", + detectionErr, + ); + } + + if (requiresJwt && !accessToken) { + console.error("No access token available"); + setError("No access token available"); + setStatus(SSHStatus.DISCONNECTED); + setConfig(null); + return SSHStatus.DISCONNECTED; + } const ssh = await client.createSSHConnection( config.hostname, @@ -63,7 +84,7 @@ export const useSSH = (client: any) => { setStatus(SSHStatus.CONNECTED); return SSHStatus.CONNECTED; } catch (err) { - console.error("SSH connection failed:", err); + console.error("Connection failed:", err); session.current = null; setStatus(SSHStatus.DISCONNECTED); setError("SSH connection failed. Check the console for details."); diff --git a/src/modules/remote-access/useNetBirdClient.ts b/src/modules/remote-access/useNetBirdClient.ts index cfc21186..8a578983 100644 --- a/src/modules/remote-access/useNetBirdClient.ts +++ b/src/modules/remote-access/useNetBirdClient.ts @@ -209,11 +209,11 @@ export const useNetBirdClient = () => { }, []); const detectSSHServerType = useCallback( - async (host: string, port: number): Promise => { + async (host: string, port: number, timeoutMs: number): Promise => { if (!netBirdClient.current?.detectSSHServerType) { throw new Error("NetBird client not ready"); } - return netBirdClient.current.detectSSHServerType(host, port); + return netBirdClient.current.detectSSHServerType(host, port, timeoutMs); }, [], ); @@ -228,7 +228,12 @@ export const useNetBirdClient = () => { if (!netBirdClient.current?.createSSHConnection) { throw new Error("Go client not ready"); } - return netBirdClient.current.createSSHConnection(host, port, username); + return netBirdClient.current.createSSHConnection( + host, + port, + username, + jwtToken, + ); }, [], ); diff --git a/src/utils/config.ts b/src/utils/config.ts index 0928f47d..c1b0ba8e 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -68,7 +68,7 @@ const loadConfig = (): Config => { googleAnalyticsID: configJson?.googleAnalyticsID || undefined, googleTagManagerID: configJson?.googleTagManagerID || undefined, wasmPath: - configJson?.wasmPath || "https://pkgs.netbird.io/wasm/client/v0.60.0", + configJson?.wasmPath || "https://pkgs.netbird.io/wasm/client/v0.60.2", } as Config; };