Example #1
0
def profile():

    if 'profilePic' in request.files and not allowed_file(request.files['profilePic'].filename):
        respo = ErrorResponse.ErrorResponseMessage(
            'File not of type Image!', str(datetime.now()), 400, "", "/profile")
        return json.dumps(respo.__dict__), 400

    if('userForm' not in request.form):
        respo = ErrorResponse.ErrorResponseMessage(
            'Invalid Request!', str(datetime.now()), 400, "", "/profile")
        return json.dumps(respo.__dict__), 400

    filename = None

    if 'profilePic' in request.files:
        file = request.files['profilePic']

        filename = secure_filename(str(datetime.now())+"-"+file.filename)
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        print("File Saved")

    apiObj = {
        'requestPath': request.path,
        'headers': {'Authorization': request.headers['Authorization']},
        'method': request.method,
        'form': request.form['userForm'],
        'file': filename if filename != None else ""
    }

    print(apiObj)
    rj.jsonarrappend('user', Path('.profileRequest'), apiObj)
    return jsonify(
        statusCode="200",
        message="Request Accepted"
    )
Example #2
0
    def setError(self, errCode, errMsg, consumerMsg):
        """ setError
			Creates a new ErrorResponse object and populates it with the arguments

			@param unknown_type errCode		The error code to return. This is either a code from the platform or an internal code.
			@param unknown_type errMsg		The error message. This is not meant for display to the consumer.
			@param unknown_type consumerMsg	The consumer message. The error message to be shown to the user.
		"""
        self.error = ErrorResponse()
        self.error.setErrorCode(errCode)
        self.error.setErrorMessage(errCode)
        if len(consumerMsg):
            self.error.setConsumerMessage(consumerMsg)
        else:
            self.error.setConsumerMessage(IDEAL_PRV_GENERIC_ERRORMESSAGE)
Example #3
0
def comment(id=None, cid=None):

    if request.method == 'POST' and not request.json and 'text' not in request.json and len(request.json['text']) == 0:
        respo = ErrorResponse.ErrorResponseMessage(
            'Comment cannot be empty', str(datetime.now()), 400, "", "/comment")
        return json.dumps(respo.__dict__), 400

    # print(predict_prob([request.json['text']]))
    # print(pf.censor(request.json['text']))
    # and predict_prob([request.json['text']]) > PROFANITY_IDX #and pf.is_profanerequest.json['text']:
    if request.method == 'POST' and check_profanity(request.json['text']):
        respo = ErrorResponse.ErrorResponseMessage(
            'Offensive Comments are Not Allowed!', str(datetime.now()), 400, "", "/comments")

        username = jwt.decode(
            request.headers['Authorization'].split(' ')[1], verify=False)
        slack.post(attachments=[
            {
                "fallback": "Plain-text summary of the attachment.",
                "color": "#FF0000",
                "pretext": "Offensive Comment - Error",
                "author_name": "Username - "+username['sub'],
                "title": "Comment Service",
            }
        ])
        return json.dumps(respo.__dict__), 400

    apiObj = {
        'requestPath': request.path,
        'headers': {'Authorization': request.headers['Authorization']},
        'method': request.method,
        'body': request.json,
        'service': 'comment'
    }

    print(apiObj)
    rj.jsonarrappend('tweet', Path('.tweetRequest'), apiObj)
    return jsonify(
        statusCode="200",
        message="Request Accepted"
    )
Example #4
0
	def setError( self, errCode, errMsg, consumerMsg ):
		""" setError
			Creates a new ErrorResponse object and populates it with the arguments

			@param unknown_type errCode		The error code to return. This is either a code from the platform or an internal code.
			@param unknown_type errMsg		The error message. This is not meant for display to the consumer.
			@param unknown_type consumerMsg	The consumer message. The error message to be shown to the user.
		"""
		self.error = ErrorResponse()
		self.error.setErrorCode( errCode )
		self.error.setErrorMessage( errCode )
		if len( consumerMsg ):
			self.error.setConsumerMessage( consumerMsg )
		else:
			self.error.setConsumerMessage( IDEAL_PRV_GENERIC_ERRORMESSAGE )
Example #5
0
	def GetIssuerList( self ):
		self.clearError()
		configCheck = self.CheckConfig( self.config )

		if configCheck <> unicode('OK'):
			errorResponse = ErrorResponse()
			errorResponse.setErrorCode('001')
			errorResponse.setErrorMessage('Config error: %s' % configCheck)
			errorResponse.setConsumerMessage('')

			return errorResponse

		# Build up the XML header for this request
		xmlMsg = self.getXMLHeader('DirectoryReq', '', '', '', '')
		if not xmlMsg:
			return False

		xmlMsg += u"</DirectoryReq>\n"

		# Post the XML to the server.
		response = self.PostXMLData( xmlMsg )

		# If the response did not work out, return an ErrorResponse object.
		if not self.parseFromXml( 'errorCode', response ) in ['', False]:
			errorResponse = ErrorResponse()

			errorResponse.setErrorCode(self.parseFromXml( 'errorCode', response ))
			errorResponse.setErrorMessage(self.parseFromXml( 'errorMessage', response ))
			errorResponse.setConsumerMessage(self.parseFromXml( 'consumerMessage', response ))

			return errorResponse

		if self.parseFromXml( 'acquirerID', response ) == '':
			errorResponse = ErrorResponse()

			errorResponse.setErrorCode('ING1001')
			errorResponse.setErrorMessage('DirectoryList service probleem')
			errorResponse.setConsumerMessage('')
				
			return errorResponse

		# Create a new DirectoryResponse object with the required information
		res = DirectoryResponse()
		res.setAcquirerID( self.parseFromXml( 'acquirerID', response ) )
		res.setDirectoryDateTimeStamp( self.parseFromXml( 'directoryDateTimeStamp', response ) )

		# While there are issuers to be read from the stream
		while response.find('<issuerID>' ) is not -1:

			# Read the information for the next issuer.
			issuerID	= self.parseFromXml( 'issuerID', response )
			issuerName	= self.parseFromXml( 'issuerName', response )
			issuerList	= self.parseFromXml( 'issuerList', response )

			# Create a new entry and add it to the list
			issuerEntry = IssuerEntry()
			issuerEntry.setIssuerID( issuerID )
			issuerEntry.setIssuerName( issuerName )
			issuerEntry.setIssuerListType( issuerList )
			res.addIssuer( issuerEntry )
				
			# Find the next issuer.
			response = response[response.find('</issuerList>')+13: ]

		return res
