Allow SSH connections to be routed through SOCKS5 or HTTP CONNECT proxies.
Backend:
- Add ProxyType, ProxyHost, ProxyPort, ProxyUsername, ProxyPassword to SSHConfig
- dialTarget() dispatches to direct TCP, SOCKS5, or HTTP CONNECT based on config
- SOCKS5: uses golang.org/x/net/proxy with optional username/password auth
- HTTP CONNECT: sends CONNECT request with optional Basic auth, validates 200 OK
- Proxy dialling replaces ssh.Dial for non-jump-host connections; the resulting
net.Conn is passed to ssh.NewClientConn for the SSH handshake
Frontend:
- Add Proxy section to SSH profile editor (collapsed by default)
- Proxy type selector: None / SOCKS5 / HTTP CONNECT
- Host, port, username, password fields
- Collect proxy values on save
Automatically generate and submit TOTP codes during SSH keyboard-interactive
authentication when a secret is configured for the profile.
Backend:
- Add TOTPSecret field to SSHConfig model
- Detect TOTP/2FA prompts in keyboard-interactive handler using keyword
matching (verification code, otp, authenticator, 2fa, etc.)
- Generate 6-digit TOTP codes using pquerna/otp library
- Retrieve TOTP secret from vault during connection (keychain or file vault)
- API: SetTOTPSecret, GetTOTPCode, HasTOTPSecret, DeleteTOTPSecret
Frontend:
- Add TOTP/2FA section to SSH profile editor (collapsed by default)
- Password-masked secret input with show/hide toggle
- Save button: encrypts and stores in vault
- Test button: generates a live 6-digit code (shown for 5 seconds)
- Delete button: removes stored secret
- Auto-detect whether secret is already saved (placeholder indicator)
- CSS for TOTP input row, danger button style
Implement expect-style auto-login scripts for SSH and Telnet connections.
Each script is an ordered list of 'wait' (match text in output) and 'send'
(write text + newline) steps that execute sequentially after connection.
Backend:
- Add LoginScriptStep model (type, value, timeout) to models.go
- Add loginScripts field to SSHConfig and TelnetConfig
- Add loginBuf/loginDone on Session struct for output buffering
- Hook onData callbacks to feed login buffer during script execution
- executeLoginScripts() runs steps in a goroutine after connect
- waitForOutput() polls session buffer with configurable timeout
Frontend:
- Add _renderLoginScriptSection() to profile editor
- Interactive step list: add/remove/reorder wait and send steps
- Type selector, value input, timeout for wait steps
- Collect loginScripts as JSON from hidden field
- CSS for login script rows, actions, add buttons
Sessions configured with auto-reconnect will automatically attempt to
re-establish the connection when unexpectedly disconnected. Uses
exponential backoff (1s, 2s, 4s, 8s... up to 30s) with a configurable
maximum number of attempts (default 5).
- New SessionReconnecting state with pulsing indicator in tab bar
- SSH and Telnet profiles gain autoReconnect and maxReconnectTries fields
- RAW protocol already had autoReconnect; now uses the shared mechanism
- CancelReconnect API to abort in-progress reconnection
- Frontend shows reconnect attempt notifications
- Profile editor exposes toggle and max attempts in Advanced/Reconnection
Argon2id:
- Increase memory parameter from 64 MiB to 128 MiB for stronger KDF
SSH Agent:
- Add agent.go with connectAgent(), agentAuthMethod(), requestAgentForwarding()
- Integrate agent auth into buildAuthMethods() (tried first when enabled)
- Set up agent forwarding after PTY allocation when agentForwarding is true
- Track and clean up agent socket connection on session close
- Add AgentAuth and AgentForwarding fields to SSHConfig model
- Add SSH Agent section to profile editor with toggle controls
Port Forwarding (new):
- Add PortForward model with local/remote direction, bind/dest addresses
- Implement ForwardManager in sshclient/portforward.go with full
bidirectional tunnel support for both local and remote forwarding
- Integrate ForwardManager into SSH client lifecycle (auto-start on
connect, clean shutdown on close)
- Add session manager methods: ListPortForwards, StartPortForward,
StopPortForward with event emission
- Add API surface: ListPortForwards, StartPortForward, StopPortForward
- Add validation for port-forward rules in ValidateSSHConfig
- Add port forwarding section to profile editor with direction, bind/dest
host/port, label, and enable toggle
- Add frontend event handling for forward:started/stopped/error
- Style port-forward rows with charcoal card design matching jump hosts
Jump Host UI improvements:
- Add private key path field to jump host editor rows
- Collect privateKeyPath in form value collection
- Restyle jump host rows as two-line cards with clear field grouping
New protocol type 'github' for browsing repositories via the GitHub REST API.
Creates a non-terminal panel showing repos grouped by owner/org, sorted by
last commit date (newest first), with search filtering and auto-refresh.
Backend:
- ProtocolGitHub constant and GitHubConfig/GitHubRepo model structs
- New internal/githubclient package (REST API, pagination, token validation)
- Session manager connectGitHub() with periodic refresh goroutine
- API surface: RefreshGitHubRepos() for on-demand refresh
- Token stored via existing credential infrastructure (keychain/vault)
Frontend:
- GitHub tab in profile editor with API URL and token storage fields
- New github.js viewer component (grouped repos, badges, language dots)
- github.css with charcoal-themed repo cards and org headers
- Protocol colour tokens, tab badge, sidebar indicator for GitHub
- Event wiring for session:github:repos and session:github:error
- Cleanup on tab close
Supports GitHub Enterprise via configurable API base URL.
Sidebar:
- Profiles are now organised into group-based sections
- Groups appear alphabetically between Favourites/Recent and Ungrouped
- Section key uses 'group:Name' prefix to avoid collisions
- Ungrouped profiles fall into 'Ungrouped' (or 'All Connections' if
no groups exist)
Profile editor:
- Add Group combo-box field to General section
- Uses HTML datalist backed by distinct group names from all profiles
- Typing a new name creates the group; selecting existing reuses it
- Help text explains the behaviour
Save handler:
- folder field now collected from form and trimmed
The Go model already had a 'folder' field — this change wires it
into the UI end-to-end.
Tab close confirmation:
- Add is-visible to both backdrop AND modal element — the modal CSS
starts with visibility:hidden/opacity:0, so the modal was invisible
despite the backdrop blur appearing
Section headers (sidebar + profile editor):
- Add mousedown preventDefault() on all clickable section headers —
WKWebView initiates a text selection gesture on mousedown for divs,
swallowing the first click and requiring a double-click
- Fix sidebar delete profile to use custom modal instead of blocked
window.confirm()
Credential storage:
- buildSecretCallback now respects profile's secretMode field:
- 'saved': checks keychain/vault first, prompts if missing, then
persists to keychain (preferred) or encrypted vault
- 'session-only': caches in memory per-session, prompts once
- 'ask-every-time': always prompts
- Previously the callback always prompted and never saved
- Change default secretMode from 'ask-every-time' to 'saved' in both
Go defaults and JS frontend defaults
- Change ConnectSession/ConnectQuick to return SessionInfo (not string)
- Change UpdateProfile to return (Profile, error) for frontend use
- Make session connection asynchronous to avoid Wails event loop deadlock
- Implement event-based secret prompt (backend ↔ frontend via requestID)
- Add TestConnection API for TCP reachability checks with latency
- Add 'Save & Connect' button in profile editor
- Wire _testConnection to real backend TCP check
- Add btn-accent CSS for the green action button
WebKit's WKWebView rejects top-level const/let declarations that shadow
global function names. Since utils.js defines functions like stateLabel()
at the global scope (non-module scripts), and later files destructure
the same names from window.NexusTerminal using const, WebKit throws:
SyntaxError: Can't create duplicate variable that shadows a global property
Fix: wrap every JS file in an IIFE so all declarations are function-scoped.
Also remove temporary diagnostic instrumentation.
Replace ES module import/export with a global namespace pattern to avoid
silent failures in the Wails v2 WKWebView which does not reliably support
<script type="module"> tags.
- Remove all import/export statements from JS files
- Register each module's exports on window.NexusTerminal
- Destructure dependencies from window.NexusTerminal at file top
- Load all scripts in dependency order in index.html as plain <script> tags