Plugin Directory

source: mobile-login-woocommerce/tags/2.2/includes/class-xoo-ml-verification.php

Last change on this file was 2818479, checked in by xootix, 2 years ago

2.2 release

File size: 17.5 KB
Line 
1<?php
2
3if ( ! defined( 'ABSPATH' ) ) {
4        exit; // Exit if accessed directly
5}
6
7
8class Xoo_Ml_Phone_Verification{
9
10        public static $ip_address;
11
12        public function __construct(){
13                $this->hooks();
14        }
15
16        /**
17         * Hooks
18        */
19        public function hooks(){
20
21                add_action( 'wp_ajax_xoo_ml_request_otp', array( $this, 'request_otp' ) );
22                add_action( 'wp_ajax_nopriv_xoo_ml_request_otp', array( $this, 'request_otp' ) );
23
24                add_action( 'wp_ajax_xoo_ml_otp_form_submit', array( $this, 'process_otp_form' ) );
25                add_action( 'wp_ajax_nopriv_xoo_ml_otp_form_submit', array( $this, 'process_otp_form' ) );
26
27                add_action( 'wp_ajax_xoo_ml_resend_otp', array( $this, 'resendOTP' ) );
28                add_action( 'wp_ajax_nopriv_xoo_ml_resend_otp', array( $this, 'resendOTP' ) );
29
30                add_action( 'init', array( $this, 'request_otp' ), 5 );
31
32                add_action( 'user_register', array( $this, 'handle_phone_on_user_registration' ) );
33
34                add_filter( 'authenticate', array( $this, 'process_login' ), 5, 3 );
35
36                add_action( 'xoo_ml_otp_validation_success', array( $this, 'wc_myaccount_update_phone' ), 10, 2 );
37                add_action( 'xoo_ml_otp_validation_success', array( $this, 'login_user_with_otp' ), 10, 2 );
38
39
40                add_action( 'wp_ajax_nopriv_xoo_ml_login_with_otp', array( $this, 'process_login_with_otp_form' ) );
41
42        }
43
44
45        /**
46         * Update phone from woocommerce my account page
47         *
48         * @param       string          $parent_form_type       Parent form type - update in this case
49         * @param       array           $otp_data                       User phone otp data
50        */
51
52        public function wc_myaccount_update_phone( $parent_form_type, $otp_data ){
53
54                if( $parent_form_type === 'update_user' ){
55                        $user_id = get_current_user_id();
56                        update_user_meta( $user_id, 'xoo_ml_phone_no', sanitize_text_field( $otp_data['phone_no'] ) );
57                        update_user_meta( $user_id, 'xoo_ml_phone_code', sanitize_text_field( $otp_data['phone_code'] ) );
58                        update_user_meta(
59                                $user_id,
60                                'xoo_ml_phone_display',
61                                sanitize_text_field( $otp_data['phone_code'] ) . sanitize_text_field( $otp_data['phone_no'] )
62                        );
63                }
64
65        }
66
67        /**
68         * Login user with OTP after OTP Verification
69         *
70         * @param       string          $parent_form_type       Parent form type
71         * @param       array           $otp_data                       User phone otp data
72        */
73
74        public function login_user_with_otp( $parent_form_type, $otp_data ){
75
76                if( $parent_form_type === 'login_with_otp' ){
77
78                        $user = xoo_ml_get_user_by_phone( $otp_data['phone_no'], $otp_data['phone_code'] );
79
80                        if( $user ){
81                                //Logging user
82                                wp_clear_auth_cookie();
83                            wp_set_current_user ( $user->ID );
84                            wp_set_auth_cookie  ( $user->ID );
85
86                            $redirect = '';
87
88                            if ( isset( $_POST['parentFormData'][ 'redirect' ] ) ) {
89                                        $redirect = sanitize_url( $_POST['parentFormData'][ 'redirect' ] );
90                                }
91
92                                $redirect = wp_validate_redirect( apply_filters( 'xoo_ml_login_with_otp_redirect', sanitize_url( $redirect ) ) );
93
94                               
95
96                            wp_send_json(array(
97                                'redirect'      => $redirect,
98                                        'error'         => 0,
99                                        'notice'        => xoo_ml_add_notice( __( 'Login successful', 'mobile-login-woocommerce' ), 'success' )
100                                ));
101                        }
102                }
103
104        }
105
106        /**
107         * Login with username/Phone and password
108         *
109         * @param       object          $user                           User object if exists
110         * @param       string          $username                       Username/Phone
111         * @param       string          $password                       Password
112        */
113        public function process_login( $user, $username, $password ){
114
115                $user_to_login = null;
116
117                //Check if username provided is a phone number
118                $phone_user = xoo_ml_get_user_by_phone( $username );
119
120                if( !$phone_user ){
121                        return $user;
122                }
123
124                //if password validates
125                if ( wp_check_password( $password, $phone_user->user_pass, $phone_user->ID ) ){
126                        return $phone_user;
127                }
128
129                return $user;
130
131        }
132
133        /**
134         * Forms with phone input field
135         *
136         * @param       string          $form_type              Form type
137        */
138        public static function is_a_phone_form(){
139
140                $settings = xoo_ml_helper()->get_phone_option();
141       
142                $forms = array(
143                        array(
144                                'key'                   => 'xoo-ml-login-with-otp',
145                                'value'                 => 1,
146                                'form'                  => 'login_with_otp',
147                                'required'              => 'yes',
148                                'cc_required'   => $settings['l-enable-cc-field'] === 'yes' ? 'yes' : 'no',
149                        )
150                );
151
152                if( class_exists( 'woocommerce' ) && $settings['r-enable-phone'] === "yes"  ){
153                        $forms[] = array(
154                                'key'                   => 'woocommerce-register-nonce',
155                                'value'                 => '',
156                                'form'                  => 'register_user',
157                                'required'              => $settings['r-phone-field'] === 'required' ? 'yes' : 'no',
158                                'cc_required'   => $settings['r-enable-cc-field'] === 'yes' ? 'yes' : 'no',
159                        );
160
161                        $forms[] = array(
162                                'key'                   => 'save-account-details-nonce',
163                                'value'                 => '',
164                                'form'                  => 'update_user',
165                                'required'              => $settings['r-phone-field'] === 'required' ? 'yes' : 'no',
166                                'cc_required'   => $settings['r-enable-cc-field'] === 'yes' ? 'yes' : 'no',
167                        );
168
169
170                }
171
172                $forms = apply_filters( 'xoo_ml_get_phone_forms', $forms );
173
174                foreach( $forms as $form ){
175                        if( isset( $_POST[ $form['key'] ] ) && ( !$form[ 'value' ] || $_POST[ $form['key'] ] == $form['value'] ) ){
176                                return $form;
177                                break;
178                        }
179                }
180
181        }
182
183
184        /**
185         * Save phone fields on user registration
186         *
187         * @param       int     $user_id                User ID
188        */
189        public function handle_phone_on_user_registration( $user_id ){
190
191                //Proceed only if user is registered with a phone number
192                if( !isset( $_POST['xoo-ml-reg-phone'] ) || !isset( $_POST['xoo-ml-form-token'] ) ){
193                        return;
194                }
195
196                $phone_otp_data = Xoo_Ml_Otp_Handler::get_otp_data();
197                if( !$phone_otp_data['verified'] ) return;
198
199                $phone_code = sanitize_text_field( $phone_otp_data['phone_code'] );
200                $phone          = sanitize_text_field( $phone_otp_data['phone_no'] );
201
202                update_user_meta( $user_id, 'xoo_ml_phone_no', $phone );
203                update_user_meta( $user_id, 'xoo_ml_phone_code', $phone_code );
204                update_user_meta( $user_id, 'xoo_ml_phone_display', $phone_code.$phone );
205
206                if( class_exists( 'woocommerce' ) ){
207                        update_user_meta( $user_id, 'billing_phone', $phone_code.$phone );
208                }
209
210
211        }
212
213        /**
214         * Resend OTP
215         *
216        */
217        public function resendOTP(){
218
219                try {
220
221                        $SMSSent = Xoo_Ml_Otp_Handler::resendOTPSMS();
222
223                        if( is_wp_error( $SMSSent ) ){
224                                throw new Xoo_Exception( $SMSSent );   
225                        }
226
227                        $data = Xoo_Ml_Otp_Handler::get_otp_data();
228
229                        wp_send_json(array(
230                                'otp_sent'      => 1,
231                                'phone'         => $data['phone_code'].$data['phone_no'],
232                                'phone_no'      => $data['phone_no'],
233                                'phone_code'=> $data['phone_code'],
234                                'error'         => 0,
235                                'notice'        => xoo_ml_add_notice( __( 'OTP Resent', 'mobile-login-woocommerce' ), 'success' )
236                        ));
237
238                } catch (Exception $e) {
239
240                        do_action( 'xoo_ml_otp_resend_failed', Xoo_Ml_Otp_Handler::get_otp_data(), $e );
241
242                        wp_send_json(array(
243                                'error'          => 1,
244                                'error_code' => $e->getWpErrorCode(),
245                                'notice'         => xoo_ml_add_notice( $e->getMessage(), 'error' )
246                        ));
247                }
248               
249
250        }
251
252        /**
253         * Process form with phone input field
254         *
255        */
256        public function request_otp(){
257
258                $phoneFormData = self::is_a_phone_form();
259
260                if( !$phoneFormData ) return;
261
262                try {
263
264                        //If phone field is empty
265                        if( ( !isset( $_POST['xoo-ml-reg-phone'] ) || !trim( $_POST['xoo-ml-reg-phone'] )  || !isset( $_POST['xoo-ml-form-token'] ) ) && $phoneFormData['required'] === 'yes' ){
266                                throw new Xoo_Exception( __( 'Phone field cannot be empty', 'mobile-login-woocommerce' ) );
267                        }
268
269                        //Check for phone code
270                        if( ( !isset( $_POST['xoo-ml-reg-phone-cc'] ) || !$_POST['xoo-ml-reg-phone-cc'] ) && $phoneFormData['cc_required'] === 'yes' ){
271                                throw new Xoo_Exception( __( 'Please select country code', 'mobile-login-woocommerce' ) );
272                        }
273
274
275                        $phone_no       = isset( $_POST['xoo-ml-reg-phone'] ) ? sanitize_text_field( trim( $_POST['xoo-ml-reg-phone'] ) ) : '';
276                        $phone_code = isset( $_POST['xoo-ml-reg-phone-cc'] ) ? sanitize_text_field( $_POST['xoo-ml-reg-phone-cc'] ): '';
277                        $form_type      = isset( $_POST['xoo-ml-form-type'] ) ? sanitize_text_field( $_POST['xoo-ml-form-type'] ) : '';
278
279                       
280                        if( !$phone_code && $form_type !== 'login_with_otp' ){
281                                $phone_code = xoo_ml_helper()->get_phone_option('r-default-country-code-type') === 'geolocation' && Xoo_Ml_Geolocation::get_phone_code() ? Xoo_Ml_Geolocation::get_phone_code() : xoo_ml_helper()->get_phone_option('r-default-country-code');
282                        }
283
284                        $phone_otp_data = Xoo_Ml_Otp_Handler::get_otp_data();
285
286                        if( !is_array( $phone_otp_data ) ){
287                                $phone_otp_data = array();
288                        }
289
290                        $form_validation = apply_filters( 'xoo_ml_phone_form_validation', new WP_Error(), $form_type, $phone_code, $phone_no, $phone_otp_data );
291
292                        if( $form_validation->get_error_code() ){
293                                throw new Xoo_Exception( $form_validation->get_error_message() );       
294                        }
295
296                        if( !$phone_no ){
297                                return; //Exit if phone number is optional and not provided
298                        }
299
300
301                        $user = xoo_ml_get_user_by_phone( $phone_no, $phone_code );
302
303                        if( $user ){
304
305                                //Update form
306                                if( $phoneFormData['form'] === 'update_user' ){
307                                        if( $user->ID === get_current_user_id() ){
308                                                return; // exit as number not changed
309                                        }
310                                        else{
311                                                throw new Xoo_Exception( __( 'Sorry, this phone number is already in use.', 'mobile-login-woocommerce' ) );
312                                        }
313                                }
314
315                                //Register form
316                                if( $phoneFormData['form'] === 'register_user' ){
317                                        $loginNotice  =  __( 'Sorry, this phone number is already in use.', 'mobile-login-woocommerce' );
318                                        $loginNotice .= defined( 'XOO_EL_VERSION' ) ? '<span class="xoo-el-login-tgr">'.__( 'Please login', 'mobile-login-woocommerce' ).'</span>' : __( 'Please login', 'mobile-login-woocommerce' );
319                                        throw new Xoo_Exception( $loginNotice );               
320                                }
321
322                        }
323
324
325                        if( $phoneFormData['form'] === 'login_with_otp' ){
326                                if( !$user ){
327                                        throw new Xoo_Exception( __( 'We cannot find an account with that mobile number', 'mobile-login-woocommerce' ) );
328                                }
329                                else{
330                                        $phone_code = get_user_meta( $user->ID, 'xoo_ml_phone_code', true );
331                                        $phone_no       = get_user_meta( $user->ID, 'xoo_ml_phone_no', true );
332                                }       
333                        }
334                       
335                       
336                        //If phone has been verified, return
337                        if( $phone_no && isset( $phone_otp_data[ 'phone_no' ] ) && $phone_otp_data['phone_no'] === $phone_no && isset( $phone_otp_data[ 'phone_code' ] ) && $phone_otp_data['phone_code'] === $phone_code && isset( $phone_otp_data['verified'] ) && $phone_otp_data['verified'] && isset( $phone_otp_data['form_token'] ) && $phone_otp_data['form_token'] === $_POST['xoo-ml-form-token']  ){
338                                return;
339                        }
340
341
342                        //Send OTP SMS only if its ajax call.
343                        if( !wp_doing_ajax() ){
344                                throw new Xoo_Exception( __( 'Please verify your mobile number', 'mobile-login-woocommerce' ) );
345                        };
346
347
348                        if( !$phone_no || !$phone_code ){
349                                return;
350                        }
351
352                        $otp = Xoo_Ml_Otp_Handler::sendOTPSMS( $phone_code, $phone_no );
353
354                        if( is_wp_error( $otp ) ){
355                                throw new Xoo_Exception( $otp->get_error_message() );
356                        }
357
358                        do_action( 'xoo_ml_request_otp_sent', $phone_code, $phone_no, $phone_otp_data );
359
360                        wp_send_json(array(
361                                'otp_sent'      => 1,
362                                'otp'           => $otp,
363                                'phone'         => $phone_code.$phone_no,
364                                'phone_no'      => $phone_no,
365                                'phone_code'=> $phone_code,
366                                'error'         => 0,
367                                'otp_txt'       => sprintf( __( 'Please enter the OTP sent to <br> %s', 'mobile-login-woocommerce' ), $phone_code.$phone_no ),
368                        ));
369
370                       
371                } catch (Exception $e) {
372
373                        $notice = apply_filters( 'xoo_ml_request_otp_failed_notice', $e->getMessage(), $e );
374                       
375                        do_action( 'xoo_ml_request_otp_failed', $e );
376
377                        if( wp_doing_ajax() ){
378                                wp_send_json(array(
379                                        'error'         => 1,
380                                        'notice'        => xoo_ml_add_notice( $notice, 'error' )
381                                ));
382                        }
383                        else{
384                                if( class_exists('woocommerce') ){
385                                        wc_add_notice( $notice, 'error' );
386                                        wp_safe_redirect( $_SERVER['HTTP_REFERER'] );
387                                        exit;
388                                }
389
390                                wp_die( $notice );
391                        }
392
393                       
394                }
395
396
397        }
398
399        public function process_otp_form(){
400
401                try {
402
403                        if( isset( $_POST['otp'] ) ){
404
405                                $phone_otp_data = Xoo_Ml_Otp_Handler::get_otp_data();
406
407                                $notice = false;
408
409                                if( !is_array( $phone_otp_data ) ){
410                                        $phone_otp_data = array();
411                                }
412
413                                //Check for incorrect limit
414                                if( isset( $phone_otp_data['incorrect'] ) && $phone_otp_data['incorrect'] > xoo_ml_helper()->get_phone_option('otp-incorrect-limit') ){
415                                        throw new Xoo_Exception( __( 'Number of tries exceeded, Please try again in few minutes', 'mobile-login-woocommerce' ) );
416                                }
417
418                                //Handle firebase verification
419                                if( xoo_ml_helper()->get_phone_option('m-operator') === 'firebase' ){
420
421
422
423                                        if( isset( $_POST['firebase_error'] ) ){
424                                                $fb_error = json_decode ( stripslashes( $_POST['firebase_error'] ) );
425
426                                                if( $fb_error->code === 'auth/code-expired' ){
427                                                        throw new Xoo_Exception( __( 'OTP Expired', 'mobile-login-woocommerce' ) );
428                                                }
429                                                elseif( $fb_error->code === 'auth/invalid-verification-code' ){
430                                                        //do nothing
431                                                }
432                                                else{
433                                                        $notice = esc_html( $fb_error->message );
434                                                }
435                                        }
436
437                                        if( isset( $_POST['firebase_idToken'] ) ){
438
439                                                $args = array(
440                                                        'method'      => 'POST',
441                                                        'body'        => array(
442                                                                'idToken' => sanitize_text_field( $_POST['firebase_idToken'] ),
443                                                        )
444                                                );
445
446                                                //Validate user token
447                                                $validate_raw   = wp_remote_post( "https://identitytoolkit.googleapis.com/v1/accounts:lookup?key=".xoo_ml_helper()->get_service_option('fb-api-key'), $args );
448                                                $fb_body                = json_decode( $validate_raw['body'] );
449
450                                                if( is_object( $fb_body ) && !empty( $fb_body->users ) ){
451                                                        if( $fb_body->users[0]->phoneNumber === ( $phone_otp_data['phone_code'].$phone_otp_data['phone_no'] ) || $fb_body->users[0]->phoneNumber === ( $phone_otp_data['phone_code'].ltrim( $phone_otp_data['phone_no'], '0' ) ) ){
452                                                                $firebaseVerified = true;
453                                                        }
454                                                }
455
456                                        }
457                                }
458
459                                if( isset( $firebaseVerified ) || ( isset( $phone_otp_data['otp'] ) && ( $phone_otp_data['otp'] === (int) $_POST['otp'] ) ) ){
460
461                                        if( isset( $phone_otp_data['expiry'] ) && strtotime('now') > (int) $phone_otp_data['expiry'] ){
462                                                throw new Xoo_Exception( __( 'OTP Expired', 'mobile-login-woocommerce' ) );
463                                        }
464                                       
465                                        Xoo_Ml_Otp_Handler::set_otp_data( array(
466                                                'verified'                      => true,
467                                                'form_token'            => sanitize_text_field( $_POST['token'] ),
468                                                'incorrect'             => 0,
469                                                'sent_items'            => 0,
470                                                'expiry'                        => '',
471                                                'created'                       => '', 
472                                        ) );
473
474                                        $parent_form_type = isset( $_POST['parentFormData'] ) && isset( $_POST['parentFormData']['xoo-ml-form-type'] ) ? sanitize_text_field( $_POST['parentFormData']['xoo-ml-form-type'] ) : '';
475
476                                        //Hook functions on OTP verification
477                                        do_action( 'xoo_ml_otp_validation_success', $parent_form_type, Xoo_Ml_Otp_Handler::get_otp_data() );
478
479                                        $notice = $parent_form_type === 'update_user' ? __( 'Your number has been successfully updated', 'mobile-login-woocommerce' ) : __( 'Thank you for verifying your number.', 'mobile-login-woocommerce' );
480
481                                        $notice = apply_filters( 'xoo_ml_otp_validation_success_notice', $notice, $parent_form_type, Xoo_Ml_Otp_Handler::get_otp_data() );
482
483                                        wp_send_json(array(
484                                                'error'         => 0,
485                                                'notice'        => xoo_ml_add_notice( $notice, 'success' )
486                                        ));
487
488                                }
489
490                                $incorrect = isset( $phone_otp_data['incorrect'] ) ? $phone_otp_data['incorrect'] + 1 : 1;
491
492                                Xoo_Ml_Otp_Handler::set_otp_data( 'incorrect', $incorrect );
493
494                        }
495
496                        throw new Xoo_Exception( $notice ? $notice : __( 'Invalid OTP', 'mobile-login-woocommerce' ) );
497
498                } catch (Exception $e) {
499
500                        $notice = apply_filters( 'xoo_ml_otp_errors', $e->getMessage() );
501                       
502                        wp_send_json(array(
503                                'error'         => 1,
504                                'notice'        => xoo_ml_add_notice( $notice, 'error' )
505                        ));
506                }
507
508        }
509
510        /**
511         * Process login with OTP Form
512         *
513         * @param       int     $user_id                User ID
514        */
515        public function process_login_with_otp_form(){
516
517                try {
518
519                        if( !isset( $_POST['xoo-ml-reg-phone'] ) || !trim($_POST['xoo-ml-reg-phone']) ){
520                                throw new Xoo_Exception( __( 'Phone field cannot be empty', 'mobile-login-woocommerce' ) );
521                        }
522
523                        if(  xoo_ml_helper()->get_phone_option('l-enable-cc-field') === "yes" && ( !isset( $_POST['xoo-ml-reg-phone-cc'] ) || !trim( $_POST['xoo-ml-reg-phone-cc'] ) ) ){
524                                throw new Xoo_Exception( __( 'Country code cannot be empty', 'mobile-login-woocommerce' ) );
525                        }
526
527                        //Here phone_no can be with country code.
528                        $phone_no       = sanitize_text_field( $_POST['xoo-ml-reg-phone'] ); 
529                        $phone_code = isset( $_POST['xoo-ml-reg-phone-cc'] ) ? sanitize_text_field( trim( $_POST['xoo-ml-reg-phone-cc'] ) ) : ''; 
530
531                        $phone_user = xoo_ml_get_user_by_phone( $phone_no, $phone_code );
532
533                        if( !$phone_user ){
534                                throw new Xoo_Exception( __( 'We cannot find an account with that mobile number', 'mobile-login-woocommerce' ) );
535                        }
536
537                        $phone_no       = xoo_ml_get_user_phone( $phone_user->ID, 'number' );
538                        $phone_code = xoo_ml_get_user_phone( $phone_user->ID, 'code' );
539
540                        if( !$phone_code ){
541                                throw new Xoo_Exception( __( 'Something went wrong. Please contact site administrator.', 'mobile-login-woocommerce' ) );
542                        }
543
544                        //Send OTP SMS
545                        $otp = Xoo_Ml_Otp_Handler::sendOTPSMS( $phone_code, $phone_no );
546
547                        if( is_wp_error( $otp ) ){
548                                throw new Xoo_Exception( $otp->get_error_message() );
549                        }
550
551                        wp_send_json(array(
552                                'otp_sent'              => 1,
553                                'phone_code'    => $phone_code,
554                                'phone_no'              => $phone_no,
555                                'error'                 => 0,
556                                'otp_txt'               => sprintf( __( 'Please enter the OTP sent to <br> %s', 'mobile-login-woocommerce' ), $phone_code.$phone_no ),
557                        ));
558
559                } catch ( Exception $e ) {
560
561                        $notice = apply_filters( 'xoo_ml_login_with_otp_errors', $e->getMessage() );
562
563                        wp_send_json(array(
564                                'error'         => 1,
565                                'notice'        => xoo_ml_add_notice( $notice, 'error' )
566                        ));
567                }
568
569               
570        }
571       
572
573}
574
575new Xoo_Ml_Phone_Verification();
Note: See TracBrowser for help on using the repository browser.