Example #6
0
class iDEALConnector( object ):
	def __init__( self ):
		self.error = ''

		self.config = self.loadConfig()
		self.verbosity, result = self.getConfiguration( "TRACELEVEL", True, True )
		self.Security = Security()

	def GetIssuerList( self ):
		self.clearError()
		configCheck = self.CheckConfig( self.config )

		if configCheck <> unicode('OK'):
			errorResponse = ErrorResponse()
			errorResponse.setErrorCode('001')
			errorResponse.setErrorMessage('Config error: %s' % configCheck)
			errorResponse.setConsumerMessage('')

			return errorResponse

		# Build up the XML header for this request
		xmlMsg = self.getXMLHeader('DirectoryReq', '', '', '', '')
		if not xmlMsg:
			return False

		xmlMsg += u"</DirectoryReq>\n"

		# Post the XML to the server.
		response = self.PostXMLData( xmlMsg )

		# If the response did not work out, return an ErrorResponse object.
		if not self.parseFromXml( 'errorCode', response ) in ['', False]:
			errorResponse = ErrorResponse()

			errorResponse.setErrorCode(self.parseFromXml( 'errorCode', response ))
			errorResponse.setErrorMessage(self.parseFromXml( 'errorMessage', response ))
			errorResponse.setConsumerMessage(self.parseFromXml( 'consumerMessage', response ))

			return errorResponse

		if self.parseFromXml( 'acquirerID', response ) == '':
			errorResponse = ErrorResponse()

			errorResponse.setErrorCode('ING1001')
			errorResponse.setErrorMessage('DirectoryList service probleem')
			errorResponse.setConsumerMessage('')
				
			return errorResponse

		# Create a new DirectoryResponse object with the required information
		res = DirectoryResponse()
		res.setAcquirerID( self.parseFromXml( 'acquirerID', response ) )
		res.setDirectoryDateTimeStamp( self.parseFromXml( 'directoryDateTimeStamp', response ) )

		# While there are issuers to be read from the stream
		while response.find('<issuerID>' ) is not -1:

			# Read the information for the next issuer.
			issuerID	= self.parseFromXml( 'issuerID', response )
			issuerName	= self.parseFromXml( 'issuerName', response )
			issuerList	= self.parseFromXml( 'issuerList', response )

			# Create a new entry and add it to the list
			issuerEntry = IssuerEntry()
			issuerEntry.setIssuerID( issuerID )
			issuerEntry.setIssuerName( issuerName )
			issuerEntry.setIssuerListType( issuerList )
			res.addIssuer( issuerEntry )
				
			# Find the next issuer.
			response = response[response.find('</issuerList>')+13: ]

		return res


	def RequestTransaction( self, issuerId, purchaseId, amount, description, entranceCode, optExpirationPeriod='', optMerchantReturnURL='' ):
		"""
			This function submits a transaction request to the server.

			@param string $issuerId			The issuer Id to send the request to
			@param string $purchaseId		The purchase Id that the merchant generates
			@param integer $amount			The amount in cents for the purchase
			@param string $description		The description of the transaction
			@param string $entranceCode		The entrance code for the visitor of the merchant site. Determined by merchant
			@param string $optExpirationPeriod		Expiration period in specific format. See reference guide. Can be configured in config.
			@param string $optMerchantReturnURL		The return URL (optional) for the visitor. Optional. Can be configured in config.
			@return An instance of AcquirerTransactionResponse or "false" on failure.
		"""
		self.clearError()
		configCheck = self.CheckConfig( self.config )

		if configCheck <> unicode('OK'):
			self.setError( ING_ERROR_MISSING_CONFIG, 'Config error: %s' % configCheck, IDEAL_PRV_GENERIC_ERROR )
			return self.getError()

		if not self.verifyNotNull( issuerId, 'issuerId' ) or \
			not self.verifyNotNull( purchaseId, 'purchaseId' ) or \
			not self.verifyNotNull( amount, 'amount' ) or \
			not self.verifyNotNull( description, 'description' ) or \
			not self.verifyNotNull( entranceCode, 'entranceCode' ):
			errorResponse = self.getError()
			return errorResponse

		# check amount length
		amountOK = self.LengthCheck( 'Amount', amount, 12 )
		if amountOK != "ok":
			return self.getError()

		# check for diacritical characters
		amountOK = self.CheckDiacritical( 'Amount', amount )
		if amountOK != "ok":
			return self.getError()

		# check entrancecode length
		entranceCodeOK = self.LengthCheck( 'Entrancecode', entranceCode, 40 )
		if entranceCodeOK != "ok":
			return self.getError()
		# check for diacritical characters
		entranceCodeOK = self.CheckDiacritical( 'Entrancecode', entranceCode )
		if entranceCodeOK != "ok":
			return self.getError()

		# check purchaseid length
		purchaseIDOK = self.LengthCheck( 'PurchaseID', purchaseId, 16 )
		if purchaseIDOK != "ok":
			return self.getError()
		# check for diacritical characters
		purchaseIDOK = self.CheckDiacritical( 'PurchaseID', purchaseId )
		if purchaseIDOK != "ok":
			return self.getError()

		# According to the specification, these values should be hardcoded.
		currency = 'EUR'
		language = 'nl'

		# Retrieve these values from the configuration file.
		cfgExpirationPeriod, result1 = self.getConfiguration( 'EXPIRATIONPERIOD', True )
		cfgMerchantReturnURL, result2 = self.getConfiguration( 'MERCHANTRETURNURL', True )

		if len( optExpirationPeriod ):
			# If a (valid?) optional setting was specified for the expiration period, use it.
			expirationPeriod = optExpirationPeriod
		else:
			expirationPeriod = cfgExpirationPeriod

		if len( optMerchantReturnURL ):
			# If a (valid?) optional setting was specified for the merchantReturnURL, use it.
			merchantReturnURL = optMerchantReturnURL
		else:
			merchantReturnURL = cfgMerchantReturnURL

		if not self.verifyNotNull( expirationPeriod, 'expirationPeriod' ) or \
			not self.verifyNotNull( merchantReturnURL, 'merchantReturnURL' ):
			return False

		# Build the XML header for the transaction request
		xmlMsg = self.getXMLHeader(
        	'AcquirerTrxReq', 
			issuerId,
			"<Issuer>\n<issuerID>%s</issuerID>\n</Issuer>\n" % issuerId,
			"%s%s%s%s%s%s%s" % (merchantReturnURL, purchaseId, amount, currency, language, description, entranceCode),
			"<merchantReturnURL>%s</merchantReturnURL>\n" % merchantReturnURL )
			
		if xmlMsg in [False, '']:
			return False

		# Add transaction information to the request.
		xmlMsg += "<Transaction>\n<purchaseID>%s</purchaseID>\n" % purchaseId;
		xmlMsg += "<amount>%s</amount>\n" % amount;
		xmlMsg += "<currency>%s</currency>\n" % currency;
		xmlMsg += "<expirationPeriod>%s</expirationPeriod>\n" % expirationPeriod;
		xmlMsg += "<language>%s</language>\n" % language;
		xmlMsg += "<description>%s</description>\n" % description;
		xmlMsg += "<entranceCode>%s</entranceCode>\n" % entranceCode;
		xmlMsg += "</Transaction>\n";
		xmlMsg += "</AcquirerTrxReq>\n";

		# Post the request to the server.
		response = self.PostXMLData( xmlMsg )

		# If the response did not work out, return an ErrorResponse object.
		if not self.parseFromXml( 'errorCode', response ) in ['', False]:
			errorResponse = ErrorResponse()

			errorResponse.setErrorCode(self.parseFromXml( 'errorCode', response ))
			errorResponse.setErrorMessage(self.parseFromXml( 'errorMessage', response ))
			errorResponse.setConsumerMessage(self.parseFromXml( 'consumerMessage', response ))

			return errorResponse

		if self.parseFromXml( 'acquirerID', response ) in ['', False]:
			errorResponse = ErrorResponse()

			errorResponse.setErrorCode('ING1001')
			errorResponse.setErrorMessage('Transactie mislukt (aquirer side)')
			errorResponse.setConsumerMessage('')
				
			return errorResponse

		html_decode_table = {
			"&amp;": "&",
			"&quot;": '"',
			"&apos;": "'",
			"&gt;": ">",
			"&lt;": "<",
			}
		
		def html_decode(text):
			"""Produce entities within text."""
			L=[]
			for c in text:
				L.append(html_decode_table.get(c,c))
			return "".join(L)

		# Build the transaction response object and pass in the data.
		res = AcquirerTransactionResponse()
		res.setAcquirerID( self.parseFromXml( 'acquirerID', response ) )
		res.setIssuerAuthenticationURL( html_decode( self.parseFromXml( 'issuerAuthenticationURL', response ) ) )
		res.setTransactionID( self.parseFromXml( 'transactionID', response ) )
		res.setPurchaseID( self.parseFromXml( 'purchaseID', response ) )

		if not res:
			return response
		
		return res


	def RequestTransactionStatus( self, transactionId ):
		""" RequestTransactionStatus
			This public function makes a transaction status request

			@param string $transactionId	The transaction ID to query. (as returned from the TX request)
			@return An instance of AcquirerStatusResponse or FALSE on failure.
		"""
		self.clearError()
		configCheck = self.CheckConfig( self.config )

		if configCheck <> unicode('OK'):
			errorResponse = ErrorResponse()
			errorResponse.setErrorCode('001')
			errorResponse.setErrorMessage('Config error: %s' % configCheck)
			errorResponse.setConsumerMessage('')

			return errorResponse

		# check TransactionId length
		if not self.LengthCheck( 'TransactionID', transactionId, 16 ).lower() == 'ok'.lower():
			return self.getError()
		if not self.verifyNotNull( transactionId, 'transactionId'):
			return self.getError()

		# Build the status request XML.
		xmlMsg = self.getXMLHeader('AcquirerStatusReq', '', '', transactionId, '')
		if not xmlMsg:
			return False

		# Add transaction information.
		xmlMsg += u"<Transaction>\n<transactionID>%s</transactionID></Transaction>\n" % transactionId
		xmlMsg += u"</AcquirerStatusReq>\n"

		# Post the request to the server.
		response = self.PostXMLData( xmlMsg )
		# If the response did not work out, return an ErrorResponse object.
		if not self.parseFromXml( 'errorCode', response ) in ['', False]:
			errorResponse = ErrorResponse()

			errorResponse.setErrorCode(self.parseFromXml( 'errorCode', response ))
			errorResponse.setErrorMessage(self.parseFromXml( 'errorMessage', response ))
			errorResponse.setConsumerMessage(self.parseFromXml( 'consumerMessage', response ))

			return errorResponse

		if self.parseFromXml( 'acquirerID', response ) in ['', False]:
			errorResponse = ErrorResponse()

			errorResponse.setErrorCode('ING1001')
			errorResponse.setErrorMessage('Status lookup mislukt (aquirer side)')
			errorResponse.setConsumerMessage('')
				
			return errorResponse

		# Build the status response object and pass the data into it.
		res = AcquirerStatusResponse()
		creationTime = self.parseFromXml( 'createDateTimeStamp', response )
		res.setAcquirerID( self.parseFromXml( 'acquirerID', response ) )
		res.setConsumerName( self.parseFromXml( 'consumerName', response ) )
		res.setConsumerAccountNumber( self.parseFromXml( 'consumerAccountNumber', response ) )
		res.setConsumerCity( self.parseFromXml( 'consumerCity', response ) )
		res.setTransactionID( self.parseFromXml( 'transactionID', response ) )
		
		# The initial status is INVALID, so that future modifications to
		# this or remote code will yield alarming conditions.
		res.setStatus( IDEAL_TX_STATUS_INVALID )
		status = self.parseFromXml( 'status', response )

		# Determine status identifier (case-insensitive).
		dStatus = {
			'Success': IDEAL_TX_STATUS_SUCCESS,
			'Cancelled': IDEAL_TX_STATUS_CANCELLED,
			'Expired': IDEAL_TX_STATUS_EXPIRED,
			'Failure': IDEAL_TX_STATUS_FAILURE,
			'Open': IDEAL_TX_STATUS_OPEN
		}

		for statuscode in dStatus.keys():
			if status.lower() == statuscode.lower():
				res.setStatus( dStatus[ statuscode ] )
		# The verification of the response starts here.
		# The message as per the reference guide instructions.
		consumerAccountNumber = res.getConsumerAccountNumber()
		if consumerAccountNumber == False:
			consumerAccountNumber = ''
		message = self.strip( '%s%s%s%s' % ( creationTime, res.getTransactionID(), status, consumerAccountNumber ) )
		# The signature value in the response contains the signed hash
		# (signed by the signing key on the server)
		signature64 = self.parseFromXml( 'signatureValue', response )

		# The signed hash is base64 encoded and inserted into the XML as such
		sig = base64.b64decode( signature64 )

		# The fingerprint is used as the identifier of the public key certificate.
		# It is sent as part of the response XML.
		fingerprint = self.parseFromXml( 'fingerprint', response )

		# The merchant should have the public certificate stored locally.
		certfile = self.getCertificateFileName( fingerprint )
		if certfile in ['', False]:
			return False

		# Verify the message signature
		valid = self.Security.verifyMessage( certfile, str(message), str(sig) )
		if not valid:
			return False

		if not res:
			return response
		
		return res

	def getError( self ):
		""" getError
			This public function returns the ErrorResponse object or "" if it does not exist.
			@return ErrorResponse object or an emptry string "".
		"""
		return self.error

	#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-#
	#                           private functions                                   #
	#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-#

	def log( self, desiredVerbosity, message ):
		""" log
			Logs a message to the file.
			@param string desiredVerbosity	The desired verbosity of the message
			@param string message			The message to log
		"""
		# Check if the log file is set. If not set, don't log.
		if 'LOGFILE' not in self.config or self.config['LOGFILE'] == '':
			return

		if desiredVerbosity not in self.verbosity:
			# The desired verbosity is not listed in the configuration
			return

		# Open the log file in 'append' mode.
		pFile = open( SECURE_PATH+'/'+self.config['LOGFILE'], 'a' )
		pFile.write( "%s: %s: %s\r\n" % ( self.getCurrentDateTime(), desiredVerbosity.upper(), message ) )
		pFile.close()

	def setError( self, errCode, errMsg, consumerMsg ):
		""" setError
			Creates a new ErrorResponse object and populates it with the arguments

			@param unknown_type errCode		The error code to return. This is either a code from the platform or an internal code.
			@param unknown_type errMsg		The error message. This is not meant for display to the consumer.
			@param unknown_type consumerMsg	The consumer message. The error message to be shown to the user.
		"""
		self.error = ErrorResponse()
		self.error.setErrorCode( errCode )
		self.error.setErrorMessage( errCode )
		if len( consumerMsg ):
			self.error.setConsumerMessage( consumerMsg )
		else:
			self.error.setConsumerMessage( IDEAL_PRV_GENERIC_ERRORMESSAGE )

	def clearError( self ):
		""" clearError
			Clears the error conditions.
		"""
		#iDEALConnector_error = 0
		#iDEALConnector_errstr = ''
		self.error = ''

	def getXMLHeader( self, msgType, firstCustomIdInsert, firstCustomFragment, secondCustomIdInsert, secondCustomFragment ):
		""" getXMLHeader
			Builds up the XML message header.

			@param string msgType				The type of message to construct.
			@param string firstCustomIdInsert	The identifier value(s) to prepend to the hash ID.
			@param string firstCustomFragment	The fragment to insert in the header before the general part.
			@param string secondCustomIdInsert	The identifier value(s) to append to the hash ID.
			@param string secondCustomFragment	The XML fragment to append to the header after the general part.
			@return string
		"""
		# Determine the (string) timestamp for the header and hash id.
		timestamp = self.getCurrentDateTime()

		# Merchant ID and sub ID come from the configuration file.
		merchantId, result = self.getConfiguration( "MERCHANTID", False )
		subId, result = self.getConfiguration( "SUBID", False )

		if not result:
			return False

		# Build the hash ID
		message = self.strip( "%s%s%s%s%s" % ( str(timestamp), str(firstCustomIdInsert), str(merchantId), str(subId), str(secondCustomIdInsert) ) )
		# Create the certificate fingerprint used to sign the message. This is passed in to identify
		# the public key of the merchant and is used for authentication and integrity checks.
		privateCert, result = self.getConfiguration( "PRIVATECERT", False )
		if not result:
			return False

		token = self.Security.createCertFingerprint( privateCert )

		if not token:
			return False

		# Calculate the base-64'd hash of the hashId and store it in tokenCode.
		tokenCode = self.calculateHash( message )

		if not tokenCode:
			return False

		# Start building the header.
