Using pass better with Vim conceal

Guthrie McAfee Armstrong

2017-11-09

The pass password manager has an issue. Editing a multiline item displays the password in plain text, rendering it vulnerable to screen peeking. I wrote a few lines of Vimscript to patch this security flaw.

For an example of the flaw, imagine if zuck wanted to change his Facebook username while giving his F8 2018 Keynote. He might type this:

$ pass edit Facebook

Then, Vim will expose this to the world in plain text:

^"a.hs(_y$;h~+@N(MDB%0m[d
username: zuck

This is really bad for zuck! If only he’d read my clever solution.

Vim’s conceal feature is pretty neat. Without changing the file, it changes the display of matching text. Usually, it’s used by programs like Twinside/vim-haskellConceal to do things like displaying >= as except when the cursor is on that line.

We can also use conceal to hide passwords! The pass program keeps passwords in the first line of its *.gpg files. So, just target the first line with '\%1l.*' and replace it with a little emoji:

:syntax match Concealed '\%1l.*' conceal cchar=⚠️
:set conceallevel=1

But opening the file will still reveal the password by placing the cursor at the first line. Luckily, Vim has an extremely simple command to solve this:

:2

If there’s only one line in the file (such as immediately after a pass insert), which we can detect with :if line('$') == 1, then we can append a new line to the file so that :2 will definitely work:

:if line('$') == 1 | $put _ | endif

We only want to do this to pass files. Note that pass edit uses a temporary file located at */pass.*/* . We can restrict our rules to files matching this pattern, obtaining the final result:

" Start on (or create) the 2nd line and conceal the first line
autocmd BufNewFile,BufRead */pass.*/* if line('$') == 1 | $put _ | endif
autocmd BufNewFile,BufRead */pass.*/* 2
autocmd BufNewFile,BufRead */pass.*/* syntax match Concealed '\%1l.*' conceal cchar=⚠️
autocmd BufNewFile,BufRead */pass.*/* set conceallevel=1

Throw that in your .vimrc, and you’ll get this (instead of the disastrous previous result):

⚠️
username: zuck