#!/usr/bin/env python
# -*- coding: utf-8 -*- 
from lazagne.config.write_output import print_debug
from lazagne.config.moduleInfo import ModuleInfo
from lazagne.config.utils import build_path
from lazagne.config.constant import *
import xml.etree.cElementTree as ET
from Crypto.Cipher import DES
import binascii
import base64
import hashlib
import array
import re
import os

class SQLDeveloper(ModuleInfo):
	def __init__(self):
		ModuleInfo.__init__(self, name='sqldeveloper', category='databases')
		
		self._salt 			= self.get_salt()
		self._passphrase 	= None
		self._iteration 	= 42

	def get_salt(self):
		salt_array 	= [5, 19, -103, 66, -109, 114, -24, -83]
		salt 		= array.array('b', salt_array)
		hexsalt 	= binascii.hexlify(salt)
		return binascii.unhexlify(hexsalt)
	
	def get_derived_key(self, password, salt, count):
		key = bytearray(password) + salt
		for i in range(count):
			m 	= hashlib.md5(key)
			key = m.digest()
		return (key[:8], key[8:])
	
	def decrypt(self, msg):
		enc_text 	= base64.b64decode(msg)
		(dk, iv) 	= self.get_derived_key(self._passphrase, self._salt, self._iteration)
		crypter 	= DES.new(dk, DES.MODE_CBC, iv)
		text 		= crypter.decrypt(enc_text)
		return re.sub(r'[\x01-\x08]','',text)
	
	def get_passphrase(self, path):
		xml_name = u'product-preferences.xml'
		xml_file = None

		if os.path.exists(os.path.join(path, xml_name)):
			xml_file = os.path.join(path, xml_name)
		else:
			for p in os.listdir(path):
				if p.startswith('system'):
					new_directory = os.path.join(path, p)

					for pp in os.listdir(new_directory):
						if pp.startswith(u'o.sqldeveloper'):
							if os.path.exists(os.path.join(new_directory, pp, xml_name)):
								xml_file = os.path.join(new_directory, pp, xml_name)
							break
		if xml_file:
			tree = ET.ElementTree(file=xml_file)
			for elem in tree.iter():
				if 'n' in elem.attrib.keys():
					if elem.attrib['n'] == 'db.system.id':
						return elem.attrib['v']

	def run(self, software_name=None):
		path = build_path(software_name)
		if path:
			self._passphrase = self.get_passphrase(path)
			if self._passphrase:
				print_debug('INFO', u'Passphrase found: {passphrase}'.format(passphrase=self._passphrase))
				xml_name = u'connections.xml'
				xml_file = None

				if os.path.exists(os.path.join(path, xml_name)):
					xml_file = os.path.join(path, xml_name)
				else:
					for p in os.listdir(path):
						if p.startswith('system'):
							new_directory = os.path.join(path, p)

							for pp in os.listdir(new_directory):
								if pp.startswith(u'o.jdeveloper.db.connection'):
									if os.path.exists(os.path.join(new_directory, pp, xml_name)):
										xml_file = os.path.join(new_directory, pp, xml_name)
									break
				
				if xml_file:
					wanted_value 	= ['sid', 'port', 'hostname', 'user', 'password', 'ConnName', 'customUrl', 'SavePassword', 'driver']
					renamed_value 	= {'sid': 'SID', 'port': 'Port', 'hostname': 'Host', 'user': 'Login', 'password': 'Password', 'ConnName': 'Name', 'customUrl': 'URL', 'SavePassword': 'SavePassword', 'driver': 'Driver'}
					tree 			= ET.ElementTree(file=xml_file)
					
					pwdFound = []
					for e in tree.findall('Reference'):
						values = {}
						for ee in e.findall('RefAddresses/StringRefAddr'):
							if ee.attrib['addrType'] in wanted_value and ee.find('Contents').text is not None:
								name 			= renamed_value[ee.attrib['addrType']] 
								value 			=  ee.find('Contents').text if name != 'Password' else self.decrypt(ee.find('Contents').text)
								values[name] 	= value
						
						pwdFound.append(values)

					return pwdFound
