CloudStorage: Allow use reserved characters in FTP username and FTP password (#3924)

Depends on RFC 3986 compliant util.urlEncode() and adds unit tests for the new functions.
pull/3929/head
Robert 6 years ago committed by Frans de Jonge
parent 22950b24f7
commit 9e67c5a614

@ -13,14 +13,14 @@ local T = require("ffi/util").template
local Ftp = {}
function Ftp:run(address, user, pass, path)
local url = FtpApi:generateUrl(address, user, pass) .. path
local url = FtpApi:generateUrl(address, util.urlEncode(user), util.urlEncode(pass)) .. path
return FtpApi:listFolder(url, path)
end
function Ftp:downloadFile(item, address, user, pass, path, close)
local url = FtpApi:generateUrl(address, user, pass) .. item.url
local url = FtpApi:generateUrl(address, util.urlEncode(user), util.urlEncode(pass)) .. item.url
logger.dbg("downloadFile url", url)
local response = FtpApi:downloadFile(url)
local response = FtpApi:ftpGet(url, "retr")
if response ~= nil then
path = util.fixUtf8(path, "_")
local file = io.open(path, "w")

@ -1,6 +1,7 @@
local DocumentRegistry = require("document/documentregistry")
local ftp = require("socket.ftp")
local ltn12 = require("ltn12")
local util = require("util")
local url = require("socket.url")
local FtpApi = {
@ -15,27 +16,28 @@ function FtpApi:generateUrl(address, user, pass)
if pass ~= "" then
colon_sign = ":"
end
local replace = "://" .. user .. colon_sign .. pass .. at_sign
local generated_url = string.gsub(address, "://", replace)
local generated_url = "ftp://" .. user .. colon_sign .. pass .. at_sign .. address:gsub("ftp://", "")
return generated_url
end
function FtpApi:nlst(u)
function FtpApi:ftpGet(u, command)
local t = {}
local p = url.parse(u)
p.command = "nlst"
p.user = util.urlDecode(p.user)
p.password = util.urlDecode(p.password)
p.command = command
p.sink = ltn12.sink.table(t)
local r, e = ftp.get(p)
return r and table.concat(t), e
end
function FtpApi:listFolder(address_path,folder_path)
function FtpApi:listFolder(address_path, folder_path)
local ftp_list = {}
local ftp_file = {}
local type
local extension
local file_name
local ls_ftp = self:nlst(address_path)
local ls_ftp = self:ftpGet(address_path, "nlst")
if ls_ftp == nil then return false end
if folder_path == "/" then
folder_path = ""
@ -79,12 +81,10 @@ function FtpApi:listFolder(address_path,folder_path)
return ftp_list
end
function FtpApi:downloadFile(file_path)
return ftp.get(file_path ..";type=i")
end
function FtpApi:delete(file_path)
local p = url.parse(file_path)
p.user = util.urlDecode(p.user)
p.password = util.urlDecode(p.password)
p.argument = string.gsub(p.path, "^/", "")
p.command = "dele"
p.check = 250

@ -646,4 +646,35 @@ function util.clearTable(t)
for i = 0, c do t[i] = nil end
end
--- Encode URL also known as percent-encoding see https://en.wikipedia.org/wiki/Percent-encoding
--- @string text the string to encode
--- @treturn encode string
--- Taken from https://gist.github.com/liukun/f9ce7d6d14fa45fe9b924a3eed5c3d99
function util.urlEncode(url)
local char_to_hex = function(c)
return string.format("%%%02X", string.byte(c))
end
if url == nil then
return
end
url = url:gsub("\n", "\r\n")
url = url:gsub("([^%w%-%.%_%~%!%*%'%(%)])", char_to_hex)
return url
end
--- Decode URL (reverse process to util.urlEncode())
--- @string text the string to decode
--- @treturn decode string
--- Taken from https://gist.github.com/liukun/f9ce7d6d14fa45fe9b924a3eed5c3d99
function util.urlDecode(url)
local hex_to_char = function(x)
return string.char(tonumber(x, 16))
end
if url == nil then
return
end
url = url:gsub("%%(%x%x)", hex_to_char)
return url
end
return util

@ -130,7 +130,7 @@ function Send2Ebook:process()
local count = 1
local ftp_config = send2ebook_settings:readSetting("ftp_config") or {address="Please setup ftp in settings", username="", password="", folder=""}
local connection_url = FtpApi:generateUrl(ftp_config.address, ftp_config.username, ftp_config.password)
local connection_url = FtpApi:generateUrl(ftp_config.address, util.urlEncode(ftp_config.username), util.urlEncode(ftp_config.password))
local ftp_files_table = FtpApi:listFolder(connection_url .. ftp_config.folder, ftp_config.folder) --args looks strange but otherwise resonse with invalid paths

@ -385,4 +385,31 @@ describe("util module", function()
util.secondsToClock(120))
end)
end)
describe("urlEncode() and urlDecode", function()
it("should encode string", function()
assert.is_equal("Secret_Password123", util.urlEncode("Secret_Password123"))
assert.is_equal("Secret%20Password123", util.urlEncode("Secret Password123"))
assert.is_equal("S*cret%3DP%40%24%24word*!%23%3F", util.urlEncode("S*cret=P@$$word*!#?"))
assert.is_equal("~%5E-_%5C%25!*'()%3B%3A%40%26%3D%2B%24%2C%2F%3F%23%5B%5D",
util.urlEncode("~^-_\\%!*'();:@&=+$,/?#[]"))
end)
it("should decode string", function()
assert.is_equal("Secret_Password123", util.urlDecode("Secret_Password123"))
assert.is_equal("Secret Password123", util.urlDecode("Secret%20Password123"))
assert.is_equal("S*cret=P@$$word*!#?", util.urlDecode("S*cret%3DP%40%24%24word*!%23%3F"))
assert.is_equal("~^-_\\%!*'();:@&=+$,/?#[]",
util.urlDecode("~%5E-_%5C%25!*'()%3B%3A%40%26%3D%2B%24%2C%2F%3F%23%5B%5D"))
end)
it("should encode and back decode string", function()
assert.is_equal("Secret_Password123",
util.urlDecode(util.urlEncode("Secret_Password123")))
assert.is_equal("Secret Password123",
util.urlDecode(util.urlEncode("Secret Password123")))
assert.is_equal("S*cret=P@$$word*!#?",
util.urlDecode(util.urlEncode("S*cret=P@$$word*!#?")))
assert.is_equal("~^-_%!*'();:@&=+$,/?#[]",
util.urlDecode(util.urlEncode("~^-_%!*'();:@&=+$,/?#[]")))
end)
end)
end)

Loading…
Cancel
Save