PluginProbe
Friends / 2.8.6
Friends v2.8.6
4.3.2 4.3.1 4.3.0 4.2.2 4.2.1 4.2.0 4.1.0 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.0 2.9.1 All 88 releases
friends / includes / class-access-control.php

class-access-control.php in Friends 2.8.6, at includes/class-access-control.php

335 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Friends Access Control
4 *
5 * This contains the functions for access control.
6 *
7 * @package Friends
8 */
9
10 namespace Friends;
11
12 /**
13 * This is the class for the Friends Plugin Access Control.
14 *
15 * @since 0.6
16 *
17 * @package Friends
18 * @author Alex Kirk
19 */
20 class Access_Control {
21 /**
22 * States whether this is an authenticated feed call.
23 *
24 * @var boolean
25 */
26 private $feed_authenticated = null;
27
28 /**
29 * Contains a reference to the Friends class.
30 *
31 * @var Friends
32 */
33 private $friends = null;
34
35 /**
36 * Constructor
37 *
38 * @param Friends $friends A reference to the Friends object.
39 */
40 public function __construct( Friends $friends ) {
41 $this->friends = $friends;
42 $this->register_hooks();
43 }
44
45 /**
46 * Register the WordPress hooks
47 */
48 private function register_hooks() {
49 add_filter( 'determine_current_user', array( $this, 'authenticate' ), 1 );
50 add_filter( 'option_comment_whitelist', array( $this, 'option_comment_whitelist' ) );
51 add_action( 'set_user_role', array( $this, 'notify_new_friend_request' ), 10, 3 );
52 add_action( 'map_meta_cap', array( $this, 'strict_friend_checking_for_super_admin' ), 10, 4 );
53 add_action( 'delete_user', array( $this, 'delete_friend_token' ) );
54 add_action( 'init', array( $this, 'remote_login' ) );
55 }
56
57 /**
58 * Whether the feed is authenticated
59 *
60 * @return bool The authentication status of the feed.
61 */
62 public function feed_is_authenticated() {
63 return (bool) $this->get_authenticated_feed_user();
64 }
65
66 /**
67 * Get authenticated feed user
68 *
69 * @return User|null The authentication status of the feed.
70 */
71 public function get_authenticated_feed_user() {
72 if ( is_null( $this->feed_authenticated ) ) {
73 $this->authenticate( 0 );
74 }
75
76 if ( is_null( $this->feed_authenticated ) ) {
77 return null;
78 }
79
80 return new User( $this->feed_authenticated );
81 }
82
83 /**
84 * Whether the private RSS feed is authenticated. This is the feed for the admins of the site that will contain the friends posts.
85 *
86 * @return bool The authentication status of the feed.
87 */
88 public static function private_rss_is_authenticated() {
89 if ( isset( $_GET['auth'] ) && get_option( 'friends_private_rss_key' ) === $_GET['auth'] ) {
90 return true;
91 }
92
93 return false;
94 }
95
96 /**
97 * Verify a friend token
98 *
99 * @param string $token The token to verify.
100 * @param integer $until Valid until timestamp.
101 * @param string $auth The auth code.
102 *
103 * @return int|bool The user id or false.
104 */
105 public function verify_token( $token, $until, $auth ) {
106 $user_id = get_option( 'friends_in_token_' . $token );
107 if ( ! $user_id ) {
108 $me = User::get_user( User::get_user_login_for_url( $token ) );
109 if ( ! $me || is_wp_error( $me ) ) {
110 return false;
111 }
112 $user_id = $me->ID;
113 } else {
114 settype( $user_id, 'int' );
115
116 if ( get_user_option( 'friends_in_token', $user_id ) !== $token ) {
117 return false;
118 }
119 }
120
121 // Allow for some grace period by skipping the auth check for older versions.
122 if ( ! is_null( $until ) && ! is_null( $auth ) ) {
123 if ( ! password_verify( $until . get_user_option( 'friends_out_token', $user_id ), $auth ) ) {
124 return false;
125 }
126
127 if ( time() > $until ) {
128 return false;
129 }
130 }
131
132 return $user_id;
133 }
134
135 /**
136 * Log in a friend via URL parameter
137 */
138 public function remote_login() {
139 if ( ! isset( $_GET['friend_auth'] ) ) {
140 return;
141 }
142 $tokens = explode( '-', $_GET['friend_auth'] );
143 if ( 3 === count( $tokens ) ) {
144 $user_id = $this->verify_token( $tokens[0], $tokens[1], $tokens[2] );
145 } elseif ( 2 === count( $tokens ) && isset( $_GET['me'] ) ) {
146 $user_id = $this->verify_token( $_GET['me'], $tokens[0], $tokens[1] );
147 } else {
148 return;
149 }
150
151 if ( ! $user_id ) {
152 return;
153 }
154 $user = new User( $user_id );
155 if ( ! $user->has_cap( 'friend' ) ) {
156 return;
157 }
158
159 wp_set_auth_cookie( $user_id );
160 wp_safe_redirect( str_replace( array( '?friend_auth=' . $_GET['friend_auth'], '&friend_auth=' . $_GET['friend_auth'], '?me=' . $_GET['me'], '&me=' . $_GET['me'] ), '', $_SERVER['REQUEST_URI'] ) );
161 exit;
162 }
163
164 /**
165 * Authenticate a user for a feed.
166 *
167 * @param int $incoming_user_id An already authenticated user.
168 * @return int The new authenticated user.
169 */
170 public function authenticate( $incoming_user_id ) {
171 if ( false === $incoming_user_id ) {
172 return false;
173 }
174
175 $user_id = false;
176 if ( isset( $_GET['friend'] ) && isset( $_GET['until'] ) && isset( $_GET['auth'] ) ) {
177 $user_id = $this->verify_token( $_GET['friend'], $_GET['until'], $_GET['auth'] );
178 } elseif ( isset( $_GET['me'] ) && isset( $_GET['until'] ) && isset( $_GET['auth'] ) ) {
179 $user_id = $this->verify_token( $_GET['me'], $_GET['until'], $_GET['auth'] );
180 }
181
182 if ( $user_id ) {
183 $user = new User( $user_id );
184 if ( $user->has_cap( 'friend' ) ) {
185 $this->feed_authenticated = $user_id;
186 return $this->feed_authenticated;
187 }
188 }
189
190 return $incoming_user_id;
191 }
192
193 /**
194 * Gets the friend auth.
195 *
196 * @param User $friend_user The friend user.
197 * @param integer $validity The validity.
198 *
199 * @return string The friend auth.
200 */
201 public function get_friend_auth( User $friend_user, $validity = 3600 ) {
202 static $tokens = array();
203
204 if ( ! isset( $tokens[ $friend_user->ID ] ) ) {
205 $tokens[ $friend_user->ID ] = array();
206 $out_token = $friend_user->get_user_option( 'friends_out_token' );
207 $in_token = $friend_user->get_user_option( 'friends_in_token' );
208
209 if ( $in_token && $out_token ) {
210 $until = time() + $validity;
211 $auth = password_hash( $until . $in_token, PASSWORD_DEFAULT );
212
213 $tokens[ $friend_user->ID ] = array(
214 'me' => User::get_user_login_for_url( home_url(), false ),
215 'until' => $until,
216 'auth' => $auth,
217 );
218 }
219 }
220
221 return $tokens[ $friend_user->ID ];
222 }
223
224 /**
225 * Appends an auth to an URL.
226 *
227 * @param string $url The url.
228 * @param User $friend_user The friend user.
229 * @param integer $validity The validity in seconds.
230 *
231 * @return string The url with an appended auth.
232 */
233 public function append_auth( $url, User $friend_user, $validity = 3600 ) {
234 if ( $validity < 0 ) {
235 return $url;
236 }
237 $friend_auth = $this->get_friend_auth( $friend_user, $validity );
238 if ( ! empty( $friend_auth ) ) {
239 $sep = false === strpos( $url, '?' ) ? '?' : '&';
240
241 $url .= $sep . 'me=' . urlencode( $friend_auth['me'] );
242 $url .= '&until=' . urlencode( $friend_auth['until'] );
243 $url .= '&auth=' . urlencode( $friend_auth['auth'] );
244 }
245
246 return $url;
247 }
248
249 /**
250 * Delete options associated with a user
251 *
252 * @param int $user_id The user id.
253 * @return The old token.
254 */
255 public function delete_friend_token( $user_id ) {
256 $current_secret = get_user_option( 'friends_in_token', $user_id );
257
258 if ( $current_secret ) {
259 delete_option( 'friends_in_token_' . $current_secret );
260 }
261
262 $user = new User( $user_id );
263
264 // No need to delete user options as the user will be deleted.
265 return $current_secret;
266 }
267
268 /**
269 * Update a friend request token
270 *
271 * @param int $user_id The user id.
272 * @param string $new_role The new role.
273 * @param array $old_roles The old roles.
274 *
275 * @return string The new token.
276 */
277 public function notify_new_friend_request( $user_id, $new_role, $old_roles ) {
278 if ( 'friend_request' !== $new_role || in_array( $new_role, $old_roles, true ) ) {
279 return;
280 }
281
282 do_action( 'notify_new_friend_request', new User( $user_id ) );
283 }
284
285 /**
286 * Demotes the super admin for the friend roles so that they can interact in the Friends system like a normal user.
287 *
288 * @param string[] $caps Primitive capabilities required of the user.
289 * @param string $cap Capability being checked.
290 * @param int $user_id The user ID.
291 * @param array $args Adds context to the capability check, typically
292 * starting with an object ID.
293 *
294 * @return array
295 */
296 public function strict_friend_checking_for_super_admin( $caps, $cap, $user_id, $args ) {
297 if ( ! in_array( $cap, array( 'friend', 'acquaintance', 'pending_friend_request', 'friend_request', 'subscription' ) ) ) {
298 return $caps;
299 }
300 if ( ! is_multisite() || ! is_super_admin( $user_id ) ) {
301 return $caps;
302 }
303
304 $user = get_user_by( 'id', $user_id );
305 if ( ! $user ) {
306 return $caps;
307 }
308
309 foreach ( $user->roles as $role ) {
310 // If they have the role we are checking for, we'll respond with unmapped caps.
311 if ( $cap === $role ) {
312 return $caps;
313 }
314 }
315
316 // If the super admin doesn't have the role, respond with do_not_allow so that they don't qualify
317 // for the capapbility, despite being a super admin (which automatically has any capability).
318 return array( 'do_not_allow' );
319 }
320
321 /**
322 * Prevent a friend's first comment ending up in moderation.
323 *
324 * @param string $value The value retrieved from the Database.
325 * @return string The filtered value.
326 */
327 public function option_comment_whitelist( $value ) {
328 // Don't moderate the first comment by a friend.
329 if ( current_user_can( 'friend' ) || current_user_can( 'acquaintance' ) ) {
330 return '0';
331 }
332 return $value;
333 }
334 }
335