Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Admin extra interface #575

Merged
merged 6 commits into from
Dec 3, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 56 additions & 24 deletions apps/ejabberd/src/mod_admin_extra_accounts.erl
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@
delete_old_users/1,
delete_old_users_vhost/2,
ban_account/3,
num_active_users/2
]).
num_active_users/2,
check_account/2,
check_password/3]).

-include("ejabberd.hrl").
-include("ejabberd_commands.hrl").
Expand All @@ -53,13 +54,13 @@ commands() ->
desc = "Change the password of an account",
module = ?MODULE, function = set_password,
args = [{user, binary}, {host, binary}, {newpass, binary}],
result = {res, rescode}},
result = {res, restuple}},
#ejabberd_commands{name = check_password_hash, tags = [accounts],
desc = "Check if the password hash is correct",
longdesc = "Allowed hash methods: md5, sha.",
module = ?MODULE, function = check_password_hash,
args = [{user, binary}, {host, binary}, {passwordhash, string}, {hashmethod, string}],
result = {res, rescode}},
result = {res, restuple}},
#ejabberd_commands{name = delete_old_users, tags = [accounts, purge],
desc = "Delete users that didn't log in last days, or that never logged",
module = ?MODULE, function = delete_old_users,
Expand All @@ -74,38 +75,66 @@ commands() ->
desc = "Ban an account: kick sessions and set random password",
module = ?MODULE, function = ban_account,
args = [{user, binary}, {host, binary}, {reason, binary}],
result = {res, rescode}},
result = {res, restuple}},
#ejabberd_commands{name = num_active_users, tags = [accounts, stats],
desc = "Get number of users active in the last days",
module = ?MODULE, function = num_active_users,
args = [{host, binary}, {days, integer}],
result = {users, integer}},
#ejabberd_commands{name = check_account, tags = [accounts],
desc = "Check if an account exists or not",
module = ejabberd_auth, function = is_user_exists,
module = ?MODULE, function = check_account,
args = [{user, binary}, {host, binary}],
result = {res, rescode}},
result = {res, restuple}},
#ejabberd_commands{name = check_password, tags = [accounts],
desc = "Check if a password is correct",
module = ejabberd_auth, function = check_password,
module = ?MODULE, function = check_password,
args = [{user, binary}, {host, binary}, {password, binary}],
result = {res, rescode}}
result = {res, restuple}}
].

%%%
%%% Accounts
%%%

-spec set_password(ejabberd:user(), ejabberd:server(), binary()) -> 'error' | 'ok'.
-spec set_password(ejabberd:user(), ejabberd:server(), binary()) -> {'error', string()} | {'ok', string()}.
set_password(User, Host, Password) ->
case ejabberd_auth:set_password(User, Host, Password) of
ok -> ok;
_ -> error
ok ->
{ok, io_lib:format("Password for user ~s@~s successfully changed", [User, Host])};
{error, Reason} ->
{error, Reason}
end.

