#!/FedTest/cgi-bin python
# -*- coding: utf-8 -*-
#print "============  S T A R T ================"

# @(#) ft_mdt_prt_test_report.py Version 1.2 04/26/18 10:11:19
import sys
from sys import stdin
from sys import stdout
import os
import re
import datetime
import time
import hashlib
import subprocess
from ft_mdt_elements import mk_home_link
from ft_mdt_elements import s_quest, p_quest, data_elements, sim_elements
now = datetime.datetime.now()

elist = []
#############################################################
#                                                           #
#  Generate Federated Testing Report -- Mobile Device Tool  #
#                                                           #
#                                                           #
#############################################################

def get_ver():
	# find: where is our federated testing version and release information?	
	if os.access('/FedTest/HTDOCS/include/global.php',os.F_OK) == 1:
		vname = '/FedTest/HTDOCS/include/global.php'
	elif os.access('/FedTest/HTDOCS/include/global.php',os.F_OK) == 1:
		vname = '/FedTest/HTDOCS/include/global.php'
	else:
		vname = ''
		
	if vname != '':
		vfile = open (vname,"rt")
		n = 2
		rel_date = "Unknown"
		rel_ver = "Unknown"
		for line in vfile:
			pass
			if line.startswith("$release_date"):
				rel_date = line.split('"')[1]
				n = n - 1
			if line.startswith("$version"):
				rel_ver = line.split('"')[1]
				n = n - 1
			if n == 0: break
		vfile.close()
		return "Federated Testing Version %s, released %s"%(rel_ver,rel_date)
	else: return "Unknown Version"

def do_comments(root,p_list,is_sim,caption):
#	print 'Comments for ',caption
# look at each phone in list
# if not is_sim, get general comment
# make a list of groups with comments
# for each group
#     for each phone
#       print comment

#	print 'Phones:',p_list
	comments = {}
	for p in p_list:
#	cfile_name = root + phone[0] + '_comment.txt'
# phone_list[px][1]+phone_list[px][2]
#		print '*************** Look at:',p,phone_list[p][1]+phone_list[p][2]
		cfile_name = root + p + '_comments.txt'
#		print '@@@@@@@@@@@@@@@@@ get file: ',cfile_name
		if os.access(cfile_name,os.F_OK):
			cfile = open(cfile_name,"rt")
#			print "++++++++++ %s"%(cfile_name)
			c = cfile.read()
			cfile.close()
#			print 'Comment:',c
			groups = re.findall('<MDC.*?</MDC>',c,flags=re.DOTALL)
			for gr in groups:
#				print "***********"
#				print gr
				if gr.find ('>\n\n</MDC') != -1:
					continue
#					print "@@@@@@@@@@@@ D E L E T E"
#				print "-----------"
				gr = gr.replace('\r\n','\n')
				gr = gr.replace('\n\r','\n')
				gr = gr.replace('\n\n','\n')
				gr = gr.replace('\r\r','\n')
				at = gr.find ('=') + 6
				tail = gr.find('>')
				eoc = gr.find('</MDC>')
				element = gr[at:tail]
#				print 'EEEEEEEEEEEE:',element,element in comments,is_sim
				note = gr[tail+2:eoc-1]
				if is_sim:
					if element[0:2] == 'sc':
						if element not in comments: comments[element] = {}
						comments[element][p] = note
#						print 'Add %s for %s << IS SD'%(element,p)
				else:
					if element[0:2] != 'sc':
						if element not in comments: comments[element] = {}
						comments[element][p] = note
#						print 'Add %s for %s << NOT SD'%(element,p)
		else:
			elist.append(cfile_name)
#			print 'no access to',cfile_name
#	print 'Elements seen:',comments.keys()

#	print '#####################################'
	if len(comments) == 0: return
	html.write ('<h3>Comments for %s</h3>\n'%(caption))
	html.write('<table>\n')

	html.write('<caption>\n')
	html.write (caption)
	html.write('</caption>\n')
	html.write ('<tr>\n')
	html.write ('<th>Data Element</th>\n')
	html.write ('<th>Device</th>\n')
	html.write ('<th>Comment</th>\n')
	html.write ('</tr>\n')
	e_keys = comments.keys()
	e_keys.sort()
	for e in e_keys:
