# -*- coding: utf-8 -*-
from constant import constant
from time import gmtime, strftime
import os, getpass, socket
import logging
import json
import tempfile
from lazagne.config.header import Header, setColor

# --------------------------- Functions used to write ---------------------------

def write_header():
	time = strftime("%Y-%m-%d %H:%M:%S", gmtime())
	header = '''|====================================================================|\r\n
|                                                                    |\r\n
|                        Credentials discovery                       |\r\n
|                                                                    |\r\n
|                          ! BANG BANG !                             |\r\n
|                                                                    |\r\n
|====================================================================|\r\n\r\n
- Date: ''' + time + '''\n\r
- Username: ''' + getpass.getuser() + ''' \r\n
- Hostname: ''' + socket.gethostname() + ''' \r\n\r\n
------------------------------ Results ------------------------------\r\n\r\n'''

	open(constant.folder_name + os.sep + constant.file_name_results + '.txt',"a+b").write(header)

def write_footer():
	footer = '\n[+] %s passwords have been found.\r\n\r\n' % str(constant.nbPasswordFound)
	open(constant.folder_name + os.sep + constant.file_name_results + '.txt',"a+b").write(footer)
	
def write_credentials(pwdFound, category, filePath):
	tmp = "############ %s passwords ############\r\n\r\n" % category
	for pwd in pwdFound:
		for p in pwd.keys():
			tmp = str(tmp) + str(p) + ": " + str(pwd[p].encode('utf-8')) + "\r\n"
		tmp = str(tmp) + "\r\n"
	open(filePath,"a+b").write(tmp)
	
def checks_write(values, category):
	if values:
		if "Passwords" not in constant.finalResults:
			constant.finalResults["Passwords"] = []
		constant.finalResults["Passwords"].append([{"Category": category}, values])

# --------------------------- End of functions used to write ---------------------------

# --------------------------- Output functions ---------------------------
def print_footer():
	footer = '\n[+] %s passwords have been found.\n' % str(constant.nbPasswordFound)
	if logging.getLogger().isEnabledFor(logging.INFO) == False:
		footer += 'For more information launch it again with the -v option\n'
	print footer

# print hex value
FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])
def dump(src, length=8):
	N=0; result=''
	while src:
		s,src = src[:length],src[length:]
		hexa = ' '.join(["%02X"%ord(x) for x in s])
		s = s.translate(FILTER)
		result += "%04X   %-*s   %s\n" % (N, length*3, hexa, s)
		N+=length
	return result

tmp_user = None
# print output if passwords have been found
def print_output(software_name, pwdFound, title1 = False):
	
	# manage differently hashes / and hex value
	if pwdFound:
		category = None
		if '__LSASecrets__' in pwdFound:
			pwdFound.remove('__LSASecrets__')
			category = 'lsa'
			pwdFound = pwdFound[0]
		elif '__Hashdump__' in pwdFound:
			pwdFound.remove('__Hashdump__')
			category = 'hash'
			pwdFound = pwdFound[0]
		elif '__MSCache__' in pwdFound:
			pwdFound.remove('__MSCache__')
			category = 'mscache'
			pwdFound = pwdFound[0]

	if pwdFound:

		# if the debug logging level is not apply => print the title
		if logging.getLogger().isEnabledFor(logging.INFO) == False:
			# print the username only if password have been found
			user = constant.finalResults.get('User', '')
			global tmp_user
			if user != tmp_user:
				tmp_user = user
				try:
					print '\n\n########## User: %s ##########\n' % user
				except:
					print '\n\n########## User: %s ##########\n' % user.encode('utf-8', errors='replace')

			# if not title1:
			Header().title(software_name)
		
		toWrite = []
		
		# LSA Secrets will not be written on the output file
		if category == 'lsa':
			for k in pwdFound:
				print k
				print dump(pwdFound[k], length=16)
			print
		
		# Windows Hashes
		elif category == 'hash':
			toWrite.append(pwdFound)
			for pwd in pwdFound:
				print pwd
			print

		# Windows MSCache
		elif category == 'mscache':
			for pwd in pwdFound:
				print pwd
			print

		# Other passwords
		else:
			for pwd in pwdFound:
				password_category = False
				# detect which kinds of password has been found
				lower_list = [s.lower() for s in pwd.keys()]
				password = [s for s in lower_list if "password" in s]
				if password: 
					password_category = password
				else:
					key = [s for s in lower_list if "key" in s] # for the wifi
					if key: 
						password_category = key
					else:
						hash = [s for s in lower_list if "hash" in s]
						if hash:
							password_category = hash
				
				# No password found
				if not password_category:
					print_debug("FAILED", "Password not found !!!")
				else:
					print_debug("OK", '%s found !!!' % password_category[0].title())
					toWrite.append(pwd)
					
					# Store all passwords found on a table => for dictionary attack if master password set
					constant.nbPasswordFound += 1
					try:
						constant.passwordFound.append(pwd[password_category[0]])
					except:
						pass
				
				for p in pwd.keys():
					try:
						print '%s: %s' % (p, pwd[p])
					except Exception,e:
						print_debug('DEBUG', '{0}'.format(e))
						print '%s: %s' % (p.encode('utf-8'), pwd[p].encode('utf-8'))
				print
			
		# write credentials into a text file
		checks_write(toWrite, software_name)
	else:
		logging.info("[!] No passwords found\n")

