Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

IP address as additional authorization parameter. Hook API to track muc rooms and opened sessions. #25

Open
wants to merge 2 commits into from

1 participant

Sergii Rustamov
Sergii Rustamov
  • IP address as last parameter for authorization modules. Modules which are not supported additional IP address parameter work without changes.
  • pre_open_session hook to add custom check for incoming IP address and username before opening actual session
  • mod_muc_hook module to have possibility to implement custom logic when room is opened and add message filtering
rustamserg added some commits
Sergii Rustamov rustamserg Added IP address as optional parameter for authentication modules. Ad…
…ded pre_open_session hook to have custom check before opening session
1afc08e
Sergii Rustamov rustamserg Added mod_muc_hook module to have custom functionality for tracking c…
…hat rooms/players and control over sent message, for example to add profanity filter
1465048
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 30, 2012
  1. Sergii Rustamov

    Added IP address as optional parameter for authentication modules. Ad…

    rustamserg authored
    …ded pre_open_session hook to have custom check before opening session
  2. Sergii Rustamov

    Added mod_muc_hook module to have custom functionality for tracking c…

    rustamserg authored
    …hat rooms/players and control over sent message, for example to add profanity filter
This page is out of date. Refresh to see the latest.
33 src/ejabberd_auth.erl
View
@@ -34,8 +34,8 @@
set_password/3,
check_password/3,
check_password/5,
- check_password_with_authmodule/3,
- check_password_with_authmodule/5,
+ check_password_with_authmodule/4,
+ check_password_with_authmodule/6,
try_register/3,
dirty_get_registered_users/0,
get_vh_registered_users/1,
@@ -129,15 +129,32 @@ check_password_with_authmodule(User, Server, Password, Digest, DigestGen) ->
check_password_loop(auth_modules(Server), [User, Server, Password,
Digest, DigestGen]).
+check_password_with_authmodule(User, Server, Password, IP) ->
+ check_password_loop(auth_modules(Server), [User, Server, Password, IP]).
+
+check_password_with_authmodule(User, Server, Password, Digest, DigestGen, IP) ->
+ check_password_loop(auth_modules(Server), [User, Server, Password,
+ Digest, DigestGen, IP]).
+
check_password_loop([], _Args) ->
false;
check_password_loop([AuthModule | AuthModules], Args) ->
- case apply(AuthModule, check_password, Args) of
- true ->
- {true, AuthModule};
- false ->
- check_password_loop(AuthModules, Args)
- end.
+ case lists:member({check_password,length(Args)}, apply(AuthModule, module_info, [exports])) of
+ true ->
+ case apply(AuthModule, check_password, Args) of
+ true ->
+ {true, AuthModule};
+ false ->
+ check_password_loop(AuthModules, Args)
+ end;
+ false ->
+ case apply(AuthModule, check_password, lists:sublist(Args, length(Args) - 1)) of
+ true ->
+ {true, AuthModule};
+ false ->
+ check_password_loop(AuthModules, Args)
+ end
+ end.
%% @spec (User::string(), Server::string(), Password::string()) ->
28 src/ejabberd_c2s.erl
View
@@ -314,11 +314,11 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
end,
fun(U, P) ->
ejabberd_auth:check_password_with_authmodule(
- U, Server, P)
+ U, Server, P, StateData#state.ip)
end,
fun(U, P, D, DG) ->
ejabberd_auth:check_password_with_authmodule(
- U, Server, P, D, DG)
+ U, Server, P, D, DG, StateData#state.ip)
end),
Mechs = lists:map(
fun(S) ->
@@ -512,7 +512,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
DGen = fun(PW) ->
sha:sha(StateData#state.streamid ++ PW) end,
case ejabberd_auth:check_password_with_authmodule(
- U, StateData#state.server, P, D, DGen) of
+ U, StateData#state.server, P, D, DGen, StateData#state.ip) of
{true, AuthModule} ->
?INFO_MSG(
"(~w) Accepted legacy authentication for ~s by ~p",
@@ -522,6 +522,14 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
Conn = get_conn_type(StateData),
Info = [{ip, StateData#state.ip}, {conn, Conn},
{auth_module, AuthModule}],
+
+ case ejabberd_hooks:run_fold(pre_open_session, true, [U, StateData#state.server, R, Info]) of
+ false ->
+ ?INFO_MSG("(~w) Pre open session check failed ~s", [StateData#state.socket, jlib:jid_to_string(JID)]),
+ Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
+ send_element(StateData, Err),
+ {stop, normal, StateData};
+ true ->
Res1 = jlib:make_result_iq_reply(El),
Res = setelement(4, Res1, []),
send_element(StateData, Res),
@@ -554,7 +562,8 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
pres_t = ?SETS:from_list(Ts1),
privacy_list = PrivList},
fsm_next_state_pack(session_established,
- NewStateData);
+ NewStateData)
+ end;
_ ->
?INFO_MSG(
"(~w) Failed legacy authentication for ~s",
@@ -958,6 +967,14 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
Conn = get_conn_type(StateData),
Info = [{ip, StateData#state.ip}, {conn, Conn},
{auth_module, StateData#state.auth_module}],
+ case ejabberd_hooks:run_fold(pre_open_session, true, [U, StateData#state.server, R, Info]) of
+ false ->
+ ejabberd_hooks:run(forbidden_session_hook, StateData#state.server, [JID]),
+ ?INFO_MSG("(~w) Pre open session check failed ~s", [StateData#state.socket, jlib:jid_to_string(JID)]),
+ Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
+ send_element(StateData, Err),
+ {stop, normal, StateData};
+ true ->
ejabberd_sm:open_session(
SID, U, StateData#state.server, R, Info),
NewStateData =
@@ -968,7 +985,8 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
pres_t = ?SETS:from_list(Ts1),
privacy_list = PrivList},
fsm_next_state_pack(session_established,
- NewStateData);
+ NewStateData)
+ end;
_ ->
ejabberd_hooks:run(forbidden_session_hook,
StateData#state.server, [JID]),
19 src/mod_muc/mod_muc_hook.erl
View
@@ -0,0 +1,19 @@
+-module(mod_muc_hook).
+
+-export([room_state/3,
+ room_user/5,
+ room_message/5,
+ room_message_private/7]).
+
+
+room_state(Host, Room, State) ->
+ ok.
+
+room_user(Host, Room, JID, Nick, State) ->
+ ok.
+
+room_message(Host, Room, FromJID, _FromNick, Message) ->
+ Message.
+
+room_message_private(Host, Room, FromJID, _FromNick, ToJIDs, _ToNick, Message) ->
+ Message.
44 src/mod_muc/mod_muc_room.erl
View
@@ -127,6 +127,7 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Creator, _Nick, D
[Room, Host, jlib:jid_to_string(Creator)]),
add_to_log(room_existence, created, State1),
add_to_log(room_existence, started, State1),
+ mod_muc_hook:room_state(Host, Room, opened),
{ok, normal_state, State1};
init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts]) ->
process_flag(trap_exit, true),
@@ -554,7 +555,8 @@ normal_state({route, From, ToNick,
?DICT:find(jlib:jid_tolower(From),
StateData#state.users),
FromNickJID = jlib:jid_replace_resource(StateData#state.jid, FromNick),
- [ejabberd_router:route(FromNickJID, ToJID, Packet) || ToJID <- ToJIDs];
+ NewPacket = mod_hook_message(Packet, StateData#state.host, StateData#state.room, From, FromNick, ToJIDs, ToNick),
+ [ejabberd_router:route(FromNickJID, ToJID, NewPacket) || ToJID <- ToJIDs];
true ->
ErrText = "It is not allowed to send private messages",
Err = jlib:make_error_reply(
@@ -691,6 +693,7 @@ handle_event({destroy, Reason}, _StateName, StateData) ->
?INFO_MSG("Destroyed MUC room ~s with reason: ~p",
[jlib:jid_to_string(StateData#state.jid), Reason]),
add_to_log(room_existence, destroyed, StateData),
+ mod_muc_hook:room_state(StateData#state.host, StateData#state.room, closed),
{stop, shutdown, StateData};
handle_event(destroy, StateName, StateData) ->
?INFO_MSG("Destroyed MUC room ~s",
@@ -900,6 +903,7 @@ process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet,
end,
case IsAllowed of
true ->
+ NewPacket = mod_hook_message(Packet, StateData#state.host, StateData#state.room, From, FromNick),
lists:foreach(
fun({_LJID, Info}) ->
ejabberd_router:route(
@@ -907,13 +911,13 @@ process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet,
StateData#state.jid,
FromNick),
Info#user.jid,
- Packet)
+ NewPacket)
end,
?DICT:to_list(StateData#state.users)),
NewStateData2 =
add_message_to_history(FromNick,
From,
- Packet,
+ NewPacket,
NewStateData1),
{next_state, normal_state, NewStateData2};
_ ->
@@ -1091,6 +1095,7 @@ process_presence(From, Nick, {xmlelement, "presence", Attrs, _Els} = Packet,
?INFO_MSG("Destroyed MUC room ~s because it's temporary and empty",
[jlib:jid_to_string(StateData#state.jid)]),
add_to_log(room_existence, destroyed, StateData),
+ mod_muc_hook:room_state(StateData#state.host, StateData#state.room, closed),
{stop, normal, StateData1};
_ ->
{next_state, normal_state, StateData1}
@@ -1556,6 +1561,7 @@ add_online_user(JID, Nick, Role, StateData) ->
role = Role},
StateData#state.users),
add_to_log(join, Nick, StateData),
+ mod_muc_hook:room_user(StateData#state.host, StateData#state.room, JID, Nick, joined),
Nicks = ?DICT:update(Nick,
fun(Entry) ->
case lists:member(LJID, Entry) of
@@ -1578,6 +1584,7 @@ remove_online_user(JID, StateData, Reason) ->
{ok, #user{nick = Nick}} =
?DICT:find(LJID, StateData#state.users),
add_to_log(leave, {Nick, Reason}, StateData),
+ mod_muc_hook:room_user(StateData#state.host, StateData#state.room, JID, Nick, left),
tab_remove_online_user(JID, StateData),
Users = ?DICT:erase(LJID, StateData#state.users),
Nicks = case ?DICT:find(Nick, StateData#state.nicks) of
@@ -3008,6 +3015,7 @@ process_iq_owner(From, set, Lang, SubEl, StateData) ->
?INFO_MSG("Destroyed MUC room ~s by the owner ~s",
[jlib:jid_to_string(StateData#state.jid), jlib:jid_to_string(From)]),
add_to_log(room_existence, destroyed, StateData),
+ mod_muc_hook:room_state(StateData#state.host, StateData#state.room, closed),
destroy_room(SubEl1, StateData);
Items ->
process_admin_items_set(From, Items, Lang, StateData)
@@ -4081,3 +4089,33 @@ tab_count_user(JID) ->
element_size(El) ->
size(xml:element_to_binary(El)).
+
+
+mod_hook_modify_message(Out, [], _ModFun) ->
+ Out;
+mod_hook_modify_message(Out, [ H | Elems ], ModFun) ->
+ case H of
+ { xmlelement, "body", _, _ } ->
+ Message = xml:get_tag_cdata(H),
+ NewMessage = ModFun(Message),
+ NewBody = { xmlelement, "body", [], [{xmlcdata, NewMessage}] },
+ mod_hook_modify_message(Out ++ [NewBody], Elems, ModFun);
+ _ ->
+ mod_hook_modify_message(Out ++ [H], Elems, ModFun)
+ end.
+
+mod_hook_message({xmlelement, "message", Attrs, Elems}, ModFun) ->
+ ModElems = mod_hook_modify_message([], Elems, ModFun),
+ {xmlelement, "message", Attrs, ModElems}.
+
+mod_hook_message(Packet, Host, Room, JID, Nick) ->
+ mod_hook_message(Packet,
+ fun(Message) ->
+ mod_muc_hook:room_message(Host, Room, JID, Nick, Message)
+ end).
+
+mod_hook_message(Packet, Host, Room, JID, Nick, ToJIDs, ToNick) ->
+ mod_hook_message(Packet,
+ fun(Message) ->
+ mod_muc_hook:room_message_private(Host, Room, JID, Nick, ToJIDs, ToNick, Message)
+ end).
Something went wrong with that request. Please try again.