From e7e8c7706240c4bef17533da63df988d228ba127 Mon Sep 17 00:00:00 2001 From: Michał Zieliński Date: Mon, 2 Dec 2013 18:34:32 +0100 Subject: 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. --- lib/pure/strutils.nim | 51 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 8 deletions(-) (limited to 'lib') 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 -- cgit 1.4.1-2-gfad0