PayPalPDT._verify_postback() nukes PDT object on bad postback

163 views
Skip to first unread message

Cole

unread,
Aug 31, 2011, 5:38:17 PM8/31/11
to django-paypal
Hi, I'm setting up paypal PDT using dcramer's fork as of Aug 5th, and
I ran into an issue while testing in the sandbox. (I would post this
as an issue on github, but it looks like dcramer has issues disabled).
Basically the problem is that resubmitting a PDT with a bogus
transaction ID doesn't get flagged correctly. If anyone has fixed this
on their fork, or has suggestions, please let me know. More details
below:

After a successful test payment, Paypal redirects to my PDT url with
transaction details in the URL parameters. I copied that URL, altered
the transaction ID, and re-submitted it -- testing how
paypal.standard.pdt deals with such a hack. Checking the admin
interface, I found a new pdt entry in my database, but it was labeled
as a "PDT: Recurring", it was not flagged, yet "flag info" was set to
"Error: 4003." Otherwise the object is blank.

I traced the problem to PayPalPDT._verify_postback() where the
postback response is evaluated. I haven't stepped through the code
yet, but it looks like the first half of the function looks for
problems in the postback response and sets the flag accordingly.
However at the end of the function it does this:

qd = QueryDict('', mutable=True)
qd.update(response_dict)
qd.update(dict(ipaddress=self.ipaddress, st=self.st,
flag_info=self.flag_info))
pdt_form = PayPalPDTForm(qd, instance=self)
pdt_form.save(commit=False)

The last line overwrites the PayPalPDT object with a new object
containing only the contents of the response dictionary and a few
other variables (ip address, st and flag_info). The result in my test
case is that the object stored in the DB is empty except for those
three extra variables. (This explains why the object is labed "PDT:
Recurring" -- _is_transaction() returns false since txn_id is blank)

My current solution is to only execute the above block of code if the
flag is clear. The assumption I'm making is that the response_dict
from the postback is always empty if the postback was invalid. Here's
my version:

if not self.flag:
qd = QueryDict('', mutable=True)
qd.update(response_dict)
qd.update(dict(ipaddress=self.ipaddress, st=self.st,
flag_info=self.flag_info))
pdt_form = PayPalPDTForm(qd, instance=self)
pdt_form.save(commit=False)

This way in case of a valid postback, _verify_postback() overwrites
the PDT object's data, but in the case of an invalid postback,
_verify_postback() just sets the flag. After a quick test I can see
the invalid PDT object in my DB with the flag set, and the query
containing the bogus tx. However, many of the fields that should be
filled in from the GET parameters are still blank, including the
txn_id. This part I haven't figured out yet, since
paypal.standard.pdt.views.pdt() won't create an object if there isn't
a txn_id. I'll follow up if I get any more answers.

- Cole
Reply all
Reply to author
Forward
0 new messages