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 |
