PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.2.11
LatePoint – Calendar Booking Plugin for Appointments and Events v5.2.11
5.6.6 5.6.5 5.6.4 5.6.3 5.6.2 5.6.1 5.6.0 5.5.2 5.5.1 5.5.0 5.4.2 trunk 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.1.91 5.1.92 5.1.93 5.1.94 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1
latepoint / lib / helpers / auth_helper.php
latepoint / lib / helpers Last commit date
activities_helper.php 3 months ago agent_helper.php 3 months ago analytics_helper.php 4 months ago auth_helper.php 3 months ago blocks_helper.php 3 months ago booking_helper.php 3 months ago bricks_helper.php 3 months ago bundles_helper.php 3 months ago calendar_helper.php 3 months ago carts_helper.php 3 months ago connector_helper.php 3 months ago csv_helper.php 3 months ago customer_helper.php 3 months ago customer_import_helper.php 3 months ago database_helper.php 3 months ago debug_helper.php 3 months ago defaults_helper.php 3 months ago elementor_helper.php 3 months ago email_helper.php 3 months ago encrypt_helper.php 3 months ago events_helper.php 3 months ago form_helper.php 3 months ago icalendar_helper.php 3 months ago image_helper.php 3 months ago invoices_helper.php 3 months ago license_helper.php 3 months ago location_helper.php 3 months ago marketing_systems_helper.php 3 months ago meeting_systems_helper.php 3 months ago menu_helper.php 3 months ago meta_helper.php 3 months ago migrations_helper.php 3 months ago money_helper.php 3 months ago notifications_helper.php 3 months ago nps_survey_helper.php 3 months ago order_intent_helper.php 3 months ago orders_helper.php 3 months ago otp_helper.php 3 months ago pages_helper.php 3 months ago params_helper.php 3 months ago payments_helper.php 3 months ago price_breakdown_helper.php 3 months ago process_jobs_helper.php 3 months ago processes_helper.php 3 months ago replacer_helper.php 3 months ago resource_helper.php 3 months ago roles_helper.php 3 months ago router_helper.php 3 months ago service_helper.php 3 months ago sessions_helper.php 3 months ago settings_helper.php 3 months ago short_links_systems_helper.php 3 months ago shortcodes_helper.php 3 months ago sms_helper.php 3 months ago steps_helper.php 3 months ago stripe_connect_helper.php 3 months ago styles_helper.php 3 months ago support_topics_helper.php 3 months ago time_helper.php 3 months ago timeline_helper.php 3 months ago transaction_helper.php 3 months ago transaction_intent_helper.php 3 months ago util_helper.php 3 months ago version_specific_updates_helper.php 3 months ago whatsapp_helper.php 3 months ago work_periods_helper.php 3 months ago wp_datetime.php 3 months ago wp_user_helper.php 3 months ago
auth_helper.php
863 lines
1 <?php
2
3 class OsAuthHelper {
4
5 public static ?\LatePoint\Misc\User $current_user = null;
6 public static $logged_in_customer_id = false;
7
8 private static int $max_login_attempts_per_contact = 20;
9 private static int $max_login_attempts_per_ip = 20;
10 private static int $login_lockout_minutes = 5;
11
12 public static function reset_current_user() {
13 self::$current_user = null;
14 }
15
16 public static function set_current_user() {
17 if ( \OsWpUserHelper::is_user_logged_in() ) {
18 // if wp user is logged in - load from it
19 self::$current_user = \LatePoint\Misc\User::load_from_wp_user( \OsWpUserHelper::get_current_user() );
20 } else {
21 self::$current_user = new \LatePoint\Misc\User();
22 }
23 $customer = self::get_logged_in_customer();
24 if ( $customer ) {
25 self::$current_user->customer = $customer;
26 }
27 }
28
29 public static function get_current_user(): \LatePoint\Misc\User {
30 if ( ! self::$current_user ) {
31 self::set_current_user();
32 }
33
34 return self::$current_user;
35 }
36
37 public static function get_highest_current_user_id() {
38 $user_id = false;
39 switch ( self::get_highest_current_user_type() ) {
40 case LATEPOINT_USER_TYPE_ADMIN:
41 case LATEPOINT_USER_TYPE_CUSTOM:
42 $user_id = self::get_logged_in_wp_user_id();
43 break;
44 case LATEPOINT_USER_TYPE_AGENT:
45 $user_id = self::get_logged_in_agent_id();
46 break;
47 case LATEPOINT_USER_TYPE_CUSTOMER:
48 $user_id = self::get_logged_in_customer_id();
49 break;
50 }
51
52 return $user_id;
53 }
54
55 public static function get_admin_or_agent_avatar_url() {
56 $avatar_url = LATEPOINT_DEFAULT_AVATAR_URL;
57 if ( self::is_agent_logged_in() ) {
58 $agent = self::get_logged_in_agent();
59 $avatar_url = $agent->get_avatar_url();
60 } elseif ( self::get_logged_in_wp_user_id() ) {
61 $wp_user = self::get_logged_in_wp_user();
62 $avatar_url = get_avatar_url( $wp_user->user_email );
63 }
64
65 return $avatar_url;
66 }
67
68 public static function get_highest_current_user_type() {
69 // check if WP admin is logged in
70 $user_type = false;
71 if ( self::get_current_user()->backend_user_type ) {
72 // backend user, admin, agent or custom role
73 return self::get_current_user()->backend_user_type;
74 } elseif ( self::get_current_user()->customer ) {
75 // customer
76 return LATEPOINT_USER_TYPE_CUSTOMER;
77 }
78
79 return $user_type;
80 }
81
82
83 public static function login_wp_user( $user ) {
84 clean_user_cache( $user->ID );
85 wp_set_current_user( $user->ID );
86 wp_set_auth_cookie( $user->ID );
87 update_user_caches( $user );
88 }
89
90 public static function login_customer( $contact_value, $password, $contact_type = 'email' ) {
91 if ( empty( $contact_value ) || empty( $password ) || ! in_array( $contact_type, self::get_enabled_contact_types_for_customer_auth() ) ) {
92 return false;
93 }
94 $available_contact_types = OsAuthHelper::get_available_contact_types_for_customer_auth();
95 if ( ! isset( $available_contact_types[ $contact_type ] ) ) {
96 return false;
97 }
98
99 if ( ! self::check_login_rate_limit( $contact_value, $contact_type ) ) {
100 return false;
101 }
102
103 if ( self::can_wp_users_login_as_customers() ) {
104 // if WP users enabled - customers can only login using existing password of the wordpress account
105 $wp_user_id = false;
106 if ( $contact_type == 'email' ) {
107 $email = sanitize_email( $contact_value );
108 $wp_user_id = email_exists( $email );
109 } elseif ( $contact_type == 'phone' ) {
110 $phone = OsUtilHelper::sanitize_phone_number( $contact_value );
111 // find latepoint customer by phone because wp users don't have a phone field
112 $customer = new OsCustomerModel();
113 $customer = $customer->where( array( 'phone' => $phone ) )->set_limit( 1 )->get_results_as_models();
114 if ( $customer ) {
115 $email = $customer->email;
116 if ( $customer->wordpress_user_id ) {
117 $wp_user_id = $customer->wordpress_user_id;
118 } else {
119 $wp_user_id = email_exists( $customer->email );
120 }
121 }
122 }
123 if ( $wp_user_id && ! empty( $email ) && ! empty( $password ) ) {
124 $wp_user = wp_signon(
125 [
126 'user_login' => $email,
127 'user_password' => $password,
128 ]
129 );
130 if ( ! is_wp_error( $wp_user ) ) {
131 // successfully logged into wp user
132 // check if latepoint customer exists in db for this wp user
133 wp_set_current_user( $wp_user->ID );
134 $customer = OsCustomerHelper::get_customer_for_wp_user( $wp_user );
135 if ( $customer->id ) {
136 self::clear_login_rate_limits( $contact_value, $contact_type );
137 return $customer;
138 } else {
139 OsDebugHelper::log( 'Can not login because can not create LatePoint Customer from WP User', 'customer_login_error', $customer->get_error_messages() );
140
141 return false;
142 }
143 } else {
144 self::record_failed_login_attempt( $contact_value, $contact_type );
145 return false;
146 }
147 } else {
148 return false;
149 }
150 } else {
151 $customer = new OsCustomerModel();
152 if ( $contact_type == 'email' ) {
153 $email = sanitize_email( $contact_value );
154 $customer = $customer->where( array( 'email' => $email ) )->set_limit( 1 )->get_results_as_models();
155 } elseif ( $contact_type == 'phone' ) {
156 $phone = OsUtilHelper::sanitize_phone_number( $contact_value );
157 $customer = $customer->where( array( 'phone' => $phone ) )->set_limit( 1 )->get_results_as_models();
158 }
159 if ( $customer && OsAuthHelper::verify_password( $password, $customer->password ) ) {
160 OsAuthHelper::authorize_customer( $customer->id );
161 self::clear_login_rate_limits( $contact_value, $contact_type );
162
163 return $customer;
164 } else {
165 self::record_failed_login_attempt( $contact_value, $contact_type );
166 return false;
167 }
168 }
169 }
170
171 private static function check_login_rate_limit( string $contact_value, string $contact_type ): bool {
172 // Per-contact check
173 $contact_key = self::get_login_rate_limit_key( 'contact', $contact_value . '::' . $contact_type );
174 $attempts = absint( get_transient( $contact_key ) );
175 if ( $attempts >= self::$max_login_attempts_per_contact ) {
176 OsDebugHelper::log(
177 'Too many login attempts for contact',
178 'login_rate_limit',
179 [
180 'contact' => $contact_value,
181 'type' => $contact_type,
182 ]
183 );
184 return false;
185 }
186
187 // Per-IP check
188 $client_ip = OsUtilHelper::get_user_ip();
189 if ( ! empty( $client_ip ) && $client_ip !== 'n/a' ) {
190 $ip_key = self::get_login_rate_limit_key( 'ip', $client_ip );
191 $ip_attempts = absint( get_transient( $ip_key ) );
192 if ( $ip_attempts >= self::$max_login_attempts_per_ip ) {
193 OsDebugHelper::log( 'Too many login attempts from IP', 'login_rate_limit_ip', [ 'ip' => $client_ip ] );
194 return false;
195 }
196 }
197
198 return true;
199 }
200
201 private static function record_failed_login_attempt( string $contact_value, string $contact_type ): void {
202 $lockout_duration = self::$login_lockout_minutes * MINUTE_IN_SECONDS;
203 $client_ip = OsUtilHelper::get_user_ip();
204
205 $contact_key = self::get_login_rate_limit_key( 'contact', $contact_value . '::' . $contact_type );
206 $attempts = absint( get_transient( $contact_key ) );
207 set_transient( $contact_key, $attempts + 1, $lockout_duration );
208
209 if ( ! empty( $client_ip ) && $client_ip !== 'n/a' ) {
210 $ip_key = self::get_login_rate_limit_key( 'ip', $client_ip );
211 $ip_attempts = absint( get_transient( $ip_key ) );
212 set_transient( $ip_key, $ip_attempts + 1, $lockout_duration );
213 }
214 }
215
216 private static function clear_login_rate_limits( string $contact_value, string $contact_type ): void {
217 delete_transient( self::get_login_rate_limit_key( 'contact', $contact_value . '::' . $contact_type ) );
218
219 $client_ip = OsUtilHelper::get_user_ip();
220 if ( ! empty( $client_ip ) && $client_ip !== 'n/a' ) {
221 delete_transient( self::get_login_rate_limit_key( 'ip', $client_ip ) );
222 }
223 }
224
225 private static function get_login_rate_limit_key( string $type, string $identifier ): string {
226 return 'latepoint_login_' . $type . '_' . substr( wp_hash( $identifier ), 0, 20 );
227 }
228
229 public static function can_wp_users_login_as_customers(): bool {
230 return OsSettingsHelper::is_on( 'wp_users_as_customers', false );
231 }
232
233
234 // CUSTOMERS
235 // ---------------
236
237 public static function logout_customer() {
238 if ( self::can_wp_users_login_as_customers() ) {
239 wp_logout();
240 } else {
241 OsSessionsHelper::destroy_customer_session_cookie();
242 }
243 }
244
245 public static function authorize_customer( $customer_id ): bool {
246 $customer = new OsCustomerModel();
247 $customer = $customer->where( [ 'id' => $customer_id ] )->set_limit( 1 )->get_results_as_models();
248 if ( empty( $customer ) ) {
249 OsDebugHelper::log( 'Tried to authorize customer with invalid ID', 'customer_authorization', [ 'customer_id' => $customer_id ] );
250
251 return false;
252 }
253
254 if ( self::can_wp_users_login_as_customers() ) {
255
256 if ( $customer->wordpress_user_id ) {
257 $wp_user = get_user_by( 'id', $customer->wordpress_user_id );
258 // check if WP User exists, if not - create new one and get ID, otherwise get ID from customer record, since its valid
259 $wordpress_user_id = ( $wp_user ) ? $customer->wordpress_user_id : OsCustomerHelper::create_wp_user_for_customer( $customer );
260 } else {
261 $wordpress_user_id = OsCustomerHelper::create_wp_user_for_customer( $customer );
262 }
263
264 if ( $wordpress_user_id ) {
265 $wp_user = get_user_by( 'id', $wordpress_user_id );
266 if ( $wp_user ) {
267 self::login_wp_user( $wp_user );
268 } else {
269 OsDebugHelper::log(
270 'WordPress user ID for customer is not found or can not be created.',
271 'customer_create_error',
272 [
273 'customer_id' => $customer_id,
274 'wordpress_user_id' => $wordpress_user_id,
275 ]
276 );
277
278 return false;
279 }
280 } else {
281 OsDebugHelper::log( 'WordPress user ID for customer is not found or can not be created.', 'customer_create_error', [ 'customer_id' => $customer_id ] );
282
283 return false;
284 }
285 }
286 OsSessionsHelper::start_or_use_session_for_customer( $customer_id );
287 OsStepsHelper::$customer_object = $customer;
288
289 return true;
290 }
291
292 public static function get_logged_in_customer_uuid() {
293 $customer = self::get_logged_in_customer();
294 if ( $customer ) {
295 return $customer->get_uuid();
296 } else {
297 return false;
298 }
299 }
300
301 public static function get_logged_in_customer_id() {
302 if ( OsAuthHelper::is_customer_auth_disabled() ) {
303 return false;
304 }
305 if ( self::can_wp_users_login_as_customers() ) {
306 // using wp users as customers
307 if ( OsWpUserHelper::is_user_logged_in() ) {
308 $wp_user = wp_get_current_user();
309 // search connected latepoint customer
310 $customer = OsCustomerHelper::get_customer_for_wp_user( $wp_user );
311 if ( $customer->id ) {
312 return $customer->id;
313 } else {
314 OsDebugHelper::log( 'Can not create LatePoint Customer from WP User', 'customer_create_error', $customer->get_error_messages() );
315
316 return false;
317 }
318 } else {
319 return false;
320 }
321 } else {
322 if ( self::$logged_in_customer_id ) {
323 return self::$logged_in_customer_id;
324 }
325 $customer_id = OsSessionsHelper::get_customer_id_from_session();
326 // make sure customer with this ID exists in database
327 $customer = new OsCustomerModel( $customer_id );
328 if ( ! $customer->is_new_record() ) {
329 self::$logged_in_customer_id = $customer_id;
330
331 return self::$logged_in_customer_id;
332 } else {
333 // customer not found, destroy this invalid customer ID in session cookie
334 OsSessionsHelper::destroy_customer_session_cookie();
335
336 return false;
337 }
338 }
339 }
340
341 public static function is_customer_logged_in() {
342 return self::get_logged_in_customer_id();
343 }
344
345 public static function get_logged_in_customer() {
346 $customer = false;
347 if ( self::is_customer_logged_in() ) {
348 $customer = new OsCustomerModel( self::get_logged_in_customer_id() );
349 if ( $customer->is_new_record() ) {
350 $customer = false;
351 }
352 }
353
354 return $customer;
355 }
356
357
358 // AGENTS
359 // -------------
360
361 public static function get_logged_in_agent_id() {
362 $agent_id = false;
363 if ( self::is_agent_logged_in() ) {
364 if ( self::get_current_user()->agent && self::get_current_user()->agent->id ) {
365 $agent_id = self::get_current_user()->agent->id;
366 }
367 }
368
369 return $agent_id;
370 }
371
372 public static function is_agent_logged_in() {
373 return ( self::get_current_user()->backend_user_type == LATEPOINT_USER_TYPE_AGENT );
374 }
375
376 public static function get_logged_in_agent() {
377 $agent = false;
378 if ( self::is_agent_logged_in() ) {
379 $agent = new OsAgentModel();
380 $agent = $agent->where( [ 'wp_user_id' => self::get_logged_in_wp_user_id() ] )->set_limit( 1 )->get_results_as_models();
381 }
382
383 return $agent;
384 }
385
386
387 public static function is_custom_backend_user_logged_in() {
388 return ( self::get_current_user()->backend_user_type == LATEPOINT_USER_TYPE_CUSTOM );
389 }
390
391 public static function is_admin_logged_in() {
392 return ( self::get_current_user()->backend_user_type == LATEPOINT_USER_TYPE_ADMIN );
393 }
394
395 public static function get_logged_in_admin_user() {
396 $admin_user = false;
397 if ( self::is_admin_logged_in() ) {
398 $admin_user = self::get_logged_in_wp_user();
399 }
400
401 return $admin_user;
402 }
403
404 public static function get_logged_in_admin_user_id() {
405 $admin_id = false;
406 if ( self::is_admin_logged_in() ) {
407 $admin_id = self::get_logged_in_wp_user_id();
408 }
409
410 return $admin_id;
411 }
412
413 public static function get_logged_in_custom_user_id() {
414 $admin_id = false;
415 if ( self::is_custom_backend_user_logged_in() ) {
416 $admin_id = self::get_logged_in_wp_user_id();
417 }
418
419 return $admin_id;
420 }
421
422
423 public static function get_default_customer_authentication_method(): string {
424 $method = OsSettingsHelper::get_settings_value( 'default_customer_authentication_method', 'password' );
425
426 $enabled_auth_methods = self::get_enabled_customer_authentication_methods();
427 if ( empty( $enabled_auth_methods ) ) {
428 $method = '';
429 } elseif ( count( $enabled_auth_methods ) == 1 ) {
430 $method = $enabled_auth_methods[0];
431 } else {
432 $method = in_array( $method, $enabled_auth_methods ) ? $method : reset( $enabled_auth_methods );
433 }
434
435 /**
436 * Default auth method
437 *
438 * @param {string} $method default auth method value
439 * @returns {string} The filtered auth method value
440 *
441 * @since 5.2.0
442 * @hook latepoint_default_contact_type_for_customer_auth
443 *
444 */
445 return apply_filters( 'latepoint_default_contact_type_for_customer_auth', $method );
446 }
447
448 public static function get_available_customer_authentication_methods(): array {
449 $methods = [
450 'password' => __( 'Password', 'latepoint' ),
451 'otp' => __( 'One-time code', 'latepoint' ),
452 ];
453
454 /**
455 * Enabled auth method
456 *
457 * @param {array} $methods available auth methods
458 * @returns {array} The filtered array of available auth methods
459 *
460 * @since 5.2.0
461 * @hook latepoint_get_available_customer_authentication_methods
462 *
463 */
464 return apply_filters( 'latepoint_get_available_customer_authentication_methods', $methods );
465 }
466
467
468 public static function get_enabled_customer_authentication_methods(): array {
469 $selected_method = OsSettingsHelper::get_settings_value( 'selected_customer_authentication_method', 'password' );
470
471 switch ( $selected_method ) {
472 case 'password':
473 $auth_methods = [ 'password' ];
474 break;
475 case 'otp':
476 $auth_methods = [ 'otp' ];
477 break;
478 case 'password_or_otp':
479 $auth_methods = [ 'password', 'otp' ];
480 break;
481 default:
482 $auth_methods = [ 'password' ];
483 }
484
485 /**
486 * Enabled auth method
487 *
488 * @param {array} $auth_methods enabled auth methods
489 * @returns {array} The filtered array of enabled auth methods
490 *
491 * @since 5.2.0
492 * @hook latepoint_get_enabled_customer_authentication_methods
493 *
494 */
495 return apply_filters( 'latepoint_get_enabled_customer_authentication_methods', $auth_methods );
496 }
497
498
499 public static function get_selected_customer_authentication_method(): string {
500 $via = OsSettingsHelper::get_settings_value( 'selected_customer_authentication_method', 'password' );
501 if ( in_array( $via, self::get_enabled_customer_authentication_methods( true ) ) ) {
502 return $via;
503 } else {
504 OsSettingsHelper::save_setting_by_name( 'selected_customer_authentication_method', 'password' );
505
506 return 'password';
507 }
508 }
509
510 public static function get_customer_authentication_method_options( $keys_only = false ): array {
511 $options = [
512 'password' => __( 'Password', 'latepoint' ),
513 'otp' => __( 'One-time code', 'latepoint' ),
514 ];
515
516 return $keys_only ? array_keys( $options ) : $options;
517 }
518
519
520 public static function get_default_contact_type_for_customer_auth(): string {
521 $method = OsSettingsHelper::get_settings_value( 'default_contact_type_for_customer_auth', 'email' );
522
523 $enabled_contact_types = self::get_enabled_contact_types_for_customer_auth();
524 if ( empty( $enabled_contact_types ) ) {
525 $method = '';
526 } elseif ( count( $enabled_contact_types ) == 1 ) {
527 $method = $enabled_contact_types[0];
528 } else {
529 $method = in_array( $method, $enabled_contact_types ) ? $method : reset( $enabled_contact_types );
530 }
531
532 /**
533 * Default auth method
534 *
535 * @param {string} $method default auth method value
536 * @returns {string} The filtered auth method value
537 *
538 * @since 5.2.0
539 * @hook latepoint_default_contact_type_for_customer_auth
540 *
541 */
542 return apply_filters( 'latepoint_default_contact_type_for_customer_auth', $method );
543 }
544
545 public static function get_available_contact_types_for_customer_auth(): array {
546 $contact_types = [
547 'email' => __( 'Email Address', 'latepoint' ),
548 'phone' => __( 'Phone Number', 'latepoint' ),
549 ];
550
551 /**
552 * Enabled auth method
553 *
554 * @param {array} $contact_types available contact types
555 * @returns {array} The filtered array of available contact types
556 *
557 * @since 5.2.0
558 * @hook latepoint_get_available_contact_types_for_customer_auth
559 *
560 */
561 return apply_filters( 'latepoint_get_available_contact_types_for_customer_auth', $contact_types );
562 }
563
564 public static function get_enabled_contact_types_for_customer_auth(): array {
565 $customer_authentication_field_type = OsSettingsHelper::get_settings_value( 'selected_customer_authentication_field_type', 'email' );
566
567 switch ( $customer_authentication_field_type ) {
568 case 'email':
569 $contact_types = [ 'email' ];
570 break;
571 case 'phone':
572 $contact_types = [ 'phone' ];
573 break;
574 case 'email_or_phone':
575 $contact_types = [ 'email', 'phone' ];
576 break;
577 case 'disabled':
578 $contact_types = [];
579 break;
580 default:
581 $contact_types = [ 'email' ];
582 }
583
584 /**
585 * Enabled auth method
586 *
587 * @param {array} $contact_types enabled contact types
588 * @returns {array} The filtered array of enabled contact types
589 *
590 * @since 5.2.0
591 * @hook latepoint_get_enabled_contact_types_for_customer_auth
592 *
593 */
594 return apply_filters( 'latepoint_get_enabled_contact_types_for_customer_auth', $contact_types );
595 }
596
597 public static function is_customer_auth_enabled(): bool {
598 return ( self::get_selected_customer_authentication_field_type() != 'disabled' );
599 }
600
601 public static function is_customer_auth_disabled(): bool {
602 return ! self::is_customer_auth_enabled();
603 }
604
605 public static function count_total_customers_violating_auth_rules(): array {
606
607 $violators = [
608 'field' => '',
609 'values' => [],
610 ];
611 $field = '';
612
613 if ( OsAuthHelper::is_customer_auth_enabled() ) {
614 // auth enabled
615 $auth_field = OsAuthHelper::get_selected_customer_authentication_field_type();
616 if ( $auth_field == 'email' ) {
617 $field = 'email';
618 }
619 if ( $auth_field == 'phone' ) {
620 $field = 'phone';
621 }
622 } else {
623 // auth disabled
624 $merge_data = OsSettingsHelper::get_settings_value( 'default_contact_merge_behavior', 'email' );
625 if ( $merge_data == 'email' ) {
626 $field = 'email';
627 }
628 if ( $merge_data == 'phone' ) {
629 $field = 'phone';
630 }
631 }
632
633 if ( $field ) {
634 $customers_model = new OsCustomerModel();
635 $result = $customers_model->select( $field )
636 ->where( [ $field . ' !=' => '' ] )
637 ->group_by( $field )
638 ->having( 'COUNT(*) > 1' )
639 ->get_results( ARRAY_A );
640 $violators['values'] = ( array_column( $result, $field ) );
641 $violators['field'] = $field;
642 }
643
644 return $violators;
645 }
646
647 public static function get_selected_customer_authentication_field_type(): string {
648 $via = OsSettingsHelper::get_settings_value( 'selected_customer_authentication_field_type' );
649 if ( empty( $via ) ) {
650 // load from legacy setting
651 if ( OsSettingsHelper::is_on( 'steps_hide_login_register_tabs' ) ) {
652 OsSettingsHelper::save_setting_by_name( 'selected_customer_authentication_field_type', 'disabled' );
653
654 return 'disabled';
655 } else {
656 OsSettingsHelper::save_setting_by_name( 'selected_customer_authentication_field_type', 'email' );
657
658 return 'email';
659 }
660 }
661 if ( in_array( $via, self::get_customer_authentication_field_type_options( true ) ) ) {
662 return $via;
663 } else {
664 OsSettingsHelper::save_setting_by_name( 'selected_customer_authentication_field_type', 'email' );
665
666 return 'email';
667 }
668 }
669
670 public static function get_customer_authentication_field_type_options( $keys_only = false ): array {
671 $options = [
672 'email' => __( 'Email Address', 'latepoint' ),
673 'phone' => __( 'Phone Number', 'latepoint' ),
674 'disabled' => __( 'Disable ability to login', 'latepoint' ),
675 ];
676
677 return $keys_only ? array_keys( $options ) : $options;
678 }
679
680
681 public static function is_classic_auth_flow(): bool {
682 return ( OsSettingsHelper::get_settings_value( 'modern_auth_flow_for_customers', LATEPOINT_VALUE_OFF ) == LATEPOINT_VALUE_OFF );
683 }
684
685 public static function is_otp_auth_enabled(): bool {
686 return in_array( 'otp', self::get_enabled_customer_authentication_methods() );
687 }
688
689
690 public static function get_default_delivery_method_for_customer_auth_contact_type( string $contact_type ) {
691 $delivery_method = 'email';
692 switch ( $contact_type ) {
693 case 'email':
694 $delivery_method = 'email';
695 break;
696 case 'phone':
697 $delivery_method = 'sms';
698 break;
699 }
700
701 /**
702 * Get default delivery method for auth contact type
703 *
704 * @param {string} $delivery_method delivery method (email, sms, whatsapp)
705 * @param {string} $contact_type contact type selected for auth (email, phone)
706 *
707 * @returns {string} Filtered delivery method
708 * @since 5.2.0
709 * @hook latepoint_get_default_delivery_method_for_customer_auth
710 *
711 */
712 return apply_filters( 'latepoint_get_default_delivery_method_for_customer_auth', $delivery_method, $contact_type );
713 }
714
715 public static function auth_form_html( $is_classic, OsCustomerModel $customer, string $selected_contact_type_for_auth = '', $selected_delivery_method = '' ): string {
716 if ( empty( $selected_contact_type_for_auth ) ) {
717 $selected_contact_type_for_auth = OsAuthHelper::get_default_contact_type_for_customer_auth();
718 }
719 if ( empty( $selected_delivery_method ) ) {
720 $selected_delivery_method = self::get_default_delivery_method_for_customer_auth_contact_type( $selected_contact_type_for_auth );
721 }
722 $enabled_contact_types_for_customer_auth = OsAuthHelper::get_enabled_contact_types_for_customer_auth();
723 $otp_allowed = self::is_otp_auth_enabled();
724 $multiple_auth_methods_enabled = ( count( self::get_enabled_customer_authentication_methods() ) > 1 );
725 $html = '';
726 if ( ! $is_classic ) {
727 $html .= '<div class="latepoint-customer-auth-wrapper">';
728 $html .= '<div class="latepoint-customer-otp-request-wrapper hide-when-entering-otp">';
729 // NEW STYLE SHOWING JUST THE AUTH OPTIONS FIRST
730 if ( in_array( 'email', $enabled_contact_types_for_customer_auth ) ) {
731 $html .= '<div data-login-method="email" class="customer-login-method-wrapper ' . ( $selected_contact_type_for_auth == 'email' ? '' : 'os-hidden' ) . '">';
732 $html .= OsFormHelper::text_field(
733 'auth[email]',
734 __( 'Your Email Address', 'latepoint' ),
735 $customer->email,
736 array(
737 'validate' => $customer->get_validations_for_property( 'email' ),
738 'class' => 'required',
739 )
740 );
741 $html .= '</div>';
742 }
743 if ( in_array( 'phone', $enabled_contact_types_for_customer_auth ) ) {
744 $html .= '<div data-login-method="phone" class="customer-login-method-wrapper ' . ( $selected_contact_type_for_auth == 'phone' ? '' : 'os-hidden' ) . '">';
745 $html .= OsFormHelper::phone_number_field(
746 'auth[phone]',
747 __( 'Your Phone Number', 'latepoint' ),
748 $customer->phone,
749 array(
750 'validate' => $customer->get_validations_for_property( 'phone' ),
751 'class' => 'required',
752 'theme' => 'simple',
753 )
754 );
755 $html .= '</div>';
756 }
757 $html .= '<a tabindex="0" class="latepoint-btn latepoint-btn-block latepoint-btn-primary latepoint-request-otp-button" data-otp-request-route="' . OsRouterHelper::build_route_name( 'auth', 'request_otp' ) . '"><span>' . __( 'Continue', 'latepoint' ) . '</span></a>';
758 $html .= '</div>';
759 $html .= '</div>';
760 } else {
761 ob_start();
762 ?>
763 <div class="os-customer-login-w os-customer-wrapped-box os-unwrapped">
764 <?php if ( count( $enabled_contact_types_for_customer_auth ) > 1 ) { ?>
765 <div class="login-options-wrapper">
766 <div class="latepoint-customer-box-title"><?php _e( 'Sign in', 'latepoint' ); ?></div>
767 <?php if ( in_array( 'email', $enabled_contact_types_for_customer_auth ) && in_array( 'phone', $enabled_contact_types_for_customer_auth ) ) { ?>
768 <div class="login-options-col login-options-via">
769 <div class="login-options-via-wrapper">
770 <div data-login-method="email" data-is-otp-enabled="<?php echo OsOTPHelper::is_otp_enabled_for_contact_type( 'email', 'email' ) ? 'yes' : 'no'; ?>"
771 data-otp-delivery-method="email"
772 class="login-option <?php echo $selected_contact_type_for_auth == 'email' ? 'os-selected os-default' : ''; ?>"><?php _e( 'Email', 'latepoint' ); ?></div>
773 <div data-login-method="phone" data-is-otp-enabled="<?php echo OsOTPHelper::is_otp_enabled_for_contact_type( 'phone', 'sms' ) ? 'yes' : 'no'; ?>"
774 data-otp-delivery-method="sms"
775 class="login-option <?php echo $selected_contact_type_for_auth == 'phone' ? 'os-selected os-default' : ''; ?>"><?php _e( 'Phone', 'latepoint' ); ?></div>
776 </div>
777 </div>
778 <?php } ?>
779 </div>
780 <?php } ?>
781 <?php
782 if ( in_array( 'email', $enabled_contact_types_for_customer_auth ) ) {
783 echo '<div data-login-method="email" class="customer-login-method-wrapper ' . ( $selected_contact_type_for_auth == 'email' ? '' : 'os-hidden' ) . '">';
784 echo OsFormHelper::text_field( 'auth[email]', __( 'Your Email Address', 'latepoint' ), '' );
785 echo '</div>';
786 }
787 ?>
788 <?php
789 if ( in_array( 'phone', $enabled_contact_types_for_customer_auth ) ) {
790 echo '<div data-login-method="phone" class="customer-login-method-wrapper ' . ( $selected_contact_type_for_auth == 'phone' ? '' : 'os-hidden' ) . '">';
791 echo OsFormHelper::phone_number_field( 'auth[phone]', __( 'Your Phone Number', 'latepoint' ), '' );
792 echo '</div>';
793 }
794 ?>
795 <div class="os-customer-login-password-fields-w" <?php echo ( OsAuthHelper::get_default_customer_authentication_method() == 'otp' ) ? 'style="display:none;"' : ''; ?>>
796 <?php echo OsFormHelper::password_field( 'auth[password]', __( 'Your Password', 'latepoint' ), '', array( 'class' => 'required' ) ); ?>
797 <a href="#" class="latepoint-btn latepoint-btn-primary latepoint-btn-link step-forgot-password-btn"
798 data-os-action="<?php echo esc_attr( OsRouterHelper::build_route_name( 'customer_cabinet', 'request_password_reset_token' ) ); ?>"
799 data-os-output-target=".os-password-reset-form-holder"
800 data-os-after-call="latepoint_reset_password_from_booking_init"
801 data-os-params="<?php echo esc_attr( OsUtilHelper::build_os_params( [ 'from_booking' => true ] ) ); ?>"><span><?php esc_html_e( 'Forgot?', 'latepoint' ); ?></span></a>
802 </div>
803
804 <?php if ( $otp_allowed ) { ?>
805 <div class="os-customer-otp-notice" <?php echo ( OsAuthHelper::get_default_customer_authentication_method() == 'otp' ) ? '' : 'style="display:none;"'; ?>>
806 <?php _e( 'You will receive a 6-digit code to log in.', 'latepoint' ); ?>
807 </div>
808 <?php } ?>
809 <div class="os-customer-login-buttons">
810 <?php if ( $multiple_auth_methods_enabled ) { ?>
811 <div class="login-options-col">
812 <div class="latepoint-customer-otp-option">
813 <?php if ( OsAuthHelper::get_default_customer_authentication_method() == 'otp' ) { ?>
814 <label><input type="checkbox" name="auth[via]" value="password"
815 class="login-with-password-toggle os-opposite"><span><?php _e( 'Use password instead', 'latepoint' ); ?></span></label>
816 <?php } else { ?>
817 <label><input type="checkbox" name="auth[via]" value="otp"
818 class="login-with-password-toggle"><span><?php _e( 'Send me a sign-in code', 'latepoint' ); ?></span></label>
819 <?php } ?>
820 </div>
821 </div>
822 <?php } else {
823 echo OsFormHelper::hidden_field( 'auth[via]', OsAuthHelper::get_default_customer_authentication_method() );
824 } ?>
825 <a data-otp-request-route="<?php echo esc_attr( OsRouterHelper::build_route_name( 'auth', 'request_otp' ) ); ?>"
826 data-password-login-route="<?php echo esc_attr( OsRouterHelper::build_route_name( 'auth', 'login_customer' ) ); ?>" href="#"
827 class="latepoint-btn latepoint-btn-primary step-login-existing-customer-btn <?php echo $multiple_auth_methods_enabled ? '' : 'latepoint-btn-block'; ?>"><span><?php esc_html_e( 'Continue', 'latepoint' ); ?></span></a>
828 </div>
829 </div>
830 <?php
831 $html = ob_get_clean();
832 }
833 $html .= OsFormHelper::hidden_field( 'auth[contact_type]', $selected_contact_type_for_auth );
834 $html .= OsFormHelper::hidden_field( 'auth[delivery_method]', $selected_delivery_method );
835 $html .= OsFormHelper::hidden_field( 'auth[action]', 'register' );
836 $html .= wp_nonce_field( 'auth_nonce', 'auth[nonce]', true, false );
837
838
839 return $html;
840 }
841
842
843 // WP USER
844 public static function get_logged_in_wp_user_id() {
845 return OsWpUserHelper::get_current_user_id();
846 }
847
848 public static function get_logged_in_wp_user() {
849 return OsWpUserHelper::get_current_user();
850 }
851
852
853 // UTILS
854
855 public static function hash_password( $password ) {
856 return wp_hash_password( $password, PASSWORD_DEFAULT );
857 }
858
859 public static function verify_password( $password, $hash ) {
860 return wp_check_password( $password, $hash );
861 }
862 }
863