PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
← All changes | src/view/two-fa/otp.php +412 -345 3.1.0 → 6.3.0 View file →
@@ -1,241 +1,254 @@
1 1 <?php
2 -if ( ! function_exists( 'login_header_otp' ) ) {
3 -//copy from wp-login
4 2 /**
5 - * Output the login page header.
3 + * This template is used to display 2FA OTP field.
6 4 *
7 - * @param string $title Optional. WordPress login Page title to display in the `<title>` element.
8 - * Default 'Log In'.
9 - * @param string $message Optional. Message to display in header. Default empty.
10 - * @param WP_Error $wp_error Optional. The error to pass. Default empty.
5 + * @package WP_Defender
11 6 */
12 -function login_header_otp( $title = 'Log In', $message = '', $wp_error = '' ) {
13 -global $error, $interim_login, $action;
14 7
15 -if ( empty( $wp_error ) ) {
16 - $wp_error = new \WP_Error();
17 -}
8 +if ( ! function_exists( 'login_header_otp' ) ) {
9 + // Copy from wp-login.php.
10 + /**
11 + * Output the login page header.
12 + *
13 + * @param string $title Optional. WordPress login Page title to display in the `<title>` element. Default 'Log In'.
14 + * @param string $message Optional. Message to display in header. Default empty.
15 + * @param bool $show_logo Optional. Show/hide header logo. Default true.
16 + * @param WP_Error $wp_error Optional. The error to pass. Default empty.
17 + */
18 + function login_header_otp( $title = 'Log In', $message = '', $show_logo = true, $wp_error = '' ) {
19 + global $error, $interim_login, $action;
18 20
19 -// Shake it!
20 -$shake_error_codes = array(
21 - 'empty_password',
22 - 'empty_email',
23 - 'invalid_email',
24 - 'invalidcombo',
25 - 'empty_username',
26 - 'invalid_username',
27 - 'incorrect_password',
28 -);
29 -/**
30 - * Filters the error codes array for shaking the login form.
31 - *
32 - * @param array $shake_error_codes Error codes that shake the login form.
33 - *
34 - * @since 3.0.0
35 - *
36 - */
37 -$shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
21 + if ( ! ( $wp_error instanceof WP_Error ) ) {
22 + $wp_error = new WP_Error();
23 + }
38 24
39 -if ( $shake_error_codes && $wp_error->get_error_code() && in_array( $wp_error->get_error_code(),
40 - $shake_error_codes ) ) {
41 - add_action( 'login_head', 'wp_shake_js', 12 );
42 -}
25 + // Shake it!
26 + $shake_error_codes = array(
27 + 'empty_password',
28 + 'empty_email',
29 + 'invalid_email',
30 + 'invalidcombo',
31 + 'empty_username',
32 + 'invalid_username',
33 + 'incorrect_password',
34 + );
35 + /**
36 + * Filters the error codes array for shaking the login form.
37 + *
38 + * @param array $shake_error_codes Error codes that shake the login form.
39 + *
40 + * @since 3.0.0
41 + */
42 + $shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
43 + if ( $shake_error_codes && $wp_error->get_error_code() && in_array(
44 + $wp_error->get_error_code(),
45 + $shake_error_codes,
46 + true
47 + ) ) {
48 + add_action( 'login_head', 'wp_shake_js', 12 );
49 + }
43 50
44 -$separator = is_rtl() ? ' &rsaquo; ' : ' &lsaquo; ';
51 + $separator = is_rtl() ? ' &rsaquo; ' : ' &lsaquo; ';
45 52
46 -?><!DOCTYPE html>
53 + ?><!DOCTYPE html>
47 54 <!--[if IE 8]>
48 -<html xmlns="http://www.w3.org/1999/xhtml" class="ie8" <?php
49 -language_attributes(); ?>>
55 +<html xmlns="http://www.w3.org/1999/xhtml" class="ie8"
56 + <?php
57 + language_attributes();
58 + ?>
59 +>
50 60 <![endif]-->
51 61 <!--[if !(IE 8) ]><!-->
52 62 <html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
53 63 <!--<![endif]-->
64 +
54 65 <head>
55 - <meta http-equiv="Content-Type"
56 - content="<?php
57 - bloginfo( 'html_type' ); ?>; charset=<?php
58 - bloginfo( 'charset' ); ?>"/>
59 - <meta name="viewport" content="width=device-width">
60 - <title><?php
61 - echo get_bloginfo( 'name', 'display' ) . $separator . $title; ?></title>
62 - <?php
66 + <meta http-equiv="Content-Type"
67 + content="<?php bloginfo( 'html_type' ); ?>; charset=<?php bloginfo( 'charset' ); ?>"/>
68 + <meta name="viewport" content="width=device-width">
69 + <title>
70 + <?php
71 + printf( '%s%s%s', esc_attr( get_bloginfo( 'name', 'display' ) ), esc_attr( $separator ), esc_attr( $title ) );
72 + ?>
73 + </title>
74 + <?php
63 75
64 - wp_enqueue_style( 'login' );
76 + wp_enqueue_style( 'login' );
65 77
66 - /*
67 - * Remove all stored post data on logging out.
68 - * This could be added by add_action('login_head'...) like wp_shake_js(),
69 - * but maybe better if it's not removable by plugins.
70 - */
71 - if ( 'loggedout' == $wp_error->get_error_code() ) {
72 - ?>
73 - <script>if ("sessionStorage" in window) {
74 - try {
75 - for (var key in sessionStorage) {
76 - if (key.indexOf("wp-autosave-") != -1) {
77 - sessionStorage.removeItem(key)
78 - }
79 - }
80 - } catch (e) {
81 - }
82 - }
83 - ;</script>
84 - <?php
85 - }
78 + /*
79 + * Remove all stored post data on logging out.
80 + * This could be added by add_action('login_head'...) like wp_shake_js(),
81 + * but maybe better if it's not removable by plugins.
82 + */
83 + if ( 'loggedout' === $wp_error->get_error_code() ) {
84 + ?>
85 + <script>if ("sessionStorage" in window) {
86 + try {
87 + for (var key in sessionStorage) {
88 + if (key.indexOf("wp-autosave-") != -1) {
89 + sessionStorage.removeItem(key)
90 + }
91 + }
92 + } catch (e) {
93 + }
94 + }
95 + </script>
96 + <?php
97 + }
86 98
87 - /**
88 - * Enqueue scripts and styles for the login page.
89 - *
90 - * @since 3.1.0
91 - */
92 - do_action( 'login_enqueue_scripts' );
99 + /**
100 + * Enqueue scripts and styles for the login page.
101 + *
102 + * @since 3.1.0
103 + */
104 + do_action( 'login_enqueue_scripts' );
93 105
94 - /**
95 - * Fires in the login page header after scripts are enqueued.
96 - *
97 - * @since 2.1.0
98 - */
99 - do_action( 'login_head' );
106 + /**
107 + * Fires in the login page header after scripts are enqueued.
108 + *
109 + * @since 2.1.0
110 + */
111 + do_action( 'login_head' );
100 112
101 - if ( is_multisite() ) {
102 - $login_header_url = network_home_url();
103 - $login_header_title = get_network()->site_name;
104 - } else {
105 - $login_header_url = __( 'https://wordpress.org/' );
106 - $login_header_title = __( 'Powered by WordPress' );
107 - }
113 + if ( is_multisite() ) {
114 + $login_header_url = network_home_url();
115 + $login_header_title = get_network()->site_name;
116 + } else {
117 + $login_header_url = 'https://wordpress.org/';
118 + $login_header_title = esc_html__( 'Powered by WordPress', 'defender-security' );
119 + }
108 120
109 - /**
110 - * Filters link URL of the header logo above login form.
111 - *
112 - * @param string $login_header_url Login header logo URL.
113 - *
114 - * @since 2.1.0
115 - *
116 - */
117 - $login_header_url = apply_filters( 'login_headerurl', $login_header_url );
121 + /**
122 + * Filters link URL of the header logo above login form.
123 + *
124 + * @param string $login_header_url Login header logo URL.
125 + *
126 + * @since 2.1.0
127 + */
128 + $login_header_url = apply_filters( 'login_headerurl', $login_header_url );
118 129
119 - /**
120 - * Filters the title attribute of the header logo above login form.
121 - *
122 - * @param string $login_header_title Login header logo title attribute.
123 - *
124 - * @since 2.1.0
125 - */
126 - $login_header_title = apply_filters( 'login_headertitle', $login_header_title );
130 + /**
131 + * Filters the title attribute of the header logo above login form.
132 + *
133 + * @param string $login_header_title Login header logo title attribute.
134 + *
135 + * @since 2.1.0
136 + */
137 + $login_header_title = apply_filters( 'login_headertitle', $login_header_title );
127 138
128 - $classes = array( 'login-action-' . $action, 'wp-core-ui' );
129 - if ( is_rtl() ) {
130 - $classes[] = 'rtl';
131 - }
132 - if ( $interim_login ) {
133 - $classes[] = 'interim-login';
134 - ?>
135 - <style type="text/css">html {
136 - background-color: transparent;
137 - }</style>
138 - <?php
139 + $classes = array( 'login-action-' . $action, 'wp-core-ui' );
140 + if ( is_rtl() ) {
141 + $classes[] = 'rtl';
142 + }
143 + if ( $interim_login ) {
144 + $classes[] = 'interim-login';
145 + ?>
146 + <style type="text/css">
147 + html {
148 + background-color: transparent;
149 + }
150 + </style>
151 + <?php
139 152
140 - if ( 'success' === $interim_login ) {
141 - $classes[] = 'interim-login-success';
153 + if ( 'success' === $interim_login ) {
154 + $classes[] = 'interim-login-success';
155 + }
142 156 }
143 - }
144 - $classes[] = ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
157 + $classes[] = ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
145 158
146 - /**
147 - * Filters the login page body classes.
148 - *
149 - * @param array $classes An array of body classes.
150 - * @param string $action The action that brought the visitor to the login page.
151 - *
152 - * @since 3.5.0
153 - */
154 - $classes = apply_filters( 'login_body_class', $classes, $action );
159 + /**
160 + * Filters the login page body classes.
161 + *
162 + * @param array $classes An array of body classes.
163 + * @param string $action The action that brought the visitor to the login page.
164 + *
165 + * @since 3.5.0
166 + */
167 + $classes = apply_filters( 'login_body_class', $classes, $action );
155 168
156 - ?>
169 + ?>
157 170 </head>
158 -<body class="login <?php
159 -echo esc_attr( implode( ' ', $classes ) ); ?>">
160 -<?php
161 -/**
162 - * Fires in the login page header after the body tag is opened.
163 - *
164 - * @since 4.6.0
165 - */
166 -do_action( 'login_header' );
167 -?>
171 +
172 +<body class="login <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
173 + <?php
174 + /**
175 + * Fires in the login page header after the body tag is opened.
176 + *
177 + * @since 4.6.0
178 + */
179 + do_action( 'login_header' );
180 + ?>
168 181 <div id="login">
182 + <?php if ( true === $show_logo ) { ?>
183 + <h1>
184 + <a id="otp-logo" href="<?php echo esc_url( $login_header_url ); ?>"
185 + title="<?php echo esc_attr( $login_header_title ); ?>" tabindex="-1"><?php bloginfo( 'name' ); ?></a>
186 + </h1>
187 + <div id="notification"></div>
188 + <?php
189 + }
190 + unset( $login_header_url, $login_header_title );
191 + /**
192 + * Filters the message to display above the login form.
193 + *
194 + * @param string $message Login message text.
195 + *
196 + * @since 2.1.0
197 + */
198 + $message = apply_filters( 'login_message', $message );
199 + if ( is_string( $message ) && '' !== trim( $message ) ) {
200 + echo wp_kses_post( $message );
201 + }
169 202
170 - <h1><a id="otp-logo" href="<?php
171 - echo esc_url( $login_header_url ); ?>" title="<?php
172 - echo esc_attr( $login_header_title ); ?>"
173 - tabindex="-1"><?php
174 - bloginfo( 'name' ); ?></a></h1>
175 - <?php
176 - unset( $login_header_url, $login_header_title );
177 - /**
178 - * Filters the message to display above the login form.
179 - *
180 - * @param string $message Login message text.
181 - *
182 - * @since 2.1.0
183 - */
184 - $message = apply_filters( 'login_message', $message );
185 - if ( ! empty( $message ) ) {
186 - echo $message . "\n";
187 - }
203 + // In case a plugin uses $error rather than the $wp_errors object.
204 + if ( $error instanceof WP_Error ) {
205 + $wp_error->add( 'error', $error );
206 + unset( $error );
207 + }
188 208
189 - // In case a plugin uses $error rather than the $wp_errors object
190 - if ( ! empty( $error ) ) {
191 - $wp_error->add( 'error', $error );
192 - unset( $error );
193 - }
194 -
195 - if ( $wp_error->get_error_code() ) {
196 - $errors = '';
197 - $messages = '';
198 - foreach ( $wp_error->get_error_codes() as $code ) {
199 - $severity = $wp_error->get_error_data( $code );
200 - foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
201 - if ( 'message' == $severity ) {
202 - $messages .= ' ' . $error_message . "<br />\n";
203 - } else {
204 - $errors .= ' ' . $error_message . "<br />\n";
209 + if ( $wp_error->get_error_code() ) {
210 + $errors = '';
211 + $messages = '';
212 + foreach ( $wp_error->get_error_codes() as $code ) {
213 + $severity = $wp_error->get_error_data( $code );
214 + foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
215 + if ( 'message' === $severity ) {
216 + $messages .= ' ' . $error_message . "<br />\n";
217 + } else {
218 + $errors .= ' ' . $error_message . "<br />\n";
219 + }
205 220 }
206 221 }
222 + if ( '' !== $errors ) {
223 + /**
224 + * Filters the error messages displayed above the login form.
225 + *
226 + * @param string $errors Login error message.
227 + *
228 + * @since 2.1.0
229 + */
230 + echo wp_kses_post( sprintf( '<div id="login_error" class="notice notice-error">%s</div>', apply_filters( 'login_errors', $errors ) ) );
231 + }
232 + if ( '' !== $messages ) {
233 + /**
234 + * Filters instructional messages displayed above the login form.
235 + *
236 + * @param string $messages Login messages.
237 + *
238 + * @since 2.5.0
239 + */
240 + echo wp_kses_post( sprintf( '<p class="message">%s</p>', apply_filters( 'login_messages', $messages ) ) );
241 + }
207 242 }
208 - if ( ! empty( $errors ) ) {
209 - /**
210 - * Filters the error messages displayed above the login form.
211 - *
212 - * @param string $errors Login error message.
213 - *
214 - * @since 2.1.0
215 - *
216 - */
217 - echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";
218 - }
219 - if ( ! empty( $messages ) ) {
220 - /**
221 - * Filters instructional messages displayed above the login form.
222 - *
223 - * @param string $messages Login messages.
224 - *
225 - * @since 2.5.0
226 - *
227 - */
228 - echo '<p class="message">' . apply_filters( 'login_messages', $messages ) . "</p>\n";
229 - }
230 243 }
231 244 }
232 -}
233 245
246 +$show_logo = WP_Defender\Model\Setting\Two_Fa::CUSTOM_GRAPHIC_TYPE_NO !== $custom_graphic_type;
234 247 if ( isset( $interim_login ) && 'success' === $interim_login ) {
235 - login_header_otp( '', $message );
248 + login_header_otp( '', $message, $show_logo );
236 249
237 - $modal_close_script = <<<END
250 + $modal_close_script = <<<'END'
238 251 <script>
239 252 jQuery(function ($) {
240 253 $('.wp-auth-check-close', window.parent.document).trigger('click');
241 254 });
@@ -243,187 +256,241 @@
243 256 END;
244 257
245 258 add_action(
246 259 'wp_print_footer_scripts',
247 - function() use ( $modal_close_script ) {
248 - echo $modal_close_script;
260 + function () use ( $modal_close_script ) {
261 + /**
262 + * Ignore WordPress.Security.EscapeOutput.OutputNotEscaped
263 + * Why?
264 + * We don't want to escape scripts here.
265 + */
266 + echo $modal_close_script; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
249 267 }
250 268 );
251 269 } else {
252 - login_header_otp( '', '', $error );
270 + login_header_otp( '', '', $show_logo, $error );
253 271
254 - if ( ! empty( $providers ) ) {
255 - foreach ( $providers as $slug => $provider ) { ?>
256 - <form method="post" class="wpdef-2fa-form" id="wpdef-2fa-form-<?php esc_attr_e( $slug ); ?>"
257 - action="<?php
258 - echo esc_url( add_query_arg( 'action', 'defender-verify-otp', site_url( 'wp-login.php', 'login_post' ) ) );
259 - ?>">
272 + if ( is_array( $providers ) && array() !== $providers ) {
273 + $nonce = wp_create_nonce( 'verify_otp' );
274 + foreach ( $providers as $slug => $provider ) {
275 + ?>
276 + <form method="post" class="wpdef-2fa-form" id="wpdef-2fa-form-<?php echo esc_attr( $slug ); ?>" action="
277 + <?php
278 + echo esc_url(
279 + add_query_arg(
280 + 'action',
281 + 'defender-verify-otp',
282 + site_url( 'wp-login.php', 'login_post' )
283 + )
284 + );
285 + ?>
286 + ">
260 287
261 288 <?php $provider->authentication_form(); ?>
262 289
263 - <input type="hidden" name="auth_method" value="<?php echo esc_attr( $slug ); ?>"/>
264 - <input type="hidden" name="login_token" value="<?php echo esc_attr( $token ); ?>"/>
265 - <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>"/>
266 - <input type="hidden" name="password" value="<?php echo esc_attr( $password ); ?>"/>
290 + <input type="hidden" name="auth_method" value="<?php echo esc_attr( $slug ); ?>"/>
291 + <input type="hidden" name="login_token" value="<?php echo esc_attr( $token ); ?>"/>
292 + <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>"/>
293 + <input type="hidden" name="password" value="<?php echo esc_attr( $password ); ?>"/>
294 + <input type="hidden" name="requested_user" value="<?php echo esc_attr( $user_id ); ?>"/>
295 + <input type="hidden" id="_wpnonce_<?php echo esc_attr( $slug ); ?>" name="_wpnonce" value="<?php echo esc_attr( $nonce ); ?>" />
267 296 <?php
268 - if ( isset( $_REQUEST['interim-login'] ) ) { ?>
269 - <input type="hidden" name="interim-login" value="1" />
297 + if ( '1' === defender_get_data_from_request( 'interim-login', 'r' ) ) {
298 + ?>
299 + <input type="hidden" name="interim-login" value="1"/>
270 300 <?php
271 301 }
272 - wp_nonce_field( 'verify_otp' ); ?>
273 - </form>
274 - <?php }
275 - if ( (is_array($providers) || $providers instanceof \Countable ? count( $providers ) : 0) > 1 ) { ?>
276 - <div id="wrap-nav">
277 - <p><?php _e('Having problems? Try another way to log in', 'wpdef' ); ?></p>
278 - <ul id="nav">
279 - <?php foreach ( $providers as $slug => $provider ) { ?>
280 - <li class="wpdef-2fa-link" id="wpdef-2fa-link-<?php esc_attr_e( $slug ); ?>"
281 - data-slug="<?php esc_attr_e( $slug ); ?>">
302 + ?>
303 + </form>
304 + <?php
305 + }
306 + if ( ( is_array( $providers ) || $providers instanceof Countable ? count( $providers ) : 0 ) > 1 ) {
307 + ?>
308 + <div id="wrap-nav">
309 + <p><?php esc_attr_e( 'Having problems? Try another way to log in', 'defender-security' ); ?></p>
310 + <ul id="nav">
311 + <?php foreach ( $providers as $slug => $provider ) { ?>
312 + <li class="wpdef-2fa-link" id="wpdef-2fa-link-<?php echo esc_attr( $slug ); ?>"
313 + data-slug="<?php echo esc_attr( $slug ); ?>">
314 + <!-- The label value is escaped on backend. It's safe. -->
315 + <?php echo $provider->get_login_label(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
282 316
283 - <?php echo $provider->get_login_label(); ?>
284 -
285 - </li>
286 - <?php } ?>
287 - </ul>
288 - <img class="def-ajaxloader" src="<?php echo defender_asset_url( '/assets/img/spinner.svg' ); ?>"/>
289 - </div>
317 + </li>
318 + <?php } ?>
319 + </ul>
320 + </div>
321 + <?php } ?>
290 322 <?php } ?>
291 - <p class="notification"></p>
292 - <?php } ?>
293 - <?php if ( $custom_graphic ) { ?>
294 - <style type="text/css">
295 - body.login div#login h1 a {
296 - background-image: url("<?php echo $custom_graphic ?>");
297 - }
298 - </style>
299 - <?php } ?>
300 - <?php
323 + <?php
324 + if ( $custom_graphic ) {
325 + ?>
326 + <style type="text/css">
327 + body.login div#login h1 a {
328 + background-image: url("<?php echo esc_url_raw( $custom_graphic ); ?>");
329 + }
330 + </style>
331 + <?php
332 + }
301 333 $totp_script = <<<END
302 334 <script>
303 335 jQuery(function ($) {
304 - function two_factor_providers( defaultSlug ) {
305 - // Hide all forms and show the one default.
306 - $('.wpdef-2fa-form').hide();
307 - $('#wpdef-2fa-form-' + defaultSlug).show();
308 - // Hide all links and show others except the default.
309 - if ( $('.wpdef-2fa-link').length > 0 ) {
310 - $('.wpdef-2fa-link').hide();
311 - $('.wpdef-2fa-link:not(#wpdef-2fa-link-'+ defaultSlug +')').each(function(){
312 - $(this).show();
313 - });
314 - }
315 - }
316 - var is_sent = false;
317 - // Logic for FallbackEmail method.
318 - function resend_code() {
319 - // Work with the button 'Resen Code'.
320 - var that = $('input[name="button_resend_code"]');
321 - if (is_sent === false) {
322 - is_sent = true;
323 - }
324 - let data = {
325 - data: JSON.stringify({
326 - 'token': '{$token}'
327 - })
328 - };
329 - $.ajax({
330 - type: 'POST',
331 - url: '{$action_fallback_email}',
332 - data: data,
333 - beforeSend: function () {
334 - that.attr('disabled', 'disabled');
335 - $('.def-ajaxloader').show();
336 - },
337 - success: function (data) {
338 - that.removeAttr('disabled');
339 - $('.def-ajaxloader').hide();
340 - $('.notification').text(data.data.message);
341 - is_sent = false;
342 - }
343 - })
344 - }
336 + function two_factor_providers(defaultSlug) {
337 + // Hide all forms and show the one default.
338 + $('.wpdef-2fa-form').hide();
339 + $('#wpdef-2fa-form-' + defaultSlug).show();
340 + // Hide all links and show others except the default.
341 + if ($('.wpdef-2fa-link').length > 0) {
342 + $('.wpdef-2fa-link').hide();
343 + $('.wpdef-2fa-link:not(#wpdef-2fa-link-' + defaultSlug + ')').each(function () {
344 + $(this).show();
345 + });
346 + }
347 + // Focus on the current input-field.
348 + if ($('#wpdef-2fa-form-' + defaultSlug).find('[name="otp"]').length > 0) {
349 + $('#wpdef-2fa-form-' + defaultSlug).find('[name="otp"]').trigger('focus');
350 + }
351 + }
345 352
346 - $('.def-ajaxloader').hide();
347 - // Hide all forms and show the one default.
348 - var defaultSlug = '{$default_slug}';
349 - two_factor_providers( defaultSlug );
350 - // Work with links.
351 - $('body').on('click', '.wpdef-2fa-link', function () {
352 - $('#login_error').remove();
353 - // Clear any previous notification.
354 - $('.notification').empty();
355 - var slug = $(this).data('slug');
356 - two_factor_providers( slug );
357 - // Switch to 'Fallback Email' method.
358 - if ('fallback-email' === slug) {
359 - resend_code();
360 - }
361 - });
362 - // Resend code.
363 - $('body').on('click', 'input[name="button_resend_code"]', function (e) {
364 - e.preventDefault();
365 - resend_code();
366 - })
367 - })
353 + var is_sent = false;
354 + // Logic for FallbackEmail method.
355 + function resend_code() {
356 + // Work with the button 'Resend Code'.
357 + var that = $('#wd-2fa-resend-code');
358 + if (is_sent === false) {
359 + is_sent = true;
360 + }
361 + let data = {
362 + data: JSON.stringify({
363 + 'token': '{$token}',
364 + 'requested_user': '{$user_id}'
365 + })
366 + };
367 + $.ajax({
368 + type: 'POST',
369 + url: '{$action_fallback_email}',
370 + data: data,
371 + beforeSend: function () {
372 + that.prop('disabled', true);
373 + $('.def-ajaxloader').show();
374 + },
375 + success: function (data) {
376 + that.prop('disabled', false);
377 + $('.def-ajaxloader').hide();
378 + $('#notification').removeClass().addClass('notice notice-success').text(data.data.message).show();
379 + is_sent = false;
380 + }
381 + });
382 + }
383 +
384 + $('.def-ajaxloader').hide();
385 + // Hide all forms and show the one default.
386 + var defaultSlug = '{$default_slug}';
387 + if (!defaultSlug && 0 < $('form.wpdef-2fa-form').first().length) {
388 + var twoFaFormId = $('form.wpdef-2fa-form').first().attr('id');
389 + defaultSlug = twoFaFormId.replace('wpdef-2fa-form-', '');
390 + if ('fallback-email' === defaultSlug) {
391 + resend_code();
392 + } else {
393 + $('#notification').hide();
394 + }
395 + }
396 + two_factor_providers(defaultSlug);
397 + // Work with links.
398 + $('body').on('click', '.wpdef-2fa-link', function () {
399 + $('#login_error').remove();
400 + // Clear any previous notification.
401 + var slug = $(this).data('slug');
402 + two_factor_providers(slug);
403 + // Switch to 'Fallback Email' method.
404 + if ('fallback-email' === slug) {
405 + resend_code();
406 + } else {
407 + $('#notification').hide();
408 + }
409 + });
410 + // Resend code.
411 + $('body').on('click', '#wd-2fa-resend-code', function (e) {
412 + e.preventDefault();
413 + resend_code();
414 + });
415 + });
368 416 </script>
369 417 END;
370 418 add_action(
371 419 'wp_print_footer_scripts',
372 - function() use ( $totp_script ) {
373 - echo $totp_script;
420 + function () use ( $totp_script ) {
421 + /**
422 + * Ignore WordPress.Security.EscapeOutput.OutputNotEscaped
423 + * Why?
424 + * We don't want to escape scripts here.
425 + */
426 + echo $totp_script; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
374 427 }
375 428 );
376 429 ?>
377 - <?php
430 + <?php
378 431 }
379 432 ?>
380 433
381 434 <?php
382 435 if ( ! function_exists( 'login_footer' ) ) {
383 - /**
384 - * Outputs the footer for the login page.
385 - *
386 - * @param string $input_id Which input to auto-focus
387 - */
388 - function login_footer( $input_id = '' ) {
389 - global $interim_login;
436 + /**
437 + * Outputs the footer for the login page.
438 + *
439 + * @param string $input_id Which input to auto-focus.
440 + */
441 + function login_footer( $input_id = '' ) {
442 + global $interim_login;
390 443
391 - // Don't allow interim logins to navigate away from the page.
392 - if ( ! $interim_login ): ?>
393 - <p id="backtoblog"><a href="<?php
394 - echo esc_url( home_url( '/' ) ); ?>"><?php
395 - /* translators: %s: site title */
396 - printf( _x( '&larr; Back to %s', 'site' ), get_bloginfo( 'title', 'display' ) );
397 - ?></a></p>
398 - <?php
399 - endif; ?>
444 + // Don't allow interim logins to navigate away from the page.
445 + if ( ! $interim_login ) :
446 + ?>
447 + <p id="backtoblog"><a href="
448 + <?php
449 + echo esc_url( home_url( '/' ) );
450 + ?>
451 + ">
452 + <?php
453 + printf(
454 + /* translators: %s: site title */
455 + esc_html_x( '&larr; Back to %s', 'site', 'defender-security' ),
456 + esc_html( get_bloginfo( 'title', 'display' ) )
457 + );
458 + ?>
459 + </a></p>
460 + <?php
461 + endif;
462 + ?>
400 463
401 464 </div>
402 465
403 -<?php
404 -if ( ! empty( $input_id ) ) : ?>
405 - <script type="text/javascript">
406 - try {
407 - document.getElementById('<?php echo $input_id; ?>').focus();
408 - } catch (e) {
409 - }
410 - if (typeof wpOnload == 'function') wpOnload();
411 - </script>
412 -<?php
413 -endif; ?>
466 + <?php
467 + if ( '' !== trim( $input_id ) ) :
468 + ?>
469 + <script type="text/javascript">
470 + try {
471 + document.getElementById('<?php echo esc_js( $input_id ); ?>').focus();
472 + } catch (e) {
473 + }
474 + if (typeof wpOnload == 'function') wpOnload();
475 + </script>
476 + <?php
477 + endif;
478 + ?>
414 479
415 -<?php
416 -/**
417 - * Fires in the login page footer.
418 - *
419 - * @since 3.1.0
420 - */
421 -do_action( 'login_footer' ); ?>
480 + <?php
481 + /**
482 + * Fires in the login page footer.
483 + *
484 + * @since 3.1.0
485 + */
486 + do_action( 'login_footer' );
487 + ?>
422 488 <div class="clear"></div>
423 489 </body>
490 +
424 491 </html>
425 -<?php
426 -}
427 -}
428 -login_footer();
429 -?>
492 + <?php
493 + }
494 + }
495 + login_footer();
496 + ?>