From 847c39749daa4130549b518c1650642b6c9d8b3a Mon Sep 17 00:00:00 2001 From: August Schwerdfeger Date: Tue, 21 Jan 2020 00:29:18 -0600 Subject: [PATCH 1/2] Corrected escaping of command-line arguments in the 'sanitize' and 'is_not_sanitized' functions. --- lib/dtutils/string.lua | 100 +++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 48 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index ba4cd67..2da4c90 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -192,33 +192,28 @@ dtutils_string.libdoc.functions["sanitize"] = { Copyright = [[]], } -function dtutils_string.sanitize(str) - local result = str - local os_quote = dt.configuration.running_os == "windows" and '"' or "'" - local escaped_os_quote = "\\" .. os_quote - - if dtutils_string.is_not_sanitized(result) then - local pos = string.find(result, os_quote) - if not pos or pos > 1 then - result = os_quote .. result - end - pos = string.find(result, os_quote, string.len(result)) - if not pos then - result = result .. os_quote - end - - if dtutils_string.is_not_sanitized(result) then --check for embedded os_quotes - pos = string.find(result, os_quote, 2) - while pos < string.len(result) do - if not string.find(result, escaped_os_quote, pos - 1) then - result = string.format("%s\\%s", string.sub(result, 1, pos -1), string.sub(result, pos)) - end - pos = string.find(result, os_quote, pos+2) - end - end +function dtutils_string.sanitize_posix(str) + if dtutils_string.is_not_sanitized(str) then + return "'" .. string.gsub(str, "'", "'\\''") .. "'" + else + return str + end +end + +function dtutils_string.sanitize_windows(str) + if dtutils_string.is_not_sanitized(str) then + return "\"" .. string.gsub(str, "\"", "\"^\"\"") .. "\"" + else + return str + end +end + +function dtutils_string.sanitize(str) + if dt.configuration.running_os == "windows" then + return dtutils_string.sanitize_windows(str) + else + return dtutils_string.sanitize_posix(str) end - - return result end dtutils_string.libdoc.functions["is_not_sanitized"] = { @@ -238,31 +233,40 @@ dtutils_string.libdoc.functions["is_not_sanitized"] = { Copyright = [[]], } +function dtutils_string.is_not_sanitized_posix(str) + -- A sanitized string must be quoted. + if not string.match(str, "^'.*'$") then + return true + -- A quoted string containing no quote characters within is sanitized. + elseif string.match(str, "^'[^']*'$") then + return false + end + + -- Any quote characters within a sanitized string must be properly + -- escaped. + local quotesStripped = string.sub(str, 2, -2) + local escapedQuotesRemoved = string.gsub(quotesStripped, "'\\''", "") + if string.find(escapedQuotesRemoved, "'") then + return true + else + return false + end +end + +function dtutils_string.is_not_sanitized_windows(str) + if not string.match(str, "^\".*\"$") then + return true + else + return false + end +end + function dtutils_string.is_not_sanitized(str) - local os_quote = dt.configuration.running_os == "windows" and '"' or "'" - local escaped_os_quote = "\\" .. os_quote - local length = string.len(str) - local not_sanitized = false - - local pos = string.find(str, os_quote) - if pos == 1 then - if string.find(str, os_quote, length) then - pos = string.find(str, os_quote, 2) - while pos ~= length do - if not string.find(str, escaped_os_quote, pos - 1) then - not_sanitized = true - end - pos = string.find(str, os_quote, pos + 1) - end - else - not_sanitized = true - end + if dt.configuration.running_os == "windows" then + return dtutils_string.is_not_sanitized_windows(str) else - not_sanitized = true + return dtutils_string.is_not_sanitized_posix(str) end - -return not_sanitized - end From 51eda4e755f34c38886c1f04d447a6a9937a72a9 Mon Sep 17 00:00:00 2001 From: August Schwerdfeger Date: Tue, 21 Jan 2020 22:17:12 -0600 Subject: [PATCH 2/2] Made Windows- and POSIX-specific sanitization functions local; moved the 'sanitize' functions after the 'is_not_sanitized' functions that they call. --- lib/dtutils/string.lua | 92 +++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 2da4c90..f58f38c 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -174,48 +174,6 @@ function dtutils_string.urlencode(str) end -dtutils_string.libdoc.functions["sanitize"] = { - Name = [[sanitize]], - Synopsis = [[surround a string in quotes making it safe to pass as an argument]], - Usage = [[local ds = require "lib/dtutils.string" - - local result = ds.sanitize(str) - str - string - the string that needs to be made safe]], - Description = [[sanitize converts a string into a version suitable for - use passing as an argument in a system command.]], - Return_Value = [[result - string - a websafe string]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} - -function dtutils_string.sanitize_posix(str) - if dtutils_string.is_not_sanitized(str) then - return "'" .. string.gsub(str, "'", "'\\''") .. "'" - else - return str - end -end - -function dtutils_string.sanitize_windows(str) - if dtutils_string.is_not_sanitized(str) then - return "\"" .. string.gsub(str, "\"", "\"^\"\"") .. "\"" - else - return str - end -end - -function dtutils_string.sanitize(str) - if dt.configuration.running_os == "windows" then - return dtutils_string.sanitize_windows(str) - else - return dtutils_string.sanitize_posix(str) - end -end - dtutils_string.libdoc.functions["is_not_sanitized"] = { Name = [[is_not_sanitized]], Synopsis = [[Check if a string has been sanitized]], @@ -233,7 +191,7 @@ dtutils_string.libdoc.functions["is_not_sanitized"] = { Copyright = [[]], } -function dtutils_string.is_not_sanitized_posix(str) +local function _is_not_sanitized_posix(str) -- A sanitized string must be quoted. if not string.match(str, "^'.*'$") then return true @@ -253,7 +211,7 @@ function dtutils_string.is_not_sanitized_posix(str) end end -function dtutils_string.is_not_sanitized_windows(str) +local function _is_not_sanitized_windows(str) if not string.match(str, "^\".*\"$") then return true else @@ -263,9 +221,51 @@ end function dtutils_string.is_not_sanitized(str) if dt.configuration.running_os == "windows" then - return dtutils_string.is_not_sanitized_windows(str) + return _is_not_sanitized_windows(str) else - return dtutils_string.is_not_sanitized_posix(str) + return _is_not_sanitized_posix(str) + end +end + +dtutils_string.libdoc.functions["sanitize"] = { + Name = [[sanitize]], + Synopsis = [[surround a string in quotes making it safe to pass as an argument]], + Usage = [[local ds = require "lib/dtutils.string" + + local result = ds.sanitize(str) + str - string - the string that needs to be made safe]], + Description = [[sanitize converts a string into a version suitable for + use passing as an argument in a system command.]], + Return_Value = [[result - string - a websafe string]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +local function _sanitize_posix(str) + if _is_not_sanitized_posix(str) then + return "'" .. string.gsub(str, "'", "'\\''") .. "'" + else + return str + end +end + +local function _sanitize_windows(str) + if _is_not_sanitized_windows(str) then + return "\"" .. string.gsub(str, "\"", "\"^\"\"") .. "\"" + else + return str + end +end + +function dtutils_string.sanitize(str) + if dt.configuration.running_os == "windows" then + return _sanitize_windows(str) + else + return _sanitize_posix(str) end end