Skip to content

feat: connect over ssh and render shells in native terminal views - #2

Merged
iscekic merged 17 commits into
mainfrom
feat/connect
Nov 13, 2026
Merged

iscekic merged 17 commits into
mainfrom
feat/connect

Conversation

@iscekic

@iscekic iscekic commented Nov 13, 2026

Copy link
Copy Markdown
Collaborator

Adds SSH sessions to the Rust core and a native terminal view on both platforms.

  • Connect with password, private key (OpenSSH and PEM, with passphrase) or keyboard-interactive. The app decides host-key trust through a callback.
  • Shells stream bytes from Rust straight into the native view; JavaScript never sees terminal traffic. Exec, resize, keepalive and connect timeout are covered.
  • Terminal view: Termux terminal emulator on Android (vendored at v0.118.0 so it can host a non-local session) and SwiftTerm on iOS. Pinch zoom, selection and clipboard, link taps, hardware keyboard and IME input.
  • A closed shell reports closure and rejects input instead of dropping it.

Verified: Rust unit tests and the OpenSSH container suite (including ordered delivery of many single-byte writes); on an Android emulator, typing, vim, htop, Ctrl-C, 256 colours, rotation resize, pinch zoom, links, copy and paste, closure and reconnect. The macOS CI job verifies the iOS build.

The core now owns sessions end to end: uniffi `SshSession.connect` runs on a
tokio runtime inside the crate, authenticates with a password, a key or
keyboard-interactive prompts, and reports every host-key and prompt decision
through a `SessionHandler` callback.

- `open_shell` streams terminal output into a foreign `ByteSink` in chunk
  sized copies, so bytes never cross into JavaScript; input and resizes go
  through one ordered writer task per channel.
- `exec` returns stdout, stderr and the exit status; `disconnect` ends the
  session without a spurious disconnect callback.
- `parse_private_key` reads OpenSSH and PKCS#8/PKCS#1/SEC1 PEM (ed25519,
  RSA, ecdsa p256/p384) and distinguishes a wrong passphrase from an
  unsupported format.
- `SshError` carries the stable categories the binding layers expose; only
  transport failures are retryable, and a test ties that policy to the
  exported `category_is_retryable`.
- Kotlin and Swift modules expose connect/exec/disconnect/parsePrivateKey
  with prompt events answered by `answerHostKey`/`answerPrompts`, and
  `SshShellSource` implements the terminal slice's byte-source contract.
- A Docker OpenSSH server (password, two-prompt PAM, silent listener) backs
  an integration suite gated on `SSH_TEST_HOST`, with a CI job that starts
  the containers.
- TypeScript API with the error category union, and an example screen that
  asks for the host key in an alert and runs `uname -a`.
Native ReactNativeSshTerminal module: ReactNativeSshTerminalView over vendored Termux
terminal-emulator/terminal-view (Apache-2.0) on Android and SwiftTerm on iOS, a
TerminalByteSource/TerminalSink contract with a sourceId registry, a JS-fed
createFeedSource(), theme/font/cursor props, resize/link/bell/title/selection events,
sendInput/copySelection/paste/scrollToBottom commands, pinch zoom, 10k scrollback, an
example PTY-over-WebSocket demo and its node-pty server.
…ll close command

The Kotlin class definition rejected a null constructor, so the module failed to
register. ShellChannel.close collided with AutoCloseable.close in the generated
bindings, so the exported method is now shutdown.
The native view already read the Android clipboard but nothing could reach it from JS, so replace the one-time transport debug log with a pasteFromClipboard module function and wire Copy/Paste actions into the SSH terminal demo.
A closed shell used to swallow keystrokes silently; the view now marks the transport closed, refuses further writes and emits onClosed so the demo can show a closed state. Copying a selection trims the Termux range and ignores empty selections, and pasting reads the clipboard before sending it to the source. Rebinding a new source after a close recreates the terminal session.
@socket-security

socket-security Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​node-pty@​1.1.09310010097100

View full report

@iscekic
iscekic merged commit f4fd4f7 into main Nov 13, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant