Skip to content

Commit

Permalink
Replace noplaintext.vim as redact_pass.vim plugin
Browse files Browse the repository at this point in the history
Per debugging from Enno Nagel <enno.nagel+vim@gmail.com>, it's become
apparent to me that to have any degree of confidence that none of these
options have actually got any plaintext password data in them, we need
to disable the options globally when a password file is edited.

In particular, in the case of the 'viminfo' global option, it's not
possible to disable it per path, and not terribly meaningful either;
things like the last seach pattern or the contents of registers, i.e.
global state of the editor, are recorded. There's no sensible approach I
can see except to actually switch the feature off entirely by blanking
it.

I've therefore completely rewritten this, to make as thorough a check as
possible that the Vim user is editing a pass(1) file by calling `pass
edit`, and then to disable the "leaky" options globally, with an
explicit warning so that the user can see it's been done.

This plugin is also available as Vim script #5707:

<https://www.vim.org/scripts/script.php?script_id=5707>

Its homepage is here:

<https://sanctum.geek.nz/cgit/vim-redact-pass.git/about/>
  • Loading branch information
tejr committed Jun 9, 2018
1 parent dda2ecc commit 5a257fe
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 46 deletions.
46 changes: 0 additions & 46 deletions contrib/vim/noplaintext.vim

This file was deleted.

41 changes: 41 additions & 0 deletions contrib/vim/redact_pass.txt
@@ -0,0 +1,41 @@
*redact_pass.txt* For Vim version 6.0 Last change: 2018 June 10

DESCRIPTION *redact_pass*

This plugin switches off the 'viminfo', 'backup', 'writebackup', 'swapfile',
and 'undofile' options globally when editing a password in `pass(1)`.

This is to prevent anyone being able to extract passwords from your Vim cache
files in the event of a compromise.

You should test this after installed to ensure you see this message is printed
whenever you `pass edit`:

> Editing password file--disabled leaky options!

REQUIREMENTS *redact_pass-requirements*

This plugin is only available if 'compatible' is not set. It also requires the
|+autocmd| feature.

IMPLEMENTATION *redact_pass-implementation*

The options are disabled globally rather than attempting to set them local to
the buffer only, which was the flawed approach of previous versions. This is
mostly because of the 'viminfo' option; it's global, and there's no meaningful
way to exclude information from the sensitive buffer from appearing in it.

Because the typical use case for editing a password file in Vim is that you
load and change a single short document, and then quit, it's more sensible to
just turn the relevant options off completely, and makes what the plugin is
doing more reliable and straightforward to understand.

AUTHOR *redact_pass-author*

Written and maintained by Tom Ryder <tom@sanctum.geek.nz>.

LICENSE *redact_pass-license*

Licensed for distribution under the same terms as the pass(1) project.

vim:tw=78:ts=8:ft=help:norl:
80 changes: 80 additions & 0 deletions contrib/vim/redact_pass.vim
@@ -0,0 +1,80 @@
"
" redact_pass.vim: Switch off the 'viminfo', 'backup', 'writebackup',
" 'swapfile', and 'undofile' globally when editing a password in pass(1).
"
" This is to prevent anyone being able to extract passwords from your Vim
" cache files in the event of a compromise.
"
" Author: Tom Ryder <tom@sanctum.geek.nz>
" License: Same as Vim itself
"
if exists('g:loaded_redact_pass') || &compatible
finish
endif
if !has('autocmd')
finish
endif
let g:loaded_redact_pass = 1

" Pattern to match for the portion of the path after the temporary dir,
" starting with the leading slash
let s:pattern = '\m\C/pass\.[^/]\+/[^/]\+\.txt$'

" Check whether the given dir name is not an empty string, whether the first
" file in the argument list is within the named dir, and that the whole path
" matches the above pattern immediately after that dir name
function! s:PassPath(root)

" Check we actually got a value, i.e. this wasn't an empty environment
" variable
if !strlen(a:root)
return 0
endif

" Full resolved path to the root dir with no trailing slashes
let l:root = fnamemodify(a:root, ':p:h')

" Full resolved path to the first file in the arg list
let l:path = fnamemodify(argv(0), ':p')

" Check the string all match and at the expected points
return stridx(l:path, l:root) == 0
\ && strlen(l:root) == match(l:path, s:pattern)

endfunction

" Check whether we should set redacting options or not
function! s:CheckArgsRedact()

" Short-circuit unless we're editing just one file and it looks like a path
" in one of the three expected directories; we're trying hard to make sure
" this really is a password file and we're not messing with the user's
" precious settings unnecessarily
if argc() != 1
\ || !s:PassPath('/dev/shm')
\ && !s:PassPath($TMPDIR)
\ && !s:PassPath('/tmp')
return
endif

" Disable all the leaky options globally
set nobackup
set nowritebackup
set noswapfile
set viminfo=
if has('persistent_undo')
set noundofile
endif

" Tell the user what we're doing so they know this worked, via a message and
" a global variable they can check
echomsg 'Editing password file--disabled leaky options!'
let g:redact_pass_redacted = 1

endfunction

" Auto function loads only when Vim starts up
augroup redact_pass
autocmd!
autocmd VimEnter * call s:CheckArgsRedact()
augroup END

0 comments on commit 5a257fe

Please sign in to comment.