From 309962fb8b70dc42dbfcc98b4e64bd251aad84b9 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Mon, 14 Nov 2016 16:52:03 +0100 Subject: [PATCH 01/16] Use p1_http from p1_utils 1.0.6 --- rebar.config | 2 +- src/ejabberd_app.erl | 1 - src/ext_mod.erl | 4 +- src/http_p1.erl | 358 --------------------------------------- src/mod_ip_blacklist.erl | 4 +- src/rest.erl | 6 +- 6 files changed, 8 insertions(+), 367 deletions(-) delete mode 100644 src/http_p1.erl diff --git a/rebar.config b/rebar.config index 3ad5cf6e7..06ca9ab10 100644 --- a/rebar.config +++ b/rebar.config @@ -8,7 +8,7 @@ %%%------------------------------------------------------------------- {deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.2.1"}}}, - {p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.5"}}}, + {p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.6"}}}, {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.4"}}}, {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}}, {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}}, diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index e88f24e1e..1791aa790 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -225,7 +225,6 @@ start_apps() -> ejabberd:start_app(fast_tls), ejabberd:start_app(fast_xml), ejabberd:start_app(stringprep), - http_p1:start(), ejabberd:start_app(cache_tab). opt_type(net_ticktime) -> diff --git a/src/ext_mod.erl b/src/ext_mod.erl index 842bb09fc..2f71343a2 100644 --- a/src/ext_mod.erl +++ b/src/ext_mod.erl @@ -45,7 +45,7 @@ start() -> [code:add_patha(module_ebin_dir(Module)) || {Module, _} <- installed()], - application:start(inets), + p1_http:start(), ejabberd_commands:register_commands(get_commands_spec()). stop() -> @@ -271,7 +271,7 @@ geturl(Url, Hdrs, UsrOpts) -> [U, Pass] -> [{proxy_user, U}, {proxy_password, Pass}]; _ -> [] end, - case httpc:request(get, {Url, Hdrs}, Host++User++UsrOpts++[{version, "HTTP/1.0"}], []) of + case p1_http:request(get, Url, Hdrs, [], Host++User++UsrOpts++[{version, "HTTP/1.0"}]) of {ok, {{_, 200, _}, Headers, Response}} -> {ok, Headers, Response}; {ok, {{_, Code, _}, _Headers, Response}} -> diff --git a/src/http_p1.erl b/src/http_p1.erl deleted file mode 100644 index f430bbe11..000000000 --- a/src/http_p1.erl +++ /dev/null @@ -1,358 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% File : http_p1.erl -%%% Author : Emilio Bustos -%%% Purpose : Provide a common API for inets / lhttpc / ibrowse -%%% Created : 29 Jul 2010 by Emilio Bustos -%%% -%%% -%%% ejabberd, Copyright (C) 2002-2016 ProcessOne -%%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License along -%%% with this program; if not, write to the Free Software Foundation, Inc., -%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -%%% -%%%---------------------------------------------------------------------- - --module(http_p1). - --author('ebustos@process-one.net'). - --export([start/0, stop/0, get/1, get/2, post/2, post/3, - request/3, request/4, request/5, - get_pool_size/0, set_pool_size/1]). - --include("logger.hrl"). - --define(USE_INETS, 1). -% -define(USE_LHTTPC, 1). -% -define(USE_IBROWSE, 1). -% inets used as default if none specified - --ifdef(USE_IBROWSE). - -start() -> - ejabberd:start_app(ibrowse). - -stop() -> - application:stop(ibrowse). - -request(Method, URL, Hdrs, Body, Opts) -> - TimeOut = proplists:get_value(timeout, Opts, infinity), - Options = [{inactivity_timeout, TimeOut} - | proplists:delete(timeout, Opts)], - case ibrowse:send_req(URL, Hdrs, Method, Body, Options) - of - {ok, Status, Headers, Response} -> - {ok, jlib:binary_to_integer(Status), Headers, - Response}; - {error, Reason} -> {error, Reason} - end. - -get_pool_size() -> - application:get_env(ibrowse, default_max_sessions, 10). - -set_pool_size(Size) -> - application:set_env(ibrowse, default_max_sessions, Size). - --else. - --ifdef(USE_LHTTPC). - -start() -> - ejabberd:start_app(lhttpc). - -stop() -> - application:stop(lhttpc). - -request(Method, URL, Hdrs, Body, Opts) -> - {[TO, SO], Rest} = proplists:split(Opts, [timeout, socket_options]), - TimeOut = proplists:get_value(timeout, TO, infinity), - SockOpt = proplists:get_value(socket_options, SO, []), - Options = [{connect_options, SockOpt} | Rest], - Result = lhttpc:request(URL, Method, Hdrs, Body, TimeOut, Options), - ?DEBUG("HTTP request -> response:~n" - "** Method = ~p~n" - "** URI = ~s~n" - "** Body = ~s~n" - "** Hdrs = ~p~n" - "** Timeout = ~p~n" - "** Options = ~p~n" - "** Response = ~p", - [Method, URL, Body, Hdrs, TimeOut, Options, Result]), - case Result of - {ok, {{Status, _Reason}, Headers, Response}} -> - {ok, Status, Headers, (Response)}; - {error, Reason} -> {error, Reason} - end. - -get_pool_size() -> - Opts = proplists:get_value(lhttpc_manager, lhttpc_manager:list_pools()), - proplists:get_value(max_pool_size,Opts). - -set_pool_size(Size) -> - lhttpc_manager:set_max_pool_size(lhttpc_manager, Size). - --else. - -start() -> - ejabberd:start_app(inets). - -stop() -> - application:stop(inets). - -to_list(Str) when is_binary(Str) -> - binary_to_list(Str); -to_list(Str) -> - Str. - -request(Method, URLRaw, HdrsRaw, Body, Opts) -> - Hdrs = lists:map(fun({N, V}) -> - {to_list(N), to_list(V)} - end, HdrsRaw), - URL = to_list(URLRaw), - - Request = case Method of - get -> {URL, Hdrs}; - head -> {URL, Hdrs}; - delete -> {URL, Hdrs}; - _ -> % post, etc. - {URL, Hdrs, - to_list(proplists:get_value(<<"content-type">>, HdrsRaw, [])), - Body} - end, - Options = case proplists:get_value(timeout, Opts, - infinity) - of - infinity -> proplists:delete(timeout, Opts); - _ -> Opts - end, - case httpc:request(Method, Request, Options, []) of - {ok, {{_, Status, _}, Headers, Response}} -> - {ok, Status, Headers, Response}; - {error, Reason} -> {error, Reason} - end. - -get_pool_size() -> - {ok, Size} = httpc:get_option(max_sessions), - Size. - -set_pool_size(Size) -> - httpc:set_option(max_sessions, Size). - --endif. - --endif. - --type({header, - {type, 63, tuple, - [{type, 63, union, - [{type, 63, string, []}, {type, 63, atom, []}]}, - {type, 63, string, []}]}, - []}). - --type({headers, - {type, 64, list, [{type, 64, header, []}]}, []}). - --type({option, - {type, 67, union, - [{type, 67, tuple, - [{atom, 67, connect_timeout}, {type, 67, timeout, []}]}, - {type, 68, tuple, - [{atom, 68, timeout}, {type, 68, timeout, []}]}, - {type, 70, tuple, - [{atom, 70, send_retry}, - {type, 70, non_neg_integer, []}]}, - {type, 71, tuple, - [{atom, 71, partial_upload}, - {type, 71, union, - [{type, 71, non_neg_integer, []}, - {atom, 71, infinity}]}]}, - {type, 72, tuple, - [{atom, 72, partial_download}, {type, 72, pid, []}, - {type, 72, union, - [{type, 72, non_neg_integer, []}, - {atom, 72, infinity}]}]}]}, - []}). - --type({options, - {type, 74, list, [{type, 74, option, []}]}, []}). - --type({result, - {type, 76, union, - [{type, 76, tuple, - [{atom, 76, ok}, - {type, 76, tuple, - [{type, 76, tuple, - [{type, 76, pos_integer, []}, {type, 76, string, []}]}, - {type, 76, headers, []}, {type, 76, string, []}]}]}, - {type, 77, tuple, - [{atom, 77, error}, {type, 77, atom, []}]}]}, - []}). - -%% @spec (URL) -> Result -%% URL = string() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a GET request. -%% Would be the same as calling `request(get, URL, [])', -%% that is {@link request/3} with an empty header list. -%% @end -%% @see request/3 --spec get(string()) -> result(). -get(URL) -> request(get, URL, []). - -%% @spec (URL, Hdrs) -> Result -%% URL = string() -%% Hdrs = [{Header, Value}] -%% Header = string() -%% Value = string() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a GET request. -%% Would be the same as calling `request(get, URL, Hdrs)'. -%% @end -%% @see request/3 --spec get(string(), headers()) -> result(). -get(URL, Hdrs) -> request(get, URL, Hdrs). - -%% @spec (URL, RequestBody) -> Result -%% URL = string() -%% RequestBody = string() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a POST request with form data. -%% Would be the same as calling -%% `request(post, URL, [{"content-type", "x-www-form-urlencoded"}], Body)'. -%% @end -%% @see request/4 --spec post(string(), string()) -> result(). -post(URL, Body) -> - request(post, URL, - [{<<"content-type">>, <<"x-www-form-urlencoded">>}], - Body). - -%% @spec (URL, Hdrs, RequestBody) -> Result -%% URL = string() -%% Hdrs = [{Header, Value}] -%% Header = string() -%% Value = string() -%% RequestBody = string() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a POST request. -%% Would be the same as calling -%% `request(post, URL, Hdrs, Body)'. -%% @end -%% @see request/4 --spec post(string(), headers(), string()) -> result(). -post(URL, Hdrs, Body) -> - NewHdrs = case [X - || {X, _} <- Hdrs, - str:to_lower(X) == <<"content-type">>] - of - [] -> - [{<<"content-type">>, <<"x-www-form-urlencoded">>} - | Hdrs]; - _ -> Hdrs - end, - request(post, URL, NewHdrs, Body). - -%% @spec (Method, URL, Hdrs) -> Result -%% Method = atom() -%% URL = string() -%% Hdrs = [{Header, Value}] -%% Header = string() -%% Value = string() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a request without a body. -%% Would be the same as calling `request(Method, URL, Hdrs, [], [])', -%% that is {@link request/5} with an empty body. -%% @end -%% @see request/5 --spec request(atom(), string(), headers()) -> result(). -request(Method, URL, Hdrs) -> - request(Method, URL, Hdrs, [], []). - -%% @spec (Method, URL, Hdrs, RequestBody) -> Result -%% Method = atom() -%% URL = string() -%% Hdrs = [{Header, Value}] -%% Header = string() -%% Value = string() -%% RequestBody = string() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a request with a body. -%% Would be the same as calling -%% `request(Method, URL, Hdrs, Body, [])', that is {@link request/5} -%% with no options. -%% @end -%% @see request/5 --spec request(atom(), string(), headers(), string()) -> result(). -request(Method, URL, Hdrs, Body) -> - request(Method, URL, Hdrs, Body, []). - -%% @spec (Method, URL, Hdrs, RequestBody, Options) -> Result -%% Method = atom() -%% URL = string() -%% Hdrs = [{Header, Value}] -%% Header = string() -%% Value = string() -%% RequestBody = string() -%% Options = [Option] -%% Option = {timeout, Milliseconds | infinity} | -%% {connect_timeout, Milliseconds | infinity} | -%% {socket_options, [term()]} | - -%% Milliseconds = integer() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a request with a body. -%% Would be the same as calling -%% `request(Method, URL, Hdrs, Body, [])', that is {@link request/5} -%% with no options. -%% @end -%% @see request/5 --spec request(atom(), string(), headers(), string(), options()) -> result(). - -% ibrowse {response_format, response_format()} | -% Options - [option()] -% Option - {sync, boolean()} | {stream, StreamTo} | {body_format, body_format()} | {full_result, -% boolean()} | {headers_as_is, boolean()} -%body_format() = string() | binary() -% The body_format option is only valid for the synchronous request and the default is string. -% When making an asynchronous request the body will always be received as a binary. -% lhttpc: always binary - diff --git a/src/mod_ip_blacklist.erl b/src/mod_ip_blacklist.erl index 897810927..ab17a8891 100644 --- a/src/mod_ip_blacklist.erl +++ b/src/mod_ip_blacklist.erl @@ -89,9 +89,9 @@ loop(_State) -> receive stop -> ok end. %% TODO: Support comment lines starting by % update_bl_c2s() -> ?INFO_MSG("Updating C2S Blacklist", []), - case httpc:request(?BLC2S) of + case p1_http:get(?BLC2S) of {ok, 200, _Headers, Body} -> - IPs = str:tokens(Body, <<"\n">>), + IPs = str:tokens(iolist_to_binary(Body), <<"\n">>), ets:delete_all_objects(bl_c2s), lists:foreach(fun (IP) -> ets:insert(bl_c2s, diff --git a/src/rest.erl b/src/rest.erl index 01b04f66a..e5c6fd963 100644 --- a/src/rest.erl +++ b/src/rest.erl @@ -36,14 +36,14 @@ -define(CONNECT_TIMEOUT, 8000). start(Host) -> - http_p1:start(), + p1_http:start(), Pool_size = ejabberd_config:get_option({ext_api_http_pool_size, Host}, fun(X) when is_integer(X), X > 0-> X end, 100), - http_p1:set_pool_size(Pool_size). + p1_http:set_pool_size(Pool_size). stop(_Host) -> ok. @@ -91,7 +91,7 @@ request(Server, Method, Path, Params, Mime, Data) -> {"content-type", Mime}, {"User-Agent", "ejabberd"}], Begin = os:timestamp(), - Result = case catch http_p1:request(Method, URI, Hdrs, Data, Opts) of + Result = case catch p1_http:request(Method, URI, Hdrs, Data, Opts) of {ok, Code, _, <<>>} -> {ok, Code, []}; {ok, Code, _, <<" ">>} -> From 717159a98fe925260578aeedd4436eb6ae5df4f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 10 Nov 2016 11:15:34 +0100 Subject: [PATCH 02/16] Make string args in http_api be list strings --- src/mod_http_api.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mod_http_api.erl b/src/mod_http_api.erl index 881587ede..a189777b1 100644 --- a/src/mod_http_api.erl +++ b/src/mod_http_api.erl @@ -273,7 +273,7 @@ handle(Call, Auth, Args, Version) when is_atom(Call), is_list(Args) -> fun ({Key, binary}, Acc) -> [{Key, <<>>}|Acc]; ({Key, string}, Acc) -> - [{Key, <<>>}|Acc]; + [{Key, ""}|Acc]; ({Key, integer}, Acc) -> [{Key, 0}|Acc]; ({Key, {list, _}}, Acc) -> @@ -406,10 +406,10 @@ format_arg(Elements, {list, ElementsDef}) format_arg(Arg, integer) when is_integer(Arg) -> Arg; format_arg(Arg, binary) when is_list(Arg) -> process_unicode_codepoints(Arg); format_arg(Arg, binary) when is_binary(Arg) -> Arg; -format_arg(Arg, string) when is_list(Arg) -> process_unicode_codepoints(Arg); -format_arg(Arg, string) when is_binary(Arg) -> Arg; +format_arg(Arg, string) when is_list(Arg) -> Arg; +format_arg(Arg, string) when is_binary(Arg) -> binary_to_list(Arg); format_arg(undefined, binary) -> <<>>; -format_arg(undefined, string) -> <<>>; +format_arg(undefined, string) -> ""; format_arg(Arg, Format) -> ?ERROR_MSG("don't know how to format Arg ~p for format ~p", [Arg, Format]), throw({invalid_parameter, From 5ffc01db5301fddae639701479f5c19ed2267723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 10 Nov 2016 11:20:57 +0100 Subject: [PATCH 03/16] Fix types in check_password_hash --- src/mod_admin_extra.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 2967e86a0..053ce8092 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -176,8 +176,8 @@ get_commands_spec() -> desc = "Check if the password hash is correct", longdesc = "Allowed hash methods: md5, sha.", module = ?MODULE, function = check_password_hash, - args = [{user, binary}, {host, binary}, {passwordhash, string}, - {hashmethod, string}], + args = [{user, binary}, {host, binary}, {passwordhash, binary}, + {hashmethod, binary}], args_example = [<<"peter">>, <<"myserver.com">>, <<"5ebe2294ecd0e0f08eab7690d2a6ee69">>, <<"md5">>], args_desc = ["User name to check", "Server to check", From 41794c57d67ab1dee63e8b67acb7b3ede5a26b92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Tue, 15 Nov 2016 09:59:04 +0100 Subject: [PATCH 04/16] Use new version of fast_xml --- rebar.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rebar.config b/rebar.config index 06ca9ab10..fca8d19e2 100644 --- a/rebar.config +++ b/rebar.config @@ -12,7 +12,7 @@ {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.4"}}}, {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}}, {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}}, - {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.15"}}}, + {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.16"}}}, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.7"}}}, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.8"}}}, {fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.6"}}}, From e75dd17e2ccb12338bfeaa9c5ea49e37d015a733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Tue, 15 Nov 2016 09:59:40 +0100 Subject: [PATCH 05/16] Fix tests that use #forwarded --- test/ejabberd_SUITE.erl | 22 +++++++++++----------- test/suite.erl | 15 ++++++++++++++- test/suite.hrl | 3 +++ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 121719cdf..3ac12953c 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -2083,7 +2083,7 @@ retrieve_messages_from_room_via_mam(Config, Range) -> xmlns = ?NS_MAM_1, queryid = QID, sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ from = MyNickJID, @@ -2411,7 +2411,7 @@ carbons_slave(Config) -> #message{from = MyBareJID, to = MyJID, type = chat, sub_els = [#carbons_sent{ - forwarded = #forwarded{ + forwarded = #forwarded_decoded{ sub_els = [#message{from = Peer, to = MyBareJID, @@ -2420,7 +2420,7 @@ carbons_slave(Config) -> #message{from = MyBareJID, to = MyJID, type = chat, sub_els = [#carbons_sent{ - forwarded = #forwarded{ + forwarded = #forwarded_decoded{ sub_els = [#message{from = Peer, to = Peer, @@ -2429,7 +2429,7 @@ carbons_slave(Config) -> #message{from = MyBareJID, to = MyJID, type = chat, sub_els = [#carbons_received{ - forwarded = #forwarded{ + forwarded = #forwarded_decoded{ sub_els = [#message{from = Peer, to = MyBareJID, @@ -2438,7 +2438,7 @@ carbons_slave(Config) -> #message{from = MyBareJID, to = MyJID, type = chat, sub_els = [#carbons_received{ - forwarded = #forwarded{ + forwarded = #forwarded_decoded{ sub_els = [#message{from = Peer, to = Peer, @@ -2560,7 +2560,7 @@ mam_query_all(Config, NS) -> [#mam_result{ queryid = QID, sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ @@ -2599,7 +2599,7 @@ mam_query_with(Config, JID, NS) -> sub_els = [#mam_result{ sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ @@ -2640,7 +2640,7 @@ mam_query_rsm(Config, NS) -> [#mam_result{ xmlns = NS, sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ @@ -2677,7 +2677,7 @@ mam_query_rsm(Config, NS) -> [#mam_result{ xmlns = NS, sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ @@ -2717,7 +2717,7 @@ mam_query_rsm(Config, NS) -> [#mam_result{ xmlns = NS, sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ @@ -2773,7 +2773,7 @@ mam_query_rsm(Config, NS) -> [#mam_result{ xmlns = NS, sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ diff --git a/test/suite.erl b/test/suite.erl index 52c030df1..3c46e8f6b 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -481,9 +481,22 @@ format_element(El) -> false -> io_lib:format(" ~s~n", El) end. +substitute_forwarded(#mam_result{sub_els = Sub} = El) -> + El#mam_result{sub_els = [substitute_forwarded(SEl) || SEl <- Sub]}; +substitute_forwarded(#carbons_sent{forwarded = Sub} = El) -> + El#carbons_sent{forwarded = [substitute_forwarded(SEl) || SEl <- Sub]}; +substitute_forwarded(#message{sub_els = Sub} = El) -> + El#message{sub_els = [substitute_forwarded(SEl) || SEl <- Sub]}; +substitute_forwarded(#forwarded{delay = Delay, xml_els = Sub}) -> + #forwarded_decoded{delay = Delay, sub_els = [xmpp:decode(SEl) || SEl <- Sub]}; +substitute_forwarded(El) -> + El. + + + decode(El, NS, Opts) -> try - Pkt = xmpp:decode(El, NS, Opts), + Pkt = substitute_forwarded(xmpp:decode(El, NS, Opts)), ct:pal("RECV:~n~s~n~s", [format_element(El), xmpp:pp(Pkt)]), Pkt diff --git a/test/suite.hrl b/test/suite.hrl index 00239f8cf..d9a9c5ab0 100644 --- a/test/suite.hrl +++ b/test/suite.hrl @@ -5,6 +5,9 @@ -include("mod_proxy65.hrl"). -include("xmpp_codec.hrl"). +-record(forwarded_decoded, {delay :: #delay{}, + sub_els = [] :: [fxml:xmlel()]}). + -define(STREAM_TRAILER, <<"">>). -define(PUBSUB(Node), <<(?NS_PUBSUB)/binary, "#", Node>>). From 909e0eb5dd097f077512210a6ed169e9d3d72a61 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 15 Nov 2016 14:18:34 +0100 Subject: [PATCH 06/16] Add configurable weight for commands --- include/ejabberd_commands.hrl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/ejabberd_commands.hrl b/include/ejabberd_commands.hrl index c5c34b743..199be890e 100644 --- a/include/ejabberd_commands.hrl +++ b/include/ejabberd_commands.hrl @@ -46,12 +46,13 @@ %% to command, so that the command can perform additional check. -record(ejabberd_commands, - {name :: atom(), + {name :: atom(), tags = [] :: [atom()] | '_' | '$2', desc = "" :: string() | '_' | '$3', longdesc = "" :: string() | '_', - version = 0 :: integer(), - module :: atom() | '_', + version = 0 :: integer(), + weight = 1 :: integer(), + module :: atom() | '_', function :: atom() | '_', args = [] :: [aterm()] | '_' | '$1' | '$2', policy = restricted :: open | restricted | admin | user, From 2b93de691248629d75e1d2657d09ebd990670924 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Mon, 16 Jun 2014 19:49:08 +0200 Subject: [PATCH 07/16] apply string optimizations --- src/str.erl | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/str.erl b/src/str.erl index 439ae6a7a..43fd51878 100644 --- a/src/str.erl +++ b/src/str.erl @@ -93,7 +93,10 @@ rchr(B, C) -> -spec str(binary(), binary()) -> non_neg_integer(). str(B1, B2) -> - string:str(binary_to_list(B1), binary_to_list(B2)). + case binary:match(B1, B2) of + {R, _Len} -> R+1; + _ -> 0 + end. -spec rstr(binary(), binary()) -> non_neg_integer(). @@ -113,7 +116,7 @@ cspan(B1, B2) -> -spec copies(binary(), non_neg_integer()) -> binary(). copies(B, N) -> - iolist_to_binary(string:copies(binary_to_list(B), N)). + binary:copy(B, N). -spec words(binary()) -> pos_integer(). @@ -201,7 +204,7 @@ join(L, Sep) -> -spec substr(binary(), pos_integer()) -> binary(). substr(B, N) -> - iolist_to_binary(string:substr(binary_to_list(B), N)). + binary_part(B, N-1, byte_size(B)-N+1). -spec chr(binary(), char()) -> non_neg_integer(). @@ -221,7 +224,7 @@ chars(C, N) -> -spec substr(binary(), pos_integer(), non_neg_integer()) -> binary(). substr(B, S, E) -> - iolist_to_binary(string:substr(binary_to_list(B), S, E)). + binary_part(B, S-1, E). -spec strip(binary(), both | left | right, char()) -> binary(). From 8df68266f2e0bf4cb0d1d51ec8a8372affadc8e5 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 9 Aug 2016 10:53:58 +0200 Subject: [PATCH 08/16] Add missing verbs for RESTfull operation --- src/rest.erl | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/rest.erl b/src/rest.erl index e5c6fd963..091002fa5 100644 --- a/src/rest.erl +++ b/src/rest.erl @@ -28,7 +28,7 @@ -behaviour(ejabberd_config). -export([start/1, stop/1, get/2, get/3, post/4, delete/2, - request/6, with_retry/4, opt_type/1]). + put/4, patch/4, request/6, with_retry/4, opt_type/1]). -include("logger.hrl"). @@ -71,18 +71,17 @@ delete(Server, Path) -> request(Server, delete, Path, [], "application/json", <<>>). post(Server, Path, Params, Content) -> - Data = case catch jiffy:encode(Content) of - {'EXIT', Reason} -> - ?ERROR_MSG("HTTP content encodage failed:~n" - "** Content = ~p~n" - "** Err = ~p", - [Content, Reason]), - <<>>; - Encoded -> - Encoded - end, + Data = encode_json(Content), request(Server, post, Path, Params, "application/json", Data). +put(Server, Path, Params, Content) -> + Data = encode_json(Content), + request(Server, put, Path, Params, "application/json", Data). + +patch(Server, Path, Params, Content) -> + Data = encode_json(Content), + request(Server, patch, Path, Params, "application/json", Data). + request(Server, Method, Path, Params, Mime, Data) -> URI = url(Server, Path, Params), Opts = [{connect_timeout, ?CONNECT_TIMEOUT}, @@ -147,6 +146,18 @@ request(Server, Method, Path, Params, Mime, Data) -> %%% HTTP helpers %%%---------------------------------------------------------------------- +encode_json(Content) -> + case catch jiffy:encode(Content) of + {'EXIT', Reason} -> + ?ERROR_MSG("HTTP content encodage failed:~n" + "** Content = ~p~n" + "** Err = ~p", + [Content, Reason]), + <<>>; + Encoded -> + Encoded + end. + base_url(Server, Path) -> Tail = case iolist_to_binary(Path) of <<$/, Ok/binary>> -> Ok; From 4d4ad922a2deaf576bece4389b0ba04cfd1cfe04 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 15 Nov 2016 18:14:21 +0100 Subject: [PATCH 09/16] Cosmetic validator changes --- src/mod_proxy65.erl | 6 ++---- src/mod_register.erl | 9 +++------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/mod_proxy65.erl b/src/mod_proxy65.erl index beea35725..2d0d9ae0a 100644 --- a/src/mod_proxy65.erl +++ b/src/mod_proxy65.erl @@ -93,12 +93,10 @@ mod_opt_type(auth_type) -> end; mod_opt_type(recbuf) -> fun (I) when is_integer(I), I > 0 -> I end; -mod_opt_type(shaper) -> - fun (A) when is_atom(A) -> A end; +mod_opt_type(shaper) -> fun acl:shaper_rules_validator/1; mod_opt_type(sndbuf) -> fun (I) when is_integer(I), I > 0 -> I end; -mod_opt_type(access) -> - fun (A) when is_atom(A) -> A end; +mod_opt_type(access) -> fun acl:access_rules_validator/1; mod_opt_type(host) -> fun iolist_to_binary/1; mod_opt_type(hostname) -> fun iolist_to_binary/1; mod_opt_type(ip) -> diff --git a/src/mod_register.erl b/src/mod_register.erl index 44a64539e..dc8ca995c 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -613,14 +613,11 @@ check_ip_access(undefined, _IPAccess) -> check_ip_access(IPAddress, IPAccess) -> acl:match_rule(global, IPAccess, IPAddress). -mod_opt_type(access) -> - fun acl:access_rules_validator/1; -mod_opt_type(access_from) -> - fun (A) when is_atom(A) -> A end; +mod_opt_type(access) -> fun acl:access_rules_validator/1; +mod_opt_type(access_from) -> fun acl:access_rules_validator/1; mod_opt_type(captcha_protected) -> fun (B) when is_boolean(B) -> B end; -mod_opt_type(ip_access) -> - fun acl:access_rules_validator/1; +mod_opt_type(ip_access) -> fun acl:access_rules_validator/1; mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; mod_opt_type(password_strength) -> fun (N) when is_number(N), N >= 0 -> N end; From 2929f5b5bcd27ef825743e2f9db5b1ea122d1a5c Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 15 Nov 2016 18:35:20 +0100 Subject: [PATCH 10/16] Minor cosmetic changes on pubsub code --- src/mod_pubsub.erl | 7 +++---- src/node_flat.erl | 2 +- src/node_flat_sql.erl | 2 +- src/pubsub_subscription.erl | 4 ++-- src/pubsub_subscription_sql.erl | 4 ++-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index a586935b8..a138b1896 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -251,7 +251,7 @@ init([ServerHost, Opts]) -> Host = gen_mod:get_opt_host(ServerHost, Opts, <<"pubsub.@HOST@">>), ejabberd_router:register_route(Host, ServerHost), Access = gen_mod:get_opt(access_createnode, Opts, - fun(A) when is_atom(A) -> A end, all), + fun acl:access_rules_validator/1, all), PepOffline = gen_mod:get_opt(ignore_pep_from_offline, Opts, fun(A) when is_boolean(A) -> A end, true), IQDisc = gen_mod:get_opt(iqdisc, Opts, @@ -262,7 +262,7 @@ init([ServerHost, Opts]) -> fun(A) when is_integer(A) andalso A >= 0 -> A end, ?MAXITEMS), MaxSubsNode = gen_mod:get_opt(max_subscriptions_node, Opts, fun(A) when is_integer(A) andalso A >= 0 -> A end, undefined), - pubsub_index:init(Host, ServerHost, Opts), + [pubsub_index:init(Host, ServerHost, Opts) || gen_mod:db_type(ServerHost, ?MODULE)==mnesia], {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), DefaultModule = plugin(Host, hd(Plugins)), BaseOptions = DefaultModule:options(), @@ -3899,8 +3899,7 @@ purge_offline(Host, LJID, Node) -> Error end. -mod_opt_type(access_createnode) -> - fun (A) when is_atom(A) -> A end; +mod_opt_type(access_createnode) -> fun acl:access_rules_validator/1; mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(host) -> fun iolist_to_binary/1; mod_opt_type(ignore_pep_from_offline) -> diff --git a/src/node_flat.erl b/src/node_flat.erl index 3afa49f22..9c1bc9b98 100644 --- a/src/node_flat.erl +++ b/src/node_flat.erl @@ -50,7 +50,7 @@ path_to_node/1, can_fetch_item/2, is_subscribed/1]). init(_Host, _ServerHost, _Opts) -> - %pubsub_subscription:init(), + %pubsub_subscription:init(Host, ServerHost, Opts), mnesia:create_table(pubsub_state, [{disc_copies, [node()]}, {type, ordered_set}, diff --git a/src/node_flat_sql.erl b/src/node_flat_sql.erl index 5adf1e559..7e5ce788f 100644 --- a/src/node_flat_sql.erl +++ b/src/node_flat_sql.erl @@ -61,7 +61,7 @@ encode_host_like/1]). init(_Host, _ServerHost, _Opts) -> - %%pubsub_subscription_sql:init(), + %%pubsub_subscription_sql:init(Host, ServerHost, Opts), ok. terminate(_Host, _ServerHost) -> diff --git a/src/pubsub_subscription.erl b/src/pubsub_subscription.erl index f2c962257..297c6627c 100644 --- a/src/pubsub_subscription.erl +++ b/src/pubsub_subscription.erl @@ -28,7 +28,7 @@ -author("bjc@kublai.com"). %% API --export([init/0, subscribe_node/3, unsubscribe_node/3, +-export([init/3, subscribe_node/3, unsubscribe_node/3, get_subscription/3, set_subscription/4, make_subid/0, get_options_xform/2, parse_options_xform/1]). @@ -73,7 +73,7 @@ %%==================================================================== %% API %%==================================================================== -init() -> ok = create_table(). +init(_Host, _ServerHost, _Opts) -> ok = create_table(). subscribe_node(JID, NodeId, Options) -> case catch mnesia:sync_dirty(fun add_subscription/3, [JID, NodeId, Options]) diff --git a/src/pubsub_subscription_sql.erl b/src/pubsub_subscription_sql.erl index 922b2a418..bb7b64112 100644 --- a/src/pubsub_subscription_sql.erl +++ b/src/pubsub_subscription_sql.erl @@ -28,7 +28,7 @@ -author("pablo.polvorin@process-one.net"). %% API --export([init/0, subscribe_node/3, unsubscribe_node/3, +-export([init/3, subscribe_node/3, unsubscribe_node/3, get_subscription/3, set_subscription/4, make_subid/0, get_options_xform/2, parse_options_xform/1]). @@ -71,7 +71,7 @@ %% API %%==================================================================== -init() -> ok = create_table(). +init(_Host, _ServerHost, _Opts) -> ok = create_table(). -spec subscribe_node(_JID :: _, _NodeId :: _, Options :: [] | mod_pubsub:subOptions()) -> {result, mod_pubsub:subId()}. From b1723c6e2d83f0d3d65f151a10610f58a54859cf Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 16 Nov 2016 13:11:23 +0100 Subject: [PATCH 11/16] Handle correctly p1_http:request result --- src/ext_mod.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ext_mod.erl b/src/ext_mod.erl index 2f71343a2..a2109e569 100644 --- a/src/ext_mod.erl +++ b/src/ext_mod.erl @@ -272,9 +272,9 @@ geturl(Url, Hdrs, UsrOpts) -> _ -> [] end, case p1_http:request(get, Url, Hdrs, [], Host++User++UsrOpts++[{version, "HTTP/1.0"}]) of - {ok, {{_, 200, _}, Headers, Response}} -> + {ok, 200, Headers, Response} -> {ok, Headers, Response}; - {ok, {{_, Code, _}, _Headers, Response}} -> + {ok, Code, _Headers, Response} -> {error, {Code, Response}}; {error, Reason} -> {error, Reason} From e69ddd981fdc40d0ccbcec37f5abca988f296936 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 16 Nov 2016 13:12:57 +0100 Subject: [PATCH 12/16] Tell git to ignore the example file ejabberd.service --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bf5fe2863..38d6d77f8 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ /doc/version.tex /ebin/ /ejabberd.init +/ejabberd.service /ejabberdctl.example XmppAddr.hrl /rel/ejabberd/ From 3cd174cb56c064e6d4f969677d94cd413003f5e0 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 16 Nov 2016 13:35:50 +0100 Subject: [PATCH 13/16] Ensure that presence_broadcast room option is stored (#1380) --- src/mod_muc_room.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index c83565734..060ac2bcd 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -3548,6 +3548,7 @@ make_opts(StateData) -> ?MAKE_CONFIG_OPT(#config.allow_voice_requests), ?MAKE_CONFIG_OPT(#config.allow_subscription), ?MAKE_CONFIG_OPT(#config.mam), + ?MAKE_CONFIG_OPT(#config.presence_broadcast), ?MAKE_CONFIG_OPT(#config.voice_request_min_interval), ?MAKE_CONFIG_OPT(#config.vcard), {captcha_whitelist, From 8ced3bdbe95c1748ae370a345b29056ba89e2e43 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 16 Nov 2016 14:18:51 +0100 Subject: [PATCH 14/16] Remove obsolete/temp file --- asn1/ELDAPv3.asn1~ | 301 --------------------------------------------- 1 file changed, 301 deletions(-) delete mode 100644 asn1/ELDAPv3.asn1~ diff --git a/asn1/ELDAPv3.asn1~ b/asn1/ELDAPv3.asn1~ deleted file mode 100644 index 1fec35cd8..000000000 --- a/asn1/ELDAPv3.asn1~ +++ /dev/null @@ -1,301 +0,0 @@ --- LDAPv3 ASN.1 specification, taken from RFC 2251 - --- Lightweight-Directory-Access-Protocol-V3 DEFINITIONS -ELDAPv3 DEFINITIONS -IMPLICIT TAGS ::= - -BEGIN - -LDAPMessage ::= SEQUENCE { - messageID MessageID, - protocolOp CHOICE { - bindRequest BindRequest, - bindResponse BindResponse, - unbindRequest UnbindRequest, - searchRequest SearchRequest, - searchResEntry SearchResultEntry, - searchResDone SearchResultDone, - searchResRef SearchResultReference, - modifyRequest ModifyRequest, - modifyResponse ModifyResponse, - addRequest AddRequest, - addResponse AddResponse, - delRequest DelRequest, - delResponse DelResponse, - modDNRequest ModifyDNRequest, - modDNResponse ModifyDNResponse, - compareRequest CompareRequest, - compareResponse CompareResponse, - abandonRequest AbandonRequest, - extendedReq ExtendedRequest, - extendedResp ExtendedResponse }, - controls [0] Controls OPTIONAL } - -MessageID ::= INTEGER (0 .. maxInt) - -maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) -- - -LDAPString ::= OCTET STRING - -LDAPOID ::= OCTET STRING - -LDAPDN ::= LDAPString - -RelativeLDAPDN ::= LDAPString - -AttributeType ::= LDAPString - -AttributeDescription ::= LDAPString - - - - --- Wahl, et. al. Standards Track [Page 44] --- --- RFC 2251 LDAPv3 December 1997 - - -AttributeDescriptionList ::= SEQUENCE OF - AttributeDescription - -AttributeValue ::= OCTET STRING - -AttributeValueAssertion ::= SEQUENCE { - attributeDesc AttributeDescription, - assertionValue AssertionValue } - -AssertionValue ::= OCTET STRING - -Attribute ::= SEQUENCE { - type AttributeDescription, - vals SET OF AttributeValue } - -MatchingRuleId ::= LDAPString - -LDAPResult ::= SEQUENCE { - resultCode ENUMERATED { - success (0), - operationsError (1), - protocolError (2), - timeLimitExceeded (3), - sizeLimitExceeded (4), - compareFalse (5), - compareTrue (6), - authMethodNotSupported (7), - strongAuthRequired (8), - -- 9 reserved -- - referral (10), -- new - adminLimitExceeded (11), -- new - unavailableCriticalExtension (12), -- new - confidentialityRequired (13), -- new - saslBindInProgress (14), -- new - noSuchAttribute (16), - undefinedAttributeType (17), - inappropriateMatching (18), - constraintViolation (19), - attributeOrValueExists (20), - invalidAttributeSyntax (21), - -- 22-31 unused -- - noSuchObject (32), - aliasProblem (33), - invalidDNSyntax (34), - -- 35 reserved for undefined isLeaf -- - aliasDereferencingProblem (36), - -- 37-47 unused -- - inappropriateAuthentication (48), - --- Wahl, et. al. Standards Track [Page 45] --- --- RFC 2251 LDAPv3 December 1997 - - - invalidCredentials (49), - insufficientAccessRights (50), - busy (51), - unavailable (52), - unwillingToPerform (53), - loopDetect (54), - -- 55-63 unused -- - namingViolation (64), - objectClassViolation (65), - notAllowedOnNonLeaf (66), - notAllowedOnRDN (67), - entryAlreadyExists (68), - objectClassModsProhibited (69), - -- 70 reserved for CLDAP -- - affectsMultipleDSAs (71), -- new - -- 72-79 unused -- - other (80) }, - -- 81-90 reserved for APIs -- - matchedDN LDAPDN, - errorMessage LDAPString, - referral [3] Referral OPTIONAL } - -Referral ::= SEQUENCE OF LDAPURL - -LDAPURL ::= LDAPString -- limited to characters permitted in URLs - -Controls ::= SEQUENCE OF Control - -Control ::= SEQUENCE { - controlType LDAPOID, - criticality BOOLEAN DEFAULT FALSE, - controlValue OCTET STRING OPTIONAL } - -BindRequest ::= [APPLICATION 0] SEQUENCE { - version INTEGER (1 .. 127), - name LDAPDN, - authentication AuthenticationChoice } - -AuthenticationChoice ::= CHOICE { - simple [0] OCTET STRING, - -- 1 and 2 reserved - sasl [3] SaslCredentials } - -SaslCredentials ::= SEQUENCE { - mechanism LDAPString, - credentials OCTET STRING OPTIONAL } - -BindResponse ::= [APPLICATION 1] SEQUENCE { - --- Wahl, et. al. Standards Track [Page 46] --- --- RFC 2251 LDAPv3 December 1997 - - - COMPONENTS OF LDAPResult, - serverSaslCreds [7] OCTET STRING OPTIONAL } - -UnbindRequest ::= [APPLICATION 2] NULL - -SearchRequest ::= [APPLICATION 3] SEQUENCE { - baseObject LDAPDN, - scope ENUMERATED { - baseObject (0), - singleLevel (1), - wholeSubtree (2) }, - derefAliases ENUMERATED { - neverDerefAliases (0), - derefInSearching (1), - derefFindingBaseObj (2), - derefAlways (3) }, - sizeLimit INTEGER (0 .. maxInt), - timeLimit INTEGER (0 .. maxInt), - typesOnly BOOLEAN, - filter Filter, - attributes AttributeDescriptionList } - -Filter ::= CHOICE { - and [0] SET OF Filter, - or [1] SET OF Filter, - not [2] Filter, - equalityMatch [3] AttributeValueAssertion, - substrings [4] SubstringFilter, - greaterOrEqual [5] AttributeValueAssertion, - lessOrEqual [6] AttributeValueAssertion, - present [7] AttributeDescription, - approxMatch [8] AttributeValueAssertion, - extensibleMatch [9] MatchingRuleAssertion } - -SubstringFilter ::= SEQUENCE { - type AttributeDescription, - -- at least one must be present - substrings SEQUENCE OF CHOICE { - initial [0] LDAPString, - any [1] LDAPString, - final [2] LDAPString } } - -MatchingRuleAssertion ::= SEQUENCE { - matchingRule [1] MatchingRuleId OPTIONAL, - type [2] AttributeDescription OPTIONAL, - matchValue [3] AssertionValue, - dnAttributes [4] BOOLEAN DEFAULT FALSE } - --- Wahl, et. al. Standards Track [Page 47] --- --- RFC 2251 LDAPv3 December 1997 - -SearchResultEntry ::= [APPLICATION 4] SEQUENCE { - objectName LDAPDN, - attributes PartialAttributeList } - -PartialAttributeList ::= SEQUENCE OF SEQUENCE { - type AttributeDescription, - vals SET OF AttributeValue } - -SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL - -SearchResultDone ::= [APPLICATION 5] LDAPResult - -ModifyRequest ::= [APPLICATION 6] SEQUENCE { - object LDAPDN, - modification SEQUENCE OF SEQUENCE { - operation ENUMERATED { - add (0), - delete (1), - replace (2) }, - modification AttributeTypeAndValues } } - -AttributeTypeAndValues ::= SEQUENCE { - type AttributeDescription, - vals SET OF AttributeValue } - -ModifyResponse ::= [APPLICATION 7] LDAPResult - -AddRequest ::= [APPLICATION 8] SEQUENCE { - entry LDAPDN, - attributes AttributeList } - -AttributeList ::= SEQUENCE OF SEQUENCE { - type AttributeDescription, - vals SET OF AttributeValue } - -AddResponse ::= [APPLICATION 9] LDAPResult - -DelRequest ::= [APPLICATION 10] LDAPDN - -DelResponse ::= [APPLICATION 11] LDAPResult - -ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { - entry LDAPDN, - newrdn RelativeLDAPDN, - deleteoldrdn BOOLEAN, - newSuperior [0] LDAPDN OPTIONAL } - -ModifyDNResponse ::= [APPLICATION 13] LDAPResult - --- Wahl, et. al. Standards Track [Page 48] --- --- RFC 2251 LDAPv3 December 1997 - - -CompareRequest ::= [APPLICATION 14] SEQUENCE { - entry LDAPDN, - ava AttributeValueAssertion } - -CompareResponse ::= [APPLICATION 15] LDAPResult - -AbandonRequest ::= [APPLICATION 16] MessageID - -ExtendedRequest ::= [APPLICATION 23] SEQUENCE { - requestName [0] LDAPOID, - requestValue [1] OCTET STRING OPTIONAL } - -ExtendedResponse ::= [APPLICATION 24] SEQUENCE { - COMPONENTS OF LDAPResult, - responseName [10] LDAPOID OPTIONAL, - response [11] OCTET STRING OPTIONAL } - -passwdModifyOID LDAPOID ::= "1.3.6.1.4.1.4203.1.11.1" - -PasswdModifyRequestValue ::= SEQUENCE { - userIdentity [0] OCTET STRING OPTIONAL, - oldPasswd [1] OCTET STRING OPTIONAL, - newPasswd [2] OCTET STRING OPTIONAL } - -PasswdModifyResponseValue ::= SEQUENCE { - genPasswd [0] OCTET STRING OPTIONAL } - -END - - From 1c90b19d748c190e3e6cc7361c2de14d686522af Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 16 Nov 2016 18:24:12 +0100 Subject: [PATCH 15/16] Fix typo --- src/ejabberd_oauth.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl index e03b78fe8..74e26e8da 100644 --- a/src/ejabberd_oauth.erl +++ b/src/ejabberd_oauth.erl @@ -471,7 +471,7 @@ process(_Handlers, [{<<"href">>, <<"https://www.ejabberd.im">>}, {<<"title">>, <<"ejabberd XMPP server">>}], <<"ejabberd">>), - ?C(" is maintained by "), + ?C(<<" is maintained by ">>), ?XAC(<<"a">>, [{<<"href">>, <<"https://www.process-one.net">>}, {<<"title">>, <<"ProcessOne - Leader in Instant Messaging and Push Solutions">>}], From 995c97671d418264d35aa2308f642bf382832638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 17 Nov 2016 12:59:27 +0100 Subject: [PATCH 16/16] Add auth to mod_http_fileserver --- src/mod_http_fileserver.erl | 88 ++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/src/mod_http_fileserver.erl b/src/mod_http_fileserver.erl index 728a2d137..a896cb8b4 100644 --- a/src/mod_http_fileserver.erl +++ b/src/mod_http_fileserver.erl @@ -56,7 +56,7 @@ -record(state, {host, docroot, accesslog, accesslogfd, directory_indices, custom_headers, default_content_type, - content_types = []}). + content_types = [], user_access = none}). -define(PROCNAME, ejabberd_mod_http_fileserver). @@ -133,7 +133,8 @@ start_link(Host, Opts) -> init([Host, Opts]) -> try initialize(Host, Opts) of {DocRoot, AccessLog, AccessLogFD, DirectoryIndices, - CustomHeaders, DefaultContentType, ContentTypes} -> + CustomHeaders, DefaultContentType, ContentTypes, + UserAccess} -> {ok, #state{host = Host, accesslog = AccessLog, accesslogfd = AccessLogFD, @@ -141,7 +142,8 @@ init([Host, Opts]) -> directory_indices = DirectoryIndices, custom_headers = CustomHeaders, default_content_type = DefaultContentType, - content_types = ContentTypes}} + content_types = ContentTypes, + user_access = UserAccess}} catch throw:Reason -> {stop, Reason} @@ -165,7 +167,15 @@ initialize(Host, Opts) -> []), DefaultContentType = gen_mod:get_opt(default_content_type, Opts, fun iolist_to_binary/1, - ?DEFAULT_CONTENT_TYPE), + ?DEFAULT_CONTENT_TYPE), + UserAccess0 = gen_mod:get_opt(must_authenticate_with, Opts, + mod_opt_type(must_authenticate_with), + []), + UserAccess = case UserAccess0 of + [] -> none; + _ -> + dict:from_list(UserAccess0) + end, ContentTypes = build_list_content_types( gen_mod:get_opt(content_types, Opts, fun(L) when is_list(L) -> @@ -180,7 +190,7 @@ initialize(Host, Opts) -> [str:join([[$*, K, " -> ", V] || {K, V} <- ContentTypes], <<", ">>)]), {DocRoot, AccessLog, AccessLogFD, DirectoryIndices, - CustomHeaders, DefaultContentType, ContentTypes}. + CustomHeaders, DefaultContentType, ContentTypes, UserAccess}. %% @spec (AdminCTs::[CT], Default::[CT]) -> [CT] @@ -246,10 +256,11 @@ try_open_log(FN, Host) -> %% {stop, Reason, State} %% Description: Handling call messages %%-------------------------------------------------------------------- -handle_call({serve, LocalPath}, _From, State) -> - Reply = serve(LocalPath, State#state.docroot, State#state.directory_indices, +handle_call({serve, LocalPath, Auth}, _From, State) -> + Reply = serve(LocalPath, Auth, State#state.docroot, State#state.directory_indices, State#state.custom_headers, - State#state.default_content_type, State#state.content_types), + State#state.default_content_type, State#state.content_types, + State#state.user_access), {reply, Reply, State}; handle_call(_Request, _From, State) -> {reply, ok, State}. @@ -305,9 +316,9 @@ code_change(_OldVsn, State, _Extra) -> %% @doc Handle an HTTP request. %% LocalPath is the part of the requested URL path that is "local to the module". %% Returns the page to be sent back to the client and/or HTTP status code. -process(LocalPath, Request) -> +process(LocalPath, #request{host = Host, auth = Auth} = Request) -> ?DEBUG("Requested ~p", [LocalPath]), - try gen_server:call(get_proc_name(Request#request.host), {serve, LocalPath}) of + try gen_server:call(get_proc_name(Host), {serve, LocalPath, Auth}) of {FileSize, Code, Headers, Contents} -> add_to_log(FileSize, Code, Request), {Code, Headers, Contents} @@ -318,21 +329,38 @@ process(LocalPath, Request) -> ejabberd_web:error(not_found) end. -serve(LocalPath, DocRoot, DirectoryIndices, CustomHeaders, DefaultContentType, ContentTypes) -> - FileName = filename:join(filename:split(DocRoot) ++ LocalPath), - case file:read_file_info(FileName) of - {error, enoent} -> ?HTTP_ERR_FILE_NOT_FOUND; - {error, enotdir} -> ?HTTP_ERR_FILE_NOT_FOUND; - {error, eacces} -> ?HTTP_ERR_FORBIDDEN; - {ok, #file_info{type = directory}} -> serve_index(FileName, - DirectoryIndices, - CustomHeaders, - DefaultContentType, - ContentTypes); - {ok, FileInfo} -> serve_file(FileInfo, FileName, - CustomHeaders, - DefaultContentType, - ContentTypes) + +serve(LocalPath, Auth, DocRoot, DirectoryIndices, CustomHeaders, DefaultContentType, + ContentTypes, UserAccess) -> + CanProceed = case {UserAccess, Auth} of + {none, _} -> true; + {_, {User, Pass}} -> + case dict:find(User, UserAccess) of + {ok, Pass} -> true; + _ -> false + end; + _ -> + false + end, + case CanProceed of + true -> + FileName = filename:join(filename:split(DocRoot) ++ LocalPath), + case file:read_file_info(FileName) of + {error, enoent} -> ?HTTP_ERR_FILE_NOT_FOUND; + {error, enotdir} -> ?HTTP_ERR_FILE_NOT_FOUND; + {error, eacces} -> ?HTTP_ERR_FORBIDDEN; + {ok, #file_info{type = directory}} -> serve_index(FileName, + DirectoryIndices, + CustomHeaders, + DefaultContentType, + ContentTypes); + {ok, FileInfo} -> serve_file(FileInfo, FileName, + CustomHeaders, + DefaultContentType, + ContentTypes) + end; + _ -> + ?HTTP_ERR_FORBIDDEN end. %% Troll through the directory indices attempting to find one which @@ -466,6 +494,14 @@ mod_opt_type(default_content_type) -> mod_opt_type(directory_indices) -> fun (L) when is_list(L) -> L end; mod_opt_type(docroot) -> fun (A) -> A end; +mod_opt_type(must_authenticate_with) -> + fun (L) when is_list(L) -> + lists:map(fun(UP) when is_binary(UP) -> + [K, V] = binary:split(UP, <<":">>), + {K, V} + end, L) + end; mod_opt_type(_) -> [accesslog, content_types, custom_headers, - default_content_type, directory_indices, docroot]. + default_content_type, directory_indices, docroot, + must_authenticate_with].