]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Feature] Add support of cookies in replies module
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Sun, 4 Nov 2018 10:01:41 +0000 (10:01 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Sun, 4 Nov 2018 10:01:41 +0000 (10:01 +0000)
src/plugins/lua/replies.lua

index fe15211efe506ecf7d8d13fd6f7094c0d3099d27..7e9816fb8b8338da0c8ff576f7cb6667c9edf74b 100644 (file)
@@ -37,6 +37,9 @@ local settings = {
   score = -4, -- Default score
   use_auth = true,
   use_local = true,
+  cookie = nil,
+  cookie_key = nil,
+  cookie_is_pattern = false
 }
 
 local N = "replies"
@@ -128,16 +131,99 @@ local function replies_set(task)
   end
 end
 
+local function replies_check_cookie(task)
+  local function cookie_matched(extra)
+
+    if extra then
+      task:insert_result(settings['symbol'], 1.0, string.format('cookie:%s', extra))
+    else
+      task:insert_result(settings['symbol'], 1.0, 'cookie')
+    end
+    if settings['action'] ~= nil then
+      local ip_addr = task:get_ip()
+      if (settings.use_auth and
+          task:get_user()) or
+          (settings.use_local and ip_addr and ip_addr:is_local()) then
+        rspamd_logger.infox(task, "not forcing action for local network or authorized user");
+      else
+        task:set_pre_result(settings['action'], settings['message'], N)
+      end
+    end
+  end
+
+  -- If in-reply-to header not present return
+  local irt = task:get_header('in-reply-to')
+  if irt == nil then
+    return
+  end
+
+  local cr = require "rspamd_cryptobox"
+  -- Extract user part if needed
+  local extracted_cookie = irt:match('^%<?([^@]+)@.*$')
+  if not extracted_cookie then
+    -- Assume full message id as a cookie
+    extracted_cookie = irt
+  end
+
+  local dec_cookie = cr.decrypt_cookie(settings.cookie_key, extracted_cookie)
+
+  if dec_cookie then
+    -- We have something that looks like a cookie
+    if settings.cookie_is_pattern then
+      local m = dec_cookie:match(settings.cookie)
+
+      if m then
+        cookie_matched(m)
+      end
+    else
+      -- Direct match
+      if dec_cookie == settings.cookie then
+        cookie_matched()
+      end
+    end
+  end
+end
+
 local opts = rspamd_config:get_all_opt('replies')
 if not (opts and type(opts) == 'table') then
   rspamd_logger.infox(rspamd_config, 'module is unconfigured')
   return
 end
 if opts then
+  settings = lua_util.override_defaults(settings, opts)
   redis_params = lua_redis.parse_redis_server('replies')
   if not redis_params then
-    rspamd_logger.infox(rspamd_config, 'no servers are specified, disabling module')
-    lua_util.disable_module(N, "redis")
+    if not (settings.cookie and settings.cookie_key) then
+      rspamd_logger.infox(rspamd_config, 'no servers are specified, disabling module')
+      lua_util.disable_module(N, "redis")
+    else
+      -- Cookies mode
+      -- Check key sanity:
+      local pattern = {'^'}
+      for i=1,32 do pattern[i + 1] = '[a-zA-Z0-9]' end
+      pattern[34] = '$'
+      if not settings.cookie_key:match(table.concat(pattern, '')) then
+        rspamd_logger.errx(rspamd_config,
+            'invalid cookies key: %s, must be 32 hex digits', settings.cookie_key)
+        lua_util.disable_module(N, "config")
+
+        return
+      end
+      local id = rspamd_config:register_symbol({
+        name = 'REPLIES_CHECK',
+        type = 'prefilter,nostat',
+        callback = replies_check_cookie,
+        priority = 10,
+        group = "replies"
+      })
+      rspamd_config:register_symbol({
+        name = settings['symbol'],
+        parent = id,
+        type = 'virtual',
+        score = settings.score,
+        group = "replies",
+      })
+    end
   else
     rspamd_config:register_symbol({
       name = 'REPLIES_SET',
@@ -161,8 +247,4 @@ if opts then
       group = "replies",
     })
   end
-
-  for k,v in pairs(opts) do
-    settings[k] = v
-  end
 end