diff options
-rw-r--r-- | net/websocket.lua | 6 | ||||
-rw-r--r-- | plugins/mod_websocket.lua | 48 |
2 files changed, 38 insertions, 16 deletions
diff --git a/net/websocket.lua b/net/websocket.lua index a4274eec..373210d6 100644 --- a/net/websocket.lua +++ b/net/websocket.lua @@ -44,7 +44,7 @@ local function fail(s, code, reason) return false end -function websocket_listeners.onincoming(handler, buffer, err) +function websocket_listeners.onincoming(handler, buffer, err) -- luacheck: ignore 212/err local s = websockets[handler]; s.readbuffer = s.readbuffer..buffer; while true do @@ -123,7 +123,7 @@ function websocket_listeners.onincoming(handler, buffer, err) end local websocket_methods = {}; -local function close_timeout_cb(now, timerid, s) +local function close_timeout_cb(now, timerid, s) -- luacheck: ignore 212/now 212/timerid s.close_timer = nil; log("warn", "Close timeout waiting for server to close, closing manually."); s.handler:close(); @@ -232,7 +232,7 @@ local function connect(url, ex, listeners) }, websocket_metatable); local http_url = url:gsub("^(ws)", "http"); - local http_req = http.request(http_url, { + local http_req = http.request(http_url, { -- luacheck: ignore 211/http_req method = "GET"; headers = headers; sslctx = ex.sslctx; diff --git a/plugins/mod_websocket.lua b/plugins/mod_websocket.lua index ea736800..c19ad566 100644 --- a/plugins/mod_websocket.lua +++ b/plugins/mod_websocket.lua @@ -14,6 +14,7 @@ local sha1 = require "util.hashes".sha1; local base64 = require "util.encodings".base64.encode; local st = require "util.stanza"; local parse_xml = require "util.xml".parse; +local contains_token = require "util.http".contains_token; local portmanager = require "core.portmanager"; local sm_destroy_session = require"core.sessionmanager".destroy_session; local log = module._log; @@ -28,16 +29,16 @@ local t_concat = table.concat; local stream_close_timeout = module:get_option_number("c2s_close_timeout", 5); local consider_websocket_secure = module:get_option_boolean("consider_websocket_secure"); -local cross_domain = module:get_option("cross_domain_websocket"); -if cross_domain then +local cross_domain = module:get_option_set("cross_domain_websocket", {}); +if cross_domain:contains("*") or cross_domain:contains(true) then + cross_domain = true; +end + +local function check_origin(origin) if cross_domain == true then - cross_domain = "*"; - elseif type(cross_domain) == "table" then - cross_domain = t_concat(cross_domain, ", "); - end - if type(cross_domain) ~= "string" then - cross_domain = nil; + return true; end + return cross_domain:contains(origin); end local xmlns_framing = "urn:ietf:params:xml:ns:xmpp-framing"; @@ -142,15 +143,18 @@ function handle_request(event) </body></html>]]; end - local wants_xmpp = false; - (request.headers.sec_websocket_protocol or ""):gsub("([^,]*),?", function (proto) - if proto == "xmpp" then wants_xmpp = true; end - end); + local wants_xmpp = contains_token(request.headers.sec_websocket_protocol or "", "xmpp"); if not wants_xmpp then + module:log("debug", "Client didn't want to talk XMPP, list of protocols was %s", request.headers.sec_websocket_protocol or "(empty)"); return 501; end + if not check_origin(request.headers.origin or "") then + module:log("debug", "Origin %s is not allowed by 'cross_domain_websocket'", request.headers.origin or "(missing header)"); + return 403; + end + local function websocket_close(code, message) conn:write(build_close(code, message)); conn:close(); @@ -285,7 +289,8 @@ function handle_request(event) response.headers.connection = "Upgrade"; response.headers.sec_webSocket_accept = base64(sha1(request.headers.sec_websocket_key .. "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")); response.headers.sec_webSocket_protocol = "xmpp"; - response.headers.access_control_allow_origin = cross_domain; + + session.log("debug", "Sending WebSocket handshake"); return ""; end @@ -310,4 +315,21 @@ function module.add_host(module) }; }); module:hook("c2s-read-timeout", keepalive, -0.9); + + if cross_domain ~= true then + local url = require "socket.url"; + local ws_url = module:http_url("websocket", "xmpp-websocket"); + local url_components = url.parse(ws_url); + -- The 'Origin' consists of the base URL without path + url_components.path = nil; + local this_origin = url.build(url_components); + local local_cross_domain = module:get_option_set("cross_domain_websocket", { this_origin }); + -- Don't add / remove something added by another host + -- This might be weird with random load order + local_cross_domain:exclude(cross_domain); + cross_domain:include(local_cross_domain); + function module.unload() + cross_domain:exclude(local_cross_domain); + end + end end |