PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.2.0
Fluent Support – Helpdesk & Customer Support Ticket System v2.2.0
2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 All 68 releases
fluent-support / app / Hooks / Handlers / TwoFaHandler.php

TwoFaHandler.php in Fluent Support – Helpdesk & Customer Support Ticket System 2.2.0, at app/Hooks/Handlers/TwoFaHandler.php

215 lines 7.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentSupport\App\Hooks\Handlers;
4
5 use FluentSupport\App\Models\Meta;
6 use FluentSupport\App\Services\Helper;
7 use FluentSupport\Framework\Support\Arr;
8
9
10 class TwoFaHandler
11 {
12 public function maybe2FaRedirect($user = null)
13 {
14 $return = $this->sendAndGet2FaConfirmFormUrl($user, 'both');
15
16 if (!$return) {
17 return false;
18 }
19
20 $getForm = $this->get2faForm($return);
21
22 wp_send_json([
23 'load_2fa' => 'yes',
24 'two_fa_form' => $getForm
25 ]);
26 }
27
28 public function sendAndGet2FaConfirmFormUrl($user, $return = 'url')
29 {
30 try {
31 $twoFaCode = str_pad(random_int(100123, 900987), 6, 0, STR_PAD_LEFT);
32 } catch (\Exception $e) {
33 $twoFaCode = str_pad(wp_rand(100123, 900987), 6, 0, STR_PAD_LEFT);
34 }
35
36 $string = $user->ID . '-' . wp_generate_uuid4() . wp_rand(1, 99999999);
37 $hash = wp_hash_password($string);
38 $hash = sanitize_title($hash, '', 'display');
39 $hash .= $user->ID . '-' . time();
40
41 $data = array(
42 'login_hash' => $hash,
43 'user_id' => $user->ID,
44 'status' => 'issued',
45 'ip_address' => isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '',
46 'use_type' => 'email_2_fa',
47 'user_email' => $user->user_email,
48 'two_fa_code_hash' => wp_hash_password($twoFaCode),
49 'valid_till' => gmdate('Y-m-d H:i:s', current_time('timestamp') + 10 * 30),
50 'created_at' => current_time('mysql'),
51 'updated_at' => current_time('mysql'),
52 'used_count' => 0
53 );
54
55 $existingRecord = Meta::where('key', $hash)->first();
56
57 if ($existingRecord) {
58 $saveSettingsData = Meta::where('key', $hash)->update([
59 'value' => maybe_serialize($data)
60 ]);
61 } else {
62 $saveSettingsData = Meta::updateOrInsert([
63 'object_type' => 'fs_2fa',
64 'key' => $hash,
65 ], [
66 'value' => maybe_serialize($data)
67 ]);
68 }
69
70 if (!$saveSettingsData) {
71 return false;
72 }
73 $data['twoFaCode'] = $twoFaCode;
74 $this->send2FaEmail($data, $user, '');
75
76 return [
77 'redirect_to' => add_query_arg([
78 'fs_2fa' => 'email',
79 'login_hash' => $hash,
80 'action' => 'fs_2fa_email'
81 ], wp_login_url()),
82 'login_hash' => $hash,
83 ];
84 }
85
86 public function verify2FaEmailCode($data)
87 {
88 $redirectUrl = Helper::getPortalBaseUrl();
89
90 $code = $data['login_passcode'];
91 $hash = $data['login_hash'];
92
93 if (!$code || !$hash) {
94 wp_send_json([
95 'message' => __('Please provide a valid login code', 'fluent-support')
96 ], 423);
97 }
98
99 $logHashMeta = Meta::where('key', $hash)->first();
100
101 if (!$logHashMeta) {
102 wp_send_json([
103 'message' => __('Your provided code or url is not valid', 'fluent-support')
104 ], 423);
105 }
106
107 $logHash = Helper::safeUnserialize($logHashMeta->value, []);
108
109 if (!$logHash) {
110 wp_send_json([
111 'message' => __('Your provided code or url is not valid', 'fluent-support')
112 ], 423);
113 }
114 if (!wp_check_password($code, $logHash['two_fa_code_hash'])) {
115
116 $logHash['used_count'] += 1;
117
118 Meta::where('key', $hash)->update([
119 'value' => maybe_serialize($logHash)
120 ]);
121
122 return false;
123 }
124
125 $createdAt = $logHash['created_at'] ?? '';
126 if (($createdAt && strtotime($createdAt) < current_time('timestamp') - 600) || ($logHash['used_count'] ?? 0) > 5 || ($logHash['status'] ?? '') != 'issued') {
127 wp_send_json([
128 'message' => __('Sorry, your login code has been expired. Please try to login again', 'fluent-support')
129 ], 423);
130 }
131 $user = get_user_by('email', $logHash['user_email']);
132
133 wp_clear_auth_cookie();
134 wp_set_current_user($user->ID);
135 wp_set_auth_cookie($user->ID);
136
137 if (is_user_logged_in()) {
138 $logHash['status'] = 'used';
139
140 Meta::where('key', $hash)->update([
141 'value' => maybe_serialize($logHash)
142 ]);
143 }
144
145 wp_send_json([
146 'redirect' => $redirectUrl
147 ], 200);
148 }
149
150 private function send2FaEmail($data, $user, $autoLoginUrl = false)
151 {
152 $emailTo = $user->user_email;
153 // translators: %1s is the site name
154 $emailSubject = sprintf(__('Your Login code for %1s', 'fluent-support'), get_bloginfo('name'));
155
156 $pStart = '<p style="font-family: Arial, sans-serif; font-size: 16px; font-weight: normal; margin: 0; margin-bottom: 16px;">';
157
158 // translators: %s is the user's display name
159 $message = $pStart . sprintf(__('Hello %s,', 'fluent-support'), $user->display_name) . '</p>' .
160 // translators: %s is the site name
161 $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')) . '</p>' .
162 // translators: %s is the two-factor authentication code
163 $pStart . '<b>' . sprintf(__('Verification Code: %s', 'fluent-support'), $data['twoFaCode']) . '</b></p>' .
164 '<br />' .
165 $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-support') . '</p>';
166
167 $message = apply_filters('fluent_support/signup_verification_email_body', $message, $data['twoFaCode'], $data);
168
169 $data = [
170 'body' => $message,
171 'pre_header' => __('Activate your account', 'fluent-support'),
172 'show_footer' => false
173 ];
174
175 $message = Helper::loadView('notification', $data);
176 $headers = array('Content-Type: text/html; charset=UTF-8');
177
178 \wp_mail($emailTo, $emailSubject, $message, $headers);
179 }
180
181 public function get2faForm($data = [])
182 {
183 ob_start();
184 ?>
185 <form
186 style="margin-top: 20px; padding: 20px; font-weight: 400; overflow: hidden; background: #f6f6f6; border: 1px solid #ccc; box-shadow: 0 0 10px rgba(0,0,0,.15);"
187 class="fs_2fa" id="fs_2fa_form">
188 <input type="hidden" name="login_hash" value="<?php echo esc_attr($data['login_hash']); ?>"/>
189 <div style="margin-bottom: 10px;">
190 <?php esc_html_e('Please check your email inbox and enter the two-factor verification code below:', 'fluent-support'); ?>
191 </div>
192 <div style="margin-bottom: 10px;">
193 <label for="login_passcode"><?php esc_html_e('Verification Code', 'fluent-support'); ?></label>
194 <div>
195 <input
196 style="font-size: 14px; padding: 8px; border: 1px solid #ccc; border-radius: 3px; width: 100%; box-sizing: border-box;"
197 placeholder="<?php esc_html_e('Login Code', 'fluent-support'); ?>" type="text" name="login_passcode"
198 id="login_passcode" class="input" size="20"/>
199 </div>
200 </div>
201 <div>
202 <button
203 style="display: inline-block; cursor: pointer; border: 0; background: #2271b1; color: #fff; text-decoration: none; text-shadow: none; min-height: 32px; padding: 8px 24px; font-size: 14px; border-radius: 3px;"
204 id="fs_2fa_confirm" type="submit">
205 <?php esc_html_e('Verify and Login', 'fluent-support'); ?>
206 </button>
207 </div>
208 </form>
209 <?php
210
211 return ob_get_clean();
212 }
213
214 }
215