Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Neovim compatibility (for terminal pinentry prompts) #32

Open
ghallberg opened this issue Apr 20, 2015 · 36 comments
Open

Neovim compatibility (for terminal pinentry prompts) #32

ghallberg opened this issue Apr 20, 2015 · 36 comments
Assignees
Milestone

Comments

@ghallberg
Copy link

neovim spawns shell commands connected to pipes, which prevents vim-gnupg from receiving input when asking for passphrase.

To make vim-gnupg work with neovim it would be great to see an updated version using termopen.

@jamessan jamessan added this to the 2.7 milestone Apr 21, 2015
@tarruda
Copy link

tarruda commented Nov 9, 2015

FWIW, I'm a long time vim-gnupg user and have been using it with neovim since day 1. I never had problems because I use gpg-agent which by defaults displays a x11 prompt to get the password(The GPG_TTY warning can be safely ignored).

With that said, it should be easy to make vim-gnupg compatible with neovim: You simply need to call jobstart passing the pty option, which will spawn the job in a headless pseudo terminal, and with jobwait you can wait for a job to finish. Here's a function that simulates system() but uses a new pty to run the program:

let s:Shell = {}

function s:Shell.on_stdout(jobid, data)
  let self.output .= a:data[0]
  for str in a:data[1:]
    let self.output .= "\n".str
  endfor
endfunction

let s:Shell.on_stderr = s:Shell.on_stdout

function! PTYSystem(cmd, ...)
  let s = extend({'output': '', 'pty': 1}, s:Shell)
  let job = jobstart(a:cmd, s)
  if a:0
    " send data plus newline plus ctrl+d to the terminal
    call jobsend(job, a:1."\n\x04")
  endif
  let [g:shell_error] = jobwait([job])
  return s.output
endfunction

This would require prompting the passwords with the inputsecret() function and feeding as the second argument of PTYSystem

@jamessan
Copy link
Owner

jamessan commented Nov 9, 2015

Thanks for the tips, @tarruda. I'll take another look at this after I finish packaging neovim for Debian.

@pmandera
Copy link

Hello! I was wondering if there is any progress with this issue? I am using neovim via tmux so the x11 prompt often does not work in this case and neovim hangs an entire window when asking for passpharse. Thanks for the great plugin anyway!

@jamessan
Copy link
Owner

Ok, I finally got Neovim packaged in Debian and will start taking a look at this.

Just as an FYI, neovim isn't actually hung. When encrypting a new file, you can type into the gpg prompt but you aren't going to see what's being typed. Other than that, it works fine. I've successfully created new encrypted files and opened existing files just fine.

Yes, it's not optimal but it is functional.

@jamessan jamessan self-assigned this Jan 27, 2016
@kierun
Copy link

kierun commented Mar 24, 2016

Any update on this?

Yes, of course, I can help test this on Fedora/CentOS/Ubuntu ☺

@sharethewisdom
Copy link

sharethewisdom commented Jun 15, 2016

Yes, it's not optimal but it is functional.

I've been playing around with the job control and pseudo terminal for a while now but I still didn't get it to work. I just wanted to point out that using pinentry-curses in a non-login shell, I need to keep an eye on the wildcards and count them: apart from the fact that the letters aren't always input into dialogue, some characters are also put into the decrypted file 😧. (I don't call that functional.)

Maybe the keys are passed through and the input is result of normal mode "i" command? (not sure)

This is likely insecure, and may not work, but I wanted to share the idea all the same: using pexpect in a remote plugin one could wait for the the spawned process (started with gpg2 -d --no-tty, no -q) to print ^gpg: encrypted with.* as a sign of successful decryption, then delete the first few lines and passing the file contents to stdout, where neovim should pick it up and load it into a buffer.

@galaux
Copy link

galaux commented Aug 25, 2016

As a complement/clarification to tarruda's comment, I would like to add that one can make vim-gnupg to work with NeoViM if one does not set gpg-agent to use pinentry-curses but any other X pinentry (make sure /usr/bin/pinentry points at pinentry-gtk-2 for instance and that setting pinentry-program is not set to …/pinentry-curses in ~/.gnupg/gpg-agent.conf).

Kind of a workaround of course but worth to be mentioned in my opinion.

@sharethewisdom
Copy link

any other X pinentry ...

