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

# @(#) ft_hwb_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

now = datetime.datetime.now()

#############################################################
#                                                           #
#  Generate Federated Testing Report -- Hardware Write Block#
#                                                           #
#                                                           #
#############################################################

# extract version info 
vlist = set()
def vcheck(line):
	if line.find('Tool:') >= 0:
		line = line[6:]
	at = line.find('@(#)')
	#if at >= 0:
	if at >= 0 and line.find('test-hwb.c') >= 0:
		vlist.add(line[at+5:].strip())
	elif line.find('%'+'Z%') >= 0: vlist.add('Uncontrolled Version')
	return

def get_ver():
	# find: where is our federated testing version and release information?	
	if os.access('/var/www/include/global.php',os.F_OK) == 1:
		vname = '/var/www/include/global.php'
	elif os.access('/Applications/MAMP/fedtesting/working/htdocs/include/global.php',os.F_OK) == 1:
		vname = '/Applications/MAMP/fedtesting/working/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"

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

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-hwb-"+start_time+".html"
html_file = root+html_file_name
try:
	html = open(html_file,"wt")
except IOError as e:
	html = stdout
try:
	sd = open("/tmp/hwb-test-report-dribble.txt","wt")
except IOError as e:
	sd = open("/dev/null","wt")

os_info = os.uname()
ver = "Tool: @(#) ft_hwb_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])

drive_dict = {"pcie": "PCIe",
	"sata": "SATA",
	"ata": "ATA/IDE",
	"usb": "USB",
	"esata": "eSATA",
	"firewire": "FireWire",
	"sas": "SAS",
	"scsi": "SCSI",
	"sd": "SD",
	"microsd": "MicroSD",
	"compactflash": "Compact Flash",
	"mmc": "MMC",
	"memorystick": "Memory Stick (e.g., PRO, Duo, Micro)",
	"xd": "xD",
	"smartmedia": "Smart Media"
	}

conn_dict ={"usb3": "USB 3",
	"usb2": "USB 2",
	"firewire800": "FireWire 800",
	"firewire400": "FireWire 400",
	"esata": "eSATA"}

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 Hardware Write Block Tool</title>
  <meta content="J Lyle NIST/CFTT" name="author">
  <meta content="Federated Testing Hardware Write Block 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>Firmware Version: %s
<br>Tool Manufacturer: %s
<br><br><font color="green"><b><i>Insert tool manufacturer contact information.
<font color="black"></i></b>
'''
report_header_text_part_2 = '''
<br><br>
<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>Test Result Details by Case. Automatically generated test results that identify anomalies.
<li>Appendix: Additional details. Additional details for each test case.
</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</h1>
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><br>
<br>%s Firmware Version: %s
'''
main_section = '''
<h1>Test Result Details by Case</h1>
This section presents test results grouped by case.
'''

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 = "hwb-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>WARNING - There is no %s in %s (you probably haven't run any Hardware Write Block tests yet)</h1>\n"%(conf,root))

# generatefinalreport.php expects the test report filename printed to stdout...
print html_file_name

try:
	config_file = open(root+conf,"rt")
except IOError as e:
	exit(0)

config = {}
config['drive'] = []
for line in config_file:
#	print line,
	if line.startswith('blockertype'):
		config['type'] = line[line.find(' '):-1].strip()
	if line.startswith('manufacturer'):
		config['vendor'] = line[line.find(' '):-1].strip()
		pass
	if line.startswith('model'):
		config['model'] = line[line.find(' '):-1].strip()
		pass
	if line.startswith('firmware'):
		config['fw'] = line[line.find(' '):-1].strip()
	if line.startswith('connections'):
		config['iface'] = []
		for ifc in line[line.find(' '):-1].split():
			config['iface'].append(ifc)
	#if line.startswith('FT-HWB-'):
	#	config['drive'].append(line.strip())
	if line.startswith('FT-HWB-'):
		stripped = line.strip()
		splitted = stripped.split("-")
		config['drive'].append(splitted[2])		
#print '--------------------'
#print config
#print '--------------------'
#print tool_name,tool_version
html.write(head)
html.write('''<p style="font-size:1.8em"><b>Test Results for Hardware Write Block Tool:<br>
	%s %s Firmware Version %s</b></p>\n'''%(config['vendor'],config['model'], config['fw']))
#html.write("blip-1")
html.write(report_header_text_part_1%(config['model'],config['fw'],config['vendor']))
#html.write("blip-2")
html.write(report_header_text_part_2%(config['model'],config['fw']))

desc_old='''
<h3>Test Case Description</h3>
Test a write blocker’s ability to write-protect %s.
This test can be repeated to test multiple types of connections
(interfaces) between a computer and the write blocker.
Test the ability of the write blocker to block write commands
from the ATA and SCSI command sets issued from a test computer from
modifying %s.