#		print 'Element:',e
		if e == 'general':group_label = 'General'
		elif e[0:2] == 'md': group_label = p_quest[int(e[-2:])][0]
		else: group_label = s_quest[int(e[-2:])][0]
		html.write('<tr>\n')
		p_keys = comments[e].keys()
		p_keys.sort()
		html.write('<td rowspan=%d>\n'%(len(p_keys)))
		html.write(group_label)
		html.write('</td>\n')
		for p in p_keys:
			html.write('<td>\n')
			html.write(phone_list[p][1]+' '+phone_list[p][2])
			html.write('</td>\n')
			html.write('<td><ul><li>\n')
			html.write(re.sub('\n','</li><li>',comments[e][p]))
			html.write('</li></ul></td>\n')
#			print '\t',p
#			print '\t\t',comments[e][p]
			html.write('</tr>\n')

	html.write('</table>\n')

def mk_result_table (q,phones,phone_list,label,d,setup,device):

	tx = {'ok':'as expected','part':'partial','na':'N/A',
		'no':'not as expected','populated':'populated',
		'omitted':'omitted'}
	html.write("<table>\n")
	html.write("<tr>")
	html.write('<th bgcolor="AAAAAA" colspan=2>')
#	html.write("Test Cases -- Internal Memory Acquisition")

	if setup == 'setup':
		html.write("Data Objects")
	else:
		if device == 'device':
			html.write("Test Results -- Internal Memory Acquisition")
		else:
			html.write("Test Results -- SIM/UICC Acquisition")

	html.write("</th>")
	for px in phones:
		html.write('<th bgcolor="AAAAAA">')
		html.write(phone_list[px][1]+phone_list[px][2])
		html.write("</th>")
	html.write("</tr>\n")
	keys = q.keys()
	keys.sort()
	rx = 1
	for ix in keys:
		row = q[ix][0]
		subs = q[ix][1:]
		n = len(subs)
		html.write("<tr>")
		html.write ('<td bgcolor="E0E0E0" rowspan=%d>%s</td>'%(n,row))
		first = True
		new_row = ''
		for sub in subs:
		
			if new_row != '': html.write( new_row)
			if rx%2 == 1:
				html.write('<td bgcolor="F3F3F3">')
				bgx = 'FFFFFF'
			else:
				html.write('<td bgcolor="AAAAAA">')
				bgx = 'E0E0E0'
			rx += 1
			xx = "%02d"%(sub[0])
			item = label+xx
			html.write(sub[1])
			html.write("</td>")
			for px in phones:
				html.write('<td bgcolor="%s">'%(bgx))
				if px in d:
					if item in d[px]:
						html.write(tx[d[px][item]])
					else:
						html.write('NO DATA')
				else:
					html.write('NO DATA')
				html.write("</td>")
			html.write("</tr>\n")
			new_row = '</tr><tr>'
			first = False
	html.write("</table>")

if os.access('/FedTest/media/cftt/FT-LOGS/',os.F_OK):
	root = '/FedTest/media/cftt/FT-LOGS/'
elif os.access('/FedTest/media/cftt/FT-LOGS/',os.F_OK):
	root = '/FedTest/media/cftt/FT-LOGS/'
else:
	root = '/FedTest/media/cftt/FT-LOGS/'


start_time = str(datetime.datetime.now())
start_at = start_time
start_time = re.sub(r'\.[0-9]*','',start_time)
start_time = re.sub('[ :]','+',start_time)
html_file_name = "test-report-mdt-"+start_time+".html"
html_file = root+html_file_name
try:
	html = open(html_file,"wt")
except IOError as e:
	html = stdout
try:
	sd = open("/FedTest/media/cftt/FT-LOGS/mdt-test-report-dribble.txt","wt")
except IOError as e:
	sd = open("/FedTest/media/cftt/FT-LOGS/null.txt","wt")

#os_info = os.uname()
#ver = "Tool: @(#) ft_mdt_prt_test_report.py Version 1.2 created 04/26/18 at 10:11:19\n"+"<br>OS: %s Version %s\n"%(
#	os_info[0],os_info[2])
sd.write ('Generate Mobile Device Test Report\n')
#sd.write(ver+'\n')
sd.write ('Start: '+start_at+'\n')

