changeset 2342:6848297cf40a

mod_firewall: Add conditions for testing whether a sender of a stanza is in the recipient's roster (or in a certain roster group)
author Matthew Wild <mwild1@gmail.com>
date Fri, 04 Nov 2016 12:46:11 +0000
parents 52dd2a51dac8
children f4ab0966ba89
files mod_firewall/README.markdown mod_firewall/conditions.lib.lua mod_firewall/mod_firewall.lua
diffstat 3 files changed, 41 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/mod_firewall/README.markdown	Wed Nov 02 20:42:27 2016 +0100
+++ b/mod_firewall/README.markdown	Fri Nov 04 12:46:11 2016 +0000
@@ -204,6 +204,27 @@
 stanza. It is not advisable to perform access control or similar rules
 on JIDs in these chains (see the chain documentation for more info).
 
+### Roster
+
+These functions access the roster of the recipient (only). Therefore they cannot (currently)
+be used in some chains, such as for outgoing messages (the recipient may be on another server).
+
+Performance note: this check can potentially cause storage access (especially if the recipient
+is currently offline), so you may want to limit its use in high-traffic situations, and place
+it below other checks (such as a rate limiter).
+
+#### IN_ROSTER
+
+Tests whether the sender is in the recipient's roster.
+
+    IN_ROSTER: yes
+
+#### IN_ROSTER_GROUP
+
+Tests whether the sender is in the recipient's roster, and in the named group.
+
+    IN_ROSTER_GROUP: Friends
+
 ### Time and date
 
 #### TIME
--- a/mod_firewall/conditions.lib.lua	Wed Nov 02 20:42:27 2016 +0100
+++ b/mod_firewall/conditions.lib.lua	Fri Nov 04 12:46:11 2016 +0000
@@ -3,6 +3,12 @@
 
 local jid = require "util.jid";
 
+-- Helper to convert user-input strings (yes/true//no/false) to a bool
+local function string_to_boolean(s)
+	s = s:lower();
+	return s == "yes" or s == "true";
+end
+
 -- Return a code string for a condition that checks whether the contents
 -- of variable with the name 'name' matches any of the values in the
 -- comma/space/pipe delimited list 'values'.
@@ -90,6 +96,15 @@
 	return zone_check(zone, "from");
 end
 
+function condition_handlers.IN_ROSTER(yes_no)
+	local in_roster_requirement = string_to_boolean(yes_no);
+	return "not "..(in_roster_requirement and "not" or "").." roster_entry", { "roster_entry" };
+end
+
+function condition_handlers.IN_ROSTER_GROUP(group)
+	return ("not not (roster_entry and roster_entry.groups[%q])"):format(group), { "roster_entry" };
+end
+
 function condition_handlers.PAYLOAD(payload_ns)
 	return ("stanza:get_child(nil, %q)"):format(payload_ns);
 end
--- a/mod_firewall/mod_firewall.lua	Wed Nov 02 20:42:27 2016 +0100
+++ b/mod_firewall/mod_firewall.lua	Fri Nov 04 12:46:11 2016 +0000
@@ -123,6 +123,11 @@
 			return ("local multi_throttle_%s = rates.%s:multi();"):format(throttle, throttle);
 		end;
 	};
+	roster_entry = {
+		global_code = [[local rostermanager = require "core.rostermanager";]];
+		local_code = [[local roster_entry = (rostermanager.load_roster(to_node, to_host) or {})[bare_from];]];
+		depends = { "split_to", "bare_from" };
+	}
 };
 
 local function include_dep(dependency, code)