changeset 2680:96bf67f1f960

mod_http_upload: Validate that file extension (used by mod_http_files) matches mime type given by client
author Kim Alvefur <zash@zash.se>
date Thu, 13 Apr 2017 20:23:17 +0200
parents 5f60dd12dbb8
children 8d8ba28d020f
files mod_http_upload/mod_http_upload.lua
diffstat 1 files changed, 18 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/mod_http_upload/mod_http_upload.lua	Thu Apr 13 16:36:25 2017 +0200
+++ b/mod_http_upload/mod_http_upload.lua	Thu Apr 13 20:23:17 2017 +0200
@@ -44,6 +44,9 @@
 module:depends("http");
 module:depends("disco");
 
+local http_files = module:depends("http_files");
+local mime_map = module:shared("/*/http_files/mime").types;
+
 -- namespaces
 local namespace = "urn:xmpp:http:upload:0";
 local legacy_namespace = "urn:xmpp:http:upload";
@@ -100,7 +103,7 @@
 	return sum < quota;
 end
 
-local function handle_request(origin, stanza, xmlns, filename, filesize)
+local function handle_request(origin, stanza, xmlns, filename, filesize, mimetype)
 	-- local clients only
 	if origin.type ~= "c2s" then
 		module:log("debug", "Request for upload slot from a %s", origin.type);
@@ -129,6 +132,15 @@
 		origin.send(st.error_reply(stanza, "wait", "resource-constraint", "Quota reached"));
 		return true;
 	end
+
+	if mime_map then
+		local file_ext = filename:match("%.([^.]+)$");
+		if (not file_ext and mimetype ~= "application/octet-stream") or (file_ext and mime_map[file_ext] ~= mimetype) then
+			origin.send(st.error_reply(stanza, "modify", "bad-request", "MIME type does not match file extension"));
+			return true;
+		end
+	end
+
 	local reply = st.reply(stanza);
 	reply:tag("slot", { xmlns = xmlns });
 
@@ -162,7 +174,8 @@
 	local request = stanza.tags[1];
 	local filename = request.attr.filename;
 	local filesize = tonumber(request.attr.size);
-	return handle_request(origin, stanza, namespace, filename, filesize);
+	local mimetype = request.attr["content-type"];
+	return handle_request(origin, stanza, namespace, filename, filesize, mimetype);
 end);
 
 module:hook("iq/host/"..legacy_namespace..":request", function (event)
@@ -170,7 +183,8 @@
 	local request = stanza.tags[1];
 	local filename = request:get_child_text("filename");
 	local filesize = tonumber(request:get_child_text("size"));
-	return handle_request(origin, stanza, legacy_namespace, filename, filesize);
+	local mimetype = request:get_child_text("content-type");
+	return handle_request(origin, stanza, legacy_namespace, filename, filesize, mimetype);
 end);
 
 -- http service
@@ -256,7 +270,7 @@
 	end
 end
 
-local serve_uploaded_files = module:depends("http_files").serve(storage_path);
+local serve_uploaded_files = http_files.serve(storage_path);
 
 local function serve_head(event, path)
 	event.response.send = send_response_sans_body;