1
0
Fork 0
mirror of https://github.com/processone/ejabberd synced 2025-10-03 17:59:31 +02:00

Support Matrix room aliases

This commit is contained in:
Alexey Shchepin 2025-02-13 16:21:05 +03:00
parent e7035f3235
commit 80423d7e69

View file

@ -77,7 +77,8 @@
client_state}). client_state}).
-record(multi_user, -record(multi_user,
{join_ts :: integer()}). {join_ts :: integer(),
room_jid :: jid()}).
-record(multi, -record(multi,
{users :: #{{binary(), binary()} => #{binary() => #multi_user{}}}}). {users :: #{{binary(), binary()} => #{binary() => #multi_user{}}}}).
@ -105,6 +106,9 @@
-define(MAX_DEPTH, 16#7FFFFFFFFFFFFFFF). -define(MAX_DEPTH, 16#7FFFFFFFFFFFFFFF).
-define(MAX_TXN_RETRIES, 5). -define(MAX_TXN_RETRIES, 5).
-define(MATRIX_ROOM_ALIAS_CACHE, matrix_room_alias_cache).
-define(MATRIX_ROOM_ALIAS_CACHE_ERROR_TIMEOUT, 60000).
%%%=================================================================== %%%===================================================================
%%% API %%% API
%%%=================================================================== %%%===================================================================
@ -140,6 +144,7 @@ create_db() ->
[{ram_copies, [node()]}, [{ram_copies, [node()]},
{type, set}, {type, set},
{attributes, record_info(fields, matrix_direct)}]), {attributes, record_info(fields, matrix_direct)}]),
ets_cache:new(?MATRIX_ROOM_ALIAS_CACHE),
ok. ok.
get_room_pid(Host, RoomID) -> get_room_pid(Host, RoomID) ->
@ -170,11 +175,13 @@ join_direct(Host, MatrixServer, RoomID, Sender, UserID) ->
Error Error
end. end.
route(#presence{from = From, to = #jid{luser = <<$!, _/binary>>} = To, route(#presence{from = From, to = #jid{luser = <<C, _/binary>>} = To,
type = Type} = Packet) -> type = Type} = Packet)
case room_id_from_xmpp(To#jid.luser) of when C == $!;
{ok, RoomID} -> C == $# ->
Host = ejabberd_config:get_myname(), Host = ejabberd_config:get_myname(),
case room_id_from_xmpp(Host, To#jid.luser) of
{ok, RoomID} ->
case From#jid.lserver of case From#jid.lserver of
Host -> Host ->
case Type of case Type of
@ -200,14 +207,20 @@ route(#presence{from = From, to = #jid{luser = <<$!, _/binary>>} = To,
ok ok
end; end;
error -> error ->
Lang = xmpp:get_lang(Packet),
Txt = <<"bad or non-existing room id">>,
Err = xmpp:err_not_acceptable(Txt, Lang),
ejabberd_router:route_error(Packet, Err),
ok ok
end; end;
route(#message{from = From, to = #jid{luser = <<$!, _/binary>>} = To, route(#message{from = From, to = #jid{luser = <<C, _/binary>>} = To,
type = groupchat, type = groupchat,
body = Body}) -> body = Body})
case room_id_from_xmpp(To#jid.luser) of when C == $!;
{ok, RoomID} -> C == $# ->
Host = ejabberd_config:get_myname(), Host = ejabberd_config:get_myname(),
case room_id_from_xmpp(Host, To#jid.luser) of
{ok, RoomID} ->
case From#jid.lserver of case From#jid.lserver of
Host -> Host ->
case user_id_from_jid(From, Host) of case user_id_from_jid(From, Host) of
@ -685,6 +698,7 @@ handle_event(cast, {join, UserJID, Packet}, _State, Data) ->
#{{LUser, LServer} := Rs} -> Rs; #{{LUser, LServer} := Rs} -> Rs;
_ -> #{} _ -> #{}
end, end,
RoomJID = jid:remove_resource(xmpp:get_to(Packet)),
Data2 = Data2 =
Data#data{ Data#data{
kind = kind =
@ -692,7 +706,8 @@ handle_event(cast, {join, UserJID, Packet}, _State, Data) ->
users = users =
Users#{{LUser, LServer} => Users#{{LUser, LServer} =>
Resources#{LResource => Resources#{LResource =>
#multi_user{join_ts = JoinTS}}}}}, #multi_user{join_ts = JoinTS,
room_jid = RoomJID}}}}},
{keep_state, Data2, [{next_event, cast, {add_event, JSON}}]}; {keep_state, Data2, [{next_event, cast, {add_event, JSON}}]};
error -> error ->
?INFO_MSG("bad join user id: ~p", [UserJID]), ?INFO_MSG("bad join user id: ~p", [UserJID]),
@ -758,6 +773,7 @@ handle_event(cast, {join, UserJID, Packet}, _State, Data) ->
{timeout, 60000}], {timeout, 60000}],
[{sync, true}, [{sync, true},
{body_format, binary}]), {body_format, binary}]),
RoomJID = jid:remove_resource(xmpp:get_to(Packet)),
?DEBUG("send_join ~p~n", [SendJoinRes]), ?DEBUG("send_join ~p~n", [SendJoinRes]),
process_send_join_res( process_send_join_res(
MatrixServer, SendJoinRes, RoomVersion, MatrixServer, SendJoinRes, RoomVersion,
@ -765,7 +781,8 @@ handle_event(cast, {join, UserJID, Packet}, _State, Data) ->
kind = kind =
#multi{users = #multi{users =
#{{LUser, LServer} => #{{LUser, LServer} =>
#{LResource => #multi_user{join_ts = JoinTS}}}}, #{LResource => #multi_user{join_ts = JoinTS,
room_jid = RoomJID}}}},
room_version = RoomVersion}) room_version = RoomVersion})
end; end;
_JSON -> _JSON ->
@ -2642,12 +2659,13 @@ notify_event_xmpp(
case Sender of case Sender of
<<$@, SenderUser/binary>> -> <<$@, SenderUser/binary>> ->
?DEBUG("notify xmpp ~p", [Users]), ?DEBUG("notify xmpp ~p", [Users]),
From = jid:replace_resource(Data#data.room_jid, SenderUser),
maps:fold( maps:fold(
fun({LUser, LServer}, Resources, ok) -> fun({LUser, LServer}, Resources, ok) ->
maps:fold( maps:fold(
fun(LResource, #multi_user{join_ts = JoinTS}, ok) fun(LResource, #multi_user{join_ts = JoinTS,
room_jid = RoomJID}, ok)
when JoinTS =< OriginTS -> when JoinTS =< OriginTS ->
From = jid:replace_resource(RoomJID, SenderUser),
UserJID = jid:make(LUser, LServer, LResource), UserJID = jid:make(LUser, LServer, LResource),
Msg = #message{from = From, Msg = #message{from = From,
to = UserJID, to = UserJID,
@ -2673,16 +2691,17 @@ notify_event_xmpp(
case user_id_to_jid(Sender, Data) of case user_id_to_jid(Sender, Data) of
#jid{} = SenderJID -> #jid{} = SenderJID ->
<<$@, SenderUser/binary>> = Sender, <<$@, SenderUser/binary>> = Sender,
From = jid:replace_resource(Data#data.room_jid, SenderUser),
maps:fold( maps:fold(
fun({LUser, LServer}, Resources, ok) -> fun({LUser, LServer}, Resources, ok) ->
maps:fold( maps:fold(
fun(LResource, #multi_user{join_ts = JoinTS}, ok) fun(LResource, #multi_user{join_ts = JoinTS,
room_jid = RoomJID}, ok)
when JoinTS =< OriginTS -> when JoinTS =< OriginTS ->
From = jid:replace_resource(RoomJID, SenderUser),
case jid:tolower(SenderJID) of case jid:tolower(SenderJID) of
{LUser, LServer, _} -> {LUser, LServer, _} ->
send_initial_presences( send_initial_presences(
SenderJID, Event, Data); SenderJID, RoomJID, Event, Data);
_ -> _ ->
ok ok
end, end,
@ -2709,12 +2728,13 @@ notify_event_xmpp(
Membership == <<"ban">> -> Membership == <<"ban">> ->
case StateKey of case StateKey of
<<$@, RUser/binary>> -> <<$@, RUser/binary>> ->
From = jid:replace_resource(Data#data.room_jid, RUser),
maps:fold( maps:fold(
fun({LUser, LServer}, Resources, ok) -> fun({LUser, LServer}, Resources, ok) ->
maps:fold( maps:fold(
fun(LResource, #multi_user{join_ts = JoinTS}, ok) fun(LResource, #multi_user{join_ts = JoinTS,
room_jid = RoomJID}, ok)
when JoinTS =< OriginTS -> when JoinTS =< OriginTS ->
From = jid:replace_resource(RoomJID, RUser),
UserJID = jid:make(LUser, LServer, LResource), UserJID = jid:make(LUser, LServer, LResource),
Pres = #presence{from = From, Pres = #presence{from = From,
to = UserJID, to = UserJID,
@ -2755,7 +2775,7 @@ notify_event_xmpp(
notify_event_xmpp(_Event, Data) -> notify_event_xmpp(_Event, Data) ->
Data. Data.
send_initial_presences(JID, Event, Data) -> send_initial_presences(JID, RoomJID, Event, Data) ->
?DEBUG("send_initial_presences ~p", [{JID, Event}]), ?DEBUG("send_initial_presences ~p", [{JID, Event}]),
maps:fold( maps:fold(
fun({?ROOM_MEMBER, _}, EID, ok) -> fun({?ROOM_MEMBER, _}, EID, ok) ->
@ -2764,7 +2784,7 @@ send_initial_presences(JID, Event, Data) ->
sender = <<$@, SenderUser/binary>>, sender = <<$@, SenderUser/binary>>,
json = #{<<"content">> := json = #{<<"content">> :=
#{<<"membership">> := <<"join">>}}}} -> #{<<"membership">> := <<"join">>}}}} ->
From = jid:replace_resource(Data#data.room_jid, SenderUser), From = jid:replace_resource(RoomJID, SenderUser),
Pres = #presence{from = From, Pres = #presence{from = From,
to = JID, to = JID,
type = available type = available
@ -3148,7 +3168,7 @@ room_id_to_xmpp(RoomID) ->
error error
end. end.
room_id_from_xmpp(RID) -> room_id_from_xmpp(Host, RID) ->
case RID of case RID of
<<$!, Parts/binary>> -> <<$!, Parts/binary>> ->
case binary:split(Parts, <<"%">>) of case binary:split(Parts, <<"%">>) of
@ -3159,10 +3179,54 @@ room_id_from_xmpp(RID) ->
{ok, <<$!, RoomID/binary, $:, S/binary>>}; {ok, <<$!, RoomID/binary, $:, S/binary>>};
_ -> error _ -> error
end; end;
<<$#, Parts/binary>> ->
case binary:split(Parts, <<"%">>) of
[R, S] ->
Alias = <<$#, R/binary, $:, S/binary>>,
case resolve_alias(Host, S, Alias) of
{ok, <<$!, _/binary>> = RoomID} ->
{ok, RoomID};
error ->
error
end;
_ -> error
end;
_ -> _ ->
error error
end. end.
resolve_alias(Host, Origin, Alias) ->
ets_cache:lookup(
?MATRIX_ROOM_ALIAS_CACHE, Alias,
fun() ->
Res =
mod_matrix_gw:send_request(
Host, get, Origin,
[<<"_matrix">>, <<"federation">>,
<<"v1">>, <<"query">>, <<"directory">>],
[{<<"room_alias">>, Alias}],
none,
[{timeout, 5000}],
[{sync, true},
{body_format, binary}]),
case Res of
{ok, {{_, 200, _}, _Headers, Body}} ->
try
case misc:json_decode(Body) of
#{<<"room_id">> := RoomID} ->
{ok, RoomID}
end
catch
Class:Reason:ST ->
?DEBUG("failed resolve_alias: ~p", [{Class, Reason, ST}]),
{cache_with_timeout, error, ?MATRIX_ROOM_ALIAS_CACHE_ERROR_TIMEOUT}
end;
{ok, {{_, _Status, _Reason}, _Headers, _Body}} ->
{cache_with_timeout, error, ?MATRIX_ROOM_ALIAS_CACHE_ERROR_TIMEOUT};
{error, _Reason} ->
{cache_with_timeout, error, ?MATRIX_ROOM_ALIAS_CACHE_ERROR_TIMEOUT}
end
end).
escape(S) -> escape(S) ->