mod_spam_report_forwarder/mod_spam_report_forwarder.lua
changeset 5848 37e38ee534ea
parent 5242 94472eb41d0a
child 5851 d00af6ebb326
equal deleted inserted replaced
5847:79ae71f52c81 5848:37e38ee534ea
       
     1 local dt = require "util.datetime";
       
     2 local jid = require "util.jid";
     1 local st = require "util.stanza";
     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);
     2 
     8 
     3 local destinations = module:get_option_set("spam_report_destinations", {});
     9 local destinations = module:get_option_set("spam_report_destinations", {});
     4 
    10 
       
    11 local archive = module:open("archive");
       
    12 
       
    13 local cache_size = module:get_option_number("spam_report_forwarder_contact_cache_size", 256);
       
    14 local report_to_origin = module:get_option_boolean("spam_report_forwarder_to_origin", true);
       
    15 local contact_lookup_timeout = module:get_option_number("spam_report_forwarder_contact_lookup_timeout", 180);
       
    16 
       
    17 local body_template = module:get_option_string("spam_report_forwarder_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 			return url.parse(field:get_child_text("value")).path;
       
    43 		end
       
    44 	end
       
    45 end
       
    46 
       
    47 local function get_origin_report_address(reported_jid)
       
    48 	local host = jid.host(reported_jid);
       
    49 	local address = report_addresses:get(host);
       
    50 	if address then return address; end
       
    51 
       
    52 	local contact_query = st.iq({ to = host, from = module.host, id = new_id() })
       
    53 		:query("http://jabber.org/protocol/disco#info");
       
    54 
       
    55 	return module:send_iq(contact_query, prosody.hosts[module.host], contact_lookup_timeout)
       
    56 		:next(function (response)
       
    57 			if response.attr.type ~= "result" then return; end
       
    58 
       
    59 			for form in response.tags[1]:childtags("x", "jabber:x:data") do
       
    60 				local form_type = form:get_child_with_attr("field", nil, "var", "FORM_TYPE");
       
    61 				if form_type == "http://jabber.org/network/serverinfo" then
       
    62 					address = get_address(form, "spam-report-addresses", "abuse-addresses");
       
    63 					break;
       
    64 				end
       
    65 			end
       
    66 			return address;
       
    67 		end);
       
    68 end
       
    69 
       
    70 local function send_report(to, message)
       
    71 	local m = st.clone(message);
       
    72 	m.attr.to = to;
       
    73 	module:send(m);
       
    74 end
       
    75 
     5 function forward_report(event)
    76 function forward_report(event)
       
    77 	local reporter_username = event.origin.username;
       
    78 	local reporter_jid = jid.join(reporter_username, module.host);
       
    79 	local reported_jid = event.jid;
       
    80 
     6 	local report = st.clone(event.report);
    81 	local report = st.clone(event.report);
     7 	report:text_tag("jid", event.jid, { xmlns = "urn:xmpp:jid:0" });
    82 	report:text_tag("jid", reported_jid, { xmlns = "urn:xmpp:jid:0" });
       
    83 
       
    84 	local reported_message_id = report:get_child_with_attr(
       
    85 		"stanza-id",
       
    86 		"urn:xmpp:sid:0",
       
    87 		"by",
       
    88 		reported_jid,
       
    89 		jid.prep
       
    90 	);
       
    91 
       
    92 	local reported_message, reported_message_time, reported_message_with;
       
    93 	if reported_message_id then
       
    94 		reported_message, reported_message_time, reported_message_with = archive:get(reporter_username, reported_message_id);
       
    95 		if jid.bare(reported_message_with) ~= event.jid then
       
    96 			reported_message = nil;
       
    97 		end
       
    98 	end
       
    99 
       
   100 	local body_text = render(body_template, {
       
   101 		reporter_jid = reporter_jid;
       
   102 		reported_jid = event.jid;
       
   103 		reported_message_time = dt.datetime(reported_message_time);
       
   104 	});
     8 
   105 
     9 	local message = st.message({ from = module.host })
   106 	local message = st.message({ from = module.host })
       
   107 		:text_tag("body", body_text)
    10 		:add_child(report);
   108 		:add_child(report);
    11 
   109 
       
   110 	if reported_message then
       
   111 		reported_message.attr.xmlns = "jabber:client";
       
   112 		local fwd = st.stanza("forwarded", { xmlns = "urn:xmpp:forward:0" })
       
   113 			:tag("delay", { xmlns = "urn:xmpp:delay", stamp = dt.datetime(reported_message_time) }):up()
       
   114 			:add_child(reported_message);
       
   115 		message:add_child(fwd);
       
   116 	end
       
   117 
    12 	for destination in destinations do
   118 	for destination in destinations do
    13 		local m = st.clone(message);
   119 		send_report(destination, message);
    14 		m.attr.to = destination;
   120 	end
    15 		module:send(m);
   121 
       
   122 	if report_to_origin then
       
   123 		module:log("debug", "Sending report to origin server...");
       
   124 		get_origin_report_address(event.jid):next(function (origin_report_address)
       
   125 			if not origin_report_address then
       
   126 				module:log("warn", "Couldn't report to origin: no contact address found for %s", jid.host(event.jid));
       
   127 				return;
       
   128 			end
       
   129 			send_report(origin_report_address, message);
       
   130 		end);
    16 	end
   131 	end
    17 end
   132 end
    18 
   133 
    19 module:hook("spam_reporting/abuse-report", forward_report, -1);
   134 module:hook("spam_reporting/abuse-report", forward_report, -1);
    20 module:hook("spam_reporting/spam-report", forward_report, -1);
   135 module:hook("spam_reporting/spam-report", forward_report, -1);