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
defender-security / src / view / two-fa / otp.php

otp.php in Defender Security – Malware Scanner, Login Security & Firewall 6.3.0, at src/view/two-fa/otp.php

497 lines 13.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This template is used to display 2FA OTP field.
4 *
5 * @package WP_Defender
6 */
7
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;
20
21 if ( ! ( $wp_error instanceof WP_Error ) ) {
22 $wp_error = new WP_Error();
23 }
24
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 }
50
51 $separator = is_rtl() ? ' &rsaquo; ' : ' &lsaquo; ';
52
53 ?><!DOCTYPE html>
54 <!--[if IE 8]>
55 <html xmlns="http://www.w3.org/1999/xhtml" class="ie8"
56 <?php
57 language_attributes();
58 ?>
59 >
60 <![endif]-->
61 <!--[if !(IE 8) ]><!-->
62 <html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
63 <!--<![endif]-->
64
65 <head>
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
75
76 wp_enqueue_style( 'login' );
77
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 }
98
99 /**
100 * Enqueue scripts and styles for the login page.
101 *
102 * @since 3.1.0
103 */
104 do_action( 'login_enqueue_scripts' );
105
106 /**
107 * Fires in the login page header after scripts are enqueued.
108 *
109 * @since 2.1.0
110 */
111 do_action( 'login_head' );
112
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 }
120
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 );
129
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 );
138
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
152
153 if ( 'success' === $interim_login ) {
154 $classes[] = 'interim-login-success';
155 }
156 }
157 $classes[] = ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
158
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 );
168
169 ?>
170 </head>
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 ?>
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 }
202
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 }
208
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 }
220 }
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 }
242 }
243 }
244 }
245
246 $show_logo = WP_Defender\Model\Setting\Two_Fa::CUSTOM_GRAPHIC_TYPE_NO !== $custom_graphic_type;
247 if ( isset( $interim_login ) && 'success' === $interim_login ) {
248 login_header_otp( '', $message, $show_logo );
249
250 $modal_close_script = <<<'END'
251 <script>
252 jQuery(function ($) {
253 $('.wp-auth-check-close', window.parent.document).trigger('click');
254 });
255 </script>
256 END;
257
258 add_action(
259 'wp_print_footer_scripts',
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
267 }
268 );
269 } else {
270 login_header_otp( '', '', $show_logo, $error );
271
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 ">
287
288 <?php $provider->authentication_form(); ?>
289
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 ); ?>" />
296 <?php
297 if ( '1' === defender_get_data_from_request( 'interim-login', 'r' ) ) {
298 ?>
299 <input type="hidden" name="interim-login" value="1"/>
300 <?php
301 }
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 ?>
316
317 </li>
318 <?php } ?>
319 </ul>
320 </div>
321 <?php } ?>
322 <?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 }
333 $totp_script = <<<END
334 <script>
335 jQuery(function ($) {
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 }
352
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 });
416 </script>
417 END;
418 add_action(
419 'wp_print_footer_scripts',
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
427 }
428 );
429 ?>
430 <?php
431 }
432 ?>
433
434 <?php
435 if ( ! function_exists( 'login_footer' ) ) {
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;
443
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 ?>
463
464 </div>
465
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 ?>
479
480 <?php
481 /**
482 * Fires in the login page footer.
483 *
484 * @since 3.1.0
485 */
486 do_action( 'login_footer' );
487 ?>
488 <div class="clear"></div>
489 </body>
490
491 </html>
492 <?php
493 }
494 }
495 login_footer();
496 ?>
497