Software /
code /
prosody-modules
File
mod_firewall/conditions.lib.lua @ 1268:854a3933cfcd
mod_muc_log_http: URL-encode room names. This allows special characters in room names to work. Ideally this escaping shouldn’t be done in the user visible content, but the module’s template system doesn’t currently allow that.
author | Waqas Hussain <waqas20@gmail.com> |
---|---|
date | Sat, 04 Jan 2014 16:50:57 -0500 |
parent | 997:69dd4e4e54a2 |
child | 2036:7ba6ed553c93 |
line wrap: on
line source
local condition_handlers = {}; local jid = require "util.jid"; -- Return a code string for a condition that checks whether the contents -- of variable with the name 'name' matches any of the values in the -- comma/space/pipe delimited list 'values'. local function compile_comparison_list(name, values) local conditions = {}; for value in values:gmatch("[^%s,|]+") do table.insert(conditions, ("%s == %q"):format(name, value)); end return table.concat(conditions, " or "); end function condition_handlers.KIND(kind) return compile_comparison_list("name", kind), { "name" }; end local wildcard_equivs = { ["*"] = ".*", ["?"] = "." }; local function compile_jid_match_part(part, match) if not match then return part.." == nil" end local pattern = match:match("<(.*)>"); if pattern then if pattern == "*" then return part; end if pattern:match("^<.*>$") then pattern = pattern:match("^<(.*)>$"); else pattern = pattern:gsub("%p", "%%%0"):gsub("%%(%p)", wildcard_equivs); end return ("%s:match(%q)"):format(part, "^"..pattern.."$"); else return ("%s == %q"):format(part, match); end end local function compile_jid_match(which, match_jid) local match_node, match_host, match_resource = jid.split(match_jid); local conditions = {}; conditions[#conditions+1] = compile_jid_match_part(which.."_node", match_node); conditions[#conditions+1] = compile_jid_match_part(which.."_host", match_host); if match_resource then conditions[#conditions+1] = compile_jid_match_part(which.."_resource", match_resource); end return table.concat(conditions, " and "); end function condition_handlers.TO(to) return compile_jid_match("to", to), { "split_to" }; end function condition_handlers.FROM(from) return compile_jid_match("from", from), { "split_from" }; end function condition_handlers.TYPE(type) return compile_comparison_list("(type or (name == 'message' and 'normal') or (name == 'presence' and 'available'))", type), { "type", "name" }; end local function zone_check(zone, which) local which_not = which == "from" and "to" or "from"; return ("(zone_%s[%s_host] or zone_%s[%s] or zone_%s[bare_%s]) " .."and not(zone_%s[%s_host] or zone_%s[%s] or zone_%s[%s])" ) :format(zone, which, zone, which, zone, which, zone, which_not, zone, which_not, zone, which_not), { "split_to", "split_from", "bare_to", "bare_from", "zone:"..zone }; end function condition_handlers.ENTERING(zone) return zone_check(zone, "to"); end function condition_handlers.LEAVING(zone) return zone_check(zone, "from"); end function condition_handlers.PAYLOAD(payload_ns) return ("stanza:get_child(nil, %q)"):format(payload_ns); end function condition_handlers.INSPECT(path) if path:find("=") then local path, match = path:match("(.-)=(.*)"); return ("stanza:find(%q) == %q"):format(path, match); end return ("stanza:find(%q)"):format(path); end function condition_handlers.FROM_GROUP(group_name) return ("group_contains(%q, bare_from)"):format(group_name), { "group_contains", "bare_from" }; end function condition_handlers.TO_GROUP(group_name) return ("group_contains(%q, bare_to)"):format(group_name), { "group_contains", "bare_to" }; end function condition_handlers.FROM_ADMIN_OF(host) return ("is_admin(bare_from, %s)"):format(host ~= "*" and host or nil), { "is_admin", "bare_from" }; end function condition_handlers.TO_ADMIN_OF(host) return ("is_admin(bare_to, %s)"):format(host ~= "*" and host or nil), { "is_admin", "bare_to" }; end local day_numbers = { sun = 0, mon = 2, tue = 3, wed = 4, thu = 5, fri = 6, sat = 7 }; local function current_time_check(op, hour, minute) hour, minute = tonumber(hour), tonumber(minute); local adj_op = op == "<" and "<" or ">="; -- Start time inclusive, end time exclusive if minute == 0 then return "(current_hour"..adj_op..hour..")"; else return "((current_hour"..op..hour..") or (current_hour == "..hour.." and current_minute"..adj_op..minute.."))"; end end local function resolve_day_number(day_name) return assert(day_numbers[day_name:sub(1,3):lower()], "Unknown day name: "..day_name); end function condition_handlers.DAY(days) local conditions = {}; for day_range in days:gmatch("[^,]+") do local day_start, day_end = day_range:match("(%a+)%s*%-%s*(%a+)"); if day_start and day_end then local day_start_num, day_end_num = resolve_day_number(day_start), resolve_day_number(day_end); local op = "and"; if day_end_num < day_start_num then op = "or"; end table.insert(conditions, ("current_day >= %d %s current_day <= %d"):format(day_start_num, op, day_end_num)); elseif day_range:match("%a") then local day = resolve_day_number(day_range:match("%a+")); table.insert(conditions, "current_day == "..day); else error("Unable to parse day/day range: "..day_range); end end assert(#conditions>0, "Expected a list of days or day ranges"); return "("..table.concat(conditions, ") or (")..")", { "time:day" }; end function condition_handlers.TIME(ranges) local conditions = {}; for range in ranges:gmatch("([^,]+)") do local clause = {}; range = range:lower() :gsub("(%d+):?(%d*) *am", function (h, m) return tostring(tonumber(h)%12)..":"..(tonumber(m) or "00"); end) :gsub("(%d+):?(%d*) *pm", function (h, m) return tostring(tonumber(h)%12+12)..":"..(tonumber(m) or "00"); end); local start_hour, start_minute = range:match("(%d+):(%d+) *%-"); local end_hour, end_minute = range:match("%- *(%d+):(%d+)"); local op = tonumber(start_hour) > tonumber(end_hour) and " or " or " and "; if start_hour and end_hour then table.insert(clause, current_time_check(">", start_hour, start_minute)); table.insert(clause, current_time_check("<", end_hour, end_minute)); end if #clause == 0 then error("Unable to parse time range: "..range); end table.insert(conditions, "("..table.concat(clause, " "..op.." ")..")"); end return table.concat(conditions, " or "), { "time:hour,min" }; end function condition_handlers.LIMIT(name) return ("not throttle_%s:poll(1)"):format(name), { "throttle:"..name }; end return condition_handlers;