#		xmlHeader = u'<?xml version="1.0" encoding="UTF-8"?>\n<%s xmlns="http://www.idealdesk.com/Message" version="1.1.0">\n<createDateTimeStamp>%s</createDateTimeStamp>\n' % ( msgType, timestamp )

		xmlHeader = u"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
		xmlHeader += u"<" + msgType + " xmlns=\"http://www.idealdesk.com/Message\" version=\"1.1.0\">\n"
		xmlHeader += u"<createDateTimeStamp>" + timestamp + "</createDateTimeStamp>\n"

		if len( firstCustomFragment ):
			# If there is a custom fragment to prepend, insert it here.
			xmlHeader += unicode(firstCustomFragment + "\n")

		# The general parts of the header
#		xmlHeader += u'<Merchant>\n<merchantID>%s</merchantID>\n<subID>%s</subID>\n<authentication>SHA1_RSA</authentication>\n<token>%s</token>\n<tokenCode>%s</tokenCode>\n' % ( self.encode_html( merchantId ), subId, token, tokenCode )

		xmlHeader += u"<Merchant>\n"
		xmlHeader += u"<merchantID>" +self.encode_html( merchantId )+ "</merchantID>\n"
		xmlHeader += u"<subID>" +subId+ "</subID>\n"
		xmlHeader += u"<authentication>SHA1_RSA</authentication>\n"
		xmlHeader += u"<token>" +unicode(token)+ "</token>\n"
		xmlHeader += u"<tokenCode>" +unicode(tokenCode)+ "</tokenCode>\n"

		if len( secondCustomFragment ):
			# If there is a fragment to append, append it here.
			xmlHeader += secondCustomFragment
		# Close the header and return it.
		xmlHeader += u'</Merchant>\n'

		return xmlHeader

	def strip( self, message ):
		""" strip
			Strips whitespace from a string.

			@param string $message	The string to strip.
			@return string			The stripped string.
		"""
		return message.replace(" ", "").replace("\t", "").replace("\n", "")

	def encode_html( self, text):
		""" encode_html
			Encodes HTML entity codes to characters

			@param string text	The text to encode
			@return string 		The encoded text
		"""
		html_escape_table = {
			"&": "&amp;",
			'"': "&quot;",
			"'": "&apos;",
			">": "&gt;",
			"<": "&lt;",
			}
		
		def html_escape(text):
			"""Produce entities within text."""
			L=[]
			for c in text:
				L.append(html_escape_table.get(c,c))
			return "".join(L)

		return html_escape( text )
#		return htmlspecialchars(strtr($text, $trans), ENT_QUOTES)

	def getCurrentDateTime( self ):
		""" getCurrentDateTime
			Gets current date and time.

			@return string	Current date and time.
		"""
		ts = time.strftime("%Y-%m-%dT%H:%M:%S.000Z", time.gmtime())
		return ts

	def loadConfig( self ):
		""" loadConfig
			Loads the configuration for the MPI interface

			@return array().  An array of the configuration elements
		"""
		dConfData = {}
		
		try:
			# Check if the file exists and read until the end.
			pFile = open( SECURE_PATH + '/config.conf', 'r' )
		except:
			return dConfData
		else:
			dFileBuffer = pFile.readlines()
			pFile.close()
		
		for sLine in dFileBuffer:
			# filter out the commented lines
			if sLine.startswith('#'):
				continue
			dConf = sLine.split('=')
			if len(dConf) == 2: # let's say: having configname and value
				dConfData[ dConf[0].strip().upper() ] = dConf[1].strip()

		return dConfData

	def CheckConfig( self, dConfData ):
		""" CheckConfig

			Checks if the Configuration is set correctly. If an option is not set correctly, it will return an error. This has
			to be checked in the begin of every function that needs these settings and if an error occurs, it must rethrown
			to show it to the user.

			@return string	Error message when configsetting is missing, if no errors occur, ok is thrown back
		"""
		if dConfData['MERCHANTID'] == '':
			return u'MERCHANTID is missing'
		elif len( dConfData['MERCHANTID'] ) > 9:
			return u'MERCHANTID too long!'
		elif dConfData['SUBID'] == '':
			return u'SUBID is missing'
		elif len( dConfData['SUBID'] ) > 6:
			return u'SUBID too long!'
		elif dConfData['ACQUIRERURL'] == '':
			return u'ACQUIRERURL is missing'
		elif dConfData['MERCHANTRETURNURL'] == '':
			return u'MERCHANTRETURNURL is missing'
		elif len( dConfData['MERCHANTRETURNURL'] ) > 512:
			return u'MERCHANTRETURNURL too long!'
		elif dConfData['EXPIRATIONPERIOD'] == '':
			return u'EXPIRATIONPERIOD is missing'
		else:
			return unicode('OK')

	def getConfiguration( self, name, allowMissing, result=False ):
		""" getConfiguration
			Safely get a configuration item.
			Returns the value when name was found, otherwise an emptry string ("").
			If "allowMissing" is set to true, it does not generate an error.

			@param string	name		The name of the configuration item.
			@param boolean	allowMissing	
			@param boolean	result		Not used, built-in for inter-api compatibility
			@return tupple	(The value as specified in the configuration file, boolean result)
		"""
		bResult = ( name in self.config.keys() ) & ( len( self.config.get( name, '') ) > 0 )
		if not bResult and not allowMissing:
			self.log( TRACE_ERROR, 'The configuration item %s is not configured in the configuraton file.' % name )
			self.setError( ING_ERROR_MISSING_CONFIG, 'Missing configuration: %s' % name, IDEAL_PRV_GENERIC_ERROR )
		return ( self.config.get( name, '' ), bResult )

	def calculateHash( self, message ):
		""" calculateHash
			Calculates the hash of a piece and encodes it with base64.

			@param string message	The message to sign.
			@return string			The signature of the message in base64.
		"""
		# Find keys and sign the message
		priv_key, result = self.getConfiguration( 'PRIVATEKEY', False )
		priv_keypass, result = self.getConfiguration( 'PRIVATEKEYPASS', False )

		tokenCode = self.Security.signMessage( priv_key, priv_keypass, message )
		if not result:
			return False
		
		# encode the signature with base64
		tokenCode = base64.b64encode( tokenCode )
		return tokenCode

	def getCertificateFileName( self, fingerprint ):
		"""
			Gets a valid certificate file name based on the certificate fingerprint.
			Uses configuration items in the config file, which are incremented when new
			security certificates are issued:
			certificate0=ideal1.crt
			certificate1=ideal2.crt
			etc...

			@param string $fingerprint	A hexadecimal representation of a certificate's fingerprint
			@return string	The filename containing the certificate corresponding to the fingerprint
		"""
		# Check if the configuration file contains such an item
		for configValue in self.config.keys():
			if configValue.startswith('CERTIFICATE'):
				certFilename = self.config[ configValue ]
			else:
				continue

			# Generate a fingerprint from the certificate in the file.
			buff = self.Security.createCertFingerprint( certFilename )
			if buff == False:
				# Could not create fingerprint from configured certificate.
				return False

			# Check if the fingerprint is equal to the desired one.
			if fingerprint == buff:
				return certFilename

		self.log( TRACE_ERROR, 'Could not find certificate with fingerprint %s' % fingerprint )
		self.setError( ING_ERROR_COULD_NOT_VERIFY, 'Could not verify message', IDEAL_PRV_GENERIC_ERROR )

		# By default, report no success.
		return False

	def PostXMLData( self, message ):
		""" PostXMLData
			Posts XML data to the server or proxy.

			@param string message	The message to post.
			@return string			The response of the server.
		"""
		sProxy, result = self.getConfiguration( 'PROXY', True )
		if sProxy == '':
			acquirerUrl, result = self.getConfiguration( 'ACQUIRERURL', False )

			if not result:
				return False
			# if Proxy configuration does not exist
			return self.PostToHost( acquirerUrl, message )

		proxyUrl, result = self.getConfiguration( 'PROXYACQURL', False )

		if not result:
			return False
		# if proxy is specified
		return self.PostToHostProxy( sProxy, proxyUrl, message )

	def PostToHost( self, sUrl, sDataToSend ):
		""" PostToHost
			Posts a message to the host.

			@param string sUrl	The URL to send the message to.
			@param string sDataToSend	The data to send
			@return string	The response from the server.
		"""
		# Decompose the URL into specific parts.
		sHost, sPort, sPath = re.findall('([\w]+://[\w\d\.-]+):([\d]+)([\w/]+)', sUrl, re.I)[0]

		# Log the request
		self.log( TRACE_DEBUG, 'sending to %s:%s%s: %s' % ( sHost, sPort, sPath, sDataToSend ) )
		return self.PostToServer( sHost, sPort, sPath, sDataToSend )

	def PostToProxy( self, sProxy, sUrl, sDataToSend ):
		""" PostToProxy
			Posts to a proxy, which is slightly different

			@param string sProxy		The proxy to post to
			@param string sUrl			The URL the proxy should post to.
			@param string sDataToSend	The data to send
			@return string	The response
		"""
		# Decompose the proxyURL into specific parts.
		sHost, sPort = re.findall('([\w]+://[\w\d\.-]+):([\d]+)', sProxy, re.I)[0]

		# Log the request
		self.log( TRACE_DEBUG, 'sending through proxy %s:%s: %s' % ( sHost, sPort, sDataToSend ) )

		# Post to the proxy
		return self.PostToServer( sHost, sPort, sUrl, sDataToSend )

	def PostToServer( self, sHost, sPort, sPath, sDataToSend ):
		"""
			Posts to the server and interprets the result

			@param string sHost		The host to post to
			@param string sPort		The port to use
			@param string sPath		The application path on the remote server
			@param string sDataToSend	The data to send
			@return string	The response of the remote server.
		"""
		sRes = ''
		
		# The connection timeout for the remote server
		timeout, result = self.getConfiguration( 'ACQUIRERTIMEOUT', False )
		if not result:
			return False

		# Open connection and report problems in custom error handler.
		

	def PostToServer( self, sHost, sPort, sPath, sDataToSend ):
		""" PostToServer
			Posts to the server and interprets the result

			@param string $host		The host to post to
			@param string $port		The port to use
			@param string $path		The application path on the remote server
			@param string $data_to_send	The data to send
			@return string	The response of the remote server.
		"""
		sHost = sHost.replace('ssl://', 'https://') # urllib2 doesn't like the ssl:// prefix
		sURL = '%s:%s%s' % ( sHost, sPort, sPath )
		# get the connection timeout (config) for the remote server
		timeout, result = self.getConfiguration( 'ACQUIRERTIMEOUT', False )
		if not result:
			return False

		# open the connection and report problems in custom error handler.
		req = urllib2.Request(url=sURL, data=sDataToSend)
		try:
			f = urllib2.urlopen(req)
		except URLError, e:
			# An error occurred when trying to connect to the server.
			self.log( TRACE_ERROR, "Could not connect to: [%s:%s%s]" % ( sHost, sPort, sPath ) )
			self.setError( ING_ERROR_COULD_NOT_CONNECT, "Could not connect to remote server", IDEAL_PRV_GENERIC_ERROR )
			return False
		else:
