]> granicus.if.org Git - ejabberd/commitdiff
Added mod_register_web: web page for account registration (EJAB-471)
authorBadlop <badlop@process-one.net>
Thu, 4 Nov 2010 21:34:18 +0000 (22:34 +0100)
committerBadlop <badlop@process-one.net>
Fri, 5 Nov 2010 17:19:52 +0000 (18:19 +0100)
doc/guide.tex
src/ejabberd.cfg.example
src/web/ejabberd_http.erl
src/web/mod_register_web.erl [new file with mode: 0644]

index 51804e2268f0b0e4007b06f8e236aa05742c0d74..4fdb43b22ade343c3d471021b160b65917d2d370 100644 (file)
@@ -88,6 +88,7 @@
 \newcommand{\modpubsub}{\module{mod\_pubsub}}
 \newcommand{\modpubsubodbc}{\module{mod\_pubsub\_odbc}}
 \newcommand{\modregister}{\module{mod\_register}}
+\newcommand{\modregisterweb}{\module{mod\_register\_web}}
 \newcommand{\modroster}{\module{mod\_roster}}
 \newcommand{\modrosterodbc}{\module{mod\_roster\_odbc}}
 \newcommand{\modservicelog}{\module{mod\_service\_log}}
@@ -2530,6 +2531,7 @@ The following table lists all modules included in \ejabberd{}.
     \hline \ahrefloc{modpubsub}{\modpubsub{}} & Pub-Sub (\xepref{0060}), PEP (\xepref{0163}) & \modcaps{} \\
     \hline \ahrefloc{modpubsub}{\modpubsubodbc{}} & Pub-Sub (\xepref{0060}), PEP (\xepref{0163}) & supported DB (*) and \modcaps{} \\
     \hline \ahrefloc{modregister}{\modregister{}} & In-Band Registration (\xepref{0077}) &  \\
+    \hline \ahrefloc{modregisterweb}{\modregisterweb{}} & Web for Account Registrations &  \\
     \hline \ahrefloc{modroster}{\modroster{}} & Roster management (XMPP IM) &  \\
     \hline \ahrefloc{modroster}{\modrosterodbc{}} & Roster management (XMPP IM) & supported DB (*) \\
     \hline \ahrefloc{modservicelog}{\modservicelog{}} & Copy user messages to logger service &  \\
@@ -3862,6 +3864,49 @@ Also define a registration timeout of one hour:
 \end{verbatim}
 \end{itemize}
 
+\makesubsection{modregisterweb}{\modregisterweb{}}
+\ind{modules!\modregisterweb{}}
+
+This module provides a web page where people can:
+\begin{itemize}
+\item Register a new account on the server.
+\item Change the password from an existing account on the server.
+\item Delete an existing account on the server.
+\end{itemize}
+
+This module supports CAPTCHA image to register a new account.
+To enable this feature, configure the options captcha\_cmd and captcha\_host.
+
+Options:
+\begin{description}
+\titem{\{registration\_watchers, [ JID, ...]\}} \ind{options!rwatchers}This option defines a
+  list of JIDs which will be notified each time a new account is registered.
+\end{description}
+
+This example configuration shows how to enable the module and the web handler:
+\begin{verbatim}
+{listen, [
+  ...
+  {5281, ejabberd_http, [
+    tls,
+    {certfile, "/etc/ejabberd/certificate.pem"},
+    register
+  ]},
+  ...
+]}.
+
+{modules,
+ [
+  ...
+  {mod_register_web, []},
+  ...
+ ]}.
+\end{verbatim}
+
+The users can visit this page: https://localhost:5281/register/
+It is important to include the last / character in the URL,
+otherwise the subpages URL will be incorrect.
+
 \makesubsection{modroster}{\modroster{}}
 \ind{modules!\modroster{}}\ind{roster management}\ind{protocols!RFC 3921: XMPP IM}
 
index d05ca8e67f8827601f93e2bddf85bfba93f89fbb..96495d7e57f4b5949c659b005c88ee9f98ba7e83 100644 (file)
                         captcha,
                         http_bind,
                         http_poll,
