Skip to content

Extract conch_remote crate for mobile support#68

Merged
an0nn30 merged 14 commits intomainfrom
feat/extract-conch-remote
Mar 20, 2026
Merged

Extract conch_remote crate for mobile support#68
an0nn30 merged 14 commits intomainfrom
feat/extract-conch-remote

Conversation

@an0nn30
Copy link
Owner

@an0nn30 an0nn30 commented Mar 20, 2026

Summary

  • New conch_remote crate — extracts all SSH/SFTP/tunnel/transfer logic from conch_tauri into a platform-agnostic library that both desktop and future mobile apps can share
  • Unified SSH handler — merges the duplicated SshHandler and TunnelSshHandler into a single ConchSshHandler backed by a RemoteCallbacks trait
  • Path abstraction — replaces all hardcoded ~/.ssh/ and ~/.config/conch/ paths with injectable RemotePaths, enabling iOS sandbox/iCloud paths
  • JNI feature-gatedconch_plugin's JNI dependency is now behind a java feature flag so mobile can compile without it
  • Design spec + implementation plan — full documentation for the iOS mobile SSH client (Phase 1 of 6)

Details

New crate: conch_remote

  • callbacks.rsRemoteCallbacks trait + RemotePaths config struct
  • handler.rs — unified ConchSshHandler implementing russh::client::Handler
  • ssh.rs — connection, auth, channel loop (ProxyCommand gated for iOS)
  • sftp.rs — SFTP operations
  • transfer.rs — file transfer engine with progress
  • tunnel.rs — tunnel manager (eliminated all duplicated auth/proxy code)
  • config.rs — server config with path-parameterized persistence
  • known_hosts.rs — OpenSSH known_hosts with path parameter

Changes to conch_tauri

  • mod.rs rewritten as thin wrappers delegating to conch_remote
  • TauriRemoteCallbacks bridges RemoteCallbacks to Tauri events
  • ~2,400 lines of duplicated code removed
  • All 6 old remote module files deleted

conch_plugin

  • jni dependency gated behind java feature (default enabled)
  • cfg(java_sdk_available) replaced with cfg(feature = "java")
  • Dead build.rs cfg emission removed

Test plan

  • cargo test --workspace — 234 tests pass (up from 218 baseline)
  • cargo check -p conch_remote — compiles independently
  • cargo check -p conch_plugin --no-default-features — compiles without JNI
  • cargo build -p conch_tauri — desktop app builds
  • cargo clippy --workspace — no errors

an0nn30 added 14 commits March 20, 2026 14:14
Covers workspace restructuring (conch_remote extraction, conch_mobile
crate), purpose-built mobile frontend, iCloud config sync, iOS platform
constraints, and phased delivery plan.
Rewrite conch_tauri/src/remote/mod.rs to delegate all SSH, SFTP,
transfer, tunnel, and config operations to conch_remote instead of
local module implementations. Key changes:

- Add TauriRemoteCallbacks implementing RemoteCallbacks trait,
  bridging host key and password prompts to Tauri events
- Add desktop_remote_paths() for platform path configuration
- Move PendingPrompts to Arc<Mutex<>> for shared access from callbacks
- Simplify ssh_connect/ssh_quick_connect by removing prompt bridge
  spawn tasks (~60 lines each) in favor of callbacks pattern
- Update tunnel_start to pass callbacks + paths to TunnelManager
- Update all config commands to use conch_remote::config::save_config
  with explicit config_dir path
- Update all SFTP/transfer commands to delegate to conch_remote
- Delete 6 old module files (ssh.rs, sftp.rs, config.rs,
  known_hosts.rs, transfer.rs, tunnel.rs) totaling ~2400 lines
- Remove direct russh/russh-keys/russh-sftp/ssh-key/base64 deps
  from conch_tauri Cargo.toml (now transitive via conch_remote)
- Add 2 new tests (pending_prompts_new_is_empty,
  desktop_remote_paths_populated)

All 234 workspace tests pass. Net: -2407 lines.
@an0nn30 an0nn30 merged commit f660247 into main Mar 20, 2026
4 checks passed
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f85462ca92

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +61 to +62
#[cfg(target_os = "ios")]
let effective_proxy: Option<String> = None;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject proxied iOS SSH sessions instead of bypassing the proxy

On target_os = "ios" this hardcodes effective_proxy to None, so the return Err("Proxy connections are not supported on iOS") branch below is unreachable and client::connect(...) runs even when server.proxy_command or proxy_jump is configured. Any mobile SSH session that depends on a bastion/ProxyCommand will now silently ignore that setting and fail with a misleading direct-connection error.

Useful? React with 👍 / 👎.

Comment on lines +243 to +244
#[cfg(target_os = "ios")]
let effective_proxy: Option<String> = None;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject proxied iOS tunnels instead of connecting directly

The tunnel path has the same issue as interactive SSH: on iOS we force effective_proxy to None, so the unsupported-proxy error at lines 252-255 can never fire and connect_for_tunnel attempts a direct TCP connection instead. Tunnels that require ProxyJump/ProxyCommand will therefore be broken on mobile and report the wrong failure mode.

Useful? React with 👍 / 👎.

Comment on lines 188 to 192
let key_paths: Vec<PathBuf> = if let Some(path) = explicit_key_path {
vec![expand_tilde(path)]
} else {
let home = dirs::home_dir().unwrap_or_default();
let ssh_dir = home.join(".ssh");
vec![
ssh_dir.join("id_ed25519"),
ssh_dir.join("id_rsa"),
ssh_dir.join("id_ecdsa"),
]
default_key_paths.to_vec()
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Support Keychain-backed auth before emptying iOS key paths

try_key_auth only looks at explicit_key_path and default_key_paths. In this extraction, RemotePaths documents that iOS leaves default_key_paths empty because keys live in Keychain, but there is no callback or other hook here to fetch a Keychain private key. For the intended mobile setup, any auth_method == "key" server without an explicit file path will immediately exhaust this list and fail authentication for both shells and tunnels.

Useful? React with 👍 / 👎.

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