Example #7
0
	def RequestTransactionStatus( self, transactionId ):
		""" RequestTransactionStatus
			This public function makes a transaction status request

			@param string $transactionId	The transaction ID to query. (as returned from the TX request)
			@return An instance of AcquirerStatusResponse or FALSE on failure.
		"""
		self.clearError()
		configCheck = self.CheckConfig( self.config )

		if configCheck <> unicode('OK'):
			errorResponse = ErrorResponse()
			errorResponse.setErrorCode('001')
			errorResponse.setErrorMessage('Config error: %s' % configCheck)
			errorResponse.setConsumerMessage('')

			return errorResponse

		# check TransactionId length
		if not self.LengthCheck( 'TransactionID', transactionId, 16 ).lower() == 'ok'.lower():
			return self.getError()
		if not self.verifyNotNull( transactionId, 'transactionId'):
			return self.getError()

		# Build the status request XML.
		xmlMsg = self.getXMLHeader('AcquirerStatusReq', '', '', transactionId, '')
		if not xmlMsg:
			return False

		# Add transaction information.
		xmlMsg += u"<Transaction>\n<transactionID>%s</transactionID></Transaction>\n" % transactionId
		xmlMsg += u"</AcquirerStatusReq>\n"

		# Post the request to the server.
		response = self.PostXMLData( xmlMsg )
		# If the response did not work out, return an ErrorResponse object.
		if not self.parseFromXml( 'errorCode', response ) in ['', False]:
			errorResponse = ErrorResponse()

			errorResponse.setErrorCode(self.parseFromXml( 'errorCode', response ))
			errorResponse.setErrorMessage(self.parseFromXml( 'errorMessage', response ))
			errorResponse.setConsumerMessage(self.parseFromXml( 'consumerMessage', response ))

			return errorResponse

		if self.parseFromXml( 'acquirerID', response ) in ['', False]:
			errorResponse = ErrorResponse()

			errorResponse.setErrorCode('ING1001')
			errorResponse.setErrorMessage('Status lookup mislukt (aquirer side)')
			errorResponse.setConsumerMessage('')
				
			return errorResponse

		# Build the status response object and pass the data into it.
		res = AcquirerStatusResponse()
		creationTime = self.parseFromXml( 'createDateTimeStamp', response )
		res.setAcquirerID( self.parseFromXml( 'acquirerID', response ) )
		res.setConsumerName( self.parseFromXml( 'consumerName', response ) )
		res.setConsumerAccountNumber( self.parseFromXml( 'consumerAccountNumber', response ) )
		res.setConsumerCity( self.parseFromXml( 'consumerCity', response ) )
		res.setTransactionID( self.parseFromXml( 'transactionID', response ) )
		
		# The initial status is INVALID, so that future modifications to
		# this or remote code will yield alarming conditions.
		res.setStatus( IDEAL_TX_STATUS_INVALID )
		status = self.parseFromXml( 'status', response )

		# Determine status identifier (case-insensitive).
		dStatus = {
			'Success': IDEAL_TX_STATUS_SUCCESS,
			'Cancelled': IDEAL_TX_STATUS_CANCELLED,
			'Expired': IDEAL_TX_STATUS_EXPIRED,
			'Failure': IDEAL_TX_STATUS_FAILURE,
			'Open': IDEAL_TX_STATUS_OPEN
		}

		for statuscode in dStatus.keys():
			if status.lower() == statuscode.lower():
				res.setStatus( dStatus[ statuscode ] )
		# The verification of the response starts here.
		# The message as per the reference guide instructions.
		consumerAccountNumber = res.getConsumerAccountNumber()
		if consumerAccountNumber == False:
			consumerAccountNumber = ''
		message = self.strip( '%s%s%s%s' % ( creationTime, res.getTransactionID(), status, consumerAccountNumber ) )
		# The signature value in the response contains the signed hash
		# (signed by the signing key on the server)
		signature64 = self.parseFromXml( 'signatureValue', response )

		# The signed hash is base64 encoded and inserted into the XML as such
		sig = base64.b64decode( signature64 )

		# The fingerprint is used as the identifier of the public key certificate.
		# It is sent as part of the response XML.
		fingerprint = self.parseFromXml( 'fingerprint', response )

		# The merchant should have the public certificate stored locally.
		certfile = self.getCertificateFileName( fingerprint )
		if certfile in ['', False]:
			return False

		# Verify the message signature
		valid = self.Security.verifyMessage( certfile, str(message), str(sig) )
		if not valid:
			return False

		if not res:
			return response
		
		return res
Example #8
0
	def RequestTransaction( self, issuerId, purchaseId, amount, description, entranceCode, optExpirationPeriod='', optMerchantReturnURL='' ):
		"""
			This function submits a transaction request to the server.

			@param string $issuerId			The issuer Id to send the request to
			@param string $purchaseId		The purchase Id that the merchant generates
			@param integer $amount			The amount in cents for the purchase
			@param string $description		The description of the transaction
			@param string $entranceCode		The entrance code for the visitor of the merchant site. Determined by merchant
			@param string $optExpirationPeriod		Expiration period in specific format. See reference guide. Can be configured in config.
			@param string $optMerchantReturnURL		The return URL (optional) for the visitor. Optional. Can be configured in config.
			@return An instance of AcquirerTransactionResponse or "false" on failure.
		"""
		self.clearError()
		configCheck = self.CheckConfig( self.config )

		if configCheck <> unicode('OK'):
			self.setError( ING_ERROR_MISSING_CONFIG, 'Config error: %s' % configCheck, IDEAL_PRV_GENERIC_ERROR )
			return self.getError()

		if not self.verifyNotNull( issuerId, 'issuerId' ) or \
			not self.verifyNotNull( purchaseId, 'purchaseId' ) or \
			not self.verifyNotNull( amount, 'amount' ) or \
			not self.verifyNotNull( description, 'description' ) or \
			not self.verifyNotNull( entranceCode, 'entranceCode' ):
			errorResponse = self.getError()
			return errorResponse

		# check amount length
		amountOK = self.LengthCheck( 'Amount', amount, 12 )
		if amountOK != "ok":
			return self.getError()

		# check for diacritical characters
		amountOK = self.CheckDiacritical( 'Amount', amount )
		if amountOK != "ok":
			return self.getError()

		# check entrancecode length
		entranceCodeOK = self.LengthCheck( 'Entrancecode', entranceCode, 40 )
		if entranceCodeOK != "ok":
			return self.getError()
		# check for diacritical characters
		entranceCodeOK = self.CheckDiacritical( 'Entrancecode', entranceCode )
		if entranceCodeOK != "ok":
			return self.getError()

		# check purchaseid length
		purchaseIDOK = self.LengthCheck( 'PurchaseID', purchaseId, 16 )
		if purchaseIDOK != "ok":
			return self.getError()
		# check for diacritical characters
		purchaseIDOK = self.CheckDiacritical( 'PurchaseID', purchaseId )
		if purchaseIDOK != "ok":
			return self.getError()

		# According to the specification, these values should be hardcoded.
		currency = 'EUR'
		language = 'nl'

		# Retrieve these values from the configuration file.
		cfgExpirationPeriod, result1 = self.getConfiguration( 'EXPIRATIONPERIOD', True )
		cfgMerchantReturnURL, result2 = self.getConfiguration( 'MERCHANTRETURNURL', True )

		if len( optExpirationPeriod ):
			# If a (valid?) optional setting was specified for the expiration period, use it.
			expirationPeriod = optExpirationPeriod
		else:
			expirationPeriod = cfgExpirationPeriod

		if len( optMerchantReturnURL ):
			# If a (valid?) optional setting was specified for the merchantReturnURL, use it.
			merchantReturnURL = optMerchantReturnURL
		else:
			merchantReturnURL = cfgMerchantReturnURL

		if not self.verifyNotNull( expirationPeriod, 'expirationPeriod' ) or \
			not self.verifyNotNull( merchantReturnURL, 'merchantReturnURL' ):
			return False

		# Build the XML header for the transaction request
		xmlMsg = self.getXMLHeader(
        	'AcquirerTrxReq', 
			issuerId,
			"<Issuer>\n<issuerID>%s</issuerID>\n</Issuer>\n" % issuerId,
			"%s%s%s%s%s%s%s" % (merchantReturnURL, purchaseId, amount, currency, language, description, entranceCode),
			"<merchantReturnURL>%s</merchantReturnURL>\n" % merchantReturnURL )
			
		if xmlMsg in [False, '']:
			return False

		# Add transaction information to the request.
		xmlMsg += "<Transaction>\n<purchaseID>%s</purchaseID>\n" % purchaseId;
		xmlMsg += "<amount>%s</amount>\n" % amount;
		xmlMsg += "<currency>%s</currency>\n" % currency;
		xmlMsg += "<expirationPeriod>%s</expirationPeriod>\n" % expirationPeriod;
		xmlMsg += "<language>%s</language>\n" % language;
		xmlMsg += "<description>%s</description>\n" % description;
		xmlMsg += "<entranceCode>%s</entranceCode>\n" % entranceCode;
		xmlMsg += "</Transaction>\n";
		xmlMsg += "</AcquirerTrxReq>\n";

		# Post the request to the server.
		response = self.PostXMLData( xmlMsg )

		# If the response did not work out, return an ErrorResponse object.
		if not self.parseFromXml( 'errorCode', response ) in ['', False]:
			errorResponse = ErrorResponse()

			errorResponse.setErrorCode(self.parseFromXml( 'errorCode', response ))
			errorResponse.setErrorMessage(self.parseFromXml( 'errorMessage', response ))
			errorResponse.setConsumerMessage(self.parseFromXml( 'consumerMessage', response ))

			return errorResponse

		if self.parseFromXml( 'acquirerID', response ) in ['', False]:
			errorResponse = ErrorResponse()

			errorResponse.setErrorCode('ING1001')
			errorResponse.setErrorMessage('Transactie mislukt (aquirer side)')
			errorResponse.setConsumerMessage('')
				
			return errorResponse

		html_decode_table = {
			"&amp;": "&",
			"&quot;": '"',
			"&apos;": "'",
			"&gt;": ">",
			"&lt;": "<",
			}
		
		def html_decode(text):
			"""Produce entities within text."""
			L=[]
			for c in text:
				L.append(html_decode_table.get(c,c))
			return "".join(L)

		# Build the transaction response object and pass in the data.
		res = AcquirerTransactionResponse()
		res.setAcquirerID( self.parseFromXml( 'acquirerID', response ) )
		res.setIssuerAuthenticationURL( html_decode( self.parseFromXml( 'issuerAuthenticationURL', response ) ) )
		res.setTransactionID( self.parseFromXml( 'transactionID', response ) )
		res.setPurchaseID( self.parseFromXml( 'purchaseID', response ) )

		if not res:
			return response
		
		return res
