From b645bcc7009c25530f46d8cd42b1afe835fea122 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sat, 26 Nov 2022 21:26:37 +0000 Subject: [PATCH] [Rework] Use a different approach for customization of the settings --- src/plugins/lua/settings.lua | 154 +++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 71 deletions(-) diff --git a/src/plugins/lua/settings.lua b/src/plugins/lua/settings.lua index b8c5736ab..80065ec4f 100644 --- a/src/plugins/lua/settings.lua +++ b/src/plugins/lua/settings.lua @@ -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) -- 2.39.5