+                        register,
                         web_admin
                        ]}
 
 
                  {access, register}
                 ]},
+  {mod_register_web, [
+                 %%
+                 %% When a user registers, send a notification to
+                 %% these XMPP accounts.
+                 %%
+                 %%{registration_watchers, ["admin1@example.org"]}
+                ]},
   {mod_roster,   []},
   %%{mod_service_log,[]},
   {mod_shared_roster,[]},
index 2f2315017401fd092d4e0bb90e91976d4d5dd08c..313e0f26409b98ee642e6f7fe7966034224fcd40 100644 (file)
@@ -111,6 +111,7 @@ init({SockMod, Socket}, Opts) ->
     %%  web_admin -> {["admin"], ejabberd_web_admin}
     %%  http_bind -> {["http-bind"], mod_http_bind}
     %%  http_poll -> {["http-poll"], ejabberd_http_poll}
+    %%  register -> {["register"], mod_register_web}
 
     RequestHandlers =
        case lists:keysearch(request_handlers, 1, Opts) of
@@ -121,6 +122,10 @@ init({SockMod, Socket}, Opts) ->
             true -> [{["captcha"], ejabberd_captcha}];
             false -> []
         end ++
+        case lists:member(register, Opts) of
+            true -> [{["register"], mod_register_web}];
+            false -> []
+        end ++
         case lists:member(web_admin, Opts) of
             true -> [{["admin"], ejabberd_web_admin}];
             false -> []
