Skip to content

Commit 7ba04a9

Browse files
feat: add SSH known hosts prompt handling (#55)
1 parent a2f3f14 commit 7ba04a9

3 files changed

Lines changed: 60 additions & 1 deletion

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ require('remote-sshfs').setup{
7070
"/etc/ssh/ssh_config",
7171
-- "/path/to/custom/ssh_config"
7272
},
73+
ssh_known_hosts = vim.fn.expand "$HOME" .. "/.ssh/known_hosts",
7374
-- NOTE: Can define ssh_configs similarly to include all configs in a folder
7475
-- ssh_configs = vim.split(vim.fn.globpath(vim.fn.expand "$HOME" .. "/.ssh/configs", "*"), "\n")
7576
sshfs_args = { -- arguments to pass to the sshfs command
@@ -308,6 +309,7 @@ Using the full config is quicker if plenary is already managed by your setup, bu
308309
- 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.
309310
- Default mount directory: By default, mounts go into `~/.sshfs/<host>/`. Override `mounts.base_dir` in your setup if you'd like a different location.
310311
- 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.
312+
- 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.
311313

312314
## 🌟 Credits
313315

lua/remote-sshfs/connections.lua

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ local handler = require "remote-sshfs.handler"
55
local config = {}
66
local hosts = {}
77
local ssh_configs = {}
8+
local ssh_known_hosts = nil
89
local sshfs_args = {}
910

1011
-- Current connection
@@ -18,6 +19,7 @@ M.setup = function(opts)
1819
config = opts
1920
utils.setup_sshfs(config)
2021
ssh_configs = config.connections.ssh_configs
22+
ssh_known_hosts = config.connections.ssh_known_hosts
2123
sshfs_args = config.connections.sshfs_args
2224
hosts = utils.parse_hosts_from_configs(ssh_configs)
2325
end
@@ -131,6 +133,58 @@ M.mount_host = function(host, mount_dir, ask_pass)
131133
-- Mount point
132134
table.insert(cmd, mount_dir)
133135

136+
local function ensure_ssh_host_key(callback)
137+
assert(ssh_known_hosts, "ssh_known_hosts is required")
138+
139+
local hostname = host["HostName"] or host["Name"]
140+
141+
-- Check if host is known
142+
local known_info = vim.fn.system { "ssh-keygen", "-F", hostname, "-f", ssh_known_hosts }
143+
if known_info:find "found" then
144+
print("Host key for " .. hostname .. " already known.")
145+
callback()
146+
return true
147+
end
148+
149+
-- Get fingerprint
150+
local scan = vim.fn.system("ssh-keyscan -t ed25519 " .. hostname .. " 2>/dev/null")
151+
if scan == "" then
152+
vim.notify("Could not get fingerprint for " .. hostname, vim.log.levels.ERROR)
153+
return false
154+
end
155+
156+
local fingerprint = vim.fn.system('echo "' .. scan .. '" | ssh-keygen -lf -')
157+
if fingerprint == "" then
158+
vim.notify("Could not parse fingerprint for " .. hostname, vim.log.levels.ERROR)
159+
return false
160+
end
161+
fingerprint = fingerprint:gsub("\n", "")
162+
163+
local prompt = string.format(
164+
"The authenticity of host '%s' can't be established. %s Add this host key to %s? (y/n)",
165+
hostname,
166+
fingerprint,
167+
ssh_known_hosts
168+
)
169+
vim.schedule(function()
170+
ui.prompt_yes_no(prompt, function(item_short)
171+
ui.clear_prompt()
172+
if item_short == "y" then
173+
local scan_cmd = string.format("ssh-keyscan %s >> %s", hostname, ssh_known_hosts)
174+
local result = vim.fn.system(scan_cmd)
175+
if vim.v.shell_error == 0 then
176+
vim.notify("Host key added for " .. hostname, vim.log.levels.INFO)
177+
callback()
178+
else
179+
vim.notify("Failed to add host key for " .. hostname .. "\n" .. result, vim.log.levels.ERROR)
180+
end
181+
else
182+
vim.notify("Aborted adding host key for " .. hostname, vim.log.levels.WARN)
183+
end
184+
end)
185+
end)
186+
end
187+
134188
local function start_job()
135189
vim.notify("Connecting to host (" .. (host["Name"] or target_host) .. ")...")
136190
local skip_clean = false
@@ -176,7 +230,9 @@ M.mount_host = function(host, mount_dir, ask_pass)
176230
vim.fn.chansend(id, password .. "\n")
177231
end
178232
end
179-
start_job()
233+
ensure_ssh_host_key(function()
234+
start_job()
235+
end)
180236
end
181237

182238
M.unmount_host = function()

lua/remote-sshfs/init.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ local default_opts = {
77
"/etc/ssh/ssh_config",
88
-- "/path/to/custom/ssh_config"
99
},
10+
ssh_known_hosts = vim.fn.expand "$HOME" .. "/.ssh/known_hosts",
1011
sshfs_args = {
1112
"-o reconnect",
1213
"-o ConnectTimeout=5",

0 commit comments

Comments
 (0)