Thanks but rather not, running a terminal using a compositor for Wayland, I would prefer to stick to a curses interface. If I can use it from other curses programs and for other uses, like signing commits and email, it feels like it should be possible to have a curses pinentry work from neovim.

The issue, I think, for me with neovim is that pinentry-curses seems to be running on /dev/ttyx, which obviously isn't the terminal connected to stdin.

@Integralist
Copy link

I'm using NeoVim on my mac 10.11.6 and it's NeoVim version v0.1.6-109-gdc6cc47 and when it asks me the passphrase I see nothing typed out and the program hangs. I can't quit it and need to shut my terminal tab down :-(

@jamessan
Copy link
Owner

Thanks to all the suggestions so far. I've already pushed some commits to fix issues related to the 'encoding' option, which will become more important once neovim/neovim#2905 is merged.

apart from the fact that the letters aren't always input into dialogue, some characters are also put into the decrypted file 😧. (I don't call that functional.)

Agreed. I don't know if I was just lucky before or didn't notice it, but it is essentially non-functional. The input randomly makes it to either nvim or the pinentry process.

This would require prompting the passwords with the inputsecret() function and feeding as the second argument of PTYSystem

I really don't like the idea of doing the password prompting in the plugin and passing it through. I removed a bunch of code that was just shuttling data between Vim and gpg when I took over maintenance of the plugin. I don't see a reason to reimplement what gpg already does just fine, and has the ability to do more securely.

That being said, I know that something needs to be done here and I'll be trying to focus my available FOSS time on this.

@kierun
Copy link

kierun commented Sep 21, 2016

@jamessan I, for one, really appreciate all your hard work. Thank you very much.

@hugomg
Copy link

hugomg commented May 8, 2017

One issue I encountered on Fedora 25 (GNOME with X, not Wayland) is that by default gnupg would not try to use the graphical password prompt, which seems to be the recommended workaround for this bug at the moment. I think this is due to this part of the script.

if (str2float(gpgversion) >= 2.1 || (exists("$GPG_AGENT_INFO") && g:GPGUseAgent == 1))
  "... stuff ...
  let s:GPGCommand .= " --use-agent"
else
    let s:GPGCommand .= " --no-use-agent"
endif

On my system, vim-gnupg tries to use gpg version 1.4 by default and the GPG_AGENT_INFO variable was unset so it falls into the "--no-use-agent" branch of the code. A workaround that worked for me was to edit my .config/nvim/init.vim to tell vim-gnupg that it should use gpg 2.1 instead:

let g:GPGExecutable = "gpg2 --trust-model always"

I hope this information might be helpful.

@ELLIOTTCABLE
Copy link

ELLIOTTCABLE commented Apr 10, 2018

I'm kinda a GPG newbie, and can't quite suss out a tl;dr from this Issue — is there a current path to editing GPG-encrypted messages in Neovim (well, VimR, for me) instead of Vim 8, on macOS?

(It sounds like some of you got it to work, but perhaps only on Linuxes?)

@kierun
Copy link

kierun commented Apr 11, 2018

@ELLIOTTCABLE If you have access to an X11 display, you can use the GPG graphical prompt. If not, you have to use vim

@jamessan
Copy link
Owner

kierun's advice is correct. The longer term solution is to use --pinentry-mode loopback, which I haven't gotten to yet. I'll probably end up doing that along with a conversion to using job control for better management of stdout/stderr.

@kierun
Copy link

kierun commented Jun 27, 2018

Any update on this?

Using mutt, I now use the gpg […] --textmode which works fine on console. Could you use that? ← I am clueless about that code.

@jamessan jamessan changed the title Neovim compatibility Neovim compatibility (for terminal pinentry prompts) Jun 27, 2018
@jamessan
Copy link
Owner

I don't see how --textmode helps here. That controls how gpg treats its input/output, not how pinentry interacts with the terminal.

@goerz
Copy link

goerz commented Mar 23, 2019

Is there any workaround for a headless server, where using an X11 pinentry program is not possible?

@kierun
Copy link

kierun commented Mar 25, 2019

@goerz Look into ~/.gnupg/gpg-agent.conf and set pinentry-program /usr/bin/pinentry-curses or where ever it resides on your system.

@sharethewisdom
Copy link

