mirror of
https://github.com/processone/ejabberd.git
synced 2024-06-30 23:02:00 +02:00
* src/ejabberd_captcha.erl: XEP-158 (CAPTCHA Forms).
* src/ejabberd_config.erl: likewise. * src/ejabberd_sup.erl: likewise. * src/jlib.hrl: likewise. * src/web/ejabberd_http.erl: likewise. * src/mod_muc/mod_muc_room.erl: CAPTCHA support. * src/mod_muc/mod_muc_room.hrl: likewise. SVN Revision: 1991
This commit is contained in:
parent
f214b8c528
commit
7e924341e4
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
||||||
|
2009-03-13 Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||||
|
|
||||||
|
* src/ejabberd_captcha.erl: XEP-158 (CAPTCHA Forms).
|
||||||
|
* src/ejabberd_config.erl: likewise.
|
||||||
|
* src/ejabberd_sup.erl: likewise.
|
||||||
|
* src/jlib.hrl: likewise.
|
||||||
|
* src/web/ejabberd_http.erl: likewise.
|
||||||
|
* src/mod_muc/mod_muc_room.erl: CAPTCHA support.
|
||||||
|
* src/mod_muc/mod_muc_room.hrl: likewise.
|
||||||
|
|
||||||
2009-03-10 Badlop <badlop@process-one.net>
|
2009-03-10 Badlop <badlop@process-one.net>
|
||||||
|
|
||||||
* doc/release_notes_2.0.4.txt: Added file for new release
|
* doc/release_notes_2.0.4.txt: Added file for new release
|
||||||
|
|
|
@ -375,6 +375,10 @@ process_term(Term, State) ->
|
||||||
add_option(watchdog_large_heap, LH, State);
|
add_option(watchdog_large_heap, LH, State);
|
||||||
{registration_timeout, Timeout} ->
|
{registration_timeout, Timeout} ->
|
||||||
add_option(registration_timeout, Timeout, State);
|
add_option(registration_timeout, Timeout, State);
|
||||||
|
{captcha_cmd, Cmd} ->
|
||||||
|
add_option(captcha_cmd, Cmd, State);
|
||||||
|
{captcha_host, Host} ->
|
||||||
|
add_option(captcha_host, Host, State);
|
||||||
{loglevel, Loglevel} ->
|
{loglevel, Loglevel} ->
|
||||||
ejabberd_loglevel:set(Loglevel),
|
ejabberd_loglevel:set(Loglevel),
|
||||||
State;
|
State;
|
||||||
|
|
|
@ -84,6 +84,13 @@ init([]) ->
|
||||||
brutal_kill,
|
brutal_kill,
|
||||||
worker,
|
worker,
|
||||||
[ejabberd_local]},
|
[ejabberd_local]},
|
||||||
|
Captcha =
|
||||||
|
{ejabberd_captcha,
|
||||||
|
{ejabberd_captcha, start_link, []},
|
||||||
|
permanent,
|
||||||
|
brutal_kill,
|
||||||
|
worker,
|
||||||
|
[ejabberd_captcha]},
|
||||||
Listener =
|
Listener =
|
||||||
{ejabberd_listener,
|
{ejabberd_listener,
|
||||||
{ejabberd_listener, start_link, []},
|
{ejabberd_listener, start_link, []},
|
||||||
|
@ -170,6 +177,7 @@ init([]) ->
|
||||||
SM,
|
SM,
|
||||||
S2S,
|
S2S,
|
||||||
Local,
|
Local,
|
||||||
|
Captcha,
|
||||||
ReceiverSupervisor,
|
ReceiverSupervisor,
|
||||||
C2SSupervisor,
|
C2SSupervisor,
|
||||||
S2SInSupervisor,
|
S2SInSupervisor,
|
||||||
|
|
|
@ -75,6 +75,12 @@
|
||||||
|
|
||||||
-define(NS_CAPS, "http://jabber.org/protocol/caps").
|
-define(NS_CAPS, "http://jabber.org/protocol/caps").
|
||||||
|
|
||||||
|
%% CAPTCHA related NSes.
|
||||||
|
-define(NS_OOB, "jabber:x:oob").
|
||||||
|
-define(NS_CAPTCHA, "urn:xmpp:captcha").
|
||||||
|
-define(NS_MEDIA, "urn:xmpp:media-element").
|
||||||
|
-define(NS_BOB, "urn:xmpp:bob").
|
||||||
|
|
||||||
% TODO: remove "code" attribute (currently it used for backward-compatibility)
|
% TODO: remove "code" attribute (currently it used for backward-compatibility)
|
||||||
-define(STANZA_ERROR(Code, Type, Condition),
|
-define(STANZA_ERROR(Code, Type, Condition),
|
||||||
{xmlelement, "error",
|
{xmlelement, "error",
|
||||||
|
|
|
@ -316,7 +316,8 @@ normal_state({route, From, "",
|
||||||
(XMLNS == ?NS_MUC_ADMIN) or
|
(XMLNS == ?NS_MUC_ADMIN) or
|
||||||
(XMLNS == ?NS_MUC_OWNER) or
|
(XMLNS == ?NS_MUC_OWNER) or
|
||||||
(XMLNS == ?NS_DISCO_INFO) or
|
(XMLNS == ?NS_DISCO_INFO) or
|
||||||
(XMLNS == ?NS_DISCO_ITEMS) ->
|
(XMLNS == ?NS_DISCO_ITEMS) or
|
||||||
|
(XMLNS == ?NS_CAPTCHA) ->
|
||||||
Res1 = case XMLNS of
|
Res1 = case XMLNS of
|
||||||
?NS_MUC_ADMIN ->
|
?NS_MUC_ADMIN ->
|
||||||
process_iq_admin(From, Type, Lang, SubEl, StateData);
|
process_iq_admin(From, Type, Lang, SubEl, StateData);
|
||||||
|
@ -325,7 +326,9 @@ normal_state({route, From, "",
|
||||||
?NS_DISCO_INFO ->
|
?NS_DISCO_INFO ->
|
||||||
process_iq_disco_info(From, Type, Lang, StateData);
|
process_iq_disco_info(From, Type, Lang, StateData);
|
||||||
?NS_DISCO_ITEMS ->
|
?NS_DISCO_ITEMS ->
|
||||||
process_iq_disco_items(From, Type, Lang, StateData)
|
process_iq_disco_items(From, Type, Lang, StateData);
|
||||||
|
?NS_CAPTCHA ->
|
||||||
|
process_iq_captcha(From, Type, Lang, SubEl, StateData)
|
||||||
end,
|
end,
|
||||||
{IQRes, NewStateData} =
|
{IQRes, NewStateData} =
|
||||||
case Res1 of
|
case Res1 of
|
||||||
|
@ -685,6 +688,30 @@ handle_info(process_room_queue, normal_state = StateName, StateData) ->
|
||||||
{empty, _} ->
|
{empty, _} ->
|
||||||
{next_state, StateName, StateData}
|
{next_state, StateName, StateData}
|
||||||
end;
|
end;
|
||||||
|
handle_info({captcha_succeed, From}, normal_state, StateData) ->
|
||||||
|
NewState = case ?DICT:find(From, StateData#state.robots) of
|
||||||
|
{ok, {Nick, Packet}} ->
|
||||||
|
Robots = ?DICT:store(From, passed, StateData#state.robots),
|
||||||
|
add_new_user(From, Nick, Packet, StateData#state{robots=Robots});
|
||||||
|
_ ->
|
||||||
|
StateData
|
||||||
|
end,
|
||||||
|
{next_state, normal_state, NewState};
|
||||||
|
handle_info({captcha_failed, From}, normal_state, StateData) ->
|
||||||
|
NewState = case ?DICT:find(From, StateData#state.robots) of
|
||||||
|
{ok, {Nick, Packet}} ->
|
||||||
|
Robots = ?DICT:erase(From, StateData#state.robots),
|
||||||
|
Err = jlib:make_error_reply(
|
||||||
|
Packet, ?ERR_NOT_AUTHORIZED),
|
||||||
|
ejabberd_router:route( % TODO: s/Nick/""/
|
||||||
|
jlib:jid_replace_resource(
|
||||||
|
StateData#state.jid, Nick),
|
||||||
|
From, Err),
|
||||||
|
StateData#state{robots=Robots};
|
||||||
|
_ ->
|
||||||
|
StateData
|
||||||
|
end,
|
||||||
|
{next_state, normal_state, NewState};
|
||||||
handle_info(_Info, StateName, StateData) ->
|
handle_info(_Info, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
|
@ -1489,7 +1516,8 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
|
||||||
From, Err),
|
From, Err),
|
||||||
StateData;
|
StateData;
|
||||||
{_, _, _, Role} ->
|
{_, _, _, Role} ->
|
||||||
case check_password(ServiceAffiliation, Els, StateData) of
|
case check_password(ServiceAffiliation, Affiliation,
|
||||||
|
Els, From, StateData) of
|
||||||
true ->
|
true ->
|
||||||
NewState =
|
NewState =
|
||||||
add_user_presence(
|
add_user_presence(
|
||||||
|
@ -1522,7 +1550,8 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
|
||||||
true ->
|
true ->
|
||||||
NewState#state{just_created = false};
|
NewState#state{just_created = false};
|
||||||
false ->
|
false ->
|
||||||
NewState
|
Robots = ?DICT:erase(From, StateData#state.robots),
|
||||||
|
NewState#state{robots = Robots}
|
||||||
end;
|
end;
|
||||||
nopass ->
|
nopass ->
|
||||||
ErrText = "Password required to enter this room",
|
ErrText = "Password required to enter this room",
|
||||||
|
@ -1533,6 +1562,29 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
|
||||||
StateData#state.jid, Nick),
|
StateData#state.jid, Nick),
|
||||||
From, Err),
|
From, Err),
|
||||||
StateData;
|
StateData;
|
||||||
|
captcha_required ->
|
||||||
|
ID = randoms:get_string(),
|
||||||
|
SID = xml:get_attr_s("id", Attrs),
|
||||||
|
RoomJID = StateData#state.jid,
|
||||||
|
To = jlib:jid_replace_resource(RoomJID, Nick),
|
||||||
|
case ejabberd_captcha:create_captcha(
|
||||||
|
ID, SID, RoomJID, To, Lang, From) of
|
||||||
|
{ok, CaptchaEls} ->
|
||||||
|
MsgPkt = {xmlelement, "message", [{"id", ID}], CaptchaEls},
|
||||||
|
Robots = ?DICT:store(From,
|
||||||
|
{Nick, Packet}, StateData#state.robots),
|
||||||
|
ejabberd_router:route(RoomJID, From, MsgPkt),
|
||||||
|
StateData#state{robots = Robots};
|
||||||
|
error ->
|
||||||
|
ErrText = "Unable to generate a captcha",
|
||||||
|
Err = jlib:make_error_reply(
|
||||||
|
Packet, ?ERRT_INTERNAL_SERVER_ERROR(Lang, ErrText)),
|
||||||
|
ejabberd_router:route( % TODO: s/Nick/""/
|
||||||
|
jlib:jid_replace_resource(
|
||||||
|
StateData#state.jid, Nick),
|
||||||
|
From, Err),
|
||||||
|
StateData
|
||||||
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
ErrText = "Incorrect password",
|
ErrText = "Incorrect password",
|
||||||
Err = jlib:make_error_reply(
|
Err = jlib:make_error_reply(
|
||||||
|
@ -1545,13 +1597,13 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
check_password(owner, _Els, _StateData) ->
|
check_password(owner, _Affiliation, _Els, _From, _StateData) ->
|
||||||
%% Don't check pass if user is owner in MUC service (access_admin option)
|
%% Don't check pass if user is owner in MUC service (access_admin option)
|
||||||
true;
|
true;
|
||||||
check_password(_ServiceAffiliation, Els, StateData) ->
|
check_password(_ServiceAffiliation, Affiliation, Els, From, StateData) ->
|
||||||
case (StateData#state.config)#config.password_protected of
|
case (StateData#state.config)#config.password_protected of
|
||||||
false ->
|
false ->
|
||||||
true;
|
check_captcha(Affiliation, From, StateData);
|
||||||
true ->
|
true ->
|
||||||
Pass = extract_password(Els),
|
Pass = extract_password(Els),
|
||||||
case Pass of
|
case Pass of
|
||||||
|
@ -1567,6 +1619,19 @@ check_password(_ServiceAffiliation, Els, StateData) ->
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
check_captcha(Affiliation, From, StateData) ->
|
||||||
|
case (StateData#state.config)#config.captcha_protected of
|
||||||
|
true when Affiliation == none ->
|
||||||
|
case ?DICT:find(From, StateData#state.robots) of
|
||||||
|
{ok, passed} ->
|
||||||
|
true;
|
||||||
|
_ ->
|
||||||
|
captcha_required
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
true
|
||||||
|
end.
|
||||||
|
|
||||||
extract_password([]) ->
|
extract_password([]) ->
|
||||||
false;
|
false;
|
||||||
extract_password([{xmlelement, _Name, Attrs, _SubEls} = El | Els]) ->
|
extract_password([{xmlelement, _Name, Attrs, _SubEls} = El | Els]) ->
|
||||||
|
@ -2744,6 +2809,9 @@ get_config(Lang, StateData, From) ->
|
||||||
?BOOLXFIELD("Make room members-only",
|
?BOOLXFIELD("Make room members-only",
|
||||||
"muc#roomconfig_membersonly",
|
"muc#roomconfig_membersonly",
|
||||||
Config#config.members_only),
|
Config#config.members_only),
|
||||||
|
?BOOLXFIELD("Make room captcha protected",
|
||||||
|
"captcha_protected",
|
||||||
|
Config#config.captcha_protected),
|
||||||
?BOOLXFIELD("Make room moderated",
|
?BOOLXFIELD("Make room moderated",
|
||||||
"muc#roomconfig_moderatedroom",
|
"muc#roomconfig_moderatedroom",
|
||||||
Config#config.moderated),
|
Config#config.moderated),
|
||||||
|
@ -2856,6 +2924,8 @@ set_xoption([{"members_by_default", [Val]} | Opts], Config) ->
|
||||||
?SET_BOOL_XOPT(members_by_default, Val);
|
?SET_BOOL_XOPT(members_by_default, Val);
|
||||||
set_xoption([{"muc#roomconfig_membersonly", [Val]} | Opts], Config) ->
|
set_xoption([{"muc#roomconfig_membersonly", [Val]} | Opts], Config) ->
|
||||||
?SET_BOOL_XOPT(members_only, Val);
|
?SET_BOOL_XOPT(members_only, Val);
|
||||||
|
set_xoption([{"captcha_protected", [Val]} | Opts], Config) ->
|
||||||
|
?SET_BOOL_XOPT(captcha_protected, Val);
|
||||||
set_xoption([{"muc#roomconfig_allowinvites", [Val]} | Opts], Config) ->
|
set_xoption([{"muc#roomconfig_allowinvites", [Val]} | Opts], Config) ->
|
||||||
?SET_BOOL_XOPT(allow_user_invites, Val);
|
?SET_BOOL_XOPT(allow_user_invites, Val);
|
||||||
set_xoption([{"muc#roomconfig_passwordprotectedroom", [Val]} | Opts], Config) ->
|
set_xoption([{"muc#roomconfig_passwordprotectedroom", [Val]} | Opts], Config) ->
|
||||||
|
@ -2947,6 +3017,7 @@ set_opts([{Opt, Val} | Opts], StateData) ->
|
||||||
members_only -> StateData#state{config = (StateData#state.config)#config{members_only = Val}};
|
members_only -> StateData#state{config = (StateData#state.config)#config{members_only = Val}};
|
||||||
allow_user_invites -> StateData#state{config = (StateData#state.config)#config{allow_user_invites = Val}};
|
allow_user_invites -> StateData#state{config = (StateData#state.config)#config{allow_user_invites = Val}};
|
||||||
password_protected -> StateData#state{config = (StateData#state.config)#config{password_protected = Val}};
|
password_protected -> StateData#state{config = (StateData#state.config)#config{password_protected = Val}};
|
||||||
|
captcha_protected -> StateData#state{config = (StateData#state.config)#config{captcha_protected = Val}};
|
||||||
password -> StateData#state{config = (StateData#state.config)#config{password = Val}};
|
password -> StateData#state{config = (StateData#state.config)#config{password = Val}};
|
||||||
anonymous -> StateData#state{config = (StateData#state.config)#config{anonymous = Val}};
|
anonymous -> StateData#state{config = (StateData#state.config)#config{anonymous = Val}};
|
||||||
logging -> StateData#state{config = (StateData#state.config)#config{logging = Val}};
|
logging -> StateData#state{config = (StateData#state.config)#config{logging = Val}};
|
||||||
|
@ -2989,6 +3060,7 @@ make_opts(StateData) ->
|
||||||
?MAKE_CONFIG_OPT(members_only),
|
?MAKE_CONFIG_OPT(members_only),
|
||||||
?MAKE_CONFIG_OPT(allow_user_invites),
|
?MAKE_CONFIG_OPT(allow_user_invites),
|
||||||
?MAKE_CONFIG_OPT(password_protected),
|
?MAKE_CONFIG_OPT(password_protected),
|
||||||
|
?MAKE_CONFIG_OPT(captcha_protected),
|
||||||
?MAKE_CONFIG_OPT(password),
|
?MAKE_CONFIG_OPT(password),
|
||||||
?MAKE_CONFIG_OPT(anonymous),
|
?MAKE_CONFIG_OPT(anonymous),
|
||||||
?MAKE_CONFIG_OPT(logging),
|
?MAKE_CONFIG_OPT(logging),
|
||||||
|
@ -3112,6 +3184,17 @@ process_iq_disco_items(From, get, _Lang, StateData) ->
|
||||||
{error, ?ERR_FORBIDDEN}
|
{error, ?ERR_FORBIDDEN}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
process_iq_captcha(_From, get, _Lang, _SubEl, _StateData) ->
|
||||||
|
{error, ?ERR_NOT_ALLOWED};
|
||||||
|
|
||||||
|
process_iq_captcha(_From, set, _Lang, SubEl, StateData) ->
|
||||||
|
case ejabberd_captcha:process_reply(SubEl) of
|
||||||
|
ok ->
|
||||||
|
{result, [], StateData};
|
||||||
|
_ ->
|
||||||
|
{error, ?ERR_NOT_ACCEPTABLE}
|
||||||
|
end.
|
||||||
|
|
||||||
get_title(StateData) ->
|
get_title(StateData) ->
|
||||||
case (StateData#state.config)#config.title of
|
case (StateData#state.config)#config.title of
|
||||||
"" ->
|
"" ->
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
public_list = true,
|
public_list = true,
|
||||||
persistent = false,
|
persistent = false,
|
||||||
moderated = true,
|
moderated = true,
|
||||||
|
captcha_protected = false,
|
||||||
members_by_default = true,
|
members_by_default = true,
|
||||||
members_only = false,
|
members_only = false,
|
||||||
allow_user_invites = false,
|
allow_user_invites = false,
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
jid,
|
jid,
|
||||||
config = #config{},
|
config = #config{},
|
||||||
users = ?DICT:new(),
|
users = ?DICT:new(),
|
||||||
|
robots = ?DICT:new(),
|
||||||
affiliations = ?DICT:new(),
|
affiliations = ?DICT:new(),
|
||||||
history,
|
history,
|
||||||
subject = "",
|
subject = "",
|
||||||
|
|
|
@ -110,6 +110,10 @@ start_link({SockMod, Socket}, Opts) ->
|
||||||
{value, {request_handlers, H}} -> H;
|
{value, {request_handlers, H}} -> H;
|
||||||
false -> []
|
false -> []
|
||||||
end ++
|
end ++
|
||||||
|
case lists:member(captcha, Opts) of
|
||||||
|
true -> [{["captcha"], ejabberd_captcha}];
|
||||||
|
false -> []
|
||||||
|
end ++
|
||||||
case lists:member(web_admin, Opts) of
|
case lists:member(web_admin, Opts) of
|
||||||
true -> [{["admin"], ejabberd_web_admin}];
|
true -> [{["admin"], ejabberd_web_admin}];
|
||||||
false -> []
|
false -> []
|
||||||
|
|
Loading…
Reference in New Issue
Block a user