-spec check_password(ejabberd:user(), ejabberd:server(), binary()) -> {Res, string()} when
Res :: ok | incorrect | user_does_not_exist.
check_password(User, Host, Password) ->
case ejabberd_auth:is_user_exists(User, Host) of
true ->
case ejabberd_auth:check_password(User, Host, Password) of
true ->
{ok, io_lib:format("Password '~s' for user ~s@~s is correct", [Password, User, Host])};
false ->
{incorrect, io_lib:format("Password '~s' for user ~s@~s is incorrect", [Password, User, Host])}
end;
false ->
{user_does_not_exist, io_lib:format("Password '~s' for user ~s@~s is incorrect because this user does not
exist", [Password, User, Host])}
end.

-spec check_account(ejabberd:user(), ejabberd:server()) -> {Res, string()} when
Res :: ok | user_does_not_exist.
check_account(User, Host) ->
case ejabberd_auth:is_user_exists(User, Host) of
true ->
{ok, io_lib:format("User ~s@~s exists", [User, Host])};
false ->
{user_does_not_exist, io_lib:format("User ~s@~s does not exist", [User, Host])}
end.


-spec check_password_hash(ejabberd:user(), ejabberd:server(), Hash :: binary(),
Method :: string()) -> 'error' | 'ok'.
Method :: string()) -> {'error', string()} | {'ok', string()} | {'incorrect', string()}.
check_password_hash(User, Host, PasswordHash, HashMethod) ->
AccountPass = ejabberd_auth:get_password_s(User, Host),
AccountPassHash = case HashMethod of
Expand All @@ -114,9 +143,12 @@ check_password_hash(User, Host, PasswordHash, HashMethod) ->
_ -> undefined
end,
case AccountPassHash of
undefined -> error;
PasswordHash -> ok;
_ -> error
undefined ->
{error, "Hash for password is undefined"};
PasswordHash ->
{ok, "Password hash is correct"};
_->
{incorrect, "Password hash is incorrect"}
end.


Expand Down Expand Up @@ -220,13 +252,16 @@ get_lastactivity_module(Server) ->
end.


-spec ban_account(ejabberd:user(), ejabberd:server(), binary() | string()) -> 'ok'.
-spec ban_account(ejabberd:user(), ejabberd:server(), binary() | string()) -> {'ok', string()} | {'error', string()}.
ban_account(User, Host, ReasonText) ->
Reason = mod_admin_extra_sessions:prepare_reason(ReasonText),
kick_sessions(User, Host, Reason),
set_random_password(User, Host, Reason),
ok.

case set_random_password(User, Host, Reason) of
ok ->
{ok, io_lib:format("User ~s@~s successfully banned with reason: ~s",[User, Host, ReasonText])};
{error, ErrorReason} ->
{error, ErrorReason}
end.

-spec kick_sessions(ejabberd:user(), ejabberd:server(), binary()) -> [ok].
kick_sessions(User, Server, Reason) ->
Expand All @@ -240,7 +275,7 @@ kick_sessions(User, Server, Reason) ->
-spec set_random_password(ejabberd:user(), ejabberd:server(), binary()) -> 'ok'.
set_random_password(User, Server, Reason) ->
NewPass = build_random_password(Reason),
set_password_auth(User, Server, NewPass).
ejabberd_auth:set_password(User, Server, NewPass).


-spec build_random_password(Reason :: binary()) -> binary().
Expand All @@ -254,6 +289,3 @@ build_random_password(Reason) ->
<<"BANNED_ACCOUNT--", Date/binary, "--", RandomString/binary, "--", Reason/binary>>.


-spec set_password_auth(ejabberd:user(), ejabberd:server(), binary()) -> 'ok'.
set_password_auth(User, Server, Password) ->
ok = ejabberd_auth:set_password(User, Server, Password).
34 changes: 25 additions & 9 deletions apps/ejabberd/src/mod_admin_extra_last.erl
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@
-author('[email protected]').

-export([
commands/0,
commands/0,

set_last/4,
get_lastactivity_module/1
]).
set_last/4,
get_lastactivity_fun/1,
get_lastactivity_module/1]).

-include("ejabberd.hrl").
-include("ejabberd_commands.hrl").
Expand All @@ -53,19 +53,35 @@ commands() ->
"1970-01-01 00:00:00 UTC, for example: date +%s",
module = ?MODULE, function = set_last,
args = [{user, binary}, {host, binary}, {timestamp, integer}, {status, binary}],
result = {res, rescode}}
result = {res, restuple}}
].

%%%
%%% Last Activity
%%%

-spec set_last(ejabberd:user(), ejabberd:server(), _, _) -> 'ok'.
-spec set_last(ejabberd:user(), ejabberd:server(), _, _) -> {Res, string()} when
Res :: ok | user_does_not_exist.
set_last(User, Server, Timestamp, Status) ->
Mod = get_lastactivity_module(Server),
Mod:store_last_info(jid:nodeprep(User), jid:nameprep(Server), Timestamp, Status),
ok.
case ejabberd_auth:is_user_exists(User, Server) of
true ->
Fun = get_lastactivity_fun(Server),
Module = get_lastactivity_module(Server),
Module:Fun(jid:nodeprep(User), jid:nameprep(Server), Timestamp, Status),
{ok, io_lib:format("Last activity for user ~s@~s is set as ~B with status ~s", [User, Server, Timestamp, Status])};
false ->
String = io_lib:format("User ~s@~s does not exist", [User, Server]),
{user_does_not_exist, String}
end.


%% Could just return fun mod_last:store_last_info/4 but its easier when called through rpc in tests
-spec get_lastactivity_fun(ejabberd:server()) -> 'store_last_info' | 'set_last_info'.
get_lastactivity_fun(Server) ->
case lists:member(mod_last, gen_mod:loaded_modules(Server)) of
true -> store_last_info;
_ -> set_last_info
end.

-spec get_lastactivity_module(ejabberd:server()) -> 'mod_last' | 'mod_last_odbc'.
get_lastactivity_module(Server) ->
Expand Down
74 changes: 44 additions & 30 deletions apps/ejabberd/src/mod_admin_extra_private.erl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