diff --git a/src/web/mod_register_web.erl b/src/web/mod_register_web.erl
new file mode 100644 (file)
index 0000000..3da93dd
--- /dev/null
@@ -0,0 +1,613 @@
+%%%-------------------------------------------------------------------
+%%% File    : mod_register_web.erl
+%%% Author  : Badlop <badlop@process-one.net>
+%%% Purpose : Web page to register account and related tasks
+%%% Created :  4 May 2008 by Badlop <badlop@process-one.net>
+%%%
+%%%
+%%% ejabberd, Copyright (C) 2002-2010   ProcessOne
+%%%
+%%% This program is free software; you can redistribute it and/or
+%%% modify it under the terms of the GNU General Public License as
+%%% published by the Free Software Foundation; either version 2 of the
+%%% License, or (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+%%% General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License
+%%% along with this program; if not, write to the Free Software
+%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+%%% 02111-1307 USA
+%%%
+%%%----------------------------------------------------------------------
+
+%%% IDEAS:
+%%%
+%%% * Implement those options, already present in mod_register:
+%%%   + access
+%%%   + captcha_protected
+%%%   + password_strength
+%%%   + welcome_message
+%%%   + registration_timeout
+%%%
+%%% * Improve this module to allow each virtual host to have different
+%%%   options. See http://support.process-one.net/browse/EJAB-561
+%%%
+%%% * Check that all the text is translatable.
+%%%
+%%% * Add option to use a custom CSS file, or custom CSS lines.
+%%%
+%%% * Don't hardcode the "register" path in URL.
+%%%
+%%% * Allow private email during register, and store in custom table.
+%%% * Optionally require private email to register.
+%%% * Optionally require email confirmation to register.
+%%% * Allow to set a private email address anytime.
+%%% * Allow to recover password using private email to confirm (mod_passrecover)
+%%% * Optionally require invitation
+%%% * Optionally register request is forwarded to admin, no account created.
+
+-module(mod_register_web).
+-author('badlop@process-one.net').
+
+-behaviour(gen_mod).
+
+-export([start/2,
+        stop/1,
+        process/2
+       ]).
+
+-include("ejabberd.hrl").
+-include("jlib.hrl").
+-include("ejabberd_http.hrl").
+-include("ejabberd_web_admin.hrl").
+
+%%%----------------------------------------------------------------------
+%%% gen_mod callbacks
+%%%----------------------------------------------------------------------
+
+start(_Host, _Opts) ->
+    %% case gen_mod:get_opt(docroot, Opts, undefined) of
+    ok.
+
+stop(_Host) ->
+    ok.
+
+%%%----------------------------------------------------------------------
+%%% HTTP handlers
+%%%----------------------------------------------------------------------
+
+process([], #request{method = 'GET', lang = Lang}) ->
+    index_page(Lang);
+
+process(["register.css"], #request{method = 'GET'}) ->
+    serve_css();
+
+process(["new"], #request{method = 'GET', lang = Lang, host = Host}) ->
+    form_new_get(Host, Lang);
+
+process(["delete"], #request{method = 'GET', lang = Lang, host = Host}) ->
+    form_del_get(Host, Lang);
+
+process(["change_password"], #request{method = 'GET', lang = Lang, host = Host}) ->
+    form_changepass_get(Host, Lang);
+
+process(["new"], #request{method = 'POST', q = Q, ip = {Ip,_Port}, lang = Lang, host = Host}) ->
+    case form_new_post(Q, Host) of
+       {success, ok, {Username, Host, _Password}} ->
+           Jid = jlib:make_jid(Username, Host, ""),
+           send_registration_notifications(Jid, Ip),
+           Text = ?T("Your Jabber account was succesfully created."),
+           {200, [], Text};
+       Error ->
+           ErrorText = ?T("There was an error creating the account: ") ++
+               ?T(get_error_text(Error)),
+           {404, [], ErrorText}
+    end;
+
+process(["delete"], #request{method = 'POST', q = Q, lang = Lang, host = Host}) ->
+    case form_del_post(Q, Host) of
+       {atomic, ok} ->
+           Text = ?T("Your Jabber account was succesfully deleted."),
+           {200, [], Text};
+       Error ->
+           ErrorText = ?T("There was an error deleting the account: ") ++
+               ?T(get_error_text(Error)),
+           {404, [], ErrorText}
+    end;
+
+%% TODO: Currently only the first vhost is usable. The web request record
+%% should include the host where the POST was sent.
+process(["change_password"], #request{method = 'POST', q = Q, lang = Lang, host = Host}) ->
+    case form_changepass_post(Q, Host) of
+       {atomic, ok} ->
+           Text = ?T("The password of your Jabber account was succesfully changed."),
+           {200, [], Text};
+       Error ->
+           ErrorText = ?T("There was an error changing the password: ") ++
+               ?T(get_error_text(Error)),
+           {404, [], ErrorText}
+    end.
+
+%%%----------------------------------------------------------------------
+%%% CSS
+%%%----------------------------------------------------------------------
+
+serve_css() ->
+    {200, [{"Content-Type", "text/css"},
+          last_modified(), cache_control_public()], css()}.
+
+last_modified() ->
+    {"Last-Modified", "Mon, 25 Feb 2008 13:23:30 GMT"}.
+cache_control_public() ->
+    {"Cache-Control", "public"}.
+
+css() ->
+    "html,body {
+background: white;
+margin: 0;
+padding: 0;
+height: 100%;
+}".
+
+%%%----------------------------------------------------------------------
+%%% Index page
+%%%----------------------------------------------------------------------
+
+index_page(Lang) ->
+    HeadEls = [
+              ?XCT("title", "Jabber Account Registration"),
+              ?XA("link",
+                  [{"href", "/register/register.css"},
+                   {"type", "text/css"},
+                   {"rel", "stylesheet"}])
+             ],
+    Els=[
+        ?XACT("h1",
+              [{"class", "title"}, {"style", "text-align:center;"}],
+              "Jabber Account Registration"),
+        ?XE("ul", [
+                   ?XE("li", [?ACT("new", "Register a Jabber account")]),
+                   ?XE("li", [?ACT("change_password", "Change Password")]),
+                   ?XE("li", [?ACT("delete", "Unregister a Jabber account")])
+                  ]
+           )
+       ],
+    {200,
+     [{"Server", "ejabberd"},
+      {"Content-Type", "text/html"}],
+     ejabberd_web:make_xhtml(HeadEls, Els)}.
+
+%%%----------------------------------------------------------------------
+%%% Formulary new account GET
+%%%----------------------------------------------------------------------
+
+form_new_get(Host, Lang) ->
+    CaptchaEls = build_captcha_li_list(Lang),
+    HeadEls = [
+              ?XCT("title", "Register a Jabber account"),
+              ?XA("link",
+                  [{"href", "/register/register.css"},
+                   {"type", "text/css"},
+                   {"rel", "stylesheet"}])
+             ],
+    Els=[
+        ?XACT("h1",
+              [{"class", "title"}, {"style", "text-align:center;"}],
+              "Register a Jabber account"),
+        ?XCT("p",
+             "This page allows to create a Jabber account in this Jabber server. "
+             "Your JID (Jabber IDentifier) will be of the form: username@server. "
+             "Please read carefully the instructions to fill correctly the fields."),
+        %% <!-- JID's take the form of 'username@server.com'. For example, my JID is 'kirjava@jabber.org'.
+        %% The maximum length for a JID is 255 characters. -->
+        ?XAE("form", [{"action", ""}, {"method", "post"}],
+             [
+              ?XE("ol", [
+                         ?XE("li", [
+                                    ?CT("Username:"),
+                                    ?C(" "),
+                                    ?INPUTS("text", "username", "", "20"),
+                                    ?BR,
+                                    ?XE("ul", [
+                                               ?XCT("li", "This is case insensitive: macbeth is the same that MacBeth and Macbeth."),
+                                               ?XCT("li", "Characters not allowed: @ : ' \" < > &")
+                                              ])
+                                   ]),
+                         ?XE("li", [
+                                    ?CT("Server:"),
+                                    ?C(" "),
+                                    ?C(Host)
+                                   ]),
+                         ?XE("li", [
+                                    ?CT("Password:"),
+                                    ?C(" "),
+                                    ?INPUTS("password", "password", "", "20"),
+                                    ?BR,
+                                    ?XE("ul", [
+                                               ?XCT("li", "Don't tell your password to anybody, "
+                                                   "not even the administrators of the Jabber server."),
+                                               ?XCT("li", "You can later change your password using a Jabber client."),
+                                               ?XCT("li", "Some Jabber clients can store your password in your computer. "
+                                                   "Use that feature only if you trust your computer is safe."),
+                                               ?XCT("li", "Memorize your password, or write it in a paper placed in a safe place. "
+                                                   "In Jabber there isn't an automated way to recover your password if you forget it.")
+                                              ])
+                                   ]),
+                         ?XE("li", [
+                                    ?CT("Password Verification:"),
+                                    ?C(" "),
+                                    ?INPUTS("password", "password2", "", "20")
+                                   ])] ++ CaptchaEls ++ [
+                         %% Nombre</b> (opcional)<b>:</b> <input type="text" size="20" name="name" maxlength="255"> <br /> <br /> -->
+                         %%
+                         %% Direcci&oacute;n de correo</b> (opcional)<b>:</b> <input type="text" size="20" name="email" maxlength="255"> <br /> <br /> -->
+                         ?XE("li", [
+                                    ?INPUTT("submit", "register", "Register")
+                                   ])
+                        ])
+             ])
+       ],
+    {200,
+     [{"Server", "ejabberd"},
+      {"Content-Type", "text/html"}],
+     ejabberd_web:make_xhtml(HeadEls, Els)}.
+
+%% Copied from mod_register.erl
+send_registration_notifications(UJID, Source) ->
+    Host = UJID#jid.lserver,
+    case gen_mod:get_module_opt(Host, ?MODULE, registration_watchers, []) of
+        [] -> ok;
+        JIDs when is_list(JIDs) ->
+            Body = lists:flatten(
+                     io_lib:format(
+                       "[~s] The account ~s was registered from IP address ~s "
+                       "on node ~w using ~p.",
+                       [get_time_string(), jlib:jid_to_string(UJID),
+                        ip_to_string(Source), node(), ?MODULE])),
+            lists:foreach(
+              fun(S) ->
+                      case jlib:string_to_jid(S) of
+                          error -> ok;
+                          JID ->
+                              ejabberd_router:route(
+                                jlib:make_jid("", Host, ""),
+                                JID,
+                                {xmlelement, "message", [{"type", "chat"}],
+                                 [{xmlelement, "body", [],
+                                   [{xmlcdata, Body}]}]})
+                      end
+              end, JIDs);
+        _ ->
+            ok
+    end.
+ip_to_string(Source) when is_tuple(Source) -> inet_parse:ntoa(Source);
+ip_to_string(undefined) -> "undefined";
+ip_to_string(_) -> "unknown".
+get_time_string() -> write_time(erlang:localtime()).
+%% Function copied from ejabberd_logger_h.erl and customized
+write_time({{Y,Mo,D},{H,Mi,S}}) ->
+    io_lib:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w",
+                  [Y, Mo, D, H, Mi, S]).
+
+%%%----------------------------------------------------------------------
+%%% Formulary new POST
+%%%----------------------------------------------------------------------
+
+form_new_post(Q, Host) ->
+    case catch get_register_parameters(Q) of
+       [Username, Password, Password, Id, Key] ->
+           form_new_post(Username, Host, Password, {Id, Key});
+       [_Username, _Password, _Password2, false, false] ->
+           {error, passwords_not_identical};
+       [_Username, _Password, _Password2, Id, Key] ->
+           ejabberd_captcha:check_captcha(Id, Key), %% This deletes the captcha
+           {error, passwords_not_identical};
+       _ ->
+           {error, wrong_parameters}
+    end.
+
+get_register_parameters(Q) ->
+    lists:map(
+      fun(Key) ->
+             case lists:keysearch(Key, 1, Q) of
+                 {value, {_Key, Value}} -> Value;
+                 false -> false
+             end
+      end,
+      ["username", "password", "password2", "id", "key"]).
+
+form_new_post(Username, Host, Password, {false, false}) ->
+    register_account(Username, Host, Password);
+form_new_post(Username, Host, Password, {Id, Key}) ->
+    case ejabberd_captcha:check_captcha(Id, Key) of
+       captcha_valid ->
+           register_account(Username, Host, Password);
+       captcha_non_valid ->
+           {error, captcha_non_valid};
+       captcha_not_found ->
+           {error, captcha_non_valid}
+    end.
+
+%%%----------------------------------------------------------------------
+%%% Formulary Captcha support for new GET/POST
+%%%----------------------------------------------------------------------
+
+build_captcha_li_list(Lang) ->
+    case ejabberd_captcha:is_feature_available() of
+       true -> build_captcha_li_list2(Lang);
+       false -> []
+    end.
+
+build_captcha_li_list2(Lang) ->
+    Id = randoms:get_string(),
+    SID = "",
+    From = #jid{user = "", server = "test", resource = ""},
+    To = #jid{user = "", server = "test", resource = ""},
+    Args = [],
+    ejabberd_captcha:create_captcha(Id, SID, From, To, Lang, Args),
+    {_, {CImg,CText,CId,CKey}} = ejabberd_captcha:build_captcha_html(Id, Lang),
+    [?XE("li", [CText,
+               ?C(" "),
+               CId,
+               CKey,
+               ?BR,
+               CImg]
+       )].
+
+%%%----------------------------------------------------------------------
+%%% Formulary change password GET
+%%%----------------------------------------------------------------------
+
+form_changepass_get(Host, Lang) ->
+    HeadEls = [
+              ?XCT("title", "Change Password"),
+              ?XA("link",
+                  [{"href", "/register/register.css"},
+                   {"type", "text/css"},
+                   {"rel", "stylesheet"}])
+             ],
+    Els=[
+        ?XACT("h1",
+              [{"class", "title"}, {"style", "text-align:center;"}],
+              "Change Password"),
+        ?XAE("form", [{"action", ""}, {"method", "post"}],
+             [
+              ?XE("ol", [
+                         ?XE("li", [
+                                    ?CT("Username:"),
+                                    ?C(" "),
+                                    ?INPUTS("text", "username", "", "20")
+                                   ]),
+                         ?XE("li", [
+                                    ?CT("Server:"),
+                                    ?C(" "),
+                                    ?C(Host)
+                                   ]),
+                         ?XE("li", [
+                                    ?CT("Old Password:"),
+                                    ?C(" "),
+                                    ?INPUTS("password", "passwordold", "", "20")
+                                   ]),
+                         ?XE("li", [
+                                    ?CT("New Password:"),
+                                    ?C(" "),
+                                    ?INPUTS("password", "password", "", "20")
+                                   ]),
+                         ?XE("li", [
+                                    ?CT("Password Verification:"),
+                                    ?C(" "),
+                                    ?INPUTS("password", "password2", "", "20")
+                                   ]),
+                         ?XE("li", [
+                                    ?INPUTT("submit", "changepass", "Change Password")
+                                   ])
+                        ])
+             ])
+       ],
+    {200,
+     [{"Server", "ejabberd"},
+      {"Content-Type", "text/html"}],
+     ejabberd_web:make_xhtml(HeadEls, Els)}.
+
+%%%----------------------------------------------------------------------
+%%% Formulary change password POST
+%%%----------------------------------------------------------------------
+
+form_changepass_post(Q, Host) ->
+    case catch get_changepass_parameters(Q) of
+       [Username, PasswordOld, Password, Password] ->
+           try_change_password(Username, Host, PasswordOld, Password);
+       [_Username, _PasswordOld, _Password, _Password2] ->
+           {error, passwords_not_identical};
+       _ ->
+           {error, wrong_parameters}
+    end.
+
+get_changepass_parameters(Q) ->
+    lists:map(
+      fun(Key) ->
+             {value, {_Key, Value}} = lists:keysearch(Key, 1, Q),
+             Value
+      end,
+      ["username", "passwordold", "password", "password2"]).
+
+%% @spec(Username,Host,PasswordOld,Password) -> {atomic, ok} |
+%%                                              {error, account_doesnt_exist} |
+%%                                              {error, password_not_changed} |
+%%                                              {error, password_incorrect}
+try_change_password(Username, Host, PasswordOld, Password) ->
+    try change_password(Username, Host, PasswordOld, Password) of
+       {atomic, ok} ->
+           {atomic, ok}
+    catch
+       error:{badmatch, Error} ->
+           {error, Error}
+    end.
+
+change_password(Username, Host, PasswordOld, Password) ->
+    %% Check the account exists
+    account_exists = check_account_exists(Username, Host),
+
+    %% Check the old password is correct
+    password_correct = check_password(Username, Host, PasswordOld),
+
+    %% This function always returns: ok
+    %% Change the password
+    ok = ejabberd_auth:set_password(Username, Host, Password),
+
+    %% Check the new password is correct
+    case check_password(Username, Host, Password) of
+       password_correct ->
+           {atomic, ok};
+       password_incorrect ->
+           {error, password_not_changed}
+    end.
+
+check_account_exists(Username, Host) ->
+    case ejabberd_auth:is_user_exists(Username, Host) of
+       true -> account_exists;
+       false -> account_doesnt_exist
+    end.
+
+check_password(Username, Host, Password) ->
+    case ejabberd_auth:check_password(Username, Host, Password) of
+       true -> password_correct;
+       false -> password_incorrect
+    end.
+
+%%%----------------------------------------------------------------------
+%%% Formulary delete account GET
+%%%----------------------------------------------------------------------
+
+form_del_get(Host, Lang) ->
+    HeadEls = [
+              ?XCT("title", "Unregister a Jabber account"),
+              ?XA("link",
+                  [{"href", "/register/register.css"},
+                   {"type", "text/css"},
+                   {"rel", "stylesheet"}])
+             ],
+    Els=[
+        ?XACT("h1",
+              [{"class", "title"}, {"style", "text-align:center;"}],
+              "Unregister a Jabber account"),
+        ?XCT("p",
+             "This page allows to unregister a Jabber account in this Jabber server."),
+        ?XAE("form", [{"action", ""}, {"method", "post"}],
+             [
+              ?XE("ol", [
+                         ?XE("li", [
+                                    ?CT("Username:"),
+                                    ?C(" "),
+                                    ?INPUTS("text", "username", "", "20")
+                                   ]),
+                         ?XE("li", [
+                                    ?CT("Server:"),
+                                    ?C(" "),
+                                    ?C(Host)
+                                   ]),
+                         ?XE("li", [
+                                    ?CT("Password:"),
+                                    ?C(" "),
+                                    ?INPUTS("password", "password", "", "20")
+                                   ]),
+                         ?XE("li", [
+                                    ?INPUTT("submit", "unregister", "Unregister")
+                                   ])
+                        ])
+             ])
+       ],
+    {200,
+     [{"Server", "ejabberd"},
+      {"Content-Type", "text/html"}],
+     ejabberd_web:make_xhtml(HeadEls, Els)}.
+
+%% @spec(Username, Host, Password) -> {success, ok, {Username, Host, Password} |
+%%                                    {success, exists, {Username, Host, Password}} |
+%%                                    {error, not_allowed} |
+%%                                    {error, invalid_jid}
+register_account(Username, Host, Password) ->
+    case ejabberd_auth:try_register(Username, Host, Password) of
+       {atomic, Res} ->
+           {success, Res, {Username, Host, Password}};
+       Other ->
+           Other
+    end.
+
+%%%----------------------------------------------------------------------
+%%% Formulary delete POST
+%%%----------------------------------------------------------------------
+
+form_del_post(Q, Host) ->
+    case catch get_unregister_parameters(Q) of
+       [Username, Password] ->
+           try_unregister_account(Username, Host, Password);
+       _ ->
+           {error, wrong_parameters}
+    end.
+
+get_unregister_parameters(Q) ->
+    lists:map(
+      fun(Key) ->
+             {value, {_Key, Value}} = lists:keysearch(Key, 1, Q),
+             Value
+      end,
+      ["username", "password"]).
+
+%% @spec(Username, Host, Password) -> {atomic, ok} |
+%%                                    {error, account_doesnt_exist} |
+%%                                    {error, account_exists} |
+%%                                    {error, password_incorrect}
+try_unregister_account(Username, Host, Password) ->
+    try unregister_account(Username, Host, Password) of
+       {atomic, ok} ->
+           {atomic, ok}
+    catch
+       error:{badmatch, Error} ->
+           {error, Error}
+    end.
+
+unregister_account(Username, Host, Password) ->
+    %% Check the account exists
+    account_exists = check_account_exists(Username, Host),
+
+    %% Check the password is correct
+    password_correct = check_password(Username, Host, Password),
+
+    %% This function always returns: ok
+    ok = ejabberd_auth:remove_user(Username, Host, Password),
+
+    %% Check the account does not exist anymore
+    account_doesnt_exist = check_account_exists(Username, Host),
+
+    %% If we reached this point, return success
+    {atomic, ok}.
+
+%%%----------------------------------------------------------------------
+%%% Error texts
+%%%----------------------------------------------------------------------
+
+get_error_text({error, captcha_non_valid}) ->
+    "The captcha you entered is wrong";
+get_error_text({atomic, exists}) ->
+    "The account already exists";
+get_error_text({error, password_incorrect}) ->
+    "Incorrect password";
+get_error_text({error, invalid_jid}) ->
+    "The username is not valid";
+get_error_text({error, not_allowed}) ->
+    "Not allowed";
+get_error_text({error, account_doesnt_exist}) ->
+    "Account doesn't exist";
+get_error_text({error, account_exists}) ->
+    "The account was not deleted";
+get_error_text({error, password_not_changed}) ->
+    "The password was not changed";
+get_error_text({error, passwords_not_identical}) ->
+    "The passwords are different";
+get_error_text({error, wrong_parameters}) ->
+    "Wrong parameters in the web formulary".