Example #9
0
    def GetIssuerList(self):
        self.clearError()
        configCheck = self.CheckConfig(self.config)

        if configCheck <> unicode('OK'):
            errorResponse = ErrorResponse()
            errorResponse.setErrorCode('001')
            errorResponse.setErrorMessage('Config error: %s' % configCheck)
            errorResponse.setConsumerMessage('')

            return errorResponse

        # Build up the XML header for this request
        xmlMsg = self.getXMLHeader('DirectoryReq', '', '', '', '')
        if not xmlMsg:
            return False

        xmlMsg += u"</DirectoryReq>\n"

        # Post the XML to the server.
        response = self.PostXMLData(xmlMsg)

        # If the response did not work out, return an ErrorResponse object.
        if not self.parseFromXml('errorCode', response) in ['', False]:
            errorResponse = ErrorResponse()

            errorResponse.setErrorCode(self.parseFromXml(
                'errorCode', response))
            errorResponse.setErrorMessage(
                self.parseFromXml('errorMessage', response))
            errorResponse.setConsumerMessage(
                self.parseFromXml('consumerMessage', response))

            return errorResponse

        if self.parseFromXml('acquirerID', response) == '':
            errorResponse = ErrorResponse()

            errorResponse.setErrorCode('ING1001')
            errorResponse.setErrorMessage('DirectoryList service probleem')
            errorResponse.setConsumerMessage('')

            return errorResponse

        # Create a new DirectoryResponse object with the required information
        res = DirectoryResponse()
        res.setAcquirerID(self.parseFromXml('acquirerID', response))
        res.setDirectoryDateTimeStamp(
            self.parseFromXml('directoryDateTimeStamp', response))

        # While there are issuers to be read from the stream
        while response.find('<issuerID>') is not -1:

            # Read the information for the next issuer.
            issuerID = self.parseFromXml('issuerID', response)
            issuerName = self.parseFromXml('issuerName', response)
            issuerList = self.parseFromXml('issuerList', response)

            # Create a new entry and add it to the list
            issuerEntry = IssuerEntry()
            issuerEntry.setIssuerID(issuerID)
            issuerEntry.setIssuerName(issuerName)
            issuerEntry.setIssuerListType(issuerList)
            res.addIssuer(issuerEntry)

            # Find the next issuer.
            response = response[response.find('</issuerList>') + 13:]

        return res
