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 / component / security-tweaks / class-change-admin.php

class-change-admin.php in Defender Security – Malware Scanner, Login Security & Firewall 6.3.0, at src/component/security-tweaks/class-change-admin.php

249 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Security Tweaks Component for changing the default 'admin' username.
4 *
5 * @package WP_Defender\Component\Security_Tweaks
6 */
7
8 namespace WP_Defender\Component\Security_Tweaks;
9
10 use WP_User;
11 use WP_Error;
12 use Calotes\Helper\HTTP;
13 use Calotes\Component\Response;
14
15 /**
16 * Handle the security tweak of changing the default 'admin' username to a user-defined one.
17 */
18 class Change_Admin extends Abstract_Security_Tweaks {
19
20 /**
21 * Slug identifier for the component.
22 *
23 * @var string
24 */
25 public string $slug = 'replace-admin-username';
26
27 /**
28 * Check whether the issue has been resolved or not.
29 *
30 * @return bool
31 */
32 public function check(): bool {
33 return $this->is_resolved();
34 }
35
36 /**
37 * If the return is true or Response, we add it to resolve list. WP_Error if any error.
38 *
39 * @return bool|WP_Error|Response
40 */
41 public function process() {
42 $username = HTTP::post( 'username' );
43 $is_valid = $this->validate( $username );
44
45 if ( is_wp_error( $is_valid ) ) {
46 return $is_valid;
47 }
48
49 return $this->update_username( $username );
50 }
51
52 /**
53 * This is for un-do stuff that has be done in @process.
54 *
55 * @return bool
56 */
57 public function revert(): bool {
58 return true;
59 }
60
61 /**
62 * Shield up.
63 *
64 * @return bool
65 */
66 public function shield_up(): bool {
67 return true;
68 }
69
70 /**
71 * Check whether the issue is resolved or not.
72 *
73 * @return bool
74 */
75 private function is_resolved() {
76 return ! $this->get_user_with_admin_username();
77 }
78
79 /**
80 * Get user with admin username.
81 *
82 * @return WP_User|false on failure
83 */
84 private function get_user_with_admin_username() {
85 return get_user_by( 'login', 'admin' );
86 }
87
88 /**
89 * Validate username.
90 *
91 * @param string $username to validate.
92 *
93 * @return bool|WP_Error on failure
94 */
95 private function validate( $username ) {
96 if ( ! is_string( $username ) || '' === $username ) {
97 return new WP_Error( 'defender_invalid_username', wp_strip_all_tags( __( 'The username can\'t be empty!', 'defender-security' ) ) );
98 }
99
100 if ( 'admin' === strtolower( $username ) ) {
101 return new WP_Error(
102 'defender_invalid_username',
103 wp_strip_all_tags( __( 'You can\'t use admin as a username again!', 'defender-security' ) )
104 );
105 }
106
107 if ( ! validate_username( $username ) ) {
108 return new WP_Error( 'defender_invalid_username', wp_strip_all_tags( __( 'The username is invalid!', 'defender-security' ) ) );
109 }
110
111 if ( username_exists( $username ) ) {
112 return new WP_Error( 'defender_invalid_username', wp_strip_all_tags( __( 'The username already exists!', 'defender-security' ) ) );
113 }
114
115 return true;
116 }
117
118 /**
119 * Updates the 'admin' username to a new username.
120 * Performs the update in the database and handles multisite admin updates if applicable.
121 *
122 * @param string $username The new username.
123 *
124 * @return bool|WP_Error|Response True on success, WP_Error on database error, Response on logout requirement.
125 */
126 private function update_username( $username ) {
127 global $wpdb;
128 $user = $this->get_user_with_admin_username();
129
130 $ret = $wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
131 $wpdb->users,
132 array( 'user_login' => trim( $username ) ),
133 array( 'ID' => $user->ID )
134 );
135 if ( ! $ret ) {
136 return new WP_Error( 'update_error', $wpdb->last_error );
137 }
138
139 if ( is_multisite() ) {
140 $site_admins = get_site_option( 'site_admins' );
141
142 if ( is_array( $site_admins ) ) {
143 $pos = array_search( 'admin', array_map( 'strtolower', $site_admins ), true );
144
145 if ( false !== $pos ) {
146 $site_admins[ $pos ] = $username;
147 update_site_option( 'site_admins', $site_admins );
148 }
149 }
150 }
151 clean_user_cache( $user );
152 // Log the user out only if it's the user with 'admin' username.
153 if ( get_current_user_id() !== $user->ID ) {
154 return true;
155 }
156 if ( defined( 'WP_DEFENDER_TESTING' ) && true === constant( 'WP_DEFENDER_TESTING' ) ) {
157 // Testing.
158 return true;
159 }
160 $interval = 5;
161 $redirect = $this->get_login_url();
162
163 return new Response(
164 true,
165 array(
166 'message' => sprintf(
167 /* translators: 1. Redirect link. 2. Line break. 3. Interval. */
168 esc_html__(
169 'Your admin name has changed. You will need to %1$s.%2$s This will auto reload after %3$s seconds.',
170 'defender-security'
171 ),
172 '<a href="' . $redirect . '"><strong>' . esc_html__( 're-login', 'defender-security' ) . '</strong></a>',
173 '<br>',
174 '<span class="hardener-timer">' . $interval . '</span>'
175 ),
176 'redirect' => $redirect,
177 'interval' => $interval,
178 )
179 );
180 }
181
182 /**
183 * Get the login url.
184 *
185 * @return string
186 */
187 private function get_login_url(): string {
188 return wp_login_url( network_admin_url( 'admin.php?page=wdf-hardener' ) );
189 }
190
191 /**
192 * Retrieve the tweak's label.
193 *
194 * @return string
195 */
196 public function get_label(): string {
197 return esc_html__( 'Change admin account', 'defender-security' );
198 }
199
200 /**
201 * Get the error reason.
202 *
203 * @return string
204 */
205 public function get_error_reason(): string {
206 return wp_kses(
207 __( '<strong>Your account uses the default “admin” username,</strong> and may attract login attacks.', 'defender-security' ),
208 array(
209 'strong' => array(),
210 )
211 );
212 }
213
214 /**
215 * Return a summary data of this tweak.
216 *
217 * @return array
218 */
219 public function to_array(): array {
220 $admin_user = $this->get_user_with_admin_username();
221 $current_user = wp_get_current_user();
222 $username = $admin_user ? $admin_user->user_login : $current_user->user_login;
223 $error_reason = wp_kses(
224 sprintf(
225 /* translators: %s: Username. */
226 __( '<strong>Your account uses the default "%s" username,</strong> and may attract login attacks.', 'defender-security' ),
227 esc_html( $username )
228 ),
229 array(
230 'strong' => array(),
231 )
232 );
233
234 return array(
235 'slug' => $this->slug,
236 'title' => $this->get_label(),
237 'errorReason' => $error_reason,
238 'successReason' => wp_strip_all_tags( __( 'Username is up to date.', 'defender-security' ) ),
239 'misc' => array(
240 'show_revert_button' => false,
241 'show_action_button' => true,
242 'admin_username' => $username,
243 ),
244 'bulk_description' => wp_strip_all_tags( __( 'Brute force attacks often rely on common usernames and guessed passwords. Create a new admin username to make your site harder to target and help protect your login area.', 'defender-security' ) ),
245 'bulk_title' => wp_strip_all_tags( __( 'Admin User', 'defender-security' ) ),
246 );
247 }
248 }
249