Mercurial > prosody-modules
comparison mod_http_upload/mod_http_upload.lua @ 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 | 2dec7cad9218 |
children | 8d8ba28d020f |
comparison
equal
deleted
inserted
replaced
2679:5f60dd12dbb8 | 2680:96bf67f1f960 |
---|---|
41 end | 41 end |
42 | 42 |
43 -- depends | 43 -- depends |
44 module:depends("http"); | 44 module:depends("http"); |
45 module:depends("disco"); | 45 module:depends("disco"); |
46 | |
47 local http_files = module:depends("http_files"); | |
48 local mime_map = module:shared("/*/http_files/mime").types; | |
46 | 49 |
47 -- namespaces | 50 -- namespaces |
48 local namespace = "urn:xmpp:http:upload:0"; | 51 local namespace = "urn:xmpp:http:upload:0"; |
49 local legacy_namespace = "urn:xmpp:http:upload"; | 52 local legacy_namespace = "urn:xmpp:http:upload"; |
50 | 53 |
98 sum = sum + item.size; | 101 sum = sum + item.size; |
99 end | 102 end |
100 return sum < quota; | 103 return sum < quota; |
101 end | 104 end |
102 | 105 |
103 local function handle_request(origin, stanza, xmlns, filename, filesize) | 106 local function handle_request(origin, stanza, xmlns, filename, filesize, mimetype) |
104 -- local clients only | 107 -- local clients only |
105 if origin.type ~= "c2s" then | 108 if origin.type ~= "c2s" then |
106 module:log("debug", "Request for upload slot from a %s", origin.type); | 109 module:log("debug", "Request for upload slot from a %s", origin.type); |
107 origin.send(st.error_reply(stanza, "cancel", "not-authorized")); | 110 origin.send(st.error_reply(stanza, "cancel", "not-authorized")); |
108 return true; | 111 return true; |
127 elseif not check_quota(origin.username, origin.host, filesize) then | 130 elseif not check_quota(origin.username, origin.host, filesize) then |
128 module:log("debug", "Upload of %dB by %s would exceed quota", filesize, origin.full_jid); | 131 module:log("debug", "Upload of %dB by %s would exceed quota", filesize, origin.full_jid); |
129 origin.send(st.error_reply(stanza, "wait", "resource-constraint", "Quota reached")); | 132 origin.send(st.error_reply(stanza, "wait", "resource-constraint", "Quota reached")); |
130 return true; | 133 return true; |
131 end | 134 end |
135 | |
136 if mime_map then | |
137 local file_ext = filename:match("%.([^.]+)$"); | |
138 if (not file_ext and mimetype ~= "application/octet-stream") or (file_ext and mime_map[file_ext] ~= mimetype) then | |
139 origin.send(st.error_reply(stanza, "modify", "bad-request", "MIME type does not match file extension")); | |
140 return true; | |
141 end | |
142 end | |
143 | |
132 local reply = st.reply(stanza); | 144 local reply = st.reply(stanza); |
133 reply:tag("slot", { xmlns = xmlns }); | 145 reply:tag("slot", { xmlns = xmlns }); |
134 | 146 |
135 local random_dir; | 147 local random_dir; |
136 repeat random_dir = uuid(); | 148 repeat random_dir = uuid(); |
160 module:hook("iq/host/"..namespace..":request", function (event) | 172 module:hook("iq/host/"..namespace..":request", function (event) |
161 local stanza, origin = event.stanza, event.origin; | 173 local stanza, origin = event.stanza, event.origin; |
162 local request = stanza.tags[1]; | 174 local request = stanza.tags[1]; |
163 local filename = request.attr.filename; | 175 local filename = request.attr.filename; |
164 local filesize = tonumber(request.attr.size); | 176 local filesize = tonumber(request.attr.size); |
165 return handle_request(origin, stanza, namespace, filename, filesize); | 177 local mimetype = request.attr["content-type"]; |
178 return handle_request(origin, stanza, namespace, filename, filesize, mimetype); | |
166 end); | 179 end); |
167 | 180 |
168 module:hook("iq/host/"..legacy_namespace..":request", function (event) | 181 module:hook("iq/host/"..legacy_namespace..":request", function (event) |
169 local stanza, origin = event.stanza, event.origin; | 182 local stanza, origin = event.stanza, event.origin; |
170 local request = stanza.tags[1]; | 183 local request = stanza.tags[1]; |
171 local filename = request:get_child_text("filename"); | 184 local filename = request:get_child_text("filename"); |
172 local filesize = tonumber(request:get_child_text("size")); | 185 local filesize = tonumber(request:get_child_text("size")); |
173 return handle_request(origin, stanza, legacy_namespace, filename, filesize); | 186 local mimetype = request:get_child_text("content-type"); |
187 return handle_request(origin, stanza, legacy_namespace, filename, filesize, mimetype); | |
174 end); | 188 end); |
175 | 189 |
176 -- http service | 190 -- http service |
177 local function upload_data(event, path) | 191 local function upload_data(event, path) |
178 local uploader = pending_slots[path]; | 192 local uploader = pending_slots[path]; |
254 else | 268 else |
255 response.conn:close(); | 269 response.conn:close(); |
256 end | 270 end |
257 end | 271 end |
258 | 272 |
259 local serve_uploaded_files = module:depends("http_files").serve(storage_path); | 273 local serve_uploaded_files = http_files.serve(storage_path); |
260 | 274 |
261 local function serve_head(event, path) | 275 local function serve_head(event, path) |
262 event.response.send = send_response_sans_body; | 276 event.response.send = send_response_sans_body; |
263 return serve_uploaded_files(event, path); | 277 return serve_uploaded_files(event, path); |
264 end | 278 end |