Paypal with Django
In a previous post I discussed the method I used to integrate Paypal’s Encrypted Web Payments in generic SSL terms I hoped would make it easy to implement from scratch in any language. I’ve had a request from Ross Poulton to share the Python code that makes it work using the M2Crypto wrapper. So, here it is:
from M2Crypto import BIO, SMIME, X509
from django.conf import settings
class PaypalOrder(dict):
"""Acts as a dictionary which can be encrypted to Paypal's EWP service"""
def __init__(self):
dict.__init__(self)
self['cert_id']=settings.MY_CERT_ID
def setNotifyURL(self, notify_url):
self['notify_url']=notify_url
# snip more wrapper functions
def plaintext(self):
"""The plaintext for the cryptography operation."""
s=''
for k in self:
s+=u'%s=%s\n'%(k,self[k])
return s.encode('utf-8')
__str__=plaintext
def encrypt(self):
"""Return the contents of this order, encrypted to Paypal's
certificate and signed using the private key
configured in the Django settings."""
# Instantiate an SMIME object.
s = SMIME.SMIME()
# Load signer's key and cert. Sign the buffer.
s.load_key_bio(BIO.openfile(settings.MY_KEYPAIR), BIO.openfile(settings.MY_CERT))
p7 = s.sign(BIO.MemoryBuffer(self.plaintext()), flags=SMIME.PKCS7_BINARY)
# Load target cert to encrypt the signed message to.
x509 = X509.load_cert_bio(BIO.openfile(settings.PAYPAL_CERT))
sk = X509.X509_Stack()
sk.push(x509)
s.set_x509_stack(sk)
# Set cipher: 3-key triple-DES in CBC mode.
s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
# Create a temporary buffer.
tmp = BIO.MemoryBuffer()
# Write the signed message into the temporary buffer.
p7.write_der(tmp)
# Encrypt the temporary buffer.
p7 = s.encrypt(tmp, flags=SMIME.PKCS7_BINARY)
# Output p7 in mail-friendly format.
out = BIO.MemoryBuffer()
p7.write(out)
return out.read()
The settings required are as follows:
MY_KEYPAIR='keys/keypair.pem' #path to keypair in PEM format
MY_CERT='keys/merchant.crt' #path to merchant certificate
MY_CERT_ID='ASDF12345' # code which Paypal assign to the certificate when you upload it
PAYPAL_CERT='keys/paypal.crt' #path to Paypal's own certificate
April 3rd, 2008 at 10:38 am
Hi:
Thank you for this code snippet ! I’m testing it in my Plone application using the PayPal sandbox, but I always get “The email address for the business is not present in the encrypted blob. Please contact your merchant.”.
As you may guess, I pass correctly the business’ e-mail address in the encrypted data.
I’ve read somewhere to try separating the key=value pairs with comma (,) instead of newlines or quoting the texts, but I had no success.
Any hint will be appreciated,
Mikel Larreategi
http://www.codesyntax.com
April 3rd, 2008 at 10:13 pm
No, it works for me with line feeds; the e-mail address is passed with the key ‘business’. I recall that the error messages are misleading though. Don’t get hung up on the format of the plaintext because I think you get similar messages if there’s a problem with the cryptography.
April 7th, 2008 at 10:09 am
Thank you for your answer. I finally had it working, exchanging the \\n with \n and sending the cert_id parameter in clear without encrypting it.
Mikel
April 7th, 2008 at 11:30 am
Oh, sorry. I don’t know how that double-slash got in there. It’s not in my source. I blame Wordpress and/or PHP.
I didn’t need the cert_id in the plain though.
June 26th, 2008 at 12:41 am
The same error (”The email address for the business is not present in the encrypted blob. Please contact your merchant.”) has been hanging me up for a couple days. Your code here has been enormously helpful—I wonder if I could get your opinion on the markup below. I’m including the cmd and business pairs both in the markup and the encrypted blob, to no avail. Does a quick glance from someone who knows more than me reveal any egregious mistakes? Thanks very much.
June 26th, 2008 at 12:42 am
Whoops, no HTML allowed. Here it is with the ’s replaced with /s.
/input type=”hidden” name=”encrypted” value=”{{ encryptedBlob }}”/
/input type=”hidden” name=”business” value=”contact@psthisispublic.com”/
/input type=”hidden” name=”cmd” value=”_s-xclick”/
/input type=”submit” value=”Yes, proceed to PayPal”/
July 15th, 2008 at 8:54 pm
I am looking for some very similar code. I am building a Membership system which is based on PayFlowPro, which uses a local paypal SDK. Paypals docs are the worst ever, in my opinion and Im trying to fuse it together with my Django projects. Any advice?