aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKim Alvefur <zash@zash.se>2016-12-05 12:29:21 +0100
committerKim Alvefur <zash@zash.se>2016-12-05 12:29:21 +0100
commit0031f4db2cd964b2f0bec5c6292a30107ee68c60 (patch)
treed8491d1afbee7ca428e0a6129a47dcdd9661dca7
parent5edecf159e4a7da6a5b8edccc9766a8119f8b69c (diff)
parentcc617421b1b118c4bfa7067f4ff6a3ee001143f1 (diff)
downloadprosody-0031f4db2cd964b2f0bec5c6292a30107ee68c60.tar.gz
prosody-0031f4db2cd964b2f0bec5c6292a30107ee68c60.zip
Merge 0.10->trunk
-rw-r--r--net/websocket.lua6
-rw-r--r--plugins/mod_websocket.lua48
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