Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,14 @@ CATEGORY:
client

OPTIONS:
--ssh-path value Path to SSH binary. Defaults to ssh on Unix, C:\Windows\System32\OpenSSH\ssh.exe on Windows (default: "ssh") [$NVRH_CLIENT_SSH_PATH]
--ssh-path value Path to SSH binary. 'binary' will use the default system SSH binary. 'internal' will use the internal SSH client. Anything else will be used as the path to the SSH binary (default: "binary") [$NVRH_CLIENT_SSH_PATH]
--use-ports Use ports instead of sockets. Defaults to true on Windows (default: false) [$NVRH_CLIENT_USE_PORTS]
--debug (default: false) [$NVRH_CLIENT_DEBUG]
--server-env value [ --server-env value ] Environment variables to set on the remote server
--local-editor value [ --local-editor value ] Local editor to use. {{SOCKET_PATH}} will be replaced with the socket path (default: "nvim", "--server", "{{SOCKET_PATH}}", "--remote-ui")
--server-env value [ --server-env value ] Environment variables to set on the remote server [$NVRH_CLIENT_SERVER_ENV]
--local-editor value [ --local-editor value ] Local editor to use. {{SOCKET_PATH}} will be replaced with the socket path (default: "nvim", "--server", "{{SOCKET_PATH}}", "--remote-ui") [$NVRH_CLIENT_LOCAL_EDITOR]
--nvim-cmd nvim [ --nvim-cmd nvim ] Command to run nvim with. Defaults to nvim (default: "nvim") [$NVRH_CLIENT_NVIM_CMD]
--ssh-arg value [ --ssh-arg value ] Additional arguments to pass to the SSH command [$NVRH_CLIENT_SSH_ARG]
--enable-automap-ports Enable automatic port mapping (default: true) [$NVRH_CLIENT_AUTOMAP_PORTS]
--help, -h show help
```

Expand All @@ -56,6 +59,29 @@ nvrh client open \
--local-editor {{SOCKET_PATH}}
```

### `nvrh client reconnect`

Reconnect to an existing nvrh session.

```
NAME:
nvrh client reconnect - Reconnect to an existing remote nvim instance

USAGE:
nvrh client reconnect [command options] <server> <session-id>

CATEGORY:
client

OPTIONS:
--ssh-path value Path to SSH binary. 'binary' will use the default system SSH binary. 'internal' will use the internal SSH client. Anything else will be used as the path to the SSH binary (default: "binary") [$NVRH_CLIENT_SSH_PATH]
--use-ports Use ports instead of sockets. Defaults to true on Windows (default: false) [$NVRH_CLIENT_USE_PORTS]
--debug (default: false) [$NVRH_CLIENT_DEBUG]
--local-editor value [ --local-editor value ] Local editor to use. {{SOCKET_PATH}} will be replaced with the socket path (default: "nvim", "--server", "{{SOCKET_PATH}}", "--remote-ui") [$NVRH_CLIENT_LOCAL_EDITOR]
--ssh-arg value [ --ssh-arg value ] Additional arguments to pass to the SSH command [$NVRH_CLIENT_SSH_ARG]
--help, -h show help
```

### `:NvrhTunnelPort`

https://github.com/user-attachments/assets/4a8c302e-4e49-4f74-81a3-ac86ba33016a
Expand Down
38 changes: 36 additions & 2 deletions src/client/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,26 @@ var CliClientOpenCommand = cli.Command{
EnvVars: []string{"NVRH_CLIENT_LOCAL_EDITOR"},
Value: cli.NewStringSlice("nvim", "--server", "{{SOCKET_PATH}}", "--remote-ui"),
},

&cli.StringSliceFlag{
Name: "nvim-cmd",
Usage: "Command to run nvim with. Defaults to `nvim`",
EnvVars: []string{"NVRH_CLIENT_NVIM_CMD"},
Value: cli.NewStringSlice("nvim"),
},

&cli.StringSliceFlag{
Name: "ssh-arg",
Usage: "Additional arguments to pass to the SSH command",
EnvVars: []string{"NVRH_CLIENT_SSH_ARG"},
},

&cli.BoolFlag{
Name: "enable-automap-ports",
Usage: "Enable automatic port mapping",
EnvVars: []string{"NVRH_CLIENT_AUTOMAP_PORTS"},
Value: true,

Copilot AI Aug 4, 2025

Copy link

Choose a reason for hiding this comment

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

[nitpick] The default value of true for enable-automap-ports could be surprising to users since it enables potentially resource-intensive functionality by default. Consider defaulting to false for safer behavior.

Suggested change
Value: true,
Value: false,

Copilot uses AI. Check for mistakes.
},
},