def print_debug(error_level, message):
	GREEN = '\x1b[32m'
	RED = '\x1b[31m'
	RESET_COLOR = '\x1b[0m'
	BRIGHT = '\x1b[1m'
	CYAN = '\x1b[36m'

	# print when password is found
	if error_level == 'OK':
		setColor('green')
		print message
		setColor()

	# print when password is not found
	elif error_level == 'FAILED':
		setColor('red', True)
		print message
		setColor()

	# print messages depending of their criticism
	elif error_level == 'CRITICAL':
		setColor('red', True)
		logging.critical('[CRITICAL] %s\n' % message)
		setColor()

	elif error_level == 'ERROR':
		setColor('red', True)
		logging.error('[ERROR] %s\n' % message)
		setColor()

	elif error_level == 'WARNING':
		setColor('cyan')
		logging.warning('[WARNING] %s\n' % message)
		setColor()

	elif error_level == 'DEBUG':
		logging.debug('[DEBUG] %s\n' % message)

	elif error_level == 'INFO':
		logging.info('%s\n' % message)
	
	else:
		logging.info('[%s] %s' % (error_level, message))

# --------------------------- End of output functions ---------------------------

def parseJsonResultToBuffer(jsonString, color=False):
	green = ''
	reset = ''
	title = ''
	# if color:
	# 	green = Fore.GREEN
	# 	title = BRIGHT + Fore.WHITE
	# 	reset = RESET_COLOR

	buffer = ''
	try:
		for json in jsonString:
			if json:
				buffer += '\r\n\r\n{title_color}########## User: {username} ##########{reset_color}\r\n\r\n'.format(title_color=title, username=json['User'], reset_color=reset)
				if 'Passwords' not in json:
					buffer += 'No passwords found for this user !'
				else:
					for all_passwords in json['Passwords']:
						buffer += '{title_color}------------------- {password_category} -----------------{reset_color}\r\n'.format(title_color=title, password_category=all_passwords[0]['Category'], reset_color=reset)
						for password_by_category in all_passwords[1]:
							buffer += '\r\n{green_color}Password found !!!{reset_color}\r\n'.format(green_color=green, reset_color=reset)
							constant.nbPasswordFound += 1
							for dic in password_by_category.keys():
								try:
									buffer += '%s: %s\r\n' % (dic, password_by_category[dic].encode('utf-8'))
								except:
									buffer += '%s: %s\r\n' % (dic, password_by_category[dic].encode(encoding='utf-8',errors='replace'))
						buffer += '\r\n'

	except Exception as e:
		print_debug('ERROR', 'Error parsing the json results: %s' % e)
		print_debug('ERROR', 'json content: %s' % jsonString)

	return buffer 