HTTP Upload: introduce new option 'external_secret'
The option makes it possible to offload all HTTP Upload processing to a separate HTTP server. Both ejabberd and the HTTP server should share this secret and behave exactly as described at at https://modules.prosody.im/mod_http_upload_external.html in the 'Implementation' section. Example configuration: modules: ... mod_http_upload: ... put_url: "http://separate.http.server/upload" external_secret: "foo bar baz" ...
This commit is contained in:
parent
fbf6ba2738
commit
fface33d54
|
@ -110,7 +110,8 @@
|
||||||
service_url :: binary() | undefined,
|
service_url :: binary() | undefined,
|
||||||
thumbnail :: boolean(),
|
thumbnail :: boolean(),
|
||||||
custom_headers :: [{binary(), binary()}],
|
custom_headers :: [{binary(), binary()}],
|
||||||
slots = #{} :: map()}).
|
slots = #{} :: map(),
|
||||||
|
external_secret :: binary()}).
|
||||||
|
|
||||||
-record(media_info,
|
-record(media_info,
|
||||||
{type :: atom(),
|
{type :: atom(),
|
||||||
|
@ -208,7 +209,9 @@ mod_opt_type(thumbnail) ->
|
||||||
end;
|
end;
|
||||||
(false) ->
|
(false) ->
|
||||||
false
|
false
|
||||||
end.
|
end;
|
||||||
|
mod_opt_type(external_secret) ->
|
||||||
|
fun iolist_to_binary/1.
|
||||||
|
|
||||||
-spec mod_options(binary()) -> [{atom(), any()}].
|
-spec mod_options(binary()) -> [{atom(), any()}].
|
||||||
mod_options(_Host) ->
|
mod_options(_Host) ->
|
||||||
|
@ -225,6 +228,7 @@ mod_options(_Host) ->
|
||||||
{put_url, <<"http://@HOST@:5444">>},
|
{put_url, <<"http://@HOST@:5444">>},
|
||||||
{get_url, undefined},
|
{get_url, undefined},
|
||||||
{service_url, undefined},
|
{service_url, undefined},
|
||||||
|
{external_secret, <<"">>},
|
||||||
{custom_headers, []},
|
{custom_headers, []},
|
||||||
{rm_on_unregister, true},
|
{rm_on_unregister, true},
|
||||||
{thumbnail, false}].
|
{thumbnail, false}].
|
||||||
|
@ -255,6 +259,7 @@ init([ServerHost, Opts]) ->
|
||||||
end,
|
end,
|
||||||
ServiceURL = gen_mod:get_opt(service_url, Opts),
|
ServiceURL = gen_mod:get_opt(service_url, Opts),
|
||||||
Thumbnail = gen_mod:get_opt(thumbnail, Opts),
|
Thumbnail = gen_mod:get_opt(thumbnail, Opts),
|
||||||
|
ExternalSecret = gen_mod:get_opt(external_secret, Opts),
|
||||||
CustomHeaders = gen_mod:get_opt(custom_headers, Opts),
|
CustomHeaders = gen_mod:get_opt(custom_headers, Opts),
|
||||||
DocRoot1 = expand_home(str:strip(DocRoot, right, $/)),
|
DocRoot1 = expand_home(str:strip(DocRoot, right, $/)),
|
||||||
DocRoot2 = expand_host(DocRoot1, ServerHost),
|
DocRoot2 = expand_host(DocRoot1, ServerHost),
|
||||||
|
@ -277,6 +282,7 @@ init([ServerHost, Opts]) ->
|
||||||
put_url = expand_host(str:strip(PutURL, right, $/), ServerHost),
|
put_url = expand_host(str:strip(PutURL, right, $/), ServerHost),
|
||||||
get_url = expand_host(str:strip(GetURL, right, $/), ServerHost),
|
get_url = expand_host(str:strip(GetURL, right, $/), ServerHost),
|
||||||
service_url = ServiceURL,
|
service_url = ServiceURL,
|
||||||
|
external_secret = ExternalSecret,
|
||||||
custom_headers = CustomHeaders}}.
|
custom_headers = CustomHeaders}}.
|
||||||
|
|
||||||
-spec handle_call(_, {pid(), _}, state())
|
-spec handle_call(_, {pid(), _}, state())
|
||||||
|
@ -532,11 +538,12 @@ process_slot_request(#iq{lang = Lang, from = From} = IQ,
|
||||||
{ok, Timer} = timer:send_after(?SLOT_TIMEOUT,
|
{ok, Timer} = timer:send_after(?SLOT_TIMEOUT,
|
||||||
{slot_timed_out,
|
{slot_timed_out,
|
||||||
Slot}),
|
Slot}),
|
||||||
|
Query = make_query_string(Slot, Size, State),
|
||||||
NewState = add_slot(Slot, Size, Timer, State),
|
NewState = add_slot(Slot, Size, Timer, State),
|
||||||
NewSlot = mk_slot(Slot, State, XMLNS),
|
NewSlot = mk_slot(Slot, State, XMLNS, Query),
|
||||||
{xmpp:make_iq_result(IQ, NewSlot), NewState};
|
{xmpp:make_iq_result(IQ, NewSlot), NewState};
|
||||||
{ok, PutURL, GetURL} ->
|
{ok, PutURL, GetURL} ->
|
||||||
Slot = mk_slot(PutURL, GetURL, XMLNS),
|
Slot = mk_slot(PutURL, GetURL, XMLNS, <<"">>),
|
||||||
xmpp:make_iq_result(IQ, Slot);
|
xmpp:make_iq_result(IQ, Slot);
|
||||||
{error, Error} ->
|
{error, Error} ->
|
||||||
xmpp:make_error(IQ, Error)
|
xmpp:make_error(IQ, Error)
|
||||||
|
@ -646,20 +653,21 @@ del_slot(Slot, #state{slots = Slots} = State) ->
|
||||||
NewSlots = maps:remove(Slot, Slots),
|
NewSlots = maps:remove(Slot, Slots),
|
||||||
State#state{slots = NewSlots}.
|
State#state{slots = NewSlots}.
|
||||||
|
|
||||||
-spec mk_slot(slot(), state(), binary()) -> upload_slot();
|
-spec mk_slot(slot(), state(), binary(), binary()) -> upload_slot();
|
||||||
(binary(), binary(), binary()) -> upload_slot().
|
(binary(), binary(), binary(), binary()) -> upload_slot().
|
||||||
mk_slot(Slot, #state{put_url = PutPrefix, get_url = GetPrefix}, XMLNS) ->
|
mk_slot(Slot, #state{put_url = PutPrefix, get_url = GetPrefix}, XMLNS, Query) ->
|
||||||
PutURL = str:join([PutPrefix | Slot], <<$/>>),
|
PutURL = str:join([PutPrefix | Slot], <<$/>>),
|
||||||
GetURL = str:join([GetPrefix | Slot], <<$/>>),
|
GetURL = str:join([GetPrefix | Slot], <<$/>>),
|
||||||
mk_slot(PutURL, GetURL, XMLNS);
|
mk_slot(PutURL, GetURL, XMLNS, Query);
|
||||||
mk_slot(PutURL, GetURL, ?NS_HTTP_UPLOAD_0) ->
|
mk_slot(PutURL, GetURL, XMLNS, Query) ->
|
||||||
#upload_slot_0{get = misc:url_encode(GetURL),
|
PutURL1 = <<(misc:url_encode(PutURL))/binary, Query/binary>>,
|
||||||
put = misc:url_encode(PutURL),
|
GetURL1 = misc:url_encode(GetURL),
|
||||||
xmlns = ?NS_HTTP_UPLOAD_0};
|
case XMLNS of
|
||||||
mk_slot(PutURL, GetURL, XMLNS) ->
|
?NS_HTTP_UPLOAD_0 ->
|
||||||
#upload_slot{get = misc:url_encode(GetURL),
|
#upload_slot_0{get = GetURL1, put = PutURL1, xmlns = XMLNS};
|
||||||
put = misc:url_encode(PutURL),
|
_ ->
|
||||||
xmlns = XMLNS}.
|
#upload_slot{get = GetURL1, put = PutURL1, xmlns = XMLNS}
|
||||||
|
end.
|
||||||
|
|
||||||
-spec make_user_string(jid(), sha1 | node) -> binary().
|
-spec make_user_string(jid(), sha1 | node) -> binary().
|
||||||
make_user_string(#jid{luser = U, lserver = S}, sha1) ->
|
make_user_string(#jid{luser = U, lserver = S}, sha1) ->
|
||||||
|
@ -671,6 +679,16 @@ make_user_string(#jid{luser = U}, node) ->
|
||||||
make_file_string(File) ->
|
make_file_string(File) ->
|
||||||
replace_special_chars(File).
|
replace_special_chars(File).
|
||||||
|
|
||||||
|
-spec make_query_string(slot(), non_neg_integer(), state()) -> binary().
|
||||||
|
make_query_string(Slot, Size, #state{external_secret = Key}) when Key /= <<>> ->
|
||||||
|
UrlPath = str:join(Slot, <<$/>>),
|
||||||
|
SizeStr = integer_to_binary(Size),
|
||||||
|
Data = <<UrlPath/binary, " ", SizeStr/binary>>,
|
||||||
|
HMAC = str:to_hexlist(crypto:hmac(sha256, Data, Key)),
|
||||||
|
<<"?v=", HMAC/binary>>;
|
||||||
|
make_query_string(_Slot, _Size, _State) ->
|
||||||
|
<<>>.
|
||||||
|
|
||||||
-spec replace_special_chars(binary()) -> binary().
|
-spec replace_special_chars(binary()) -> binary().
|
||||||
replace_special_chars(S) ->
|
replace_special_chars(S) ->
|
||||||
re:replace(S, <<"[^\\p{Xan}_.-]">>, <<$_>>,
|
re:replace(S, <<"[^\\p{Xan}_.-]">>, <<$_>>,
|
||||||
|
|
Loading…
Reference in New Issue