Action: func(c *cli.Context) error {
Expand Down Expand Up @@ -119,13 +139,18 @@ var CliClientOpenCommand = cli.Command{

RemoteSocketPath: fmt.Sprintf("/tmp/nvrh-socket-%s", sessionId),
LocalSocketPath: filepath.Join(os.TempDir(), fmt.Sprintf("nvrh-socket-%s", sessionId)),
AutomapPorts: c.Bool("enable-automap-ports"),

BrowserScriptPath: fmt.Sprintf("/tmp/nvrh-browser-%s", sessionId),

SshPath: sshPath,
Debug: isDebug,

TunneledPorts: make(map[string]bool),

NvimCmd: c.StringSlice("nvim-cmd"),

SshArgs: c.StringSlice("ssh-arg"),
}

if nvrhContext.SshPath == "internal" {
Expand Down Expand Up @@ -285,6 +310,12 @@ var CliClientReconnectCommand = cli.Command{
EnvVars: []string{"NVRH_CLIENT_LOCAL_EDITOR"},
Value: cli.NewStringSlice("nvim", "--server", "{{SOCKET_PATH}}", "--remote-ui"),
},

&cli.StringSliceFlag{
Name: "ssh-arg",
Usage: "Additional arguments to pass to the SSH command",
EnvVars: []string{"NVRH_CLIENT_SSH_ARG"},
},
},

Action: func(c *cli.Context) error {
Expand Down Expand Up @@ -324,6 +355,7 @@ var CliClientReconnectCommand = cli.Command{
BrowserScriptPath: fmt.Sprintf("/tmp/nvrh-browser-%s", sessionId),
SshPath: sshPath,
Debug: isDebug,
SshArgs: c.StringSlice("ssh-arg"),
}

portNumberString := c.Args().Get(2)
Expand Down Expand Up @@ -541,7 +573,8 @@ vim.fn.writefile(vim.fn.split(script_contents, '\n'), browser_script_path)
os.execute('chmod +x ' .. browser_script_path)
`, nil, nvrhContext.BrowserScriptPath, nvrhContext.RemoteSocketOrPort(), nv.ChannelID())

batch.ExecLua(`
if nvrhContext.AutomapPorts {
batch.ExecLua(`
local nvrh_port_scanner = {
active_watchers = {},

Expand Down Expand Up @@ -605,7 +638,8 @@ vim.api.nvim_create_autocmd("TermOpen", {
nvrh_port_scanner.attach_port_watcher(args.buf)
end,
})
`, nil)
`, nil)
}

batch.ExecLua(`
local original_open = vim.ui.open
Expand Down
8 changes: 6 additions & 2 deletions src/context/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type NvrhContext struct {
ShouldUsePorts bool
LocalPortNumber int
RemotePortNumber int
AutomapPorts bool

RemoteEnv []string
LocalEditor []string
Expand All @@ -26,10 +27,13 @@ type NvrhContext struct {

CommandsToKill []*exec.Cmd

SshPath string
Debug bool
Debug bool

SshPath string
SshClient nvrh_base_ssh.BaseNvrhSshClient
SshArgs []string

NvimCmd []string

TunneledPorts map[string]bool
}
Expand Down
5 changes: 4 additions & 1 deletion src/nvim_helpers/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ func BuildRemoteCommandString(nvrhContext *context.NvrhContext) string {
envPairsString = strings.Join(nvrhContext.RemoteEnv, " ")
}

nvimCmd := strings.Join(nvrhContext.NvimCmd, " ")

Copilot AI Aug 4, 2025

Copy link

Choose a reason for hiding this comment

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

Joining command arguments with spaces without proper escaping could lead to command injection if the arguments contain special characters. Consider using proper shell escaping or validation for the NvimCmd arguments.

Copilot uses AI. Check for mistakes.

return fmt.Sprintf(
"%s nvim --headless --listen \"%s\"",
"%s %s --headless --listen \"%s\"",
envPairsString,
nvimCmd,
nvrhContext.RemoteSocketOrPort(),
)
}
6 changes: 5 additions & 1 deletion src/nvrh_binary_ssh/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ func (c *NvrhBinarySshClient) Run(command string, tunnelInfo *ssh_tunnel_info.Ss
args = append(args, "-L", tunnelInfo.BoundToIp())
}

args = append(args, "-t", c.Ctx.Endpoint.Given, command)
if c.Ctx.SshArgs != nil && len(c.Ctx.SshArgs) > 0 {
args = append(args, c.Ctx.SshArgs...)
Comment on lines +27 to +28

Copilot AI Aug 4, 2025

Copy link

Choose a reason for hiding this comment

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

Adding the -- separator is good for security, but the SSH arguments are inserted before the endpoint which could allow argument injection. Consider validating SSH arguments or placing them after the endpoint to prevent potential command injection.

Suggested change
if c.Ctx.SshArgs != nil && len(c.Ctx.SshArgs) > 0 {
args = append(args, c.Ctx.SshArgs...)
// Validate SSH arguments to prevent argument injection
if c.Ctx.SshArgs != nil && len(c.Ctx.SshArgs) > 0 {
validArgs := validateSshArgs(c.Ctx.SshArgs)
args = append(args, validArgs...)

Copilot uses AI. Check for mistakes.
}

args = append(args, "-t", c.Ctx.Endpoint.Given, "--", command)

slog.Debug("Running command via SSH", "command", command)

Expand Down