Mercurial > prosody-modules
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 4092:2b6918714792 | 4093:a2116f5a7c8f |
|---|---|
| 1 local id = require "util.id"; | |
| 2 local http_formdecode = require "net.http".formdecode; | |
| 3 local usermanager = require "core.usermanager"; | |
| 4 local nodeprep = require "util.encodings".stringprep.nodeprep; | |
| 5 local st = require "util.stanza"; | |
| 6 local url_escape = require "util.http".urlencode; | |
| 7 local render_html_template = require"util.interpolation".new("%b{}", st.xml_escape, { | |
| 8 urlescape = url_escape; | |
| 9 }); | |
| 10 | |
| 11 | |
| 12 module:depends("register_apps"); | |
| 13 | |
| 14 local site_name = module:get_option_string("site_name", module.host); | |
| 15 local site_apps = module:shared("register_apps/apps"); | |
| 16 | |
| 17 module:depends("http"); | |
| 18 module:depends("easy_invite"); | |
| 19 local invites = module:depends("invites"); | |
| 20 local invites_page = module:depends("invites_page"); | |
| 21 | |
| 22 function serve_register_page(event) | |
| 23 local register_page_template = assert(module:load_resource("html/register.html")):read("*a"); | |
| 24 | |
| 25 local query_params = http_formdecode(event.request.url.query); | |
| 26 | |
| 27 local invite = invites.get(query_params.t); | |
| 28 if not invite then | |
| 29 return { | |
| 30 status_code = 303; | |
| 31 headers = { | |
| 32 ["Location"] = invites.module:http_url().."?"..event.request.url.query; | |
| 33 }; | |
| 34 }; | |
| 35 end | |
| 36 | |
| 37 local invite_page = render_html_template(register_page_template, { | |
| 38 site_name = site_name; | |
| 39 token = invite.token; | |
| 40 domain = module.host; | |
| 41 uri = invite.uri; | |
| 42 type = invite.type; | |
| 43 jid = invite.jid; | |
| 44 inviter = invite.inviter; | |
| 45 app = query_params.c and site_apps[query_params.c]; | |
| 46 }); | |
| 47 return invite_page; | |
| 48 end | |
| 49 | |
| 50 function handle_register_form(event) | |
| 51 local request, response = event.request, event.response; | |
| 52 local form_data = http_formdecode(request.body); | |
| 53 local user, password, token = form_data["user"], form_data["password"], form_data["token"]; | |
| 54 local app_id = form_data["app_id"]; | |
| 55 | |
| 56 local register_page_template = assert(module:load_resource("html/register.html")):read("*a"); | |
| 57 local error_template = assert(module:load_resource("html/register_error.html")):read("*a"); | |
| 58 | |
| 59 local invite = invites.get(token); | |
| 60 if not invite then | |
| 61 return { | |
| 62 status_code = 303; | |
| 63 headers = { | |
| 64 ["Location"] = invites_page.module:http_url().."?"..event.request.url.query; | |
| 65 }; | |
| 66 }; | |
| 67 end | |
| 68 | |
| 69 response.headers.content_type = "text/html; charset=utf-8"; | |
| 70 | |
| 71 if not user or #user == 0 or not password or #password == 0 or not token then | |
| 72 return render_html_template(register_page_template, { | |
| 73 site_name = site_name; | |
| 74 token = invite.token; | |
| 75 domain = module.host; | |
| 76 uri = invite.uri; | |
| 77 type = invite.type; | |
| 78 jid = invite.jid; | |
| 79 | |
| 80 msg_class = "alert-warning"; | |
| 81 message = "Please fill in all fields."; | |
| 82 }); | |
| 83 end | |
| 84 | |
| 85 -- Shamelessly copied from mod_register_web. | |
| 86 local prepped_username = nodeprep(user); | |
| 87 | |
| 88 if not prepped_username or #prepped_username == 0 then | |
| 89 return render_html_template(register_page_template, { | |
| 90 site_name = site_name; | |
| 91 token = invite.token; | |
| 92 domain = module.host; | |
| 93 uri = invite.uri; | |
| 94 type = invite.type; | |
| 95 jid = invite.jid; | |
| 96 | |
| 97 msg_class = "alert-warning"; | |
| 98 message = "This username contains invalid characters."; | |
| 99 }); | |
| 100 end | |
| 101 | |
| 102 if usermanager.user_exists(prepped_username, module.host) then | |
| 103 return render_html_template(register_page_template, { | |
| 104 site_name = site_name; | |
| 105 token = invite.token; | |
| 106 domain = module.host; | |
| 107 uri = invite.uri; | |
| 108 type = invite.type; | |
| 109 jid = invite.jid; | |
| 110 | |
| 111 msg_class = "alert-warning"; | |
| 112 message = "This username is already in use."; | |
| 113 }); | |
| 114 end | |
| 115 | |
| 116 local registering = { | |
| 117 validated_invite = invite; | |
| 118 username = prepped_username; | |
| 119 host = module.host; | |
| 120 allowed = true; | |
| 121 }; | |
| 122 | |
| 123 module:fire_event("user-registering", registering); | |
| 124 | |
| 125 if not registering.allowed then | |
| 126 return render_html_template(error_template, { | |
| 127 site_name = site_name; | |
| 128 msg_class = "alert-danger"; | |
| 129 message = registering.reason or "Registration is not allowed."; | |
| 130 }); | |
| 131 end | |
| 132 | |
| 133 local ok, err = usermanager.create_user(prepped_username, password, module.host); | |
| 134 | |
| 135 if ok then | |
| 136 module:fire_event("user-registered", { | |
| 137 username = prepped_username; | |
| 138 host = module.host; | |
| 139 source = "mod_"..module.name; | |
| 140 validated_invite = invite; | |
| 141 }); | |
| 142 | |
| 143 local app_info = site_apps[app_id]; | |
| 144 | |
| 145 local success_template; | |
| 146 if app_info then | |
| 147 -- If recognised app, we serve a page that includes setup instructions | |
| 148 success_template = assert(module:load_resource("html/register_success_setup.html")):read("*a"); | |
| 149 else | |
| 150 success_template = assert(module:load_resource("html/register_success.html")):read("*a"); | |
| 151 end | |
| 152 | |
| 153 -- Due to the credentials being served here, ensure that | |
| 154 -- the browser or any intermediary does not cache the page | |
| 155 event.response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"; | |
| 156 event.response.headers["Pragma"] = "no-cache"; | |
| 157 event.response.headers["Expires"] = "0"; | |
| 158 | |
| 159 return render_html_template(success_template, { | |
| 160 site_name = site_name; | |
| 161 username = prepped_username; | |
| 162 domain = module.host; | |
| 163 password = password; | |
| 164 app = app_info; | |
| 165 }); | |
| 166 else | |
| 167 local err_id = id.short(); | |
| 168 module:log("warn", "Registration failed (%s): %s", err_id, tostring(err)); | |
| 169 return render_html_template(error_template, { | |
| 170 site_name = site_name; | |
| 171 msg_class = "alert-danger"; | |
| 172 message = ("An unknown error has occurred (%s)"):format(err_id); | |
| 173 }); | |
| 174 end | |
| 175 end | |
| 176 | |
| 177 module:provides("http", { | |
| 178 default_path = "register"; | |
| 179 route = { | |
| 180 ["GET"] = serve_register_page; | |
| 181 ["POST"] = handle_register_form; | |
| 182 }; | |
| 183 }); |
