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/controller/class-mask-login.php +108 -58 5.5.1 → 6.3.0 View file →
@@ -57,9 +57,8 @@
57 57 /**
58 58 * Initializes the model and service, registers routes, and sets up scheduled events if the model is active.
59 59 */
60 60 public function __construct() {
61 - add_filter( 'wp_defender_advanced_tools_data', array( $this, 'script_data' ) );
62 61 // Internal cache, so we don't need to query many times.
63 62 $this->model = wd_di()->get( Model_Mask_Login::class );
64 63 $this->service = wd_di()->get( Component_Mask_Login::class );
65 64 $this->register_routes();
@@ -174,14 +173,10 @@
174 173 * @return void
175 174 * @since 2.8.0
176 175 */
177 176 public function before_mask_login_handle(): void {
178 - // Some plugins for Cron actions clear HTTP_HOST-param.
179 - $host = defender_get_data_from_request( 'HTTP_HOST', 's' );
180 - if ( ! isset( $host['HTTP_HOST'] ) ) {
181 - $host = '';
182 - }
183 - $current_url = set_url_scheme( 'http://' . $host . defender_get_data_from_request( 'REQUEST_URI', 's' ) );
177 + $request_uri = (string) defender_get_data_from_request( 'REQUEST_URI', 's' );
178 + $current_url = home_url( $request_uri );
184 179 $login_url = $this->get_model()->get_new_login_url( $this->get_site_url() );
185 180
186 181 if (
187 182 ! is_user_logged_in() &&
@@ -215,8 +210,11 @@
215 210 // Make sure that wp-login.php is never used in site URLs or redirects.
216 211 if ( ! $this->service->is_login_url() ) {
217 212 $redirect_path = trim( (string) wp_parse_url( $location, PHP_URL_PATH ), '/' );
218 213 if ( $redirect_path === $this->get_model()->mask_url ) {
214 + if ( $this->is_recipient_email_action() ) {
215 + return $location;
216 + }
219 217 $this->maybe_lock();
220 218 }
221 219 }
222 220
@@ -241,9 +239,9 @@
241 239 // Need to check if the current request is for signup, login.
242 240 // If it is not the slug, then we redirect to the 404 redirect, or 403 wp die.
243 241 $requested_path = $this->service->get_request_path();
244 242 $requested_path_without_slash = ltrim( $requested_path, '/' );
245 - if ( ! $requested_path_without_slash && ! empty( get_option( 'permalink_structure' ) ) ) {
243 + if ( ! $requested_path_without_slash && '' !== get_option( 'permalink_structure', '' ) ) {
246 244 return;
247 245 } else {
248 246 $params = wp_parse_args( defender_get_data_from_request( 'QUERY_STRING', 's' ), array() );
249 247 if ( isset( $params[ $this->model->mask_url ] ) ) {
@@ -252,9 +250,10 @@
252 250 }
253 251
254 252 if ( '/' . ltrim( $this->get_model()->mask_url, '/' ) === $requested_path ) {
255 253 // We need to redirect this one to wp-login and open it.
256 - return $this->show_login_page();
254 + $this->show_login_page();
255 + return;
257 256 }
258 257 /**
259 258 * Allowed if:
260 259 * it's AJAX,
@@ -292,9 +291,10 @@
292 291 }
293 292
294 293 // If current is same then we show the login screen.
295 294 if ( $this->service->is_land_on_masked_url( $this->model->mask_url ) ) {
296 - return $this->show_login_page();
295 + $this->show_login_page();
296 + return;
297 297 }
298 298
299 299 // If it's the verification link to change Network Admin Email.
300 300 $is_multisite = is_multisite();
@@ -320,9 +320,10 @@
320 320 ( ! $is_multisite && 'wp-signup.php' === $requested_path_without_slash )
321 321 || $this->service->is_on_login_page( $requested_path_without_slash )
322 322 ) {
323 323 // If they are here and the flow getting here, then just lock.
324 - return $this->maybe_lock();
324 + $this->maybe_lock();
325 + return;
325 326 }
326 327 }
327 328
328 329 /**
@@ -350,10 +351,10 @@
350 351 $this->data_frontend()
351 352 )
352 353 );
353 354 }
354 - $data_frontend = $this->data_frontend();
355 - $result['message'] = $this->model->get_formatted_errors();
355 + $data_frontend = $this->data_frontend();
356 + $result = array( 'message' => $this->model->get_formatted_errors() );
356 357 // Don't hide the error notice if the module is not activated.
357 358 if ( ! $data_frontend['is_active'] ) {
358 359 $result['auto_close'] = false;
359 360 }
@@ -451,9 +452,9 @@
451 452 $requested_path = $this->service->get_request_path( $current_url );
452 453 if ( '/wp-admin' === $requested_path ) {
453 454 $current_domain = defender_get_data_from_request( 'HTTP_HOST', 's' );
454 455 $sub_domain = wp_parse_url( $current_url, PHP_URL_HOST );
455 - if ( ! empty( $sub_domain ) && false === stripos( $sub_domain, $current_domain ) ) {
456 + if ( is_string( $sub_domain ) && '' !== trim( $sub_domain ) && false === stripos( $sub_domain, $current_domain ) ) {
456 457 return $this->get_model()->get_new_login_url( $sub_domain );
457 458 }
458 459 }
459 460 }
@@ -531,9 +532,9 @@
531 532 * Show the forbidden screen.
532 533 */
533 534 public function show_forbidden_screen(): void {
534 535 wp_die(
535 - esc_html__( 'This feature is forbidden temporarily for security reason. Try login again.', 'defender-security' ),
536 + esc_html__( 'This feature is temporarily forbidden for security reasons. Try logging in again.', 'defender-security' ),
536 537 esc_html__( 'Forbidden', 'defender-security' ),
537 538 array(
538 539 'response' => 403,
539 540 )
@@ -553,21 +554,8 @@
553 554 return new Model_Mask_Login();
554 555 }
555 556
556 557 /**
557 - * Provide data to the frontend via localized script.
558 - *
559 - * @param array $data Data collection is ready to passed.
560 - *
561 - * @return array Modified data array with added this controller data.
562 - */
563 - public function script_data( array $data ): array {
564 - $data['mask_login'] = $this->data_frontend();
565 -
566 - return $data;
567 - }
568 -
569 - /**
570 558 * Redirects the user to the admin URL if the given URL is the home URL.
571 559 *
572 560 * @param string $url The URL to be redirected.
573 561 * @param string $raw_url The raw URL.
@@ -595,9 +583,9 @@
595 583 *
596 584 * @return string The site URL with the specified parameters.
597 585 */
598 586 private function get_site_url( $blog_id = null, $path = '', $scheme = null ) {
599 - if ( empty( $blog_id ) || ! is_multisite() ) {
587 + if ( ! is_int( $blog_id ) || 0 === $blog_id || ! is_multisite() ) {
600 588 $url = get_option( 'siteurl' );
601 589 } else {
602 590 switch_to_blog( $blog_id );
603 591 $url = get_option( 'siteurl' );
@@ -857,24 +845,24 @@
857 845 * @return array An array of strings.
858 846 */
859 847 public function export_strings(): array {
860 848 return array(
861 - $this->get_model()->is_active() ? esc_html__( 'Active', 'defender-security' ) : esc_html__( 'Inactive', 'defender-security' ),
849 + \WP_Defender\Model\Setting\Mask_Login::get_module_name() . ' '
850 + . ( $this->get_model()->enabled ? esc_html__( 'active', 'defender-security' ) : esc_html__( 'inactive', 'defender-security' ) ),
862 851 );
863 852 }
864 853
865 854 /**
866 - * Generates configuration strings based on the provided configuration and
867 - * whether the product is a pro version.
855 + * Generates configuration strings based on the provided configuration.
868 856 *
869 857 * @param array $config Configuration data.
870 - * @param bool $is_pro Indicates if the product is a pro version.
871 858 *
872 859 * @return array Returns an array of configuration strings.
873 860 */
874 - public function config_strings( array $config, bool $is_pro ): array {
861 + public function config_strings( array $config ): array {
875 862 return array(
876 - $config['enabled'] ? esc_html__( 'Active', 'defender-security' ) : esc_html__( 'Inactive', 'defender-security' ),
863 + \WP_Defender\Model\Setting\Mask_Login::get_module_name() . ' '
864 + . ( $config['enabled'] ? esc_html__( 'active', 'defender-security' ) : esc_html__( 'inactive', 'defender-security' ) ),
877 865 );
878 866 }
879 867
880 868 /**
@@ -887,8 +875,12 @@
887 875 $action = defender_get_data_from_request( 'action', 'g' );
888 876 $key = wp_unslash( defender_get_data_from_request( 'key', 'r' ) );
889 877 $login = wp_unslash( defender_get_data_from_request( 'login', 'r' ) );
890 878 $wd_ml_token = defender_get_data_from_request( 'wd-ml-token', 'g' );
879 + $cookie_name = 'wd-rp-' . COOKIEHASH;
880 + $rp_path = defined( 'COOKIEPATH' ) ? COOKIEPATH : '/';
881 + $rp_domain = defined( 'COOKIE_DOMAIN' ) ? COOKIE_DOMAIN : '';
882 +
891 883 if (
892 884 isset( $action, $key, $login, $wd_ml_token )
893 885 && 'rp' === $action
894 886 && $login === $wd_ml_token
@@ -895,35 +887,59 @@
895 887 ) {
896 888
897 889 $user = check_password_reset_key( $key, $login );
898 890 if ( ! is_wp_error( $user ) ) {
899 - $value = sprintf( '%s:%s', $login, $key );
900 - set_site_transient( 'wd-rp-' . COOKIEHASH, $value, 2 * MINUTE_IN_SECONDS );
891 + $token = wp_generate_password( 20, false );
892 + $transient_key = 'wd-rp-' . COOKIEHASH . '_' . $token;
893 + $value = sprintf( '%s:%s', $login, $key );
894 +
895 + set_site_transient( $transient_key, $value, 2 * MINUTE_IN_SECONDS );
896 + setcookie( $cookie_name, $token, 0, $rp_path, $rp_domain, is_ssl(), true );
897 + $_COOKIE[ $cookie_name ] = $token;
898 +
901 899 wp_safe_redirect( remove_query_arg( array( 'key', 'login', 'wd-ml-token' ) ) );
902 900 exit;
903 901 }
904 902 }
905 - $value = get_site_transient( 'wd-rp-' . COOKIEHASH );
903 +
904 + $cookie_token = defender_get_data_from_request( $cookie_name, 'c' );
905 + if ( ! is_string( $cookie_token ) || '' === trim( $cookie_token ) ) {
906 + return;
907 + }
908 +
909 + $transient_key = 'wd-rp-' . COOKIEHASH . '_' . $cookie_token;
910 + $value = get_site_transient( $transient_key );
911 +
906 912 // Process the data and display the result.
907 913 if (
908 914 isset( $action )
909 915 && in_array( $action, array( 'rp', 'resetpass' ), true )
910 - && isset( $value ) && 0 < strpos( $value, ':' )
916 + && is_string( $value ) && 0 < strpos( $value, ':' )
911 917 ) {
912 918 [ $login, $key ] = explode( ':', wp_unslash( $value ), 2 );
913 919 $user = check_password_reset_key( $key, $login );
920 +
921 + if ( is_wp_error( $user ) ) {
922 + delete_site_transient( $transient_key );
923 + setcookie( $cookie_name, ' ', time() - YEAR_IN_SECONDS, $rp_path, $rp_domain, is_ssl(), true );
924 + unset( $_COOKIE[ $cookie_name ] );
925 +
926 + return;
927 + }
928 +
914 929 if ( 'resetpass' === $action ) {
915 - delete_site_transient( 'wd-rp-' . COOKIEHASH );
930 + delete_site_transient( $transient_key );
931 + setcookie( $cookie_name, ' ', time() - YEAR_IN_SECONDS, $rp_path, $rp_domain, is_ssl(), true );
932 + unset( $_COOKIE[ $cookie_name ] );
916 933 }
917 - if ( ! is_wp_error( $user ) ) {
918 - $this->render_partial(
919 - 'mask-login/reset',
920 - array(
921 - 'user' => $user,
922 - )
923 - );
924 - exit;
925 - }
934 +
935 + $this->render_partial(
936 + 'mask-login/reset',
937 + array(
938 + 'user' => $user,
939 + )
940 + );
941 + exit;
926 942 }
927 943 }
928 944
929 945 /**
@@ -935,10 +951,15 @@
935 951 * @since 2.6.4
936 952 */
937 953 private function is_allowed_path( string $path ): bool {
938 954 // Admin post requests to admin-post.php should be allowed.
939 - $allowed = 'wp-admin/admin-post.php' === $path && ! empty( defender_get_data_from_request( 'action', 'r' ) );
955 + $action = defender_get_data_from_request( 'action', 'r' );
956 + $allowed = 'wp-admin/admin-post.php' === $path && is_string( $action ) && '' !== trim( $action );
940 957
958 + if ( 'wp-admin/admin-ajax.php' === $path && $this->is_recipient_email_action() ) {
959 + $allowed = true;
960 + }
961 +
941 962 /**
942 963 * Filter to allow whitelisting paths from login masking.
943 964 *
944 965 * @param bool $allowed Is current path allowed?.
@@ -949,8 +970,37 @@
949 970 return apply_filters( 'wd_mask_login_is_allowed_path', $allowed, $path );
950 971 }
951 972
952 973 /**
974 + * Check if the request is a signed recipient email action.
975 + *
976 + * @return bool
977 + */
978 + private function is_recipient_email_action(): bool {
979 + $action = defender_get_data_from_request( 'action', 'r' );
980 + $hash = defender_get_data_from_request( 'hash', 'r' );
981 + if ( ! is_string( $hash ) || '' === trim( $hash ) ) {
982 + return false;
983 + }
984 +
985 + if ( Notification::SLUG_UNSUBSCRIBE === $action ) {
986 + $slug = defender_get_data_from_request( 'slug', 'r' );
987 +
988 + return is_string( $slug ) && '' !== trim( $slug );
989 + }
990 +
991 + if ( Notification::SLUG_SUBSCRIBE !== $action ) {
992 + return false;
993 + }
994 +
995 + $slug = defender_get_data_from_request( 'uid', 'r' );
996 + $slugs = defender_get_data_from_request( 'uids', 'r' );
997 +
998 + return ( is_string( $slug ) && '' !== trim( $slug ) )
999 + || ( is_string( $slugs ) && '' !== trim( $slugs ) );
1000 + }
1001 +
1002 + /**
953 1003 * An endpoint for fetching Post/Page.
954 1004 *
955 1005 * @param Request $request Request data.
956 1006 *
@@ -1013,9 +1063,9 @@
1013 1063 public function posts_where_title( string $where, WP_Query $wp_query ) {
1014 1064 global $wpdb;
1015 1065
1016 1066 $search_term = $wp_query->get( 'search_by_post_title' );
1017 - if ( ! empty( $search_term ) ) {
1067 + if ( is_string( $search_term ) && '' !== trim( $search_term ) ) {
1018 1068 $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( $wpdb->esc_like( $search_term ) ) . '%\'';
1019 1069 }
1020 1070
1021 1071 return $where;
@@ -1030,12 +1080,12 @@
1030 1080 *
1031 1081 * @return string The modified URL.
1032 1082 */
1033 1083 public function change_subsites_admin_url( string $url, string $path, $blog_id ) {
1034 - if ( empty( $path ) && ! empty( $blog_id ) ) {
1084 + if ( '' === trim( $path ) && is_int( $blog_id ) && 0 < $blog_id ) {
1035 1085 $mask_url = trim( $this->model->mask_url );
1036 1086
1037 - if ( ! empty( $mask_url ) && $this->check_if_domain_is_mapped( $url ) ) {
1087 + if ( '' !== $mask_url && $this->check_if_domain_is_mapped( $url ) ) {
1038 1088 $url = str_replace( 'wp-admin', $mask_url, untrailingslashit( $url ) );
1039 1089 }
1040 1090 }
1041 1091
@@ -1051,15 +1101,15 @@
1051 1101 */
1052 1102 public function check_if_domain_is_mapped( string $url ): bool {
1053 1103 $is_mapped = false;
1054 1104
1055 - if ( ! empty( $url ) ) {
1105 + if ( '' !== trim( $url ) ) {
1056 1106 $url_arr = wp_parse_url( $url );
1057 1107 $net_url_arr = wp_parse_url( network_site_url() );
1058 1108
1059 1109 if (
1060 - ! empty( $url_arr['host'] ) &&
1061 - ! empty( $net_url_arr['host'] ) &&
1110 + isset( $url_arr['host'] ) && is_string( $url_arr['host'] ) && '' !== trim( $url_arr['host'] ) &&
1111 + isset( $net_url_arr['host'] ) && is_string( $net_url_arr['host'] ) && '' !== trim( $net_url_arr['host'] ) &&
1062 1112 $this->get_domain_from_host( $url_arr['host'] ) !== $this->get_domain_from_host( $net_url_arr['host'] )
1063 1113 ) {
1064 1114 $is_mapped = true;
1065 1115 }
@@ -1099,9 +1149,9 @@
1099 1149 * @since 3.4.0
1100 1150 */
1101 1151 public function update_admin_bar_menu( WP_Admin_Bar $admin_bar ) {
1102 1152 $mask_url = trim( $this->model->mask_url );
1103 - if ( empty( $mask_url ) ) {
1153 + if ( '' === $mask_url ) {
1104 1154 return;
1105 1155 }
1106 1156
1107 1157 $admin_bar_nodes = $admin_bar->get_nodes();
@@ -1132,9 +1182,9 @@
1132 1182 */
1133 1183 public function update_myblogs_blog_actions( string $actions, object $user_blog ) {
1134 1184 $mask_url = trim( $this->model->mask_url );
1135 1185
1136 - if ( empty( $mask_url ) ) {
1186 + if ( '' === $mask_url ) {
1137 1187 return $actions;
1138 1188 }
1139 1189
1140 1190 $admin_url = get_admin_url( $user_blog->userblog_id );