]> source.dussan.org Git - rspamd.git/commitdiff
[Rework] Use a different approach for customization of the settings
authorVsevolod Stakhov <vsevolod@rspamd.com>
Sat, 26 Nov 2022 21:26:37 +0000 (21:26 +0000)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Sat, 26 Nov 2022 21:26:37 +0000 (21:26 +0000)
src/plugins/lua/settings.lua

index b8c5736abf5dd533e4d96932395dd75a3756ccf8..80065ec4f26dc90be2c64cb677fe14a61f4788e4 100644 (file)
@@ -34,7 +34,6 @@ local fun = require "fun"
 local rspamd_mempool = require "rspamd_mempool"
 
 local redis_params
-local external_map -- used when settings are queried from an external resource
 
 local settings = {}
 local N = "settings"
@@ -285,8 +284,6 @@ end
 -- Check limit for a task
 local function check_settings(task)
   local function check_specific_setting(rule, matched)
-    local res = false
-
     local function process_atom(atom)
       local elt = rule.checks[atom]
 
@@ -305,7 +302,7 @@ local function check_settings(task)
       return 0
     end
 
-    res = rule.expression and rule.expression:process(process_atom)
+    local res = rule.expression and rule.expression:process(process_atom) or rule.implicit
 
     if res and res > 0 then
       if rule['whitelist'] then
@@ -356,17 +353,6 @@ local function check_settings(task)
     return
   end
 
-  if external_map then
-    local selector_result = external_map.selector(task)
-
-    if selector_result then
-      external_map.map:get_key(selector_result, nil, task)
-      -- No more selection logic
-      return
-    else
-      rspamd_logger.infox("cannot query selector to make external map request")
-    end
-  end
   -- Match rules according their order
   local applied = false
 
@@ -375,12 +361,12 @@ local function check_settings(task)
       for _,s in ipairs(settings[pri]) do
         local matched = {}
 
-        lua_util.debugm(N, task, "check for settings element %s",
-            s.name)
         local result = check_specific_setting(s.rule, matched)
+        lua_util.debugm(N, task, "check for settings element %s; result = %s",
+            s.name, result)
         -- Can use xor here but more complicated for reading
         if result then
-          if s.rule['apply'] then
+          if s.rule.apply then
             if s.rule.id then
               -- Extract static settings
               local cached = lua_settings.settings_by_id(s.rule.id)
@@ -404,6 +390,17 @@ local function check_settings(task)
             end
 
             applied = true
+          elseif s.rule.external_map then
+            local external_map = s.rule.external_map
+            local selector_result = external_map.selector(task)
+
+            if selector_result then
+              external_map.map:get_key(selector_result, nil, task)
+              -- No more selection logic
+              return
+            else
+              rspamd_logger.infox("cannot query selector to make external map request")
+            end
           end
           if s.rule['symbols'] then
             -- Add symbols, specified in the settings
@@ -430,6 +427,28 @@ local function convert_to_table(chk_elt, out)
   return out
 end
 
+local function gen_settings_external_cb(name)
+  return function (result, err_or_data, code, task)
+    if result then
+      local parser = ucl.parser()
+
+      local res,ucl_err = parser:parse_string(err_or_data)
+      if not res then
+        rspamd_logger.warnx(task, 'cannot parse settings from the external map %s: %s',
+            name, ucl_err)
+      else
+        local obj = parser:get_object()
+        rspamd_logger.infox(task, "<%s> apply settings according to the external map %s",
+            name, task:get_message_id())
+        apply_settings(task, obj, nil, 'external_map')
+      end
+    else
+      rspamd_logger.infox(task, "<%s> no settings returned from the external map %s: %s (code = %s)",
+          task:get_message_id(), name, err_or_data, code)
+    end
+  end
+end
+
 -- Process IP address: converted to a table {ip, mask}
 local function process_ip_condition(ip)
   local out = {}
@@ -1016,8 +1035,11 @@ local function process_settings_table(tbl, allow_ids, mempool, is_static)
             name, nchecks)
       end
     else
-      lua_util.debugm(N, rspamd_config, 'registered settings %s with no checks',
-          name)
+      if not elt.disabled then
+        lua_util.debugm(N, rspamd_config, 'registered settings %s with no checks, assume it as implicit',
+            name)
+        out.implicit = 1
+      end
     end
 
     -- Process symbols part/apply part
@@ -1027,15 +1049,47 @@ local function process_settings_table(tbl, allow_ids, mempool, is_static)
       out['symbols'] = elt['symbols']
     end
 
