PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.4.5
Fluent Support – Helpdesk & Customer Support Ticket System v2.4.5
2.4.5 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 All 69 releases
fluent-support / app / Hooks / Handlers / EmailVerificationHandler.php

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

134 lines 6.2 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 EmailVerificationHandler
11 {
12 /**
13 * Must match the "valid for 10 minutes" copy in the email below.
14 */
15 const CODE_TTL_SECONDS = 10 * MINUTE_IN_SECONDS;
16
17 public static function sendSignupEmailVerificationHtml($formData)
18 {
19 $email = strtolower(trim($formData['email']));
20
21 // The email bucket is the main throttle against mail-bombing an address. The IP
22 // bucket is looser because offices and NATs share IPs.
23 $ipKey = 'fs_signup_verify_ip_' . wp_hash(Helper::getIp());
24 $emailKey = 'fs_signup_verify_email_' . wp_hash($email);
25
26 /*
27 * Site-wide hourly cap on signup verification mail, for attackers who rotate
28 * both IP and address. Tripping it blocks signup for everyone, so keep it well
29 * above organic traffic.
30 *
31 * @since v2.2.2
32 * @param int $limit Signup verification emails allowed site-wide per hour.
33 */
34 $globalLimit = (int) apply_filters('fluent_support/signup_verification_hourly_limit', 100);
35
36 // Check the global bucket last. Short-circuiting means only requests that pass
37 // the IP and email gates count toward it, so one IP can't exhaust it.
38 if (Helper::hitRateLimit($ipKey, 20)
39 || Helper::hitRateLimit($emailKey, 5)
40 || Helper::hitRateLimit('fs_signup_verify_global', $globalLimit, HOUR_IN_SECONDS)
41 ) {
42 wp_send_json([
43 'message' => __('Too many verification code requests. Please try again later.', 'fluent-support')
44 ], 429);
45 }
46
47 try {
48 $verifcationCode = str_pad(random_int(100123, 900987), 6, 0, STR_PAD_LEFT);
49 } catch (\Exception $e) {
50 $verifcationCode = str_pad(wp_rand(100123, 900987), 6, 0, STR_PAD_LEFT);
51 }
52
53 $string = $formData['email'] . '-' . wp_generate_uuid4() . wp_rand(1, 99999999);
54 $hash = wp_hash_password($string);
55 $hash = sanitize_title($hash, '', 'display');
56 $hash .= $formData['email'] . '-' . time();
57
58 $data = array(
59 'login_hash' => $hash,
60 'status' => 'issued',
61 'email' => strtolower(trim($formData['email'])),
62 'ip_address' => Helper::getIp(),
63 'use_type' => 'signup_verification',
64 'used_count' => 0,
65 'two_fa_code_hash' => wp_hash_password($verifcationCode),
66 'valid_till' => gmdate('Y-m-d H:i:s', current_time('timestamp') + self::CODE_TTL_SECONDS),
67 'created_at' => current_time('mysql'),
68 'updated_at' => current_time('mysql')
69 );
70
71 $savedRecord = Meta::create([
72 'object_type' => 'fs_login_hashes',
73 'key' => $hash,
74 'value' => maybe_serialize($data)
75 ]);
76
77 if (!$savedRecord || !$savedRecord->exists) {
78 wp_send_json([
79 'message' => __('Unable to send verification code. Please try again later.', 'fluent-support')
80 ], 500);
81 }
82
83 // translators: %s is the site name
84 $mailSubject = apply_filters("fluent_support/signup_verification_mail_subject", sprintf(__('Your registration verification code for %s', 'fluent-support'), get_bloginfo('name')));
85
86 $pStart = '<p style="font-family: Arial, sans-serif; font-size: 16px; font-weight: normal; margin: 0; margin-bottom: 16px;">';
87
88 // translators: %s is the user's first name
89 $message = $pStart . sprintf(__('Hello %s,', 'fluent-support'), Arr::get($formData, 'first_name')) . '</p>' .
90 $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-support') . '</p>' .
91 // translators: %s is the verification code
92 $pStart . '<b>' . sprintf(__('Verification Code: %s', 'fluent-support'), $verifcationCode) . '</b></p>' .
93 '<br />' .
94 $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>';
95
96 $message = apply_filters('fluent_support/signup_verification_email_body', $message, $verifcationCode, $formData);
97
98 $data = [
99 'body' => $message,
100 'pre_header' => __('Activate your account', 'fluent-support'),
101 'show_footer' => false
102 ];
103
104 $message = Helper::loadView('notification', $data);
105 $headers = array('Content-Type: text/html; charset=UTF-8');
106
107 \wp_mail($formData['email'], $mailSubject, $message, $headers);
108
109 ob_start();
110 ?>
111 <div class="fs_signup_verification">
112 <div class="fs_field_group fs_field_verification">
113 <?php // translators: %s is the email address ?>
114 <p><?php echo esc_html(sprintf(__('A verification code has been sent to %s. Please provide the code below:', 'fluent-support'), $formData['email'])); ?></p>
115 <input type="hidden" name="_email_verification_hash" value="<?php echo esc_attr($hash); ?>"/>
116 <div class="fs_field_label is-required">
117 <label for="fs_field_verification"><?php esc_html_e('Verification Code', 'fluent-support'); ?></label>
118 </div>
119 <div class="fs_input_wrap">
120 <input type="text" id="fs_field_verification" placeholder="" name="_email_verification_token" required>
121 </div>
122 </div>
123 <button
124 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; margin-top: 10px;"
125 id="fs_verification_submit" type="submit">
126 <?php esc_html_e('Complete Signup', 'fluent-support'); ?>
127 </button>
128 </div>
129 <?php
130 return ob_get_clean();
131 }
132
133 }
134