<h3>Test %s Description</h3>
Test %s make, model & size: <font color="green"><i><b>List the make, model and size for the test %s you used for this test.</i></b><font color="black">

<h3>Test Evaluation Criteria</h3>
For each computer to blocker connection tested,
the number of ‘writes not blocked’ should be 0.

<h3>Test Case Results</h3>
The following table presents results for the test case.
<br>
<br>
'''

desc='''
<h3>Test Case Description</h3>
Test a write blocker’s ability to write-protect %s.
This test can be repeated to test multiple types of connections
(interfaces) between a computer and the write blocker.
Test the ability of the write blocker to block write commands
from the ATA and SCSI command sets issued from a test computer from
modifying %s.

<h3>Test %s Description</h3>
Manufacturer, model & size of the test %s used for this test: <font color="green"><i><b>List the manufacturer, model and size for the test %s you used for this test.</i></b><font color="black">

<h3>Test Evaluation Criteria</h3>
For each computer to blocker connection tested,
the number of ‘writes not blocked’ should be 0.

<h3>Test Case Results</h3>
The following table presents results for the test case.
<br>
<br>
'''

########################## get data for each device ###########
root_files = os.listdir(root)
#print root_files
#html.write('<h1>Test Report Details by Case</h1>\n')
html.write(main_section)
obs = '''
<em class="x">
<p>INSERT ANY DISCUSSION, COMMENTS OR OBSERVATIONS HERE.
</em>
'''

config['drive'].sort()
config['iface'].sort()
# iterate over the list of test cases (drive/media types tested)
for dri in config['drive']:
	testcase_dir = "FT-HWB-"+dri
	html.write('<h2>FT-HWB-%s</h2>\n'%(drive_dict[dri]))
	if testcase_dir in root_files:
#		print dr,'found'
		# are we working with drive or media card types?
		if config['type'] == "drive":
			m_type = "drive"
			cap_m_type = "Drive"
		else:
			if dri == "usb": # USB is special...
				m_type = "drive"
				cap_m_type = "Drive"
			else:
				m_type = "media card"
				cap_m_type = "Media Card"
		# use "a" vs "an"
		first = dri[0]
		if first in 'aeiou':
			desc_str = "an "+drive_dict[dri]+" "+m_type
			html.write(desc%(desc_str, desc_str, cap_m_type, m_type, m_type))			
		else:
			desc_str = "a "+drive_dict[dri]+" "+m_type
			html.write(desc%(desc_str, desc_str, cap_m_type, m_type, m_type))

		if not os.access(root+testcase_dir,os.F_OK): continue
		#dr_files = os.listdir(root+'/'+testcase_dir)
		dr_files = os.listdir(root+testcase_dir)
#		print dr_files
		res_tab = {}
		count = 0
		# There should be a log file for each of the interfaces/connections from hwb-config.txt.
		# iterate over and process each one.  
		for ifc in config['iface']:
			iff = ''
#			print 'search for',ifc
			# try to find the log file created when the current interface was tested 
			for d_file in dr_files:
				if d_file.startswith(ifc):
					iff = d_file
					break
#			print 'Found log file for',ifc,iff
#			html.write('<p>%s</p>\n'%(iff))
			line_no = 0
			if iff == '': continue
			if not os.access(root+testcase_dir+'/'+iff,os.F_OK): continue
			#lf = open(root+'/'+testcase_dir+'/'+iff)
			# open the log file for the current interface we're processing
			lf = open(root+testcase_dir+'/'+iff)
			for log_line in lf:
				line_no += 1
				if log_line.find('writes sent') != -1:
					log_cnts = log_line.split(' ')
#					print log_line,log_cnts[0],log_cnts[3]
					res_tab[ifc] = (log_cnts[0],log_cnts[3])
			lf.close()
		html.write('<table>\n')
		html.write('<caption>\n')
		html.write('Test Results for %s\n'%("FT-HWB-"+drive_dict[dri]))
		html.write('</caption>\n')
		html.write('<tr>\n')
		html.write('<th>Computer to Blocker Connection</th>\n')
		html.write('<th>Write Commands Sent</th>\n')
		html.write('<th>Writes Not Blocked</th>\n')
		html.write('</tr>\n')
		html.write('<tr>\n')
		for ifc in config['iface']:
			if ifc in res_tab:
				html.write('<tr>\n')
				if res_tab[ifc][1] != "0": # case: PROBLEM - blocker didn't block all writes!
					html.write('<td>%s</td><td>%s</td><td bgcolor="pink"><b>%s</b></td>\n'%(conn_dict[ifc],
					res_tab[ifc][0],res_tab[ifc][1]))
				else: # case: OKAY - no writes got through
					html.write('<td>%s</td><td>%s</td><td>%s</td>\n'%(conn_dict[ifc],
					res_tab[ifc][0],res_tab[ifc][1]))		
				html.write('</tr>\n')
				count += int(res_tab[ifc][1])
		html.write('</tr>\n')
		html.write('</table>\n')
		html.write('<h3>%s</h3>\n'%('Case Summary'))
		if count == 0:
			# html.write('<p>Blocker blocked all writes.\n')
			html.write('<p>Test drive unchanged.\n')
		else:
			html.write('<p>Blocker DID NOT block all writes.\n')
		html.write(obs)
	else:
#		print dr,'missing'
		#html.write ('<p>%s is missing</p>'%(root+'/'+testcase_dir))
		html.write ('<p>%s is missing</p>'%(root+testcase_dir))

# print Appendix...
html.write('<h1>Appendix: Additional Details</h1>\n')
# iterate over each of the test cases from hwb-config.txt
for dri in config['drive']:
	testcase_dir = "FT-HWB-"+dri
	# if there's no directory for the current test case on the log drive, continue to processing the next case
	if not os.access(root+testcase_dir,os.F_OK): continue
	#dr_files = os.listdir(root+'/'+testcase_dir)
	html.write("<h2>FT-HWB-%s</h2>\n"%(drive_dict[dri]))		
	# grab all the log files for the current test case
	dr_files = os.listdir(root+testcase_dir)
	#print dr_files
	# iterate over all the interfaces (from hwb-config.txt) we should have log files for
	#print config['iface']
	for ifc in config['iface']:
		#for ifc in config['iface']:
		iff = ''
		for d_file in dr_files:
			# find the log file for the ifc interface
			if d_file.startswith(ifc):
				iff = d_file
		# html.write("<h2>%s Drive, Over %s Interface</h2>\n"%(dri,ifc))
		html.write("<h3>%s</h3>\n"%(conn_dict[ifc]))
		# if there's no log file for the ifc interface, tell the user and continue
		#if not os.access(root+testcase_dir+'/'+iff,os.F_OK): continue
		if (iff == ''):
			html.write ('<p>No %s test run log file found at %s. Log file is missing.</p>'%(conn_dict[ifc], root+testcase_dir))			
			continue
		html.write("<pre>\n")
		#lf = open(root+'/'+testcase_dir+'/'+iff)
		lf = open(root+testcase_dir+'/'+iff)
		# for log_line in lf:
		# 	vcheck(log_line)
		# 	html.write(log_line)
		# 	if log_line.startswith('RESULTS'): break
		for log_line in lf:
			vcheck(log_line)
			if log_line.startswith('Appendix'): 
				break
#			elif log_line.startswith('run start') or log_line.startswith('run finish') or log_line.startswith('elapsed') or log_line.startswith('Normal exit'):
#				continue
			else:
				html.write(log_line)

		lf.close()
		html.write("</pre>\n")

html.write('<h2>Test Setup & Analysis Tool Versions</h2><p>')
html.write('Version numbers of tools used are listed.<br><br>\n')
html.write(table_head)
html.write("<caption><b>Setup & Analysis Tool Versions</b></caption>"+'\n')
#html.write('<tr><th>Version</th></tr>\n')
slist = []
for v in vlist:
	slist.append(v)
slist.sort()
for v in slist:
	html.write('<tr><td>%s</td></tr>\n'%(v))
html.write(table_tail)

finish_time = str(datetime.datetime.now())
html.write("<br>\n")
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>6789"
# print "<TITLE>Generate Test Report</TITLE>"
# print "<body><H1>"
# print 'REPORT saved to %s'%(html_file)
# print "</H1>"
# print "<p>Done: %s" % now.strftime("%A, %B %d, %Y at %H:%M")
# print "</body>"
# print "</html>"
exit(0)
