diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index ba4cd67..f58f38c 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -174,6 +174,59 @@ function dtutils_string.urlencode(str) end +dtutils_string.libdoc.functions["is_not_sanitized"] = { + Name = [[is_not_sanitized]], + Synopsis = [[Check if a string has been sanitized]], + Usage = [[local ds = require "lib/dtutils.string" + local result = ds.is_not_sanitized(str) + str - string - the string that needs to be made safe]], + Description = [[is_not_sanitized checks a string to see if it + has been made safe use passing as an argument in a system command.]], + Return_Value = [[result - boolean - true if the string is not sanitized otherwise false]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +local function _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 + +local function _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) + if dt.configuration.running_os == "windows" then + return _is_not_sanitized_windows(str) + else + 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]], @@ -192,77 +245,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 +local function _sanitize_posix(str) + if _is_not_sanitized_posix(str) then + return "'" .. string.gsub(str, "'", "'\\''") .. "'" + else + return str end - - return result end -dtutils_string.libdoc.functions["is_not_sanitized"] = { - Name = [[is_not_sanitized]], - Synopsis = [[Check if a string has been sanitized]], - Usage = [[local ds = require "lib/dtutils.string" - local result = ds.is_not_sanitized(str) - str - string - the string that needs to be made safe]], - Description = [[is_not_sanitized checks a string to see if it - has been made safe use passing as an argument in a system command.]], - Return_Value = [[result - boolean - true if the string is not sanitized otherwise false]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} - -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 +local function _sanitize_windows(str) + if _is_not_sanitized_windows(str) then + return "\"" .. string.gsub(str, "\"", "\"^\"\"") .. "\"" else - not_sanitized = true + return str end +end -return not_sanitized - +function dtutils_string.sanitize(str) + if dt.configuration.running_os == "windows" then + return _sanitize_windows(str) + else + return _sanitize_posix(str) + end end