@kierun @goerz note that pinentry-curses from vim in a non-login shell still seems problematic (see my comment above). I'm not sure how this works through ssh in a login shell.

@jgyurkovitz
Copy link

jgyurkovitz commented Mar 26, 2019 via email

@jamessan
Copy link
Owner

I've been following this thread and I don't believe that this is an issue that vim-gnupg needs to address

It's not necessary for vim-gnupg to address it, but the biggest problem with Neovim support is that both pinentry and neovim are trying to use the same tty at the same time.

The current workaround is to use an X11 pinentry, which doesn't work when you're SSHing (unless you do X forwarding).

@czocher
Copy link

czocher commented Mar 27, 2019

... which doesn't work when you're SSHing (unless you do X forwarding).

It's enough to do a gpg-agent forwarding, you don't have to have X on the remote system:
https://wiki.gnupg.org/AgentForwarding
When you do that gpg will ask for the PIN on your local computer (where you probably have X). Also it uses your local gpg-keyring, which means you don't have to upload your keys to the remote system and you can use a local gpg-smartcard plugged in into your local computer.

@maxigaz
Copy link

maxigaz commented Dec 26, 2019

I’ve tried the plugin with Neovim running inside Kitty and Termux. In Kitty, about every 2nd and 3rd keypress is registered by the passphrase prompt, while in Termux, the prompt doesn’t appear at all; instead, I receive a “Message could not be decrypted!” error in Neovim’s status bar.

Since using an X11-based prompt on Termux is a no-go (at least locally), I went down a different road and tried running gpg --decrypt foo.bar.asc > /dev/null before opening it in Neovim. It works well in both cases, so I added the following keyboard shortcut to my ranger configuration for easy access:

map cg shell gpg --decrypt %s > /dev/null; nvim %s

@jamessan jamessan modified the milestones: 2.7, 3.0 May 10, 2020
@xanderdunn
Copy link

macOS 11.5.2
iTerm2 3.4.8
bash 5.1.8(1)-release
gpg 2.3.2
vim-gpg main branch:

commit 96be0be1240a848da56d665b38e1b0fe7ee3f1af (grafted, HEAD -> main, origin/main, origin/HEAD)
Author: James McCoy <jamessan@jamessan.com>
Date:   Wed Nov 11 15:57:22 2020 -0500

    Clean up the README

    Signed-off-by: James McCoy <jamessan@jamessan.com>

In my ~/.profile:

export "GPG_TTY=$(tty)"

I'm experiencing the same issue described above by several users: Some of my keystrokes on passphrase input are randomly not received. If I'm extremely patient and press some keys over and over until it's received I can eventually get through my whole passphrase. If I successfully open the text file, the passphrase keystrokes that weren't received by the pin entry are inserted into my text file. If I kill the pin entry capture, the missing keystrokes appear in my terminal prompt. This seems like particularly poor security given that many of the characters of my passphrase I'm typing are being piped to god-knows-where.

Setting pinentry-program /opt/homebrew/bin/pinentry-curses in ~/.gnupg/gpg-agent.conf had no effect on the problem.

Reading through the above comments I didn't find a workaround for my situation. I don't have X since I'm on macOS. Is the only solution to just not use the neovim terminal pin entry to unlock the gpg agent, as suggested by @maxigaz?

@kblcuk
Copy link

kblcuk commented Aug 31, 2021

@xanderdunn at least I got everything working locally with pinentry-mac and following Signing your git commits gist on M1 Air/Big Sur. Hopefully it will work for you as well!

@xanderdunn
Copy link

@kblcuk Setting pinentry-program /opt/homebrew/bin/pinentry-mac in ~/.gnupg/gpg-agent.conf did the trick for me, thanks!

@molleweide
Copy link

@kblcuk and @xanderdunn, when using pinentry-mac do you guys get prompted for the password inside neovim?
I switched to pinentry-mac now and it works but I don't get prompted for the password at all, even if I restart the gpg agent. So however, my commits are being signed, which is nice, but I don't understand how this works since I don't get prompted for the password. When I write that I don't get prompted for the password, this also applies to creating the commit in the CLI and not in Neovim, ie. I don't get prompted for pass either in Neovim or in the CLI.

@kblcuk
Copy link

kblcuk commented Mar 28, 2022

