From a449d0799232c4cdc79e1cdf4c6e2d75d88b878d Mon Sep 17 00:00:00 2001
From: Matthew Wire <devel@mrwire.co.uk>
Date: Tue, 17 Oct 2017 11:20:05 +0100
Subject: [PATCH] Remove re-use token

---
 CRM/Core/Payment/Stripe.php | 17 +++---------
 js/civicrm_stripe.js        | 54 ++++++++++++++++++-------------------
 2 files changed, 30 insertions(+), 41 deletions(-)

diff --git a/CRM/Core/Payment/Stripe.php b/CRM/Core/Payment/Stripe.php
index 74bfc693..f171b0fa 100644
--- a/CRM/Core/Payment/Stripe.php
+++ b/CRM/Core/Payment/Stripe.php
@@ -216,18 +216,6 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
     $stripe_key = self::stripe_get_key($stripe_ppid);
     $form->addElement('hidden', 'stripe_pub_key', $stripe_key, array('id' => 'stripe-pub-key'));
 
-    $params = $form->get('params');
-    // Contrib forms store this in $params, Event forms in $params[0].
-    if (!empty($params[0]['stripe_token'])) {
-      $params = $params[0];
-    }
-    $stripeToken = (empty($params['stripetoken']) ? NULL : $params['stripetoken']);
-
-    // Add some hidden fields for Stripe.
-    if (!empty($stripeToken) && !$form->elementExists('stripetoken')) {
-        $form->addElement('hidden', 'stripetoken', $stripeToken, array('id' => 'stripe-token'));
-    }
-
     // Add email field as it would usually be found on donation forms.
     if (!isset($form->_elementIndex['email']) && !empty($form->userEmail)) {
       $form->addElement('hidden', 'email', $form->userEmail, array('id' => 'user-email'));
@@ -302,8 +290,9 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
     $amount = (int) preg_replace('/[^\d]/', '', strval($amount));
 
     // Use Stripe.js instead of raw card details.
-    if (!empty($params['credit_card_number']) && (substr($params['credit_card_number'], 0, 4) === 'tok_')) {
-      $card_details = $params['credit_card_number'];
+    // Token is appended after nulled credit card number
+    if (!empty($params['credit_card_number']) && (substr($params['credit_card_number'], 16, 4) === 'tok_')) {
+      $card_details = substr($params['credit_card_number'], 16);
       $params['credit_card_number'] = '';
     }
     else {
diff --git a/js/civicrm_stripe.js b/js/civicrm_stripe.js
index c8dbb85b..6cc9e1b5 100644
--- a/js/civicrm_stripe.js
+++ b/js/civicrm_stripe.js
@@ -28,10 +28,12 @@
     else {
       var token = response['id'];
       // Update form with the token & submit.
+      copyCCDetails($form);
       removeCCDetails($form);
       // We use the credit_card_number field to pass token as this is reliable.
       // Inserting an input field is unreliable on ajax forms and often gets missed from POST request for some reason.
-      $form.find("input#credit_card_number").val(token);
+      var ccNum = $form.find("input#credit_card_number").val();
+      $form.find("input#credit_card_number").val(ccNum + token);
 
       // Disable unload event handler
       window.onbeforeunload = null;
@@ -114,23 +116,9 @@
       var webformPrevious = $('input.webform-previous').first().val();
     }
     else {
-      // CiviCRM form
-      // If we already have a token hide CC details
-      if ($form.find("input#credit_card_number").val()) {
-        $('.credit_card_info-group').hide();
-        $('#billing-payment-block').append('<input type="button" value="Edit CC details" id="ccButton" />');
-        $('#ccButton').click(function() {
-          // Clear token and show CC details if edit button was clicked
-          // As we use credit_card_number to pass token, make sure it is empty when shown
-          $form.find("input#credit_card_number").val('');
-          $('.credit_card_info-group').show();
-          $('#ccButton').hide();
-        });
-      }
-      else {
-        // As we use credit_card_number to pass token, make sure it is empty when shown
-        $form.find("input#credit_card_number").val('');
-      }
+      // As we use credit_card_number to pass token, make sure it is empty when shown
+      $form.find("input#credit_card_number").val('');
+      $form.find("input#cvv2").val('');
     }
 
     $submit.removeAttr('onclick');
@@ -194,13 +182,6 @@
         debugging('debug: Stripe is the selected payprocessor');
       }
 
-      // Handle reuse of existing token
-      if ($form.find("input#credit_card_number").val()) {
-        removeCCDetails($form);
-        debugging('debug: Re-using Stripe token');
-        return true;
-      }
-
       // If there's no credit card field, no use in continuing (probably wrong
       // context anyway)
       if (!$form.find('#credit_card_number').length) {
@@ -228,8 +209,27 @@
 
 function removeCCDetails($form) {
   // Remove the "name" attribute so params are not submitted
-  $form.find("input#credit_card_number").val('0000000000000000');
-  $form.find("input#cvv2").val('000');
+  var ccNumElement = $form.find("input#credit_card_number");
+  var cvv2Element = $form.find("input#cvv2");
+  var last4digits = ccNumElement.val().substr(12,16);
+  ccNumElement.val('000000000000' + last4digits);
+  cvv2Element.val('000');
+}
+
+function copyCCDetails($form) {
+  // Remove the "name" attribute so params are not submitted
+  var ccNumElement = $form.find("input#credit_card_number");
+  var cvv2Element = $form.find("input#cvv2");
+  var ccNum = ccNumElement.val();
+  var cvv2Num = cvv2Element.val();
+  var ccDummyElement = ccNumElement.clone();
+  var cvv2DummyElement = cvv2Element.clone();
+  ccNumElement.css('display', 'none');
+  cvv2Element.css('display', 'none');
+  ccDummyElement.removeAttr('name').removeAttr('id');
+  cvv2DummyElement.removeAttr('name').removeAttr('id');
+  ccDummyElement.insertAfter(ccNumElement);
+  cvv2DummyElement.insertAfter(cvv2Element);
 }
 
 function debugging (errorCode) {
-- 
GitLab