aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrm-minus-rf <rm.minus.rf@protonmail.com>2020-04-17 07:43:56 +0200
committerrm-minus-rf <rm.minus.rf@protonmail.com>2020-04-17 07:43:56 +0200
commit834279171c3ec8c8a355a9e438f07a06f5b16325 (patch)
tree789362c07329ded6f584d9f214c368551d1e10d8
parent0d13c724df534012de7e41c5d5b743a7d9314431 (diff)
downloadrspamd-834279171c3ec8c8a355a9e438f07a06f5b16325.tar.gz
rspamd-834279171c3ec8c8a355a9e438f07a06f5b16325.zip
[Feature] add queueid, uid, messageid and specific symbols to selectors
[Minor] use only selectors to fill vars in force_actions message
-rw-r--r--lualib/lua_selectors/extractors.lua50
-rw-r--r--lualib/lua_selectors/transforms.lua14
-rw-r--r--src/plugins/lua/force_actions.lua71
3 files changed, 79 insertions, 56 deletions
diff --git a/lualib/lua_selectors/extractors.lua b/lualib/lua_selectors/extractors.lua
index 625af435c..635972226 100644
--- a/lualib/lua_selectors/extractors.lua
+++ b/lualib/lua_selectors/extractors.lua
@@ -388,6 +388,54 @@ The first argument must be header name.]],
]],
['args_schema'] = { ts.one_of { 'stem', 'raw', 'norm', 'full' }:is_optional()},
},
+ -- Get queue ID
+ ['queueid'] = {
+ ['get_value'] = function(task)
+ local queueid = task:get_queue_id()
+ if queueid then return queueid,'string' end
+ return nil
+ end,
+ ['description'] = [[Get queue ID]],
+ },
+ -- Get ID of the task being processed
+ ['uid'] = {
+ ['get_value'] = function(task)
+ local uid = task:get_uid()
+ if uid then return uid,'string' end
+ return nil
+ end,
+ ['description'] = [[Get ID of the task being processed]],
+ },
+ -- Get message ID of the task being processed
+ ['messageid'] = {
+ ['get_value'] = function(task)
+ local mid = task:get_message_id()
+ if mid then return mid,'string' end
+ return nil
+ end,
+ ['description'] = [[Get message ID]],
+ },
+ -- Get specific symbol
+ ['symbol'] = {
+ ['get_value'] = function(task, args)
+ local symbol = task:get_symbol(args[1])
+ if args[2] and symbol then
+ if args[2] == 'options' then
+ -- concat options tables to avoid table representation strings produced by implicit conversion
+ return fun.map(function(r) return table.concat(r[args[2]], ', ') end, symbol), 'string_list'
+ elseif args[2] == 'score' then
+ -- only userdata_list seems to work for scores
+ return fun.map(function(r) return r[args[2]] end, symbol), 'userdata_list'
+ else
+ return fun.map(function(r) return r[args[2]] end, symbol), 'string_list'
+ end
+ end
+ return symbol,'table_list'
+ end,
+ ['description'] = [[Get specific symbol. The first argument must be the symbol name. If no second argument is specified, returns a list of symbol tables. Otherwise the second argument specifies the attribute which is returned as list (`options`, `score` or `group`)]],
+ ['args_schema'] = {ts.string, ts.one_of{'options','score','group'}:is_optional()}
+ },
+
}
-return extractors \ No newline at end of file
+return extractors
diff --git a/lualib/lua_selectors/transforms.lua b/lualib/lua_selectors/transforms.lua
index b0c912deb..be896126d 100644
--- a/lualib/lua_selectors/transforms.lua
+++ b/lualib/lua_selectors/transforms.lua
@@ -413,8 +413,20 @@ Empty string comes the first argument or 'true', non-empty string comes nil]],
['args_schema'] = {(ts.number + ts.string / tonumber),
(ts.number + ts.string / tonumber):is_optional()}
},
+ -- Returns the string with all non ascii chars replaced
+ ['to_ascii'] = {
+ ['types'] = {
+ ['string'] = true,
+ },
+ ['map_type'] = 'string',
+ ['process'] = function(inp, _)
+ return string.gsub(inp, '[\128-\255]', '?'), 'string'
+ end,
+ ['description'] = 'Returns the string with all non-ascii bytes replaced with `?`',
+ },
+
}
transform_function.match = transform_function.regexp
-return transform_function \ No newline at end of file
+return transform_function
diff --git a/src/plugins/lua/force_actions.lua b/src/plugins/lua/force_actions.lua
index 8e645290e..caa03da64 100644
--- a/src/plugins/lua/force_actions.lua
+++ b/src/plugins/lua/force_actions.lua
@@ -64,66 +64,29 @@ local function gen_cb(expr, act, pool, message, subject, raction, honor, limit,
return function(task)
- local function fill_vars(repl, var_class, var_payload)
- -- fill template vars prefixed with
- -- 'selector::' => fill with value extracted by a selector
- -- 'symbol::' => fill with matching symbol option string(s)
- -- 'task::' => fill with matching task attribute
- -- (only queue_id and uid allowed)
-
- if var_class == "selector" then
- local selector = lua_selectors.create_selector_closure(rspamd_config, var_payload, '', true)
+ local function process_message_selectors(repl, selector_expr)
+ -- create/reuse selector to extract value for this placeholder
+ local selector = selector_cache[selector_expr]
+ if not selector then
+ selector_cache[selector_expr] = lua_selectors.create_selector_closure(rspamd_config, selector_expr, '', true)
+ selector = selector_cache[selector_expr]
if not selector then
- rspamd_logger.errx(rspamd_config, 'could not create selector [%1]', var_payload)
+ rspamd_logger.errx(task, 'could not create selector [%1]', selector_expr)
return "((could not create selector))"
end
- local extracted = selector(task)
- if extracted then
- -- replace non ascii chars
- if type(extracted) == 'table' then
- extracted = table.concat(extracted, ',')
- end
- extracted = string.gsub(extracted, '[\128-\255]', '?')
- else
- rspamd_logger.errx(rspamd_config, 'could not extract value with selector [%1]', var_payload)
- extracted = '((error extracting value))'
- end
- return extracted
end
-
- if var_class == "symbol" then
- local symb_opts
- local symb_strs = {}
- if task:has_symbol(var_payload) then
- local symb_tbl = task:get_symbol(var_payload)
- for _,symb in ipairs(symb_tbl) do
- local symb_opts = symb.options
- if symb_opts then
- -- replace non ascii chars
- symb_strs[#symb_strs+1] = string.gsub(table.concat(symb_opts, ','), '[\128-\255]', '?')
- end
- end
- symb_str = table.concat(symb_strs, ',')
- else
- symb_str = '((symbol not found))'
+ local extracted = selector(task)
+ if extracted then
+ if type(extracted) == 'table' then
+ extracted = table.concat(extracted, ',')
end
- return symb_str
- end
-
- -- NOTE-TO-VSTAKHOV: would it make sense to export task:get_queue_id and task:get_uid as selector data definition?
- if var_class == "task" then
- local attr_val = '((unknown task attribute))'
- if var_payload == 'queue_id' then
- attr_val = task:get_queue_id()
- elseif var_payload == 'uid' then
- attr_val = task:get_uid()
- end
- return attr_val
+ else
+ rspamd_logger.errx(task, 'could not extract value with selector [%1]', selector_expr)
+ extracted = '((error extracting value))'
end
-
+ return extracted
end
-
local cact = task:get_metric_action('default')
if cact == act then
return false
@@ -144,8 +107,8 @@ local function gen_cb(expr, act, pool, message, subject, raction, honor, limit,
if least then flags = "least" end
if type(message) == 'string' then
- -- fill vars in return message
- message = string.gsub(message, '(${(.-)::(.-)})', fill_vars)
+ -- process selector expressions in the message
+ message = string.gsub(message, '(${(.-)})', process_message_selectors)
task:set_pre_result(act, message, N, nil, nil, flags)
else