sd.write("Args:"+str(sys.argv)+'\n')
sd.write('Full report\n'+html_file+'\n')


head = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html; charset=UTF-8"
 http-equiv="Content-Type">
  <title>Test Results for Mobile Device Acquisition Tool</title>
  <meta content="J Lyle NIST/CFTT" name="author">
  <meta content="Federated Testing Mobile Device Acquisition Test Results"
 name="description">
	<style>
	em.x {color: green;font-size: 100%;font-style:italic;font-weight:bold;}
	em.p {bgcolor: green;font-size: 100%;font-weight:bold;}
	th {
	   border-collapse: collapse;
	   border: 1px solid black;
	   text-align: center;
	   } 
	table, th, td {
	   border-collapse: collapse;
	   border: 1px solid black;
	   } 

body {
counter-reset: chapter;
}
h1 {
counter-increment: chapter;
counter-reset: section;
}
h2 {
counter-increment: section;
counter-reset: sub;
}

h3 {
counter-increment: sub;
}
h1:before {
content: counter(chapter) ". ";
}
h2:before {
content: counter(chapter) "." counter(section) " ";
}

h3:before {
content: counter(chapter) "." counter(section) "." counter(sub) " ";
}
	</style>
</head>
<body>
"""
tail = """
</body>
</html>
"""

report_header_text_part_1 = '''
<em class="x">
Text formatted like this (Bold, Italics and Green) should be
removed and replaced. These are instructions
to the report writer.
</em>
<h1>Tool Description</h1>
<p>Tool Name: %s
<br>Tool Version: %s
<br>Vendor: 
<font color="green"><b><i>Insert vendor name and contact information.
<font color="black"></b></i>
'''
report_header_text_part_2 = '''
<h1>Testing Organization</h1>
<font color="green"><b><i>The following items
in this section may be included or omitted as per organization's
policy for tool test reports.<font color="black"></b></i>
<br>Organization conducting test:
<font color="green"><b><i>Insert Organization name.<font color="black"></b></i>
<br>Contact:
<font color="green"><b><i>Insert contact name.<font color="black"></b></i>
<br>Report date:
<font color="green"><b><i>Insert date.<font color="black"></b></i>
<br>Authored by:
<font color="green"><b><i>Insert author name.<font color="black"></b></i>
<br>Reviewed by:
<font color="green"><b><i>Insert name of reviewer.<font color="black"></b></i>
<br>Reviewed by date:
<font color="green"><b><i>Insert date.<font color="black"></b></i>
<br>Approved:
<font color="green"><b><i>Insert name of approving official.<font color="black"></b></i>
<br>Approved by date:
<font color="green"><b><i>Insert date.<font color="black"></b></i>
<br>
<br>This test report was generated using CFTT's Federated Testing Forensic
Tool Testing Environment, see <a href="http://www.cftt.nist.gov/federated-testing.html">
Federated Testing Home Page</a>.
<br>
<h1>How to Read This Report</h1>
This report is organized into the following sections:
<br><em class=x>Of course, you can reorganize sections, but then you should update
this list.</em><br>
<ol>
<li>Tested Tool Description. The tool name, version and vendor information are listed.
<li>Testing Organization. Contact information and approvals.
<li>How to Read This Report (this section).
<li>Results Summary. This section identifies any significant anomalies
observed in the test runs.
This section provides a narrative of key findings identifying where the tool meets
expectations and provides a summary of any ways the tool did not
meet expectations.
The section also provides any observations of interest about the tool or about testing
the tool including any observed limitations or organization imposed
restrictions on tool use.
<li>Test Environment. Description of hardware and software used in tool testing in
sufficient detail to satisfy the testing organization's policy and requirements.
<li>Mobile Devices Used in Testing. A table describing each mobile device used in testing. Includes
the make, model, operating system, firmware version and network of each device.
<li>Device and SIM/UICC Card Setup. List of data elements populated to each device and SIM/UICC card.
<li>Test Result Details by Device.
</ol>
<h1>Results Summary</h1>
<em class=x>
Provide a narrative of key findings -- did the tool meet
expectations. If not provide a summary of how the tool did not
meet expectations.
Provide any observations of interest about the tool or about testing
the tool including any observed limitations or organization imposed
restrictions on tool use.
</em>
<!-- <h1>Test Environment & Selected Cases</h1> -->
<h1>Test Environment</h1>
<p>This section describes any additional hardware or software used in testing.</p>
Hardware:
<font color="green"><b><i>List and describe any hardware used during testing in sufficient detail
to repeat the tests.<font color="black"></b></i><br>
<br>Software:
<font color="green"><b><i>List and describe any additional software used during
testing in sufficient detail
to repeat the tests.<font color="black"></b></i>
'''
main_section = '''
<h1>Test Result Details by Case</h1>
This section presents test results grouped by function.
'''

test_results_old = '''

This section provides the test cases results reported by the tool.
 Sections 4.1 – 4.3 identify the mobile device operating system type
 (e.g., Android, iOS) and the make and model of mobile devices used
 for testing %s Version %s
<br><br>
The Test Cases column (internal memory acquisition) in the following
 subsections are comprised of two sub-columns that define a
 particular test category and individual sub-categories that are
 verified when acquiring the internal memory for supported mobile
 devices and SIM/UICCs within each test case. 
 Each individual sub-category row results for each mobile
 device or SIM/UICC tested.  The results are as follows:

<br><br>
As Expected: the mobile forensic application returned expected
test results – the tool acquired and reported data from the
mobile device or SIM/UICC successfully.

<br><br>
Partial: the mobile forensic application returned some of data
from the mobile device or SIM/UICC.

<br><br>
Not As Expected: the mobile forensic application failed to return
expected test results – the tool did not acquire or
report supported data from the mobile device or SIM/UICC successfully.

<br><br>
NA: Not Applicable – the mobile forensic application is unable
to perform the test or the tool does not provide support for the
acquisition for a particular data element. 
'''

test_results = '''

This section provides the test results from testing %s Version %s. 
<br><br>
The Test Results column (Internal Memory Acquisition / SIM/UICC Acquisition) in the following
 subsections are comprised of two sub-columns that define a
 particular test category and individual sub-categories that are
 verified when acquiring the internal memory for supported mobile
 devices and SIM/UICCs. 
 Each individual sub-category row shows results for each mobile
 device or SIM/UICC tested.  The results are as follows:

<br><br>
As Expected: the mobile forensic application returned expected
test results – the tool acquired and reported data from the
mobile device or SIM/UICC successfully.

<br><br>
Partial: the mobile forensic application returned some of data
from the mobile device or SIM/UICC.

<br><br>
Not As Expected: the mobile forensic application failed to return
expected test results – the tool did not acquire or
report supported data from the mobile device or SIM/UICC successfully.

<br><br>
NA: Not Applicable – the mobile forensic application is unable
to perform the test or the tool does not provide support for the
acquisition for a particular data element. 
'''

table_head = """
<table style="text-align: left;" border="2" cellpadding="2" cellspacing="2">
<tbody>
"""

table_tail = """
</tbody>
</table>
"""

#######################################################
#     main
#########################################################
#########################################################
########### S t a r t    H e r e ########################
#########################################################
#########################################################


conf = "mdt-config.txt"
sd.write("START\n")


html.write(head+'\n')
if not os.access(root+conf,os.F_OK):
	sd.write("There is no %s in %s\n"%(conf,root))
	#html.write("<h1>There is no %s in %s</h1>\n"%(conf,root))
	#html.write('<h1>Go back and enter a tool name & version</h1>')
	html.write("<h1>WARNING - Missing tool name and version (there is no %s in %s)! \n"%(conf,root))
	html.write('Please go back to the \'Enter Tool Name and Version\' page and enter a tool name and version.</h1>')
	tool_name = 'No name given'
	tool_version = 'No Version given'
else:
	config_file = open(root+conf,"rt")
	tool_name = config_file.readline().strip()
	tool_version = config_file.readline().strip()
	

#print tool_name,tool_version
#html.write(head)
html.write('''<p style="font-size:1.8em"><b>Test Results for Mobile Device Acquisition Tool:<br>
	%s Version %s</b></p>\n'''%(tool_name,tool_version))
html.write(report_header_text_part_1%(tool_name,tool_version))
html.write(report_header_text_part_2)


############## Device List ###############

html.write('<h1>Mobile Devices Used in Testing</h1>')
html.write("<p>The following table lists the mobile devices used in testing %s version %s.</p>"%(
	tool_name,tool_version))
phone_list = {}
if os.access (root+'/'+"devices.txt",os.F_OK):
	pfile = open(root+'/'+"devices.txt","rt")
	for line in pfile:
		fields = line.strip().split(';')
		if len(fields) == 8:
			phone_list[fields[0]] = fields
#html.write("<br>")
#for px in phone_list:
#	html.write("<p>px %s %s\n"%(px,str(phone_list[px])))
html.write("<table>\n")
html.write("<caption>")
html.write("Mobile Devices Used in Testing %s Version %s"%(
	tool_name,tool_version))
html.write("</caption>")
###################### ROW ##################
html.write("<tr>")
html.write("<th>Make</th>")
html.write("<th>Model</th>")
html.write("<th>OS</th>")
html.write("<th>Version</th>")
html.write("<th>Firmware</th>")
html.write("<th>Network</th>")
html.write("<th>SIM/UICC</th>")
html.write("</tr>\n")
####################### ROW ##################
p_keys = phone_list.keys()
p_keys.sort()
for px in p_keys:
#for phone in phone_list:
	phone = phone_list[px]
	html.write("<tr>")
	for field in phone[1:]:
		html.write("<td>")
		if field == 'sim': html.write ('SIM/UICC')
		elif field == 'nosim': html.write('No SIM/UICC')
		else: html.write(field)
		html.write("</td>")
	html.write("</tr>\n")
####################### End of ROW ##################
html.write("</table>")

############## END of Device List ###############


ios_phones = []
ios_sims = []
and_phones = []
and_sims = []
other_phones = []
other_sims = []
for px in phone_list:
	phone = phone_list[px]
	if phone[3] == 'iOS':
		ios_phones.append(phone[0])
		if phone[7] == 'sim': ios_sims.append(phone[0])
	elif phone[3] == 'Android':
		and_phones.append(phone[0])
		if phone[7] == 'sim': and_sims.append(phone[0])
	else:
		other_phones.append(phone[0])
		if phone[7] == 'sim': other_sims.append(phone[0])
##############################################################

ios_phones.sort()
and_phones.sort()
other_phones.sort()
ios_sims.sort()
and_sims.sort()
other_sims.sort()

#print '++++++++++++++++++++++++++++++'
#print ios_sims
#print '++++++++++++++++++++++++++++++'
#print and_sims
#print '++++++++++++++++++++++++++++++'
#print other_sims
#print '++++++++++++++++++++++++++++++'

########################## get data for each device ###########
root_files = os.listdir(root)
data_files = []
item_set = set()
for f in root_files:
	if f.startswith('phone') and f.find('comment') == -1:
		data_files.append(f)
#html.write('<p>files:')
#for f in data_files:
#	html.write(' '+f)
#html.write('<p>end file list')
d = {}
#print 'FILE LIST:',data_files
for f_name in data_files:
	phone = f_name[0:7]
	if phone not in d: d[phone] = {}
#	print 'PHONE PHONE . . .',phone,f_name
	for line in open(root+'/'+f_name,'rt'):
		(item,value) = line.strip().split(':')
		d[phone][item] = value


#print '==============='
#print phone_list
#print '==============='
#print ios_phones
#print len(ios_phones)
#print '==============='
html.write('<h1>Device and SIM/UICC Card Setup</h1>')
html.write('<p>The following sections describe the data objects populated onto the internal memory of the test mobile devices and SIM/UICCs.</p>')
if len(ios_phones) > 0:
	html.write("<h2>Setup for iOS Devices and SIM/UICC Cards</h2>")
	html.write("<h3>Setup for iOS Devices</h3>")
	mk_result_table (data_elements,ios_phones,phone_list,'dev_init_',d,'setup','device')
	if len(ios_sims) > 0:
		html.write("<h3>Setup for SIM/UICC cards in iOS Devices</h3>")
		mk_result_table (sim_elements,ios_sims,phone_list,'sim_init_',d,'setup','device')
if len(and_phones) > 0:
	html.write("<h2>Setup for Android Devices and SIM/UICC Cards</h2>")
	html.write("<h3>Setup for Android Devices</h3>")
	mk_result_table (data_elements,and_phones,phone_list,'dev_init_',d,'setup','device')
	if len(and_sims) > 0:
		html.write("<h3>Setup for SIM/UICC cards in Android Devices</h3>")
		mk_result_table (sim_elements,and_sims,phone_list,'sim_init_',d,'setup','device')
if len(other_phones) > 0:
	html.write("<h2>Setup for Other (non-Android & non-iOS) Devices and SIM/UICC Cards</h2>")
	html.write("<h3>Setup for Other (non-Android & non-iOS) Devices</h3>")
	mk_result_table (data_elements,other_phones,phone_list,'dev_init_',d,'setup','device')
	if len(other_sims) > 0:
		html.write("<h3>Setup for SIM/UICC cards in Other (non-Android & non-iOS) Devices</h3>")
		mk_result_table (sim_elements,other_sims,phone_list,'sim_init_',d,'setup','device')



###########################################################
html.write('<h1>Test Results</h1>')
html.write(test_results%(tool_name,tool_version))
########################## Start Comments Section #############

if len(ios_phones) > 0:
	html.write('\n<h2>Results for iOS Devices and SIM/UICC cards in iOS Devices</h2>')
	do_comments(root,ios_phones,False,'iOS Devices')
	html.write("<br>")

	html.write("<h3>Results for iOS Devices</h3>")
	mk_result_table (p_quest,ios_phones,phone_list,'dev_data_',d,'results','device')
	html.write("<br>")
	html.write("<br>")
	if len(ios_sims) > 0:
		do_comments(root,ios_sims,True,'SIM/UICC Cards in iOS Devices')
		html.write("<h3>Results for SIM/UICC cards in iOS Devices</h3>")
		mk_result_table (s_quest,ios_sims,phone_list,'sim_data_',d,'results','sim')

if len(and_phones) > 0:
	html.write("<h2>Results for Android Devices and SIM/UICC cards in Android Devices</h2>")
	do_comments(root,and_phones,False,'Android Devices')
	html.write("<h3>Results for Android Devices</h3>")
	mk_result_table (p_quest,and_phones,phone_list,'dev_data_',d,'results','device')
	if len(and_sims) > 0:
		do_comments(root,and_phones,True,'SIM/UICC Cards in Android Devices')
		html.write("<h3>Results for SIM/UICC cards in Android Devices</h3>")
		mk_result_table (s_quest,and_sims,phone_list,'sim_data_',d,'results','sim')


if len(other_phones) > 0:
	html.write("<h2>Results for Other Devices and SIM/UICC cards in Other Devices</h2>")
	do_comments(root,other_phones,False,'Other Devices')
	html.write("<h3>Results for Other Devices</h3>")
	mk_result_table (p_quest,other_phones,phone_list,'dev_data_',d,'results','device')
	if len(other_sims) > 0:
		do_comments(root,other_sims,True,'SIM/UICC Cards in Other Devices')
		html.write("<h3>Results for SIM/UICC cards in Other Devices</h3>")
		mk_result_table (s_quest,other_sims,phone_list,'sim_data_',d,'results','sim')


finish_time = str(datetime.datetime.now())
#html.write("<br>\n")
#csr html.write (ver+'\n<br>')
html.write("Done: "+finish_time+'\n')
html.write("<br>\n")
html.write('\n'+get_ver()+'\n')
#html.write("<br>\n")

#html.write('<br><p>REPORT saved to %s'%(html_file))
html.write('<br><p>END of REPORT')
html.write('</body></html>')
# print "Content-Type: text/html\n\n"
# print "<html>"
# print "<TITLE>Generate Test Report</TITLE>"
# print "<body><H1>"
# print 'REPORT saved to %s'%(html_file)
# print "</H1>"
# if not os.access(root+conf,os.F_OK):
# 	print '<h1>You need to go back and enter the tool name & version</h1>'
# print mk_home_link ()
# print "<p>Done: %s" % now.strftime("%A, %B %d, %Y at %H:%M")
# print "</body>"
# print "</html>"
print html_file_name
exit(0)
