PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 3.5.0
Tutor LMS – eLearning and online course solution v3.5.0
3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / restapi / RestAuth.php
tutor / restapi Last commit date
REST_Author.php 2 years ago REST_Course.php 2 years ago REST_Course_Announcement.php 2 years ago REST_Lesson.php 2 years ago REST_Quiz.php 1 year ago REST_Rating.php 2 years ago REST_Response.php 2 years ago REST_Topic.php 2 years ago RestAuth.php 2 years ago
RestAuth.php
414 lines
1 <?php
2 /**
3 * Manage Rest API Authentication
4 *
5 * API key, secret create, invoke etc
6 *
7 * @package Tutor
8 * @author Themeum <support@themeum.com>
9 * @link https://themeum.com
10 * @since 2.2.1
11 */
12
13 namespace TUTOR;
14
15 use Tutor\Helpers\QueryHelper;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit;
19 }
20
21 /**
22 * Rest API authentication
23 *
24 * @since 2.2.1
25 */
26 class RestAuth {
27
28 /**
29 * Read Permissions
30 *
31 * @var string
32 */
33 const READ = 'Read';
34
35 /**
36 * Write Permissions
37 *
38 * @var string
39 */
40 const WRITE = 'Write';
41
42 /**
43 * Delete Permissions
44 *
45 * @var string
46 */
47 const DELETE = 'Delete';
48
49 /**
50 * Read Write Permissions
51 *
52 * @var string
53 */
54 const READ_WRITE = 'Read/Write';
55
56 /**
57 * All Permissions
58 *
59 * @var string
60 */
61 const ALL = 'All';
62
63 /**
64 * User meta key to store key, secret, permission info
65 *
66 * @var string
67 */
68 const KEYS_USER_META_KEY = 'tutor-api-key-secret';
69
70 /**
71 * Register hooks.
72 *
73 * @since 2.2.1
74 *
75 * @return void
76 */
77 public function __construct() {
78 add_action( 'wp_ajax_tutor_generate_api_keys', __CLASS__ . '::generate_api_keys' );
79 add_action( 'wp_ajax_tutor_update_api_permission', __CLASS__ . '::update_api_permission' );
80 add_action( 'wp_ajax_tutor_revoke_api_keys', __CLASS__ . '::revoke_api_keys' );
81 add_filter( 'determine_current_user', array( $this, 'api_auth' ) );
82 }
83
84 /**
85 * API auth.
86 *
87 * @since 2.7.1
88 *
89 * @param int|false $user_id user id.
90 *
91 * @return int|false
92 */
93 public function api_auth( $user_id ) {
94 // Don't authenticate twice.
95 if ( ! empty( $user_id ) || ! $this->is_tutor_api_request() ) {
96 return $user_id;
97 }
98
99 if ( ! wp_is_application_passwords_available() ) {
100 return $user_id;
101 }
102
103 if ( ! isset( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) ) {
104 return $user_id;
105 }
106
107 $api_key = $_SERVER['PHP_AUTH_USER']; //phpcs:ignore sanitization ok
108 $api_secret = $_SERVER['PHP_AUTH_PW']; //phpcs:ignore sanitization ok
109 $record = self::validate_api_key_secret( $api_key, $api_secret, true );
110 if ( $record ) {
111 return $record->user_id;
112 }
113
114 return $user_id;
115 }
116
117 /**
118 * Is request is tutor rest api.
119 *
120 * @since 2.7.1
121 *
122 * @return boolean
123 */
124 public static function is_tutor_api_request() {
125 $rest_prefix = trailingslashit( rest_get_url_prefix() );
126 $request_uri = esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ?? '' ) );
127
128 $is_tutor_api = ( false !== strpos( $request_uri, $rest_prefix . 'tutor/' ) );
129
130 return $is_tutor_api;
131 }
132
133 /**
134 * Generate api keys
135 *
136 * @since 2.2.1
137 *
138 * @return void send wp_json response
139 */
140 public static function generate_api_keys() {
141 // Validate nonce.
142 tutor_utils()->checking_nonce();
143
144 // Check user permission.
145 if ( ! current_user_can( 'administrator' ) ) {
146 wp_send_json_error( tutor_utils()->error_message() );
147 }
148
149 $api_key = 'key_' . bin2hex( random_bytes( 16 ) );
150 $api_secret = 'secret_' . bin2hex( random_bytes( 32 ) );
151
152 $permission = Input::post( 'permission' );
153 $description = Input::post( 'description', '', Input::TYPE_TEXTAREA );
154
155 $info = wp_json_encode(
156 array(
157 'key' => $api_key,
158 'secret' => $api_secret,
159 'permission' => $permission,
160 'description' => $description,
161 )
162 );
163
164 // Update user meta.
165 $add = add_user_meta(
166 get_current_user_id(),
167 self::KEYS_USER_META_KEY,
168 $info
169 );
170
171 if ( $add ) {
172 $response = self::prepare_response( $add, $api_key, $api_secret, $permission, $description );
173 wp_send_json_success( $response );
174 } else {
175 wp_send_json_error( tutor_utils()->error_message( '0' ) );
176 }
177
178 }
179
180
181 /**
182 * Update api permission
183 *
184 * @since 2.5.0
185 *
186 * @return void send wp_json response
187 */
188 public static function update_api_permission() {
189 global $wpdb;
190
191 // Validate nonce.
192 tutor_utils()->checking_nonce();
193
194 // Check user permission.
195 if ( ! current_user_can( 'administrator' ) ) {
196 wp_send_json_error( tutor_utils()->error_message() );
197 }
198
199 $meta_id = Input::post( 'meta_id', 0, Input::TYPE_INT );
200 $permission = Input::post( 'permission' );
201 $description = Input::post( 'description', '', Input::TYPE_TEXTAREA );
202
203 $info = QueryHelper::get_row( $wpdb->usermeta, array( 'umeta_id' => $meta_id ), 'umeta_id' );
204 $meta_value = json_decode( $info->meta_value );
205
206 $meta_value->permission = $permission;
207 $meta_value->description = $description;
208
209 // Update user meta.
210 try {
211 QueryHelper::update(
212 $wpdb->usermeta,
213 array( 'meta_value' => json_encode( $meta_value ) ),
214 array( 'umeta_id' => $meta_id )
215 );
216
217 $response = self::prepare_response( $meta_id, $meta_value->key, $meta_value->secret, $permission, $description );
218 wp_send_json_success( $response );
219
220 } catch ( \Throwable $th ) {
221 wp_send_json_error( $th->getMessage() );
222 }
223 }
224
225 /**
226 * Revoke api keys
227 *
228 * @since 2.2.1
229 *
230 * @return void send wp_json response
231 */
232 public static function revoke_api_keys() {
233 // Validate nonce.
234 tutor_utils()->checking_nonce();
235
236 // Check user permission.
237 if ( ! current_user_can( 'administrator' ) ) {
238 wp_send_json_error( tutor_utils()->error_message() );
239 }
240
241 $meta_id = Input::post( 'meta_id', 0, Input::TYPE_INT );
242
243 if ( ! $meta_id ) {
244 wp_send_json_error( __( 'Invalid meta id', 'tutor' ) );
245 }
246
247 // Delete api keys.
248 global $wpdb;
249 $delete = QueryHelper::delete( $wpdb->usermeta, array( 'umeta_id' => $meta_id ) );
250
251 if ( $delete ) {
252 wp_send_json_success( __( 'API keys permanently revoked', 'tutor' ) );
253 } else {
254 wp_send_json_error( __( 'API keys revoke failed, please try again.', 'tutor' ) );
255 }
256 }
257
258 /**
259 * Check if api key & secret is valid
260 *
261 * @since 2.2.1
262 * @since 2.7.1 $return_result param added.
263 *
264 * @param string $api_key api key.
265 * @param string $api_secret api secret.
266 * @param bool $return_result return matched meta record.
267 *
268 * @return bool|object
269 */
270 public static function validate_api_key_secret( $api_key, $api_secret, $return_result = false ) {
271 global $wpdb;
272 $table = $wpdb->usermeta;
273
274 $valid = false;
275
276 $results = QueryHelper::get_all(
277 $table,
278 array( 'meta_key' => self::KEYS_USER_META_KEY ), //phpcs:ignore
279 'umeta_id'
280 );
281
282 if ( is_array( $results ) && count( $results ) ) {
283 foreach ( $results as $result ) {
284 $obj = json_decode( $result->meta_value );
285 if ( $obj->key === $api_key && $obj->secret === $api_secret ) {
286 $valid = true;
287 if ( $return_result ) {
288 return $result;
289 }
290 break;
291 }
292 }
293 }
294
295 return $valid;
296 }
297
298 /**
299 * Process api request
300 *
301 * @since 2.2.1
302 *
303 * @return boolean
304 */
305 public static function process_api_request() {
306 $headers = apache_request_headers();
307
308 if ( isset( $headers['Authorization'] ) ) {
309 $authorization_header = $headers['Authorization'];
310
311 if ( strpos( $authorization_header, 'Basic' ) !== false ) {
312 $base_64_credentials = str_replace( 'Basic ', '', $authorization_header );
313 $credentials = base64_decode( $base_64_credentials ); //phpcs:ignore
314
315 list($api_key, $api_secret) = explode( ':', $credentials );
316
317 if ( self::validate_api_key_secret( $api_key, $api_secret ) ) {
318 return true;
319 }
320 }
321 }
322
323 // Key and secret are invalid or not provided.
324 return false;
325 }
326
327 /**
328 * Prepare html response
329 *
330 * @since 2.2.1
331 *
332 * @param int $meta_id meta id.
333 * @param string $key api key.
334 * @param string $secret api secret.
335 * @param string $permission authorization permission.
336 * @param string $description description.
337 *
338 * @return string
339 */
340 public static function prepare_response( $meta_id, $key, $secret, $permission, $description = '' ) {
341 $user_id = get_current_user_id();
342 ob_start();
343 ?>
344 <tr id="<?php echo esc_attr( $meta_id ); ?>">
345 <td>
346 <?php echo esc_html( tutor_utils()->display_name( $user_id ) ); ?>
347 </td>
348 <td>
349 <a class="tutor-btn tutor-btn-outline-primary tutor-btn-sm">
350 <span class="tutor-icon-copy tutor-mr-8"></span>
351 <span class="tutor-copy-text" data-text="<?php echo esc_attr( $key ); ?>">
352 <?php echo esc_html( substr( $key, 0, 5 ) . '...' ); ?>
353 </span>
354 </a>
355 </td>
356 <td>
357 <a class="tutor-btn tutor-btn-outline-primary tutor-btn-sm">
358 <span class="tutor-icon-copy tutor-mr-8"></span>
359 <span class="tutor-copy-text" data-text="<?php echo esc_attr( $secret ); ?>">
360 <?php echo esc_html( substr( $secret, 0, 9 ) . '...' ); ?>
361 </span>
362 </a>
363 </td>
364 <td>
365 <?php echo esc_html( $permission ); ?>
366 <?php if ( ! empty( $description ) ) : ?>
367 <div class="tooltip-wrap tooltip-icon-custom" >
368 <i class="tutor-fs-7 tutor-icon-circle-info-o tutor-color-muted tutor-ml-4"></i>
369 <span class="tooltip-txt tooltip-bottom">
370 <?php echo esc_textarea( $description ); ?>
371 </span>
372 </div>
373 <?php endif; ?>
374 </td>
375 <td>
376 <div class="tutor-dropdown-parent">
377 <button type="button" class="tutor-iconic-btn" action-tutor-dropdown="toggle">
378 <span class="tutor-icon-kebab-menu" area-hidden="true"></span>
379 </button>
380 <div class="tutor-dropdown tutor-dropdown-dark tutor-text-left">
381 <a href="javascript:void(0)" class="tutor-dropdown-item" data-tutor-modal-target="tutor-update-permission-modal" data-update-id="<?php echo esc_attr( $meta_id ); ?>" data-permission="<?php echo esc_attr( $permission ); ?>" data-description="<?php echo esc_attr( $description ); ?>">
382 <i class="tutor-icon-edit tutor-mr-8" area-hidden="true" data-update-id="<?php echo esc_attr( $meta_id ); ?>" data-permission="<?php echo esc_attr( $permission ); ?>" data-description="<?php echo esc_attr( $description ); ?>"></i>
383 <span data-update-id="<?php echo esc_attr( $meta_id ); ?>" data-permission="<?php echo esc_attr( $permission ); ?>" data-description="<?php echo esc_attr( $description ); ?>"><?php esc_html_e( 'Edit', 'tutor' ); ?></span>
384 </a>
385 <a href="javascript:void(0)" class="tutor-dropdown-item" data-meta-id="<?php echo esc_attr( $meta_id ); ?>">
386 <i class="tutor-icon-trash-can-bold tutor-mr-8" area-hidden="true" data-meta-id="<?php echo esc_attr( $meta_id ); ?>"></i>
387 <span data-meta-id="<?php echo esc_attr( $meta_id ); ?>"><?php esc_html_e( 'Revoke', 'tutor' ); ?></span>
388 </a>
389 </div>
390 </div>
391 </td>
392 </tr>
393 <?php
394 return ob_get_clean();
395 }
396
397 /**
398 * Get available permission
399 *
400 * @since 2.2.1
401 *
402 * @return array
403 */
404 public static function available_permissions(): array {
405 $permissions = array(
406 array(
407 'value' => self::READ,
408 'label' => __( 'Read', 'tutor' ),
409 ),
410 );
411 return apply_filters( 'tutor_rest_api_permissions', $permissions );
412 }
413 }
414