PluginProbe
UpStream: a Project Management Plugin for WordPress / trunk
UpStream: a Project Management Plugin for WordPress vtrunk
trunk 1.39.0 1.39.1 1.39.2 1.39.3 2.0.7 2.1.0
upstream / includes / frontend / class-upstream-login.php

class-upstream-login.php in UpStream: a Project Management Plugin for WordPress trunk, at includes/frontend/class-upstream-login.php

312 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handle frontend login
4 *
5 * @package UpStream
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 /**
13 * Class UpStream_Login
14 */
15 final class UpStream_Login {
16
17 /**
18 * Represent the feedback message for the current action.
19 *
20 * @since 1.0.0
21 * @access private
22 *
23 * @var string $feedback_message
24 */
25 private $feedback_message = '';
26
27 /**
28 * Class constructor.
29 *
30 * @since 1.0.0
31 */
32 public function __construct() {
33 $this->perform_user_login_action();
34 }
35
36 /**
37 * Handles the flow of the login/logout process.
38 *
39 * @since 1.0.0
40 * @access private
41 */
42 private function perform_user_login_action() {
43 $get_data = isset( $_GET ) ? wp_unslash( $_GET ) : array();
44 $post_data = isset( $_POST ) ? wp_unslash( $_POST ) : array();
45 $action = isset( $get_data['action'] ) ? sanitize_text_field( $get_data['action'] ) : null;
46 $user_is_trying_to_login = isset( $post_data['login'] );
47
48 if ( 'logout' === $action && ! $user_is_trying_to_login ) {
49 self::do_destroy_session();
50 } elseif ( $user_is_trying_to_login ) {
51 if ( ! isset( $post_data['upstream_login_nonce'] ) || ! wp_verify_nonce(
52 sanitize_text_field( $post_data['upstream_login_nonce'] ),
53 'upstream-login-nonce'
54 ) ) {
55 return false;
56 }
57
58 $data = $this->validate_log_in_post_data();
59
60 if ( is_array( $data ) ) {
61 $this->authenticate_data( $data );
62 }
63 }
64 }
65
66 /**
67 * Destroy user's session data.
68 *
69 * @since 1.9.0
70 * @static
71 */
72 public static function do_destroy_session() {
73 wp_logout();
74
75 $get_data = isset( $_GET ) ? wp_unslash( $_GET ) : array();
76
77 if ( session_status() === PHP_SESSION_ACTIVE && isset( $_SESSION['upstream'] ) ) {
78 unset( $_SESSION['upstream'] );
79 }
80
81 if ( ! empty( $get_data ) && isset( $get_data['action'] ) && sanitize_text_field( $get_data['action'] ) === 'logout' ) {
82 unset( $get_data['action'] );
83 }
84 }
85
86 /**
87 * Validate the login form data by checking if a username and a password were provided.
88 * If data is valid, an array will be returned. The return will be FALSE otherwise.
89 *
90 * @since 1.9.0
91 * @access private
92 *
93 * @return array | bool
94 */
95 private function validate_log_in_post_data() {
96 $post_data = isset( $_POST ) ? wp_unslash( $_POST ) : array();
97
98 if ( ! isset( $post_data['upstream_login_nonce'] ) || ! wp_verify_nonce(
99 sanitize_text_field( $post_data['upstream_login_nonce'] ),
100 'upstream-login-nonce'
101 ) ) {
102 return false;
103 }
104
105 $post_data = array(
106 'username' => isset( $post_data['user_email'] ) ? trim( sanitize_text_field( $post_data['user_email'] ) ) : '',
107 'password' => isset( $post_data['user_password'] ) ? $post_data['user_password'] : '',
108 );
109
110 if ( empty( $post_data['username'] ) ) {
111 $this->feedback_message = __( 'Email address/username field cannot be empty.', 'upstream' );
112 } elseif ( strlen( $post_data['username'] ) < 3 ) {
113 $this->feedback_message = __( 'Invalid email address/username.', 'upstream' );
114 } else {
115 if ( empty( $post_data['password'] ) ) {
116 $this->feedback_message = __( 'Password field cannot be empty.', 'upstream' );
117 } elseif ( strlen( $post_data['password'] ) < 2 ) {
118 $this->feedback_message = __( 'Invalid email address and/or password.', 'upstream' );
119 } else {
120 return $post_data;
121 }
122 }
123
124 return false;
125 }
126
127 /**
128 * Upstream Get Project Roles
129 */
130 private function upstream_get_project_roles() {
131 $options = (array) get_option( 'upstream_general' );
132
133 if ( ! isset( $options['project_user_roles'] ) || empty( $options['project_user_roles'] ) ) {
134 $roles = array(
135 'upstream_manager',
136 'upstream_user',
137 'administrator',
138 );
139 } else {
140 $roles = (array) $options['project_user_roles'];
141 }
142
143 $roles = apply_filters( 'upstream_user_roles_for_projects', $roles );
144
145 return $roles;
146 }
147
148
149 /**
150 * Attempt to authenticate a user against the open project given current email address and password.
151 *
152 * @since 1.9.0
153 * @access private
154 *
155 * @param array $data An associative array containing an email (already sanitized) and a raw password.
156 * @throws \Exception Exception.
157 *
158 * @return bool
159 */
160 private function authenticate_data( $data ) {
161 try {
162 if ( ! isset( $data['username'] ) || ! isset( $data['password'] ) ) {
163 throw new \Exception( __( 'Invalid email address and/or password.', 'upstream' ) );
164 }
165
166 $user = get_user_by( 'email', $data['username'] );
167 if ( empty( $user ) ) {
168 $user = get_user_by( 'login', $data['username'] );
169 if ( empty( $user ) ) {
170 throw new \Exception( __( 'Invalid user/email address and/or password.', 'upstream' ) );
171 }
172 }
173
174 $user_roles = (array) $user->roles;
175 $project_roles = array_merge( array( 'administrator', 'upstream_client_user', 'upstream_user', 'upstream_manager' ), $this->upstream_get_project_roles() );
176
177 if ( count(
178 array_intersect(
179 $user_roles,
180 $project_roles
181 )
182 ) === 0 ) {
183 throw new \Exception( __( "You don't have enough permissions to log in here.", 'upstream' ) );
184 }
185
186 $project_id = (int) upstream_post_id();
187 $can_continue = false;
188
189 // Make sure he can be authenticated if he's an admin/manager.
190 if ( count( array_intersect( $user_roles, array( 'administrator', 'upstream_manager' ) ) ) > 0 ) {
191 $can_continue = true;
192 } elseif ( upstream_is_clients_disabled() ) {
193 throw new \Exception( __( 'Invalid email address and/or password.', 'upstream' ) );
194 } else {
195 // Check if he, as an UpStream User, is a current member of this project.
196 if ( in_array( 'upstream_user', $user_roles, true ) ) {
197 $meta_key_name = '_upstream_project_members';
198 } else {
199 // Check if he, as an UpStream Client User, is allowed to log in in this project.
200 $meta_key_name = '_upstream_project_client_users';
201 }
202
203 $meta = (array) get_post_meta( $project_id, $meta_key_name );
204 if ( count( $meta ) > 0 ) {
205 $can_continue = in_array( (string) $user->ID, $meta[0] );
206 }
207 }
208
209 if ( ! $can_continue ) {
210 throw new \Exception( __( 'Sorry, you are not allowed to access this project.', 'upstream' ) );
211 }
212
213 $user = wp_signon(
214 array(
215 'user_login' => $data['username'],
216 'user_password' => $data['password'],
217 'remember' => false,
218 )
219 );
220
221 if ( is_wp_error( $user ) ) {
222 throw new \Exception( __( 'Invalid email address and/or password.', 'upstream' ) );
223 }
224
225 // Retrieve the project's client id.
226 $client_id = (array) get_post_meta( $project_id, '_upstream_project_client' );
227 if ( count( $client_id ) > 0 ) {
228 $client_id = (int) $client_id[0];
229 } else {
230 $client_id = 0;
231 }
232
233 $_SESSION['upstream'] = array(
234 'project_id' => $project_id,
235 'client_id' => $client_id,
236 'user_id' => $user->ID,
237 );
238
239 $project_permalink = get_the_permalink( $project_id );
240 wp_save_redirect( esc_url( $project_permalink ) );
241
242 return true;
243 } catch ( \Exception $e ) {
244 $this->feedback_message = $e->getMessage();
245
246 return false;
247 }
248 }
249
250 /**
251 * Return the current status of the user's login.
252 *
253 * @since 1.0.0
254 * @static
255 *
256 * @return bool
257 */
258 public static function user_is_logged_in() {
259 if ( session_status() === PHP_SESSION_NONE ) {
260 return false;
261 }
262
263 $user_is_logged_in = (
264 isset( $_SESSION['upstream'] ) &&
265 ! empty( $_SESSION['upstream']['client_id'] ) &&
266 ! empty( $_SESSION['upstream']['user_id'] )
267 );
268
269 return $user_is_logged_in;
270 }
271
272 /**
273 * Check if there's a feedback message for the current action.
274 *
275 * @since 1.9.0
276 *
277 * @return bool
278 */
279 public function has_feedback_message() {
280 $has_feedback_message = ! empty( $this->feedback_message );
281
282 return $has_feedback_message;
283 }
284
285 /**
286 * Retrieve the feedback message for the current action.
287 *
288 * @since 1.9.0
289 *
290 * @return string
291 */
292 public function get_feedback_message() {
293 $feedback_message = (string) $this->feedback_message;
294
295 $this->feedback_message = '';
296
297 return $feedback_message;
298 }
299
300 /**
301 * Logs the user out.
302 *
303 * @since 1.9.0
304 * @access private
305 */
306 private function do_log_out() {
307 self::do_destroy_session();
308
309 $this->feedback_message = __( 'You were just logged out.', 'upstream' );
310 }
311 }
312