]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Fix] Fix issues in logstats/mapstats from code review 5885/head
authorVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 12 Feb 2026 10:00:14 +0000 (10:00 +0000)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 12 Feb 2026 10:00:14 +0000 (10:00 +0000)
- Shell-quote paths in io.popen() to prevent injection
- Fix typo: correllations -> correlations in JSON output
- Pre-compile ignored symbol regexes instead of recompiling per call
- Deduplicate score change output logic in logstats
- Use native rspamd_ip equality instead of string comparison in mapstats

lualib/lua_log_utils.lua
lualib/rspamadm/logstats.lua
lualib/rspamadm/mapstats.lua

index 03dcdeb3a604a0b62fa37ab717def3a3deb0e688..319031c56afc26af531811f722428f39f0c2e621 100644 (file)
@@ -135,11 +135,15 @@ function exports.normalized_time(s)
   return s
 end
 
+local function shell_quote(s)
+  return "'" .. s:gsub("'", "'\\''") .. "'"
+end
+
 function exports.open_log_file(path)
   local ext = path:match('%.([^%.]+)$')
   local dc = decompressor[ext]
   if dc then
-    return io.popen(dc .. ' ' .. path, 'r')
+    return io.popen(dc .. ' ' .. shell_quote(path), 'r')
   else
     return io.open(path, 'r')
   end
index 981e3ad12385f99934510c6e6d6aa34d3e1eaadc..31517136be65b5ee7df6f0e4b6dab729d039a6b8 100644 (file)
@@ -107,10 +107,20 @@ parser:option "-x --exclude-logs"
 parser:flag "--json"
   :description "Print JSON output"
 
-local function is_ignored(sym, ignored_list)
+local function compile_ignored(ignored_list)
+  local compiled = {}
   for _, ex in ipairs(ignored_list) do
     local re = rspamd_regexp.create('^' .. ex .. '$')
-    if re and re:match(sym) then
+    if re then
+      table.insert(compiled, re)
+    end
+  end
+  return compiled
+end
+
+local function is_ignored(sym, ignored_compiled)
+  for _, re in ipairs(ignored_compiled) do
+    if re:match(sym) then
       return true
     end
   end
@@ -211,7 +221,7 @@ local function handler(args)
   local symbols_search = res['symbol'] or {}
   local symbols_bidir = res['symbol_bidir'] or {}
   local symbols_exclude = res['exclude'] or {}
-  local symbols_ignored = res['ignore'] or {}
+  local symbols_ignored = compile_ignored(res['ignore'] or {})
   local symbols_groups = res['group'] or {}
   local symbols_mult = parse_mult_options(res['mult'] or {})
   local diff_alpha = res['alpha_score']
@@ -525,7 +535,7 @@ local function handler(args)
               local sym_prob = r.hits / total
               corr_data[cs] = corr_prob / sym_prob
             end
-            sym_data.correllations = corr_data
+            sym_data.correlations = corr_data
           end
 
           result.symbols[s] = sym_data
@@ -566,27 +576,23 @@ local function handler(args)
           local jchp = (total_junk > 0) and (r.junk_change / total_junk * 100.0) or 0
 
           if r.weight ~= 0 then
+            local spam_desc, junk_desc
             if r.weight > 0 then
-              io.write(string.format(
-                "\nSpam changes (ham/junk -> spam): %6d/%-6d (%7.3f%%)\n" ..
-                "Spam  changes / total spam hits: %6d/%-6d (%7.3f%%)\n" ..
-                "Junk changes      (ham -> junk): %6d/%-6d (%7.3f%%)\n" ..
-                "Junk  changes / total junk hits: %6d/%-6d (%7.3f%%)\n",
-                r.spam_change, th, (r.spam_change / th * 100),
-                r.spam_change, total_spam, schp,
-                r.junk_change, th, (r.junk_change / th * 100),
-                r.junk_change, total_junk, jchp))
+              spam_desc = "Spam changes (ham/junk -> spam)"
+              junk_desc = "Junk changes      (ham -> junk)"
             else
-              io.write(string.format(
-                "\nSpam changes (spam -> junk/ham): %6d/%-6d (%7.3f%%)\n" ..
-                "Spam changes / total spam hits : %6d/%-6d (%7.3f%%)\n" ..
-                "Junk changes (junk -> ham)     : %6d/%-6d (%7.3f%%)\n" ..
-                "Junk changes / total junk hits : %6d/%-6d (%7.3f%%)\n",
-                r.spam_change, th, (r.spam_change / th * 100),
-                r.spam_change, total_spam, schp,
-                r.junk_change, th, (r.junk_change / th * 100),
-                r.junk_change, total_junk, jchp))
+              spam_desc = "Spam changes (spam -> junk/ham)"
+              junk_desc = "Junk changes (junk -> ham)     "
             end
+            io.write(string.format(
+              "\n%s: %6d/%-6d (%7.3f%%)\n" ..
+              "Spam  changes / total spam hits: %6d/%-6d (%7.3f%%)\n" ..
+              "%s: %6d/%-6d (%7.3f%%)\n" ..
+              "Junk  changes / total junk hits: %6d/%-6d (%7.3f%%)\n",
+              spam_desc, r.spam_change, th, (r.spam_change / th * 100),
+              r.spam_change, total_spam, schp,
+              junk_desc, r.junk_change, th, (r.junk_change / th * 100),
+              r.junk_change, total_junk, jchp))
           end
 
           if correlations then
index 43b386f2cd1655d1af734e8e7553f957a6d41c24..8fbcc81ce0bd66ab411a8a6adacbcd82f3f6e5a0 100644 (file)
@@ -229,13 +229,13 @@ local function ip_within(ip_obj, cidr_str)
     if not ip_masked or not cidr_masked then
       return false
     end
-    return tostring(ip_masked) == tostring(cidr_masked)
+    return ip_masked == cidr_masked
   else
     local cidr_ip = rspamd_ip.from_string(cidr_str)
     if not cidr_ip or not cidr_ip:is_valid() then
       return false
     end
-    return tostring(ip_obj) == tostring(cidr_ip)
+    return ip_obj == cidr_ip
   end
 end