diff --git a/assets/js/src/public.js b/assets/js/src/public.js index defbf2e02f..ca97653ed9 100644 --- a/assets/js/src/public.js +++ b/assets/js/src/public.js @@ -40,7 +40,7 @@ function( // ajax request MailPoet.Ajax.post({ url: MailPoetForm.ajax_url, - token: MailPoetForm.token, + token: data.token, endpoint: 'subscribers', action: 'subscribe', data: data diff --git a/lib/API/API.php b/lib/API/API.php index 80b08bc98f..3f3b8a55c6 100644 --- a/lib/API/API.php +++ b/lib/API/API.php @@ -5,6 +5,13 @@ use \MailPoet\Util\Security; if(!defined('ABSPATH')) exit; class API { + private $_endpoint; + private $_method; + private $_token; + + private $_endpoint_class; + private $_data = array(); + function init() { // security token add_action( @@ -26,18 +33,80 @@ class API { } function setupAdmin() { - if($this->checkToken() === false) { + $this->getRequestData(); + $this->checkToken(); + $this->checkPermissions(); + $this->processRoute(); + } + + function setupPublic() { + $this->getRequestData(); + $this->checkToken(); + $this->processRoute(); + } + + function getRequestData() { + $this->_endpoint = isset($_POST['endpoint']) ? trim($_POST['endpoint']) : null; + $this->_method = (isset($_POST['method'])) + ? trim($_POST['method']) + : null; + $this->_token = (isset($_POST['token'])) + ? trim($_POST['token']) + : null; + + if(!$this->_endpoint || !$this->_method || !$this->_token) { + // throw exception bad request $error_response = new ErrorResponse( array( - Error::UNAUTHORIZED => __('You need to specify a valid API token.', 'mailpoet') + Error::BAD_REQUEST => __('Invalid request.', 'mailpoet') ), array(), - Response::STATUS_UNAUTHORIZED + Response::STATUS_BAD_REQUEST + ); + $error_response->send(); + } else { + $this->_endpoint_class = ( + __NAMESPACE__."\\Endpoints\\".ucfirst($this->_endpoint) + ); + + $this->_data = isset($_POST['data']) + ? stripslashes_deep($_POST['data']) + : array(); + + // remove reserved keywords from data + if(is_array($this->_data) && !empty($this->_data)) { + // filter out reserved keywords from data + $reserved_keywords = array( + 'token', + 'endpoint', + 'method', + 'mailpoet_redirect' + ); + $this->_data = array_diff_key( + $this->_data, + array_flip($reserved_keywords) + ); + } + } + } + + function processRoute() { + try { + $endpoint = new $this->_endpoint_class(); + $response = $endpoint->{$this->_method}($this->_data); + $response->send(); + } catch(\Exception $e) { + $error_response = new ErrorResponse( + array($e->getCode() => $e->getMessage()) ); $error_response->send(); } + } - if($this->checkPermissions() === false) { + function checkPermissions() { + $has_permission = current_user_can('manage_options'); + + if($has_permission === false) { $error_response = new ErrorResponse( array( Error::FORBIDDEN => __('You do not have the required permissions.', 'mailpoet') @@ -47,52 +116,23 @@ class API { ); $error_response->send(); } - - $this->processRoute(); } - function setupPublic() { - if($this->checkToken() === false) { + function checkToken() { + $action = $this->_endpoint.'_'.$this->_method; + + $is_valid_token = wp_verify_nonce($this->_token, $action); + + if($is_valid_token === false) { $error_response = new ErrorResponse( array( - Error::UNAUTHORIZED => __('You need to specify a valid API token.', 'mailpoet') + Error::UNAUTHORIZED => __('Invalid request.', 'mailpoet') ), array(), Response::STATUS_UNAUTHORIZED ); $error_response->send(); } - - $this->processRoute(); - } - - function processRoute() { - $class = ucfirst($_POST['endpoint']); - $endpoint = __NAMESPACE__ . "\\Endpoints\\" . $class; - $method = $_POST['method']; - $data = isset($_POST['data']) ? stripslashes_deep($_POST['data']) : array(); - - if(is_array($data) && !empty($data)) { - // filter out reserved keywords from data - $reserved_keywords = array( - 'token', - 'endpoint', - 'method', - 'mailpoet_redirect' - ); - $data = array_diff_key($data, array_flip($reserved_keywords)); - } - - try { - $endpoint = new $endpoint(); - $response = $endpoint->$method($data); - $response->send(); - } catch(\Exception $e) { - $error_response = new ErrorResponse( - array($e->getCode() => $e->getMessage()) - ); - $error_response->send(); - } } function setToken() { @@ -101,16 +141,4 @@ class API { $global .= ''; echo $global; } - - function checkPermissions() { - return current_user_can('manage_options'); - } - - function checkToken() { - return ( - isset($_POST['token']) - && - wp_verify_nonce($_POST['token'], 'mailpoet_token') - ); - } } \ No newline at end of file diff --git a/lib/Config/Widget.php b/lib/Config/Widget.php index 67e5a65d31..30d21f17f4 100644 --- a/lib/Config/Widget.php +++ b/lib/Config/Widget.php @@ -69,8 +69,7 @@ class Widget { 'form' => $form_html, 'mailpoet_form' => array( 'ajax_url' => admin_url('admin-ajax.php', 'absolute'), - 'is_rtl' => $is_rtl, - 'token' => Security::generateToken() + 'is_rtl' => $is_rtl ) ); @@ -103,8 +102,7 @@ class Widget { wp_localize_script('mailpoet_public', 'MailPoetForm', array( 'ajax_url' => admin_url('admin-ajax.php'), - 'is_rtl' => (function_exists('is_rtl') ? (bool)is_rtl() : false), - 'token' => Security::generateToken() + 'is_rtl' => (function_exists('is_rtl') ? (bool)is_rtl() : false) )); } diff --git a/lib/Form/Widget.php b/lib/Form/Widget.php index ab06584387..c4d61755b7 100644 --- a/lib/Form/Widget.php +++ b/lib/Form/Widget.php @@ -161,7 +161,7 @@ class Widget extends \WP_Widget { ); // generate security token - $data['token'] = Security::generateToken(); + $data['token'] = Security::generateToken('subscribers_subscribe'); // render form $renderer = new Renderer(); diff --git a/lib/Util/Security.php b/lib/Util/Security.php index 9fdfb2624f..f916df25b7 100644 --- a/lib/Util/Security.php +++ b/lib/Util/Security.php @@ -5,8 +5,8 @@ if(!defined('ABSPATH')) exit; require_once(ABSPATH . 'wp-includes/pluggable.php'); class Security { - static function generateToken() { - return wp_create_nonce('mailpoet_token'); + static function generateToken($action = 'mailpoet_token') { + return wp_create_nonce($action); } static function generateRandomString($length = 5) {