@molleweide if I recall correctly, it prompted for the password first time, and there was an option to save password to MacOS keychain, which I did.
Also the gist I linked to seems to support this theory 😀

@wakatara

This comment was marked as off-topic.

@jamessan
Copy link
Owner

@wakatara Please open a new issue, since this one is specific to the use of terminal pinentry prompts.

@gdbaldw
Copy link

gdbaldw commented Apr 1, 2023

A working solution: (perhaps vim-gnupg can script this, possibly as an exception handler)

$nvim /tmp/README.asc
error: Message could not be decrypted! (Press ENTER)
<Enter>
:terminal
(at NVim terminal prompt) $gpg --pinentry-mode loopback --out /dev/null -d /tmp/README.asc
(when prompted, enter password)
$exit
:q
:e /tmp/README.asc

maybebyte added a commit to maybebyte/dotfiles that referenced this issue Jul 18, 2023
gauravjuvekar added a commit to gauravjuvekar/dotvim that referenced this issue Nov 11, 2024
gauravjuvekar added a commit to gauravjuvekar/dotvim that referenced this issue Nov 11, 2024
@strottie
Copy link

Is this still an issue? I'm running NVIM 0.10.2 and it works fine with pinentry-curses: I get successfully prompted for my passphrase in full screen/tty.
(ssh + mosh + tmux, target system is RedHat Enterprise 8.9, no DISPLAY, GPG_TTY=tty, not loopback mode)

I have not tried vim-gnupg on nvim for a while so I can't say how recently this started working.

Here's the process stack to show how it's executed and wrapped in the shell:

$ ptree -pac 30399
zsh,30399
  └─nvim,32233 test.gpg
      └─nvim,32234 --embed test.gpg
          └─sh,32417 -c (gpg --trust-model always --use-agent --quiet --decrypt '/users/strottie/.config/nvim/test.gpg' 2>/dev/null) >/tmp/nvim.strottie/1YhQ7Y/0 2>&1
              └─gpg,32420 --trust-model always --use-agent --quiet --decrypt /users/strottie/.config/nvim/test.gpg

@ckjoris
Copy link

ckjoris commented Nov 13, 2024

Is this still an issue? I'm running NVIM 0.10.2 and it works fine with pinentry-curses: I get successfully prompted for my passphrase in full screen/tty. (ssh + mosh + tmux, target system is RedHat Enterprise 8.9, no DISPLAY, GPG_TTY=tty, not loopback mode)

I have not tried vim-gnupg on nvim for a while so I can't say how recently this started working.

Here's the process stack to show how it's executed and wrapped in the shell:

$ ptree -pac 30399
zsh,30399
  └─nvim,32233 test.gpg
      └─nvim,32234 --embed test.gpg
          └─sh,32417 -c (gpg --trust-model always --use-agent --quiet --decrypt '/users/strottie/.config/nvim/test.gpg' 2>/dev/null) >/tmp/nvim.strottie/1YhQ7Y/0 2>&1
              └─gpg,32420 --trust-model always --use-agent --quiet --decrypt /users/strottie/.config/nvim/test.gpg

on NVIM 0.10.1 its still not working for me, neither pinentry-curses nor pinentry-tty.
TTY does not seem to respond to input at all,
And curses displays the box nicely, but seems to eat half my keypresses, so cannot enter password.

I'm on desktop with a GUI so will continue using the pinentry-gnome3 which works fine.

Wondering what part of your setup makes the curses method work.
(Using bash, tmux, openSuse tumbleweed, gpg 2.4.5)

@strottie
Copy link

Thanks @ckjoris for trying it out.

I might have spoken too fast. Even with NVIM 0.10.2, the tty pinentry is still losing some characters which tells me both NVIM and pinentry are still reading from the same tty. Typing really slow seems to allow pinentry to win most of the time but that might just be my luck.

It was too good to be true.

@strottie
Copy link

Perhaps gpg-agent can be "seeded" by running a dummy decrypt inside :terminal and then the passphrase is sure to be available without prompting for the real decrypt? Assuming gpg-agent's cache TTL is not set to 0, of course (default is 10 minutes).

For a POSIX &shell, something like

:terminal GPG_TTY=`tty` gpg --decrypt dummy.gpg

dummy.gpg should be encrypted for the same recipient(s) as the file vim-gnupg is ultimately trying to decrypt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests