diff options
author | Michał Zieliński <michal@zielinscy.org.pl> | 2013-12-02 18:34:32 +0100 |
---|---|---|
committer | Michał Zieliński <michal@zielinscy.org.pl> | 2013-12-07 22:56:02 +0100 |
commit | e7e8c7706240c4bef17533da63df988d228ba127 (patch) | |
tree | 9841b117a79e64f00f6e6165e77ee3a5ec0d65e2 /lib | |
parent | 5dcfa97fb959eda3cb8a41e2bd39e998c30052c8 (diff) | |
download | Nim-e7e8c7706240c4bef17533da63df988d228ba127.tar.gz |
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.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/strutils.nim | 51 |
1 files changed, 43 insertions, 8 deletions
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index a4aa81578..0299f5cd2 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -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 |