Example #10
0
class iDEALConnector(object):
    def __init__(self):
        self.error = ''

        self.config = self.loadConfig()
        self.verbosity, result = self.getConfiguration("TRACELEVEL", True,
                                                       True)
        self.Security = Security()

    def GetIssuerList(self):
        self.clearError()
        configCheck = self.CheckConfig(self.config)

        if configCheck <> unicode('OK'):
            errorResponse = ErrorResponse()
            errorResponse.setErrorCode('001')
            errorResponse.setErrorMessage('Config error: %s' % configCheck)
            errorResponse.setConsumerMessage('')

            return errorResponse

        # Build up the XML header for this request
        xmlMsg = self.getXMLHeader('DirectoryReq', '', '', '', '')
        if not xmlMsg:
            return False

        xmlMsg += u"</DirectoryReq>\n"

        # Post the XML to the server.
        response = self.PostXMLData(xmlMsg)

        # If the response did not work out, return an ErrorResponse object.
        if not self.parseFromXml('errorCode', response) in ['', False]:
            errorResponse = ErrorResponse()

            errorResponse.setErrorCode(self.parseFromXml(
                'errorCode', response))
            errorResponse.setErrorMessage(
                self.parseFromXml('errorMessage', response))
            errorResponse.setConsumerMessage(
                self.parseFromXml('consumerMessage', response))

            return errorResponse

        if self.parseFromXml('acquirerID', response) == '':
            errorResponse = ErrorResponse()

            errorResponse.setErrorCode('ING1001')
            errorResponse.setErrorMessage('DirectoryList service probleem')
            errorResponse.setConsumerMessage('')

            return errorResponse

        # Create a new DirectoryResponse object with the required information
        res = DirectoryResponse()
        res.setAcquirerID(self.parseFromXml('acquirerID', response))
        res.setDirectoryDateTimeStamp(
            self.parseFromXml('directoryDateTimeStamp', response))

        # While there are issuers to be read from the stream
        while response.find('<issuerID>') is not -1:

            # Read the information for the next issuer.
            issuerID = self.parseFromXml('issuerID', response)
            issuerName = self.parseFromXml('issuerName', response)
            issuerList = self.parseFromXml('issuerList', response)

            # Create a new entry and add it to the list
            issuerEntry = IssuerEntry()
            issuerEntry.setIssuerID(issuerID)
            issuerEntry.setIssuerName(issuerName)
            issuerEntry.setIssuerListType(issuerList)
            res.addIssuer(issuerEntry)

            # Find the next issuer.
            response = response[response.find('</issuerList>') + 13:]

        return res

    def RequestTransaction(self,
                           issuerId,
                           purchaseId,
                           amount,
                           description,
                           entranceCode,
                           optExpirationPeriod='',
                           optMerchantReturnURL=''):
        """
			This function submits a transaction request to the server.

			@param string $issuerId			The issuer Id to send the request to
			@param string $purchaseId		The purchase Id that the merchant generates
			@param integer $amount			The amount in cents for the purchase
			@param string $description		The description of the transaction
			@param string $entranceCode		The entrance code for the visitor of the merchant site. Determined by merchant
			@param string $optExpirationPeriod		Expiration period in specific format. See reference guide. Can be configured in config.
			@param string $optMerchantReturnURL		The return URL (optional) for the visitor. Optional. Can be configured in config.
			@return An instance of AcquirerTransactionResponse or "false" on failure.
		"""
        self.clearError()
        configCheck = self.CheckConfig(self.config)

        if configCheck <> unicode('OK'):
            self.setError(ING_ERROR_MISSING_CONFIG,
                          'Config error: %s' % configCheck,
                          IDEAL_PRV_GENERIC_ERROR)
            return self.getError()

        if not self.verifyNotNull( issuerId, 'issuerId' ) or \
         not self.verifyNotNull( purchaseId, 'purchaseId' ) or \
         not self.verifyNotNull( amount, 'amount' ) or \
         not self.verifyNotNull( description, 'description' ) or \
         not self.verifyNotNull( entranceCode, 'entranceCode' ):
            errorResponse = self.getError()
            return errorResponse

        # check amount length
        amountOK = self.LengthCheck('Amount', amount, 12)
        if amountOK != "ok":
            return self.getError()

        # check for diacritical characters
        amountOK = self.CheckDiacritical('Amount', amount)
        if amountOK != "ok":
            return self.getError()

        # check entrancecode length
        entranceCodeOK = self.LengthCheck('Entrancecode', entranceCode, 40)
        if entranceCodeOK != "ok":
            return self.getError()
        # check for diacritical characters
        entranceCodeOK = self.CheckDiacritical('Entrancecode', entranceCode)
        if entranceCodeOK != "ok":
            return self.getError()

        # check purchaseid length
        purchaseIDOK = self.LengthCheck('PurchaseID', purchaseId, 16)
        if purchaseIDOK != "ok":
            return self.getError()
        # check for diacritical characters
        purchaseIDOK = self.CheckDiacritical('PurchaseID', purchaseId)
        if purchaseIDOK != "ok":
            return self.getError()

        # According to the specification, these values should be hardcoded.
        currency = 'EUR'
        language = 'nl'

        # Retrieve these values from the configuration file.
        cfgExpirationPeriod, result1 = self.getConfiguration(
            'EXPIRATIONPERIOD', True)
        cfgMerchantReturnURL, result2 = self.getConfiguration(
            'MERCHANTRETURNURL', True)

        if len(optExpirationPeriod):
            # If a (valid?) optional setting was specified for the expiration period, use it.
            expirationPeriod = optExpirationPeriod
        else:
            expirationPeriod = cfgExpirationPeriod

        if len(optMerchantReturnURL):
            # If a (valid?) optional setting was specified for the merchantReturnURL, use it.
            merchantReturnURL = optMerchantReturnURL
        else:
            merchantReturnURL = cfgMerchantReturnURL

        if not self.verifyNotNull( expirationPeriod, 'expirationPeriod' ) or \
         not self.verifyNotNull( merchantReturnURL, 'merchantReturnURL' ):
            return False

        # Build the XML header for the transaction request
        xmlMsg = self.getXMLHeader(
            'AcquirerTrxReq', issuerId,
            "<Issuer>\n<issuerID>%s</issuerID>\n</Issuer>\n" % issuerId,
            "%s%s%s%s%s%s%s" % (merchantReturnURL, purchaseId, amount,
                                currency, language, description, entranceCode),
            "<merchantReturnURL>%s</merchantReturnURL>\n" % merchantReturnURL)

        if xmlMsg in [False, '']:
            return False

        # Add transaction information to the request.
        xmlMsg += "<Transaction>\n<purchaseID>%s</purchaseID>\n" % purchaseId
        xmlMsg += "<amount>%s</amount>\n" % amount
        xmlMsg += "<currency>%s</currency>\n" % currency
        xmlMsg += "<expirationPeriod>%s</expirationPeriod>\n" % expirationPeriod
        xmlMsg += "<language>%s</language>\n" % language
        xmlMsg += "<description>%s</description>\n" % description
        xmlMsg += "<entranceCode>%s</entranceCode>\n" % entranceCode
        xmlMsg += "</Transaction>\n"
        xmlMsg += "</AcquirerTrxReq>\n"

        # Post the request to the server.
        response = self.PostXMLData(xmlMsg)

        # If the response did not work out, return an ErrorResponse object.
        if not self.parseFromXml('errorCode', response) in ['', False]:
            errorResponse = ErrorResponse()

            errorResponse.setErrorCode(self.parseFromXml(
                'errorCode', response))
            errorResponse.setErrorMessage(
                self.parseFromXml('errorMessage', response))
            errorResponse.setConsumerMessage(
                self.parseFromXml('consumerMessage', response))

            return errorResponse

        if self.parseFromXml('acquirerID', response) in ['', False]:
            errorResponse = ErrorResponse()

            errorResponse.setErrorCode('ING1001')
            errorResponse.setErrorMessage('Transactie mislukt (aquirer side)')
            errorResponse.setConsumerMessage('')

            return errorResponse

        html_decode_table = {
            "&amp;": "&",
            "&quot;": '"',
            "&apos;": "'",
            "&gt;": ">",
            "&lt;": "<",
        }

        def html_decode(text):
            """Produce entities within text."""
            L = []
            for c in text:
                L.append(html_decode_table.get(c, c))
            return "".join(L)

        # Build the transaction response object and pass in the data.
        res = AcquirerTransactionResponse()
        res.setAcquirerID(self.parseFromXml('acquirerID', response))
        res.setIssuerAuthenticationURL(
            html_decode(self.parseFromXml('issuerAuthenticationURL',
                                          response)))
        res.setTransactionID(self.parseFromXml('transactionID', response))
        res.setPurchaseID(self.parseFromXml('purchaseID', response))

        if not res:
            return response

        return res

    def RequestTransactionStatus(self, transactionId):
        """ RequestTransactionStatus
			This public function makes a transaction status request

			@param string $transactionId	The transaction ID to query. (as returned from the TX request)
			@return An instance of AcquirerStatusResponse or FALSE on failure.
		"""
        self.clearError()
        configCheck = self.CheckConfig(self.config)

        if configCheck <> unicode('OK'):
            errorResponse = ErrorResponse()
            errorResponse.setErrorCode('001')
            errorResponse.setErrorMessage('Config error: %s' % configCheck)
            errorResponse.setConsumerMessage('')

            return errorResponse

        # check TransactionId length
        if not self.LengthCheck('TransactionID', transactionId,
                                16).lower() == 'ok'.lower():
            return self.getError()
        if not self.verifyNotNull(transactionId, 'transactionId'):
            return self.getError()

        # Build the status request XML.
        xmlMsg = self.getXMLHeader('AcquirerStatusReq', '', '', transactionId,
                                   '')
        if not xmlMsg:
            return False

        # Add transaction information.
        xmlMsg += u"<Transaction>\n<transactionID>%s</transactionID></Transaction>\n" % transactionId
        xmlMsg += u"</AcquirerStatusReq>\n"

        # Post the request to the server.
        response = self.PostXMLData(xmlMsg)
        # If the response did not work out, return an ErrorResponse object.
        if not self.parseFromXml('errorCode', response) in ['', False]:
            errorResponse = ErrorResponse()

            errorResponse.setErrorCode(self.parseFromXml(
                'errorCode', response))
            errorResponse.setErrorMessage(
                self.parseFromXml('errorMessage', response))
            errorResponse.setConsumerMessage(
                self.parseFromXml('consumerMessage', response))

            return errorResponse

        if self.parseFromXml('acquirerID', response) in ['', False]:
            errorResponse = ErrorResponse()

            errorResponse.setErrorCode('ING1001')
            errorResponse.setErrorMessage(
                'Status lookup mislukt (aquirer side)')
            errorResponse.setConsumerMessage('')

            return errorResponse

        # Build the status response object and pass the data into it.
        res = AcquirerStatusResponse()
        creationTime = self.parseFromXml('createDateTimeStamp', response)
        res.setAcquirerID(self.parseFromXml('acquirerID', response))
        res.setConsumerName(self.parseFromXml('consumerName', response))
        res.setConsumerAccountNumber(
            self.parseFromXml('consumerAccountNumber', response))
        res.setConsumerCity(self.parseFromXml('consumerCity', response))
        res.setTransactionID(self.parseFromXml('transactionID', response))

        # The initial status is INVALID, so that future modifications to
        # this or remote code will yield alarming conditions.
        res.setStatus(IDEAL_TX_STATUS_INVALID)
        status = self.parseFromXml('status', response)

        # Determine status identifier (case-insensitive).
        dStatus = {
            'Success': IDEAL_TX_STATUS_SUCCESS,
            'Cancelled': IDEAL_TX_STATUS_CANCELLED,
            'Expired': IDEAL_TX_STATUS_EXPIRED,
            'Failure': IDEAL_TX_STATUS_FAILURE,
            'Open': IDEAL_TX_STATUS_OPEN
        }

        for statuscode in dStatus.keys():
            if status.lower() == statuscode.lower():
                res.setStatus(dStatus[statuscode])
        # The verification of the response starts here.
        # The message as per the reference guide instructions.
        consumerAccountNumber = res.getConsumerAccountNumber()
        if consumerAccountNumber == False:
            consumerAccountNumber = ''
        message = self.strip('%s%s%s%s' %
                             (creationTime, res.getTransactionID(), status,
                              consumerAccountNumber))
        # The signature value in the response contains the signed hash
        # (signed by the signing key on the server)
        signature64 = self.parseFromXml('signatureValue', response)

        # The signed hash is base64 encoded and inserted into the XML as such
        sig = base64.b64decode(signature64)

        # The fingerprint is used as the identifier of the public key certificate.
        # It is sent as part of the response XML.
        fingerprint = self.parseFromXml('fingerprint', response)

        # The merchant should have the public certificate stored locally.
        certfile = self.getCertificateFileName(fingerprint)
        if certfile in ['', False]:
            return False

        # Verify the message signature
        valid = self.Security.verifyMessage(certfile, str(message), str(sig))
        if not valid:
            return False

        if not res:
            return response

        return res

    def getError(self):
        """ getError
			This public function returns the ErrorResponse object or "" if it does not exist.
			@return ErrorResponse object or an emptry string "".
		"""
        return self.error

    #-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-#
    #                           private functions                                   #
    #-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-#

    def log(self, desiredVerbosity, message):
        """ log
			Logs a message to the file.
			@param string desiredVerbosity	The desired verbosity of the message
			@param string message			The message to log
		"""
        # Check if the log file is set. If not set, don't log.
        if 'LOGFILE' not in self.config or self.config['LOGFILE'] == '':
            return

        if desiredVerbosity not in self.verbosity:
            # The desired verbosity is not listed in the configuration
            return

        # Open the log file in 'append' mode.
        pFile = open(SECURE_PATH + '/' + self.config['LOGFILE'], 'a')
        pFile.write(
            "%s: %s: %s\r\n" %
            (self.getCurrentDateTime(), desiredVerbosity.upper(), message))
        pFile.close()

    def setError(self, errCode, errMsg, consumerMsg):
        """ setError
			Creates a new ErrorResponse object and populates it with the arguments

			@param unknown_type errCode		The error code to return. This is either a code from the platform or an internal code.
			@param unknown_type errMsg		The error message. This is not meant for display to the consumer.
			@param unknown_type consumerMsg	The consumer message. The error message to be shown to the user.
		"""
        self.error = ErrorResponse()
        self.error.setErrorCode(errCode)
        self.error.setErrorMessage(errCode)
        if len(consumerMsg):
            self.error.setConsumerMessage(consumerMsg)
        else:
            self.error.setConsumerMessage(IDEAL_PRV_GENERIC_ERRORMESSAGE)

    def clearError(self):
        """ clearError
			Clears the error conditions.
		"""
        #iDEALConnector_error = 0
        #iDEALConnector_errstr = ''
        self.error = ''

    def getXMLHeader(self, msgType, firstCustomIdInsert, firstCustomFragment,
                     secondCustomIdInsert, secondCustomFragment):
        """ getXMLHeader
			Builds up the XML message header.

			@param string msgType				The type of message to construct.
			@param string firstCustomIdInsert	The identifier value(s) to prepend to the hash ID.
			@param string firstCustomFragment	The fragment to insert in the header before the general part.
			@param string secondCustomIdInsert	The identifier value(s) to append to the hash ID.
			@param string secondCustomFragment	The XML fragment to append to the header after the general part.
			@return string
		"""
        # Determine the (string) timestamp for the header and hash id.
        timestamp = self.getCurrentDateTime()

        # Merchant ID and sub ID come from the configuration file.
        merchantId, result = self.getConfiguration("MERCHANTID", False)
        subId, result = self.getConfiguration("SUBID", False)

        if not result:
            return False

        # Build the hash ID
        message = self.strip(
            "%s%s%s%s%s" %
            (str(timestamp), str(firstCustomIdInsert), str(merchantId),
             str(subId), str(secondCustomIdInsert)))
        # Create the certificate fingerprint used to sign the message. This is passed in to identify
        # the public key of the merchant and is used for authentication and integrity checks.
        privateCert, result = self.getConfiguration("PRIVATECERT", False)
        if not result:
            return False

        token = self.Security.createCertFingerprint(privateCert)

        if not token:
            return False

        # Calculate the base-64'd hash of the hashId and store it in tokenCode.
        tokenCode = self.calculateHash(message)

        if not tokenCode:
            return False

        # Start building the header.
#		xmlHeader = u'<?xml version="1.0" encoding="UTF-8"?>\n<%s xmlns="http://www.idealdesk.com/Message" version="1.1.0">\n<createDateTimeStamp>%s</createDateTimeStamp>\n' % ( msgType, timestamp )

        xmlHeader = u"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
        xmlHeader += u"<" + msgType + " xmlns=\"http://www.idealdesk.com/Message\" version=\"1.1.0\">\n"
        xmlHeader += u"<createDateTimeStamp>" + timestamp + "</createDateTimeStamp>\n"

        if len(firstCustomFragment):
            # If there is a custom fragment to prepend, insert it here.
            xmlHeader += unicode(firstCustomFragment + "\n")

        # The general parts of the header
#		xmlHeader += u'<Merchant>\n<merchantID>%s</merchantID>\n<subID>%s</subID>\n<authentication>SHA1_RSA</authentication>\n<token>%s</token>\n<tokenCode>%s</tokenCode>\n' % ( self.encode_html( merchantId ), subId, token, tokenCode )

        xmlHeader += u"<Merchant>\n"
        xmlHeader += u"<merchantID>" + self.encode_html(
            merchantId) + "</merchantID>\n"
        xmlHeader += u"<subID>" + subId + "</subID>\n"
        xmlHeader += u"<authentication>SHA1_RSA</authentication>\n"
        xmlHeader += u"<token>" + unicode(token) + "</token>\n"
        xmlHeader += u"<tokenCode>" + unicode(tokenCode) + "</tokenCode>\n"

        if len(secondCustomFragment):
            # If there is a fragment to append, append it here.
            xmlHeader += secondCustomFragment
        # Close the header and return it.
        xmlHeader += u'</Merchant>\n'

        return xmlHeader

    def strip(self, message):
        """ strip
			Strips whitespace from a string.

			@param string $message	The string to strip.
			@return string			The stripped string.
		"""
        return message.replace(" ", "").replace("\t", "").replace("\n", "")

    def encode_html(self, text):
        """ encode_html
			Encodes HTML entity codes to characters

			@param string text	The text to encode
			@return string 		The encoded text
		"""
        html_escape_table = {
            "&": "&amp;",
            '"': "&quot;",
            "'": "&apos;",
            ">": "&gt;",
            "<": "&lt;",
        }

        def html_escape(text):
            """Produce entities within text."""
            L = []
            for c in text:
                L.append(html_escape_table.get(c, c))
            return "".join(L)

        return html_escape(text)
