From e7758d61ae84cf3a3f73d2966b89de932f14d11a Mon Sep 17 00:00:00 2001 From: Garfieldcmix Date: Thu, 31 Jul 2025 23:46:11 +0700 Subject: [PATCH 1/3] Add SSH known hosts prompt handling --- lua/remote-sshfs/connections.lua | 63 +++++++++++++++++++++++++++++++- lua/remote-sshfs/init.lua | 1 + 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/lua/remote-sshfs/connections.lua b/lua/remote-sshfs/connections.lua index a98fa2d..55c19f8 100644 --- a/lua/remote-sshfs/connections.lua +++ b/lua/remote-sshfs/connections.lua @@ -5,6 +5,7 @@ local handler = require "remote-sshfs.handler" local config = {} local hosts = {} local ssh_configs = {} +local ssh_known_hosts = nil local sshfs_args = {} -- Current connection @@ -18,6 +19,7 @@ M.setup = function(opts) config = opts utils.setup_sshfs(config) ssh_configs = config.connections.ssh_configs + ssh_known_hosts = config.connections.ssh_known_hosts sshfs_args = config.connections.sshfs_args hosts = utils.parse_hosts_from_configs(ssh_configs) end @@ -131,6 +133,63 @@ M.mount_host = function(host, mount_dir, ask_pass) -- Mount point table.insert(cmd, mount_dir) + local function ensure_ssh_host_key(callback) + assert(ssh_known_hosts, "ssh_known_hosts is required") + + local hostname = host["HostName"] or host["Name"] + + -- Check if host is known + local known_info = vim.fn.system { "ssh-keygen", "-F", hostname, "-f", ssh_known_hosts } + if known_info:find "found" then + print("Host key for " .. hostname .. " already known.") + callback() + return true + end + + -- Get fingerprint + local scan = vim.fn.system("ssh-keyscan -t ed25519 " .. hostname .. " 2>/dev/null") + if scan == "" then + vim.notify("Could not get fingerprint for " .. hostname, vim.log.levels.ERROR) + return false + end + + local fingerprint = vim.fn.system('echo "' .. scan .. '" | ssh-keygen -lf -') + if fingerprint == "" then + vim.notify("Could not parse fingerprint for " .. hostname, vim.log.levels.ERROR) + return false + end + fingerprint = fingerprint:gsub("\n", "") + + local prompt = string.format( + [[ +The authenticity of host '%s' can't be established. +%s +Add this host key to %s? +]], + hostname, + fingerprint, + ssh_known_hosts + ) + + vim.schedule(function() + ui.prompt_yes_no(prompt, function(item_short) + ui.clear_prompt() + if item_short == "y" then + local scan_cmd = string.format("ssh-keyscan %s >> %s", hostname, ssh_known_hosts) + local result = vim.fn.system(scan_cmd) + if vim.v.shell_error == 0 then + vim.notify("Host key added for " .. hostname, vim.log.levels.INFO) + callback() + else + vim.notify("Failed to add host key for " .. hostname .. "\n" .. result, vim.log.levels.ERROR) + end + else + vim.notify("Aborted adding host key for " .. hostname, vim.log.levels.WARN) + end + end) + end) + end + local function start_job() vim.notify("Connecting to host (" .. (host["Name"] or target_host) .. ")...") local skip_clean = false @@ -176,7 +235,9 @@ M.mount_host = function(host, mount_dir, ask_pass) vim.fn.chansend(id, password .. "\n") end end - start_job() + ensure_ssh_host_key(function() + start_job() + end) end M.unmount_host = function() diff --git a/lua/remote-sshfs/init.lua b/lua/remote-sshfs/init.lua index 1063caa..0075483 100644 --- a/lua/remote-sshfs/init.lua +++ b/lua/remote-sshfs/init.lua @@ -7,6 +7,7 @@ local default_opts = { "/etc/ssh/ssh_config", -- "/path/to/custom/ssh_config" }, + ssh_known_hosts = vim.fn.expand "$HOME" .. "/.ssh/known_hosts", sshfs_args = { "-o reconnect", "-o ConnectTimeout=5", From 1aaa5a0c268d144f89c5d0c42ab2e4cca606c3c7 Mon Sep 17 00:00:00 2001 From: Garfieldcmix Date: Wed, 6 Aug 2025 12:15:46 +0700 Subject: [PATCH 2/3] Fix prompt sometime disapearing --- lua/remote-sshfs/connections.lua | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lua/remote-sshfs/connections.lua b/lua/remote-sshfs/connections.lua index 55c19f8..49c3968 100644 --- a/lua/remote-sshfs/connections.lua +++ b/lua/remote-sshfs/connections.lua @@ -161,16 +161,11 @@ M.mount_host = function(host, mount_dir, ask_pass) fingerprint = fingerprint:gsub("\n", "") local prompt = string.format( - [[ -The authenticity of host '%s' can't be established. -%s -Add this host key to %s? -]], + "The authenticity of host '%s' can't be established. %s Add this host key to %s? (y/n)", hostname, fingerprint, ssh_known_hosts ) - vim.schedule(function() ui.prompt_yes_no(prompt, function(item_short) ui.clear_prompt() From e212b895c2df51859c41ba65f6dbf353e7824cc0 Mon Sep 17 00:00:00 2001 From: Garfieldcmix Date: Wed, 6 Aug 2025 12:21:19 +0700 Subject: [PATCH 3/3] Update README.md about SSH known hosts prompt handling --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index bbd0e55..74d3a30 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ require('remote-sshfs').setup{ "/etc/ssh/ssh_config", -- "/path/to/custom/ssh_config" }, + ssh_known_hosts = vim.fn.expand "$HOME" .. "/.ssh/known_hosts", -- NOTE: Can define ssh_configs similarly to include all configs in a folder -- ssh_configs = vim.split(vim.fn.globpath(vim.fn.expand "$HOME" .. "/.ssh/configs", "*"), "\n") sshfs_args = { -- arguments to pass to the sshfs command @@ -291,6 +292,7 @@ Using the full config is quicker if plenary is already managed by your setup, bu - Password handling: When key-based authentication isn't used, you'll be prompted to enter a password/passphrase, which is piped to `sshfs -o password_stdin`. Ensure your SSH server allows password auth or use an SSH agent. - Default mount directory: By default, mounts go into `~/.sshfs//`. Override `mounts.base_dir` in your setup if you'd like a different location. - Key-based authentication: This plugin relies on your local SSH config and agent for auth. Make sure `ssh-agent` is running and your keys are loaded, or configure `IdentityFile` in your SSH config. +- Known hosts management: If the target host is not already listed in `known_hosts`, the user will be prompted with its fingerprint and given the choice to trust and store it. ## 🌟 Credits