Mercurial > prosody-modules
diff mod_invites_register_web/mod_invites_register_web.lua @ 4093:a2116f5a7c8f
mod_invites_register_web: New module to allow web registration with an invite token
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Fri, 11 Sep 2020 13:51:54 +0100 |
parents | |
children | f49e3ea99785 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_invites_register_web/mod_invites_register_web.lua Fri Sep 11 13:51:54 2020 +0100 @@ -0,0 +1,183 @@ +local id = require "util.id"; +local http_formdecode = require "net.http".formdecode; +local usermanager = require "core.usermanager"; +local nodeprep = require "util.encodings".stringprep.nodeprep; +local st = require "util.stanza"; +local url_escape = require "util.http".urlencode; +local render_html_template = require"util.interpolation".new("%b{}", st.xml_escape, { + urlescape = url_escape; +}); + + +module:depends("register_apps"); + +local site_name = module:get_option_string("site_name", module.host); +local site_apps = module:shared("register_apps/apps"); + +module:depends("http"); +module:depends("easy_invite"); +local invites = module:depends("invites"); +local invites_page = module:depends("invites_page"); + +function serve_register_page(event) + local register_page_template = assert(module:load_resource("html/register.html")):read("*a"); + + local query_params = http_formdecode(event.request.url.query); + + local invite = invites.get(query_params.t); + if not invite then + return { + status_code = 303; + headers = { + ["Location"] = invites.module:http_url().."?"..event.request.url.query; + }; + }; + end + + local invite_page = render_html_template(register_page_template, { + site_name = site_name; + token = invite.token; + domain = module.host; + uri = invite.uri; + type = invite.type; + jid = invite.jid; + inviter = invite.inviter; + app = query_params.c and site_apps[query_params.c]; + }); + return invite_page; +end + +function handle_register_form(event) + local request, response = event.request, event.response; + local form_data = http_formdecode(request.body); + local user, password, token = form_data["user"], form_data["password"], form_data["token"]; + local app_id = form_data["app_id"]; + + local register_page_template = assert(module:load_resource("html/register.html")):read("*a"); + local error_template = assert(module:load_resource("html/register_error.html")):read("*a"); + + local invite = invites.get(token); + if not invite then + return { + status_code = 303; + headers = { + ["Location"] = invites_page.module:http_url().."?"..event.request.url.query; + }; + }; + end + + response.headers.content_type = "text/html; charset=utf-8"; + + if not user or #user == 0 or not password or #password == 0 or not token then + return render_html_template(register_page_template, { + site_name = site_name; + token = invite.token; + domain = module.host; + uri = invite.uri; + type = invite.type; + jid = invite.jid; + + msg_class = "alert-warning"; + message = "Please fill in all fields."; + }); + end + + -- Shamelessly copied from mod_register_web. + local prepped_username = nodeprep(user); + + if not prepped_username or #prepped_username == 0 then + return render_html_template(register_page_template, { + site_name = site_name; + token = invite.token; + domain = module.host; + uri = invite.uri; + type = invite.type; + jid = invite.jid; + + msg_class = "alert-warning"; + message = "This username contains invalid characters."; + }); + end + + if usermanager.user_exists(prepped_username, module.host) then + return render_html_template(register_page_template, { + site_name = site_name; + token = invite.token; + domain = module.host; + uri = invite.uri; + type = invite.type; + jid = invite.jid; + + msg_class = "alert-warning"; + message = "This username is already in use."; + }); + end + + local registering = { + validated_invite = invite; + username = prepped_username; + host = module.host; + allowed = true; + }; + + module:fire_event("user-registering", registering); + + if not registering.allowed then + return render_html_template(error_template, { + site_name = site_name; + msg_class = "alert-danger"; + message = registering.reason or "Registration is not allowed."; + }); + end + + local ok, err = usermanager.create_user(prepped_username, password, module.host); + + if ok then + module:fire_event("user-registered", { + username = prepped_username; + host = module.host; + source = "mod_"..module.name; + validated_invite = invite; + }); + + local app_info = site_apps[app_id]; + + local success_template; + if app_info then + -- If recognised app, we serve a page that includes setup instructions + success_template = assert(module:load_resource("html/register_success_setup.html")):read("*a"); + else + success_template = assert(module:load_resource("html/register_success.html")):read("*a"); + end + + -- Due to the credentials being served here, ensure that + -- the browser or any intermediary does not cache the page + event.response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"; + event.response.headers["Pragma"] = "no-cache"; + event.response.headers["Expires"] = "0"; + + return render_html_template(success_template, { + site_name = site_name; + username = prepped_username; + domain = module.host; + password = password; + app = app_info; + }); + else + local err_id = id.short(); + module:log("warn", "Registration failed (%s): %s", err_id, tostring(err)); + return render_html_template(error_template, { + site_name = site_name; + msg_class = "alert-danger"; + message = ("An unknown error has occurred (%s)"):format(err_id); + }); + end +end + +module:provides("http", { + default_path = "register"; + route = { + ["GET"] = serve_register_page; + ["POST"] = handle_register_form; + }; +});