Skip to content

Commit 2022f5f

Browse files
committed
Implement ownership validation
1 parent 7e9dad5 commit 2022f5f

File tree

2 files changed

+205
-11
lines changed

2 files changed

+205
-11
lines changed

assets/js/amazon-wc-checkout.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,58 @@
7878
}
7979
}
8080

81+
function is_blocked( $node ) {
82+
return $node.is( '.processing' ) || $node.parents( '.processing' ).length;
83+
}
84+
85+
function block( $node ) {
86+
if ( ! is_blocked( $node ) ) {
87+
$node.addClass( 'processing' ).block( {
88+
message: null,
89+
overlayCSS: {
90+
background: '#fff',
91+
opacity: 0.6
92+
}
93+
} );
94+
}
95+
}
96+
97+
function unblock( $node ) {
98+
$node.removeClass( 'processing' ).unblock();
99+
}
100+
101+
function sendConfirmationCode( e ) {
102+
var $this = $( this );
103+
e.preventDefault();
104+
105+
if ( $this.data( 'sending' ) ) {
106+
return;
107+
}
108+
109+
$this.data( 'sending', true );
110+
111+
var $thisArea = $this.parents('.create-account');
112+
113+
block( $thisArea );
114+
115+
$.ajax(
116+
{
117+
type: 'post',
118+
url: $this.prop( 'href' ),
119+
success: function( result ) {
120+
unblock( $thisArea );
121+
$this.data( 'sending', false );
122+
// TODO: Maybe display some feedback
123+
},
124+
error: function( jqXHR, textStatus, errorThrown ) {
125+
unblock( $thisArea );
126+
$this.data( 'sending', false );
127+
// TODO: Maybe display some feedback about what went wrong?
128+
}
129+
}
130+
);
131+
}
132+
81133
function initAmazonPaymentFields() {
82134
if ( ! isAmazonCheckout() ) {
83135
return;
@@ -103,6 +155,8 @@
103155
$( '.woocommerce-shipping-fields' ).insertBefore( '#payment' );
104156
}
105157
$( '.woocommerce-additional-fields' ).insertBefore( '#payment' );
158+
159+
$( '.wc-apa-send-confirm-ownership-code' ).on( 'click', sendConfirmationCode );
106160
}
107161

108162
initAmazonPaymentFields();

includes/class-wc-gateway-amazon-payments-advanced.php

Lines changed: 151 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,83 @@ public function handle_account_registration( $customer_id ) {
259259
}
260260
}
261261

262+
if ( $customer_id ) { // Already registered, or logged in. Return normally
263+
return $customer_id;
264+
}
265+
266+
// FROM: WC_Checkout->process_customer
267+
if ( ! is_user_logged_in() && ( $checkout->is_registration_required() || ! empty( $data['createaccount'] ) ) ) {
268+
269+
if ( isset( $data['amazon_validate'] ) ) {
270+
$checkout_session = $this->get_checkout_session();
271+
$buyer_id = $checkout_session->buyer->buyerId;
272+
$buyer_email = $checkout_session->buyer->email;
273+
274+
$buyer_user_id = $this->get_customer_id_from_buyer( $buyer_id );
275+
276+
if ( is_user_logged_in() ) {
277+
return; // We shouldn't be here anyways
278+
}
279+
280+
if ( $buyer_user_id ) {
281+
return; // We shouldn't be here anyways
282+
}
283+
$user_id = email_exists( $buyer_email );
284+
if ( ! $user_id ) {
285+
return; // We shouldn't be here anyways
286+
}
287+
288+
$code = get_user_meta( $user_id, 'wc_apa_ownership_verification_code', true );
289+
if ( empty( $code ) ) {
290+
throw new Exception( __( 'You have to send yourself a code before attempting to claim an account. If you want, you can continue as guest.', 'woocommerce-gateway-amazon-payments-advanced' ) );
291+
}
292+
293+
if ( empty( $data['amazon_validate'] ) ) {
294+
throw new Exception( __( 'You did not enter the code to validate your account. If you want, you can continue as guest.', 'woocommerce-gateway-amazon-payments-advanced' ) );
295+
}
296+
297+
if ( $code !== $data['amazon_validate'] ) { // TODO: Rotate code after 5 failed attempts
298+
throw new Exception( __( 'The code you entered did not match. Try again, or continue as guest.', 'woocommerce-gateway-amazon-payments-advanced' ) );
299+
}
300+
301+
$customer_id = $user_id;
302+
303+
$this->set_customer_id_for_buyer( $buyer_id, $customer_id );
304+
305+
delete_user_meta( $user_id, 'wc_apa_ownership_verification_code' );
306+
}
307+
308+
wc_set_customer_auth_cookie( $customer_id );
309+
310+
// As we are now logged in, checkout will need to refresh to show logged in data.
311+
WC()->session->set( 'reload_checkout', true );
312+
313+
// Also, recalculate cart totals to reveal any role-based discounts that were unavailable before registering.
314+
WC()->cart->calculate_totals();
315+
}
316+
262317
return $customer_id;
263318
}
264319

