includes/admin/class-llms-rest-admin-form-controller.php
<?php
/**
* Handle admin form submissions
*
* @package LifterLMS_REST/Admin/Classes
*
* @since 1.0.0-beta.1
* @version 1.0.0-beta.27
*/
defined( 'ABSPATH' ) || exit;
/**
* LLMS_REST_Admin_Form_Controller class.
*
* @since 1.0.0-beta.1
* @since 1.0.0-beta.3 Added API credential download methods.
*/
class LLMS_REST_Admin_Form_Controller {
/**
* Constructor.
*
* @since 1.0.0-beta.1
*
* @return void
*/
public function __construct() {
add_action( 'admin_init', array( $this, 'handle_events' ) );
}
/**
* Handles submission of admin forms & nonce links.
*
* @since 1.0.0-beta.1
* @since 1.0.0-beta.3 Added logic for handling api key txt download via nonce link.
*
* @return false|void
*/
public function handle_events() {
if ( llms_verify_nonce( 'key-revoke-nonce', 'revoke', 'GET' ) ) {
$delete = LLMS_REST_API()->keys()->delete( llms_filter_input( INPUT_GET, 'revoke-key', FILTER_VALIDATE_INT ) );
if ( $delete ) {
LLMS_Admin_Notices::flash_notice( esc_html__( 'The API Key has been successfully deleted.', 'lifterlms' ), 'success' );
return llms_redirect_and_exit( admin_url( 'admin.php?page=llms-settings&tab=rest-api§ion=keys' ) );
}
} elseif ( llms_verify_nonce( 'llms_rest_webhook_nonce', 'create-update-webhook', 'POST' ) ) {
return $this->handle_webhook_upsert();
} elseif ( llms_verify_nonce( 'delete-webhook-nonce', 'delete', 'GET' ) ) {
$delete = LLMS_REST_API()->webhooks()->delete( llms_filter_input( INPUT_GET, 'delete-webhook', FILTER_VALIDATE_INT ) );
if ( $delete ) {
LLMS_Admin_Notices::flash_notice( esc_html__( 'The webhook has been successfully deleted.', 'lifterlms' ), 'success' );
return llms_redirect_and_exit( admin_url( 'admin.php?page=llms-settings&tab=rest-api§ion=webhooks' ) );
}
} elseif ( llms_verify_nonce( 'dl-key-nonce', 'dl-key', 'GET' ) ) {
return $this->handle_key_download();
}
return false;
}
/**
* Generate and download a api key credentials file.
*
* @since 1.0.0-beta.3
*
* @return false|void
*/
protected function handle_key_download() {
$info = $this->prepare_key_download();
if ( ! $info ) {
return false;
}
header( 'Content-type: text/plain' );
header( 'Content-Disposition: attachment; filename="' . $info['fn'] );
header( 'Pragma: no-cache' );
header( 'Expires: 0' );
// Translators: %s = Consumer Key.
printf( esc_html__( 'Consumer Key: %s', 'lifterlms' ), esc_html( $info['ck'] ) );
echo "\r\n";
// Translators: %s = Consumer Secret.
printf( esc_html__( 'Consumer Secret: %s', 'lifterlms' ), esc_html( $info['cs'] ) );
die();
}
/**
* Handle creating/updating a webhook via admin interfaces.
*
* @since 1.0.0-beta.1
* @since 1.0.0-beta.27 Replaced use of the deprecated `FILTER_SANITIZE_STRING` constant.
*
* @return true|void|WP_Error true on update success, void (redirect) on creation success, WP_Error on failure.
*/
protected function handle_webhook_upsert() {
$data = array(
'name' => llms_filter_input_sanitize_string( INPUT_POST, 'llms_rest_webhook_name' ),
'status' => llms_filter_input_sanitize_string( INPUT_POST, 'llms_rest_webhook_status' ),
'topic' => llms_filter_input_sanitize_string( INPUT_POST, 'llms_rest_webhook_topic' ),
'delivery_url' => llms_filter_input( INPUT_POST, 'llms_rest_webhook_delivery_url', FILTER_SANITIZE_URL ),
'secret' => llms_filter_input_sanitize_string( INPUT_POST, 'llms_rest_webhook_secret' ),
);
if ( 'action' === $data['topic'] ) {
$data['topic'] .= '.' . llms_filter_input_sanitize_string( INPUT_POST, 'llms_rest_webhook_action' );
}
$hook_id = llms_filter_input( INPUT_POST, 'llms_rest_webhook_id', FILTER_SANITIZE_NUMBER_INT );
if ( ! $hook_id ) {
$hook = LLMS_REST_API()->webhooks()->create( $data );
if ( ! is_wp_error( $hook ) ) {
return llms_redirect_and_exit( $hook->get_edit_link(), array( 'status' => 301 ) );
}
} else {
$hook = LLMS_REST_API()->webhooks()->get( $hook_id );
if ( ! $hook ) {
// Translators: %s = Webhook ID.
$hook = new WP_Error( 'llms_rest_api_webhook_not_found', sprintf( __( '"%s" is not a valid Webhook.', 'lifterlms' ), $hook_id ) );
} else {
$data['id'] = $hook_id;
$hook = LLMS_REST_API()->webhooks()->update( $data );
}
}
if ( is_wp_error( $hook ) ) {
// Translators: %1$s = error message; %2$s = error code.
LLMS_Admin_Notices::flash_notice( sprintf( __( 'Error: %1$s [Code: %2$s]', 'lifterlms' ), $hook->get_error_message(), $hook->get_error_code() ), 'error' );
return $hook;
}
return true;
}
/**
* Validates `GET` information from the credential download URL and prepares information for generating the file.
*
* @since 1.0.0-beta.3
* @since 1.0.0-beta.27 Replaced use of the deprecated `FILTER_SANITIZE_STRING` constant.
*
* @return false|array
*/
protected function prepare_key_download() {
$key_id = llms_filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
$consumer_key = llms_filter_input_sanitize_string( INPUT_GET, 'ck' );
// return if missing required fields.
if ( ! $key_id || ! $consumer_key ) {
return false;
}
// return if key doesn't exist.
$key = LLMS_REST_API()->keys()->get( $key_id );
if ( ! $key ) {
return false;
}
// validate the decoded consumer key looks like the stored truncated key.
$consumer_key = base64_decode( $consumer_key ); //phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -- This is benign usage.
if ( substr( $consumer_key, -7 ) !== $key->get( 'truncated_key' ) ) {
return false;
}
return array(
'fn' => sanitize_file_name( $key->get( 'description' ) ) . '.txt',
'ck' => $consumer_key,
'cs' => $key->get( 'consumer_secret' ),
);
}
}
return new LLMS_REST_Admin_Form_Controller();