mod_incidents_handling/incidents_handling/incidents_handling.lib.lua
changeset 1343 7dbde05b48a9
parent 913 f42837829d5f
equal deleted inserted replaced
1342:0ae065453dc9 1343:7dbde05b48a9
    11 local my_host = nil
    11 local my_host = nil
    12 
    12 
    13 -- // Util and Functions //
    13 -- // Util and Functions //
    14 
    14 
    15 local function ft_str()
    15 local function ft_str()
    16 	local d = os_date("%FT%T%z"):gsub("^(.*)(%+%d+)", function(dt, z) 
    16 	local d = os_date("%FT%T%z"):gsub("^(.*)(%+%d+)", function(dt, z)
    17 		if z == "+0000" then return dt.."Z" else return dt..z end
    17 		if z == "+0000" then return dt.."Z" else return dt..z end
    18 	end)
    18 	end)
    19 	return d
    19 	return d
    20 end
    20 end
    21 
    21 
    22 local function get_incident_layout(i_type)
    22 local function get_incident_layout(i_type)
    23 	local layout = {
    23 	local layout = {
    24 		title = (i_type == "report" and "Incident report form") or (i_type == "request" and "Request for assistance with incident form"),
    24 		title = (i_type == "report" and "Incident report form") or (i_type == "request" and "Request for assistance with incident form"),
    25 		instructions = "Started/Ended Time, Contacts, Sources and Targets of the attack are mandatory. See RFC 5070 for further format instructions.",
    25 		instructions = "Started/Ended Time, Contacts, Sources and Targets of the attack are mandatory. See RFC 5070 for further format instructions.",
    26 		{ name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/commands" },
    26 		{ name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/commands" },
    27 		
    27 
    28 		{ name = "name", type = "hidden", value = my_host },
    28 		{ name = "name", type = "hidden", value = my_host },
    29 		{ name = "entity", type ="text-single", label = "Remote entity to query" },
    29 		{ name = "entity", type ="text-single", label = "Remote entity to query" },
    30 		{ name = "started", type = "text-single", label = "Incident Start Time" },
    30 		{ name = "started", type = "text-single", label = "Incident Start Time" },
    31 		{ name = "ended", type = "text-single", label = "Incident Ended Time" },
    31 		{ name = "ended", type = "text-single", label = "Incident Ended Time" },
    32 		{ name = "reported", type = "hidden", value = ft_str() },
    32 		{ name = "reported", type = "hidden", value = ft_str() },
    33 		{ name = "description", type = "text-single", label = "Description",
    33 		{ name = "description", type = "text-single", label = "Description",
    34 		  desc = "Description syntax is: <lang (in xml:lang format)> <short description>" },
    34 		  desc = "Description syntax is: <lang (in xml:lang format)> <short description>" },
    35 		{ name = "contacts", type = "text-multi", label = "Contacts",
    35 		{ name = "contacts", type = "text-multi", label = "Contacts",
    36 		  desc = "Contacts entries format is: <address> <type> <role> - separated by new lines" },
    36 		  desc = "Contacts entries format is: <address> <type> <role> - separated by new lines" },
    37 		{ name = "related", type = "text-multi", label = "Related Incidents", 
    37 		{ name = "related", type = "text-multi", label = "Related Incidents",
    38 		  desc = "Related incidents entries format is: <CSIRT's FQDN> <Incident ID> - separated by new lines" },
    38 		  desc = "Related incidents entries format is: <CSIRT's FQDN> <Incident ID> - separated by new lines" },
    39 		{ name = "impact", type = "text-single", label = "Impact Assessment", 
    39 		{ name = "impact", type = "text-single", label = "Impact Assessment",
    40 		  desc = "Impact assessment format is: <severity> <completion> <type>" },
    40 		  desc = "Impact assessment format is: <severity> <completion> <type>" },
    41 		{ name = "sources", type = "text-multi", label = "Attack Sources", 
    41 		{ name = "sources", type = "text-multi", label = "Attack Sources",
    42 		  desc = "Attack sources format is: <address> <category> <count> <count-type>" },
    42 		  desc = "Attack sources format is: <address> <category> <count> <count-type>" },
    43 		{ name = "targets", type = "text-multi", label = "Attack Targets", 
    43 		{ name = "targets", type = "text-multi", label = "Attack Targets",
    44 		  desc = "Attack target format is: <address> <category> <noderole>" }
    44 		  desc = "Attack target format is: <address> <category> <noderole>" }
    45 	}
    45 	}
    46 
    46 
    47 	if i_type == "request" then
    47 	if i_type == "request" then
    48 		table.insert(layout, { 
    48 		table.insert(layout, {
    49 			name = "expectation",
    49 			name = "expectation",
    50 			type = "list-single",
    50 			type = "list-single",
    51 			label = "Expected action from remote entity",
    51 			label = "Expected action from remote entity",
    52 			value = {
    52 			value = {
    53 				{ value = "nothing", label = "No action" },
    53 				{ value = "nothing", label = "No action" },
    65 local function render_list(incidents)
    65 local function render_list(incidents)
    66 	local layout = {
    66 	local layout = {
    67 		title = "Stored Incidents List",
    67 		title = "Stored Incidents List",
    68 		instructions = "You can select and view incident reports here, if a followup/response is possible it'll be noted in the step after selection.",
    68 		instructions = "You can select and view incident reports here, if a followup/response is possible it'll be noted in the step after selection.",
    69 		{ name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/commands" },
    69 		{ name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/commands" },
    70 		{ 
    70 		{
    71 			name = "ids",
    71 			name = "ids",
    72 			type = "list-single",
    72 			type = "list-single",
    73 			label = "Stored Incidents",
    73 			label = "Stored Incidents",
    74 			value = {}
    74 			value = {}
    75 		}
    75 		}
   104 		if contact.email then insert_fixed(layout, "--> E-Mail: "..contact.email) end
   104 		if contact.email then insert_fixed(layout, "--> E-Mail: "..contact.email) end
   105 		if contact.telephone then insert_fixed(layout, "--> Telephone: "..contact.telephone) end
   105 		if contact.telephone then insert_fixed(layout, "--> Telephone: "..contact.telephone) end
   106 		if contact.postaladdr then insert_fixed(layout, "--> Postal Address: "..contact.postaladdr) end
   106 		if contact.postaladdr then insert_fixed(layout, "--> Postal Address: "..contact.postaladdr) end
   107 	end
   107 	end
   108 
   108 
   109 	insert_fixed(layout, "Related Activity --")	
   109 	insert_fixed(layout, "Related Activity --")
   110 	for _, related in ipairs(incident.data.related) do
   110 	for _, related in ipairs(incident.data.related) do
   111 		insert_fixed(layout, string.format("Name: %s ID: %s", related.name, related.text))
   111 		insert_fixed(layout, string.format("Name: %s ID: %s", related.name, related.text))
   112 	end
   112 	end
   113 
   113 
   114 	insert_fixed(layout, "Assessment --")
   114 	insert_fixed(layout, "Assessment --")
   203 				email = email,
   203 				email = email,
   204 				telephone = telephone,
   204 				telephone = telephone,
   205 				postaladdr = postaladdr
   205 				postaladdr = postaladdr
   206 			}
   206 			}
   207 		else
   207 		else
   208 			object.contacts[#object.contacts + 1] = { 
   208 			object.contacts[#object.contacts + 1] = {
   209 				role = tag.attr.role,
   209 				role = tag.attr.role,
   210 				ext_role = (tag.attr["ext-role"] and true) or nil,
   210 				ext_role = (tag.attr["ext-role"] and true) or nil,
   211 				type = tag.attr.type,
   211 				type = tag.attr.type,
   212 				ext_type = (tag.attr["ext-type"] and true) or nil,
   212 				ext_type = (tag.attr["ext-type"] and true) or nil,
   213 				xmlns = jid.attr.xmlns,
   213 				xmlns = jid.attr.xmlns,
   224 				object.related[#object.related + 1] = { text = t:get_text(), name = tag.attr.name }
   224 				object.related[#object.related + 1] = { text = t:get_text(), name = tag.attr.name }
   225 			end
   225 			end
   226 		end
   226 		end
   227 	elseif tag.name == "Assessment" then
   227 	elseif tag.name == "Assessment" then
   228 		local impact = tag:get_child("Impact")
   228 		local impact = tag:get_child("Impact")
   229 		object.assessment = { lang = impact.attr.lang, severity = impact.attr.severity, completion = impact.attr.completion, type = impact.attr.type } 
   229 		object.assessment = { lang = impact.attr.lang, severity = impact.attr.severity, completion = impact.attr.completion, type = impact.attr.type }
   230 	elseif tag.name == "EventData" then
   230 	elseif tag.name == "EventData" then
   231 		local source = tag:get_child("Flow").tags[1]
   231 		local source = tag:get_child("Flow").tags[1]
   232 		local target = tag:get_child("Flow").tags[2]
   232 		local target = tag:get_child("Flow").tags[2]
   233 		local expectation = tag:get_child("Flow").tags[3]
   233 		local expectation = tag:get_child("Flow").tags[3]
   234 		object.event_data = { sources = {}, targets = {} }
   234 		object.event_data = { sources = {}, targets = {} }
   242 		end
   242 		end
   243 		for _, entry in ipairs(target.tags) do
   243 		for _, entry in ipairs(target.tags) do
   244 			local noderole = { cat = entry:get_child("NodeRole").attr.category, ext = entry:get_child("NodeRole").attr["ext-category"] }
   244 			local noderole = { cat = entry:get_child("NodeRole").attr.category, ext = entry:get_child("NodeRole").attr["ext-category"] }
   245 			local current = #object.event_data.targets + 1
   245 			local current = #object.event_data.targets + 1
   246 			object.event_data.targets[current] = { addresses = {}, noderole = noderole }
   246 			object.event_data.targets[current] = { addresses = {}, noderole = noderole }
   247 			for _, tag in ipairs(entry.tags) do				
   247 			for _, tag in ipairs(entry.tags) do
   248 				object.event_data.targets[current].addresses[#object.event_data.targets[current].addresses + 1] = { text = tag:get_text(), cat = tag.attr.category, ext = tag.attr["ext-category"] }
   248 				object.event_data.targets[current].addresses[#object.event_data.targets[current].addresses + 1] = { text = tag:get_text(), cat = tag.attr.category, ext = tag.attr["ext-category"] }
   249 			end
   249 			end
   250 		end
   250 		end
   251 		if expectation then 
   251 		if expectation then
   252 			object.event_data.expectation = { 
   252 			object.event_data.expectation = {
   253 				action = expectation.attr.action,
   253 				action = expectation.attr.action,
   254 				desc = expectation:get_child("Description") and expectation:get_child("Description"):get_text()
   254 				desc = expectation:get_child("Description") and expectation:get_child("Description"):get_text()
   255 			} 
   255 			}
   256 		end
   256 		end
   257 	elseif tag.name == "History" then
   257 	elseif tag.name == "History" then
   258 		object.history = {}
   258 		object.history = {}
   259 		for _, t in ipairs(tag.tags) do
   259 		for _, t in ipairs(tag.tags) do
   260 			object.history[#object.history + 1] = {
   260 			object.history[#object.history + 1] = {
   266 	end
   266 	end
   267 end
   267 end
   268 
   268 
   269 local function stanza_parser(stanza)
   269 local function stanza_parser(stanza)
   270 	local object = {}
   270 	local object = {}
   271 	
   271 
   272 	if stanza:get_child("report", xmlns_inc) then
   272 	if stanza:get_child("report", xmlns_inc) then
   273 		local report = st.clone(stanza):get_child("report", xmlns_inc):get_child("Incident", xmlns_iodef)
   273 		local report = st.clone(stanza):get_child("report", xmlns_inc):get_child("Incident", xmlns_iodef)
   274 		for _, tag in ipairs(report.tags) do do_tag_mapping(tag, object) end
   274 		for _, tag in ipairs(report.tags) do do_tag_mapping(tag, object) end
   275 	elseif stanza:get_child("request", xmlns_inc) then
   275 	elseif stanza:get_child("request", xmlns_inc) then
   276 		local request = st.clone(stanza):get_child("request", xmlns_inc):get_child("Incident", xmlns_iodef)
   276 		local request = st.clone(stanza):get_child("request", xmlns_inc):get_child("Incident", xmlns_iodef)
   293 			:tag("IncidentID", { name = object.id.name }):text(object.id.text):up()
   293 			:tag("IncidentID", { name = object.id.name }):text(object.id.text):up()
   294 			:tag("StartTime"):text(object.start_time):up()
   294 			:tag("StartTime"):text(object.start_time):up()
   295 			:tag("EndTime"):text(object.end_time):up()
   295 			:tag("EndTime"):text(object.end_time):up()
   296 			:tag("ReportTime"):text(object.report_time):up()
   296 			:tag("ReportTime"):text(object.report_time):up()
   297 			:tag("Description", { ["xml:lang"] = object.desc.lang }):text(object.desc.text):up():up();
   297 			:tag("Description", { ["xml:lang"] = object.desc.lang }):text(object.desc.text):up():up();
   298 		
   298 
   299 		local incident = stanza:get_child(s_type, xmlns_inc):get_child("Incident", xmlns_iodef)		
   299 		local incident = stanza:get_child(s_type, xmlns_inc):get_child("Incident", xmlns_iodef)
   300 
   300 
   301 		for _, contact in ipairs(object.contacts) do
   301 		for _, contact in ipairs(object.contacts) do
   302 			incident:tag("Contact", { role = (contact.ext_role and "ext-role") or contact.role,
   302 			incident:tag("Contact", { role = (contact.ext_role and "ext-role") or contact.role,
   303 						  ["ext-role"] = (contact.ext_role and contact.role) or nil,
   303 						  ["ext-role"] = (contact.ext_role and contact.role) or nil,
   304 						  type = (contact.ext_type and "ext-type") or contact.type,
   304 						  type = (contact.ext_type and "ext-type") or contact.type,
   306 				:tag("Email"):text(contact.email):up()
   306 				:tag("Email"):text(contact.email):up()
   307 				:tag("Telephone"):text(contact.telephone):up()
   307 				:tag("Telephone"):text(contact.telephone):up()
   308 				:tag("PostalAddress"):text(contact.postaladdr):up()
   308 				:tag("PostalAddress"):text(contact.postaladdr):up()
   309 				:tag("AdditionalData")
   309 				:tag("AdditionalData")
   310 					:tag("jid", { xmlns = contact.xmlns }):text(contact.jid):up():up():up()
   310 					:tag("jid", { xmlns = contact.xmlns }):text(contact.jid):up():up():up()
   311 	
   311 
   312 		end
   312 		end
   313 
   313 
   314 		incident:tag("RelatedActivity"):up();
   314 		incident:tag("RelatedActivity"):up();
   315 
   315 
   316 		for _, related in ipairs(object.related) do
   316 		for _, related in ipairs(object.related) do
   317 			incident:get_child("RelatedActivity")			
   317 			incident:get_child("RelatedActivity")
   318 				:tag("IncidentID", { name = related.name }):text(related.text):up();
   318 				:tag("IncidentID", { name = related.name }):text(related.text):up();
   319 		end
   319 		end
   320 
   320 
   321 		incident:tag("Assessment")
   321 		incident:tag("Assessment")
   322 			:tag("Impact", { 
   322 			:tag("Impact", {
   323 				lang = object.assessment.lang,
   323 				lang = object.assessment.lang,
   324 				severity = object.assessment.severity,
   324 				severity = object.assessment.severity,
   325 				completion = object.assessment.completion,
   325 				completion = object.assessment.completion,
   326 				type = object.assessment.type
   326 				type = object.assessment.type
   327 			}):up():up();
   327 			}):up():up();
   360 			end
   360 			end
   361 		end
   361 		end
   362 
   362 
   363 		if object.history then
   363 		if object.history then
   364 			local history = incident:tag("History"):up();
   364 			local history = incident:tag("History"):up();
   365 			
   365 
   366 			for _, item in ipairs(object.history) do
   366 			for _, item in ipairs(object.history) do
   367 				history:tag("HistoryItem", { action = item.action })
   367 				history:tag("HistoryItem", { action = item.action })
   368 					:tag("DateTime"):text(item.date):up()
   368 					:tag("DateTime"):text(item.date):up()
   369 					:tag("Description"):text(item.desc):up():up();
   369 					:tag("Description"):text(item.desc):up():up();
   370 			end	
   370 			end
   371 		end
   371 		end
   372 
   372 
   373 		-- Sanitize contact empty tags
   373 		-- Sanitize contact empty tags
   374 		for _, tag in ipairs(incident) do
   374 		for _, tag in ipairs(incident) do
   375 			if tag.name == "Contact" then
   375 			if tag.name == "Contact" then
   376 				for i, check in ipairs(tag) do
   376 				for i, check in ipairs(tag) do
   377 					if (check.name == "Email" or check.name == "PostalAddress" or check.name == "Telephone") and
   377 					if (check.name == "Email" or check.name == "PostalAddress" or check.name == "Telephone") and
   378 					   not check:get_text() then
   378 					   not check:get_text() then
   379 						table.remove(tag, i) 
   379 						table.remove(tag, i)
   380 					end
   380 					end
   381 				end	
   381 				end
   382 			end
   382 			end
   383 		end
   383 		end
   384 
   384 
   385 		if s_type == "request" then stanza.attr.type = "get"
   385 		if s_type == "request" then stanza.attr.type = "get"
   386 		elseif s_type == "response" then stanza.attr.type = "set"
   386 		elseif s_type == "response" then stanza.attr.type = "set"
   387 		else stanza.attr.type = "set" end 
   387 		else stanza.attr.type = "set" end
   388 
   388 
   389 		return stanza
   389 		return stanza
   390 	end
   390 	end
   391 end 
   391 end
   392 
   392 
   393 
   393 
   394 _M = {} -- wraps methods into the library.
   394 _M = {} -- wraps methods into the library.
   395 _M.ft_str = ft_str
   395 _M.ft_str = ft_str
   396 _M.get_incident_layout = get_incident_layout
   396 _M.get_incident_layout = get_incident_layout