| rev | 
   line source | 
| 
jbe/bsw@20
 | 
     1 --[[--
 | 
| 
jbe/bsw@20
 | 
     2 url,                         -- normalized URL or nil
 | 
| 
jbe/bsw@20
 | 
     3 auth.openid._normalize_url(
 | 
| 
jbe/bsw@20
 | 
     4   url                        -- unnormalized URL
 | 
| 
jbe/bsw@20
 | 
     5 )
 | 
| 
jbe/bsw@20
 | 
     6 
 | 
| 
jbe/bsw@20
 | 
     7 This function normalizes an URL, and returns nil if the given URL is not a
 | 
| 
jbe/bsw@20
 | 
     8 valid absolute URL. For security reasons only a restricted set of URLs is
 | 
| 
jbe/bsw@20
 | 
     9 valid.
 | 
| 
jbe/bsw@20
 | 
    10 
 | 
| 
jbe/bsw@20
 | 
    11 --]]--
 | 
| 
jbe/bsw@20
 | 
    12 
 | 
| 
jbe/bsw@20
 | 
    13 function auth.openid._normalize_url(url)
 | 
| 
jbe/bsw@20
 | 
    14   local url = string.match(url, "^(.-)??$")  -- remove "?" at end
 | 
| 
jbe/bsw@20
 | 
    15   local proto, host, path = string.match(
 | 
| 
jbe/bsw@20
 | 
    16     url,
 | 
| 
jbe/bsw@20
 | 
    17     "([A-Za-z]+)://([0-9A-Za-z.:_-]+)/?([0-9A-Za-z%%/._~-]*)$"
 | 
| 
jbe/bsw@20
 | 
    18   )
 | 
| 
jbe/bsw@20
 | 
    19   if not proto then
 | 
| 
jbe/bsw@20
 | 
    20     return nil
 | 
| 
jbe/bsw@20
 | 
    21   end
 | 
| 
jbe/bsw@20
 | 
    22   proto = string.lower(proto)
 | 
| 
jbe/bsw@20
 | 
    23   host  = string.lower(host)
 | 
| 
jbe/bsw@20
 | 
    24   local port = string.match(host, ":(.*)")
 | 
| 
jbe/bsw@20
 | 
    25   if port then
 | 
| 
jbe/bsw@20
 | 
    26     if string.find(port, "^[0-9]+$") then
 | 
| 
jbe/bsw@20
 | 
    27       port = tonumber(port)
 | 
| 
jbe/bsw@20
 | 
    28       host = string.match(host, "^(.-):")
 | 
| 
jbe/bsw@20
 | 
    29       if port < 1 or port > 65535 then
 | 
| 
jbe/bsw@20
 | 
    30         return nil
 | 
| 
jbe/bsw@20
 | 
    31       end
 | 
| 
jbe/bsw@20
 | 
    32     else
 | 
| 
jbe/bsw@20
 | 
    33       return nil
 | 
| 
jbe/bsw@20
 | 
    34     end
 | 
| 
jbe/bsw@20
 | 
    35   end
 | 
| 
jbe/bsw@20
 | 
    36   if proto == "http" then
 | 
| 
jbe/bsw@20
 | 
    37     if port == 80 then port = nil end
 | 
| 
jbe/bsw@20
 | 
    38   elseif proto == "https" then
 | 
| 
jbe/bsw@20
 | 
    39     if port == 443 then port = nil end
 | 
| 
jbe/bsw@20
 | 
    40   else
 | 
| 
jbe/bsw@20
 | 
    41     return nil
 | 
| 
jbe/bsw@20
 | 
    42   end
 | 
| 
jbe/bsw@20
 | 
    43   if
 | 
| 
jbe/bsw@20
 | 
    44     string.find(host, "^%.") or
 | 
| 
jbe/bsw@20
 | 
    45     string.find(host, "%.$") or
 | 
