Simple Machines Community Forum

Customizing SMF => SMF Coding Discussion => Topic started by: Shotster on December 28, 2009, 12:27:38 PM

Title: Encrypted PayPal Subscription Payments
Post by: Shotster on December 28, 2009, 12:27:38 PM
I was planning to use the subscription feature of SMF, but it does not appear to support encrypted payments. I've already got a custom cart that uses encrypted PayPal payments, and my PayPal account is set up to accept only encrypted payments.

Can someone point me in the right direction as to which SMF file(s) to hack to encrypt the PayPal payment form?

Thanks,

-Steve
Title: Re: Encrypted PayPal Subscription Payments
Post by: Arantor on December 28, 2009, 12:32:28 PM
If you tell me which version of SMF, maybe I can help.
Title: Re: Encrypted PayPal Subscription Payments
Post by: Shotster on December 28, 2009, 12:40:08 PM
Quote from: Arantor on December 28, 2009, 12:32:28 PM
If you tell me which version of SMF, maybe I can help.

Oops, sorry. 2.0 RC2

-Steve
Title: Re: Encrypted PayPal Subscription Payments
Post by: Arantor on December 28, 2009, 12:44:48 PM
It'll be primarily Sources/Subscriptions-PayPal.php, I'd be guessing.
Title: Re: Encrypted PayPal Subscription Payments
Post by: Shotster on December 28, 2009, 01:22:07 PM
Quote from: Arantor on December 28, 2009, 12:44:48 PM
It'll be primarily Sources/Subscriptions-PayPal.php, I'd be guessing.

Yeah, I found that file. Thanks. I've got to refresh my memory on how to implement encrypted web payments.

-Steve
Title: Re: Encrypted PayPal Subscription Payments
Post by: Arantor on December 28, 2009, 01:23:00 PM
It's not something I've come across (especially since the subs system uses IPN; not sure if PayPal encrypts that differently?) but if you do have to modify it, I'd appreciate your notes on it.
Title: Re: Encrypted PayPal Subscription Payments
Post by: Shotster on January 01, 2010, 11:02:54 PM
Quote from: Arantor on December 28, 2009, 01:23:00 PMif you do have to modify it, I'd appreciate your notes on it.

It was relatively straightforward to get this working since I'd already implemented it elsewhere on my site and have configured my PayPal account to accept only encrypted payments. Details are on PayPal site, but the short and sweet of it is as follows...

You can download the encryption class and sample PHP code from PayPal. They refer to it as Encrypted Web Payments (EWP Services). You encrypt your form variables using the PayPal-provided encryption class so that someone viewing the source of your site can't read the details. Basically, all the form variables are wrapped up in an encrypted mess such that all you submit to PayPal (and all anyone viewing the HTML source sees) is something like the following...

<input type="hidden" id="paypal_cmd" name="cmd" value="_s-xclick" />
<input type="hidden" id="paypal_encrypted" name="encrypted" value="-----BEGIN
PKCS7-----
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
6uL8gwoOchlmRuEFEdLgJ+iM9HUBDhKyOpkV5s/
jSBFwQXcwcHgqTJkaqNY2w4u1cln24wL7Zvoan9E4n1EWiPiDZN0ezYsKz8lbpmBSl+AoVCVvze5CG8dfiS6bEQyhVg6QUem99l/
zJ0WjL1NxigLm+qBUFjqQP24DTXlbtzaVnu8bfwiq0t/5cfs+/CRjYdgVeiVKY4xL/F3PH3CuYkI/
jl9Hydez8WZlkRxXexkBdMd1KvP0PSPyRv8l4t/MF5LSVSpjWbL3SG7Qa1vSfIaz4Zs1niZXqAIYbKs8tIXIh2Vu51fcMn+
Hqfl6iFs6dyChPsyeiifaTf0O62il4/nvFLRpSp6jKX9v2bxdCmZyrQ55/EYiWYh3kX+
DCNgvkqOcApiVkcRVYVaSpA0k4QQlsUVrxCow6dgbALb0iv94TEgXs1eqszC84h6KildzZ2Mj/
76XYnTZ05MO3bXbHaFiQuCH1OIJlW3WHEDF600VAO/
UnQoSvW9K110NlS8Hfok6XJKnwVnRe3Y61oiNGzQ1Ulpj044eFdMB7UVbXDxgheP676UFVEjRVJQq1TcktWRhnxSB++
EZxcUED4sNDvcxcxD+i3TCVoDgE8zxpadsykMOWlUQ6J4VO/
lgyD1cyG449D0xnXbvSattZ9olfP2D4dgQuc3pJnijYhb69JxtUavK4/RY2TUUZiTPEqw3/
eAifYrvmVBApstYV6n3uBhDA7KpLUjPTFXZ2o5YzYFnj166o6cVXEcRCREiyTBHC99w5mXjYV0fTPNpQXR9buhTimiTouFVJ7Xtq
5mO3MsN5uvuf+8PnCUsD/A3vpTMvia7cB/6FAyfSYPrMtz3EaUBpYZX7M+tuOKZ4swRigOruDl3PF0bOR+O3O2UG0/
1IdAyKTPnraevBTAFlG52iJTTPAacy7ALFNqtFAbIjh6tGViwEza+HUccNG/VDk86IDhJl0ZtAU5hgNRfVvIoVtFtylAJoUAHolb
/VNe3GITlmAstrqITlWy0KHWRZwMd5QH1/HN0PDJX/mGraWyksHkLVcdeSzvVA==-----END PKCS7-----" />

