diff mod_block_registrations/mod_block_registrations.lua @ 6322:f110bce35630

mod_block_registrations: Support blocking confusable usernames (UTS 39) This prevents registering e.g. "admin" but with a Cyrillic 'a' U+0430 and other such variations, including keming like "adrnin".
author Kim Alvefur <zash@zash.se>
date Sat, 06 Sep 2025 21:02:26 +0200
parents 2f01497b04c9
children a1df76ba4f68
line wrap: on
line diff
--- a/mod_block_registrations/mod_block_registrations.lua	Sat Sep 06 19:25:15 2025 +0200
+++ b/mod_block_registrations/mod_block_registrations.lua	Sat Sep 06 21:02:26 2025 +0200
@@ -1,12 +1,29 @@
-local st = require "util.stanza";
 local nodeprep = require "util.encodings".stringprep.nodeprep;
 
+local normal = nodeprep;
+if module:get_option_boolean("block_registrations_confusable", true) then
+	local confusable = require "util.encodings".confusable;
+	if not confusable then
+		module:log("error", "Prosody not built with ICU, confusables mapping is unavailable.");
+		module:log("error", "Rebuild or disable this feature with 'block_registrations_confusable = false'");
+	end
+	function normal(username)
+		if username then
+			username = nodeprep(username);
+		end
+		if username then
+			username = confusable.skeleton(username);
+		end
+		return username;
+	end
+end
+
 local block_users = module:get_option_set("block_registrations_users", {
 	"abuse", "admin", "administrator", "hostmaster", "info", "news",
 	"noc", "operator", "owner", "postmaster", "register", "registration",
 	"root", "security", "service", "signup", "support", "sysadmin",
 	"sysop", "system", "test", "trouble", "webmaster", "www", "xmpp",
-});
+}) / normal;
 local block_patterns = module:get_option_set("block_registrations_matching", {});
 local require_pattern = module:get_option_string("block_registrations_require");
 
@@ -14,6 +31,9 @@
 	-- Check if the username is simply blocked
 	if block_users:contains(username) then return true; end
 
+	local normalized_username = normal(username);
+	if block_users:contains(normalized_username) then return true; end
+
 	for pattern in block_patterns do
 		if username:find(pattern) then
 			return true;