'''
fuzzer.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

'''

from string import letters, digits
from random import choice, randint
from core.data.fuzzer.mutant import mutant as mutant
import core.data.kb.config as cf

def createMutants( freq, mutantStrList, append=False, fuzzableParamList = [] ):
	'''
	@parameter freq: A fuzzable request with a dataContainer inside.
	@parameter mutantStrList: a list with mutant strings to use
	@parameter append: This indicates if the content of mutantStrList should be appended to the variable value
	@parameter fuzzableParamList: If [] then all params are fuzzed. If ['a'] , then only 'a' is fuzzed.
	@return: Returns a MutantList.
	'''
	result = []

	fuzzable = freq.getFuzzable()
	for fuzzableType in fuzzable.keys() :
		
		dataContainer = fuzzable[ fuzzableType ]
		
		# First we fill all empty variables in the dataContainer
		# This will help when testing forms with server side validation that says "if not a complete form: error() else: executeSQLquery( formValues )"
		for variable in dataContainer.keys():
			if dataContainer[variable] == '':
				dataContainer[variable] = smartFill( variable )
		
		# Now I create more mutant strings, these mutant strings will do the "fuzz file content" feature
		if cf.cf.getData('fuzzFileContent' ) and freq.getFileVariables():
			fileStrList = []
			for mutantStr in mutantStrList:
				if type( mutantStr ) == str:
					# I have to create the fileStr with a "name" attr. This is needed for MultipartPostHandler
					fStr = fileStr( mutantStr )
					extension = cf.cf.getData('fuzzFCExt' ) or 'txt'
					fStr.name = createRandAlpha( 7 ) + '.' + extension
					fileStrList.append( fStr )
			result.extend( _createMutantsWorker( freq, fuzzableType, dataContainer, fileStrList, freq.getFileVariables() , append ) )
				
		result.extend( _createMutantsWorker( freq, fuzzableType, dataContainer, mutantStrList, fuzzableParamList , append ) )
				
	return result

def _createMutantsWorker( freq, fuzzableType, dataContainer, mutantStrList, fuzzableParamList,append):
	'''
	An auxiliary function to createMutants.
	'''
	result = []
	for var_to_mod in dataContainer.keys():
		for mutantStr in mutantStrList:
			
			# Only fuzz the specified parameters
			if var_to_mod in fuzzableParamList or fuzzableParamList == []:
				
				dataContainerCopy = dataContainer.copy()
				if append :
					dataContainerCopy[var_to_mod] = dataContainerCopy[var_to_mod] + mutantStr
				else:
					dataContainerCopy[var_to_mod] = mutantStr
				freqCopy = freq.copy()
				m = mutant( freqCopy )
				m.setFuzzable( fuzzableType, dataContainerCopy )
				m.setVar( var_to_mod )
				m.setModValue( mutantStr )
				result.append ( m )
				
	return result
	
def createRandAlpha( length=0 ):
	'''
	Create a random string ONLY with letters
	
	@return: A random string only composed by letters.
	'''
	if length == 0:
		jibber = ''.join([letters])
		ru = ''.join([choice(jibber) for x in range(randint(10, 30))])
	else:
		jibber = ''.join([letters])
		ru = ''.join([choice(jibber) for x in range(length)])
	return ru
	
def createRandAlNum( length=0):
	'''
	Create a random string with random length
	
	@return: A random string of with length > 10 and length < 30.
	'''
	if length == 0:
		jibber = ''.join([letters, digits])
		ru = ''.join([choice(jibber) for x in range(randint(10, 30))])
	else:
		jibber = ''.join([letters, digits])
		ru = ''.join([choice(jibber) for x in range(length)])
	return ru

def createRandNum( length=0):
	'''
	Create a random string ONLY with numbers
	
	@return: A random string only composed by numbers.
	'''
	if length == 0:
		jibber = ''.join([digits])
		ru = ''.join([choice(jibber) for x in range(randint(10, 30))])
	else:
		jibber = ''.join([digits])
		ru = ''.join([choice(jibber) for x in range(length)])
	return ru
	
def createFormatString(  length ):
	'''
	@return: A string with $length %s and a final %n
	'''
	result = '%n' * length
	return result

class fileStr( str ):
	isFile = True
	name = ''
	def read( self, size = 0 ):
		return self.__repr__()[1:-1]
		
	def seek( self, foo = 0 ):
		pass
		

from core.data.fuzzer.formFiller import smartFill
