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 |