Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
chrzaszcz committed Oct 19, 2022
1 parent a9ee17f commit 689ad91
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 157 deletions.
18 changes: 8 additions & 10 deletions big_tests/tests/graphql_stanza_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,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 +197,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 @@ -312,8 +310,8 @@ admin_send_stanza_from_unknown_user_story(Config, Bob) ->
From = <<"YeeeAH@", Server/binary>>,
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(<<"unknown_sender">>, get_err_code(Res)),
?assertEqual(<<"Sender's account 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 +322,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_sender">>, get_err_code(Res)),
?assertEqual(<<"Sender's account 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 @@ -498,5 +496,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, <<"Sender's account does not exist">>} =
send_message_bin(<<"baduser@", (domain())/binary>>, BobJID),
{?BAD_REQUEST, <<"Unknown domain">>} =
{?BAD_REQUEST, <<"Sender's account 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, <<"Sender's account does not exist">>} =
send_stanza(extended_message([{<<"from">>, <<"baduser@baddomain">>}, {<<"to">>, BobJid}])),
{?BAD_REQUEST, <<"Unknown user">>} =
{?BAD_REQUEST, <<"Sender's account 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
22 changes: 10 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, [format_result/2]).

execute(_Ctx, _Obj, <<"sendMessage">>, Args) ->
send_message(Args);
Expand All @@ -17,16 +17,14 @@ 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(null, 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(null, From, To, Body, 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(null, Packet),
format_result(Res, #{}).
2 changes: 1 addition & 1 deletion src/graphql/mongoose_graphql_helper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,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 Down
51 changes: 11 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, [format_result/2]).

execute(Ctx, _Obj, <<"sendMessage">>, Args) ->
send_message(Ctx, Args);
Expand All @@ -16,44 +16,15 @@ 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, 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, From, To, Body, 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, #{}).
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
12 changes: 4 additions & 8 deletions src/mongoose_admin_api/mongoose_admin_api_messages.erl
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,11 @@ handle_post(Req, State) ->
From = get_caller(Args),
To = get_to(Args),
Body = get_body(Args),
Packet = mongoose_stanza_helper:build_message(
jid:to_binary(From), jid:to_binary(To), Body),
case mongoose_stanza_helper:route(From, To, Packet, true) of
{error, #{what := unknown_domain}} ->
throw_error(bad_request, <<"Unknown domain">>);
{error, #{what := unknown_user}} ->
throw_error(bad_request, <<"Unknown user">>);
case mongoose_stanza_api:send_chat_message(null, From, To, Body) of
{ok, _} ->
{true, Req, State}
{true, Req, State};
{_Error, Msg} ->
throw_error(bad_request, Msg)
end.

-spec row_to_map(mod_mam:message_row()) -> map().
Expand Down
37 changes: 6 additions & 31 deletions src/mongoose_admin_api/mongoose_admin_api_stanzas.erl
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,11 @@ from_json(Req, State) ->
handle_post(Req, State) ->
Args = parse_body(Req),
Stanza = get_stanza(Args),
From = get_from_jid(Stanza),
To = get_to_jid(Stanza),
case mongoose_stanza_helper:route(From, To, Stanza, true) of
{error, #{what := unknown_domain}} ->
throw_error(bad_request, <<"Unknown domain">>);
{error, #{what := unknown_user}} ->
throw_error(bad_request, <<"Unknown user">>);
case mongoose_stanza_api:send_stanza(null, Stanza) of
{ok, _} ->
{true, Req, State}
{true, Req, State};
{_Error, Msg} ->
throw_error(bad_request, Msg)
end.

get_stanza(#{stanza := BinStanza}) ->
Expand All @@ -68,26 +64,5 @@ get_stanza(#{stanza := BinStanza}) ->
{error, _} ->
throw_error(bad_request, <<"Malformed stanza">>)
end;
get_stanza(#{}) -> throw_error(bad_request, <<"Missing stanza">>).

get_from_jid(Stanza) ->
case exml_query:attr(Stanza, <<"from">>) of
undefined ->
throw_error(bad_request, <<"Missing sender JID">>);
JidBin ->
case jid:from_binary(JidBin) of
error -> throw_error(bad_request, <<"Invalid sender JID">>);
Jid -> Jid
end
end.

get_to_jid(Stanza) ->
case exml_query:attr(Stanza, <<"to">>) of
undefined ->
throw_error(bad_request, <<"Missing recipient JID">>);
JidBin ->
case jid:from_binary(JidBin) of
error -> throw_error(bad_request, <<"Invalid recipient JID">>);
Jid -> Jid
end
end.
get_stanza(#{}) ->
throw_error(bad_request, <<"Missing stanza">>).
7 changes: 2 additions & 5 deletions src/mongoose_client_api/mongoose_client_api_messages.erl
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,11 @@ handle_get(Req, State = #{jid := OwnerJid}) ->
Resp = [make_json_msg(Msg, MAMId) || #{id := MAMId, packet := Msg} <- Rows],
{jiffy:encode(Resp), Req, State}.

handle_post(Req, State = #{jid := From}) ->
handle_post(Req, State = #{jid := UserJid}) ->
Args = parse_body(Req),
To = get_to(Args),
Body = get_body(Args),
Packet = mongoose_stanza_helper:build_message(jid:to_binary(From), jid:to_binary(To), Body),
{ok, _} = mongoose_stanza_helper:route(From, To, Packet, true),
Id = exml_query:attr(Packet, <<"id">>),
Resp = #{<<"id">> => Id},
{ok, Resp} = mongoose_stanza_api:send_chat_message(UserJid, null, To, Body),
Req2 = cowboy_req:set_resp_body(jiffy:encode(Resp), Req),
{true, Req2, State}.

Expand Down
86 changes: 84 additions & 2 deletions src/mongoose_stanza_api.erl
Original file line number Diff line number Diff line change
@@ -1,15 +1,92 @@
-module(mongoose_stanza_api).
-export([lookup_recent_messages/4]).
-export([send_chat_message/4, send_headline_message/5, send_stanza/2, lookup_recent_messages/4]).

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

-spec send_chat_message(jid:jid() | null, jid:jid() | null, jid:jid(), binary()) ->
{unknown_sender | invalid_sender, iodata()} | {ok, map()}.
send_chat_message(User, From, To, Body) ->
M = #{user => User, from => From, to => To, body => Body},
fold(M, [fun get_sender_jid/1, fun prepare_chat_message/1, fun send/1]).

-spec send_headline_message(jid:jid() | null, jid:jid() | null, jid:jid(),
binary() | null, binary() | null) ->
{unknown_sender | invalid_sender | no_sender |
invalid_recipient | no_recipient, iodata()} | {ok, map()}.
send_headline_message(User, From, To, Body, Subject) ->
M = #{user => User, from => From, to => To, body => Body, subject => Subject},
fold(M, [fun get_sender_jid/1, fun prepare_headline_message/1, fun send/1]).

-spec send_stanza(jid:jid() | null, exml:element()) ->
{unknown_sender | invalid_sender, iodata()} | {ok, map()}.
send_stanza(User, Stanza) ->
M = #{user => User, stanza => Stanza},
fold(M, [fun get_from_jid/1, fun get_to_jid/1, fun get_sender_jid/1,
fun prepare_stanza/1, fun send/1]).

get_sender_jid(M = #{user := null, from := From = #jid{}}) ->
case ejabberd_auth:does_user_exist(From) of
true ->
M;
false ->
{unknown_sender, <<"Sender's account does not exist">>}
end;
get_sender_jid(M = #{user := User = #jid{}, from := null}) ->
M#{from => User};
get_sender_jid(M = #{user := User = #jid{}, from := From = #jid{}}) ->
case jid:are_bare_equal(User, From) of
true ->
M;
false ->
{invalid_sender, <<"Sender's JID is different from the user's JID">>}
end.

send(#{from := #jid{lserver = SenderDomain} = From, to := To, stanza := Stanza}) ->
{ok, HostType} = mongoose_domain_api:get_domain_host_type(SenderDomain),
mongoose_stanza_helper:route(HostType, SenderDomain, From, To, Stanza).

get_from_jid(M = #{stanza := Stanza}) ->
case exml_query:attr(Stanza, <<"from">>) of
undefined ->
{no_sender, <<"Missing sender JID">>};
JidBin ->
case jid:from_binary(JidBin) of
error -> {invalid_sender, <<"Invalid sender JID">>};
Jid -> M#{from => Jid}
end
end.

get_to_jid(M = #{stanza := Stanza}) ->
case exml_query:attr(Stanza, <<"to">>) of
undefined ->
{no_recipient, <<"Missing recipient JID">>};
JidBin ->
case jid:from_binary(JidBin) of
error -> {invalid_recipient, <<"Invalid recipient JID">>};
Jid -> M#{to => Jid}
end
end.

prepare_chat_message(M = #{from := From, to := To, body := Body}) ->
FromBin = jid:to_binary(From),
ToBin = jid:to_binary(To),
M#{stanza => mongoose_stanza_helper:build_message(FromBin, ToBin, Body)}.

prepare_headline_message(M = #{from := From, to := To, body := Body, subject := Subject}) ->
FromBin = jid:to_binary(From),
ToBin = jid:to_binary(To),
M#{stanza => mongoose_stanza_helper:build_message_with_headline(FromBin, ToBin, Body, Subject)}.

prepare_stanza(M = #{stanza := Stanza}) ->
M#{stanza := mongoose_stanza_helper:ensure_id(Stanza)}.

%% TODO fix error handling, do not crash for non-existing users
%% Before is in microseconds
-spec lookup_recent_messages(
ArcJID :: jid:jid(),
With :: jid:jid() | undefined,
Before :: mod_mam:unix_timestamp() | undefined,
Before :: mod_mam:unix_timestamp() | undefined, % microseconds
Limit :: non_neg_integer()) ->
[mod_mam:message_row()].
lookup_recent_messages(_, _, _, Limit) when Limit > 500 ->
Expand Down Expand Up @@ -37,3 +114,8 @@ lookup_recent_messages(ArcJID, WithJID, Before, Limit) ->
R = mod_mam_pm:lookup_messages(HostType, Params),
{ok, {_, _, L}} = R,
L.

fold({_, _} = Result, _) ->
Result;
fold(M, [Step | Rest]) when is_map(M) ->
fold(Step(M), Rest).
Loading

0 comments on commit 689ad91

Please sign in to comment.