So you're really just submitting two parameters to PayPal. All the actual details are in the encrypted mess. Here's my modified version of the fetchGatewayFields method of the paypal_display class in Subscriptions-PayPal.php...

public function fetchGatewayFields($unique_id, $sub_data, $value, $period, $return_url)
{
   global $modSettings, $txt, $boardurl;

   require_once PRIVATE_DATA_DIR . 'inc.paypal.php';
   require_once dirname(__FILE__) . '/../../ecom/pp/EWPServices.php';

   $return_data = array(
      'form'          => 'https://www.' . (DEBUG == 1 ? 'sandbox.' : '') . 'paypal.com/cgi-bin/webscr',
      'id'            => 'paypal',
      'hidden'        => array(),
      'title'         => $txt['paypal'],
      'desc'          => $txt['paid_confirm_paypal'],
      'submit'        => $txt['paid_paypal_order'],
      'javascript'    => '',
   );

   // All the standard bits.
   $pp_data['cert_id'] = MY_PUBLIC_CERT_ID;
   $pp_data['charset'] = 'utf-8';
   $pp_data['business'] = PP_BUSINESS_EMAIL;
   $pp_data['item_name'] = $sub_data['name'] . ' ' . $txt['subscription'];
   $pp_data['item_number'] = $unique_id;
   $pp_data['currency_code'] = strtoupper($modSettings['paid_currency_code']);
   $pp_data['no_shipping'] = 1;
   $pp_data['no_note'] = 1;
   $pp_data['amount'] = $value;
   $pp_data['cmd'] = !$sub_data['repeatable'] ? '_xclick' : '_xclick-subscriptions';
   $pp_data['return'] = $return_url;
   $pp_data['a3'] = $value;
   $pp_data['src'] = 1;
// $pp_data['notify_url'] = $boardurl . '/subscriptions.php';

   // Now stuff dependant on what we're doing.
   if ($sub_data['flexible'])
   {
      $pp_data['p3'] = 1;
      $pp_data['t3'] = strtoupper(substr($period, 0, 1));
   }
   else
   {
      preg_match('~(\d*)(\w)~', $sub_data['real_length'], $match);
      $unit = $match[1];
      $period = $match[2];

      $pp_data['p3'] = $unit;
      $pp_data['t3'] = $period;
   }

   // If it's repeatable do some javascript to respect this idea.
   if (!empty($sub_data['repeatable']))
      $return_data['javascript'] = '
         document.write(\'<label for="do_paypal_recur"><input type="checkbox" name="do_paypal_recur" id="do_paypal_recur" checked="checked" onclick="switchPaypalRecur();"  class="input_check" />' . $txt['paid_make_recurring'] . '</label><br />\');

         function switchPaypalRecur()
         {
            document.getElementById("paypal_cmd").value = document.getElementById("do_paypal_recur").checked ? "_xclick-subscriptions" : "_xclick";
         }';

   // Encrypt form data using PayPal-supplied class...
   $return_val = EWPServices::encryptButton(
      $pp_data,
      MY_PUBLIC_CERT,
      MY_PRIVATE_KEY,
      MY_PRIVATE_KEY_PW,
      PAYPAL_CERT,
      true                // data only - no button
   );

   if ($return_val['status']) {

      $return_data['hidden']['cmd'] = '_s-xclick';
      $return_data['hidden']['encrypted'] = $return_val['encryptedData'];

   } else {

      // Handle error
   }
   return $return_data;
}


I also use SSL (https) for my IPN notification url (which is specified in my PayPal account), so that's why I commented out the board's url in the above code.

Hope it helps,

-Steve
Title: Re: Encrypted PayPal Subscription Payments
Post by: Arantor on January 02, 2010, 08:23:43 AM
Cool, thanks :)

If you don't mind, I'd like to point the devs in this direction to see if it's possible to add this either to 2.0 or (more likely) 2.1...
Title: Re: Encrypted PayPal Subscription Payments
Post by: Shotster on January 02, 2010, 01:58:24 PM
Quote from: Arantor on January 02, 2010, 08:23:43 AMIf you don't mind, I'd like to point the devs in this direction to see if it's possible to add this either to 2.0 or (more likely) 2.1...

Of course I don't mind. I did, however, gloss over some details like generating / downloading the encryption certificates, but all the juicy details can be obtained from PayPal. Ideally, the SMF UI would provide the user with a way to enter (or point to the files containing) the requisite certificates, etc.

-Steve