#		return htmlspecialchars(strtr($text, $trans), ENT_QUOTES)

    def getCurrentDateTime(self):
        """ getCurrentDateTime
			Gets current date and time.

			@return string	Current date and time.
		"""
        ts = time.strftime("%Y-%m-%dT%H:%M:%S.000Z", time.gmtime())
        return ts

    def loadConfig(self):
        """ loadConfig
			Loads the configuration for the MPI interface

			@return array().  An array of the configuration elements
		"""
        dConfData = {}

        try:
            # Check if the file exists and read until the end.
            pFile = open(SECURE_PATH + '/config.conf', 'r')
        except:
            return dConfData
        else:
            dFileBuffer = pFile.readlines()
            pFile.close()

        for sLine in dFileBuffer:
            # filter out the commented lines
            if sLine.startswith('#'):
                continue
            dConf = sLine.split('=')
            if len(dConf) == 2:  # let's say: having configname and value
                dConfData[dConf[0].strip().upper()] = dConf[1].strip()

        return dConfData

    def CheckConfig(self, dConfData):
        """ CheckConfig

			Checks if the Configuration is set correctly. If an option is not set correctly, it will return an error. This has
			to be checked in the begin of every function that needs these settings and if an error occurs, it must rethrown
			to show it to the user.

			@return string	Error message when configsetting is missing, if no errors occur, ok is thrown back
		"""
        if dConfData['MERCHANTID'] == '':
            return u'MERCHANTID is missing'
        elif len(dConfData['MERCHANTID']) > 9:
            return u'MERCHANTID too long!'
        elif dConfData['SUBID'] == '':
            return u'SUBID is missing'
        elif len(dConfData['SUBID']) > 6:
            return u'SUBID too long!'
        elif dConfData['ACQUIRERURL'] == '':
            return u'ACQUIRERURL is missing'
        elif dConfData['MERCHANTRETURNURL'] == '':
            return u'MERCHANTRETURNURL is missing'
        elif len(dConfData['MERCHANTRETURNURL']) > 512:
            return u'MERCHANTRETURNURL too long!'
        elif dConfData['EXPIRATIONPERIOD'] == '':
            return u'EXPIRATIONPERIOD is missing'
        else:
            return unicode('OK')

    def getConfiguration(self, name, allowMissing, result=False):
        """ getConfiguration
			Safely get a configuration item.
			Returns the value when name was found, otherwise an emptry string ("").
			If "allowMissing" is set to true, it does not generate an error.

			@param string	name		The name of the configuration item.
			@param boolean	allowMissing	
			@param boolean	result		Not used, built-in for inter-api compatibility
			@return tupple	(The value as specified in the configuration file, boolean result)
		"""
        bResult = (name in self.config.keys()) & (len(self.config.get(
            name, '')) > 0)
        if not bResult and not allowMissing:
            self.log(
                TRACE_ERROR,
                'The configuration item %s is not configured in the configuraton file.'
                % name)
            self.setError(ING_ERROR_MISSING_CONFIG,
                          'Missing configuration: %s' % name,
                          IDEAL_PRV_GENERIC_ERROR)
        return (self.config.get(name, ''), bResult)

    def calculateHash(self, message):
        """ calculateHash
			Calculates the hash of a piece and encodes it with base64.

			@param string message	The message to sign.
			@return string			The signature of the message in base64.
		"""
        # Find keys and sign the message
        priv_key, result = self.getConfiguration('PRIVATEKEY', False)
        priv_keypass, result = self.getConfiguration('PRIVATEKEYPASS', False)

        tokenCode = self.Security.signMessage(priv_key, priv_keypass, message)
        if not result:
            return False

        # encode the signature with base64
        tokenCode = base64.b64encode(tokenCode)
        return tokenCode

    def getCertificateFileName(self, fingerprint):
        """
			Gets a valid certificate file name based on the certificate fingerprint.
			Uses configuration items in the config file, which are incremented when new
			security certificates are issued:
			certificate0=ideal1.crt
			certificate1=ideal2.crt
			etc...

			@param string $fingerprint	A hexadecimal representation of a certificate's fingerprint
			@return string	The filename containing the certificate corresponding to the fingerprint
		"""
        # Check if the configuration file contains such an item
        for configValue in self.config.keys():
            if configValue.startswith('CERTIFICATE'):
                certFilename = self.config[configValue]
            else:
                continue

            # Generate a fingerprint from the certificate in the file.
            buff = self.Security.createCertFingerprint(certFilename)
            if buff == False:
                # Could not create fingerprint from configured certificate.
                return False

            # Check if the fingerprint is equal to the desired one.
            if fingerprint == buff:
                return certFilename

        self.log(
            TRACE_ERROR,
            'Could not find certificate with fingerprint %s' % fingerprint)
        self.setError(ING_ERROR_COULD_NOT_VERIFY, 'Could not verify message',
                      IDEAL_PRV_GENERIC_ERROR)

        # By default, report no success.
        return False

    def PostXMLData(self, message):
        """ PostXMLData
			Posts XML data to the server or proxy.

			@param string message	The message to post.
			@return string			The response of the server.
		"""
        sProxy, result = self.getConfiguration('PROXY', True)
        if sProxy == '':
            acquirerUrl, result = self.getConfiguration('ACQUIRERURL', False)

            if not result:
                return False
            # if Proxy configuration does not exist
            return self.PostToHost(acquirerUrl, message)

        proxyUrl, result = self.getConfiguration('PROXYACQURL', False)

        if not result:
            return False
        # if proxy is specified
        return self.PostToHostProxy(sProxy, proxyUrl, message)

    def PostToHost(self, sUrl, sDataToSend):
        """ PostToHost
			Posts a message to the host.

			@param string sUrl	The URL to send the message to.
			@param string sDataToSend	The data to send
			@return string	The response from the server.
		"""
        # Decompose the URL into specific parts.
        sHost, sPort, sPath = re.findall(
            '([\w]+://[\w\d\.-]+):([\d]+)([\w/]+)', sUrl, re.I)[0]

        # Log the request
        self.log(TRACE_DEBUG,
                 'sending to %s:%s%s: %s' % (sHost, sPort, sPath, sDataToSend))
        return self.PostToServer(sHost, sPort, sPath, sDataToSend)

    def PostToProxy(self, sProxy, sUrl, sDataToSend):
        """ PostToProxy
			Posts to a proxy, which is slightly different

			@param string sProxy		The proxy to post to
			@param string sUrl			The URL the proxy should post to.
			@param string sDataToSend	The data to send
			@return string	The response
		"""
        # Decompose the proxyURL into specific parts.
        sHost, sPort = re.findall('([\w]+://[\w\d\.-]+):([\d]+)', sProxy,
                                  re.I)[0]

        # Log the request
        self.log(
            TRACE_DEBUG,
            'sending through proxy %s:%s: %s' % (sHost, sPort, sDataToSend))

        # Post to the proxy
        return self.PostToServer(sHost, sPort, sUrl, sDataToSend)

#	def PostToServer( self, sHost, sPort, sPath, sDataToSend ):
#		"""
#			Posts to the server and interprets the result
#
#			@param string sHost		The host to post to
#			@param string sPort		The port to use
#			@param string sPath		The application path on the remote server
#			@param string sDataToSend	The data to send
#			@return string	The response of the remote server.
#		"""
#		sRes = ''
#
#		# The connection timeout for the remote server
#		timeout, result = self.getConfiguration( 'ACQUIRERTIMEOUT', False )
#		if not result:
#			return False
#
#		# Open connection and report problems in custom error handler.

    def PostToServer(self, sHost, sPort, sPath, sDataToSend):
        """ PostToServer
			Posts to the server and interprets the result

			@param string $host		The host to post to
			@param string $port		The port to use
			@param string $path		The application path on the remote server
			@param string $data_to_send	The data to send
			@return string	The response of the remote server.
		"""
        sHost = sHost.replace(
            'ssl://', 'https://')  # urllib2 doesn't like the ssl:// prefix
        sURL = '%s:%s%s' % (sHost, sPort, sPath)
        # get the connection timeout (config) for the remote server
        timeout, result = self.getConfiguration('ACQUIRERTIMEOUT', False)
        if not result:
            return False

        # open the connection and report problems in custom error handler.
        req = urllib2.Request(url=sURL, data=sDataToSend)
        try:
            f = urllib2.urlopen(req)
        except urllib2.URLError, e:
            # An error occurred when trying to connect to the server.
            self.log(TRACE_ERROR,
                     "Could not connect to: [%s:%s%s]" % (sHost, sPort, sPath))
            self.setError(ING_ERROR_COULD_NOT_CONNECT,
                          "Could not connect to remote server",
                          IDEAL_PRV_GENERIC_ERROR)
            return False
        else:
