PluginProbe
The WP Remote WordPress Plugin / 6.76
The WP Remote WordPress Plugin v6.76
6.76 6.72 6.69 6.65 6.62 6.48 6.47 4.87 4.97 5.05 5.09 5.16 5.22 5.24 5.25 5.38 5.41 5.42 5.45 5.47 5.53 5.56 5.65 5.68 5.72 All 54 releases
wpremote / wp_2fa / wp_2fa.php

wp_2fa.php in The WP Remote WordPress Plugin 6.76, at wp_2fa/wp_2fa.php

163 lines 5.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) exit;
3 if (!class_exists('WPRWP2FA')) :
4
5 require_once dirname(__FILE__) . '/utils.php';
6 require_once dirname(__FILE__) . '/time_otp.php';
7 require_once dirname(__FILE__) . '/time_otp_login.php';
8 require_once dirname(__FILE__) . '/email_otp.php';
9 require_once dirname(__FILE__) . '/email_otp_template.php';
10 require_once dirname(__FILE__) . '/email_otp_sender.php';
11 require_once dirname(__FILE__) . '/email_otp_login.php';
12
13 class WPRWP2FA {
14 const FLAG_META_KEY = 'wpr_2fa_enabled';
15 const SECRET_META_KEY = 'wpr_2fa_secret';
16 const METHOD_META_KEY = 'wpr_2fa_method';
17 const EMAIL_CHALLENGE_META_KEY = 'wpr_2fa_email_challenge';
18 const EMAIL_RATE_META_KEY = 'wpr_2fa_email_rate';
19 const ATTEMPTS_META_KEY = 'wpr_2fa_attempts';
20 const INVALID_CODE_MESSAGE = 'The 2FA code you entered is incorrect.';
21 const TOOLTIP_MESSAGE = 'Please contact your administrator if you need assistance.';
22 const CONTEXT_MESSAGE = 'Two-factor authentication is required in the standard sign-in page.';
23 const CONFIG_MESSAGE = 'Please contact your administrator to login.';
24
25 public static $cipher_algo = 'aes-256-cbc';
26 public static $wp_2fa_option = 'wprWp2faConf';
27
28 private static $whitelabel = null;
29
30 public static function whitelabelMessage($key, $default) {
31 if (self::$whitelabel === null) {
32 $info = new WPRInfo(new WPRWPSettings());
33 $values = $info->getLPWhitelabelInfo();
34 self::$whitelabel = is_array($values) ? $values : array();
35 }
36
37 return (isset(self::$whitelabel[$key]) && is_string(self::$whitelabel[$key])) ? self::$whitelabel[$key] : $default;
38 }
39
40 # Sent as a JSON failure rather than returned as a WP_Error. These are system
41 # states, not wrong credentials, and a WP_Error would be recorded as a failed
42 # login against the firewall's lockout counter.
43 public static function sendFailure($message, $data = array()) {
44 wp_send_json_error(array_merge($data, array('message' => $message)));
45 exit;
46 }
47
48 public static function humanWait($seconds) {
49 if ($seconds < 90) {
50 return sprintf('%d seconds', max(1, intval($seconds)));
51 }
52
53 return sprintf('%d minutes', intval(ceil($seconds / MINUTE_IN_SECONDS)));
54 }
55
56 public static function isEnabled($settings) {
57 $config = $settings->getOption(self::$wp_2fa_option);
58
59 return (is_array($config) && array_key_exists('enabled', $config) &&
60 $config['enabled'] === true);
61 }
62
63 public function init() {
64 add_filter('authenticate', array($this, 'authenticate'), 25, 3);
65 add_action('login_form', array($this, 'custom_login_form'));
66 add_action('login_enqueue_scripts', array($this, 'enqueue_login_assets'));
67 }
68
69 public function enqueue_login_assets() {
70 wp_enqueue_style('WPR-wp-2fa-login', plugin_dir_url(__FILE__) . 'css/login.css', array(), '1.4');
71 wp_enqueue_script('WPR-wp-2fa-login', plugin_dir_url(__FILE__) . 'js/login.js', array(), '1.4', true);
72 }
73
74 public function authenticate($user, $username, $password) {
75 if (!($user instanceof WP_User)) {
76 return $user;
77 }
78
79 if ('1' !== get_user_meta($user->ID, self::FLAG_META_KEY, true)) {
80 return $user;
81 }
82
83 if (!self::isInteractiveLogin()) {
84 return new WP_Error('twofa_context', self::CONTEXT_MESSAGE);
85 }
86
87 $method = get_user_meta($user->ID, self::METHOD_META_KEY, true);
88 if ($method === 'email_otp') {
89 return WPRWP2FAEmailOTPLogin::authenticate($user);
90 }
91 if ($method !== '' && $method !== 'totp') {
92 self::sendFailure(self::CONFIG_MESSAGE);
93 }
94
95 return WPRWP2FATimeOTPLogin::authenticate($user);
96 }
97
98 private static function isInteractiveLogin() {
99 global $pagenow;
100
101 if ((defined('XMLRPC_REQUEST') && XMLRPC_REQUEST) ||
102 (defined('REST_REQUEST') && REST_REQUEST) ||
103 (defined('WP_CLI') && WP_CLI)) {
104 return false;
105 }
106
107 return $pagenow === 'wp-login.php';
108 }
109
110 function custom_login_form() {
111 $tooltip_message = self::whitelabelMessage('2fa_tooltip', self::TOOLTIP_MESSAGE);
112 $is_url = filter_var($tooltip_message, FILTER_VALIDATE_URL);
113 $allowed_tooltip_html = array(
114 'a' => array(
115 'class' => true,
116 'href' => true,
117 'rel' => true,
118 'target' => true
119 ),
120 'span' => array(
121 'class' => true,
122 'id' => true,
123 'title' => true
124 )
125 );
126
127 $icon_html = '<span
128 id="twofa-help-icon"
129 class="dashicons dashicons-editor-help"></span>';
130
131 if ($is_url) {
132 $tooltip_html = '<a
133 href="' . esc_url($tooltip_message) . '"
134 target="_blank"
135 rel="noopener noreferrer"
136 class="twofa-help-link">' . $icon_html . '</a>';
137 } else {
138 $tooltip_html = '<span
139 id="twofa-help-icon"
140 class="dashicons dashicons-editor-help"
141 title="' . esc_attr($tooltip_message) . '"></span>';
142 }
143 ?>
144 <div class="wp2fa-progress-bar">
145 <div class="progress-bar-inner"></div>
146 </div>
147 <template id="twofa-field-template">
148 <p id="twofa-code-field">
149 <label for="twofa-code">
150 2FA Code
151 <?php echo wp_kses($tooltip_html, $allowed_tooltip_html); ?>
152 </label>
153 <input type="text" required name="twofa_code" id="twofa-code" class="input" value="" maxlength="6" minlength="6" inputmode="numeric" pattern="[0-9]*" autocomplete="one-time-code">
154 <span id="twofa-destination" role="status" aria-live="polite"></span>
155 <button type="button" id="twofa-resend" class="button-link">Send a new code</button>
156 <span id="twofa-resend-status" role="status" aria-live="polite"></span>
157 </p>
158 </template>
159 <?php
160 }
161 }
162 endif;
163