mod_firewall: Add experimental user-centric persistent marks behind a feature flag
--- 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 = {} };