PluginProbe
Patchstack – WordPress & Plugins Security / 2.1.4
Patchstack – WordPress & Plugins Security v2.1.4
2.3.7 trunk 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.17 2.1.18 2.1.19 2.1.2 2.1.20 2.1.21 2.1.22 2.1.23 2.1.24 2.1.25 2.1.3 2.1.4 2.1.5 2.1.6 All 49 releases
patchstack / includes / hide-login.php

hide-login.php in Patchstack – WordPress & Plugins Security 2.1.4, at includes/hide-login.php

329 lines 10.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // Do not allow the file to be called directly.
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 /**
9 * This class is used to hide the login page, if it's enabled.
10 */
11 class P_Hide_Login extends P_Core {
12
13 /**
14 * Whether we should use PHP to redirect the login.
15 *
16 * @var boolean
17 */
18 protected $wp_login_php = false;
19
20 /**
21 * Add the actions required to hide the login page.
22 *
23 * @param Patchstack $core
24 * @return void
25 */
26 public function __construct( $core ) {
27 parent::__construct( $core );
28
29 if ( $this->get_option( 'patchstack_license_free', 0 ) == 1 ) {
30 return;
31 }
32
33 // Determine if the proper WordPress version is installed.
34 global $wp_version;
35 if ( version_compare( $wp_version, '4.0-RC1-src', '<' ) ) {
36 add_action( 'admin_notices', array( $this, 'admin_notices_incompatible' ) );
37 add_action( 'network_admin_notices', array( $this, 'admin_notices_incompatible' ) );
38 return;
39 }
40
41 // No need to continue if it is not enabled.
42 if ( ! get_site_option( 'patchstack_mv_wp_login' ) || ! get_site_option( 'patchstack_rename_wp_login' ) ) {
43 return;
44 }
45
46 // We need to load the plugin library for multisite.
47 if ( is_multisite() && ( ! function_exists( 'is_plugin_active_for_network' ) || ! function_exists( 'is_plugin_active' ) ) ) {
48 require_once ABSPATH . '/wp-admin/includes/plugin.php';
49 }
50
51 // Register the filters and actions for the functionality.
52 add_filter( 'site_url', array( $this, 'site_url' ), 10, 4 );
53 add_filter( 'network_site_url', array( $this, 'network_site_url' ), 10, 3 );
54 add_filter( 'wp_redirect', array( $this, 'wp_redirect' ), 10, 2 );
55 add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 9999 );
56 add_action( 'wp_loaded', array( $this, 'wp_loaded' ) );
57 add_action( 'init', array( $this, 'deny_default_login_page' ) );
58 }
59
60 /**
61 * Deny access to wp-login if rewrite wp-admin option is enabled.
62 *
63 * @return void
64 */
65 public function deny_default_login_page() {
66 if ( get_site_option( 'patchstack_mv_wp_login' ) && strpos( strtolower( $_SERVER['REQUEST_URI'] ), 'wp-login.php' ) !== false ) {
67 die( 'Forbidden!' );
68 }
69 }
70
71 /**
72 * Send the email that contains the new login page URL.
73 *
74 * @return boolean If the email was sent or not.
75 */
76 public function send_email() {
77 global $current_user;
78 $subject = __( 'New Login URL', 'patchstack' );
79 $message = '<br /><br />Your login page is now here: <strong> <a href="' . get_site_url() . '/' . get_site_option( 'patchstack_rename_wp_login' ) . '">' . get_site_url() . '/' . get_site_option( 'patchstack_rename_wp_login' ) . '</strong></a>';
80 return wp_mail( $current_user->user_email, $subject, $message );
81 }
82
83 /**
84 * Get the current site's URL.
85 *
86 * @param string $url
87 * @param string $path
88 * @param string $scheme
89 * @param integer $blog_id
90 * @return string
91 */
92 public function site_url( $url, $path, $scheme, $blog_id ) {
93 return $this->filter_wp_login_php( $url, $scheme );
94 }
95
96 /**
97 * Determine if the current page is a login/registration page.
98 *
99 * @return void
100 */
101 public function plugins_loaded() {
102 global $pagenow;
103 $stop = false;
104 $request = parse_url( $_SERVER['REQUEST_URI'] );
105
106 // If the current page is wp-login.php
107 if ( ( strpos( rawurldecode( $_SERVER['REQUEST_URI'] ), 'wp-login.php' ) !== false || untrailingslashit( $request['path'] ) === site_url( 'wp-login', 'relative' ) ) && ! is_admin() ) {
108 $this->wp_login_php = true;
109 $_SERVER['REQUEST_URI'] = $this->user_trailingslashit( '/' . str_repeat( '-/', 10 ) );
110 $pagenow = 'index.php';
111 $stop = true;
112 }
113
114 // If the current page is the renamed login page.
115 if ( ! $stop && ( untrailingslashit( $request['path'] ) === home_url( $this->new_login_slug(), 'relative' ) || ( ! get_site_option( 'permalink_structure' ) && isset( $_GET[ $this->new_login_slug() ] ) && empty( $_GET[ $this->new_login_slug() ] ) ) ) ) {
116 $pagenow = 'wp-login.php';
117 $stop = true;
118 }
119
120 // If the current page is registration page.
121 if ( ! $stop && ( ( strpos( rawurldecode( $_SERVER['REQUEST_URI'] ), 'wp-register.php' ) !== false || untrailingslashit( $request['path'] ) === site_url( 'wp-register', 'relative' ) ) && ! is_admin() ) ) {
122 $this->wp_login_php = true;
123 $_SERVER['REQUEST_URI'] = $this->user_trailingslashit( '/' . str_repeat( '-/', 10 ) );
124 $pagenow = 'index.php';
125 }
126 }
127
128 /**
129 * Determine if we should redirect the user upon visiting new/old login page.
130 *
131 * @return void
132 */
133 public function wp_loaded() {
134 global $pagenow;
135 $request = parse_url( $_SERVER['REQUEST_URI'] );
136
137 // Redirect when admin page is requested but no admin access.
138 if ( is_admin() && ! is_user_logged_in() && ! defined( 'DOING_AJAX' ) && $pagenow !== 'admin-post.php' && ( isset( $_GET ) && empty( $_GET['adminhash'] ) && $request['path'] !== '/wp-admin/options.php' ) ) {
139 wp_safe_redirect( home_url( '/404' ) );
140 exit;
141 }
142
143 // If the current page is the login page, redirect to 404.
144 if ( $pagenow === 'wp-login.php' && $request['path'] !== $this->user_trailingslashit( $request['path'] ) && get_site_option( 'permalink_structure' ) ) {
145 wp_safe_redirect( home_url( '/404' ) );
146 exit;
147 }
148
149 // Other possible login pages that we need to block by default.
150 $login_pages = array(
151 home_url( 'wp-login.php', 'relative' ),
152 home_url( 'login', 'relative' ),
153 site_url( 'login', 'relative' ),
154 );
155 if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $login_pages, true ) ) {
156 wp_safe_redirect( home_url( '/404' ) );
157 exit;
158 }
159
160 // Determine if we should redirect the user to the new login page.
161 if ( $this->wp_login_php ) {
162 if ( ( $referer = wp_get_referer() ) && strpos( $referer, 'wp-activate.php' ) !== false && ( $referer = parse_url( $referer ) ) && ! empty( $referer['query'] ) ) {
163 parse_str( $referer['query'], $referer );
164
165 // When a user is self-created.
166 if ( ! empty( $referer['key'] ) && ( $result = wpmu_activate_signup( $referer['key'] ) ) && is_wp_error( $result ) && ( $result->get_error_code() === 'already_active' || $result->get_error_code() === 'blog_taken' ) ) {
167 wp_safe_redirect( $this->new_login_url() . ( ! empty( $_SERVER['QUERY_STRING'] ) ? '?' . $_SERVER['QUERY_STRING'] : '' ) );
168 exit;
169 }
170 }
171 $this->wp_template_loader();
172 }
173
174 @require_once ABSPATH . 'wp-includes/post.php';
175
176 // There must be a better way
177 $one = get_home_url() . '/' . $request['path'] . '/';
178 $two = get_home_url() . '/' . get_site_option( 'patchstack_rename_wp_login' ) . '/';
179 $one = str_replace( get_home_url(), '', $one );
180 $two_url = parse_url( get_home_url() );
181 $two = str_replace( $two_url['scheme'] . '://' . $two_url['host'], '', $two );
182 $one = str_replace( '//', '/', $one );
183 $two = str_replace( '//', '/', $two );
184
185 // Show the login page if not already logged in.
186 if ( $one == $two ) {
187 global $error, $interim_login, $action, $user_login;
188
189 if ( is_user_logged_in() && ! isset( $_REQUEST['action'] ) ) {
190 wp_safe_redirect( admin_url() );
191 exit;
192 }
193 @require_once ABSPATH . 'wp-login.php';
194 exit;
195 }
196 }
197
198 /**
199 * Load the template loader.
200 *
201 * @return void
202 */
203 private function wp_template_loader() {
204 global $pagenow;
205 $pagenow = 'index.php';
206
207 if ( ! defined( 'WP_USE_THEMES' ) ) {
208 define( 'WP_USE_THEMES', true );
209 }
210
211 wp();
212 if ( $_SERVER['REQUEST_URI'] === $this->user_trailingslashit( str_repeat( '-/', 10 ) ) ) {
213 $_SERVER['REQUEST_URI'] = $this->user_trailingslashit( '/wp-login-php/' );
214 }
215
216 @require_once ABSPATH . WPINC . '/template-loader.php';
217 exit;
218 }
219
220 /**
221 * Filter the wp-login.php URL.
222 *
223 * @param string $url
224 * @param string $scheme
225 * @return string
226 */
227 public function filter_wp_login_php( $url, $scheme = null ) {
228 // Attempt to retrieve the URL.
229 if ( strpos( $url, 'wp-login.php' ) !== false ) {
230 if ( is_ssl() ) {
231 $scheme = 'https';
232 }
233
234 $args = explode( '?', $url );
235 if ( isset( $args[1] ) ) {
236 parse_str( $args[1], $args );
237 if ( isset( $args['login'] ) ) {
238 $args['login'] = rawurlencode( $args['login'] );
239 }
240 $url = add_query_arg( $args, $this->new_login_url( $scheme ) );
241 } else {
242 $url = $this->new_login_url( $scheme );
243 }
244 }
245
246 return $url;
247 }
248
249 /**
250 * Get the network site URL.
251 *
252 * @param string $url
253 * @param string $path
254 * @param string $scheme
255 * @return string
256 */
257 public function network_site_url( $url, $path, $scheme ) {
258 return $this->filter_wp_login_php( $url, $scheme );
259 }
260
261 /**
262 * Redirect the user to given location.
263 *
264 * @param string $location
265 * @param integer $status
266 * @return string
267 */
268 public function wp_redirect( $location, $status ) {
269 return $this->filter_wp_login_php( $location );
270 }
271
272 /**
273 * Show a notice that WordPress needs to be upgraded.
274 *
275 * @return void
276 */
277 public function admin_notices_incompatible() {
278 echo wp_kses( '<div class="error notice is-dismissible"><p>' . __( 'Patchstack: Please upgrade to the latest version of WordPress to activate', 'patchstack' ) . '</p></div>', $this->allowed_html );
279 }
280
281 /**
282 * Get the new login slug.
283 *
284 * @return string
285 */
286 private function new_login_slug() {
287 if ( $slug = get_site_option( 'patchstack_rename_wp_login' ) ) {
288 return $slug;
289 } elseif ( ( is_multisite() && is_plugin_active_for_network( plugin_basename( __FILE__ ) ) && ( $slug = get_site_option( 'patchstack_rename_wp_login', 'login' ) ) ) ) {
290 return $slug;
291 } elseif ( $slug = 'login' ) {
292 return $slug;
293 }
294 }
295
296 /**
297 * Get the new login URL.
298 *
299 * @param string $scheme
300 * @return void
301 */
302 public function new_login_url( $scheme = null ) {
303 if ( get_site_option( 'permalink_structure' ) ) {
304 return $this->user_trailingslashit( home_url( '/', $scheme ) . $this->new_login_slug() );
305 } else {
306 return home_url( '/', $scheme ) . $this->new_login_slug();
307 }
308 }
309
310 /**
311 * Determine if we have to use trailing slashes.
312 *
313 * @return boolean
314 */
315 private function use_trailing_slashes() {
316 return substr( get_site_option( 'permalink_structure' ), - 1, 1 ) === '/';
317 }
318
319 /**
320 * Use trailing slashes, if needed.
321 *
322 * @param string $string
323 * @return void
324 */
325 private function user_trailingslashit( $string ) {
326 return $this->use_trailing_slashes() ? trailingslashit( $string ) : untrailingslashit( $string );
327 }
328 }
329