gocodebox/lifterlms-rest

View on GitHub
includes/admin/class-llms-rest-admin-form-controller.php

Summary

Maintainability
A
3 hrs
Test Coverage
B
81%
<?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&section=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&section=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();