'''
googleProxy.py

Copyright 2006 Andres Riancho

This file is part of w3af, w3af.sourceforge.net .

w3af is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.

w3af is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with w3af; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

'''


import core.controllers.outputManager as om
from core.controllers.basePlugin.baseAttackPlugin import baseAttackPlugin
from core.controllers.w3afException import w3afException
from core.controllers.daemons.proxy import *

import cgi , urllib

import re

class googleProxy(baseAttackPlugin):
	'''
	This plugin is a local proxy for HTTP requests that 
	  
	@author: Andres Riancho ( andres.riancho@gmail.com )
	'''
	
	def __init__(self):
		baseAttackPlugin.__init__(self)
		
		# Internal variables
		self._proxyd = None
		
		# User options
		self._proxyAddress = '127.0.0.1'
		self._proxyPort = 8082
	
	def setUrlOpener( self, urlOpener ):
		self._urlOpener = urlOpener
		
		# Now, I'm starting the proxy server !
		self._proxy()
	
	def exploit( self ):
		'''
		Do nothing, this plugin is rather odd.
		This plugin is a  googleProxy server that's used for mangling requests. All the "magic" is done
		in the _proxy method and in the handler class.
		'''
		
		om.out.information('google proxy listening on ' + self._proxyAddress + ':' + str(self._proxyPort) )
		# All i need to run is runned from setUrlOpener and setOptions
		# All i need to run is self._proxy() with the correct parameters
		return True
		
	def canExploit( self ):
		return True
		
	def getType(self):
		return 'proxy'
	
	def fastExploit( self ):
		self.exploit()
	
	def getRootProbability( self ):
		return 0.0
		
	def setOptions( self, OptionsMap ):
		
		self._proxyPort = OptionsMap['proxyPort']
		self._proxyAddress = OptionsMap['proxyAddress']
		
		# Restart the proxy, with the new options
		self._proxy()
	
	class proxyHandler(w3afProxyHandler):
		
		def _editResponse( self, responseBody ):
			#responseBody = responseBody.replace('/gwt/n?u=http%3A%2F%2F', 'http://')
			responseBody = responseBody.replace( '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">', '')
			responseBody = responseBody.replace('<html xmlns="http://www.w3.org/1999/xhtml">', '<html>')
			responseBody = responseBody.replace('&amp;_gwt_noimg=1', '')
			responseBody = responseBody.replace('&amp;_gwt_srcpg=0', '')
			responseBody = responseBody.replace('&amp;_gwt_ov=1', '')
			responseBody = re.sub('<div style="background-color:#9ACEFF"><hr/>P.*', '</html>', responseBody)
			responseBody = re.sub('<div style="background-color:#9ACEFF"><a href=".*?">.*?</a><br/><hr/></div>', '', responseBody)
			for match in re.findall( '/gwt/n\?u=(.*?)"', responseBody ):
				responseBody = responseBody.replace( '/gwt/n?u=' + match, urllib.unquote_plus( match ), 1)
			return responseBody
		
		def _sendToBrowser( self, res ):
			'''
			Send a response to the browser
			'''
			# return the response to the browser
			try:
				self.send_response( res.getCode() )
				
				for header in res.getHeaders():
					if not header == 'content-type':
						self.send_header( header, res.getHeaders()[header] )
					else:
						self.send_header( 'content-type', 'text/html' )
				self.send_header( 'Connection', 'close')
				self.end_headers()
				
				self.wfile.write( self._editResponse( res.getBody() ) )
				self.wfile.close()
			except Exception, e:
				om.out.debug('Failed to send the data to the browser: ' + str(e) )		
	
		def _sendToServer( self ):
			'''
			I should send to the server:
				-	http://www.google.com/gwt/n?u=http%3A%2F%2Fwww.joomla.org%2F&_gwt_noimg=1
			When the client requests:
				-	http://www.joomla.org
			'''
			self.headers['Connection'] = 'close'
			
			# Prepare the url for google.
			googleProxyURL = 'http://www.google.com/gwt/n?'
			qs = queryString.queryString()
			qs['u'] = self.path
			qs['_gwt_noimg'] = 1
			url = googleProxyURL + str( qs )
			
			# Do the request to the remote server
			if self.headers.dict.has_key('content-length'):
				# POST
				cl = int( self.headers['content-length'] )
				postData = self.rfile.read( cl )
				try:
					res = self._urlOpener.POST( url , data=postData, headers=self.headers )
				except w3afException, w:
					om.out.error('The proxy request failed, error: ' + str(w) )
					raise w
				except:
					raise
				return res
				
			else:
				# GET
				try:
					res = self._urlOpener.GET( url, headers=self.headers )
				except w3afException, w:
					om.out.error('The proxy request failed, error: ' + str(w) )
					raise w
				except:
					raise
				return res

			
	def _proxy( self ):
		'''
		This method starts the proxy server with the configured options.
		'''
		if self._proxyd != None and self._proxyd.isRunning():
			self._proxyd.stop()
		
		self._proxyd = proxy( self._proxyAddress, self._proxyPort , self._urlOpener, proxyHandler=self.proxyHandler )
		self._proxyd.start2()
		
	def getOptionsXML(self):
		'''
		This method returns a XML containing the Options that the plugin has.
		Using this XML the framework will build a window, a menu, or some other input method to retrieve
		the info from the user. The XML has to validate against the xml schema file located at :
		w3af/core/output.xsd
		'''
		return	'<?xml version="1.0" encoding="ISO-8859-1"?>\
		<OptionList>\
			<Option name="proxyPort">\
				<default>'+str(self._proxyPort)+'</default>\
				<desc>Local TCP port where the proxy will listen on.</desc>\
				<type>integer</type>\
			</Option>\
			<Option name="proxyAddress">\
				<default>'+str(self._proxyAddress)+'</default>\
				<desc>Local IP Address where the proxy will listen on.</desc>\
				<type>string</type>\
			</Option>\
		</OptionList>\
		'

	def getPluginDeps( self ):
		'''
		@return: A list with the names of the plugins that should be runned before the
		current one.
		'''
		return []
	
	def getLongDesc( self ):
		'''
		@return: A DETAILED description of the plugin functions and features.
		'''
		return '''
		This plugin exploits a service that google provides for mobile users and generates an HTTP proxy that can be
		used to navigate the web anonymously.
		
		Two configurable parameters exist:
			- proxyPort
			- proxyAddress
		'''
