mod_report_forward/mod_report_forward.lua
changeset 5858 fcfe490de8a4
parent 5851 d00af6ebb326
child 5859 05356f2d4425
equal deleted inserted replaced
5857:97c9b76867ca 5858:fcfe490de8a4
       
     1 local dt = require "util.datetime";
       
     2 local jid = require "util.jid";
       
     3 local st = require "util.stanza";
       
     4 local url = require "socket.url";
       
     5 
       
     6 local new_id = require "util.id".short;
       
     7 local render = require"util.interpolation".new("%b{}", function (s) return s; end);
       
     8 
       
     9 local destinations = module:get_option_set("report_forward_to", {});
       
    10 
       
    11 local archive = module:open("archive");
       
    12 
       
    13 local cache_size = module:get_option_number("report_forward_contact_cache_size", 256);
       
    14 local report_to_origin = module:get_option_boolean("report_forward_to_origin", true);
       
    15 local contact_lookup_timeout = module:get_option_number("report_forward_contact_lookup_timeout", 180);
       
    16 
       
    17 local body_template = module:get_option_string("report_forward_body_template", [[
       
    18 SPAM/ABUSE REPORT
       
    19 -----------------
       
    20 
       
    21 Reported JID: {reported_jid}
       
    22 
       
    23 A user on our service has reported a message originating from the above JID on
       
    24 your server.
       
    25 
       
    26 {reported_message_time&The reported message was sent at: {reported_message_time}}
       
    27 
       
    28 --
       
    29 This message contains also machine-readable payloads, including XEP-0377, in case
       
    30 you want to automate handling of these reports. You can receive these reports
       
    31 to a different address by setting 'spam-report-addresses' in your server
       
    32 contact info configuration. For more information, see https://xmppbl.org/reports/
       
    33 ]]):gsub("^%s+", ""):gsub("(%S)\n(%S)", "%1 %2");
       
    34 
       
    35 local report_addresses = require "util.cache".new(cache_size);
       
    36 
       
    37 local function get_address(form, ...)
       
    38 	for i = 1, select("#", ...) do
       
    39 		local field_var = select(i, ...);
       
    40 		local field = form:get_child_with_attr("field", "jabber:x:data", "var", field_var);
       
    41 		if field then
       
    42 			local parsed = url.parse(field:get_child_text("value"));
       
    43 			if parsed.scheme == "xmpp" and parsed.path and not parsed.query then
       
    44 				return parsed.path;
       
    45 			end
       
    46 		end
       
    47 	end
       
    48 end
       
    49 
       
    50 local function get_origin_report_address(reported_jid)
       
    51 	local host = jid.host(reported_jid);
       
    52 	local address = report_addresses:get(host);
       
    53 	if address then return address; end
       
    54 
       
    55 	local contact_query = st.iq({ to = host, from = module.host, id = new_id() })
       
    56 		:query("http://jabber.org/protocol/disco#info");
       
    57 
       
    58 	return module:send_iq(contact_query, prosody.hosts[module.host], contact_lookup_timeout)
       
    59 		:next(function (response)
       
    60 			if response.attr.type ~= "result" then return; end
       
    61 
       
    62 			for form in response.tags[1]:childtags("x", "jabber:x:data") do
       
    63 				local form_type = form:get_child_with_attr("field", nil, "var", "FORM_TYPE");
       
    64 				if form_type == "http://jabber.org/network/serverinfo" then
       
    65 					address = get_address(form, "spam-report-addresses", "abuse-addresses");
       
    66 					break;
       
    67 				end
       
    68 			end
       
    69 			return address;
       
    70 		end);
       
    71 end
       
    72 
       
    73 local function send_report(to, message)
       
    74 	local m = st.clone(message);
       
    75 	m.attr.to = to;
       
    76 	module:send(m);
       
    77 end
       
    78 
       
    79 function forward_report(event)
       
    80 	local reporter_username = event.origin.username;
       
    81 	local reporter_jid = jid.join(reporter_username, module.host);
       
    82 	local reported_jid = event.jid;
       
    83 
       
    84 	local report = st.clone(event.report);
       
    85 	report:text_tag("jid", reported_jid, { xmlns = "urn:xmpp:jid:0" });
       
    86 
       
    87 	local reported_message_id = report:get_child_with_attr(
       
    88 		"stanza-id",
       
    89 		"urn:xmpp:sid:0",
       
    90 		"by",
       
    91 		reported_jid,
       
    92 		jid.prep
       
    93 	);
       
    94 
       
    95 	local reported_message, reported_message_time, reported_message_with;
       
    96 	if reported_message_id then
       
    97 		reported_message, reported_message_time, reported_message_with = archive:get(reporter_username, reported_message_id);
       
    98 		if jid.bare(reported_message_with) ~= event.jid then
       
    99 			reported_message = nil;
       
   100 		end
       
   101 	end
       
   102 
       
   103 	local body_text = render(body_template, {
       
   104 		reporter_jid = reporter_jid;
       
   105 		reported_jid = event.jid;
       
   106 		reported_message_time = dt.datetime(reported_message_time);
       
   107 	});
       
   108 
       
   109 	local message = st.message({ from = module.host })
       
   110 		:text_tag("body", body_text)
       
   111 		:add_child(report);
       
   112 
       
   113 	if reported_message then
       
   114 		reported_message.attr.xmlns = "jabber:client";
       
   115 		local fwd = st.stanza("forwarded", { xmlns = "urn:xmpp:forward:0" })
       
   116 			:tag("delay", { xmlns = "urn:xmpp:delay", stamp = dt.datetime(reported_message_time) }):up()
       
   117 			:add_child(reported_message);
       
   118 		message:add_child(fwd);
       
   119 	end
       
   120 
       
   121 	for destination in destinations do
       
   122 		send_report(destination, message);
       
   123 	end
       
   124 
       
   125 	if report_to_origin then
       
   126 		module:log("debug", "Sending report to origin server...");
       
   127 		get_origin_report_address(event.jid):next(function (origin_report_address)
       
   128 			if not origin_report_address then
       
   129 				module:log("warn", "Couldn't report to origin: no contact address found for %s", jid.host(event.jid));
       
   130 				return;
       
   131 			end
       
   132 			send_report(origin_report_address, message);
       
   133 		end);
       
   134 	end
       
   135 end
       
   136 
       
   137 module:hook("spam_reporting/abuse-report", forward_report, -1);
       
   138 module:hook("spam_reporting/spam-report", forward_report, -1);
       
   139 module:hook("spam_reporting/unknown-report", forward_report, -1);