Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
chrzaszcz committed Oct 21, 2022
1 parent a9ee17f commit 8cca662
Show file tree
Hide file tree
Showing 14 changed files with 267 additions and 272 deletions.
28 changes: 15 additions & 13 deletions big_tests/tests/graphql_stanza_SUITE.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
-module(graphql_stanza_SUITE).

-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-include_lib("exml/include/exml.hrl").

Expand Down Expand Up @@ -111,9 +112,11 @@ init_mam(Config) when is_list(Config) ->
disabled ->
Config;
Backend ->
Mods = [{mod_mam, mam_helper:config_opts(#{backend => Backend, pm => #{}})}],
MAMOpts = #{max_result_limit := MaxResultLimit} =
mam_helper:config_opts(#{backend => Backend, pm => #{}}),
Mods = [{mod_mam, MAMOpts}],
dynamic_modules:ensure_modules(domain_helper:host_type(), Mods),
[{has_mam, true}|Config]
[{has_mam, true}, {max_result_limit, MaxResultLimit}|Config]
end;
init_mam(Other) ->
Other.
Expand Down Expand Up @@ -185,8 +188,7 @@ admin_send_message_headline_story(Config, Alice, Bob) ->
To = escalus_client:short_jid(Bob),
Res = send_message_headline(From, To, <<"Welcome">>, <<"Hi!">>, Config),
#{<<"id">> := MamID} = get_ok_value([data, stanza, sendMessageHeadLine], Res),
% Headlines are not stored in MAM
<<>> = MamID,
assert_not_empty(MamID, Config),
escalus:assert(is_message, escalus:wait_for_stanza(Bob)).

user_send_message_headline(Config) ->
Expand All @@ -198,8 +200,7 @@ user_send_message_headline_story(Config, Alice, Bob) ->
To = escalus_client:short_jid(Bob),
Res = user_send_message_headline(Alice, From, To, <<"Welcome">>, <<"Hi!">>, Config),
#{<<"id">> := MamID} = get_ok_value([data, stanza, sendMessageHeadLine], Res),
% Headlines are not stored in MAM
<<>> = MamID,
assert_not_empty(MamID, Config),
escalus:assert(is_message, escalus:wait_for_stanza(Bob)).

user_send_message_headline_with_spoofed_from(Config) ->
Expand Down Expand Up @@ -313,7 +314,7 @@ admin_send_stanza_from_unknown_user_story(Config, Bob) ->
Stanza = escalus_stanza:from(escalus_stanza:chat_to_short_jid(Bob, Body), From),
Res = send_stanza(exml:to_binary(Stanza), Config),
?assertEqual(<<"unknown_user">>, get_err_code(Res)),
?assertEqual(<<"Given user does not exist">>, get_err_msg(Res)).
?assertEqual(<<"User does not exist">>, get_err_msg(Res)).

admin_send_stanza_from_unknown_domain(Config) ->
escalus:fresh_story_with_config(Config, [{bob, 1}],
Expand All @@ -324,8 +325,8 @@ admin_send_stanza_from_unknown_domain_story(Config, Bob) ->
From = <<"YeeeAH@oopsie">>,
Stanza = escalus_stanza:from(escalus_stanza:chat_to_short_jid(Bob, Body), From),
Res = send_stanza(exml:to_binary(Stanza), Config),
?assertEqual(<<"unknown_domain">>, get_err_code(Res)),
?assertEqual(<<"Given domain does not exist">>, get_err_msg(Res)).
?assertEqual(<<"unknown_user">>, get_err_code(Res)),
?assertEqual(<<"User's domain does not exist">>, get_err_msg(Res)).

admin_get_last_messages(Config) ->
escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
Expand Down Expand Up @@ -366,7 +367,7 @@ admin_get_last_messages_for_unknown_user(Config) ->
Jid = <<"maybemaybebutnot@", Domain/binary>>,
Res = get_last_messages(Jid, null, null, Config),
?assertEqual(<<"unknown_user">>, get_err_code(Res)),
?assertEqual(<<"Given user does not exist">>, get_err_msg(Res)).
?assertEqual(<<"User does not exist">>, get_err_msg(Res)).

admin_get_last_messages_with(Config) ->
escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}, {kate, 1}],
Expand Down Expand Up @@ -409,7 +410,8 @@ admin_get_last_messages_limit_enforced_story(Config, Alice, Bob) ->
Caller = escalus_client:full_jid(Alice),
Res = get_last_messages(Caller, null, 1000, null, Config),
%% The actual limit is returned
#{<<"stanzas">> := [M1], <<"limit">> := 500} =
MaxResultLimit = ?config(max_result_limit, Config),
#{<<"stanzas">> := [M1], <<"limit">> := MaxResultLimit} =
get_ok_value([data, stanza, getLastMessages], Res),
check_stanza_map(M1, Alice).

Expand Down Expand Up @@ -498,5 +500,5 @@ check_stanza_map(#{<<"sender">> := SenderJID,

spoofed_error(Call, Response) ->
null = graphql_helper:get_err_value([data, stanza, Call], Response),
?assertEqual(<<"Sending from this JID is not allowed">>, get_err_msg(Response)),
?assertEqual(<<"bad_from_jid">>, get_err_code(Response)).
?assertEqual(<<"Sender's JID is different from the user's JID">>, get_err_msg(Response)),
?assertEqual(<<"invalid_sender">>, get_err_code(Response)).
8 changes: 4 additions & 4 deletions big_tests/tests/rest_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,9 @@ message_errors(Config) ->
send_message_bin(AliceJID, <<"@noway">>),
{?BAD_REQUEST, <<"Invalid sender JID">>} =
send_message_bin(<<"@noway">>, BobJID),
{?BAD_REQUEST, <<"Unknown user">>} =
{?BAD_REQUEST, <<"User does not exist">>} =
send_message_bin(<<"baduser@", (domain())/binary>>, BobJID),
{?BAD_REQUEST, <<"Unknown domain">>} =
{?BAD_REQUEST, <<"User's domain does not exist">>} =
send_message_bin(<<"baduser@baddomain">>, BobJID).

stanzas_are_sent_and_received(Config) ->
Expand Down Expand Up @@ -297,9 +297,9 @@ stanza_errors(Config) ->
send_stanza(extended_message([{<<"from">>, AliceJid}, {<<"to">>, <<"@invalid">>}])),
{?BAD_REQUEST, <<"Invalid sender JID">>} =
send_stanza(extended_message([{<<"from">>, <<"@invalid">>}, {<<"to">>, BobJid}])),
{?BAD_REQUEST, <<"Unknown domain">>} =
{?BAD_REQUEST, <<"User's domain does not exist">>} =
send_stanza(extended_message([{<<"from">>, <<"baduser@baddomain">>}, {<<"to">>, BobJid}])),
{?BAD_REQUEST, <<"Unknown user">>} =
{?BAD_REQUEST, <<"User does not exist">>} =
send_stanza(extended_message([{<<"from">>, UnknownJid}, {<<"to">>, BobJid}])),
{?BAD_REQUEST, <<"Malformed stanza">>} =
send_stanza(broken_message([{<<"from">>, AliceJid}, {<<"to">>, BobJid}])),
Expand Down
23 changes: 11 additions & 12 deletions src/graphql/admin/mongoose_graphql_stanza_admin_mutation.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
-ignore_xref([execute/4]).

-include("../mongoose_graphql_types.hrl").
-include("mongoose_logger.hrl").
-include("jlib.hrl").

-import(mongoose_graphql_helper, [null_to_undefined/1, format_result/2]).

execute(_Ctx, _Obj, <<"sendMessage">>, Args) ->
send_message(Args);
Expand All @@ -17,16 +17,15 @@ execute(_Ctx, _Obj, <<"sendStanza">>, Args) ->
send_stanza(Args).

send_message(#{<<"from">> := From, <<"to">> := To, <<"body">> := Body}) ->
Packet = mongoose_stanza_helper:build_message(
jid:to_binary(From), jid:to_binary(To), Body),
mongoose_stanza_helper:route(From, To, Packet, true).
Res = mongoose_stanza_api:send_chat_message(undefined, From, To, Body),
format_result(Res, #{from => jid:to_binary(From)}).

send_message_headline(Args = #{<<"from">> := From, <<"to">> := To}) ->
Packet = mongoose_stanza_helper:build_message_with_headline(
jid:to_binary(From), jid:to_binary(To), Args),
mongoose_stanza_helper:route(From, To, Packet, true).
send_message_headline(#{<<"from">> := From, <<"to">> := To,
<<"body">> := Body, <<"subject">> := Subject}) ->
Res = mongoose_stanza_api:send_headline_message(
undefined, From, To, null_to_undefined(Body), null_to_undefined(Subject)),
format_result(Res, #{from => jid:to_binary(From)}).

send_stanza(#{<<"stanza">> := Packet}) ->
From = jid:from_binary(exml_query:attr(Packet, <<"from">>)),
To = jid:from_binary(exml_query:attr(Packet, <<"to">>)),
mongoose_stanza_helper:route(From, To, Packet, true).
Res = mongoose_stanza_api:send_stanza(undefined, Packet),
format_result(Res, #{}).
11 changes: 4 additions & 7 deletions src/graphql/admin/mongoose_graphql_stanza_admin_query.erl
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
-module(mongoose_graphql_stanza_admin_query).
-behaviour(mongoose_graphql).

-import(mongoose_graphql_helper, [format_result/2]).

-export([execute/4]).

-ignore_xref([execute/4]).

-include("../mongoose_graphql_types.hrl").
-include("mongoose_logger.hrl").

execute(_Ctx, _Obj, <<"getLastMessages">>, Args) ->
get_last_messages(Args).

get_last_messages(#{<<"caller">> := Caller, <<"limit">> := Limit,
<<"with">> := With, <<"before">> := Before})
when is_integer(Limit) ->
case mongoose_graphql_helper:check_user(Caller, true) of
{ok, _HostType} ->
mongoose_stanza_helper:get_last_messages(Caller, Limit, With, Before);
Error ->
Error
end.
Res = mongoose_graphql_stanza_helper:get_last_messages(Caller, Limit, With, Before, true),
format_result(Res, #{user => jid:to_binary(Caller)}).
24 changes: 1 addition & 23 deletions src/graphql/mongoose_graphql_helper.erl
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
-module(mongoose_graphql_helper).

-export([check_user/2]).

-export([null_to_default/2, null_to_undefined/1]).

-export([format_result/2, make_error/2, make_error/3]).

-include("jlib.hrl").
-include("mongoose_graphql_types.hrl").

-spec format_result(InResult, Context) -> OutResult when
Expand All @@ -15,7 +12,7 @@
OutResult :: {ok, binary() | integer()} | {error, resolver_error()}.
format_result(Result, Context) ->
case Result of
{ok, Val} when is_integer(Val) -> {ok, Val};
{ok, Val} when is_integer(Val) orelse is_map(Val) -> {ok, Val};
{ok, Msg} -> {ok, iolist_to_binary(Msg)};
{ErrCode, Msg} -> make_error(ErrCode, Msg, Context)
end.
Expand All @@ -28,25 +25,6 @@ make_error({Reason, Msg}, Context) ->
make_error(Reason, Msg, Context) ->
{error, #resolver_error{reason = Reason, msg = iolist_to_binary(Msg), context = Context}}.

-spec check_user(jid:jid(), boolean()) -> {ok, mongooseim:host_type()} | {error, term()}.
check_user(#jid{lserver = LServer} = Jid, CheckAuth) ->
case mongoose_domain_api:get_domain_host_type(LServer) of
{ok, HostType} ->
check_auth(HostType, Jid, CheckAuth);
_ ->
{error, #{what => unknown_domain, domain => LServer}}
end.

check_auth(HostType, _Jid, false) ->
{ok, HostType};
check_auth(HostType, Jid, true) ->
case ejabberd_auth:does_user_exist(HostType, Jid, stored) of
true ->
{ok, HostType};
false ->
{error, #{what => unknown_user, jid => jid:to_binary(Jid)}}
end.

null_to_default(null, Default) ->
Default;
null_to_default(Value, _Default) ->
Expand Down
20 changes: 19 additions & 1 deletion src/graphql/mongoose_graphql_stanza_helper.erl
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
-module(mongoose_graphql_stanza_helper).

-export([row_to_map/1]).
-import(mongoose_graphql_helper, [null_to_undefined/1, make_error/2]).

-export([get_last_messages/5, row_to_map/1]).

-spec get_last_messages(Caller :: jid:jid(),
Limit :: null | non_neg_integer(),
With :: null | jid:jid(),
Before :: null | mod_mam:unix_timestamp(), boolean()) ->
{ok, map()} | {unknown_user, iodata()}.
get_last_messages(Caller, Limit, With, Before, CheckUser) ->
case mongoose_stanza_api:lookup_recent_messages(
Caller, null_to_undefined(With), null_to_undefined(Before),
null_to_undefined(Limit), CheckUser) of
{ok, {Rows, Limit2}} ->
Maps = lists:map(fun row_to_map/1, Rows),
{ok, #{<<"stanzas">> => Maps, <<"limit">> => Limit2}};
Error ->
Error
end.

-spec row_to_map(mod_mam:message_row()) -> {ok, map()}.
row_to_map(#{id := Id, jid := From, packet := Msg}) ->
Expand Down
52 changes: 12 additions & 40 deletions src/graphql/user/mongoose_graphql_stanza_user_mutation.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
-ignore_xref([execute/4]).

-include("../mongoose_graphql_types.hrl").
-include("mongoose_logger.hrl").
-include("jlib.hrl").

-import(mongoose_graphql_helper, [null_to_undefined/1, format_result/2]).

execute(Ctx, _Obj, <<"sendMessage">>, Args) ->
send_message(Ctx, Args);
Expand All @@ -16,44 +16,16 @@ execute(Ctx, _Obj, <<"sendMessageHeadLine">>, Args) ->
execute(Ctx, _Obj, <<"sendStanza">>, Args) ->
send_stanza(Ctx, Args).

send_message(Ctx, Args) ->
with_from(Ctx, Args, fun send_message2/1).

send_message_headline(Ctx, Args) ->
with_from(Ctx, Args, fun send_message_headline2/1).

send_message2(#{<<"from">> := From, <<"to">> := To, <<"body">> := Body}) ->
Packet = mongoose_stanza_helper:build_message(jid:to_binary(From), jid:to_binary(To), Body),
%% SkipAuth = false, because we already checked if From exists
mongoose_stanza_helper:route(From, To, Packet, false).
send_message(#{user := User}, #{<<"from">> := From, <<"to">> := To, <<"body">> := Body}) ->
Res = mongoose_stanza_api:send_chat_message(User, null_to_undefined(From), To, Body),
format_result(Res, #{}).

send_message_headline2(Args = #{<<"from">> := From, <<"to">> := To}) ->
Packet = mongoose_stanza_helper:build_message_with_headline(
jid:to_binary(From), jid:to_binary(To), Args),
mongoose_stanza_helper:route(From, To, Packet, false).
send_message_headline(#{user := User}, #{<<"from">> := From, <<"to">> := To, <<"body">> := Body,
<<"subject">> := Subject}) ->
Res = mongoose_stanza_api:send_headline_message(
User, null_to_undefined(From), To, null_to_undefined(Body), null_to_undefined(Subject)),
format_result(Res, #{}).

send_stanza(#{user := User}, #{<<"stanza">> := Packet}) ->
From = jid:from_binary(exml_query:attr(Packet, <<"from">>)),
To = jid:from_binary(exml_query:attr(Packet, <<"to">>)),
case jid:are_bare_equal(User, From) of
true ->
mongoose_stanza_helper:route(From, To, Packet, false);
false ->
{error, #{what => bad_from_jid}}
end.

with_from(_Ctx = #{user := User}, Args, Next) ->
case maps:get(<<"from">>, Args, null) of
null ->
Next(Args#{<<"from">> => User});
From ->
case jid:are_bare_equal(User, From) of
true ->
%% We still can allow a custom resource
Next(Args#{<<"from">> => From});
false ->
?LOG_ERROR(#{what => bad_from_jid,
user_jid => User, from_jid => From}),
{error, #{what => bad_from_jid}}
end
end.
Res = mongoose_stanza_api:send_stanza(User, Packet),
format_result(Res, #{}).
6 changes: 4 additions & 2 deletions src/graphql/user/mongoose_graphql_stanza_user_query.erl
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
-module(mongoose_graphql_stanza_user_query).
-behaviour(mongoose_graphql).

-import(mongoose_graphql_helper, [format_result/2]).

-export([execute/4]).

-ignore_xref([execute/4]).

-include("../mongoose_graphql_types.hrl").
-include("mongoose_logger.hrl").

execute(#{user := User}, _Obj, <<"getLastMessages">>, Args) ->
get_last_messages(Args, User).

get_last_messages(#{<<"limit">> := Limit,
<<"with">> := With, <<"before">> := Before}, Caller)
when is_integer(Limit) ->
mongoose_stanza_helper:get_last_messages(Caller, Limit, With, Before).
Res = mongoose_graphql_stanza_helper:get_last_messages(Caller, Limit, With, Before, false),
format_result(Res, #{user => jid:to_binary(Caller)}).
10 changes: 0 additions & 10 deletions src/mam/mod_mam_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

%% UID
-export([get_or_generate_mam_id/1,
get_mam_id_ext/1,
generate_message_id/1,
encode_compact_uuid/2,
decode_compact_uuid/1,
Expand Down Expand Up @@ -177,15 +176,6 @@ get_or_generate_mam_id(Acc) ->
mod_mam_utils:external_binary_to_mess_id(ExtMessId)
end.

-spec get_mam_id_ext(mongoose_acc:t()) -> binary().
get_mam_id_ext(Acc) ->
case mongoose_acc:get(mam, mam_id, undefined, Acc) of
undefined ->
<<>>;
ExtMessId ->
ExtMessId
end.

-spec generate_message_id(integer()) -> integer().
generate_message_id(CandidateStamp) ->
{ok, NodeId} = ejabberd_node_id:node_id(),
Expand Down
Loading

0 comments on commit 8cca662

Please sign in to comment.