Mercurial > prosody-modules
comparison mod_http_upload_external/mod_http_upload_external.lua @ 2978:ac99a04231b1
mod_http_upload_external: Add newer 'v2' protocol (and share_v2.php) which supports content-type preservation
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Mon, 02 Apr 2018 10:57:17 +0100 |
| parents | 280305c043b0 |
| children | 7af4776a5dea |
comparison
equal
deleted
inserted
replaced
| 2977:7036e82f83f5 | 2978:ac99a04231b1 |
|---|---|
| 12 local dataform = require "util.dataforms".new; | 12 local dataform = require "util.dataforms".new; |
| 13 local HMAC = require "util.hashes".hmac_sha256; | 13 local HMAC = require "util.hashes".hmac_sha256; |
| 14 | 14 |
| 15 -- config | 15 -- config |
| 16 local file_size_limit = module:get_option_number(module.name .. "_file_size_limit", 100 * 1024 * 1024); -- 100 MB | 16 local file_size_limit = module:get_option_number(module.name .. "_file_size_limit", 100 * 1024 * 1024); -- 100 MB |
| 17 local base_url = assert(module:get_option_string(module.name .. "_base_url"), module.name .. "_base_url is a required option"); | 17 local base_url = assert(module:get_option_string(module.name .. "_base_url"), |
| 18 local secret = assert(module:get_option_string(module.name .. "_secret"), module.name .. "_secret is a required option"); | 18 module.name .. "_base_url is a required option"); |
| 19 local secret = assert(module:get_option_string(module.name .. "_secret"), | |
| 20 module.name .. "_secret is a required option"); | |
| 21 | |
| 22 local token_protocol = module:get_option_string(module.name .. "_protocol", "v1"); | |
| 19 | 23 |
| 20 -- depends | 24 -- depends |
| 21 module:depends("disco"); | 25 module:depends("disco"); |
| 22 | 26 |
| 23 -- namespace | 27 -- namespace |
| 37 module:add_extension(dataform { | 41 module:add_extension(dataform { |
| 38 { name = "FORM_TYPE", type = "hidden", value = legacy_namespace }, | 42 { name = "FORM_TYPE", type = "hidden", value = legacy_namespace }, |
| 39 { name = "max-file-size", type = "text-single" }, | 43 { name = "max-file-size", type = "text-single" }, |
| 40 }:form({ ["max-file-size"] = tostring(file_size_limit) }, "result")); | 44 }:form({ ["max-file-size"] = tostring(file_size_limit) }, "result")); |
| 41 | 45 |
| 42 local function magic_crypto_dust(random, filename, filesize) | 46 local function magic_crypto_dust(random, filename, filesize, filetype) |
| 43 local message = string.format("%s/%s %d", random, filename, filesize); | 47 local param, message; |
| 48 if token_protocol == "v1" then | |
| 49 param, message = "v", string.format("%s/%s %d", random, filename, filesize); | |
| 50 else | |
| 51 param, message = "v2", string.format("%s/%s\0%d\0%s", random, filename, filesize, filetype); | |
| 52 end | |
| 44 local digest = HMAC(secret, message, true); | 53 local digest = HMAC(secret, message, true); |
| 45 random, filename = http.urlencode(random), http.urlencode(filename); | 54 random, filename = http.urlencode(random), http.urlencode(filename); |
| 46 return base_url .. random .. "/" .. filename, "?v=" .. digest; | 55 return base_url .. random .. "/" .. filename, "?"..param.."=" .. digest; |
| 47 end | 56 end |
| 48 | 57 |
| 49 local function handle_request(origin, stanza, xmlns, filename, filesize) | 58 local function handle_request(origin, stanza, xmlns, filename, filesize, filetype) |
| 50 -- local clients only | 59 -- local clients only |
| 51 if origin.type ~= "c2s" then | 60 if origin.type ~= "c2s" then |
| 52 module:log("debug", "Request for upload slot from a %s", origin.type); | 61 module:log("debug", "Request for upload slot from a %s", origin.type); |
| 53 origin.send(st.error_reply(stanza, "cancel", "not-authorized")); | 62 origin.send(st.error_reply(stanza, "cancel", "not-authorized")); |
| 54 return nil, nil; | 63 return nil, nil; |
| 69 st.stanza("file-too-large", {xmlns=xmlns}) | 78 st.stanza("file-too-large", {xmlns=xmlns}) |
| 70 :tag("max-size"):text(tostring(file_size_limit)))); | 79 :tag("max-size"):text(tostring(file_size_limit)))); |
| 71 return nil, nil; | 80 return nil, nil; |
| 72 end | 81 end |
| 73 local random = uuid(); | 82 local random = uuid(); |
| 74 local get_url, verify = magic_crypto_dust(random, filename, filesize); | 83 local get_url, verify = magic_crypto_dust(random, filename, filesize, filetype); |
| 75 local put_url = get_url .. verify; | 84 local put_url = get_url .. verify; |
| 76 | 85 |
| 77 module:log("info", "Handing out upload slot %s to %s@%s", get_url, origin.username, origin.host); | 86 module:log("info", "Handing out upload slot %s to %s@%s", get_url, origin.username, origin.host); |
| 78 | 87 |
| 79 return get_url, put_url; | 88 return get_url, put_url; |
| 83 module:hook("iq/host/"..legacy_namespace..":request", function (event) | 92 module:hook("iq/host/"..legacy_namespace..":request", function (event) |
| 84 local stanza, origin = event.stanza, event.origin; | 93 local stanza, origin = event.stanza, event.origin; |
| 85 local request = stanza.tags[1]; | 94 local request = stanza.tags[1]; |
| 86 local filename = request:get_child_text("filename"); | 95 local filename = request:get_child_text("filename"); |
| 87 local filesize = tonumber(request:get_child_text("size")); | 96 local filesize = tonumber(request:get_child_text("size")); |
| 97 local filetype = request.attr["content-type"] or "application/octet-stream"; | |
| 88 | 98 |
| 89 local get_url, put_url = handle_request( | 99 local get_url, put_url = handle_request( |
| 90 origin, stanza, legacy_namespace, filename, filesize); | 100 origin, stanza, legacy_namespace, filename, filesize, filetype); |
| 91 | 101 |
| 92 if not get_url then | 102 if not get_url then |
| 93 -- error was already sent | 103 -- error was already sent |
| 94 return true; | 104 return true; |
| 95 end | 105 end |
| 106 module:hook("iq/host/"..namespace..":request", function (event) | 116 module:hook("iq/host/"..namespace..":request", function (event) |
| 107 local stanza, origin = event.stanza, event.origin; | 117 local stanza, origin = event.stanza, event.origin; |
| 108 local request = stanza.tags[1]; | 118 local request = stanza.tags[1]; |
| 109 local filename = request.attr.filename; | 119 local filename = request.attr.filename; |
| 110 local filesize = tonumber(request.attr.size); | 120 local filesize = tonumber(request.attr.size); |
| 121 local filetype = request.attr["content-type"] or "application/octet-stream"; | |
| 122 | |
| 111 local get_url, put_url = handle_request( | 123 local get_url, put_url = handle_request( |
| 112 origin, stanza, namespace, filename, filesize); | 124 origin, stanza, namespace, filename, filesize, filetype); |
| 113 | 125 |
| 114 if not get_url then | 126 if not get_url then |
| 115 -- error was already sent | 127 -- error was already sent |
| 116 return true; | 128 return true; |
| 117 end | 129 end |