320+
public function get_amazon_validate_ownership_url() {
321+
return add_query_arg(
322+
array(
323+
'amazon_payments_advanced' => 'true',
324+
'amazon_validate_ownership' => 'true',
325+
),
326+
get_permalink( wc_get_page_id( 'checkout' ) )
327+
);
328+
}
329+
330+
public function print_validate_button( $html, $key, $field, $value ) {
331+
$html = '<p class="form-row" id="amazon_validate_notice_field" data-priority="">';
332+
$html .= __( 'An account with your Amazon Pay email address exists already. Is that you?', 'woocommerce-gateway-amazon-payments-advanced' );
333+
$html .= ' ';
334+
$html .= sprintf( __( 'Click %shere%s to send a code to your email, which will help you validate the ownership of the account.', 'woocommerce-gateway-amazon-payments-advanced' ), '<a href="' . esc_url( $this->get_amazon_validate_ownership_url() ) . '" class="wc-apa-send-confirm-ownership-code" target="_blank">', '</a>' );
335+
$html .= '</p>';
336+
return $html;
337+
}
338+
265339
public function checkout_init( $checkout ) {
266340

267341
/**
@@ -282,6 +356,7 @@ public function checkout_init( $checkout ) {
282356
}
283357

284358
add_action( 'woocommerce_checkout_process', array( $this, 'signal_account_hijack' ) );
359+
add_filter( 'woocommerce_form_field_amazon_validate_notice', array( $this, 'print_validate_button' ), 10, 4 );
285360

286361
// If all prerequisites are meet to be an amazon checkout.
287362
do_action( 'woocommerce_amazon_checkout_init' );
@@ -389,6 +464,52 @@ public function maybe_handle_apa_action() {
389464
exit;
390465
}
391466

467+
if ( isset( $_GET['amazon_validate_ownership'] ) && $this->is_logged_in() ) {
468+
$checkout_session = $this->get_checkout_session();
469+
$buyer_id = $checkout_session->buyer->buyerId;
470+
$buyer_email = $checkout_session->buyer->email;
471+
472+
$buyer_user_id = $this->get_customer_id_from_buyer( $buyer_id );
473+
474+
if ( is_user_logged_in() ) {
475+
return; // We shouldn't be here anyways
476+
}
477+
478+
if ( $buyer_user_id ) {
479+
return; // We shouldn't be here anyways
480+
}
481+
$user_id = email_exists( $buyer_email );
482+
if ( ! $user_id ) {
483+
return; // We shouldn't be here anyways
484+
}
485+
486+
$subject = 'Link your account with Amazon Pay';
487+
$code = wp_rand( 1111, 9999 );
488+
update_user_meta( $user_id, 'wc_apa_ownership_verification_code', $code );
489+
490+
$mailer = WC()->mailer();
491+
492+
// Buffer.
493+
ob_start();
494+
495+
do_action( 'woocommerce_email_header', $subject, null );
496+
497+
?>
498+
<p><?php esc_html_e( 'It seems that someone is trying to make an order on your behalf. If that is the case, please use the code below to link your Amazon Pay account to your account upon checkout.', 'woocommerce' ); ?></p>
499+
<p style="vertical-align: top; word-wrap: break-word; -ms-hyphens: none; hyphens: none; border-collapse: collapse; -moz-hyphens: none; -webkit-hyphens: none; color: #222222; font-family: Lato, Arial, sans-serif; font-weight: normal; letter-spacing: 10px; line-height: 2; font-size: 48px; text-align: center;"><?php echo esc_html( $code ); ?></p>
500+
<p><?php esc_html_e( 'If this is not you, you can ignore this message.', 'woocommerce' ); ?></p>
501+
<?php
502+
503+
do_action( 'woocommerce_email_footer', null );
504+
505+
// Get contents.
506+
$message = ob_get_clean();
507+
508+
$mailer->send( $buyer_email, wp_strip_all_tags( $subject ), $message );
509+
510+
exit;
511+
}
512+
392513
}
393514

394515
protected function get_checkout_session_id() {
@@ -502,6 +623,25 @@ public function hijack_checkout_fields( $checkout ) {
502623
* @param WC_Checkout $checkout WC_Checkout instance.
503624
*/
504625
protected function hijack_checkout_field_account( $checkout ) {
626+
if ( is_user_logged_in() ) {
627+
return; // There's nothing to do here if the user is logged in
628+
}
629+
630+
$checkout_session = $this->get_checkout_session();
631+
$buyer_id = $checkout_session->buyer->buyerId;
632+
$buyer_email = $checkout_session->buyer->email;
633+
634+
$buyer_user_id = $this->get_customer_id_from_buyer( $buyer_id );
635+
636+
if ( $buyer_user_id ) {
637+
return; // We shouldn't be here anyways
638+
}
639+
640+
$user_id = email_exists( $buyer_email );
641+
if ( ! $user_id ) {
642+
return; // We shouldn't be here anyways
643+
}
644+
505645
/**
506646
* WC 3.0 changes a bit a way to retrieve fields.
507647
*
@@ -511,17 +651,17 @@ protected function hijack_checkout_field_account( $checkout ) {
511651
? $checkout->get_checkout_fields()
512652
: $checkout->checkout_fields;
513653

514-
/**
515-
* Before 3.0.0, account fields may not set at all if guest checkout is
516-
* disabled with account and password generated automatically.
517-
*
518-
* @see https://github.com/woocommerce/woocommerce/blob/2.6.14/includes/class-wc-checkout.php#L92-L132
519-
* @see https://github.com/woocommerce/woocommerce/blob/master/includes/class-wc-checkout.php#L187-L197
520-
* @see https://github.com/woocommerce/woocommerce-gateway-amazon-payments-advanced/issues/228
521-
*/
522-
$checkout_fields['account'] = ! empty( $checkout_fields['account'] )
523-
? $checkout_fields['account']
524-
: array();
654+
$checkout_fields['account'] = array();
655+
656+
$checkout_fields['account']['amazon_validate_notice'] = array(
657+
'type' => 'amazon_validate_notice',
658+
);
659+
660+
$checkout_fields['account']['amazon_validate'] = array(
661+
'type' => 'text',
662+
'label' => __( 'Verification Code', 'woocommerce-gateway-amazon-payments-advanced' ),
663+
'required' => true,
664+
);
525665

526666
$checkout->checkout_fields = $checkout_fields;
527667
}

0 commit comments

Comments
 (0)