]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Feature] milter_headers: annotate fuzzy hashes header
authorVsevolod Stakhov <vsevolod@rspamd.com>
Fri, 24 Jul 2026 17:29:07 +0000 (18:29 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Fri, 24 Jul 2026 17:29:07 +0000 (18:29 +0100)
X-Rspamd-Fuzzy now uses structured fuzzy results: every matched hash
is annotated with the rule, flag, probability, the queried hash for
non-exact matches and the storage timestamp. Falls back to the legacy
fuzzy_hashes pool variable when no structured results exist.

src/plugins/lua/milter_headers.lua

index e99e50bd3b84a88d3692504db163c03dda4a770f..25ded43abf612fd62226eb9a2110d5e6d691118e 100644 (file)
@@ -626,13 +626,33 @@ local function milter_headers(task)
   end
 
   routines['fuzzy-hashes'] = function()
-    local res = task:get_mempool():get_variable("fuzzy_hashes", "fstrings")
+    local matches = task:get_fuzzy_results()
+    local out = {}
 
-    if res and #res > 0 then
+    if matches and #matches > 0 then
+      for _, m in ipairs(matches) do
+        local ann = string.format('rule=%s; flag=%s; prob=%.2f', m.rule, m.flag, m.prob)
+
+        if not m.exact then
+          ann = ann .. string.format('; queried=%s', m.queried)
+        end
+
+        if m.added and m.added > 0 then
+          ann = ann .. string.format('; added=%s', os.date('!%Y-%m-%d %H:%M:%S', m.added))
+        end
+
+        out[#out + 1] = string.format('%s (%s)', m.found, ann)
+      end
+    else
+      -- Legacy pool variable set by external fuzzy implementations
+      out = task:get_mempool():get_variable("fuzzy_hashes", "fstrings") or {}
+    end
+
+    if #out > 0 then
       if settings.headers_modify_mode == 'compat' then
-        add_header('fuzzy-hashes', table.concat(res, ','))
+        add_header('fuzzy-hashes', table.concat(out, ','))
       else
-        for _, h in ipairs(res) do
+        for _, h in ipairs(out) do
           add_header('fuzzy-hashes', h)
         end
       end