mod_http_upload: Add slot request hook
Let mod_http_upload run an 'http_upload_slot_request' hook. If 'deny' or an error element is returned, the request is rejected; if 'allow' is returned, it is accepted.
This commit is contained in:
parent
14c3b13a11
commit
8a849069ec
|
@ -439,17 +439,16 @@ process_iq(_From,
|
||||||
sub_el = [#xmlel{name = <<"query">>,
|
sub_el = [#xmlel{name = <<"query">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_DISCO_INFO}],
|
attrs = [{<<"xmlns">>, ?NS_DISCO_INFO}],
|
||||||
children = iq_disco_info(Lang, Name) ++ AddInfo}]};
|
children = iq_disco_info(Lang, Name) ++ AddInfo}]};
|
||||||
process_iq(#jid{luser = LUser, lserver = LServer} = From,
|
process_iq(From,
|
||||||
#iq{type = get, xmlns = XMLNS, lang = Lang, sub_el = SubEl} = IQ,
|
#iq{type = get, xmlns = XMLNS, lang = Lang, sub_el = SubEl} = IQ,
|
||||||
#state{server_host = ServerHost, access = Access} = State)
|
#state{server_host = ServerHost, access = Access} = State)
|
||||||
when XMLNS == ?NS_HTTP_UPLOAD;
|
when XMLNS == ?NS_HTTP_UPLOAD;
|
||||||
XMLNS == ?NS_HTTP_UPLOAD_OLD ->
|
XMLNS == ?NS_HTTP_UPLOAD_OLD ->
|
||||||
User = <<LUser/binary, $@, LServer/binary>>,
|
|
||||||
case acl:match_rule(ServerHost, Access, From) of
|
case acl:match_rule(ServerHost, Access, From) of
|
||||||
allow ->
|
allow ->
|
||||||
case parse_request(SubEl, Lang) of
|
case parse_request(SubEl, Lang) of
|
||||||
{ok, File, Size, ContentType} ->
|
{ok, File, Size, ContentType} ->
|
||||||
case create_slot(State, User, File, Size, ContentType, Lang) of
|
case create_slot(State, From, File, Size, ContentType, Lang) of
|
||||||
{ok, Slot} ->
|
{ok, Slot} ->
|
||||||
{ok, Timer} = timer:send_after(?SLOT_TIMEOUT,
|
{ok, Timer} = timer:send_after(?SLOT_TIMEOUT,
|
||||||
{slot_timed_out, Slot}),
|
{slot_timed_out, Slot}),
|
||||||
|
@ -463,11 +462,13 @@ process_iq(#jid{luser = LUser, lserver = LServer} = From,
|
||||||
IQ#iq{type = error, sub_el = [SubEl, Error]}
|
IQ#iq{type = error, sub_el = [SubEl, Error]}
|
||||||
end;
|
end;
|
||||||
{error, Error} ->
|
{error, Error} ->
|
||||||
?DEBUG("Cannot parse request from ~s", [User]),
|
?DEBUG("Cannot parse request from ~s",
|
||||||
|
[jlib:jid_to_string(From)]),
|
||||||
IQ#iq{type = error, sub_el = [SubEl, Error]}
|
IQ#iq{type = error, sub_el = [SubEl, Error]}
|
||||||
end;
|
end;
|
||||||
deny ->
|
deny ->
|
||||||
?DEBUG("Denying HTTP upload slot request from ~s", [User]),
|
?DEBUG("Denying HTTP upload slot request from ~s",
|
||||||
|
[jlib:jid_to_string(From)]),
|
||||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]}
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]}
|
||||||
end;
|
end;
|
||||||
process_iq(_From, #iq{sub_el = SubEl} = IQ, _State) ->
|
process_iq(_From, #iq{sub_el = SubEl} = IQ, _State) ->
|
||||||
|
@ -504,34 +505,46 @@ parse_request(#xmlel{name = <<"request">>, attrs = Attrs} = Request, Lang) ->
|
||||||
end;
|
end;
|
||||||
parse_request(_El, _Lang) -> {error, ?ERR_BAD_REQUEST}.
|
parse_request(_El, _Lang) -> {error, ?ERR_BAD_REQUEST}.
|
||||||
|
|
||||||
-spec create_slot(state(), binary(), binary(), pos_integer(), binary(),
|
-spec create_slot(state(), jid(), binary(), pos_integer(), binary(), binary())
|
||||||
binary())
|
|
||||||
-> {ok, slot()} | {ok, binary(), binary()} | {error, xmlel()}.
|
-> {ok, slot()} | {ok, binary(), binary()} | {error, xmlel()}.
|
||||||
|
|
||||||
create_slot(#state{service_url = undefined, max_size = MaxSize},
|
create_slot(#state{service_url = undefined, max_size = MaxSize},
|
||||||
User, File, Size, _ContentType, Lang) when MaxSize /= infinity,
|
JID, File, Size, _ContentType, Lang) when MaxSize /= infinity,
|
||||||
Size > MaxSize ->
|
Size > MaxSize ->
|
||||||
Text = <<"File larger than ", (jlib:integer_to_binary(MaxSize))/binary,
|
Text = <<"File larger than ", (jlib:integer_to_binary(MaxSize))/binary,
|
||||||
" Bytes.">>,
|
" Bytes.">>,
|
||||||
?INFO_MSG("Rejecting file ~s from ~s (too large: ~B bytes)",
|
?INFO_MSG("Rejecting file ~s from ~s (too large: ~B bytes)",
|
||||||
[File, User, Size]),
|
[File, jlib:jid_to_string(JID), Size]),
|
||||||
{error, ?ERRT_NOT_ACCEPTABLE(Lang, Text)};
|
{error, ?ERRT_NOT_ACCEPTABLE(Lang, Text)};
|
||||||
create_slot(#state{service_url = undefined,
|
create_slot(#state{service_url = undefined,
|
||||||
jid_in_url = JIDinURL,
|
jid_in_url = JIDinURL,
|
||||||
secret_length = SecretLength},
|
secret_length = SecretLength,
|
||||||
User, File, _Size, _ContentType, _Lang) ->
|
server_host = ServerHost,
|
||||||
UserStr = make_user_string(User, JIDinURL),
|
docroot = DocRoot},
|
||||||
RandStr = make_rand_string(SecretLength),
|
JID, File, Size, _ContentType, Lang) ->
|
||||||
FileStr = make_file_string(File),
|
UserStr = make_user_string(JID, JIDinURL),
|
||||||
?INFO_MSG("Got HTTP upload slot for ~s (file: ~s)", [User, File]),
|
UserDir = <<DocRoot/binary, $/, UserStr/binary>>,
|
||||||
{ok, [UserStr, RandStr, FileStr]};
|
case ejabberd_hooks:run_fold(http_upload_slot_request, ServerHost, allow,
|
||||||
create_slot(#state{service_url = ServiceURL}, User, File, Size, ContentType,
|
[JID, UserDir, Size, Lang]) of
|
||||||
|
allow ->
|
||||||
|
RandStr = make_rand_string(SecretLength),
|
||||||
|
FileStr = make_file_string(File),
|
||||||
|
?INFO_MSG("Got HTTP upload slot for ~s (file: ~s)",
|
||||||
|
[jlib:jid_to_string(JID), File]),
|
||||||
|
{ok, [UserStr, RandStr, FileStr]};
|
||||||
|
deny ->
|
||||||
|
{error, ?ERR_SERVICE_UNAVAILABLE};
|
||||||
|
#xmlel{} = Error ->
|
||||||
|
{error, Error}
|
||||||
|
end;
|
||||||
|
create_slot(#state{service_url = ServiceURL},
|
||||||
|
#jid{luser = U, lserver = S} = JID, File, Size, ContentType,
|
||||||
_Lang) ->
|
_Lang) ->
|
||||||
Options = [{body_format, binary}, {full_result, false}],
|
Options = [{body_format, binary}, {full_result, false}],
|
||||||
HttpOptions = [{timeout, ?SERVICE_REQUEST_TIMEOUT}],
|
HttpOptions = [{timeout, ?SERVICE_REQUEST_TIMEOUT}],
|
||||||
SizeStr = jlib:integer_to_binary(Size),
|
SizeStr = jlib:integer_to_binary(Size),
|
||||||
GetRequest = binary_to_list(ServiceURL) ++
|
GetRequest = binary_to_list(ServiceURL) ++
|
||||||
"?jid=" ++ ?URL_ENC(User) ++
|
"?jid=" ++ ?URL_ENC(jlib:jid_to_string({U, S, <<"">>})) ++
|
||||||
"&name=" ++ ?URL_ENC(File) ++
|
"&name=" ++ ?URL_ENC(File) ++
|
||||||
"&size=" ++ ?URL_ENC(SizeStr) ++
|
"&size=" ++ ?URL_ENC(SizeStr) ++
|
||||||
"&content_type=" ++ ?URL_ENC(ContentType),
|
"&content_type=" ++ ?URL_ENC(ContentType),
|
||||||
|
@ -540,29 +553,32 @@ create_slot(#state{service_url = ServiceURL}, User, File, Size, ContentType,
|
||||||
case binary:split(Body, <<$\n>>, [global, trim]) of
|
case binary:split(Body, <<$\n>>, [global, trim]) of
|
||||||
[<<"http", _/binary>> = PutURL, <<"http", _/binary>> = GetURL] ->
|
[<<"http", _/binary>> = PutURL, <<"http", _/binary>> = GetURL] ->
|
||||||
?INFO_MSG("Got HTTP upload slot for ~s (file: ~s)",
|
?INFO_MSG("Got HTTP upload slot for ~s (file: ~s)",
|
||||||
[User, File]),
|
[jlib:jid_to_string(JID), File]),
|
||||||
{ok, PutURL, GetURL};
|
{ok, PutURL, GetURL};
|
||||||
Lines ->
|
Lines ->
|
||||||
?ERROR_MSG("Cannot parse data received for ~s from <~s>: ~p",
|
?ERROR_MSG("Cannot parse data received for ~s from <~s>: ~p",
|
||||||
[User, ServiceURL, Lines]),
|
[jlib:jid_to_string(JID), ServiceURL, Lines]),
|
||||||
{error, ?ERR_SERVICE_UNAVAILABLE}
|
{error, ?ERR_SERVICE_UNAVAILABLE}
|
||||||
end;
|
end;
|
||||||
{ok, {402, _Body}} ->
|
{ok, {402, _Body}} ->
|
||||||
?INFO_MSG("Got status code 402 for ~s from <~s>", [User, ServiceURL]),
|
?INFO_MSG("Got status code 402 for ~s from <~s>",
|
||||||
|
[jlib:jid_to_string(JID), ServiceURL]),
|
||||||
{error, ?ERR_RESOURCE_CONSTRAINT};
|
{error, ?ERR_RESOURCE_CONSTRAINT};
|
||||||
{ok, {403, _Body}} ->
|
{ok, {403, _Body}} ->
|
||||||
?INFO_MSG("Got status code 403 for ~s from <~s>", [User, ServiceURL]),
|
?INFO_MSG("Got status code 403 for ~s from <~s>",
|
||||||
|
[jlib:jid_to_string(JID), ServiceURL]),
|
||||||
{error, ?ERR_NOT_ALLOWED};
|
{error, ?ERR_NOT_ALLOWED};
|
||||||
{ok, {413, _Body}} ->
|
{ok, {413, _Body}} ->
|
||||||
?INFO_MSG("Got status code 413 for ~s from <~s>", [User, ServiceURL]),
|
?INFO_MSG("Got status code 413 for ~s from <~s>",
|
||||||
|
[jlib:jid_to_string(JID), ServiceURL]),
|
||||||
{error, ?ERR_NOT_ACCEPTABLE};
|
{error, ?ERR_NOT_ACCEPTABLE};
|
||||||
{ok, {Code, _Body}} ->
|
{ok, {Code, _Body}} ->
|
||||||
?ERROR_MSG("Got unexpected status code for ~s from <~s>: ~B",
|
?ERROR_MSG("Got unexpected status code for ~s from <~s>: ~B",
|
||||||
[User, ServiceURL, Code]),
|
[jlib:jid_to_string(JID), ServiceURL, Code]),
|
||||||
{error, ?ERR_SERVICE_UNAVAILABLE};
|
{error, ?ERR_SERVICE_UNAVAILABLE};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ERROR_MSG("Error requesting upload slot for ~s from <~s>: ~p",
|
?ERROR_MSG("Error requesting upload slot for ~s from <~s>: ~p",
|
||||||
[User, ServiceURL, Reason]),
|
[jlib:jid_to_string(JID), ServiceURL, Reason]),
|
||||||
{error, ?ERR_SERVICE_UNAVAILABLE}
|
{error, ?ERR_SERVICE_UNAVAILABLE}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -597,13 +613,12 @@ slot_el(PutURL, GetURL, XMLNS) ->
|
||||||
#xmlel{name = <<"get">>,
|
#xmlel{name = <<"get">>,
|
||||||
children = [{xmlcdata, GetURL}]}]}.
|
children = [{xmlcdata, GetURL}]}]}.
|
||||||
|
|
||||||
-spec make_user_string(binary(), sha1 | node) -> binary().
|
-spec make_user_string(jid(), sha1 | node) -> binary().
|
||||||
|
|
||||||
make_user_string(User, sha1) ->
|
make_user_string(#jid{luser = U, lserver = S}, sha1) ->
|
||||||
p1_sha:sha(User);
|
p1_sha:sha(<<U/binary, $@, S/binary>>);
|
||||||
make_user_string(User, node) ->
|
make_user_string(#jid{luser = U}, node) ->
|
||||||
[Node, _Domain] = binary:split(User, <<$@>>),
|
re:replace(U, <<"[^a-zA-Z0-9_.-]">>, <<$_>>, [global, {return, binary}]).
|
||||||
re:replace(Node, <<"[^a-zA-Z0-9_.-]">>, <<$_>>, [global, {return, binary}]).
|
|
||||||
|
|
||||||
-spec make_file_string(binary()) -> binary().
|
-spec make_file_string(binary()) -> binary().
|
||||||
|
|
||||||
|
@ -769,17 +784,16 @@ get_proc_name(ServerHost) ->
|
||||||
-spec remove_user(binary(), binary()) -> ok.
|
-spec remove_user(binary(), binary()) -> ok.
|
||||||
|
|
||||||
remove_user(User, Server) ->
|
remove_user(User, Server) ->
|
||||||
LUser = jlib:nodeprep(User),
|
ServerHost = jlib:nameprep(Server),
|
||||||
LServer = jlib:nameprep(Server),
|
DocRoot = gen_mod:get_module_opt(ServerHost, ?MODULE, docroot,
|
||||||
DocRoot = gen_mod:get_module_opt(LServer, ?MODULE, docroot,
|
|
||||||
fun iolist_to_binary/1,
|
fun iolist_to_binary/1,
|
||||||
<<"@HOME@/upload">>),
|
<<"@HOME@/upload">>),
|
||||||
JIDinURL = gen_mod:get_module_opt(LServer, ?MODULE, jid_in_url,
|
JIDinURL = gen_mod:get_module_opt(ServerHost, ?MODULE, jid_in_url,
|
||||||
fun(sha1) -> sha1;
|
fun(sha1) -> sha1;
|
||||||
(node) -> node
|
(node) -> node
|
||||||
end,
|
end,
|
||||||
sha1),
|
sha1),
|
||||||
UserStr = make_user_string(<<LUser/binary, $@, LServer/binary>>, JIDinURL),
|
UserStr = make_user_string(jlib:make_jid(User, Server, <<"">>), JIDinURL),
|
||||||
UserDir = str:join([expand_home(DocRoot), UserStr], <<$/>>),
|
UserDir = str:join([expand_home(DocRoot), UserStr], <<$/>>),
|
||||||
case del_tree(UserDir) of
|
case del_tree(UserDir) of
|
||||||
ok ->
|
ok ->
|
||||||
|
|
Loading…
Reference in New Issue