You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lua_maps.lua 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. --[[[
  2. -- @module lua_maps
  3. -- This module contains helper functions for managing rspamd maps
  4. --]]
  5. --[[
  6. Copyright (c) 2017, Vsevolod Stakhov <vsevolod@highsecure.ru>
  7. Licensed under the Apache License, Version 2.0 (the "License");
  8. you may not use this file except in compliance with the License.
  9. You may obtain a copy of the License at
  10. http://www.apache.org/licenses/LICENSE-2.0
  11. Unless required by applicable law or agreed to in writing, software
  12. distributed under the License is distributed on an "AS IS" BASIS,
  13. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. See the License for the specific language governing permissions and
  15. limitations under the License.
  16. ]]--
  17. local exports = {}
  18. --[[[
  19. -- @function lua_maps.map_add_from_ucl(opt, mtype, description)
  20. -- Creates a map from static data
  21. -- Returns true if map was added or nil
  22. -- @param {string or table} opt data for map (or URL)
  23. -- @param {string} mtype type of map (`set`, `map`, `radix`, `regexp`)
  24. -- @param {string} description human-readable description of map
  25. -- @return {bool} true on success, or `nil`
  26. --]]
  27. local function rspamd_map_add_from_ucl(opt, mtype, description)
  28. local ret = {
  29. get_key = function(t, k)
  30. if t.__data then
  31. return t.__data:get_key(k)
  32. end
  33. return nil
  34. end
  35. }
  36. local ret_mt = {
  37. __index = function(t, k)
  38. if t.__data then
  39. return t.get_key(k)
  40. end
  41. return nil
  42. end
  43. }
  44. if not opt then
  45. return nil
  46. end
  47. if type(opt) == 'string' then
  48. -- We have a single string, so we treat it as a map
  49. local map = rspamd_config:add_map{
  50. type = mtype,
  51. description = description,
  52. url = opt,
  53. }
  54. if map then
  55. ret.__data = map
  56. setmetatable(ret, ret_mt)
  57. return ret
  58. end
  59. elseif type(opt) == 'table' then
  60. -- it might be plain map or map of plain elements
  61. if opt[1] then
  62. if mtype == 'radix' then
  63. if string.find(opt[1], '^%d') then
  64. local map = rspamd_config:radix_from_ucl(opt)
  65. if map then
  66. ret.__data = map
  67. setmetatable(ret, ret_mt)
  68. return ret
  69. end
  70. else
  71. -- Plain table
  72. local map = rspamd_config:add_map{
  73. type = mtype,
  74. description = description,
  75. url = opt,
  76. }
  77. if map then
  78. ret.__data = map
  79. setmetatable(ret, ret_mt)
  80. return ret
  81. end
  82. end
  83. elseif mtype == 'regexp' then
  84. -- Plain table
  85. local map = rspamd_config:add_map{
  86. type = mtype,
  87. description = description,
  88. url = opt,
  89. }
  90. if map then
  91. ret.__data = map
  92. setmetatable(ret, ret_mt)
  93. return ret
  94. end
  95. else
  96. if string.find(opt[1], '^/%a') or string.find(opt[1], '^http') then
  97. -- Plain table
  98. local map = rspamd_config:add_map{
  99. type = mtype,
  100. description = description,
  101. url = opt,
  102. }
  103. if map then
  104. ret.__data = map
  105. setmetatable(ret, ret_mt)
  106. return ret
  107. end
  108. else
  109. local data = {}
  110. local nelts = 0
  111. for _,elt in ipairs(opt) do
  112. if type(elt) == 'string' then
  113. data[elt] = true
  114. nelts = nelts + 1
  115. end
  116. end
  117. if nelts > 0 then
  118. ret.__data = data
  119. ret.get_key = function(t, k)
  120. if k ~= '__data' then
  121. return t.__data[k]
  122. end
  123. return nil
  124. end
  125. return ret
  126. end
  127. end
  128. end
  129. else
  130. local map = rspamd_config:add_map{
  131. type = mtype,
  132. description = description,
  133. url = opt,
  134. }
  135. if map then
  136. ret.__data = map
  137. setmetatable(ret, ret_mt)
  138. return ret
  139. end
  140. end
  141. end
  142. return nil
  143. end
  144. --[[[
  145. -- @function lua_maps.map_add(mname, optname, mtype, description)
  146. -- Creates a map from configuration elements (static data or URL)
  147. -- Returns true if map was added or nil
  148. -- @param {string} mname config section to use
  149. -- @param {string} optname option name to use
  150. -- @param {string} mtype type of map ('set', 'hash', 'radix', 'regexp')
  151. -- @param {string} description human-readable description of map
  152. -- @return {bool} true on success, or `nil`
  153. --]]
  154. local function rspamd_map_add(mname, optname, mtype, description)
  155. local opt = rspamd_config:get_module_opt(mname, optname)
  156. return rspamd_map_add_from_ucl(opt, mtype, description)
  157. end
  158. exports.rspamd_map_add = rspamd_map_add
  159. exports.map_add = rspamd_map_add
  160. exports.rspamd_map_add_from_ucl = rspamd_map_add_from_ucl
  161. exports.map_add_from_ucl = rspamd_map_add_from_ucl
  162. -- Check `what` for being lua_map name, otherwise just compares key with what
  163. local function rspamd_maybe_check_map(key, what)
  164. local fun = require "fun"
  165. local function starts(where,st)
  166. return string.sub(where,1,string.len(st))==st
  167. end
  168. if type(what) == "table" then
  169. return fun.any(function(elt) return rspamd_maybe_check_map(key, elt) end, what)
  170. end
  171. if type(rspamd_maps) == "table" then
  172. local mn
  173. if starts(what, "map:") then
  174. mn = string.sub(what, 4)
  175. elseif starts(what, "map://") then
  176. mn = string.sub(what, 6)
  177. end
  178. if mn and rspamd_maps[mn] then
  179. return rspamd_maps[mn]:get_key(key)
  180. else
  181. return what:lower() == key
  182. end
  183. else
  184. return what:lower() == key
  185. end
  186. end
  187. exports.rspamd_maybe_check_map = rspamd_maybe_check_map
  188. return exports