WooCommerce Stripe Payment Gateway - Version 4.5.4

Version Description

  • 2020-11-16 =
  • Add - Stripe Connect OAuth.
  • Tweak - Add site_url to all transactions, not just recurring ones.
  • Add - Customer's full name is now included in Stripe Customer object if available.
  • Add - Accept payments via AliPay when store currency is set to CNY.
  • Tweak - Wording of Apple Pay link.
  • Fix - Serve Apple Pay domain verification file via a rewrite rule.
  • Add - Add Inbox note for Apple Pay domain verification if needed.
  • Add - Apple Pay holiday marketing notice.
  • Fix - Apple Pay: Ensure payer phone is available before attempting to access it.
  • Add - Pass payment method for renewal charges if not a source.
  • Fix - Ensure defaults are used for missing settings.
  • Add - Add shipping address to payment requests.
  • Fix - Fix the Not a valid URL notice.
  • Add - Security.md with security and vulnerability reporting guidelines.

See changelog for all versions.

Download this release

Release Info

Developer woothemes
Plugin Icon 128x128 WooCommerce Stripe Payment Gateway
Version 4.5.4
Comparing to
See all releases

Code changes from version 4.5.3 to 4.5.4

Files changed (31) hide show
  1. SECURITY.md +29 -0
  2. assets/js/stripe-admin.js +14 -0
  3. assets/js/stripe-admin.min.js +1 -1
  4. assets/js/stripe-payment-request.js +1 -1
  5. assets/js/stripe-payment-request.min.js +1 -1
  6. changelog.txt +16 -1
  7. includes/abstracts/abstract-wc-stripe-connect-rest-controller.php +168 -0
  8. includes/abstracts/abstract-wc-stripe-payment-gateway.php +27 -4
  9. includes/admin/class-wc-stripe-inbox-notes.php +130 -0
  10. includes/admin/stripe-alipay-settings.php +1 -1
  11. includes/admin/stripe-bancontact-settings.php +1 -1
  12. includes/admin/stripe-eps-settings.php +1 -1
  13. includes/admin/stripe-giropay-settings.php +1 -1
  14. includes/admin/stripe-ideal-settings.php +1 -1
  15. includes/admin/stripe-multibanco-settings.php +1 -1
  16. includes/admin/stripe-p24-settings.php +1 -1
  17. includes/admin/stripe-sepa-settings.php +1 -1
  18. includes/admin/stripe-settings.php +38 -1
  19. includes/admin/stripe-sofort-settings.php +1 -1
  20. includes/class-wc-gateway-stripe.php +1 -1
  21. includes/class-wc-stripe-apple-pay-registration.php +135 -126
  22. includes/class-wc-stripe-customer.php +10 -0
  23. includes/compat/class-wc-stripe-subs-compat.php +7 -6
  24. includes/connect/class-wc-stripe-connect-api.php +241 -0
  25. includes/connect/class-wc-stripe-connect-rest-oauth-connect-controller.php +69 -0
  26. includes/connect/class-wc-stripe-connect-rest-oauth-init-controller.php +69 -0
  27. includes/connect/class-wc-stripe-connect.php +196 -0
  28. includes/payment-methods/class-wc-gateway-stripe-alipay.php +1 -0
  29. languages/woocommerce-gateway-stripe.pot +220 -125
  30. readme.txt +17 -10
  31. woocommerce-gateway-stripe.php +88 -18
