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 });