Comparison

plugins/mod_register.lua @ 7036:f26debcae34e

Merge 0.10->trunk
author Kim Alvefur <zash@zash.se>
date Sun, 27 Dec 2015 12:29:28 +0100
parent 7027:77d838ba91c6
child 7037:5d52e4ee2ae1
comparison
equal deleted inserted replaced
7015:17e275e8bd79 7036:f26debcae34e
11 local dataform_new = require "util.dataforms".new; 11 local dataform_new = require "util.dataforms".new;
12 local usermanager_user_exists = require "core.usermanager".user_exists; 12 local usermanager_user_exists = require "core.usermanager".user_exists;
13 local usermanager_create_user = require "core.usermanager".create_user; 13 local usermanager_create_user = require "core.usermanager".create_user;
14 local usermanager_set_password = require "core.usermanager".set_password; 14 local usermanager_set_password = require "core.usermanager".set_password;
15 local usermanager_delete_user = require "core.usermanager".delete_user; 15 local usermanager_delete_user = require "core.usermanager".delete_user;
16 local os_time = os.time;
17 local nodeprep = require "util.encodings".stringprep.nodeprep; 16 local nodeprep = require "util.encodings".stringprep.nodeprep;
18 local jid_bare = require "util.jid".bare; 17 local jid_bare = require "util.jid".bare;
18 local create_throttle = require "util.throttle".create;
19 local new_cache = require "util.cache".new;
19 20
20 local compat = module:get_option_boolean("registration_compat", true); 21 local compat = module:get_option_boolean("registration_compat", true);
21 local allow_registration = module:get_option_boolean("allow_registration", false); 22 local allow_registration = module:get_option_boolean("allow_registration", false);
22 local additional_fields = module:get_option("additional_registration_fields", {}); 23 local additional_fields = module:get_option("additional_registration_fields", {});
23 24
82 features:add_child(register_stream_feature); 83 features:add_child(register_stream_feature);
83 end); 84 end);
84 85
85 local function handle_registration_stanza(event) 86 local function handle_registration_stanza(event)
86 local session, stanza = event.origin, event.stanza; 87 local session, stanza = event.origin, event.stanza;
88 local log = session.log or module._log;
87 89
88 local query = stanza.tags[1]; 90 local query = stanza.tags[1];
89 if stanza.attr.type == "get" then 91 if stanza.attr.type == "get" then
90 local reply = st.reply(stanza); 92 local reply = st.reply(stanza);
91 reply:tag("query", {xmlns = "jabber:iq:register"}) 93 reply:tag("query", {xmlns = "jabber:iq:register"})
95 session.send(reply); 97 session.send(reply);
96 else -- stanza.attr.type == "set" 98 else -- stanza.attr.type == "set"
97 if query.tags[1] and query.tags[1].name == "remove" then 99 if query.tags[1] and query.tags[1].name == "remove" then
98 local username, host = session.username, session.host; 100 local username, host = session.username, session.host;
99 101
102 -- This one weird trick sends a reply to this stanza before the user is deleted
100 local old_session_close = session.close; 103 local old_session_close = session.close;
101 session.close = function(session, ...) 104 session.close = function(session, ...)
102 session.send(st.reply(stanza)); 105 session.send(st.reply(stanza));
103 return old_session_close(session, ...); 106 return old_session_close(session, ...);
104 end 107 end
105 108
106 local ok, err = usermanager_delete_user(username, host); 109 local ok, err = usermanager_delete_user(username, host);
107 110
108 if not ok then 111 if not ok then
109 module:log("debug", "Removing user account %s@%s failed: %s", username, host, err); 112 log("debug", "Removing user account %s@%s failed: %s", username, host, err);
110 session.close = old_session_close; 113 session.close = old_session_close;
111 session.send(st.error_reply(stanza, "cancel", "service-unavailable", err)); 114 session.send(st.error_reply(stanza, "cancel", "service-unavailable", err));
112 return true; 115 return true;
113 end 116 end
114 117
115 module:log("info", "User removed their account: %s@%s", username, host); 118 log("info", "User removed their account: %s@%s", username, host);
116 module:fire_event("user-deregistered", { username = username, host = host, source = "mod_register", session = session }); 119 module:fire_event("user-deregistered", { username = username, host = host, source = "mod_register", session = session });
117 else 120 else
118 local username = nodeprep(query:get_child_text("username")); 121 local username = nodeprep(query:get_child_text("username"));
119 local password = query:get_child_text("password"); 122 local password = query:get_child_text("password");
120 if username and password then 123 if username and password then
167 end 170 end
168 return data; 171 return data;
169 end 172 end
170 end 173 end
171 174
172 local recent_ips = {};
173 local min_seconds_between_registrations = module:get_option_number("min_seconds_between_registrations"); 175 local min_seconds_between_registrations = module:get_option_number("min_seconds_between_registrations");
174 local whitelist_only = module:get_option_boolean("whitelist_registration_only"); 176 local whitelist_only = module:get_option_boolean("whitelist_registration_only");
175 local whitelisted_ips = module:get_option_set("registration_whitelist", { "127.0.0.1" })._items; 177 local whitelisted_ips = module:get_option_set("registration_whitelist", { "127.0.0.1" })._items;
176 local blacklisted_ips = module:get_option_set("registration_blacklist", {})._items; 178 local blacklisted_ips = module:get_option_set("registration_blacklist", {})._items;
177 179
180 local throttle_max = module:get_option_number("registration_throttle_max", min_seconds_between_registrations and 1);
181 local throttle_period = module:get_option_number("registration_throttle_period", min_seconds_between_registrations);
182 local throttle_cache_size = module:get_option_number("registration_throttle_cache_size", 100);
183 local blacklist_overflow = module_get_option_boolean("blacklist_on_registration_throttle_overload", false);
184
185 local throttle_cache = new_cache(throttle_cache_size, blacklist_overflow and function (ip, throttle)
186 if not throttle:peek() then
187 module:log("info", "Adding ip %s to registration blacklist", ip);
188 blacklisted_ips[ip] = true;
189 end
190 end);
191
192 local function check_throttle(ip)
193 if not throttle_max then return true end
194 local throttle = throttle_cache:get(ip);
195 if not throttle then
196 throttle = create_throttle(throttle_max, throttle_period);
197 end
198 throttle_cache:set(ip, throttle);
199 return throttle:poll(1);
200 end
201
178 module:hook("stanza/iq/jabber:iq:register:query", function(event) 202 module:hook("stanza/iq/jabber:iq:register:query", function(event)
179 local session, stanza = event.origin, event.stanza; 203 local session, stanza = event.origin, event.stanza;
204 local log = session.log or module._log;
180 205
181 if not(allow_registration) or session.type ~= "c2s_unauthed" then 206 if not(allow_registration) or session.type ~= "c2s_unauthed" then
182 session.send(st.error_reply(stanza, "cancel", "service-unavailable")); 207 session.send(st.error_reply(stanza, "cancel", "service-unavailable"));
183 else 208 else
184 local query = stanza.tags[1]; 209 local query = stanza.tags[1];
194 if errors then 219 if errors then
195 session.send(st.error_reply(stanza, "modify", "not-acceptable")); 220 session.send(st.error_reply(stanza, "modify", "not-acceptable"));
196 else 221 else
197 -- Check that the user is not blacklisted or registering too often 222 -- Check that the user is not blacklisted or registering too often
198 if not session.ip then 223 if not session.ip then
199 module:log("debug", "User's IP not known; can't apply blacklist/whitelist"); 224 log("debug", "User's IP not known; can't apply blacklist/whitelist");
200 elseif blacklisted_ips[session.ip] or (whitelist_only and not whitelisted_ips[session.ip]) then 225 elseif blacklisted_ips[session.ip] or (whitelist_only and not whitelisted_ips[session.ip]) then
201 session.send(st.error_reply(stanza, "cancel", "not-acceptable", "You are not allowed to register an account.")); 226 session.send(st.error_reply(stanza, "cancel", "not-acceptable", "You are not allowed to register an account."));
202 return true; 227 return true;
203 elseif min_seconds_between_registrations and not whitelisted_ips[session.ip] then 228 elseif min_seconds_between_registrations and not whitelisted_ips[session.ip] then
204 if not recent_ips[session.ip] then 229 if check_throttle(session.ip) then
205 recent_ips[session.ip] = { time = os_time(), count = 1 }; 230 session.send(st.error_reply(stanza, "wait", "not-acceptable"));
206 else 231 return true;
207 local ip = recent_ips[session.ip];
208 ip.count = ip.count + 1;
209
210 if os_time() - ip.time < min_seconds_between_registrations then
211 ip.time = os_time();
212 session.send(st.error_reply(stanza, "wait", "not-acceptable"));
213 return true;
214 end
215 ip.time = os_time();
216 end 232 end
217 end 233 end
218 local username, password = nodeprep(data.username), data.password; 234 local username, password = nodeprep(data.username), data.password;
219 data.username, data.password = nil, nil; 235 data.username, data.password = nil, nil;
220 local host = module.host; 236 local host = module.host;
236 usermanager_delete_user(username, host); 252 usermanager_delete_user(username, host);
237 session.send(error_reply); 253 session.send(error_reply);
238 return true; 254 return true;
239 end 255 end
240 session.send(st.reply(stanza)); -- user created! 256 session.send(st.reply(stanza)); -- user created!
241 module:log("info", "User account created: %s@%s", username, host); 257 log("info", "User account created: %s@%s", username, host);
242 module:fire_event("user-registered", { 258 module:fire_event("user-registered", {
243 username = username, host = host, source = "mod_register", 259 username = username, host = host, source = "mod_register",
244 session = session }); 260 session = session });
245 else 261 else
246 session.send(error_reply); 262 session.send(error_reply);