123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- --[[
- Copyright (c) 2019, Vsevolod Stakhov <vsevolod@highsecure.ru>
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ]]--
-
- local exports = {}
-
- ---[[[
- -- @function lua_verdict.get_default_verdict(task)
- -- Returns verdict for a task + score if certain, must be called from idempotent filters only
- -- Returns string:
- -- * `spam`: if message have over reject threshold and has more than one positive rule
- -- * `junk`: if a message has between score between [add_header/rewrite subject] to reject thresholds and has more than two positive rules
- -- * `passthrough`: if a message has been passed through some short-circuit rule
- -- * `ham`: if a message has overall score below junk level **and** more than three negative rule, or negative total score
- -- * `uncertain`: all other cases
- --]]
- local function default_verdict_function(task)
- local result = task:get_metric_result()
-
- if result then
-
- if result.passthrough then
- return 'passthrough',nil
- end
-
- local score = result.score
-
- local action = result.action
-
- if action == 'reject' and result.npositive > 1 then
- return 'spam',score
- elseif action == 'no action' then
- if score < 0 or result.nnegative > 3 then
- return 'ham',score
- end
- else
- -- All colors of junk
- if action == 'add header' or action == 'rewrite subject' then
- if result.npositive > 2 then
- return 'junk',score
- end
- end
- end
-
- return 'uncertain',score
- end
- end
-
- local default_possible_verdicts = {
- passthrough = {
- can_learn = false,
- description = 'message has passthrough result',
- },
- spam = {
- can_learn = 'spam',
- description = 'message is likely spam',
- },
- junk = {
- can_learn = 'spam',
- description = 'message is likely possible spam',
- },
- ham = {
- can_learn = 'ham',
- description = 'message is likely ham',
- },
- uncertain = {
- can_learn = false,
- description = 'not certainity in verdict'
- }
- }
-
- -- Verdict functions specific for modules
- local specific_verdicts = {
- default = {
- callback = default_verdict_function,
- possible_verdicts = default_possible_verdicts
- }
- }
-
- local default_verdict = specific_verdicts.default
-
- exports.get_default_verdict = default_verdict.callback
- exports.set_verdict_function = function(func, what)
- assert(type(func) == 'function')
- if not what then
- -- Default verdict
- local existing = specific_verdicts.default.callback
- specific_verdicts.default.callback = func
- exports.get_default_verdict = func
-
- return existing
- else
- local existing = specific_verdicts[what]
-
- if not existing then
- specific_verdicts[what] = {
- callback = func,
- possible_verdicts = default_possible_verdicts
- }
- else
- existing = existing.callback
- end
-
- specific_verdicts[what].callback = func
- return existing
- end
- end
-
- exports.set_verdict_table = function(verdict_tbl, what)
- assert(type(verdict_tbl) == 'table' and
- type(verdict_tbl.callback) == 'function' and
- type(verdict_tbl.possible_verdicts) == 'table')
-
- if not what then
- -- Default verdict
- local existing = specific_verdicts.default
- specific_verdicts.default = verdict_tbl
- exports.get_default_verdict = specific_verdicts.default.callback
-
- return existing
- else
- local existing = specific_verdicts[what]
- specific_verdicts[what] = verdict_tbl
- return existing
- end
- end
-
- exports.get_specific_verdict = function(what, task)
- if specific_verdicts[what] then
- return specific_verdicts[what].callback(task)
- end
-
- return exports.get_default_verdict(task)
- end
-
- exports.get_possible_verdicts = function(what)
- local lua_util = require "lua_util"
- if what then
- if specific_verdicts[what] then
- return lua_util.keys(specific_verdicts[what].possible_verdicts)
- end
- else
- return lua_util.keys(specific_verdicts.default.possible_verdicts)
- end
-
- return nil
- end
-
- exports.can_learn = function(verdict, what)
- if what then
- if specific_verdicts[what] and specific_verdicts[what].possible_verdicts[verdict] then
- return specific_verdicts[what].possible_verdicts[verdict].can_learn
- end
- else
- if specific_verdicts.default.possible_verdicts[verdict] then
- return specific_verdicts.default.possible_verdicts[verdict].can_learn
- end
- end
-
- return nil -- To distinguish from `false` that could happen in can_learn
- end
-
- exports.describe = function(verdict, what)
- if what then
- if specific_verdicts[what] and specific_verdicts[what].possible_verdicts[verdict] then
- return specific_verdicts[what].possible_verdicts[verdict].description
- end
- else
- if specific_verdicts.default.possible_verdicts[verdict] then
- return specific_verdicts.default.possible_verdicts[verdict].description
- end
- end
-
- return nil
- end
-
- return exports
|