Make quoteIfContainsWhite quote argument, so it can be safely passed to shell.

On Windows put it in double quotes and escape double quotes using backslash.
On Posix put it in single quotes and escape single quotes using '"'"'.

This commit changes what quoteIfContainsWhite does, but before that change it
was used incorrectly all over standard library, which caused security issues.
This commit is contained in:
Michał Zieliński
2013-12-02 18:34:32 +01:00
parent 5dcfa97fb9
commit e7e8c77062
2 changed files with 45 additions and 8 deletions

View File

@@ -709,14 +709,6 @@ proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} =
if result != -1: return
return -1
proc quoteIfContainsWhite*(s: string): string =
## returns ``'"' & s & '"'`` if `s` contains a space and does not
## start with a quote, else returns `s`
if find(s, {' ', '\t'}) >= 0 and s[0] != '"':
result = '"' & s & '"'
else:
result = s
proc contains*(s: string, c: char): bool {.noSideEffect.} =
## Same as ``find(s, c) >= 0``.
return find(s, c) >= 0
@@ -780,6 +772,49 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
# copy the rest:
add result, substr(s, i)
proc quoteIfContainsWhite*(s: string): string {.noSideEffect.} =
## Quote s, so it can be safely passed to shell.
when defined(Windows):
# based on Python's subprocess.list2cmdline
# see http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
let needQuote = {' ', '\t'} in s or s.len == 0
result = ""
var backslashBuff = ""
if needQuote:
result.add("\"")
for c in s:
if c == '\\':
backslashBuff.add(c)
elif c == '\"':
result.add(backslashBuff)
result.add(backslashBuff)
backslashBuff.setLen(0)
result.add("\\\"")
else:
if backslashBuff.len != 0:
result.add(backslashBuff)
backslashBuff.setLen(0)
result.add(c)
if needQuote:
result.add("\"")
else:
# based on Python's pipes.quote
const safeUnixChars = {'%', '+', '-', '.', '/', '_', ':', '=', '@',
'0'..'9', 'A'..'Z', 'a'..'z'}
if s.len == 0:
return "''"
let safe = s.allCharsInSet(safeUnixChars)
if safe:
return s
else:
return "'" & s.replace("'", "'\"'\"'") & "'"
proc delete*(s: var string, first, last: int) {.noSideEffect,
rtl, extern: "nsuDelete".} =
## Deletes in `s` the characters at position `first` .. `last`. This modifies

View File

@@ -28,6 +28,8 @@ Changes affecting backwards compatibility
require an error code to be passed to them. This error code can be retrieved
using the new ``OSLastError`` proc.
- ``os.parentDir`` now returns "" if there is no parent dir.
- ``quoteIfContainsWhite`` now escapes argument in such way that it can be safely
passed to shell, instead of just adding double quotes.
Compiler Additions