Comparison

mod_audit/mod_audit.lua @ 5856:75dee6127829 draft

Merge upstream
author Trần H. Trung <xmpp:trần.h.trung@trung.fun>
date Tue, 06 Feb 2024 18:32:01 +0700
parent 5786:6c0570a8b866
comparison
equal deleted inserted replaced
5664:52db2da66680 5856:75dee6127829
1 module:set_global(); 1 module:set_global();
2 2
3 local time_now = os.time; 3 local time_now = os.time;
4 local parse_duration = require "util.human.io".parse_duration;
5 local ip = require "util.ip"; 4 local ip = require "util.ip";
6 local st = require "util.stanza"; 5 local st = require "util.stanza";
7 local moduleapi = require "core.moduleapi"; 6 local moduleapi = require "core.moduleapi";
8 7
9 local host_wide_user = "@"; 8 local host_wide_user = "@";
10 9
11 local cleanup_after = module:get_option_string("audit_log_expires_after", "28d"); 10 local cleanup_after = module:get_option_period("audit_log_expires_after", "28d");
12 if cleanup_after == "never" then
13 cleanup_after = nil;
14 else
15 cleanup_after = parse_duration(cleanup_after);
16 end
17 11
18 local attach_ips = module:get_option_boolean("audit_log_ips", true); 12 local attach_ips = module:get_option_boolean("audit_log_ips", true);
19 local attach_ipv4_prefix = module:get_option_number("audit_log_ipv4_prefix", nil); 13 local attach_ipv4_prefix = module:get_option_number("audit_log_ipv4_prefix", nil);
20 local attach_ipv6_prefix = module:get_option_number("audit_log_ipv6_prefix", nil); 14 local attach_ipv6_prefix = module:get_option_number("audit_log_ipv6_prefix", nil);
21 15
59 module:context(host):log("debug", "Pruned expired audit log entries"); 53 module:context(host):log("debug", "Pruned expired audit log entries");
60 return true; 54 return true;
61 end 55 end
62 56
63 local function get_ip_network(ip_addr) 57 local function get_ip_network(ip_addr)
64 local _ip = ip.new_ip(ip_addr); 58 local proto = ip_addr.proto;
65 local proto = _ip.proto;
66 local network; 59 local network;
67 if proto == "IPv4" and attach_ipv4_prefix then 60 if proto == "IPv4" and attach_ipv4_prefix then
68 network = ip.truncate(_ip, attach_ipv4_prefix).normal.."/"..attach_ipv4_prefix; 61 network = ip.truncate(ip_addr, attach_ipv4_prefix).normal.."/"..attach_ipv4_prefix;
69 elseif proto == "IPv6" and attach_ipv6_prefix then 62 elseif proto == "IPv6" and attach_ipv6_prefix then
70 network = ip.truncate(_ip, attach_ipv6_prefix).normal.."/"..attach_ipv6_prefix; 63 network = ip.truncate(ip_addr, attach_ipv6_prefix).normal.."/"..attach_ipv6_prefix;
71 end 64 end
72 return network; 65 return network;
73 end 66 end
74 67
75 local function session_extra(session) 68 local function session_extra(session)
81 end 74 end
82 if session.type then 75 if session.type then
83 attr.type = session.type; 76 attr.type = session.type;
84 end 77 end
85 local stanza = st.stanza("session", attr); 78 local stanza = st.stanza("session", attr);
86 if attach_ips and session.ip then 79 local remote_ip = session.ip and ip.new_ip(session.ip);
87 local remote_ip, network = session.ip; 80 if attach_ips and remote_ip then
81 local network;
88 if attach_ipv4_prefix or attach_ipv6_prefix then 82 if attach_ipv4_prefix or attach_ipv6_prefix then
89 network = get_ip_network(remote_ip); 83 network = get_ip_network(remote_ip);
90 end 84 end
91 stanza:text_tag("remote-ip", network or remote_ip); 85 stanza:text_tag("remote-ip", network or remote_ip.normal);
92 end 86 end
93 if attach_location and session.ip then 87 if attach_location and remote_ip then
94 local remote_ip = ip.new(session.ip); 88 local geoip_info = remote_ip.proto == "IPv6" and geoip6_country:query_by_addr6(remote_ip.normal) or geoip4_country:query_by_addr(remote_ip.normal);
95 local geoip_country = ip.proto == "IPv6" and geoip6_country or geoip4_country; 89 stanza:text_tag("location", geoip_info.name, {
96 stanza:tag("location", { 90 country = geoip_info.code;
97 country = geoip_country:query_by_addr(remote_ip.normal); 91 continent = geoip_info.continent;
98 }):up(); 92 }):up();
99 end 93 end
100 if session.client_id then 94 if session.client_id then
101 stanza:text_tag("client", session.client_id); 95 stanza:text_tag("client", session.client_id);
102 end 96 end
138 local id, err = store:append(nil, nil, stanza, extra and extra.timestamp or time_now(), user_key); 132 local id, err = store:append(nil, nil, stanza, extra and extra.timestamp or time_now(), user_key);
139 if not id then 133 if not id then
140 if err == "quota-limit" then 134 if err == "quota-limit" then
141 local limit = store.caps and store.caps.quota or 1000; 135 local limit = store.caps and store.caps.quota or 1000;
142 local truncate_to = math.floor(limit * 0.99); 136 local truncate_to = math.floor(limit * 0.99);
143 if type(cleanup_after) == "number" then 137 if cleanup_after ~= math.huge then
144 module:log("debug", "Audit log has reached quota - forcing prune"); 138 module:log("debug", "Audit log has reached quota - forcing prune");
145 if prune_audit_log(host) then 139 if prune_audit_log(host) then
146 -- Retry append 140 -- Retry append
147 id, err = store:append(nil, nil, stanza, extra and extra.timestamp or time_now(), user_key); 141 id, err = store:append(nil, nil, stanza, extra and extra.timestamp or time_now(), user_key);
148 end 142 end
175 local jid = require "util.jid"; 169 local jid = require "util.jid";
176 local arg = require "util.argparse".parse(arg_, { 170 local arg = require "util.argparse".parse(arg_, {
177 value_params = { "limit" }; 171 value_params = { "limit" };
178 }); 172 });
179 173
180 for k, v in pairs(arg) do print("U", k, v) end 174 module:log("debug", "arg = %q", arg);
181 local query_user, host = jid.prepped_split(arg[1]); 175 local query_jid = jid.prep(arg[1]);
176 local host = jid.host(query_jid);
182 177
183 if arg.prune then 178 if arg.prune then
184 local sm = require "core.storagemanager"; 179 local sm = require "core.storagemanager";
185 if host then 180 if host then
186 sm.initialize_host(host); 181 sm.initialize_host(host);
205 require "core.storagemanager".initialize_host(host); 200 require "core.storagemanager".initialize_host(host);
206 local store = stores[host]; 201 local store = stores[host];
207 local c = 0; 202 local c = 0;
208 203
209 if arg.global then 204 if arg.global then
210 if query_user then 205 if jid.node(query_jid) then
211 print("WW: Specifying a user account is incompatible with --global. Showing only global events."); 206 print("WW: Specifying a user account is incompatible with --global. Showing only global events.");
212 end 207 end
213 query_user = "@"; 208 query_jid = "@";
209 elseif host == query_jid then
210 query_jid = nil;
214 end 211 end
215 212
216 local results, err = store:find(nil, { 213 local results, err = store:find(nil, {
217 with = query_user; 214 with = query_jid;
218 limit = arg.limit and tonumber(arg.limit) or nil; 215 limit = arg.limit and tonumber(arg.limit) or nil;
219 reverse = true; 216 reverse = true;
220 }) 217 })
221 if not results then 218 if not results then
222 print("EE: Failed to query audit log: "..tostring(err)); 219 print("EE: Failed to query audit log: "..tostring(err));
223 return 1; 220 return 1;
224 end 221 end
225 222
226 local colspec = { 223 local colspec = {
227 { title = "Date", key = "when", width = 19, mapper = function (when) return os.date("%Y-%m-%d %R:%S", when); end }; 224 { title = "Date", key = "when", width = 19, mapper = function (when) return os.date("%Y-%m-%d %R:%S", math.floor(when)); end };
228 { title = "Source", key = "source", width = "2p" }; 225 { title = "Source", key = "source", width = "2p" };
229 { title = "Event", key = "event_type", width = "2p" }; 226 { title = "Event", key = "event_type", width = "2p" };
230 }; 227 };
231 228
232 if arg.show_user ~= false and (not arg.global and not query_user) or arg.show_user then 229 if arg.show_user ~= false and (not arg.global and not query_jid) or arg.show_user then
233 table.insert(colspec, { 230 table.insert(colspec, {
234 title = "User", key = "username", width = "2p", 231 title = "User", key = "username", width = "2p",
235 mapper = function (user) 232 mapper = function (user)
236 if user == "@" then return ""; end 233 if user == "@" then return ""; end
237 if user:sub(-#host-1, -1) == ("@"..host) then 234 if user:sub(-#host-1, -1) == ("@"..host) then
268 print(row({ 265 print(row({
269 when = when; 266 when = when;
270 source = entry.attr.source; 267 source = entry.attr.source;
271 event_type = entry.attr.type:gsub("%-", " "); 268 event_type = entry.attr.type:gsub("%-", " ");
272 username = user; 269 username = user;
273 ip = entry:get_child_text("remote-ip"); 270 ip = entry:find("{xmpp:prosody.im/audit}session/remote-ip#");
274 location = entry:find("location@country"); 271 country = entry:find("{xmpp:prosody.im/audit}session/location@country");
275 note = entry:get_child_text("note"); 272 note = entry:get_child_text("note");
276 })); 273 }));
277 end 274 end
278 end 275 end
279 print(string.rep("-", width)); 276 print(string.rep("-", width));