mod_firewall/actions.lib.lua
changeset 947 c91cac3b823f
child 949 b729414b4bf1
equal deleted inserted replaced
946:2c5430ff1c11 947:c91cac3b823f
       
     1 local action_handlers = {};
       
     2 
       
     3 -- Takes an XML string and returns a code string that builds that stanza
       
     4 -- using st.stanza()
       
     5 local function compile_xml(data)
       
     6 	local code = {};
       
     7 	local first, short_close = true, nil;
       
     8 	for tagline, text in data:gmatch("<([^>]+)>([^<]*)") do
       
     9 		if tagline:sub(-1,-1) == "/" then
       
    10 			tagline = tagline:sub(1, -2);
       
    11 			short_close = true;
       
    12 		end
       
    13 		if tagline:sub(1,1) == "/" then
       
    14 			code[#code+1] = (":up()");
       
    15 		else
       
    16 			local name, attr = tagline:match("^(%S*)%s*(.*)$");
       
    17 			local attr_str = {};
       
    18 			for k, _, v in attr:gmatch("(%S+)=([\"'])([^%2]-)%2") do
       
    19 				if #attr_str == 0 then
       
    20 					table.insert(attr_str, ", { ");
       
    21 				else
       
    22 					table.insert(attr_str, ", ");
       
    23 				end
       
    24 				if k:match("^%a%w*$") then
       
    25 					table.insert(attr_str, string.format("%s = %q", k, v));
       
    26 				else
       
    27 					table.insert(attr_str, string.format("[%q] = %q", k, v));
       
    28 				end
       
    29 			end
       
    30 			if #attr_str > 0 then
       
    31 				table.insert(attr_str, " }");
       
    32 			end
       
    33 			if first then
       
    34 				code[#code+1] = (string.format("st.stanza(%q %s)", name, #attr_str>0 and table.concat(attr_str) or ", nil"));
       
    35 				first = nil;
       
    36 			else
       
    37 				code[#code+1] = (string.format(":tag(%q%s)", name, table.concat(attr_str)));
       
    38 			end
       
    39 		end
       
    40 		if text and text:match("%S") then
       
    41 			code[#code+1] = (string.format(":text(%q)", text));
       
    42 		elseif short_close then
       
    43 			short_close = nil;
       
    44 			code[#code+1] = (":up()");
       
    45 		end
       
    46 	end
       
    47 	return table.concat(code, "");
       
    48 end
       
    49 
       
    50 
       
    51 function action_handlers.DROP()
       
    52 	return "log('debug', 'Firewall dropping stanza: %s', tostring(stanza)); return true;";
       
    53 end
       
    54 
       
    55 function action_handlers.STRIP(tag_desc)
       
    56 	local code = {};
       
    57 	local name, xmlns = tag_desc:match("^(%S+) (.+)$");
       
    58 	if not name then
       
    59 		name, xmlns = tag_desc, nil;
       
    60 	end
       
    61 	if name == "*" then
       
    62 		name = nil;
       
    63 	end
       
    64 	code[#code+1] = ("local stanza_xmlns = stanza.attr.xmlns; ");
       
    65 	code[#code+1] = "stanza:maptags(function (tag) if ";
       
    66 	if name then
       
    67 		code[#code+1] = ("tag.name == %q and "):format(name);
       
    68 	end
       
    69 	if xmlns then
       
    70 		code[#code+1] = ("(tag.attr.xmlns or stanza_xmlns) == %q "):format(xmlns);
       
    71 	else
       
    72 		code[#code+1] = ("tag.attr.xmlns == stanza_xmlns ");
       
    73 	end
       
    74 	code[#code+1] = "then return nil; end return tag; end );";
       
    75 	return table.concat(code);
       
    76 end
       
    77 
       
    78 function action_handlers.INJECT(tag)
       
    79 	return "stanza:add_child("..compile_xml(tag)..")", { "st" };
       
    80 end
       
    81 
       
    82 local error_types = {
       
    83 	["bad-request"] = "modify";
       
    84 	["conflict"] = "cancel";
       
    85 	["feature-not-implemented"] = "cancel";
       
    86 	["forbidden"] = "auth";
       
    87 	["gone"] = "cancel";
       
    88 	["internal-server-error"] = "cancel";
       
    89 	["item-not-found"] = "cancel";
       
    90 	["jid-malformed"] = "modify";
       
    91 	["not-acceptable"] = "modify";
       
    92 	["not-allowed"] = "cancel";
       
    93 	["not-authorized"] = "auth";
       
    94 	["payment-required"] = "auth";
       
    95 	["policy-violation"] = "modify";
       
    96 	["recipient-unavailable"] = "wait";
       
    97 	["redirect"] = "modify";
       
    98 	["registration-required"] = "auth";
       
    99 	["remote-server-not-found"] = "cancel";
       
   100 	["remote-server-timeout"] = "wait";
       
   101 	["resource-constraint"] = "wait";
       
   102 	["service-unavailable"] = "cancel";
       
   103 	["subscription-required"] = "auth";
       
   104 	["undefined-condition"] = "cancel";
       
   105 	["unexpected-request"] = "wait";
       
   106 };
       
   107 
       
   108 
       
   109 local function route_modify(make_new, to, drop)
       
   110 	local reroute, deps = "session.send(newstanza)", { "st" };
       
   111 	if to then
       
   112 		reroute = ("newstanza.attr.to = %q; core_post_stanza(session, newstanza)"):format(to);
       
   113 		deps[#deps+1] = "core_post_stanza";
       
   114 	end
       
   115 	return ([[local newstanza = st.%s; %s; %s; ]])
       
   116 		:format(make_new, reroute, drop and "return true" or ""), deps;
       
   117 end
       
   118 	
       
   119 function action_handlers.BOUNCE(with)
       
   120 	local error = with and with:match("^%S+") or "service-unavailable";
       
   121 	local error_type = error:match(":(%S+)");
       
   122 	if not error_type then
       
   123 		error_type = error_types[error] or "cancel";
       
   124 	else
       
   125 		error = error:match("^[^:]+");
       
   126 	end
       
   127 	error, error_type = string.format("%q", error), string.format("%q", error_type);
       
   128 	local text = with and with:match(" %((.+)%)$");
       
   129 	if text then
       
   130 		text = string.format("%q", text);
       
   131 	else
       
   132 		text = "nil";
       
   133 	end
       
   134 	return route_modify(("error_reply(stanza, %s, %s, %s)"):format(error_type, error, text), nil, true);
       
   135 end
       
   136 
       
   137 function action_handlers.REDIRECT(where)
       
   138 	return route_modify("clone(stanza)", where, true, true);
       
   139 end
       
   140 
       
   141 function action_handlers.COPY(where)
       
   142 	return route_modify("clone(stanza)", where, true, false);
       
   143 end
       
   144 
       
   145 function action_handlers.LOG(string)
       
   146 	local level = string:match("^%[(%a+)%]") or "info";
       
   147 	string = string:gsub("^%[%a+%] ?", "");
       
   148 	return (("log(%q, %q)"):format(level, string)
       
   149 		:gsub("$top", [["..stanza:top_tag().."]])
       
   150 		:gsub("$stanza", [["..stanza.."]])
       
   151 		:gsub("$(%b())", [["..%1.."]]));
       
   152 end
       
   153 
       
   154 function action_handlers.RULEDEP(dep)
       
   155 	return "", { dep };
       
   156 end
       
   157 
       
   158 return action_handlers;