+    --[[
+    external_map = {
+      map = { ... };
+      selector = "...";
+    }
+    --]]
+    if type(elt.external_map) == 'table'
+        and elt.external_map.map and elt.external_map.selector then
+      local maybe_external_map = {}
+      maybe_external_map.map = lua_maps.map_add_from_ucl(elt.external_map.map, "",
+          string.format("External map for settings element %s", name),
+          gen_settings_external_cb(name))
+      maybe_external_map.selector = lua_selectors.create_selector_closure_fn(rspamd_config,
+          rspamd_config, elt.external_map.selector, ";", lua_selectors.kv_table_from_pairs)
+
+      if maybe_external_map.map and maybe_external_map.selector then
+        rspamd_logger.infox(rspamd_config, "added external map for user's settings %s", name)
+        out.external_map = maybe_external_map
+      else
+        local incorrect_element
+        if not maybe_external_map.map then
+          incorrect_element = "map definition"
+        else
+          incorrect_element = "selector definition"
+        end
+        rspamd_logger.warnx(rspamd_config, "cannot add external map for user's settings; incorrect element: %s",
+            incorrect_element)
+        out.external_map = nil
+      end
+    end
 
-    if elt['apply'] then
-      -- Just insert all metric results to the action key
-      out['apply'] = elt['apply']
-    elseif elt['whitelist'] or elt['want_spam'] then
-      out['whitelist'] = true
-    else
-      rspamd_logger.errx(rspamd_config, "no actions in settings: " .. name)
-      return nil
+    if not elt.external_map then
+      if elt['apply'] then
+        -- Just insert all metric results to the action key
+        out['apply'] = elt['apply']
+      elseif elt['whitelist'] or elt['want_spam'] then
+        out['whitelist'] = true
+      else
+        rspamd_logger.errx(rspamd_config, "no actions in settings: " .. name)
+        return nil
+      end
     end
 
     if allow_ids then
@@ -1117,7 +1171,7 @@ local function process_settings_table(tbl, allow_ids, mempool, is_static)
 
   settings_initialized = true
   lua_settings.load_all_settings(true)
-  rspamd_logger.infox(rspamd_config, 'loaded %1 elements of settings', nrules)
+  rspamd_logger.infox(rspamd_config, 'loaded %s elements of settings', nrules)
 
   return true
 end
@@ -1210,26 +1264,6 @@ local function gen_redis_callback(handler, id)
   end
 end
 
-local function settings_external_cb(result, err_or_data, code, task)
-  if result then
-    local parser = ucl.parser()
-
-    local res,ucl_err = parser:parse_string(err_or_data)
-    if not res then
-      rspamd_logger.warnx(task, 'cannot parse settings from the external map: %s',
-          ucl_err)
-    else
-      local obj = parser:get_object()
-      rspamd_logger.infox(task, "<%s> apply settings according to the external map",
-          task:get_message_id())
-      apply_settings(task, obj, nil, 'external_map')
-    end
-  else
-    rspamd_logger.infox(task, "<%s> no settings returned from the external map: %s (code = %s)",
-        task:get_message_id(), err_or_data, code)
-  end
-end
-
 local redis_section = rspamd_config:get_all_opt("settings_redis")
 local redis_key_handlers = {}
 
@@ -1321,28 +1355,6 @@ elseif set_section and type(set_section) == "table" then
           end, set_section)
   )
 
-  --[[
-  external_map = {
-    map = { ... };
-    selector = "...";
-  }
-  --]]
-  if type(set_section.external_map) == 'table'
-      and set_section.external_map.map and set_section.external_map.selector then
-    local maybe_external_map = {}
-    maybe_external_map.map = lua_maps.map_add_from_ucl(set_section.external_map.map, "", "External map for settings",
-        settings_external_cb)
-    maybe_external_map.selector = lua_selectors.create_selector_closure_fn(rspamd_config,
-        rspamd_config, set_section.external_map.selector, ";", lua_selectors.kv_table_from_pairs)
-
-    if maybe_external_map.map and maybe_external_map.selector then
-      rspamd_logger.infox(rspamd_config, "added external map for user's settings")
-      external_map = maybe_external_map
-      set_section.external_map = nil -- to avoid internal processing
-    else
-      rspamd_logger.warnx(rspamd_config, "cannot add external map for user's settings")
-    end
-  end
   rspamd_config:add_post_init(function ()
     process_settings_table(set_section, true, settings_map_pool, true)
   end, 100)