| 
jbe/bsw@20
 | 
    46     string.find(host, "%.%.")
 | 
| 
jbe/bsw@20
 | 
    47   then
 | 
| 
jbe/bsw@20
 | 
    48     return nil
 | 
| 
jbe/bsw@20
 | 
    49   end
 | 
| 
jbe/bsw@20
 | 
    50   for part in string.gmatch(host, "[^.]+") do
 | 
| 
jbe/bsw@20
 | 
    51     if not string.find(part, "[A-Za-z]") then
 | 
| 
jbe/bsw@20
 | 
    52       return nil
 | 
| 
jbe/bsw@20
 | 
    53     end
 | 
| 
jbe/bsw@20
 | 
    54   end
 | 
| 
jbe/bsw@20
 | 
    55   local path_parts = {}
 | 
| 
jbe/bsw@20
 | 
    56   for part in string.gmatch(path, "[^/]+") do
 | 
| 
jbe/bsw@20
 | 
    57     if part == "." then
 | 
| 
jbe/bsw@20
 | 
    58       -- do nothing
 | 
| 
jbe/bsw@20
 | 
    59     elseif part == ".." then
 | 
| 
jbe/bsw@20
 | 
    60       path_parts[#path_parts] = nil
 | 
| 
jbe/bsw@20
 | 
    61     else
 | 
| 
jbe/bsw@20
 | 
    62       local fail = false
 | 
| 
jbe/bsw@20
 | 
    63       local part = string.gsub(
 | 
| 
jbe/bsw@20
 | 
    64         part,
 | 
| 
jbe/bsw@20
 | 
    65         "%%([0-9A-Fa-f]?[0-9A-Fa-f]?)",
 | 
| 
jbe/bsw@20
 | 
    66         function (hex)
 | 
| 
jbe/bsw@20
 | 
    67           if #hex ~= 2 then
 | 
| 
jbe/bsw@20
 | 
    68             fail = true
 | 
| 
jbe/bsw@20
 | 
    69             return
 | 
| 
jbe/bsw@20
 | 
    70           end
 | 
| 
jbe/bsw@20
 | 
    71           local char = string.char(tonumber("0x" .. hex))
 | 
| 
jbe/bsw@20
 | 
    72           if string.find(char, "[0-9A-Za-z._~-]") then
 | 
| 
jbe/bsw@20
 | 
    73             return char
 | 
| 
jbe/bsw@20
 | 
    74           else
 | 
| 
jbe/bsw@20
 | 
    75             return "%" .. string.upper(hex)
 | 
| 
jbe/bsw@20
 | 
    76           end
 | 
| 
jbe/bsw@20
 | 
    77         end
 | 
| 
jbe/bsw@20
 | 
    78       )
 | 
| 
jbe/bsw@20
 | 
    79       if fail then
 | 
| 
jbe/bsw@20
 | 
    80         return nil
 | 
| 
jbe/bsw@20
 | 
    81       end
 | 
| 
jbe/bsw@20
 | 
    82       path_parts[#path_parts+1] = part
 | 
| 
jbe/bsw@20
 | 
    83     end
 | 
| 
jbe/bsw@20
 | 
    84   end
 | 
| 
jbe/bsw@20
 | 
    85   if string.find(path, "/$") then
 | 
| 
jbe/bsw@20
 | 
    86     path_parts[#path_parts+1] = ""
 | 
| 
jbe/bsw@20
 | 
    87   end
 | 
| 
jbe/bsw@20
 | 
    88   path = table.concat(path_parts, "/")
 | 
| 
jbe/bsw@20
 | 
    89   if port then
 | 
| 
jbe/bsw@20
 | 
    90     host = host .. ":" .. tostring(port)
 | 
| 
jbe/bsw@20
 | 
    91   end
 | 
| 
jbe/bsw@20
 | 
    92   return proto .. "://" .. host .. "/" .. path
 | 
| 
jbe/bsw@20
 | 
    93 end
 |