-export([
commands/0,

private_get/4,
private_set/3
]).
Expand All @@ -50,12 +49,12 @@ commands() ->
desc = "Get some information from a user private storage",
module = ?MODULE, function = private_get,
args = [{user, binary}, {host, binary}, {element, binary}, {ns, binary}],
result = {res, string}},
result = {content, string}},
#ejabberd_commands{name = private_set, tags = [private],
desc = "Set to the user private storage",
module = ?MODULE, function = private_set,
args = [{user, binary}, {host, binary}, {element, binary}],
result = {res, rescode}}
result = {res, restuple}}
].

%%%
Expand All @@ -67,51 +66,66 @@ commands() ->
%% $ mongooseimctl private_get badlop localhost aa bb
%% <aa xmlns='bb'>Cluth</aa>

-spec private_get(ejabberd:user(), ejabberd:server(), binary(), binary()) -> binary().
-spec private_get(ejabberd:user(), ejabberd:server(), binary(), binary()) ->
{error, string()} | string().
private_get(Username, Host, Element, Ns) ->
M = get_private_module(Host),
case ejabberd_auth:is_user_exists(Username, Host) of
true ->
do_private_get(Username, Host, Element, Ns);
false ->
{error, io_lib:format("User ~s@~s does not exist", [Username, Host])}
end.

do_private_get(Username, Host, Element, Ns) ->
From = jid:make(Username, Host, <<"">>),
To = jid:make(Username, Host, <<"">>),
IQ = {iq, <<"">>, get, ?NS_PRIVATE, <<"">>,
#xmlel{ name = <<"query">>,
attrs = [{<<"xmlns">>,?NS_PRIVATE}],
children = [#xmlel{ name = Element, attrs = [{<<"xmlns">>, Ns}]}] } },
ResIq = M:process_sm_iq(From, To, IQ),
attrs = [{<<"xmlns">>,?NS_PRIVATE}],
children = [#xmlel{ name = Element, attrs = [{<<"xmlns">>, Ns}]}] } },
ResIq = mod_private:process_sm_iq(From, To, IQ),
[#xmlel{ name = <<"query">>,
attrs = [{<<"xmlns">>,<<"jabber:iq:private">>}],
children = [SubEl] }] = ResIq#iq.sub_el,
attrs = [{<<"xmlns">>,<<"jabber:iq:private">>}],
children = [SubEl] }] = ResIq#iq.sub_el,
exml:to_binary(SubEl).


-spec private_set(ejabberd:user(), ejabberd:server(),
ElementString :: binary()) -> error | ok.
ElementString :: binary()) -> {Res, string()} when
Res :: ok | user_does_not_exist | user_does_not_exist | not_loaded.
private_set(Username, Host, ElementString) ->
case exml:parse(ElementString) of
{error, Error} ->
io:format("Error found parsing the element:~n ~p~nError: ~p~n",
String = io_lib:format("Error found parsing the element:~n ~p~nError: ~p~n",
[ElementString, Error]),
error;
{parse_error, String};
{ok, Xml} ->
private_set2(Username, Host, Xml)
end.


-spec private_set2(ejabberd:user(), ejabberd:server(), Xml :: jlib:xmlel()) -> ok.
private_set2(Username, Host, Xml) ->
M = get_private_module(Host),
From = jid:make(Username, Host, <<"">>),
To = jid:make(Username, Host, <<"">>),
IQ = {iq, <<"">>, set, ?NS_PRIVATE, <<"">>,
#xmlel{ name = <<"query">>,
attrs = [{<<"xmlns">>,?NS_PRIVATE}],
children = [Xml]}},
M:process_sm_iq(From, To, IQ),
ok.

case ejabberd_auth:is_user_exists(Username, Host) of
true ->
do_private_set2(Username, Host, Xml);
false ->
{user_does_not_exist, io_lib:format("User ~s@~s does not exist", [Username, Host])}
end.

-spec get_private_module(ejabberd:server()) -> 'mod_private' | 'mod_private_odbc'.
get_private_module(Server) ->
case lists:member(mod_private, gen_mod:loaded_modules(Server)) of
true -> mod_private;
_ -> mod_private_odbc
do_private_set2(Username, Host, Xml) ->
case is_private_module_loaded(Host) of
true ->
From = jid:make(Username, Host, <<"">>),
To = jid:make(Username, Host, <<"">>),
IQ = {iq, <<"">>, set, ?NS_PRIVATE, <<"">>,
#xmlel{ name = <<"query">>,
attrs = [{<<"xmlns">>,?NS_PRIVATE}],
children = [Xml]}},
mod_private:process_sm_iq(From, To, IQ),
{ok, ""};
false ->
{not_loaded, io_lib:format("Module mod_private is not loaded on host ~s", [Host])}
end.

-spec is_private_module_loaded(ejabberd:server()) -> true | false.
is_private_module_loaded(Server) ->
lists:member(mod_private, gen_mod:loaded_modules(Server)).
Loading