Changeset

2894:165d2877eeac

mod_firewall: Add experimental user-centric persistent marks behind a feature flag
author Kim Alvefur <zash@zash.se>
date Sat, 24 Feb 2018 21:40:56 +0100
parents 2893:d958558e0058
children 2895:589cc51209f7
files mod_firewall/actions.lib.lua mod_firewall/conditions.lib.lua mod_firewall/marks.lib.lua mod_firewall/mod_firewall.lua
diffstat 4 files changed, 49 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/mod_firewall/actions.lib.lua	Sat Feb 24 19:38:10 2018 +0100
+++ b/mod_firewall/actions.lib.lua	Sat Feb 24 21:40:56 2018 +0100
@@ -213,6 +213,14 @@
 	return [[session.firewall_marked_]]..idsafe(name)..[[ = nil;]]
 end
 
+function action_handlers.MARK_USER(name)
+	return [[if session.firewall_marks then session.firewall_marks.]]..idsafe(name)..[[ = current_timestamp; end]], { "timestamp" };
+end
+
+function action_handlers.UNMARK_USER(name)
+	return [[if session.firewall_marks then session.firewall_marks.]]..idsafe(name)..[[ = nil; end]], { "timestamp" };
+end
+
 function action_handlers.ADD_TO(spec)
 	local list_name, value = spec:match("(%S+) (.+)");
 	local meta_deps = {};
--- a/mod_firewall/conditions.lib.lua	Sat Feb 24 19:38:10 2018 +0100
+++ b/mod_firewall/conditions.lib.lua	Sat Feb 24 21:40:56 2018 +0100
@@ -276,6 +276,20 @@
 	return ("not not session.firewall_marked_"..idsafe(name));
 end
 
+function condition_handlers.USER_MARKED(name_and_time)
+	local name, time = name_and_time:match("^%s*([%w_]+)%s+%(([^)]+)s%)%s*$");
+	if not name then
+		name = name_and_time:match("^%s*([%w_]+)%s*$");
+	end
+	if not name then
+		error("Error parsing mark name, see documentation for usage examples");
+	end
+	if time then
+		return ("(current_timestamp - (session.firewall_marks and session.firewall_marks.%s or 0)) < %d"):format(idsafe(name), tonumber(time)), { "timestamp" };
+	end
+	return ("not not (session.firewall_marks and session.firewall_marks."..idsafe(name)..")");
+end
+
 function condition_handlers.SENT_DIRECTED_PRESENCE_TO_SENDER()
 	return "not not (session.directed and session.directed[from])", { "from" };
 end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_firewall/marks.lib.lua	Sat Feb 24 21:40:56 2018 +0100
@@ -0,0 +1,23 @@
+local mark_storage = module:open_store("firewall_marks");
+
+local user_sessions = prosody.hosts[module.host].sessions;
+
+module:hook("resource-bind", function (event)
+	local session = event.session;
+	local username = session.username;
+	local user = user_sessions[username];
+	local marks = user.firewall_marks;
+	if not marks then
+		marks = mark_storage:get(username) or {};
+		user.firewall_marks = marks; -- luacheck: ignore 122
+	end
+	session.firewall_marks = marks;
+end);
+
+module:hook("resource-unbind", function (event)
+	local session = event.session;
+	local username = session.username;
+	local marks = session.firewall_marks;
+	mark_storage:set(username, marks);
+end);
+
--- a/mod_firewall/mod_firewall.lua	Sat Feb 24 19:38:10 2018 +0100
+++ b/mod_firewall/mod_firewall.lua	Sat Feb 24 21:40:56 2018 +0100
@@ -303,6 +303,10 @@
 local condition_handlers = module:require("conditions");
 local action_handlers = module:require("actions");
 
+if module:get_option_boolean("firewall_experimental_user_marks", false) then
+	module:require"marks";
+end
+
 local function new_rule(ruleset, chain)
 	assert(chain, "no chain specified");
 	local rule = { conditions = {}, actions = {}, deps = {} };