PluginProbe
SpinupWP / 1.9.0
SpinupWP v1.9.0
trunk 1.0 1.0.1 1.0.2 1.0.3 1.1 1.1.1 1.1.2 1.2 1.3 1.4 1.4.1 1.4.2 1.5 1.5.1 1.6 1.7 1.7.1 1.8.0 1.9.0 1.9.1
spinupwp / src / MagicLogin.php

MagicLogin.php in SpinupWP 1.9.0, at src/MagicLogin.php

156 lines 3.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SpinupWp;
4
5 use Exception;
6 use WP_User;
7
8 class MagicLogin {
9
10 /**
11 * Init
12 *
13 * @return void
14 */
15 public function init() {
16 if (
17 is_admin()
18 || ( defined( 'DOING_AJAX' ) && DOING_AJAX )
19 || ( defined( 'DOING_CRON' ) && DOING_CRON )
20 || ( defined( 'WP_CLI' ) && WP_CLI )
21 || ( defined( 'WP_INSTALLING' ) && WP_INSTALLING ) ) {
22 return;
23 }
24
25 if ( ! $this->is_login_request() ) {
26 return;
27 }
28
29 add_action( 'plugins_loaded', array( $this, 'handle_request' ) );
30 }
31
32 /**
33 * Handle magic login request.
34 */
35 public function handle_request() {
36 $secret = $this->get_login_secret();
37
38 if ( ! $this->has_valid_signature( $secret ) ) {
39 $this->error('Invalid Signature', 'Your login link is not valid. Please try again.');
40 }
41
42 if ( $this->has_exipred() ) {
43 $this->error('Link Expired', 'Your login link has expired. Please try again.');
44 }
45
46 $user = $this->retrieve_user();
47
48 if ( ! $user ) {
49 $this->error('User Not Found', 'No such user with that login exists.');
50 }
51
52 wp_set_auth_cookie( $user->ID );
53 wp_safe_redirect( admin_url() );
54 exit;
55 }
56
57 /**
58 * Determine if this is a magic login request.
59 *
60 * @return bool
61 */
62 protected function is_login_request() {
63 $query = $_SERVER['QUERY_STRING'];
64
65 if ( empty( $query ) ) {
66 return false;
67 }
68
69 parse_str( $query, $parameters );
70
71 if ( empty( $parameters['spinupwp_signature'] ) ) {
72 return false;
73 }
74
75 return true;
76 }
77
78 /**
79 * Get the login secret.
80 *
81 * @return string
82 * @throws Exception
83 */
84 protected function get_login_secret() {
85 $secret_path = getenv( 'HOME' ) . DIRECTORY_SEPARATOR . '.spinupwp-login.secret';
86
87 if ( ! file_exists( $secret_path ) ) {
88 throw new Exception( 'Secret not found' );
89 }
90
91 $secret = file_get_contents( $secret_path );
92
93 if ( ! $secret ) {
94 throw new Exception( 'Cannot read secret' );
95 }
96
97 return trim( $secret );
98 }
99
100 /**
101 * Determine if the signature is valid.
102 *
103 * @return bool
104 */
105 protected function has_valid_signature( string $secret ) {
106 parse_str( $_SERVER['QUERY_STRING'], $parameters );
107
108 $query_signature = array_pop( $parameters );
109
110 $query = http_build_query( $parameters );
111 $url = home_url() . "?{$query}";
112 $signature = hash_hmac( 'sha256', $url, $secret );
113
114 return hash_equals( $signature, $query_signature );
115 }
116
117 /**
118 * Determine if the signature has expired.
119 *
120 * @return bool
121 */
122 protected function has_exipred() {
123 parse_str( $_SERVER['QUERY_STRING'], $parameters );
124
125 if ( empty( $parameters['expires'] ) ) {
126 return true;
127 }
128
129 return time() > (int) $parameters['expires'];
130 }
131
132 /**
133 * Retrieve the user.
134 *
135 * @return WP_User|false
136 */
137 protected function retrieve_user() {
138 parse_str( $_SERVER['QUERY_STRING'], $parameters );
139 $user_name = sanitize_user( $parameters['user'] );
140
141 $user = get_user_by( 'login', $user_name );
142
143 if ( ! $user && strpos( $user_name, '@' ) ) {
144 $user = get_user_by( 'email', $user_name );
145 }
146
147 return $user;
148 }
149
150 /**
151 * Display error and die.
152 */
153 protected function error($title, $body) {
154 wp_die( "<h1>{$title}</h1>\n<p>{$body}</p>" );
155 }
156 }