diff mod_audit/mod_audit.lua @ 4938:bc8832c6696b

upstream merge
author Goffi <goffi@goffi.org>
date Wed, 11 May 2022 12:44:32 +0200
parents ae83200fb55f
children 4a5837591380
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_audit/mod_audit.lua	Wed May 11 12:44:32 2022 +0200
@@ -0,0 +1,85 @@
+module:set_global();
+
+local time_now = os.time;
+local st = require "util.stanza";
+local moduleapi = require "core.moduleapi";
+
+local host_wide_user = "@";
+
+local stores = {};
+
+local function get_store(self, host)
+	local store = rawget(self, host);
+	if store then
+		return store
+	end
+	store = module:context(host):open_store("audit", "archive");
+	rawset(self, host, store);
+	return store;
+end
+
+setmetatable(stores, { __index = get_store });
+
+
+local function session_extra(session)
+	local attr = {
+		xmlns = "xmpp:prosody.im/audit",
+	};
+	if session.id then
+		attr.id = session.id;
+	end
+	if session.type then
+		attr.type = session.type;
+	end
+	local stanza = st.stanza("session", attr);
+	if session.ip then
+		stanza:text_tag("remote-ip", session.ip);
+	end
+	return stanza
+end
+
+local function audit(host, user, source, event_type, extra)
+	if not host or host == "*" then
+		error("cannot log audit events for global");
+	end
+	local user_key = user or host_wide_user;
+
+	local attr = {
+		["source"] = source,
+		["type"] = event_type,
+	};
+	if user_key ~= host_wide_user then
+		attr.user = user_key;
+	end
+	local stanza = st.stanza("audit-event", attr);
+	if extra ~= nil then
+		if extra.session then
+			local child = session_extra(extra.session);
+			if child then
+				stanza:add_child(child);
+			end
+		end
+		if extra.custom then
+			for _, child in extra.custom do
+				if not st.is_stanza(child) then
+					error("all extra.custom items must be stanzas")
+				end
+				stanza:add_child(child);
+			end
+		end
+	end
+
+	local id, err = stores[host]:append(nil, nil, stanza, time_now(), user_key);
+	if err then
+		module:log("error", "failed to persist audit event: %s", err);
+		return
+	else
+		module:log("debug", "persisted audit event %s as %s", stanza:top_tag(), id);
+	end
+end
+
+function moduleapi.audit(module, user, event_type, extra)
+	audit(module.host, user, "mod_" .. module:get_name(), event_type, extra);
+end
+
+module:hook("audit", audit, 0);