Example #11
0
    def RequestTransactionStatus(self, transactionId):
        """ RequestTransactionStatus
			This public function makes a transaction status request

			@param string $transactionId	The transaction ID to query. (as returned from the TX request)
			@return An instance of AcquirerStatusResponse or FALSE on failure.
		"""
        self.clearError()
        configCheck = self.CheckConfig(self.config)

        if configCheck <> unicode('OK'):
            errorResponse = ErrorResponse()
            errorResponse.setErrorCode('001')
            errorResponse.setErrorMessage('Config error: %s' % configCheck)
            errorResponse.setConsumerMessage('')

            return errorResponse

        # check TransactionId length
        if not self.LengthCheck('TransactionID', transactionId,
                                16).lower() == 'ok'.lower():
            return self.getError()
        if not self.verifyNotNull(transactionId, 'transactionId'):
            return self.getError()

        # Build the status request XML.
        xmlMsg = self.getXMLHeader('AcquirerStatusReq', '', '', transactionId,
                                   '')
        if not xmlMsg:
            return False

        # Add transaction information.
        xmlMsg += u"<Transaction>\n<transactionID>%s</transactionID></Transaction>\n" % transactionId
        xmlMsg += u"</AcquirerStatusReq>\n"

        # Post the request to the server.
        response = self.PostXMLData(xmlMsg)
        # If the response did not work out, return an ErrorResponse object.
        if not self.parseFromXml('errorCode', response) in ['', False]:
            errorResponse = ErrorResponse()

            errorResponse.setErrorCode(self.parseFromXml(
                'errorCode', response))
            errorResponse.setErrorMessage(
                self.parseFromXml('errorMessage', response))
            errorResponse.setConsumerMessage(
                self.parseFromXml('consumerMessage', response))

            return errorResponse

        if self.parseFromXml('acquirerID', response) in ['', False]:
            errorResponse = ErrorResponse()

            errorResponse.setErrorCode('ING1001')
            errorResponse.setErrorMessage(
                'Status lookup mislukt (aquirer side)')
            errorResponse.setConsumerMessage('')

            return errorResponse

        # Build the status response object and pass the data into it.
        res = AcquirerStatusResponse()
        creationTime = self.parseFromXml('createDateTimeStamp', response)
        res.setAcquirerID(self.parseFromXml('acquirerID', response))
        res.setConsumerName(self.parseFromXml('consumerName', response))
        res.setConsumerAccountNumber(
            self.parseFromXml('consumerAccountNumber', response))
        res.setConsumerCity(self.parseFromXml('consumerCity', response))
        res.setTransactionID(self.parseFromXml('transactionID', response))

        # The initial status is INVALID, so that future modifications to
        # this or remote code will yield alarming conditions.
        res.setStatus(IDEAL_TX_STATUS_INVALID)
        status = self.parseFromXml('status', response)

        # Determine status identifier (case-insensitive).
        dStatus = {
            'Success': IDEAL_TX_STATUS_SUCCESS,
            'Cancelled': IDEAL_TX_STATUS_CANCELLED,
            'Expired': IDEAL_TX_STATUS_EXPIRED,
            'Failure': IDEAL_TX_STATUS_FAILURE,
            'Open': IDEAL_TX_STATUS_OPEN
        }

        for statuscode in dStatus.keys():
            if status.lower() == statuscode.lower():
                res.setStatus(dStatus[statuscode])
        # The verification of the response starts here.
        # The message as per the reference guide instructions.
        consumerAccountNumber = res.getConsumerAccountNumber()
        if consumerAccountNumber == False:
            consumerAccountNumber = ''
        message = self.strip('%s%s%s%s' %
                             (creationTime, res.getTransactionID(), status,
                              consumerAccountNumber))
        # The signature value in the response contains the signed hash
        # (signed by the signing key on the server)
        signature64 = self.parseFromXml('signatureValue', response)

        # The signed hash is base64 encoded and inserted into the XML as such
        sig = base64.b64decode(signature64)

        # The fingerprint is used as the identifier of the public key certificate.
        # It is sent as part of the response XML.
        fingerprint = self.parseFromXml('fingerprint', response)

        # The merchant should have the public certificate stored locally.
        certfile = self.getCertificateFileName(fingerprint)
        if certfile in ['', False]:
            return False

        # Verify the message signature
        valid = self.Security.verifyMessage(certfile, str(message), str(sig))
        if not valid:
            return False

        if not res:
            return response

        return res
Example #12
0
    def RequestTransaction(self,
                           issuerId,
                           purchaseId,
                           amount,
                           description,
                           entranceCode,
                           optExpirationPeriod='',
                           optMerchantReturnURL=''):
        """
			This function submits a transaction request to the server.

			@param string $issuerId			The issuer Id to send the request to
			@param string $purchaseId		The purchase Id that the merchant generates
			@param integer $amount			The amount in cents for the purchase
			@param string $description		The description of the transaction
			@param string $entranceCode		The entrance code for the visitor of the merchant site. Determined by merchant
			@param string $optExpirationPeriod		Expiration period in specific format. See reference guide. Can be configured in config.
			@param string $optMerchantReturnURL		The return URL (optional) for the visitor. Optional. Can be configured in config.
			@return An instance of AcquirerTransactionResponse or "false" on failure.
		"""
        self.clearError()
        configCheck = self.CheckConfig(self.config)

        if configCheck <> unicode('OK'):
            self.setError(ING_ERROR_MISSING_CONFIG,
                          'Config error: %s' % configCheck,
                          IDEAL_PRV_GENERIC_ERROR)
            return self.getError()

        if not self.verifyNotNull( issuerId, 'issuerId' ) or \
         not self.verifyNotNull( purchaseId, 'purchaseId' ) or \
         not self.verifyNotNull( amount, 'amount' ) or \
         not self.verifyNotNull( description, 'description' ) or \
         not self.verifyNotNull( entranceCode, 'entranceCode' ):
            errorResponse = self.getError()
            return errorResponse

        # check amount length
        amountOK = self.LengthCheck('Amount', amount, 12)
        if amountOK != "ok":
            return self.getError()

        # check for diacritical characters
        amountOK = self.CheckDiacritical('Amount', amount)
        if amountOK != "ok":
            return self.getError()

        # check entrancecode length
        entranceCodeOK = self.LengthCheck('Entrancecode', entranceCode, 40)
        if entranceCodeOK != "ok":
            return self.getError()
        # check for diacritical characters
        entranceCodeOK = self.CheckDiacritical('Entrancecode', entranceCode)
        if entranceCodeOK != "ok":
            return self.getError()

        # check purchaseid length
        purchaseIDOK = self.LengthCheck('PurchaseID', purchaseId, 16)
        if purchaseIDOK != "ok":
            return self.getError()
        # check for diacritical characters
        purchaseIDOK = self.CheckDiacritical('PurchaseID', purchaseId)
        if purchaseIDOK != "ok":
            return self.getError()

        # According to the specification, these values should be hardcoded.
        currency = 'EUR'
        language = 'nl'

        # Retrieve these values from the configuration file.
        cfgExpirationPeriod, result1 = self.getConfiguration(
            'EXPIRATIONPERIOD', True)
        cfgMerchantReturnURL, result2 = self.getConfiguration(
            'MERCHANTRETURNURL', True)

        if len(optExpirationPeriod):
            # If a (valid?) optional setting was specified for the expiration period, use it.
            expirationPeriod = optExpirationPeriod
        else:
            expirationPeriod = cfgExpirationPeriod

        if len(optMerchantReturnURL):
            # If a (valid?) optional setting was specified for the merchantReturnURL, use it.
            merchantReturnURL = optMerchantReturnURL
        else:
            merchantReturnURL = cfgMerchantReturnURL

        if not self.verifyNotNull( expirationPeriod, 'expirationPeriod' ) or \
         not self.verifyNotNull( merchantReturnURL, 'merchantReturnURL' ):
            return False

        # Build the XML header for the transaction request
        xmlMsg = self.getXMLHeader(
            'AcquirerTrxReq', issuerId,
            "<Issuer>\n<issuerID>%s</issuerID>\n</Issuer>\n" % issuerId,
            "%s%s%s%s%s%s%s" % (merchantReturnURL, purchaseId, amount,
                                currency, language, description, entranceCode),
            "<merchantReturnURL>%s</merchantReturnURL>\n" % merchantReturnURL)

        if xmlMsg in [False, '']:
            return False

        # Add transaction information to the request.
        xmlMsg += "<Transaction>\n<purchaseID>%s</purchaseID>\n" % purchaseId
        xmlMsg += "<amount>%s</amount>\n" % amount
        xmlMsg += "<currency>%s</currency>\n" % currency
        xmlMsg += "<expirationPeriod>%s</expirationPeriod>\n" % expirationPeriod
        xmlMsg += "<language>%s</language>\n" % language
        xmlMsg += "<description>%s</description>\n" % description
        xmlMsg += "<entranceCode>%s</entranceCode>\n" % entranceCode
        xmlMsg += "</Transaction>\n"
        xmlMsg += "</AcquirerTrxReq>\n"

        # Post the request to the server.
        response = self.PostXMLData(xmlMsg)

        # If the response did not work out, return an ErrorResponse object.
        if not self.parseFromXml('errorCode', response) in ['', False]:
            errorResponse = ErrorResponse()

            errorResponse.setErrorCode(self.parseFromXml(
                'errorCode', response))
            errorResponse.setErrorMessage(
                self.parseFromXml('errorMessage', response))
            errorResponse.setConsumerMessage(
                self.parseFromXml('consumerMessage', response))

            return errorResponse

        if self.parseFromXml('acquirerID', response) in ['', False]:
            errorResponse = ErrorResponse()

            errorResponse.setErrorCode('ING1001')
            errorResponse.setErrorMessage('Transactie mislukt (aquirer side)')
            errorResponse.setConsumerMessage('')

            return errorResponse

        html_decode_table = {
            "&amp;": "&",
            "&quot;": '"',
            "&apos;": "'",
            "&gt;": ">",
            "&lt;": "<",
        }

        def html_decode(text):
            """Produce entities within text."""
            L = []
            for c in text:
                L.append(html_decode_table.get(c, c))
            return "".join(L)

        # Build the transaction response object and pass in the data.
        res = AcquirerTransactionResponse()
        res.setAcquirerID(self.parseFromXml('acquirerID', response))
        res.setIssuerAuthenticationURL(
            html_decode(self.parseFromXml('issuerAuthenticationURL',
                                          response)))
        res.setTransactionID(self.parseFromXml('transactionID', response))
        res.setPurchaseID(self.parseFromXml('purchaseID', response))

        if not res:
            return response

        return res
Example #13
0
def tweet(id=None, cid=None):

    if request.method == 'POST' and 'file' in request.files and not allowed_file(request.files['file'].filename):
        respo = ErrorResponse.ErrorResponseMessage(
            'File not of type Image!', str(datetime.now()), 400, "", "/tweet")
        return json.dumps(respo.__dict__), 400

    if (request.method == 'POST' or request.method == 'PUT') and ('tweetForm' not in request.form or len(request.form['tweetForm']) == 0):
        respo = ErrorResponse.ErrorResponseMessage(
            'Invalid Request!', str(datetime.now()), 400, "", "/tweet")
        return json.dumps(respo.__dict__), 400

    if (request.method == 'POST' or request.method == 'PUT') and check_profanity(request.form['tweetForm']):
        respo = ErrorResponse.ErrorResponseMessage(
            'Offensive Tweets are Not Allowed!', str(datetime.now()), 400, "", "/tweet")

        username = jwt.decode(
            request.headers['Authorization'].split(' ')[1], verify=False)
        slack.post(attachments=[
            {
                "fallback": "Plain-text summary of the attachment.",
                "color": "#FF0000",
                "pretext": "Offensive Tweet - Error",
                "author_name": "Username - "+username['sub'],
                "title": "Tweet Service",
            }
        ])
        return json.dumps(respo.__dict__), 400

    filename = None

    if request.method == 'POST' and 'file' in request.files:
        file = request.files['file']

        filename = secure_filename(str(datetime.now())+"-"+file.filename)
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        print("File Saved")

    if request.method == 'POST' or request.method == 'PUT':
        apiObj = {
            'requestPath': request.path,
            'headers': {'Authorization': request.headers['Authorization']},
            'method': request.method,
            'form': request.form['tweetForm'],
            'file': filename if filename != None else "",
            'service': 'tweet'
        }
    else:
        apiObj = {
            'requestPath': request.path,
            'headers': {'Authorization': request.headers['Authorization']},
            'method': request.method,
            'service': 'tweet'
        }

    print(apiObj)
    rj.jsonarrappend('tweet', Path('.tweetRequest'), apiObj)
    return jsonify(
        statusCode="200",
        message="Request Accepted"
    )