SECURITY.md ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Security Policy
2
+
3
+ Full details of the Automattic Security Policy can be found on [automattic.com](https://automattic.com/security/).
4
+
5
+ ## Supported Versions
6
+
7
+ Generally, only the latest version of the extension has continued support. In some cases, we may opt to backport critical vulnerabilities fixes to previous versions.
8
+
9
+ ## Reporting a Vulnerability
10
+
11
+ [WooCommerce Stripe Payment Gateway](https://woocommerce.com/products/stripe/) is an open-source plugin for WooCommerce. Our HackerOne program covers the plugin software.
12
+
13
+ **For responsible disclosure of security issues and to be eligible for our bug bounty program, please submit your report via the [HackerOne](https://hackerone.com/automattic) portal.**
14
+
15
+ _Please note that the **WordPress software is a separate entity** from Automattic. Please report vulnerabilities for WordPress through [the WordPress Foundation's HackerOne page](https://hackerone.com/wordpress)._
16
+
17
+ ## Guidelines
18
+
19
+ We're committed to working with security researchers to resolve the vulnerabilities they discover. You can help us by following these guidelines:
20
+
21
+ * Follow [HackerOne's disclosure guidelines](https://www.hackerone.com/disclosure-guidelines).
22
+ * Pen-testing Production:
23
+ * Please **setup a local environment** instead whenever possible. Most of our code is open source (see above).
24
+ * If that's not possible, **limit any data access/modification** to the bare minimum necessary to reproduce a PoC.
25
+ * **_Don't_ automate form submissions!** That's very annoying for us, because it adds extra work for the volunteers who manage those systems, and reduces the signal/noise ratio in our communication channels.
26
+ * To be eligible for a bounty, all of these guidelines must be followed.
27
+ * Be Patient - Give us a reasonable time to correct the issue before you disclose the vulnerability.
28
+
29
+ We also expect you to comply with all applicable laws. You're responsible to pay any taxes associated with your bounties.
assets/js/stripe-admin.js CHANGED
@@ -5,6 +5,7 @@ jQuery( function( $ ) {
5
  * Object to handle Stripe admin functions.
6
  */
7
  var wc_stripe_admin = {
 
8
  isTestMode: function() {
9
  return $( '#woocommerce_stripe_testmode' ).is( ':checked' );
10
  },
@@ -108,6 +109,19 @@ jQuery( function( $ ) {
108
  $dashicon.addClass( 'dashicons-hidden' );
109
  }
110
  } );
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  }
112
  };
113
 
5
  * Object to handle Stripe admin functions.
6
  */
7
  var wc_stripe_admin = {
8
+
9
  isTestMode: function() {
10
  return $( '#woocommerce_stripe_testmode' ).is( ':checked' );
11
  },
109
  $dashicon.addClass( 'dashicons-hidden' );
110
  }
111
  } );
112
+
113
+ $( 'form' ).find( 'input, select' ).on( 'change input', function disableConnect() {
114
+
115
+ $( '#wc_stripe_connect_button' ).addClass( 'disabled' );
116
+
117
+ $( '#wc_stripe_connect_button' ).on( 'click', function() { return false; } );
118
+
119
+ $( '#woocommerce_stripe_api_credentials' )
120
+ .next( 'p' )
121
+ .append( ' (Please save changes before selecting this button.)' );
122
+
123
+ $( 'form' ).find( 'input, select' ).off( 'change input', disableConnect );
124
+ } );
125
  }
126
  };
127
 
assets/js/stripe-admin.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(function(i){"use strict";var e={isTestMode:function(){return i("#woocommerce_stripe_testmode").is(":checked")},getSecretKey:function(){return e.isTestMode()?i("#woocommerce_stripe_test_secret_key").val():i("#woocommerce_stripe_secret_key").val()},init:function(){i(document.body).on("change","#woocommerce_stripe_testmode",function(){var e=i("#woocommerce_stripe_test_secret_key").parents("tr").eq(0),t=i("#woocommerce_stripe_test_publishable_key").parents("tr").eq(0),o=i("#woocommerce_stripe_test_webhook_secret").parents("tr").eq(0),s=i("#woocommerce_stripe_secret_key").parents("tr").eq(0),r=i("#woocommerce_stripe_publishable_key").parents("tr").eq(0),c=i("#woocommerce_stripe_webhook_secret").parents("tr").eq(0);i(this).is(":checked")?(e.show(),t.show(),o.show(),s.hide(),r.hide(),c.hide()):(e.hide(),t.hide(),o.hide(),s.show(),r.show(),c.show())}),i("#woocommerce_stripe_testmode").change(),i("#woocommerce_stripe_payment_request").change(function(){i(this).is(":checked")?i("#woocommerce_stripe_payment_request_button_theme, #woocommerce_stripe_payment_request_button_type, #woocommerce_stripe_payment_request_button_height").closest("tr").show():i("#woocommerce_stripe_payment_request_button_theme, #woocommerce_stripe_payment_request_button_type, #woocommerce_stripe_payment_request_button_height").closest("tr").hide()}).change(),i("#woocommerce_stripe_payment_request_button_type").change(function(){"custom"===i(this).val()?i("#woocommerce_stripe_payment_request_button_label").closest("tr").show():i("#woocommerce_stripe_payment_request_button_label").closest("tr").hide()}).change(),i("#woocommerce_stripe_payment_request_button_type").change(function(){"branded"===i(this).val()?i("#woocommerce_stripe_payment_request_button_branded_type").closest("tr").show():i("#woocommerce_stripe_payment_request_button_branded_type").closest("tr").hide()}).change(),i(".wc-stripe-3ds-missing").each(function(){var e=i(this);e.find(".notice-dismiss").on("click.wc-stripe-dismiss-notice",function(){i.ajax({type:"head",url:window.location.href+"&stripe_dismiss_3ds="+e.data("nonce")})})}),i("#woocommerce_stripe_test_secret_key, #woocommerce_stripe_secret_key, #woocommerce_stripe_test_webhook_secret, #woocommerce_stripe_webhook_secret").after('<button class="wc-stripe-toggle-secret" style="height: 30px; margin-left: 2px; cursor: pointer"><span class="dashicons dashicons-visibility"></span></button>'),i(".wc-stripe-toggle-secret").on("click",function(e){e.preventDefault();var t=i(this).closest("button").find(".dashicons"),o=i(this).closest("tr").find(".input-text");"text"==o.attr("type")?(o.attr("type","password"),t.removeClass("dashicons-hidden"),t.addClass("dashicons-visibility")):(o.attr("type","text"),t.removeClass("dashicons-visibility"),t.addClass("dashicons-hidden"))})}};e.init()});
1
+ jQuery(function(i){"use strict";var e={isTestMode:function(){return i("#woocommerce_stripe_testmode").is(":checked")},getSecretKey:function(){return e.isTestMode()?i("#woocommerce_stripe_test_secret_key").val():i("#woocommerce_stripe_secret_key").val()},init:function(){i(document.body).on("change","#woocommerce_stripe_testmode",function(){var e=i("#woocommerce_stripe_test_secret_key").parents("tr").eq(0),t=i("#woocommerce_stripe_test_publishable_key").parents("tr").eq(0),o=i("#woocommerce_stripe_test_webhook_secret").parents("tr").eq(0),s=i("#woocommerce_stripe_secret_key").parents("tr").eq(0),c=i("#woocommerce_stripe_publishable_key").parents("tr").eq(0),r=i("#woocommerce_stripe_webhook_secret").parents("tr").eq(0);i(this).is(":checked")?(e.show(),t.show(),o.show(),s.hide(),c.hide(),r.hide()):(e.hide(),t.hide(),o.hide(),s.show(),c.show(),r.show())}),i("#woocommerce_stripe_testmode").change(),i("#woocommerce_stripe_payment_request").change(function(){i(this).is(":checked")?i("#woocommerce_stripe_payment_request_button_theme, #woocommerce_stripe_payment_request_button_type, #woocommerce_stripe_payment_request_button_height").closest("tr").show():i("#woocommerce_stripe_payment_request_button_theme, #woocommerce_stripe_payment_request_button_type, #woocommerce_stripe_payment_request_button_height").closest("tr").hide()}).change(),i("#woocommerce_stripe_payment_request_button_type").change(function(){"custom"===i(this).val()?i("#woocommerce_stripe_payment_request_button_label").closest("tr").show():i("#woocommerce_stripe_payment_request_button_label").closest("tr").hide()}).change(),i("#woocommerce_stripe_payment_request_button_type").change(function(){"branded"===i(this).val()?i("#woocommerce_stripe_payment_request_button_branded_type").closest("tr").show():i("#woocommerce_stripe_payment_request_button_branded_type").closest("tr").hide()}).change(),i(".wc-stripe-3ds-missing").each(function(){var e=i(this);e.find(".notice-dismiss").on("click.wc-stripe-dismiss-notice",function(){i.ajax({type:"head",url:window.location.href+"&stripe_dismiss_3ds="+e.data("nonce")})})}),i("#woocommerce_stripe_test_secret_key, #woocommerce_stripe_secret_key, #woocommerce_stripe_test_webhook_secret, #woocommerce_stripe_webhook_secret").after('<button class="wc-stripe-toggle-secret" style="height: 30px; margin-left: 2px; cursor: pointer"><span class="dashicons dashicons-visibility"></span></button>'),i(".wc-stripe-toggle-secret").on("click",function(e){e.preventDefault();var t=i(this).closest("button").find(".dashicons"),o=i(this).closest("tr").find(".input-text");"text"==o.attr("type")?(o.attr("type","password"),t.removeClass("dashicons-hidden"),t.addClass("dashicons-visibility")):(o.attr("type","text"),t.removeClass("dashicons-visibility"),t.addClass("dashicons-hidden"))}),i("form").find("input, select").on("change input",function e(){i("#wc_stripe_connect_button").addClass("disabled"),i("#wc_stripe_connect_button").on("click",function(){return!1}),i("#woocommerce_stripe_api_credentials").next("p").append(" (Please save changes before selecting this button.)"),i("form").find("input, select").off("change input",e)})}};e.init()});
assets/js/stripe-payment-request.js CHANGED
@@ -94,7 +94,7 @@ jQuery( function( $ ) {
94
  billing_last_name: null !== name ? name.split( ' ' ).slice( 1 ).join( ' ' ) : '',
95
  billing_company: '',
96
  billing_email: null !== email ? email : evt.payerEmail,
97
- billing_phone: null !== phone ? phone : evt.payerPhone.replace( '/[() -]/g', '' ),
98
  billing_country: null !== billing ? billing.country : '',
99
  billing_address_1: null !== billing ? billing.line1 : '',
100
  billing_address_2: null !== billing ? billing.line2 : '',
94
  billing_last_name: null !== name ? name.split( ' ' ).slice( 1 ).join( ' ' ) : '',
95
  billing_company: '',
96
  billing_email: null !== email ? email : evt.payerEmail,
97
+ billing_phone: null !== phone ? phone : evt.payerPhone && evt.payerPhone.replace( '/[() -]/g', '' ),
98
  billing_country: null !== billing ? billing.country : '',
99
  billing_address_1: null !== billing ? billing.line1 : '',
100
  billing_address_2: null !== billing ? billing.line2 : '',
assets/js/stripe-payment-request.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(function(i){"use strict";var o,u=Stripe(wc_stripe_payment_request_params.stripe.key),p={getAjaxURL:function(t){return wc_stripe_payment_request_params.ajax_url.toString().replace("%%endpoint%%","wc_stripe_"+t)},getCartDetails:function(){var t={security:wc_stripe_payment_request_params.nonce.payment};i.ajax({type:"POST",data:t,url:p.getAjaxURL("get_cart_details"),success:function(t){p.startPaymentRequest(t)}})},getAttributes:function(){var t=i(".variations_form").find(".variations select"),a={},n=0,s=0;return t.each(function(){var t=i(this).data("attribute_name")||i(this).attr("name"),e=i(this).val()||"";0<e.length&&s++,n++,a[t]=e}),{count:n,chosenCount:s,data:a}},processSource:function(t,e){var a=p.getOrderData(t,e);return i.ajax({type:"POST",data:a,dataType:"json",url:p.getAjaxURL("create_order")})},getOrderData:function(t,e){var a=t.source,n=a.owner.email,s=a.owner.phone,r=a.owner.address,i=a.owner.name,o=t.shippingAddress,u={_wpnonce:wc_stripe_payment_request_params.nonce.checkout,billing_first_name:null!==i?i.split(" ").slice(0,1).join(" "):"",billing_last_name:null!==i?i.split(" ").slice(1).join(" "):"",billing_company:"",billing_email:null!==n?n:t.payerEmail,billing_phone:null!==s?s:t.payerPhone.replace("/[() -]/g",""),billing_country:null!==r?r.country:"",billing_address_1:null!==r?r.line1:"",billing_address_2:null!==r?r.line2:"",billing_city:null!==r?r.city:"",billing_state:null!==r?r.state:"",billing_postcode:null!==r?r.postal_code:"",shipping_first_name:"",shipping_last_name:"",shipping_company:"",shipping_country:"",shipping_address_1:"",shipping_address_2:"",shipping_city:"",shipping_state:"",shipping_postcode:"",shipping_method:[null===t.shippingOption?null:t.shippingOption.id],order_comments:"",payment_method:"stripe",ship_to_different_address:1,terms:1,stripe_source:a.id,payment_request_type:e};return o&&(u.shipping_first_name=o.recipient.split(" ").slice(0,1).join(" "),u.shipping_last_name=o.recipient.split(" ").slice(1).join(" "),u.shipping_company=o.organization,u.shipping_country=o.country,u.shipping_address_1=void 0===o.addressLine[0]?"":o.addressLine[0],u.shipping_address_2=void 0===o.addressLine[1]?"":o.addressLine[1],u.shipping_city=o.city,u.shipping_state=o.region,u.shipping_postcode=o.postalCode),u},getErrorMessageHTML:function(t){return i('<div class="woocommerce-error" />').text(t)},abortPayment:function(t,e){if(t.complete("fail"),i(".woocommerce-error").remove(),wc_stripe_payment_request_params.is_product_page){var a=i(".product");a.before(e),i("html, body").animate({scrollTop:a.prev(".woocommerce-error").offset().top},600)}else{var n=i(".shop_table.cart").closest("form");n.before(e),i("html, body").animate({scrollTop:n.prev(".woocommerce-error").offset().top},600)}},completePayment:function(t,e){p.block(),t.complete("success"),window.location=e},block:function(){i.blockUI({message:null,overlayCSS:{background:"#fff",opacity:.6}})},updateShippingOptions:function(t,e){var a={security:wc_stripe_payment_request_params.nonce.shipping,country:e.country,state:e.region,postcode:e.postalCode,city:e.city,address:void 0===e.addressLine[0]?"":e.addressLine[0],address_2:void 0===e.addressLine[1]?"":e.addressLine[1],payment_request_type:o,is_product_page:wc_stripe_payment_request_params.is_product_page};return i.ajax({type:"POST",data:a,url:p.getAjaxURL("get_shipping_options")})},updateShippingDetails:function(t,e){var a={security:wc_stripe_payment_request_params.nonce.update_shipping,shipping_method:[e.id],payment_request_type:o,is_product_page:wc_stripe_payment_request_params.is_product_page};return i.ajax({type:"POST",data:a,url:p.getAjaxURL("update_shipping_method")})},addToCart:function(){var t=i(".single_add_to_cart_button").val();i(".single_variation_wrap").length&&(t=i(".single_variation_wrap").find('input[name="product_id"]').val());var n={security:wc_stripe_payment_request_params.nonce.add_to_cart,product_id:t,qty:i(".quantity .qty").val(),attributes:i(".variations_form").length?p.getAttributes().data:[]},e=i("form.cart").serializeArray();return i.each(e,function(t,e){if(/^addon-/.test(e.name))if(/\[\]$/.test(e.name)){var a=e.name.substring(0,e.name.length-2);n[a]?n[a].push(e.value):n[a]=[e.value]}else n[e.name]=e.value}),i.ajax({type:"POST",data:n,url:p.getAjaxURL("add_to_cart")})},clearCart:function(){var t={security:wc_stripe_payment_request_params.nonce.clear_cart};return i.ajax({type:"POST",data:t,url:p.getAjaxURL("clear_cart"),success:function(t){}})},getRequestOptionsFromLocal:function(){return{total:wc_stripe_payment_request_params.product.total,currency:wc_stripe_payment_request_params.checkout.currency_code,country:wc_stripe_payment_request_params.checkout.country_code,requestPayerName:!0,requestPayerEmail:!0,requestPayerPhone:wc_stripe_payment_request_params.checkout.needs_payer_phone,requestShipping:wc_stripe_payment_request_params.product.requestShipping,displayItems:wc_stripe_payment_request_params.product.displayItems}},startPaymentRequest:function(t){var a,e;a=wc_stripe_payment_request_params.is_product_page?e=p.getRequestOptionsFromLocal():(e={total:t.order_data.total,currency:t.order_data.currency,country:t.order_data.country_code,requestPayerName:!0,requestPayerEmail:!0,requestPayerPhone:wc_stripe_payment_request_params.checkout.needs_payer_phone,requestShipping:!!t.shipping_required,displayItems:t.order_data.displayItems},t.order_data);var n=u.paymentRequest(e),s=u.elements({locale:wc_stripe_payment_request_params.button.locale}),r=p.createPaymentRequestButton(s,n);n.canMakePayment().then(function(t){t&&(o=t.applePay?"apple_pay":"payment_request_api",p.attachPaymentRequestButtonEventListeners(r,n),p.showPaymentRequestButton(r))}),n.on("shippingaddresschange",function(e){i.when(p.updateShippingOptions(a,e.shippingAddress)).then(function(t){e.updateWith({status:t.result,shippingOptions:t.shipping_options,total:t.total,displayItems:t.displayItems})})}),n.on("shippingoptionchange",function(e){i.when(p.updateShippingDetails(a,e.shippingOption)).then(function(t){"success"===t.result&&e.updateWith({status:"success",total:t.total,displayItems:t.displayItems}),"fail"===t.result&&e.updateWith({status:"fail"})})}),n.on("source",function(e){"no"===wc_stripe_payment_request_params.stripe.allow_prepaid_card&&"prepaid"===e.source.card.funding?p.abortPayment(e,p.getErrorMessageHTML(wc_stripe_payment_request_params.i18n.no_prepaid_card)):i.when(p.processSource(e,o)).then(function(t){"success"===t.result?p.completePayment(e,t.redirect):p.abortPayment(e,t.messages)})})},getSelectedProductData:function(){var t=i(".single_add_to_cart_button").val();i(".single_variation_wrap").length&&(t=i(".single_variation_wrap").find('input[name="product_id"]').val());var e=(i("#product-addons-total").data("price_data")||[]).reduce(function(t,e){return t+e.cost},0),a={security:wc_stripe_payment_request_params.nonce.get_selected_product_data,product_id:t,qty:i(".quantity .qty").val(),attributes:i(".variations_form").length?p.getAttributes().data:[],addon_value:e};return i.ajax({type:"POST",data:a,url:p.getAjaxURL("get_selected_product_data")})},debounce:function(n,s,r){var i;return function(){var t=this,e=arguments,a=r&&!i;clearTimeout(i),i=setTimeout(function(){i=null,r||s.apply(t,e)},n),a&&s.apply(t,e)}},createPaymentRequestButton:function(t,e){var a;if(wc_stripe_payment_request_params.button.is_custom&&(a=i(wc_stripe_payment_request_params.button.css_selector)).length)return a.data("isCustom",!0),a;if(wc_stripe_payment_request_params.button.is_branded){if(p.shouldUseGooglePayBrand())return(a=p.createGooglePayButton()).data("isBranded",!0),a;wc_stripe_payment_request_params.button.type="long"===wc_stripe_payment_request_params.button.branded_type?"buy":"default"}return t.create("paymentRequestButton",{paymentRequest:e,style:{paymentRequestButton:{type:wc_stripe_payment_request_params.button.type,theme:wc_stripe_payment_request_params.button.theme,height:wc_stripe_payment_request_params.button.height+"px"}}})},isCustomPaymentRequestButton:function(t){return t&&"function"==typeof t.data&&t.data("isCustom")},isBrandedPaymentRequestButton:function(t){return t&&"function"==typeof t.data&&t.data("isBranded")},shouldUseGooglePayBrand:function(){var t=window.navigator.userAgent.toLowerCase(),e=/chrome/.test(t)&&!/edge|edg|opr|brave\//.test(t)&&"Google Inc."===window.navigator.vendor,a=e&&window.navigator.brave;return e&&!a},createGooglePayButton:function(){var t=wc_stripe_payment_request_params.button.theme,e=wc_stripe_payment_request_params.button.branded_type,a=wc_stripe_payment_request_params.button.locale,n=wc_stripe_payment_request_params.button.height;t=["dark","light"].includes(t)?t:"light",e=["short","long"].includes(e)?e:"long";var s=i('<button type="button" id="wc-stripe-branded-button" aria-label="Google Pay" class="gpay-button"></button>');s.css("height",n+"px"),s.addClass(t+" "+e),"long"===e&&function(t,e,a){t.css("background-image","url("+e+")");var n=document.createElement("img");n.onerror=function(){t.css("background-image","url("+a+")")},n.src=e}(s,"https://www.gstatic.com/instantbuy/svg/"+t+"/"+a+".svg","https://www.gstatic.com/instantbuy/svg/"+t+"/en.svg");return s},attachPaymentRequestButtonEventListeners:function(t,e){wc_stripe_payment_request_params.is_product_page?p.attachProductPageEventListeners(t,e):p.attachCartPageEventListeners(t,e)},attachProductPageEventListeners:function(e,a){var n=[],s=i(".single_add_to_cart_button");e.on("click",function(t){return s.is(".disabled")?(t.preventDefault(),void(s.is(".wc-variation-is-unavailable")?window.alert(wc_add_to_cart_variation_params.i18n_unavailable_text):s.is(".wc-variation-selection-needed")&&window.alert(wc_add_to_cart_variation_params.i18n_make_a_selection_text))):0<n.length?(t.preventDefault(),void window.alert(n)):(p.addToCart(),void((p.isCustomPaymentRequestButton(e)||p.isBrandedPaymentRequestButton(e))&&(t.preventDefault(),a.show())))}),i(document.body).on("woocommerce_variation_has_changed",function(){p.blockPaymentRequestButton(e),i.when(p.getSelectedProductData()).then(function(t){i.when(a.update({total:t.total,displayItems:t.displayItems})).then(function(){p.unblockPaymentRequestButton(e)})})}),i(".quantity").on("input",".qty",function(){p.blockPaymentRequestButton(e)}),i(".quantity").on("input",".qty",p.debounce(250,function(){p.blockPaymentRequestButton(e),n=[],i.when(p.getSelectedProductData()).then(function(t){t.error?(n=[t.error],p.unblockPaymentRequestButton(e)):i.when(a.update({total:t.total,displayItems:t.displayItems})).then(function(){p.unblockPaymentRequestButton(e)})})}))},attachCartPageEventListeners:function(t,e){(wc_stripe_payment_request_params.button.is_custom&&p.isCustomPaymentRequestButton(t)||wc_stripe_payment_request_params.button.is_branded&&p.isBrandedPaymentRequestButton(t))&&t.on("click",function(t){t.preventDefault(),e.show()})},showPaymentRequestButton:function(t){p.isCustomPaymentRequestButton(t)?(t.addClass("is-active"),i("#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator").show()):p.isBrandedPaymentRequestButton(t)?(i("#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator").show(),i("#wc-stripe-payment-request-button").html(t)):i("#wc-stripe-payment-request-button").length&&(i("#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator").show(),t.mount("#wc-stripe-payment-request-button"))},blockPaymentRequestButton:function(t){i("#wc-stripe-payment-request-button").data("blockUI.isBlocked")||(i("#wc-stripe-payment-request-button").block({message:null}),p.isCustomPaymentRequestButton(t)&&t.addClass("is-blocked"))},unblockPaymentRequestButton:function(t){i("#wc-stripe-payment-request-button").unblock(),p.isCustomPaymentRequestButton(t)&&t.removeClass("is-blocked")},init:function(){wc_stripe_payment_request_params.is_product_page?p.startPaymentRequest(""):p.getCartDetails()}};p.init(),i(document.body).on("updated_cart_totals",function(){p.init()}),i(document.body).on("updated_checkout",function(){p.init()})});
1
+ jQuery(function(i){"use strict";var o,u=Stripe(wc_stripe_payment_request_params.stripe.key),p={getAjaxURL:function(t){return wc_stripe_payment_request_params.ajax_url.toString().replace("%%endpoint%%","wc_stripe_"+t)},getCartDetails:function(){var t={security:wc_stripe_payment_request_params.nonce.payment};i.ajax({type:"POST",data:t,url:p.getAjaxURL("get_cart_details"),success:function(t){p.startPaymentRequest(t)}})},getAttributes:function(){var t=i(".variations_form").find(".variations select"),a={},n=0,s=0;return t.each(function(){var t=i(this).data("attribute_name")||i(this).attr("name"),e=i(this).val()||"";0<e.length&&s++,n++,a[t]=e}),{count:n,chosenCount:s,data:a}},processSource:function(t,e){var a=p.getOrderData(t,e);return i.ajax({type:"POST",data:a,dataType:"json",url:p.getAjaxURL("create_order")})},getOrderData:function(t,e){var a=t.source,n=a.owner.email,s=a.owner.phone,r=a.owner.address,i=a.owner.name,o=t.shippingAddress,u={_wpnonce:wc_stripe_payment_request_params.nonce.checkout,billing_first_name:null!==i?i.split(" ").slice(0,1).join(" "):"",billing_last_name:null!==i?i.split(" ").slice(1).join(" "):"",billing_company:"",billing_email:null!==n?n:t.payerEmail,billing_phone:null!==s?s:t.payerPhone&&t.payerPhone.replace("/[() -]/g",""),billing_country:null!==r?r.country:"",billing_address_1:null!==r?r.line1:"",billing_address_2:null!==r?r.line2:"",billing_city:null!==r?r.city:"",billing_state:null!==r?r.state:"",billing_postcode:null!==r?r.postal_code:"",shipping_first_name:"",shipping_last_name:"",shipping_company:"",shipping_country:"",shipping_address_1:"",shipping_address_2:"",shipping_city:"",shipping_state:"",shipping_postcode:"",shipping_method:[null===t.shippingOption?null:t.shippingOption.id],order_comments:"",payment_method:"stripe",ship_to_different_address:1,terms:1,stripe_source:a.id,payment_request_type:e};return o&&(u.shipping_first_name=o.recipient.split(" ").slice(0,1).join(" "),u.shipping_last_name=o.recipient.split(" ").slice(1).join(" "),u.shipping_company=o.organization,u.shipping_country=o.country,u.shipping_address_1=void 0===o.addressLine[0]?"":o.addressLine[0],u.shipping_address_2=void 0===o.addressLine[1]?"":o.addressLine[1],u.shipping_city=o.city,u.shipping_state=o.region,u.shipping_postcode=o.postalCode),u},getErrorMessageHTML:function(t){return i('<div class="woocommerce-error" />').text(t)},abortPayment:function(t,e){if(t.complete("fail"),i(".woocommerce-error").remove(),wc_stripe_payment_request_params.is_product_page){var a=i(".product");a.before(e),i("html, body").animate({scrollTop:a.prev(".woocommerce-error").offset().top},600)}else{var n=i(".shop_table.cart").closest("form");n.before(e),i("html, body").animate({scrollTop:n.prev(".woocommerce-error").offset().top},600)}},completePayment:function(t,e){p.block(),t.complete("success"),window.location=e},block:function(){i.blockUI({message:null,overlayCSS:{background:"#fff",opacity:.6}})},updateShippingOptions:function(t,e){var a={security:wc_stripe_payment_request_params.nonce.shipping,country:e.country,state:e.region,postcode:e.postalCode,city:e.city,address:void 0===e.addressLine[0]?"":e.addressLine[0],address_2:void 0===e.addressLine[1]?"":e.addressLine[1],payment_request_type:o,is_product_page:wc_stripe_payment_request_params.is_product_page};return i.ajax({type:"POST",data:a,url:p.getAjaxURL("get_shipping_options")})},updateShippingDetails:function(t,e){var a={security:wc_stripe_payment_request_params.nonce.update_shipping,shipping_method:[e.id],payment_request_type:o,is_product_page:wc_stripe_payment_request_params.is_product_page};return i.ajax({type:"POST",data:a,url:p.getAjaxURL("update_shipping_method")})},addToCart:function(){var t=i(".single_add_to_cart_button").val();i(".single_variation_wrap").length&&(t=i(".single_variation_wrap").find('input[name="product_id"]').val());var n={security:wc_stripe_payment_request_params.nonce.add_to_cart,product_id:t,qty:i(".quantity .qty").val(),attributes:i(".variations_form").length?p.getAttributes().data:[]},e=i("form.cart").serializeArray();return i.each(e,function(t,e){if(/^addon-/.test(e.name))if(/\[\]$/.test(e.name)){var a=e.name.substring(0,e.name.length-2);n[a]?n[a].push(e.value):n[a]=[e.value]}else n[e.name]=e.value}),i.ajax({type:"POST",data:n,url:p.getAjaxURL("add_to_cart")})},clearCart:function(){var t={security:wc_stripe_payment_request_params.nonce.clear_cart};return i.ajax({type:"POST",data:t,url:p.getAjaxURL("clear_cart"),success:function(t){}})},getRequestOptionsFromLocal:function(){return{total:wc_stripe_payment_request_params.product.total,currency:wc_stripe_payment_request_params.checkout.currency_code,country:wc_stripe_payment_request_params.checkout.country_code,requestPayerName:!0,requestPayerEmail:!0,requestPayerPhone:wc_stripe_payment_request_params.checkout.needs_payer_phone,requestShipping:wc_stripe_payment_request_params.product.requestShipping,displayItems:wc_stripe_payment_request_params.product.displayItems}},startPaymentRequest:function(t){var a,e;a=wc_stripe_payment_request_params.is_product_page?e=p.getRequestOptionsFromLocal():(e={total:t.order_data.total,currency:t.order_data.currency,country:t.order_data.country_code,requestPayerName:!0,requestPayerEmail:!0,requestPayerPhone:wc_stripe_payment_request_params.checkout.needs_payer_phone,requestShipping:!!t.shipping_required,displayItems:t.order_data.displayItems},t.order_data);var n=u.paymentRequest(e),s=u.elements({locale:wc_stripe_payment_request_params.button.locale}),r=p.createPaymentRequestButton(s,n);n.canMakePayment().then(function(t){t&&(o=t.applePay?"apple_pay":"payment_request_api",p.attachPaymentRequestButtonEventListeners(r,n),p.showPaymentRequestButton(r))}),n.on("shippingaddresschange",function(e){i.when(p.updateShippingOptions(a,e.shippingAddress)).then(function(t){e.updateWith({status:t.result,shippingOptions:t.shipping_options,total:t.total,displayItems:t.displayItems})})}),n.on("shippingoptionchange",function(e){i.when(p.updateShippingDetails(a,e.shippingOption)).then(function(t){"success"===t.result&&e.updateWith({status:"success",total:t.total,displayItems:t.displayItems}),"fail"===t.result&&e.updateWith({status:"fail"})})}),n.on("source",function(e){"no"===wc_stripe_payment_request_params.stripe.allow_prepaid_card&&"prepaid"===e.source.card.funding?p.abortPayment(e,p.getErrorMessageHTML(wc_stripe_payment_request_params.i18n.no_prepaid_card)):i.when(p.processSource(e,o)).then(function(t){"success"===t.result?p.completePayment(e,t.redirect):p.abortPayment(e,t.messages)})})},getSelectedProductData:function(){var t=i(".single_add_to_cart_button").val();i(".single_variation_wrap").length&&(t=i(".single_variation_wrap").find('input[name="product_id"]').val());var e=(i("#product-addons-total").data("price_data")||[]).reduce(function(t,e){return t+e.cost},0),a={security:wc_stripe_payment_request_params.nonce.get_selected_product_data,product_id:t,qty:i(".quantity .qty").val(),attributes:i(".variations_form").length?p.getAttributes().data:[],addon_value:e};return i.ajax({type:"POST",data:a,url:p.getAjaxURL("get_selected_product_data")})},debounce:function(n,s,r){var i;return function(){var t=this,e=arguments,a=r&&!i;clearTimeout(i),i=setTimeout(function(){i=null,r||s.apply(t,e)},n),a&&s.apply(t,e)}},createPaymentRequestButton:function(t,e){var a;if(wc_stripe_payment_request_params.button.is_custom&&(a=i(wc_stripe_payment_request_params.button.css_selector)).length)return a.data("isCustom",!0),a;if(wc_stripe_payment_request_params.button.is_branded){if(p.shouldUseGooglePayBrand())return(a=p.createGooglePayButton()).data("isBranded",!0),a;wc_stripe_payment_request_params.button.type="long"===wc_stripe_payment_request_params.button.branded_type?"buy":"default"}return t.create("paymentRequestButton",{paymentRequest:e,style:{paymentRequestButton:{type:wc_stripe_payment_request_params.button.type,theme:wc_stripe_payment_request_params.button.theme,height:wc_stripe_payment_request_params.button.height+"px"}}})},isCustomPaymentRequestButton:function(t){return t&&"function"==typeof t.data&&t.data("isCustom")},isBrandedPaymentRequestButton:function(t){return t&&"function"==typeof t.data&&t.data("isBranded")},shouldUseGooglePayBrand:function(){var t=window.navigator.userAgent.toLowerCase(),e=/chrome/.test(t)&&!/edge|edg|opr|brave\//.test(t)&&"Google Inc."===window.navigator.vendor,a=e&&window.navigator.brave;return e&&!a},createGooglePayButton:function(){var t=wc_stripe_payment_request_params.button.theme,e=wc_stripe_payment_request_params.button.branded_type,a=wc_stripe_payment_request_params.button.locale,n=wc_stripe_payment_request_params.button.height;t=["dark","light"].includes(t)?t:"light",e=["short","long"].includes(e)?e:"long";var s=i('<button type="button" id="wc-stripe-branded-button" aria-label="Google Pay" class="gpay-button"></button>');s.css("height",n+"px"),s.addClass(t+" "+e),"long"===e&&function(t,e,a){t.css("background-image","url("+e+")");var n=document.createElement("img");n.onerror=function(){t.css("background-image","url("+a+")")},n.src=e}(s,"https://www.gstatic.com/instantbuy/svg/"+t+"/"+a+".svg","https://www.gstatic.com/instantbuy/svg/"+t+"/en.svg");return s},attachPaymentRequestButtonEventListeners:function(t,e){wc_stripe_payment_request_params.is_product_page?p.attachProductPageEventListeners(t,e):p.attachCartPageEventListeners(t,e)},attachProductPageEventListeners:function(e,a){var n=[],s=i(".single_add_to_cart_button");e.on("click",function(t){return s.is(".disabled")?(t.preventDefault(),void(s.is(".wc-variation-is-unavailable")?window.alert(wc_add_to_cart_variation_params.i18n_unavailable_text):s.is(".wc-variation-selection-needed")&&window.alert(wc_add_to_cart_variation_params.i18n_make_a_selection_text))):0<n.length?(t.preventDefault(),void window.alert(n)):(p.addToCart(),void((p.isCustomPaymentRequestButton(e)||p.isBrandedPaymentRequestButton(e))&&(t.preventDefault(),a.show())))}),i(document.body).on("woocommerce_variation_has_changed",function(){p.blockPaymentRequestButton(e),i.when(p.getSelectedProductData()).then(function(t){i.when(a.update({total:t.total,displayItems:t.displayItems})).then(function(){p.unblockPaymentRequestButton(e)})})}),i(".quantity").on("input",".qty",function(){p.blockPaymentRequestButton(e)}),i(".quantity").on("input",".qty",p.debounce(250,function(){p.blockPaymentRequestButton(e),n=[],i.when(p.getSelectedProductData()).then(function(t){t.error?(n=[t.error],p.unblockPaymentRequestButton(e)):i.when(a.update({total:t.total,displayItems:t.displayItems})).then(function(){p.unblockPaymentRequestButton(e)})})}))},attachCartPageEventListeners:function(t,e){(wc_stripe_payment_request_params.button.is_custom&&p.isCustomPaymentRequestButton(t)||wc_stripe_payment_request_params.button.is_branded&&p.isBrandedPaymentRequestButton(t))&&t.on("click",function(t){t.preventDefault(),e.show()})},showPaymentRequestButton:function(t){p.isCustomPaymentRequestButton(t)?(t.addClass("is-active"),i("#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator").show()):p.isBrandedPaymentRequestButton(t)?(i("#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator").show(),i("#wc-stripe-payment-request-button").html(t)):i("#wc-stripe-payment-request-button").length&&(i("#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator").show(),t.mount("#wc-stripe-payment-request-button"))},blockPaymentRequestButton:function(t){i("#wc-stripe-payment-request-button").data("blockUI.isBlocked")||(i("#wc-stripe-payment-request-button").block({message:null}),p.isCustomPaymentRequestButton(t)&&t.addClass("is-blocked"))},unblockPaymentRequestButton:function(t){i("#wc-stripe-payment-request-button").unblock(),p.isCustomPaymentRequestButton(t)&&t.removeClass("is-blocked")},init:function(){wc_stripe_payment_request_params.is_product_page?p.startPaymentRequest(""):p.getCartDetails()}};p.init(),i(document.body).on("updated_cart_totals",function(){p.init()}),i(document.body).on("updated_checkout",function(){p.init()})});
changelog.txt CHANGED
@@ -1,5 +1,21 @@
1
  *** Changelog ***
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  = 4.5.3 - 2020-10-06 =
4
  * Fix - Apple Pay now requires a buyer's phone number only if it's required in Appearance > Customize > WooCommerce > Checkout.
5
  * Add - Allow toggling secrets temporarily to visible in settings.
@@ -7,7 +23,6 @@
7
  * Tweak - Update payment request button description to include link to Stripe dashboard Apple Pay settings.
8
  * Add - Add off session payment intent filter, props rfair404.
9
  * Tweak - Update contributors list.
10
- * Add - Link from Payment Request button setting to Apple Pay settings in Stripe dashboard.
11
 
12
  = 4.5.2 - 2020-08-19 =
13
  * Fix - Allow extension to attempt to run in all countries, not just officially supported ones
1
  *** Changelog ***
2
 
3
+ = 4.5.4 - 2020-11-16 =
4
+ * Add - Stripe Connect OAuth.
5
+ * Tweak - Add site_url to all transactions, not just recurring ones.
6
+ * Add - Customer's full name is now included in Stripe Customer object if available.
7
+ * Add - Accept payments via AliPay when store currency is set to CNY.
8
+ * Tweak - Wording of Apple Pay link.
9
+ * Fix - Serve Apple Pay domain verification file via a rewrite rule.
10
+ * Add - Add Inbox note for Apple Pay domain verification if needed.
11
+ * Add - Apple Pay holiday marketing notice.
12
+ * Fix - Apple Pay: Ensure payer phone is available before attempting to access it.
13
+ * Add - Pass payment method for renewal charges if not a source.
14
+ * Fix - Ensure defaults are used for missing settings.
15
+ * Add - Add shipping address to payment requests.
16
+ * Fix - Fix the Not a valid URL notice.
17
+ * Add - Security.md with security and vulnerability reporting guidelines.
18
+
19
  = 4.5.3 - 2020-10-06 =
20
  * Fix - Apple Pay now requires a buyer's phone number only if it's required in Appearance > Customize > WooCommerce > Checkout.
21
  * Add - Allow toggling secrets temporarily to visible in settings.
23
  * Tweak - Update payment request button description to include link to Stripe dashboard Apple Pay settings.
24
  * Add - Add off session payment intent filter, props rfair404.
25
  * Tweak - Update contributors list.
 
26
 
27
  = 4.5.2 - 2020-08-19 =
28
  * Fix - Allow extension to attempt to run in all countries, not just officially supported ones
includes/abstracts/abstract-wc-stripe-connect-rest-controller.php ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
+ }
6
+
7
+ /**
8
+ * Stripe Connect base REST controller class.
9
+ */
10
+ abstract class WC_Stripe_Connect_REST_Controller extends WP_REST_Controller {
11
+
12
+ /**
13
+ * Endpoint namespace.
14
+ *
15
+ * @var string
16
+ */
17
+ protected $namespace = 'wc/v1';
18
+
19
+ /**
20
+ * Stripe connect api.
21
+ *
22
+ * @var object $api
23
+ */
24
+ private $api;
25
+
26
+ /**
27
+ * Constructor.
28
+ *
29
+ * @param WC_Stripe_Connect_API $api stripe connect api.
30
+ */
31
+ public function __construct( WC_Stripe_Connect_API $api ) {
32
+
33
+ $this->api = $api;
34
+ }
35
+
36
+ /**
37
+ * Registers rest routes for stripe connect functionality
38
+ */
39
+ public function register_routes() {
40
+
41
+ if ( method_exists( $this, 'get' ) ) {
42
+ register_rest_route(
43
+ $this->namespace,
44
+ '/' . $this->rest_base,
45
+ array(
46
+ array(
47
+ 'methods' => 'GET',
48
+ 'callback' => array( $this, 'get_internal' ),
49
+ 'permission_callback' => array( $this, 'check_permission' ),
50
+ ),
51
+ )
52
+ );
53
+ }
54
+
55
+ if ( method_exists( $this, 'post' ) ) {
56
+ register_rest_route(
57
+ $this->namespace,
58
+ '/' . $this->rest_base,
59
+ array(
60
+ array(
61
+ 'methods' => 'POST',
62
+ 'callback' => array( $this, 'post_internal' ),
63
+ 'permission_callback' => array( $this, 'check_permission' ),
64
+ ),
65
+ )
66
+ );
67
+ }
68
+
69
+ if ( method_exists( $this, 'delete' ) ) {
70
+ register_rest_route(
71
+ $this->namespace,
72
+ '/' . $this->rest_base,
73
+ array(
74
+ array(
75
+ 'methods' => 'DELETE',
76
+ 'callback' => array( $this, 'delete_internal' ),
77
+ 'permission_callback' => array( $this, 'check_permission' ),
78
+ ),
79
+ )
80
+ );
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Send get request.
86
+ *
87
+ * @param array $request request.
88
+ *
89
+ * @return array
90
+ */
91
+ public function get_internal( $request ) {
92
+
93
+ $this->prevent_route_caching();
94
+
95
+ return $this->get( $request );
96
+ }
97
+
98
+ /**
99
+ * Send post request.
100
+ *
101
+ * @param array $request request.
102
+ *
103
+ * @return array
104
+ */
105
+ public function post_internal( $request ) {
106
+
107
+ $this->prevent_route_caching();
108
+
109
+ return $this->post( $request );
110
+ }
111
+
112
+ /**
113
+ * Sends delete request.
114
+ *
115
+ * @param array $request request.
116
+ *
117
+ * @return array
118
+ */
119
+ public function delete_internal( $request ) {
120
+
121
+ $this->prevent_route_caching();
122
+
123
+ return $this->delete( $request );
124
+ }
125
+
126
+ /**
127
+ * Validate the requester's permissions
128
+ *
129
+ * @param array $request request.
130
+ *
131
+ * @return bool
132
+ */
133
+ public function check_permission( $request ) {
134
+
135
+ return current_user_can( 'manage_woocommerce' );
136
+ }
137
+
138
+ /**
139
+ * Consolidate cache prevention mechanisms.
140
+ */
141
+ public function prevent_route_caching() {
142
+
143
+ if ( ! defined( 'DONOTCACHEPAGE' ) ) {
144
+ define( 'DONOTCACHEPAGE', true ); // Play nice with WP-Super-Cache.
145
+ }
146
+
147
+ // Prevent our REST API endpoint responses from being added to browser cache.
148
+ add_filter( 'rest_post_dispatch', array( $this, 'send_nocache_header' ), PHP_INT_MAX, 2 );
149
+ }
150
+
151
+ /**
152
+ * Send a no-cache header for WCS REST API responses. Prompted by cache issues
153
+ * on the Pantheon hosting platform.
154
+ *
155
+ * See: https://pantheon.io/docs/cache-control/
156
+ *
157
+ * @param WP_REST_Response $response REST API response.
158
+ * @param WP_REST_Server $server server.
159
+ *
160
+ * @return WP_REST_Response passthrough $response parameter
161
+ */
162
+ public function send_nocache_header( $response, $server ) {
163
+
164
+ $server->send_header( 'Cache-Control', 'no-cache, must-revalidate, max-age=0' );
165
+
166
+ return $response;
167
+ }
168
+ }
includes/abstracts/abstract-wc-stripe-payment-gateway.php CHANGED
@@ -322,7 +322,7 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
322
  * Generate the request for the payment.
323
  *
324
  * @since 3.1.0
325
- * @version 4.0.0
326
  * @param WC_Order $order
327
  * @param object $prepared_source
328
  * @return array()
@@ -359,18 +359,32 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
359
  break;
360
  }
361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
  $post_data['expand[]'] = 'balance_transaction';
363
 
364
  $metadata = array(
365
  __( 'customer_name', 'woocommerce-gateway-stripe' ) => sanitize_text_field( $billing_first_name ) . ' ' . sanitize_text_field( $billing_last_name ),
366
  __( 'customer_email', 'woocommerce-gateway-stripe' ) => sanitize_email( $billing_email ),
367
  'order_id' => $order->get_order_number(),
 
368
  );
369
 
370
  if ( $this->has_subscription( $order->get_id() ) ) {
371
  $metadata += array(
372
  'payment_type' => 'recurring',
373
- 'site_url' => esc_url( get_site_url() ),
374
  );
375
  }
376
 
@@ -1039,6 +1053,10 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
1039
  $request['statement_descriptor'] = $full_request['statement_descriptor'];
1040
  }
1041
 
 
 
 
 
1042
  /**
1043
  * Filter the return value of the WC_Payment_Gateway_CC::generate_create_intent_request.
1044
  *
@@ -1377,9 +1395,10 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
1377
  }
1378
 
1379
  if ( isset( $full_request['source'] ) ) {
1380
- $request['source'] = $full_request['source'];
 
1381
  }
1382
-
1383
  /**
1384
  * Filter the value of the request.
1385
  *
@@ -1390,6 +1409,10 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
1390
  */
1391
  $request = apply_filters('wc_stripe_generate_create_intent_request', $request, $order, $prepared_source );
1392
 
 
 
 
 
1393
  $level3_data = $this->get_level3_data_from_order( $order );
1394
  $intent = WC_Stripe_API::request_with_level3_data(
1395
  $request,
322
  * Generate the request for the payment.
323
  *
324
  * @since 3.1.0
325
+ * @version 4.5.4
326
  * @param WC_Order $order
327
  * @param object $prepared_source
328
  * @return array()
359
  break;
360
  }
361
 
362
+ if ( method_exists( $order, 'get_shipping_postcode' ) && ! empty( $order->get_shipping_postcode() ) ) {
363
+ $post_data['shipping'] = array(
364
+ 'name' => trim( $order->get_shipping_first_name() . ' ' . $order->get_shipping_last_name() ),
365
+ 'address' => array(
366
+ 'line1' => $order->get_shipping_address_1(),
367
+ 'line2' => $order->get_shipping_address_2(),
368
+ 'city' => $order->get_shipping_city(),
369
+ 'country' => $order->get_shipping_country(),
370
+ 'postal_code' => $order->get_shipping_postcode(),
371
+ 'state' => $order->get_shipping_state(),
372
+ )
373
+ );
374
+ }
375
+
376
  $post_data['expand[]'] = 'balance_transaction';
377
 
378
  $metadata = array(
379
  __( 'customer_name', 'woocommerce-gateway-stripe' ) => sanitize_text_field( $billing_first_name ) . ' ' . sanitize_text_field( $billing_last_name ),
380
  __( 'customer_email', 'woocommerce-gateway-stripe' ) => sanitize_email( $billing_email ),
381
  'order_id' => $order->get_order_number(),
382
+ 'site_url' => esc_url( get_site_url() ),
383
  );
384
 
385
  if ( $this->has_subscription( $order->get_id() ) ) {
386
  $metadata += array(
387
  'payment_type' => 'recurring',
 
388
  );
389
  }
390
 
1053
  $request['statement_descriptor'] = $full_request['statement_descriptor'];
1054
  }
1055
 
1056
+ if ( isset( $full_request['shipping'] ) ) {
1057
+ $request['shipping'] = $full_request['shipping'];
1058
+ }
1059
+
1060
  /**
1061
  * Filter the return value of the WC_Payment_Gateway_CC::generate_create_intent_request.
1062
  *
1395
  }
1396
 
1397
  if ( isset( $full_request['source'] ) ) {
1398
+ $is_source = 'src_' === substr( $full_request['source'], 0, 4 );
1399
+ $request[ $is_source ? 'source' : 'payment_method' ] = $full_request['source'];
1400
  }
1401
+
1402
  /**
1403
  * Filter the value of the request.
1404
  *
1409
  */
1410
  $request = apply_filters('wc_stripe_generate_create_intent_request', $request, $order, $prepared_source );
1411
 
1412
+ if ( isset( $full_request['shipping'] ) ) {
1413
+ $request['shipping'] = $full_request['shipping'];
1414
+ }
1415
+
1416
  $level3_data = $this->get_level3_data_from_order( $order );
1417
  $intent = WC_Stripe_API::request_with_level3_data(
1418
  $request,
includes/admin/class-wc-stripe-inbox-notes.php ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ }
5
+
6
+ use Automattic\WooCommerce\Admin\Notes\WC_Admin_Note;
7
+ use Automattic\WooCommerce\Admin\Notes\WC_Admin_Notes;
8
+
9
+ /**
10
+ * Class that adds Inbox notifications.
11
+ *
12
+ * @since 4.5.4
13
+ */
14
+ class WC_Stripe_Inbox_Notes {
15
+ const SUCCESS_NOTE_NAME = 'stripe-apple-pay-marketing-guide-holiday-2020';
16
+ const FAILURE_NOTE_NAME = 'stripe-apple-pay-domain-verification-needed';
17
+
18
+ const POST_SETUP_SUCCESS_ACTION = 'wc_stripe_apple_pay_post_setup_success';
19
+
20
+ public function __construct() {
21
+ add_action( self::POST_SETUP_SUCCESS_ACTION, array( self::class, 'create_marketing_note' ) );
22
+ }
23
+
24
+ /**
25
+ * Manage notes to show after Apple Pay domain verification.
26
+ */
27
+ public static function notify_on_apple_pay_domain_verification( $verification_complete ) {
28
+ if ( ! class_exists( 'Automattic\WooCommerce\Admin\Notes\WC_Admin_Notes' ) ) {
29
+ return;
30
+ }
31
+
32
+ if ( ! class_exists( 'WC_Data_Store' ) ) {
33
+ return;
34
+ }
35
+
36
+ if ( $verification_complete ) {
37
+ if ( self::should_show_marketing_note() && ! wp_next_scheduled( self::POST_SETUP_SUCCESS_ACTION ) ) {
38
+ wp_schedule_single_event( time() + DAY_IN_SECONDS, self::POST_SETUP_SUCCESS_ACTION );
39
+ }
40
+
41
+ // If the domain verification completed after failure note was created, make sure it's marked as actioned.
42
+ $data_store = WC_Data_Store::load( 'admin-note' );
43
+ $failure_note_ids = $data_store->get_notes_with_name( self::FAILURE_NOTE_NAME );
44
+ if ( ! empty( $failure_note_ids ) ) {
45
+ $note_id = array_pop( $failure_note_ids );
46
+ $note = WC_Admin_Notes::get_note( $note_id );
47
+ if ( false !== $note && WC_Admin_Note::E_WC_ADMIN_NOTE_ACTIONED !== $note->get_status() ) {
48
+ $note->set_status( WC_Admin_Note::E_WC_ADMIN_NOTE_ACTIONED );
49
+ $note->save();
50
+ }
51
+ }
52
+ } else {
53
+ if ( empty( $failure_note_ids ) ) {
54
+ self::create_failure_note();
55
+ }
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Whether conditions are right for the marketing note.
61
+ */
62
+ public static function should_show_marketing_note() {
63
+ // Display to US merchants only.
64
+ $base_location = wc_get_base_location();
65
+ if ( ! $base_location || 'US' !== $base_location['country'] ) {
66
+ return false;
67
+ }
68
+
69
+ // Make sure Apple Pay is enabled and setup is successful.
70
+ $stripe_settings = get_option( 'woocommerce_stripe_settings', array() );
71
+ $stripe_enabled = isset( $stripe_settings['enabled'] ) && 'yes' === $stripe_settings['enabled'];
72
+ $button_enabled = isset( $stripe_settings['payment_request'] ) && 'yes' === $stripe_settings['payment_request'];
73
+ $verification_complete = isset( $stripe_settings['apple_pay_domain_set'] ) && 'yes' === $stripe_settings['apple_pay_domain_set'];
74
+ if ( ! $stripe_enabled || ! $button_enabled || ! $verification_complete ) {
75
+ return false;
76
+ }
77
+
78
+ // Make sure note doesn't already exist.
79
+ $data_store = WC_Data_Store::load( 'admin-note' );
80
+ $success_note_ids = $data_store->get_notes_with_name( self::SUCCESS_NOTE_NAME );
81
+ if ( ! empty( $success_note_ids ) ) {
82
+ return false;
83
+ }
84
+
85
+ return true;
86
+ }
87
+
88
+ /**
89
+ * If conditions are right, show note promoting Apple Pay marketing guide.
90
+ */
91
+ public static function create_marketing_note() {
92
+ // Make sure conditions for this note still hold.
93
+ if ( ! self::should_show_marketing_note() ) {
94
+ return;
95
+ }
96
+
97
+ $note = new WC_Admin_Note();
98
+ $note->set_title( __( 'Boost sales this holiday season with Apple Pay!', 'woocommerce-gateway-stripe' ) );
99
+ $note->set_content( __( 'Now that you accept Apple Pay® with Stripe, you can increase conversion rates by letting your customers know that Apple Pay is available. Here’s a marketing guide to help you get started.', 'woocommerce-gateway-stripe' ) );
100
+ $note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_MARKETING );
101
+ $note->set_name( self::SUCCESS_NOTE_NAME );
102
+ $note->set_source( 'woocommerce-gateway-stripe' );
103
+ $note->add_action(
104
+ 'marketing-guide',
105
+ __( 'See marketing guide', 'woocommerce-gateway-stripe' ),
106
+ 'https://developer.apple.com/apple-pay/marketing/'
107
+ );
108
+ $note->save();
109
+ }
110
+
111
+ /**
112
+ * Show note indicating domain verification failure.
113
+ */
114
+ public static function create_failure_note() {
115
+ $note = new WC_Admin_Note();
116
+ $note->set_title( __( 'Apple Pay domain verification needed', 'woocommerce-gateway-stripe' ) );
117
+ $note->set_content( __( 'The WooCommerce Stripe Gateway extension attempted to perform domain verification on behalf of your store, but was unable to do so. This must be resolved before Apple Pay can be offered to your customers.', 'woocommerce-gateway-stripe' ) );
118
+ $note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
119
+ $note->set_name( self::FAILURE_NOTE_NAME );
120
+ $note->set_source( 'woocommerce-gateway-stripe' );
121
+ $note->add_action(
122
+ 'learn-more',
123
+ __( 'Learn more', 'woocommerce-gateway-stripe' ),
124
+ 'https://docs.woocommerce.com/document/stripe/#apple-pay'
125
+ );
126
+ $note->save();
127
+ }
128
+ }
129
+
130
+ new WC_Stripe_Inbox_Notes();
includes/admin/stripe-alipay-settings.php CHANGED
@@ -7,7 +7,7 @@ return apply_filters(
7
  'wc_stripe_alipay_settings',
8
  array(
9
  'geo_target' => array(
10
- 'description' => __( 'Relevant Payer Geography: China', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'guide' => array(
7
  'wc_stripe_alipay_settings',
8
  array(
9
  'geo_target' => array(
10
+ 'description' => __( 'Customer Geography: China', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'guide' => array(
includes/admin/stripe-bancontact-settings.php CHANGED
@@ -7,7 +7,7 @@ return apply_filters(
7
  'wc_stripe_bancontact_settings',
8
  array(
9
  'geo_target' => array(
10
- 'description' => __( 'Relevant Payer Geography: Belgium', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'guide' => array(
7
  'wc_stripe_bancontact_settings',
8
  array(
9
  'geo_target' => array(
10
+ 'description' => __( 'Customer Geography: Belgium', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'guide' => array(
includes/admin/stripe-eps-settings.php CHANGED
@@ -7,7 +7,7 @@ return apply_filters(
7
  'wc_stripe_eps_settings',
8
  array(
9
  'geo_target' => array(
10
- 'description' => __( 'Relevant Payer Geography: Austria', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'activation' => array(
7
  'wc_stripe_eps_settings',
8
  array(
9
  'geo_target' => array(
10
+ 'description' => __( 'Customer Geography: Austria', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'activation' => array(
includes/admin/stripe-giropay-settings.php CHANGED
@@ -7,7 +7,7 @@ return apply_filters(
7
  'wc_stripe_giropay_settings',
8
  array(
9
  'geo_target' => array(
10
- 'description' => __( 'Relevant Payer Geography: Germany', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'guide' => array(
7
  'wc_stripe_giropay_settings',
8
  array(
9
  'geo_target' => array(
10
+ 'description' => __( 'Customer Geography: Germany', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'guide' => array(
includes/admin/stripe-ideal-settings.php CHANGED
@@ -7,7 +7,7 @@ return apply_filters(
7
  'wc_stripe_ideal_settings',
8
  array(
9
  'geo_target' => array(
10
- 'description' => __( 'Relevant Payer Geography: The Netherlands', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'guide' => array(
7
  'wc_stripe_ideal_settings',
8
  array(
9
  'geo_target' => array(
10
+ 'description' => __( 'Customer Geography: The Netherlands', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'guide' => array(
includes/admin/stripe-multibanco-settings.php CHANGED
@@ -7,7 +7,7 @@ return apply_filters(
7
  'wc_stripe_multibanco_settings',
8
  array(
9
  'geo_target' => array(
10
- 'description' => __( 'Relevant Payer Geography: Portugal', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'activation' => array(
7
  'wc_stripe_multibanco_settings',
8
  array(
9
  'geo_target' => array(
10
+ 'description' => __( 'Customer Geography: Portugal', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'activation' => array(
includes/admin/stripe-p24-settings.php CHANGED
@@ -7,7 +7,7 @@ return apply_filters(
7
  'wc_stripe_p24_settings',
8
  array(
9
  'geo_target' => array(
10
- 'description' => __( 'Relevant Payer Geography: Poland', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'activation' => array(
7
  'wc_stripe_p24_settings',
8
  array(
9
  'geo_target' => array(
10
+ 'description' => __( 'Customer Geography: Poland', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'activation' => array(
includes/admin/stripe-sepa-settings.php CHANGED
@@ -7,7 +7,7 @@ return apply_filters(
7
  'wc_stripe_sepa_settings',
8
  array(
9
  'geo_target' => array(
10
- 'description' => __( 'Relevant Payer Geography: France, Germany, Spain, Belgium, Netherlands, Luxembourg, Italy, Portugal, Austria, Ireland', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'guide' => array(
7
  'wc_stripe_sepa_settings',
8
  array(
9
  'geo_target' => array(
10
+ 'description' => __( 'Customer Geography: France, Germany, Spain, Belgium, Netherlands, Luxembourg, Italy, Portugal, Austria, Ireland', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'guide' => array(
includes/admin/stripe-settings.php CHANGED
@@ -3,6 +3,38 @@ if ( ! defined( 'ABSPATH' ) ) {
3
  exit;
4
  }
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  return apply_filters(
7
  'wc_stripe_settings',
8
  array(
@@ -33,6 +65,11 @@ return apply_filters(
33
  /* translators: webhook URL */
34
  'description' => $this->display_admin_settings_webhook_description(),
35
  ),
 
 
 
 
 
36
  'testmode' => array(
37
  'title' => __( 'Test mode', 'woocommerce-gateway-stripe' ),
38
  'label' => __( 'Enable Test Mode', 'woocommerce-gateway-stripe' ),
@@ -109,7 +146,7 @@ return apply_filters(
109
  'title' => __( 'Payment Request Buttons', 'woocommerce-gateway-stripe' ),
110
  'label' => sprintf(
111
  /* translators: 1) br tag 2) Stripe anchor tag 3) Apple anchor tag 4) Stripe dashboard opening anchor tag 5) Stripe dashboard closing anchor tag */
112
- __( 'Enable Payment Request Buttons. (Apple Pay/Google Pay) %1$sBy using Apple Pay, you agree to %2$s and %3$s\'s terms of service. %4$sLog into your Stripe dashboard%5$s to complete or update your Apple Pay setup.', 'woocommerce-gateway-stripe' ),
113
  '<br />',
114
  '<a href="https://stripe.com/apple-pay/legal" target="_blank">Stripe</a>',
115
  '<a href="https://developer.apple.com/apple-pay/acceptable-use-guidelines-for-websites/" target="_blank">Apple</a>',
3
  exit;
4
  }
5
 
6
+ if ( wc_stripe()->connect->is_connected() ) {
7
+ $reset_link = add_query_arg(
8
+ array(
9
+ '_wpnonce' => wp_create_nonce( 'reset_stripe_api_credentials' ),
10
+ 'reset_stripe_api_credentials' => true,
11
+ ),
12
+ admin_url( 'admin.php?page=wc-settings&tab=checkout&section=stripe' )
13
+ );
14
+
15
+ $api_credentials_text = sprintf(
16
+ __( '%1$sClear all Stripe account keys.%2$s %3$sThis will disable any connection to Stripe.%4$s', 'woocommerce-gateway-stripe' ),
17
+ '<a id="wc_stripe_connect_button" href="' . $reset_link . '" class="button button-secondary">',
18
+ '</a>',
19
+ '<span style="color:red;">',
20
+ '</span>'
21
+ );
22
+ } else {
23
+ $oauth_url = wc_stripe()->connect->get_oauth_url();
24
+
25
+ if ( ! is_wp_error( $oauth_url ) ) {
26
+ $api_credentials_text = sprintf(
27
+ __( '%1$sSetup or link an existing Stripe account.%2$s By clicking this button you agree to the %3$sTerms of Service%2$s. Or, manually enter Stripe account keys below.', 'woocommerce-gateway-stripe' ),
28
+ '<a id="wc_stripe_connect_button" href="' . $oauth_url . '" class="button button-primary">',
29
+ '</a>',
30
+ '<a href="https://wordpress.com/tos">'
31
+
32
+ );
33
+ } else {
34
+ $api_credentials_text = __( 'Manually enter Stripe keys below.', 'woocommerce-gateway-stripe' );
35
+ }
36
+ }
37
+
38
  return apply_filters(
39
  'wc_stripe_settings',
40
  array(
65
  /* translators: webhook URL */
66
  'description' => $this->display_admin_settings_webhook_description(),
67
  ),
68
+ 'api_credentials' => array(
69
+ 'title' => __( 'Stripe Account Keys', 'woocommerce-gateway-stripe' ),
70
+ 'type' => 'title',
71
+ 'description' => $api_credentials_text
72
+ ),
73
  'testmode' => array(
74
  'title' => __( 'Test mode', 'woocommerce-gateway-stripe' ),
75
  'label' => __( 'Enable Test Mode', 'woocommerce-gateway-stripe' ),
146
  'title' => __( 'Payment Request Buttons', 'woocommerce-gateway-stripe' ),
147
  'label' => sprintf(
148
  /* translators: 1) br tag 2) Stripe anchor tag 3) Apple anchor tag 4) Stripe dashboard opening anchor tag 5) Stripe dashboard closing anchor tag */
149
+ __( 'Enable Payment Request Buttons. (Apple Pay/Google Pay) %1$sBy using Apple Pay, you agree to %2$s and %3$s\'s terms of service. (Apple Pay domain verification is performed automatically; configuration can be found on the %4$sStripe dashboard%5$s.)', 'woocommerce-gateway-stripe' ),
150
  '<br />',
151
  '<a href="https://stripe.com/apple-pay/legal" target="_blank">Stripe</a>',
152
  '<a href="https://developer.apple.com/apple-pay/acceptable-use-guidelines-for-websites/" target="_blank">Apple</a>',
includes/admin/stripe-sofort-settings.php CHANGED
@@ -7,7 +7,7 @@ return apply_filters(
7
  'wc_stripe_sofort_settings',
8
  array(
9
  'geo_target' => array(
10
- 'description' => __( 'Relevant Payer Geography: Germany, Austria', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'guide' => array(
7
  'wc_stripe_sofort_settings',
8
  array(
9
  'geo_target' => array(
10
+ 'description' => __( 'Customer Geography: Germany, Austria', 'woocommerce-gateway-stripe' ),
11
  'type' => 'title',
12
  ),
13
  'guide' => array(
includes/class-wc-gateway-stripe.php CHANGED
@@ -87,7 +87,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
87
  $this->id = 'stripe';
88
  $this->method_title = __( 'Stripe', 'woocommerce-gateway-stripe' );
89
  /* translators: 1) link to Stripe register page 2) link to Stripe api keys page */
90
- $this->method_description = sprintf( __( 'Stripe works by adding payment fields on the checkout and then sending the details to Stripe for verification. <a href="%1$s" target="_blank">Sign up</a> for a Stripe account, and <a href="%2$s" target="_blank">get your Stripe account keys</a>.', 'woocommerce-gateway-stripe' ), 'https://dashboard.stripe.com/register', 'https://dashboard.stripe.com/account/apikeys' );
91
  $this->has_fields = true;
92
  $this->supports = array(
93
  'products',
87
  $this->id = 'stripe';
88
  $this->method_title = __( 'Stripe', 'woocommerce-gateway-stripe' );
89
  /* translators: 1) link to Stripe register page 2) link to Stripe api keys page */
90
+ $this->method_description = __( 'Stripe works by adding payment fields on the checkout and then sending the details to Stripe for verification.', 'woocommerce-gateway-stripe' );
91
  $this->has_fields = true;
92
  $this->supports = array(
93
  'products',
includes/class-wc-stripe-apple-pay-registration.php CHANGED
@@ -17,20 +17,6 @@ class WC_Stripe_Apple_Pay_Registration {
17
  */
18
  public $stripe_settings;
19
 
20
- /**
21
- * Main Stripe Enabled.
22
- *
23
- * @var bool
24
- */
25
- public $stripe_enabled;
26
-
27
- /**
28
- * Do we accept Payment Request?
29
- *
30
- * @var bool
31
- */
32
- public $payment_request;
33
-
34
  /**
35
  * Apple Pay Domain Set.
36
  *
@@ -38,13 +24,6 @@ class WC_Stripe_Apple_Pay_Registration {
38
  */
39
  public $apple_pay_domain_set;
40
 
41
- /**
42
- * Secret Key.
43
- *
44
- * @var string
45
- */
46
- public $secret_key;
47
-
48
  /**
49
  * Stores Apple Pay domain verification issues.
50
  *
@@ -53,23 +32,18 @@ class WC_Stripe_Apple_Pay_Registration {
53
  public $apple_pay_verify_notice;
54
 
55
  public function __construct() {
56
- add_action( 'woocommerce_stripe_updated', array( $this, 'verify_domain_if_needed' ) );
57
- add_action( 'update_option_woocommerce_stripe_settings', array( $this, 'verify_domain_on_new_secret_key' ), 10, 2 );
 
 
 
 
 
 
58
 
59
  $this->stripe_settings = get_option( 'woocommerce_stripe_settings', array() );
60
- $this->stripe_enabled = $this->get_option( 'enabled' );
61
- $this->payment_request = 'yes' === $this->get_option( 'payment_request', 'yes' );
62
  $this->apple_pay_domain_set = 'yes' === $this->get_option( 'apple_pay_domain_set', 'no' );
63
  $this->apple_pay_verify_notice = '';
64
- $this->secret_key = $this->get_secret_key();
65
-
66
- if ( empty( $this->stripe_settings ) ) {
67
- return;
68
- }
69
-
70
- $this->init_apple_pay();
71
-
72
- add_action( 'admin_notices', array( $this, 'admin_notices' ) );
73
  }
74
 
75
  /**
@@ -92,6 +66,19 @@ class WC_Stripe_Apple_Pay_Registration {
92
  return $default;
93
  }
94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  /**
96
  * Gets the Stripe secret key for the current mode.
97
  *
@@ -104,31 +91,53 @@ class WC_Stripe_Apple_Pay_Registration {
104
  }
105
 
106
  /**
107
- * Initializes Apple Pay process on settings page.
 
 
 
 
 
 
 
 
 
 
108
  *
109
- * @since 3.1.0
110
- * @version 3.1.0
 
 
 
 
 
 
 
 
 
 
111
  */
112
- public function init_apple_pay() {
113
  if (
114
- is_admin() &&
115
- isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] &&
116
- isset( $_GET['tab'] ) && 'checkout' === $_GET['tab'] &&
117
- isset( $_GET['section'] ) && 'stripe' === $_GET['section'] &&
118
- $this->payment_request
119
  ) {
120
- $this->verify_domain();
121
  }
 
 
 
 
 
122
  }
123
 
124
  /**
125
- * Registers the domain with Stripe/Apple Pay
126
  *
127
  * @since 3.1.0
128
- * @version 3.1.0
129
  * @param string $secret_key
130
  */
131
- private function register_domain_with_apple( $secret_key = '' ) {
132
  if ( empty( $secret_key ) ) {
133
  throw new Exception( __( 'Unable to verify domain - missing secret key.', 'woocommerce-gateway-stripe' ) );
134
  }
@@ -167,60 +176,19 @@ class WC_Stripe_Apple_Pay_Registration {
167
  }
168
  }
169
 
170
- /**
171
- * Updates the Apple Pay domain association file.
172
- *
173
- * @param bool $force True to create the file if it didn't exist, false for just updating the file if needed.
174
- *
175
- * @version 4.3.0
176
- * @since 4.3.0
177
- * @return bool True on success, false on failure.
178
- */
179
- public function update_domain_association_file( $force = false ) {
180
- $path = untrailingslashit( $_SERVER['DOCUMENT_ROOT'] );
181
- $dir = '.well-known';
182
- $file = 'apple-developer-merchantid-domain-association';
183
- $fullpath = $path . '/' . $dir . '/' . $file;
184
-
185
- $existing_contents = @file_get_contents( $fullpath );
186
- $new_contents = @file_get_contents( WC_STRIPE_PLUGIN_PATH . '/' . $file );
187
- if ( ( ! $existing_contents && ! $force ) || $existing_contents === $new_contents ) {
188
- return true;
189
- }
190
-
191
- if ( ! file_exists( $path . '/' . $dir ) ) {
192
- if ( ! @mkdir( $path . '/' . $dir, 0755 ) ) { // @codingStandardsIgnoreLine
193
- WC_Stripe_Logger::log( 'Error: ' . __( 'Unable to create domain association folder to domain root.', 'woocommerce-gateway-stripe' ) );
194
- return false;
195
- }
196
- }
197
-
198
- if ( ! @copy( WC_STRIPE_PLUGIN_PATH . '/' . $file, $fullpath ) ) { // @codingStandardsIgnoreLine
199
- WC_Stripe_Logger::log( 'Error: ' . __( 'Unable to copy domain association file to domain root.', 'woocommerce-gateway-stripe' ) );
200
- return false;
201
- }
202
-
203
- WC_Stripe_Logger::log( 'Domain association file updated.' );
204
- return true;
205
- }
206
-
207
  /**
208
  * Processes the Apple Pay domain verification.
209
  *
210
  * @since 3.1.0
211
- * @version 3.1.0
 
 
 
 
212
  */
213
- public function verify_domain() {
214
- if ( ! $this->update_domain_association_file( true ) ) {
215
- $this->stripe_settings['apple_pay_domain_set'] = 'no';
216
- update_option( 'woocommerce_stripe_settings', $this->stripe_settings );
217
- return;
218
- }
219
-
220
  try {
221
- // At this point then the domain association folder and file should be available.
222
- // Proceed to verify/and or verify again.
223
- $this->register_domain_with_apple( $this->secret_key );
224
 
225
  // No errors to this point, verification success!
226
  $this->stripe_settings['apple_pay_domain_set'] = 'yes';
@@ -230,44 +198,69 @@ class WC_Stripe_Apple_Pay_Registration {
230
 
231
  WC_Stripe_Logger::log( 'Your domain has been verified with Apple Pay!' );
232
 
 
 
233
  } catch ( Exception $e ) {
234
  $this->stripe_settings['apple_pay_domain_set'] = 'no';
 
235
 
236
  update_option( 'woocommerce_stripe_settings', $this->stripe_settings );
237
 
238
  WC_Stripe_Logger::log( 'Error: ' . $e->getMessage() );
 
 
239
  }
240
  }
241
 
242
  /**
243
- * Conditionally process the Apple Pay domain verification after a new secret key is set.
244
  *
245
- * @since 4.5.3
246
- * @version 4.5.3
247
  */
248
- public function verify_domain_on_new_secret_key( $prev_settings, $settings ) {
249
- $this->stripe_settings = $prev_settings;
250
- $prev_secret_key = $this->get_secret_key();
251
 
252
- $this->stripe_settings = $settings;
253
- $this->secret_key = $this->get_secret_key();
254
-
255
- if ( ! empty( $this->secret_key ) && $this->secret_key !== $prev_secret_key ) {
256
- $this->verify_domain();
257
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
  }
259
 
260
  /**
261
- * Process the Apple Pay domain verification if not already done - otherwise just update the file.
262
  *
263
  * @since 4.5.3
264
- * @version 4.5.3
265
  */
266
- public function verify_domain_if_needed() {
267
- if ( $this->apple_pay_domain_set ) {
268
- $this->update_domain_association_file();
269
- } else {
270
- $this->verify_domain();
 
 
 
 
 
271
  }
272
  }
273
 
@@ -277,7 +270,7 @@ class WC_Stripe_Apple_Pay_Registration {
277
  * @since 4.0.6
278
  */
279
  public function admin_notices() {
280
- if ( ! $this->stripe_enabled ) {
281
  return;
282
  }
283
 
@@ -285,15 +278,9 @@ class WC_Stripe_Apple_Pay_Registration {
285
  return;
286
  }
287
 
288
- if ( $this->payment_request && ! empty( $this->apple_pay_verify_notice ) ) {
289
- $allowed_html = array(
290
- 'a' => array(
291
- 'href' => array(),
292
- 'title' => array(),
293
- ),
294
- );
295
-
296
- echo '<div class="error stripe-apple-pay-message"><p>' . wp_kses( make_clickable( $this->apple_pay_verify_notice ), $allowed_html ) . '</p></div>';
297
  }
298
 
299
  /**
@@ -301,10 +288,32 @@ class WC_Stripe_Apple_Pay_Registration {
301
  * when setting screen is displayed. So if domain verification is not set,
302
  * something went wrong so lets notify user.
303
  */
304
- if ( ! empty( $this->secret_key ) && $this->payment_request && ! $this->apple_pay_domain_set ) {
 
 
 
 
 
 
 
 
305
  /* translators: 1) HTML anchor open tag 2) HTML anchor closing tag */
306
- echo '<div class="error stripe-apple-pay-message"><p>' . sprintf( __( 'Apple Pay domain verification failed. Please check the %1$slog%2$s to see the issue. (Logging must be enabled to see recorded logs)', 'woocommerce-gateway-stripe' ), '<a href="' . admin_url( 'admin.php?page=wc-status&tab=logs' ) . '">', '</a>' ) . '</p></div>';
307
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  }
309
  }
310
 
17
  */
18
  public $stripe_settings;
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  /**
21
  * Apple Pay Domain Set.
22
  *
24
  */
25
  public $apple_pay_domain_set;
26
 
 
 
 
 
 
 
 
27
  /**
28
  * Stores Apple Pay domain verification issues.
29
  *
32
  public $apple_pay_verify_notice;
33
 
34
  public function __construct() {
35
+ add_action( 'init', array( $this, 'add_domain_association_rewrite_rule' ) );
36
+ add_filter( 'query_vars', array( $this, 'whitelist_domain_association_query_param' ), 10, 1 );
37
+ add_action( 'parse_request', array( $this, 'parse_domain_association_request' ), 10, 1 );
38
+
39
+ add_action( 'woocommerce_stripe_updated', array( $this, 'verify_domain_if_configured' ) );
40
+ add_action( 'add_option_woocommerce_stripe_settings', array( $this, 'verify_domain_on_new_settings' ), 10, 2 );
41
+ add_action( 'update_option_woocommerce_stripe_settings', array( $this, 'verify_domain_on_updated_settings' ), 10, 2 );
42
+ add_action( 'admin_notices', array( $this, 'admin_notices' ) );
43
 
44
  $this->stripe_settings = get_option( 'woocommerce_stripe_settings', array() );
 
 
45
  $this->apple_pay_domain_set = 'yes' === $this->get_option( 'apple_pay_domain_set', 'no' );
46
  $this->apple_pay_verify_notice = '';
 
 
 
 
 
 
 
 
 
47
  }
48
 
49
  /**
66
  return $default;
67
  }
68
 
69
+ /**
70
+ * Whether the gateway and Payment Request Button (prerequisites for Apple Pay) are enabled.
71
+ *
72
+ * @since 4.5.4
73
+ * @return string Whether Apple Pay required settings are enabled.
74
+ */
75
+ private function is_enabled() {
76
+ $stripe_enabled = 'yes' === $this->get_option( 'enabled', 'no' );
77
+ $payment_request_button_enabled = 'yes' === $this->get_option( 'payment_request', 'yes' );
78
+
79
+ return $stripe_enabled && $payment_request_button_enabled;
80
+ }
81
+
82
  /**
83
  * Gets the Stripe secret key for the current mode.
84
  *
91
  }
92
 
93
  /**
94
+ * Adds a rewrite rule for serving the domain association file from the proper location.
95
+ */
96
+ public function add_domain_association_rewrite_rule() {
97
+ $regex = '^\.well-known\/apple-developer-merchantid-domain-association$';
98
+ $redirect = 'index.php?apple-developer-merchantid-domain-association=1';
99
+
100
+ add_rewrite_rule( $regex, $redirect, 'top' );
101
+ }
102
+
103
+ /**
104
+ * Add to the list of publicly allowed query variables.
105
  *
106
+ * @param array $query_vars - provided public query vars.
107
+ * @return array Updated public query vars.
108
+ */
109
+ public function whitelist_domain_association_query_param( $query_vars ) {
110
+ $query_vars[] = 'apple-developer-merchantid-domain-association';
111
+ return $query_vars;
112
+ }
113
+
114
+ /**
115
+ * Serve domain association file when proper query param is provided.
116
+ *
117
+ * @param WP WordPress environment object.
118
  */
119
+ public function parse_domain_association_request( $wp ) {
120
  if (
121
+ ! isset( $wp->query_vars['apple-developer-merchantid-domain-association'] ) ||
122
+ '1' !== $wp->query_vars['apple-developer-merchantid-domain-association']
 
 
 
123
  ) {
124
+ return;
125
  }
126
+
127
+ $path = WC_STRIPE_PLUGIN_PATH . '/apple-developer-merchantid-domain-association';
128
+ header( 'Content-Type: application/octet-stream' );
129
+ echo esc_html( file_get_contents( $path ) );
130
+ exit;
131
  }
132
 
133
  /**
134
+ * Makes request to register the domain with Stripe/Apple Pay.
135
  *
136
  * @since 3.1.0
137
+ * @version 4.5.4
138
  * @param string $secret_key
139
  */
140
+ private function make_domain_registration_request( $secret_key ) {
141
  if ( empty( $secret_key ) ) {
142
  throw new Exception( __( 'Unable to verify domain - missing secret key.', 'woocommerce-gateway-stripe' ) );
143
  }
176
  }
177
  }
178
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  /**
180
  * Processes the Apple Pay domain verification.
181
  *
182
  * @since 3.1.0
183
+ * @version 4.5.4
184
+ *
185
+ * @param string $secret_key
186
+ *
187
+ * @return bool Whether domain verification succeeded.
188
  */
189
+ public function register_domain_with_apple( $secret_key ) {
 
 
 
 
 
 
190
  try {
191
+ $this->make_domain_registration_request( $secret_key );
 
 
192
 
193
  // No errors to this point, verification success!
194
  $this->stripe_settings['apple_pay_domain_set'] = 'yes';
198
 
199
  WC_Stripe_Logger::log( 'Your domain has been verified with Apple Pay!' );
200
 
201
+ return true;
202
+
203
  } catch ( Exception $e ) {
204
  $this->stripe_settings['apple_pay_domain_set'] = 'no';
205
+ $this->apple_pay_domain_set = false;
206
 
207
  update_option( 'woocommerce_stripe_settings', $this->stripe_settings );
208
 
209
  WC_Stripe_Logger::log( 'Error: ' . $e->getMessage() );
210
+
211
+ return false;
212
  }
213
  }
214
 
215
  /**
216
+ * Process the Apple Pay domain verification if proper settings are configured.
217
  *
218
+ * @since 4.5.4
219
+ * @version 4.5.4
220
  */
221
+ public function verify_domain_if_configured() {
222
+ $secret_key = $this->get_secret_key();
 
223
 
224
+ if ( ! $this->is_enabled() || empty( $secret_key ) ) {
225
+ return;
 
 
 
226
  }
227
+
228
+ // Ensure that domain association file will be served.
229
+ flush_rewrite_rules();
230
+
231
+ // Register the domain with Apple Pay.
232
+ $verification_complete = $this->register_domain_with_apple( $secret_key );
233
+
234
+ // Show/hide notes if necessary.
235
+ WC_Stripe_Inbox_Notes::notify_on_apple_pay_domain_verification( $verification_complete );
236
+ }
237
+
238
+ /**
239
+ * Conditionally process the Apple Pay domain verification after settings are initially set.
240
+ *
241
+ * @since 4.5.4
242
+ * @version 4.5.4
243
+ */
244
+ public function verify_domain_on_new_settings( $option, $settings ) {
245
+ $this->verify_domain_on_updated_settings( array(), $settings );
246
  }
247
 
248
  /**
249
+ * Conditionally process the Apple Pay domain verification after settings are updated.
250
  *
251
  * @since 4.5.3
252
+ * @version 4.5.4
253
  */
254
+ public function verify_domain_on_updated_settings( $prev_settings, $settings ) {
255
+ // Grab previous state and then update cached settings.
256
+ $this->stripe_settings = $prev_settings;
257
+ $prev_secret_key = $this->get_secret_key();
258
+ $prev_is_enabled = $this->is_enabled();
259
+ $this->stripe_settings = $settings;
260
+
261
+ // If Stripe or Payment Request Button wasn't enabled (or secret key was different) then might need to verify now.
262
+ if ( ! $prev_is_enabled || ( $this->get_secret_key() !== $prev_secret_key ) ) {
263
+ $this->verify_domain_if_configured();
264
  }
265
  }
266
 
270
  * @since 4.0.6
271
  */
272
  public function admin_notices() {
273
+ if ( ! $this->is_enabled() ) {
274
  return;
275
  }
276
 
278
  return;
279
  }
280
 
281
+ $empty_notice = empty( $this->apple_pay_verify_notice );
282
+ if ( $empty_notice && ( $this->apple_pay_domain_set || empty( $this->secret_key ) ) ) {
283
+ return;
 
 
 
 
 
 
284
  }
285
 
286
  /**
288
  * when setting screen is displayed. So if domain verification is not set,
289
  * something went wrong so lets notify user.
290
  */
291
+ $allowed_html = array(
292
+ 'a' => array(
293
+ 'href' => array(),
294
+ 'title' => array(),
295
+ ),
296
+ );
297
+ $verification_failed_without_error = __( 'Apple Pay domain verification failed.', 'woocommerce-gateway-stripe' );
298
+ $verification_failed_with_error = __( 'Apple Pay domain verification failed with the following error:', 'woocommerce-gateway-stripe' );
299
+ $check_log_text = sprintf(
300
  /* translators: 1) HTML anchor open tag 2) HTML anchor closing tag */
301
+ esc_html__( 'Please check the %1$slogs%2$s for more details on this issue. Logging must be enabled to see recorded logs.', 'woocommerce-gateway-stripe' ),
302
+ '<a href="' . admin_url( 'admin.php?page=wc-status&tab=logs' ) . '">',
303
+ '</a>'
304
+ );
305
+
306
+ ?>
307
+ <div class="error stripe-apple-pay-message">
308
+ <?php if ( $empty_notice ) : ?>
309
+ <p><?php echo esc_html( $verification_failed_without_error ); ?></p>
310
+ <?php else : ?>
311
+ <p><?php echo esc_html( $verification_failed_with_error ); ?></p>
312
+ <p><i><?php echo wp_kses( make_clickable( esc_html( $this->apple_pay_verify_notice ) ), $allowed_html ); ?></i></p>
313
+ <?php endif; ?>
314
+ <p><?php echo $check_log_text; ?></p>
315
+ </div>
316
+ <?php
317
  }
318
  }
319
 
includes/class-wc-stripe-customer.php CHANGED
@@ -124,6 +124,11 @@ class WC_Stripe_Customer {
124
  'email' => $user->user_email,
125
  'description' => $description,
126
  );
 
 
 
 
 
127
  } else {
128
  $billing_first_name = isset( $_POST['billing_first_name'] ) ? filter_var( wp_unslash( $_POST['billing_first_name'] ), FILTER_SANITIZE_STRING ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
129
  $billing_last_name = isset( $_POST['billing_last_name'] ) ? filter_var( wp_unslash( $_POST['billing_last_name'] ), FILTER_SANITIZE_STRING ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
@@ -135,6 +140,11 @@ class WC_Stripe_Customer {
135
  'email' => $billing_email,
136
  'description' => $description,
137
  );
 
 
 
 
 
138
  }
139
 
140
  $metadata = array();
124
  'email' => $user->user_email,
125
  'description' => $description,
126
  );
127
+
128
+ $billing_full_name = trim( $billing_first_name . ' ' . $billing_last_name );
129
+ if ( ! empty( $billing_full_name ) ) {
130
+ $defaults['name'] = $billing_full_name;
131
+ }
132
  } else {
133
  $billing_first_name = isset( $_POST['billing_first_name'] ) ? filter_var( wp_unslash( $_POST['billing_first_name'] ), FILTER_SANITIZE_STRING ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
134
  $billing_last_name = isset( $_POST['billing_last_name'] ) ? filter_var( wp_unslash( $_POST['billing_last_name'] ), FILTER_SANITIZE_STRING ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
140
  'email' => $billing_email,
141
  'description' => $description,
142
  );
143
+
144
+ $billing_full_name = trim( $billing_first_name . ' ' . $billing_last_name );
145
+ if ( ! empty( $billing_full_name ) ) {
146
+ $defaults['name'] = $billing_full_name;
147
+ }
148
  }
149
 
150
  $metadata = array();
includes/compat/class-wc-stripe-subs-compat.php CHANGED
@@ -499,12 +499,13 @@ class WC_Stripe_Subs_Compat extends WC_Gateway_Stripe {
499
  }
500
 
501
  if (
502
- ( ! empty( $payment_meta['post_meta']['_stripe_source_id']['value'] )
503
- && 0 !== strpos( $payment_meta['post_meta']['_stripe_source_id']['value'], 'card_' ) )
504
- && ( ! empty( $payment_meta['post_meta']['_stripe_source_id']['value'] )
505
- && 0 !== strpos( $payment_meta['post_meta']['_stripe_source_id']['value'], 'src_' ) ) ) {
506
-
507
- throw new Exception( __( 'Invalid source ID. A valid source "Stripe Source ID" must begin with "src_" or "card_".', 'woocommerce-gateway-stripe' ) );
 
508
  }
509
  }
510
  }
499
  }
500
 
501
  if (
502
+ ! empty( $payment_meta['post_meta']['_stripe_source_id']['value'] ) && (
503
+ 0 !== strpos( $payment_meta['post_meta']['_stripe_source_id']['value'], 'card_' )
504
+ && 0 !== strpos( $payment_meta['post_meta']['_stripe_source_id']['value'], 'src_' )
505
+ && 0 !== strpos( $payment_meta['post_meta']['_stripe_source_id']['value'], 'pm_' )
506
+ )
507
+ ) {
508
+ throw new Exception( __( 'Invalid source ID. A valid source "Stripe Source ID" must begin with "src_", "pm_", or "card_".', 'woocommerce-gateway-stripe' ) );
509
  }
510
  }
511
  }
includes/connect/class-wc-stripe-connect-api.php ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ }
5
+
6
+ if ( ! defined( 'WOOCOMMERCE_CONNECT_SERVER_URL' ) ) {
7
+ define( 'WOOCOMMERCE_CONNECT_SERVER_URL', 'https://api.woocommerce.com/' );
8
+ }
9
+
10
+ if ( ! class_exists( 'WC_Stripe_Connect_API' ) ) {
11
+ /**
12
+ * Stripe Connect API class.
13
+ */
14
+ class WC_Stripe_Connect_API {
15
+
16
+ const WOOCOMMERCE_CONNECT_SERVER_API_VERSION = '3';
17
+
18
+ /**
19
+ * Send request to Connect Server to initiate Stripe OAuth
20
+ *
21
+ * @param string $return_url return address.
22
+ *
23
+ * @return array
24
+ */
25
+ public function get_stripe_oauth_init( $return_url ) {
26
+
27
+ $current_user = wp_get_current_user();
28
+ $business_data = array();
29
+ $business_data['url'] = get_site_url();
30
+ $business_data['business_name'] = html_entity_decode( get_bloginfo( 'name' ), ENT_QUOTES );
31
+ $business_data['first_name'] = $current_user->user_firstname;
32
+ $business_data['last_name'] = $current_user->user_lastname;
33
+ $business_data['phone'] = '';
34
+ $business_data['currency'] = get_woocommerce_currency();
35
+
36
+ $wc_countries = WC()->countries;
37
+
38
+ if ( method_exists( $wc_countries, 'get_base_address' ) ) {
39
+ $business_data['country'] = $wc_countries->get_base_country();
40
+ $business_data['street_address'] = $wc_countries->get_base_address();
41
+ $business_data['city'] = $wc_countries->get_base_city();
42
+ $business_data['state'] = $wc_countries->get_base_state();
43
+ $business_data['zip'] = $wc_countries->get_base_postcode();
44
+ } else {
45
+ $base_location = wc_get_base_location();
46
+ $business_data['country'] = $base_location['country'];
47
+ $business_data['street_address'] = '';
48
+ $business_data['city'] = '';
49
+ $business_data['state'] = $base_location['state'];
50
+ $business_data['zip'] = '';
51
+ }
52
+
53
+ $request = array(
54
+ 'returnUrl' => $return_url,
55
+ 'businessData' => $business_data,
56
+ );
57
+
58
+ return $this->request( 'POST', '/stripe/oauth-init', $request );
59
+ }
60
+
61
+ /**
62
+ * Send request to Connect Server for Stripe keys
63
+ *
64
+ * @param string $code OAuth server code.
65
+ *
66
+ * @return array
67
+ */
68
+ public function get_stripe_oauth_keys( $code ) {
69
+
70
+ $request = array( 'code' => $code );
71
+
72
+ return $this->request( 'POST', '/stripe/oauth-keys', $request );
73
+ }
74
+
75
+ /**
76
+ * General OAuth request method.
77
+ *
78
+ * @param string $method request method.
79
+ * @param string $path path for request.
80
+ * @param array $body request body.
81
+ *
82
+ * @return array|WP_Error
83
+ */
84
+ protected function request( $method, $path, $body = array() ) {
85
+
86
+ if ( ! is_array( $body ) ) {
87
+ return new WP_Error(
88
+ 'request_body_should_be_array',
89
+ __( 'Unable to send request to WooCommerce Connect server. Body must be an array.', 'woocommerce-gateway-stripe' )
90
+ );
91
+ }
92
+
93
+ $url = trailingslashit( WOOCOMMERCE_CONNECT_SERVER_URL );
94
+ $url = apply_filters( 'wc_connect_server_url', $url );
95
+ $url = trailingslashit( $url ) . ltrim( $path, '/' );
96
+
97
+ // Add useful system information to requests that contain bodies.
98
+ if ( in_array( $method, array( 'POST', 'PUT' ), true ) ) {
99
+ $body = $this->request_body( $body );
100
+ $body = wp_json_encode( apply_filters( 'wc_connect_api_client_body', $body ) );
101
+
102
+ if ( ! $body ) {
103
+ return new WP_Error(
104
+ 'unable_to_json_encode_body',
105
+ __( 'Unable to encode body for request to WooCommerce Connect server.', 'woocommerce-gateway-stripe' )
106
+ );
107
+ }
108
+ }
109
+
110
+ $headers = $this->request_headers();
111
+ if ( is_wp_error( $headers ) ) {
112
+ return $headers;
113
+ }
114
+
115
+ $http_timeout = 60; // 1 minute
116
+ wc_set_time_limit( $http_timeout + 10 );
117
+ $args = array(
118
+ 'headers' => $headers,
119
+ 'method' => $method,
120
+ 'body' => $body,
121
+ 'redirection' => 0,
122
+ 'compress' => true,
123
+ 'timeout' => $http_timeout,
124
+ );
125
+
126
+ $args = apply_filters( 'wc_connect_request_args', $args );
127
+ $response = wp_remote_request( $url, $args );
128
+ $response_code = wp_remote_retrieve_response_code( $response );
129
+ $content_type = wp_remote_retrieve_header( $response, 'content-type' );
130
+
131
+ if ( false === strpos( $content_type, 'application/json' ) ) {
132
+ if ( 200 !== $response_code ) {
133
+ return new WP_Error(
134
+ 'wcc_server_error',
135
+ sprintf(
136
+ // Translators: HTTP error code.
137
+ __( 'Error: The WooCommerce Connect server returned HTTP code: %d', 'woocommerce-gateway-stripe' ),
138
+ $response_code
139
+ )
140
+ );
141
+ } else {
142
+ return new WP_Error(
143
+ 'wcc_server_error_content_type',
144
+ sprintf(
145
+ // Translators: content-type error code.
146
+ __( 'Error: The WooCommerce Connect server returned an invalid content-type: %s.', 'woocommerce-gateway-stripe' ),
147
+ $content_type
148
+ )
149
+ );
150
+ }
151
+ }
152
+
153
+ $response_body = wp_remote_retrieve_body( $response );
154
+ if ( ! empty( $response_body ) ) {
155
+ $response_body = json_decode( $response_body );
156
+ }
157
+
158
+ if ( 200 !== $response_code ) {
159
+ if ( empty( $response_body ) ) {
160
+ return new WP_Error(
161
+ 'wcc_server_empty_response',
162
+ sprintf(
163
+ // Translators: HTTP error code.
164
+ __( 'Error: The WooCommerce Connect server returned ( %d ) and an empty response body.', 'woocommerce-gateway-stripe' ),
165
+ $response_code
166
+ )
167
+ );
168
+ }
169
+
170
+ $error = property_exists( $response_body, 'error' ) ? $response_body->error : '';
171
+ $message = property_exists( $response_body, 'message' ) ? $response_body->message : '';
172
+ $data = property_exists( $response_body, 'data' ) ? $response_body->data : '';
173
+
174
+ return new WP_Error(
175
+ 'wcc_server_error_response',
176
+ sprintf(
177
+ /* translators: %1$s: error code, %2$s: error message, %3$d: HTTP response code */
178
+ __( 'Error: The WooCommerce Connect server returned: %1$s %2$s ( %3$d )', 'woocommerce-gateway-stripe' ),
179
+ $error,
180
+ $message,
181
+ $response_code
182
+ ),
183
+ $data
184
+ );
185
+ }
186
+
187
+ return $response_body;
188
+ }
189
+
190
+ /**
191
+ * Adds useful WP/WC/WCC information to request bodies.
192
+ *
193
+ * @param array $initial_body body of initial request.
194
+ *
195
+ * @return array
196
+ */
197
+ protected function request_body( $initial_body = array() ) {
198
+
199
+ $default_body = array(
200
+ 'settings' => array(),
201
+ );
202
+
203
+ $body = array_merge( $default_body, $initial_body );
204
+
205
+ // Add interesting fields to the body of each request.
206
+ $body['settings'] = wp_parse_args(
207
+ $body['settings'],
208
+ array(
209
+ 'base_city' => WC()->countries->get_base_city(),
210
+ 'base_country' => WC()->countries->get_base_country(),
211
+ 'base_state' => WC()->countries->get_base_state(),
212
+ 'base_postcode' => WC()->countries->get_base_postcode(),
213
+ 'currency' => get_woocommerce_currency(),
214
+ 'stripe_version' => WC_STRIPE_VERSION,
215
+ 'wc_version' => WC()->version,
216
+ 'wp_version' => get_bloginfo( 'version' ),
217
+ )
218
+ );
219
+
220
+ return $body;
221
+ }
222
+
223
+ /**
224
+ * Generates headers for request to the WooCommerce Connect Server.
225
+ *
226
+ * @return array|WP_Error
227
+ */
228
+ protected function request_headers() {
229
+
230
+ $headers = array();
231
+ $locale = strtolower( str_replace( '_', '-', get_locale() ) );
232
+ $locale_elements = explode( '-', $locale );
233
+ $lang = $locale_elements[0];
234
+ $headers['Accept-Language'] = $locale . ',' . $lang;
235
+ $headers['Content-Type'] = 'application/json; charset=utf-8';
236
+ $headers['Accept'] = 'application/vnd.woocommerce-connect.v' . self::WOOCOMMERCE_CONNECT_SERVER_API_VERSION;
237
+
238
+ return $headers;
239
+ }
240
+ }
241
+ }
includes/connect/class-wc-stripe-connect-rest-oauth-connect-controller.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
+ }
6
+
7
+ if ( ! class_exists( 'WC_Stripe_Connect_REST_Oauth_Connect_Controller' ) ) {
8
+ /**
9
+ * Stripe Connect Oauth Connect controller class.
10
+ */
11
+ class WC_Stripe_Connect_REST_Oauth_Connect_Controller extends WC_Stripe_Connect_REST_Controller {
12
+
13
+ /**
14
+ * REST base.
15
+ *
16
+ * @var string
17
+ */
18
+ protected $rest_base = 'connect/stripe/oauth/connect';
19
+
20
+ /**
21
+ * Stripe Connect.
22
+ *
23
+ * @var WC_Stripe_Connect
24
+ */
25
+ protected $connect;
26
+
27
+ /**
28
+ * Constructor.
29
+ *
30
+ * @param WC_Stripe_Connect $connect stripe connect.
31
+ * @param WC_Stripe_Connect_API $api stripe connect api.
32
+ */
33
+ public function __construct( WC_Stripe_Connect $connect, WC_Stripe_Connect_API $api ) {
34
+
35
+ parent::__construct( $api );
36
+
37
+ $this->connect = $connect;
38
+ }
39
+
40
+ /**
41
+ * OAuth Connection flow.
42
+ *
43
+ * @param array $request POST request.
44
+ *
45
+ * @return array|WP_Error
46
+ */
47
+ public function post( $request ) {
48
+
49
+ $data = $request->get_json_params();
50
+ $response = $this->connect->connect_oauth( $data['state'], $data['code'] );
51
+
52
+ if ( is_wp_error( $response ) ) {
53
+
54
+ WC_Stripe_Logger::log( $response, __CLASS__ );
55
+
56
+ return new WP_Error(
57
+ $response->get_error_code(),
58
+ $response->get_error_message(),
59
+ array( 'status' => 400 )
60
+ );
61
+ }
62
+
63
+ return array(
64
+ 'success' => true,
65
+ 'account_id' => $response->accountId, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
66
+ );
67
+ }
68
+ }
69
+ }
includes/connect/class-wc-stripe-connect-rest-oauth-init-controller.php ADDED
@@ -0,0 +1,69 @@