PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 1.1.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v1.1.0
2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 1.1.0 All 77 releases
fluent-community / Modules / Auth / AuthHelper.php

AuthHelper.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 1.1.0, at Modules/Auth/AuthHelper.php

376 lines 15.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\Modules\Auth;
4
5 use FluentCommunity\App\App;
6 use FluentCommunity\App\Services\Helper;
7 use FluentCommunity\App\Services\Libs\Mailer;
8 use FluentCommunity\Framework\Support\Arr;
9
10 class AuthHelper
11 {
12 public static function registerNewUser($user_login, $user_email, $user_pass = '', $extraData = [])
13 {
14 $errors = new \WP_Error();
15
16 $sanitized_user_login = sanitize_user($user_login);
17
18 $user_email = apply_filters('user_registration_email', $user_email);
19
20 // Check the username.
21 if ('' === $sanitized_user_login) {
22 $errors->add('empty_username', __('<strong>Error</strong>: Please enter a username.', 'fluent-community'));
23 } elseif (!validate_username($user_login)) {
24 $errors->add('invalid_username', __('<strong>Error</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.', 'fluent-community'));
25 $sanitized_user_login = '';
26 } elseif (username_exists($sanitized_user_login)) {
27 $errors->add('username_exists', __('<strong>Error</strong>: This username is already registered. Please choose another one.', 'fluent-community'));
28 } else {
29 /** This filter is documented in wp-includes/user.php */
30 $illegal_user_logins = (array)apply_filters('illegal_user_logins', array());
31 if (in_array(strtolower($sanitized_user_login), array_map('strtolower', $illegal_user_logins), true)) {
32 $errors->add('invalid_username', __('<strong>Error</strong>: Sorry, that username is not allowed.', 'fluent-community'));
33 }
34 }
35
36 // Check the email address.
37 if ('' === $user_email) {
38 $errors->add('empty_email', __('<strong>Error</strong>: Please type your email address.', 'fluent-community'));
39 } elseif (!is_email($user_email)) {
40 $errors->add('invalid_email', __('<strong>Error</strong>: The email address is not correct.', 'fluent-community'));
41 $user_email = '';
42 } elseif (email_exists($user_email)) {
43 $errors->add(
44 'email_exists',
45 __('<strong>Error:</strong> This email address is already registered. Please login or try resetting your password.', 'fluent-community')
46 );
47 }
48
49 do_action('register_post', $sanitized_user_login, $user_email, $errors);
50
51 $errors = apply_filters('registration_errors', $errors, $sanitized_user_login, $user_email);
52
53 if ($errors->has_errors()) {
54 return $errors;
55 }
56
57 if (!$user_pass) {
58 $user_pass = wp_generate_password(8, false);
59 }
60
61 $data = [
62 'user_login' => wp_slash($sanitized_user_login),
63 'user_email' => wp_slash($user_email),
64 'user_pass' => $user_pass
65 ];
66
67 if (!empty($extraData['first_name'])) {
68 $data['first_name'] = sanitize_text_field($extraData['first_name']);
69 }
70
71 if (!empty($extraData['last_name'])) {
72 $data['last_name'] = sanitize_text_field($extraData['last_name']);
73 }
74
75 if (!empty($extraData['full_name']) && empty($extraData['first_name']) && empty($extraData['last_name'])) {
76 $extraData['full_name'] = sanitize_text_field($extraData['full_name']);
77 // extract the names
78 $fullNameArray = explode(' ', $extraData['full_name']);
79 $data['first_name'] = array_shift($fullNameArray);
80 if ($fullNameArray) {
81 $data['last_name'] = implode(' ', $fullNameArray);
82 } else {
83 $data['last_name'] = '';
84 }
85 }
86
87 if (!empty($extraData['description'])) {
88 $data['description'] = sanitize_textarea_field($extraData['description']);
89 }
90
91 if (!empty($extraData['user_url']) && filter_var($extraData['user_url'], FILTER_VALIDATE_URL)) {
92 $data['user_url'] = sanitize_url($extraData['user_url']);
93 }
94
95 if (!empty($extraData['role'])) {
96 $data['role'] = $extraData['role'];
97 }
98
99 $user_id = wp_insert_user($data);
100
101 if (!$user_id || is_wp_error($user_id)) {
102 $errors->add('registerfail', __('<strong>Error</strong>: Could not register you. Please contact the site admin!', 'fluent-community')
103 );
104 return $errors;
105 }
106
107 if (!empty($_COOKIE['wp_lang'])) {
108 $wp_lang = sanitize_text_field($_COOKIE['wp_lang']);
109 if (in_array($wp_lang, get_available_languages(), true)) {
110 update_user_meta($user_id, 'locale', $wp_lang); // Set user locale if defined on registration.
111 }
112 }
113
114 do_action('register_new_user', $user_id);
115
116 return $user_id;
117 }
118
119 public static function makeLogin($user)
120 {
121 wp_clear_auth_cookie();
122 wp_set_current_user($user->ID, $user->user_login);
123 wp_set_auth_cookie($user->ID, true, is_ssl());
124
125 $user = get_user_by('ID', $user->ID);
126
127 if ($user) {
128 do_action('wp_login', $user->user_login, $user);
129 }
130
131 return $user;
132 }
133
134 public static function isFluentAuthAvailable()
135 {
136 if (defined('FLUENT_AUTH_VERSION') && FLUENT_AUTH_VERSION) {
137 return (new \FluentAuth\App\Hooks\Handlers\CustomAuthHandler())->isEnabled();
138 }
139
140 return false;
141 }
142
143 public static function getFormFields($invitation = null)
144 {
145
146 $policyUrl = apply_filters('fluent_community/terms_policy_url', get_privacy_policy_url());
147
148 $termsText = __('I agree to the terms and conditions', 'fluent-community');
149 if($policyUrl) {
150 $termsText = sprintf(__('I agree to the %1sterms and conditions%2s', 'fluent-community'), '<a rel="nooppener" href="' . esc_url($policyUrl) . '" target="_blank">', '</a>');
151 }
152
153
154 $fields = apply_filters('fluent_communuty/auth/signup_fields', [
155 'full_name' => [
156 'label' => __('Full name', 'fluent-community'),
157 'placeholder' => __('Your first & last name', 'fluent-community'),
158 'type' => 'text',
159 'required' => true,
160 'value' => $invitation ? Arr::get($invitation->meta, 'invitee_name') : '',
161 'sanitize_callback' => 'sanitize_text_field'
162 ],
163 'email' => [
164 'type' => 'email',
165 'placeholder' => __('Your email address', 'fluent-community'),
166 'label' => __('Email Address', 'fluent-community'),
167 'required' => true,
168 'value' => $invitation ? $invitation->message : '',
169 'readonly' => !!$invitation,
170 'sanitize_callback' => 'sanitize_email'
171 ],
172 'username' => [
173 'type' => 'text',
174 'placeholder' => __('No space or special characters', 'fluent-community'),
175 'label' => __('Username', 'fluent-community'),
176 'required' => true,
177 'sanitize_callback' => 'sanitize_user'
178 ],
179 'password' => [
180 'type' => 'password',
181 'placeholder' => __('Password', 'fluent-community'),
182 'label' => __('Account Password', 'fluent-community'),
183 'required' => true,
184 'sanitize_callback' => 'sanitize_text_field'
185 ],
186 'conf_password' => [
187 'type' => 'password',
188 'placeholder' => __('Password Confirmation', 'fluent-community'),
189 'label' => __('Re-type Account Password', 'fluent-community'),
190 'required' => true,
191 'sanitize_callback' => 'sanitize_text_field'
192 ],
193 'terms' => [
194 'type' => 'inline_checkbox',
195 'inline_label' => $termsText,
196 'required' => true
197 ]
198 ], $invitation);
199
200 if (!self::isPasswordConfRequired()) {
201 unset($fields['conf_password']);
202 }
203
204 return $fields;
205 }
206
207 public static function getLoginFormFields()
208 {
209 return apply_filters('fluent_community/auth/login_fields', [
210 'username' => [
211 'type' => 'text',
212 'placeholder' => __('Your account email address', 'fluent-community'),
213 'label' => __('Email Address', 'fluent-community'),
214 'required' => true,
215 'sanitize_callback' => 'sanitize_user'
216 ],
217 'password' => [
218 'type' => 'password',
219 'placeholder' => __('Your account password', 'fluent-community'),
220 'label' => __('Password', 'fluent-community'),
221 'required' => true,
222 'sanitize_callback' => 'sanitize_text_field'
223 ]
224 ]);
225 }
226
227 public static function isPasswordConfRequired()
228 {
229 return apply_filters('fluent_community/autg/password_confirmation', true);
230 }
231
232 public static function isRegistrationEnabled()
233 {
234 return apply_filters('fluent_community/auth/registration_enabled', !!get_option('users_can_register'));
235 }
236
237 public static function isTwoFactorEnabled()
238 {
239 return apply_filters('fluent_community/auth/two_factor_enabled', true);
240 }
241
242 public static function get2FaRegistrationCodeForm($formData)
243 {
244 $generalSettings = Helper::generalSettings();
245 try {
246 $verifcationCode = str_pad(random_int(100123, 900987), 6, 0, STR_PAD_LEFT);
247 } catch (\Exception $e) {
248 $verifcationCode = str_pad(mt_rand(100123, 900987), 6, 0, STR_PAD_LEFT);
249 }
250
251 // Hash the code
252 $codeHash = wp_hash_password($verifcationCode);
253
254 // Create a token with the email and code hash
255 $data = [
256 'email' => $formData['email'],
257 'code_hash' => $codeHash,
258 'expires' => time() + 600 // 10 minutes expiry
259 ];
260 $token = base64_encode(json_encode($data));
261
262 // Sign the token
263 $signature = hash_hmac('sha256', $token, SECURE_AUTH_KEY);
264 $signedToken = $token . '.' . $signature;
265
266 $mailSubject = apply_filters("fluent_community/auth/signup_verification_mail_subject", sprintf(__('Your registration verification code for %s', 'fluent-community'), Arr::get($generalSettings, 'site_title')));
267
268 $pStart = '<p style="font-family: Arial, sans-serif; font-size: 16px; font-weight: normal; margin: 0; margin-bottom: 16px;">';
269
270 $message = $pStart . sprintf(__('Hello %s,', 'fluent-community'), Arr::get($formData, 'first_name')) . '</p>' .
271 $pStart . __('Thank you for registering with us! To complete the setup of your account, please enter the verification code below on the registration page.', 'fluent-community') . '</p>' .
272 $pStart . '<b>' . sprintf(__('Verification Code: %s', 'fluent-community'), $verifcationCode) . '</b></p>' .
273 '<br />' .
274 $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-community') . '</p>';
275
276 $message = apply_filters('fluent_community/auth/signup_verification_email_body', $message, $verifcationCode, $formData);
277
278 $generalSettings = Helper::generalSettings();
279 $message = (string)App::make('view')->make('email.template', [
280 'logo' => [
281 'url' => $generalSettings['logo'],
282 'alt' => $generalSettings['site_title']
283 ],
284 'bodyContent' => $message,
285 'pre_header' => __('Activate your account', 'fluent-community'),
286 'footerLines' => [
287 __('If you did not initiate this request, please ignore this email.', 'fluent-community'),
288 sprintf(__('This email has been sent from %1$s. Site: %2$s', 'fluent-community'), Arr::get($generalSettings, 'site_title'), site_url())
289 ]
290 ]);
291
292 $mailer = new Mailer($formData['email'], $mailSubject, $message);
293
294 if ($formData['first_name']) {
295 $toName = trim(Arr::get($formData, 'first_name') . ' ' . Arr::get($formData, 'last_name'));
296 $mailer = $mailer->to($formData['email'], $toName);
297 }
298
299 $mailer->send();
300
301 ob_start();
302 ?>
303 <div class="fls_signup_verification">
304 <input type="hidden" name="__two_fa_signed_token" value="<?php echo esc_attr($signedToken); ?>"/>
305 <p><?php echo esc_html(sprintf(__('A verification code has been sent to %s. Please provide the code below: ', 'fluent-community'), $formData['email'])) ?></p>
306 <div class="fcom_form-group fcom_field_vefication">
307 <div class="fcom_form_label">
308 <label for="fcom_field_vefication"><?php _e('Verification Code', 'fluent-community'); ?></label>
309 </div>
310 <div class="fs_input_wrap">
311 <input type="text" id="fcom_field_vefication"
312 placeholder="<?php _e('2FA Code', 'fluent-community'); ?>" name="_email_verification_code"
313 required/>
314 </div>
315 </div>
316 <div class="fcom_form-group">
317 <div class="fcom_form_input">
318 <button type="submit" class="fcom_btn fcom_btn_primary">
319 <?php _e('Complete Signup', 'fluent-community'); ?>
320 </button>
321 </div>
322 </div>
323 </div>
324
325 <?php
326 return ob_get_clean();
327 }
328
329 public static function validateVerificationCode($code, $verificationToken, $formData)
330 {
331 list($data, $signature) = explode('.', $verificationToken, 2);
332 $expectedSignature = hash_hmac('sha256', $data, SECURE_AUTH_KEY);
333
334 if (!hash_equals($expectedSignature, $signature)) {
335 return new \WP_Error('invalid_token', __('Invalid verification token. Please try again', 'fluent-community'));
336 }
337
338 $data = json_decode(base64_decode($data), true);
339 if ($data['expires'] < time()) {
340 return new \WP_Error('expired_token', __('Verification token has expired. Please try again.', 'fluent-community'));
341 }
342
343 if ($data['email'] !== $formData['email']) {
344 return new \WP_Error('invalid_email', __('Invalid email address. Please try again', 'fluent-community'));
345 }
346
347 if (!wp_check_password($code, $data['code_hash'])) {
348 return new \WP_Error('invalid_code', __('Invalid verification code. Please try again', 'fluent-community'));
349 }
350
351 return true;
352 }
353
354 public static function isAuthRateLimit()
355 {
356 if (apply_filters('fluent_community/auth/disable_rate_limit', false)) {
357 return true;
358 }
359
360 $transientKey = 'fluent_com_rate_limit_' . md5(Helper::getIp());
361 $rateLimit = get_transient($transientKey);
362
363 if (!$rateLimit) {
364 $rateLimit = 0;
365 }
366
367 if ($rateLimit >= 10) {
368 return new \WP_Error('rate_limit', __('Too many requests. Please try again later', 'fluent-community'));
369 }
370
371 $rateLimit = $rateLimit + 1;
372 set_transient($transientKey, $rateLimit, 300); // per 5 minutes
373 return true;
374 }
375 }
376