sendAndGet2FaConfirmFormUrl($user, 'both'); if (!$return) { return false; } $getForm = $this->get2faForm($return); wp_send_json([ 'load_2fa' => 'yes', 'two_fa_form' => $getForm ]); } public function sendAndGet2FaConfirmFormUrl($user, $return = 'url') { try { $twoFaCode = str_pad(random_int(100123, 900987), 6, 0, STR_PAD_LEFT); } catch (\Exception $e) { $twoFaCode = str_pad(wp_rand(100123, 900987), 6, 0, STR_PAD_LEFT); } $string = $user->ID . '-' . wp_generate_uuid4() . wp_rand(1, 99999999); $hash = wp_hash_password($string); $hash = sanitize_title($hash, '', 'display'); $hash .= $user->ID . '-' . time(); $data = array( 'login_hash' => $hash, 'user_id' => $user->ID, 'status' => 'issued', 'ip_address' => $_SERVER['HTTP_USER_AGENT'], 'use_type' => 'email_2_fa', 'user_email' => $user->user_email, 'two_fa_code_hash' => wp_hash_password($twoFaCode), 'valid_till' => date('Y-m-d H:i:s', current_time('timestamp') + 10 * 30), 'created_at' => current_time('mysql'), 'updated_at' => current_time('mysql'), 'used_count' => 0 ); $existingRecord = Meta::where('key', $hash)->first(); if ($existingRecord) { $saveSettingsData = Meta::where('key', $hash)->update([ 'value' => maybe_serialize($data) ]); } else { $saveSettingsData = Meta::updateOrInsert([ 'object_type' => 'fs_2fa', 'key' => $hash, ], [ 'value' => maybe_serialize($data) ]); } if (!$saveSettingsData) { return false; } $data['twoFaCode'] = $twoFaCode; $this->send2FaEmail($data, $user, ''); return [ 'redirect_to' => add_query_arg([ 'fs_2fa' => 'email', 'login_hash' => $hash, 'action' => 'fs_2fa_email' ], wp_login_url()), 'login_hash' => $hash, ]; } public function verify2FaEmailCode($data) { $redirectUrl = Helper::getPortalBaseUrl(); $code = $data['login_passcode']; $hash = $data['login_hash']; if (!$code || !$hash) { wp_send_json([ 'message' => __('Please provide a valid login code', 'fluent-support') ], 423); } $logHash = Meta::where('key', $hash)->first(); $logHash = Helper::safeUnserialize($logHash->value, []); if (!$logHash) { wp_send_json([ 'message' => __('Your provided code or url is not valid', 'fluent-support') ], 423); } if (!wp_check_password($code, $logHash['two_fa_code_hash'])) { $logHash['used_count'] += 1; Meta::where('key', $hash)->update([ 'value' => maybe_serialize($logHash) ]); return false; } if (strtotime($logHash['created_at']) < current_time('timestamp') - 600 || $logHash['used_count'] > 5 || $logHash['status'] != 'issued') { wp_send_json([ 'message' => __('Sorry, your login code has been expired. Please try to login again', 'fluent-support') ], 423); } $user = get_user_by('email', $logHash['user_email']); wp_clear_auth_cookie(); wp_set_current_user($user->ID); wp_set_auth_cookie($user->ID); if (is_user_logged_in()) { $logHash['status'] = 'used'; Meta::where('key', $hash)->update([ 'value' => maybe_serialize($logHash) ]); } wp_send_json([ 'redirect' => $redirectUrl ], 200); } private function send2FaEmail($data, $user, $autoLoginUrl = false) { $emailTo = $user->user_email; $emailSubject = sprintf(__('Your Login code for %1s', 'fluent-support'), get_bloginfo('name')); $pStart = '

'; $message = $pStart . sprintf(__('Hello %s,', 'fluent-support'), $user->display_name) . '

' . $pStart . sprintf(__('Someone requested to login to %s and here is the Login code that you can use in the login form', 'fluent-support'), get_bloginfo('name')) . '

' . $pStart . '' . sprintf(__('Verification Code: %s', 'fluent-security'), $data['twoFaCode']) . '

' . '
' . $pStart . __('This code is valid for 10 minutes and is meant to ensure the security of your account. If you did not initiate this request, please ignore this email.', 'fluent-security') . '

'; $message = apply_filters('fluent_support/signup_verification_email_body', $message, $data['twoFaCode'], $data); $data = [ 'body' => $message, 'pre_header' => __('Activate your account', 'fluent-security'), 'show_footer' => false ]; $message = Helper::loadView('notification', $data); $headers = array('Content-Type: text/html; charset=UTF-8'); \wp_mail($emailTo, $emailSubject, $message, $headers); } public function get2faForm($data = []) { ob_start(); ?>