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

Add missing calls to the shellescape() function #1099

Merged
merged 9 commits into from
Apr 10, 2020
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- **.PATCH**: Pull Request Title (PR Author) [PR Number](Link to PR)
-->
#### 6.7
- **.4**: Add missing calls to the `shellescape()` function (lifecrisis) [#1099](https://github.com/preservim/nerdtree/pull/1099)
- **.3**: Fix vsplit to not open empty buffers when opening previously closed file (AwkwardKore) [#1098](https://github.com/preservim/nerdtree/pull/1098)
- **.2**: Fix infinity loop (on winvim) in FindParentVCSRoot (Eugenij-W) [#1095](https://github.com/preservim/nerdtree/pull/1095)
- **.1**: File Move: Escape existing directory name when looking for open files. (PhilRunninger) [#1094](https://github.com/preservim/nerdtree/pull/1094)
Expand Down
2 changes: 1 addition & 1 deletion lib/nerdtree/path.vim
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ function! s:Path.copy(dest)
let cmd_prefix = (self.isDirectory ? g:NERDTreeCopyDirCmd : g:NERDTreeCopyFileCmd)
endif

let cmd = cmd_prefix . ' ' . escape(self.str(), self._escChars()) . ' ' . escape(a:dest, self._escChars())
let cmd = cmd_prefix . ' ' . shellescape(self.str()) . ' ' . shellescape(a:dest)
Copy link
Member

Choose a reason for hiding this comment

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

Does shellescape() take into account the OS and the &shellslash setting?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know.

Because this is security related, though, I would recommend using it and only reverting it if people complain.

let success = system(cmd)
if v:shell_error !=# 0
throw "NERDTree.CopyError: Could not copy '". self.str() ."' to: '" . a:dest . "'"
Expand Down
57 changes: 40 additions & 17 deletions nerdtree_plugin/fs_menu.vim
Original file line number Diff line number Diff line change
Expand Up @@ -388,44 +388,67 @@ endfunction

" FUNCTION: NERDTreeQuickLook() {{{1
function! NERDTreeQuickLook()
let treenode = g:NERDTreeFileNode.GetSelected()
if treenode !=# {}
call system("qlmanage -p 2>/dev/null '" . treenode.path.str() . "'")
Copy link
Member

Choose a reason for hiding this comment

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

@lifecrisis , do you have a way to test this? These single quotes are thwarting my attempts to do the command injection in the old code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Most of these will allow injection when operating on a file that looks like...

'; touch FOOBAR ; echo '

Opening this file on Linux with mo, and the file FOOBAR will appear in Vim's current working directory. This snippet provides a simplified example of the mechanism:

func! g:Foo()
    return "'; touch FOOBAR ; echo '" 
endfunc

call system("xdg-open '" . g:Foo() . "' &")

This problem seems like it would never happen, but you can do some funky things in the terminal... like concealing characters that actually are contained in the path using terminal escape codes. It's definitely better to use shellescape().

let l:node = g:NERDTreeFileNode.GetSelected()

if empty(l:node)
return
endif

call system('qlmanage -p 2>/dev/null ' . shellescape(l:node.path.str()))
endfunction

" FUNCTION: NERDTreeRevealInFinder() {{{1
function! NERDTreeRevealInFinder()
let treenode = g:NERDTreeFileNode.GetSelected()
if treenode !=# {}
call system("open -R '" . treenode.path.str() . "'")
let l:node = g:NERDTreeFileNode.GetSelected()

if empty(l:node)
return
endif

call system('open -R ' . shellescape(l:node.path.str()))
endfunction

" FUNCTION: NERDTreeExecuteFile() {{{1
function! NERDTreeExecuteFile()
let treenode = g:NERDTreeFileNode.GetSelected()
if treenode !=# {}
call system("open '" . treenode.path.str() . "'")
let l:node = g:NERDTreeFileNode.GetSelected()

if empty(l:node)
Copy link
Member

Choose a reason for hiding this comment

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

Are you following a certain pattern here, instead of

if !empty()
    do the thing
endif

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I always prefer early returns. They seem cleaner to me; i.e., I think they're simpler and read better.

Strictly speaking, though, we should probably be using try statements here. I always try to follow EAFP when possible.

return
endif

call system('open ' . shellescape(l:node.path.str()))
endfunction

" FUNCTION: NERDTreeRevealFileLinux() {{{1
function! NERDTreeRevealFileLinux()
let treenode = g:NERDTreeFileNode.GetSelected()
let parentnode = treenode.parent
if parentnode !=# {}
call system("xdg-open '" . parentnode.path.str() . "' &")
let l:node = g:NERDTreeFileNode.GetSelected()

if empty(l:node)
return
endif

" Handle the edge case of "/", which has no parent.
if l:node.path.str() ==# '/'
call system('xdg-open /')
return
endif

if empty(l:node.parent)
return
endif

call system('xdg-open ' . shellescape(l:node.parent.path.str()))
endfunction

" FUNCTION: NERDTreeExecuteFileLinux() {{{1
function! NERDTreeExecuteFileLinux()
let treenode = g:NERDTreeFileNode.GetSelected()
if treenode !=# {}
call system("xdg-open '" . treenode.path.str() . "' &")
let l:node = g:NERDTreeFileNode.GetSelected()

if empty(l:node)
return
endif

call system('xdg-open ' . shellescape(l:node.path.str()))
endfunction

" vim: set sw=4 sts=4 et fdm=marker: