Skip to content

Commit

Permalink
Merge pull request #3261 from esl/amp-with-dynamic-domains
Browse files Browse the repository at this point in the history
AMP with dynamic domains
  • Loading branch information
vkatsuba authored Sep 13, 2021
2 parents 537eabc + 3fb18c1 commit 7942d44
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 148 deletions.
2 changes: 2 additions & 0 deletions big_tests/dynamic_domains.spec
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

{suites, "tests", adhoc_SUITE}.

{suites, "tests", amp_big_SUITE}.

{suites, "tests", bosh_SUITE}.

{suites, "tests", carboncopy_SUITE}.
Expand Down
35 changes: 17 additions & 18 deletions big_tests/tests/amp_big_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
require_rpc_nodes/1,
rpc/4]).
-import(muc_light_helper, [lbin/1]).
-import(domain_helper, [host_type/0]).

suite() ->
require_rpc_nodes([mim]) ++ escalus:suite().
Expand All @@ -23,9 +24,9 @@ all() ->
[{group, G} || G <- main_group_names(), is_enabled(G)].

groups() ->
ct_helper:repeat_all_until_all_ok(group_spec(main_group_names())).
group_spec(main_group_names()).

is_enabled(mam) -> mongoose_helper:is_rdbms_enabled(domain());
is_enabled(mam) -> mongoose_helper:is_rdbms_enabled(host_type());
is_enabled(_) -> true.

%% Group definitions
Expand Down Expand Up @@ -100,7 +101,7 @@ deliver_test_cases(notify) ->
notify_deliver_to_offline_user_recipient_privacy_test,
notify_deliver_to_online_user_broken_connection_test,
notify_deliver_to_stranger_test,
notify_deliver_to_malformed_jid_test];
notify_deliver_to_unknown_domain_test];
deliver_test_cases(error) ->
[error_deliver_to_online_user_test,
error_deliver_to_offline_user_test,
Expand All @@ -113,7 +114,6 @@ deliver_test_cases(drop) ->
%% Setup and teardown

init_per_suite(Config) ->
rpc(mim(), ejabberd_config, add_local_option, [{{s2s_host, <<"not a jid">>}, domain()}, deny]),
ConfigWithHooks = [{ct_hooks, [{multiple_config_cth, fun tests_with_config/1}]} | Config],
{Mod, Code} = rpc(mim(), dynamic_compile, from_string, [amp_test_helper_code()]),
rpc(mim(), code, load_binary, [Mod, "amp_test_helper.erl", Code]),
Expand All @@ -132,19 +132,18 @@ amp_test_helper_code() ->
" end.\n".

end_per_suite(C) ->
rpc(mim(), ejabberd_config, del_local_option, [{{s2s_host, <<"not a jid">>}, domain()}]),
teardown_meck(suite),
escalus_fresh:clean(),
escalus:end_per_suite(C).

init_per_group(GroupName, Config) ->
Config1 = case lists:member(GroupName, main_group_names()) of
true ->
ConfigWithModules = dynamic_modules:save_modules(domain(), Config),
dynamic_modules:ensure_modules(domain(), required_modules(GroupName)),
ConfigWithModules;
false ->
Config
true ->
ConfigWithModules = dynamic_modules:save_modules(host_type(), Config),
dynamic_modules:ensure_modules(host_type(), required_modules(GroupName)),
ConfigWithModules;
false ->
Config
end,
setup_meck(GroupName),
save_offline_status(GroupName, Config1).
Expand All @@ -168,7 +167,7 @@ save_offline_status(_GN, Config) -> Config.
end_per_group(GroupName, Config) ->
teardown_meck(GroupName),
case lists:member(GroupName, main_group_names()) of
true -> dynamic_modules:restore_modules(domain(), Config);
true -> dynamic_modules:restore_modules(host_type(), Config);
false -> ok
end.

Expand Down Expand Up @@ -455,15 +454,15 @@ notify_deliver_to_stranger_test(Config) ->
client_receives_nothing(Alice)
end).

notify_deliver_to_malformed_jid_test(Config) ->
notify_deliver_to_unknown_domain_test(Config) ->
escalus:fresh_story(
Config, [{alice, 1}],
fun(Alice) ->
%% given
StrangerJid = <<"not a jid">>,
StrangerJid = <<"stranger@unknown.domain">>,
Rule = {deliver, none, notify},
Rules = rules(Config, [Rule]),
Msg = amp_message_to(StrangerJid, Rules, <<"Msg to malformed jid">>),
Msg = amp_message_to(StrangerJid, Rules, <<"Msg to unknown domain">>),
%% when
client_sends_message(Alice, Msg),

Expand All @@ -472,8 +471,8 @@ notify_deliver_to_malformed_jid_test(Config) ->
true -> client_receives_notification(Alice, StrangerJid, Rule);
false -> ok
end,
% s2s does not allow routing to 'not a jid', so error 503 is expected
client_receives_generic_error(Alice, <<"503">>, <<"cancel">>),
% error 404: 'remote server not found' is expected
client_receives_generic_error(Alice, <<"404">>, <<"cancel">>),
client_receives_nothing(Alice)
end).

Expand Down Expand Up @@ -977,7 +976,7 @@ amp_error_container(<<"unsupported-conditions">>) -> <<"unsupported-conditions">
amp_error_container(<<"undefined-condition">>) -> <<"failed-rules">>.

is_module_loaded(Mod) ->
rpc(mim(), gen_mod, is_loaded, [domain(), Mod]).
rpc(mim(), gen_mod, is_loaded, [host_type(), Mod]).

required_modules(basic) ->
mam_modules(off) ++ offline_modules(off);
Expand Down
54 changes: 0 additions & 54 deletions rel/mim1.vars-toml.config
Original file line number Diff line number Diff line change
Expand Up @@ -29,60 +29,6 @@
anonymous.allow_multiple_connections = true
anonymous.protocol = \"both\"

[[host_config]]
host_type = \"test type\"

[host_config.modules.mod_adhoc]

[host_config.modules.mod_bosh]

[host_config.modules.mod_cache_users]

[host_config.modules.mod_carboncopy]

[host_config.modules.mod_commands]

[host_config.modules.mod_muc_commands]

[host_config.modules.mod_muc_light_commands]

[host_config.modules.mod_stream_management]

[host_config.modules.mod_disco]

[host_config.modules.mod_register]

[host_config.modules.mod_sic]

{{#mod_last}}
[host_config.modules.mod_last]
{{{mod_last}}}
{{/mod_last}}
{{#mod_offline}}
[host_config.modules.mod_offline]
{{{mod_offline}}}
{{/mod_offline}}
{{#mod_roster}}
[host_config.modules.mod_roster]
{{{mod_roster}}}
{{/mod_roster}}
{{#mod_privacy}}
[host_config.modules.mod_privacy]
{{{mod_privacy}}}
{{/mod_privacy}}
{{#mod_private}}
[host_config.modules.mod_private]
{{{mod_private}}}
{{/mod_private}}
{{#mod_blocking}}
[host_config.modules.mod_blocking]
{{{mod_blocking}}}
{{/mod_blocking}}
{{#mod_vcard}}
[host_config.modules.mod_vcard]
{{{mod_vcard}}}
{{/mod_vcard}}

[[host_config]]
host_type = \"dummy auth\"

Expand Down
88 changes: 42 additions & 46 deletions src/mod_amp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
-behavior(gen_mod).
-behaviour(mongoose_module_metrics).
-xep([{xep, 79}, {version, "1.2"}, {comment, "partially implemented."}]).
-export([start/2, stop/1]).
-export([start/2, stop/1, supported_features/0]).
-export([run_initial_check/2,
check_packet/2,
disco_local_features/1,
Expand All @@ -27,19 +27,24 @@
-define(AMP_RESOLVER, amp_resolver).
-define(AMP_STRATEGY, amp_strategy).

start(Host, _Opts) ->
ejabberd_hooks:add(hooks(Host)).
-spec start(mongooseim:host_type(), gen_mod:module_opts()) -> ok.
start(HostType, _Opts) ->
ejabberd_hooks:add(hooks(HostType)).

stop(Host) ->
ejabberd_hooks:delete(hooks(Host)).
-spec stop(mongooseim:host_type()) -> ok.
stop(HostType) ->
ejabberd_hooks:delete(hooks(HostType)).

hooks(Host) ->
[{c2s_stream_features, Host, ?MODULE, c2s_stream_features, 50},
{disco_local_features, Host, ?MODULE, disco_local_features, 99},
{c2s_preprocessing_hook, Host, ?MODULE, run_initial_check, 10},
{amp_verify_support, Host, ?AMP_RESOLVER, verify_support, 10},
{amp_check_condition, Host, ?AMP_RESOLVER, check_condition, 10},
{amp_determine_strategy, Host, ?AMP_STRATEGY, determine_strategy, 10}].
-spec supported_features() -> [atom()].
supported_features() -> [dynamic_domains].

hooks(HostType) ->
[{c2s_stream_features, HostType, ?MODULE, c2s_stream_features, 50},
{disco_local_features, HostType, ?MODULE, disco_local_features, 99},
{c2s_preprocessing_hook, HostType, ?MODULE, run_initial_check, 10},
{amp_verify_support, HostType, ?AMP_RESOLVER, verify_support, 10},
{amp_check_condition, HostType, ?AMP_RESOLVER, check_condition, 10},
{amp_determine_strategy, HostType, ?AMP_STRATEGY, determine_strategy, 10}].

%% API

Expand Down Expand Up @@ -95,9 +100,10 @@ run_initial_check(Acc) ->
to_jid => To}, Acc1)
end.

-spec validate_and_process_rules(exml:element(), jid:jid(), amp_rules(), mongoose_acc:t()) -> amp_rules() | drop.
-spec validate_and_process_rules(exml:element(), jid:jid(), amp_rules(), mongoose_acc:t()) ->
amp_rules() | drop.
validate_and_process_rules(Packet, From, Rules, Acc) ->
VerifiedRules = verify_support(host(From), Rules),
VerifiedRules = verify_support(mongoose_acc:host_type(Acc), Rules),
{Good, Bad} = lists:partition(fun is_supported_rule/1, VerifiedRules),
ValidRules = [ Rule || {supported, Rule} <- Good ],
case Bad of
Expand Down Expand Up @@ -131,31 +137,36 @@ amp_feature_suffixes() ->
<<"?condition=deliver">>,
<<"?condition=match-resource">>].

-spec process_rules(exml:element(), jid:jid(), amp_event(), amp_rules(), mongoose_acc:t()) -> amp_rules() | drop.
-spec process_rules(exml:element(), jid:jid(), amp_event(), amp_rules(), mongoose_acc:t()) ->
amp_rules() | drop.
process_rules(Packet, From, Event, Rules, Acc) ->
Strategy = determine_strategy(Packet, From, Event),
HostType = mongoose_acc:host_type(Acc),
To = mongoose_acc:to_jid(Acc),
Strategy = determine_strategy(HostType, Packet, From, To, Event),
RulesWithResults = apply_rules(fun(Rule) ->
resolve_condition(From, Strategy, Event, Rule)
resolve_condition(HostType, Strategy, Event, Rule)
end, Rules),
PacketResult = take_action(Packet, From, RulesWithResults, Acc),
return_result(PacketResult, Event, RulesWithResults).

%% @doc hooks helpers
-spec verify_support(binary(), amp_rules()) -> [amp_rule_support()].
verify_support(Host, Rules) ->
mongoose_hooks:amp_verify_support(Host, Rules).
-spec verify_support(mongooseim:host_type(), amp_rules()) -> [amp_rule_support()].
verify_support(HostType, Rules) ->
mongoose_hooks:amp_verify_support(HostType, Rules).

-spec determine_strategy(exml:element(), jid:jid(), amp_event()) -> amp_strategy().
determine_strategy(Packet, From, Event) ->
To = message_target(Packet),
mongoose_hooks:amp_determine_strategy(host(From), From, To, Packet, Event).
-spec determine_strategy(mongooseim:host_type(), exml:element(), jid:jid(), jid:jid(),
amp_event()) ->
amp_strategy().
determine_strategy(HostType, Packet, From, To, Event) ->
mongoose_hooks:amp_determine_strategy(HostType, From, To, Packet, Event).

apply_rules(F, Rules) ->
[Rule#amp_rule{result = F(Rule)} || Rule <- Rules].

-spec resolve_condition(jid:jid(), amp_strategy(), amp_event(), amp_rule()) -> amp_match_result().
resolve_condition(From, Strategy, Event, Rule) ->
Result = mongoose_hooks:amp_check_condition(host(From), Strategy, Rule),
-spec resolve_condition(mongooseim:host_type(), amp_strategy(), amp_event(), amp_rule()) ->
amp_match_result().
resolve_condition(HostType, Strategy, Event, Rule) ->
Result = mongoose_hooks:amp_check_condition(HostType, Strategy, Rule),
match_undecided_for_final_event(Rule, Event, Result).

match_undecided_for_final_event(#amp_rule{condition = deliver}, Event, undecided)
Expand All @@ -176,11 +187,10 @@ return_result(pass, _Event, Rules) ->
Result =:= undecided
end, Rules).

-spec take_action_for_matched_rule(exml:element(), jid:jid(), amp_rule(), mongoose_acc:t()) -> pass | drop.
take_action_for_matched_rule(Packet, From, #amp_rule{action = notify} = Rule, _) ->
Host = host(From),
-spec take_action_for_matched_rule(exml:element(), jid:jid(), amp_rule(), mongoose_acc:t()) ->
pass | drop.
take_action_for_matched_rule(Packet, From, #amp_rule{action = notify} = Rule, _Acc) ->
reply_to_sender(Rule, server_jid(From), From, Packet),
mongoose_hooks:amp_notify_action_triggered(Host),
pass;
take_action_for_matched_rule(Packet, From, #amp_rule{action = error} = Rule, Acc) ->
send_error_and_drop(Packet, From, 'undefined-condition', Rule, Acc);
Expand All @@ -203,37 +213,23 @@ send_errors_and_drop(Packet, From, [], Acc) ->
exml_packet => Packet, from => From}),
update_metric_and_drop(Packet, From, Acc);
send_errors_and_drop(Packet, From, ErrorRules, Acc) ->
Host = host(From),
{Errors, Rules} = lists:unzip(ErrorRules),
ErrorResponse = amp:make_error_response(Errors, Rules, From, Packet),
ejabberd_router:route(server_jid(From), From, ErrorResponse),
mongoose_hooks:amp_error_action_triggered(Host),
update_metric_and_drop(Packet, From, Acc).

-spec update_metric_and_drop(exml:element(), jid:jid(), mongoose_acc:t()) -> drop.
update_metric_and_drop(Packet, From, Acc) ->
mongoose_hooks:xmpp_stanza_dropped(Acc, From,
message_target(Packet),
Packet),
mongoose_hooks:xmpp_stanza_dropped(Acc, From, mongoose_acc:to_jid(Acc), Packet),
drop.

-spec is_supported_rule(amp_rule_support()) -> boolean().
is_supported_rule({supported, _}) -> true;
is_supported_rule(_) -> false.

-spec host(jid:jid()) -> binary().
host(#jid{lserver=Host}) -> Host.

server_jid(#jid{lserver = Host}) ->
jid:from_binary(Host).

-spec message_target(exml:element()) -> jid:jid() | undefined.
message_target(El) ->
case exml_query:attr(El, <<"to">>) of
undefined -> undefined;
J -> jid:from_binary(J)
end.

find(_Pred, []) -> not_found;
find(Pred, [H|T]) ->
case Pred(H) of
Expand Down
Loading

0 comments on commit 7942d44

Please sign in to comment.