PluginProbe
MailPoet – Newsletters, Email Marketing, and Automation / 3.6.2
MailPoet – Newsletters, Email Marketing, and Automation v3.6.2
5.38.0 5.37.0 5.36.1 5.36.0 5.35.1 5.35.0 5.34.3 5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 All 542 releases
mailpoet / lib / API / JSON / API.php

API.php in MailPoet – Newsletters, Email Marketing, and Automation 3.6.2, at lib/API/JSON/API.php

211 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace MailPoet\API\JSON;
3
4 use MailPoet\Config\AccessControl;
5 use MailPoet\Models\Setting;
6 use MailPoet\Util\Helpers;
7 use MailPoet\Util\Security;
8 use MailPoet\WP\Hooks;
9
10 if(!defined('ABSPATH')) exit;
11
12 class API {
13 private $_request_api_version;
14 private $_request_endpoint;
15 private $_request_method;
16 private $_request_token;
17 private $_request_endpoint_class;
18 private $_request_data = array();
19 private $_endpoint_namespaces = array();
20 private $_available_api_versions = array(
21 'v1'
22 );
23 private $access_control;
24 const CURRENT_VERSION = 'v1';
25
26 function __construct(AccessControl $access_control) {
27 $this->access_control = $access_control;
28 foreach($this->_available_api_versions as $available_api_version) {
29 $this->addEndpointNamespace(
30 sprintf('%s\%s', __NAMESPACE__, $available_api_version),
31 $available_api_version
32 );
33 }
34 }
35
36 function init() {
37 // admin security token and API version
38 add_action(
39 'admin_head',
40 array($this, 'setTokenAndAPIVersion')
41 );
42
43 // ajax (logged in users)
44 add_action(
45 'wp_ajax_mailpoet',
46 array($this, 'setupAjax')
47 );
48
49 // ajax (logged out users)
50 add_action(
51 'wp_ajax_nopriv_mailpoet',
52 array($this, 'setupAjax')
53 );
54 }
55
56 function setupAjax() {
57 Hooks::doAction('mailpoet_api_setup', array($this));
58 $this->setRequestData($_POST);
59
60 $ignoreToken = (
61 Setting::getValue('re_captcha.enabled') &&
62 $this->_request_endpoint === 'subscribers' &&
63 $this->_request_method === 'subscribe'
64 );
65
66 if(!$ignoreToken && $this->checkToken() === false) {
67 $error_message = __('Sorry, but we couldn\'t connect to the MailPoet server. Please refresh the web page and try again.', 'mailpoet');
68 $error_response = $this->createErrorResponse(Error::UNAUTHORIZED, $error_message, Response::STATUS_UNAUTHORIZED);
69 return $error_response->send();
70 }
71
72 $response = $this->processRoute();
73 $response->send();
74 }
75
76 function setRequestData($data) {
77 $this->_request_api_version = !empty($data['api_version']) ? $data['api_version']: false;
78
79 $this->_request_endpoint = isset($data['endpoint'])
80 ? Helpers::underscoreToCamelCase(trim($data['endpoint']))
81 : null;
82
83 // JS part of /wp-admin/customize.php does not like a 'method' field in a form widget
84 $method_param_name = isset($data['mailpoet_method']) ? 'mailpoet_method' : 'method';
85 $this->_request_method = isset($data[$method_param_name])
86 ? Helpers::underscoreToCamelCase(trim($data[$method_param_name]))
87 : null;
88
89 $this->_request_token = isset($data['token'])
90 ? trim($data['token'])
91 : null;
92
93 if(!$this->_request_endpoint || !$this->_request_method || !$this->_request_api_version) {
94 $error_message = __('Invalid API request.', 'mailpoet');
95 $error_response = $this->createErrorResponse(Error::BAD_REQUEST, $error_message, Response::STATUS_BAD_REQUEST);
96 return $error_response;
97 } else if(!empty($this->_endpoint_namespaces[$this->_request_api_version])) {
98 foreach($this->_endpoint_namespaces[$this->_request_api_version] as $namespace) {
99 $endpoint_class = sprintf(
100 '%s\%s',
101 $namespace,
102 ucfirst($this->_request_endpoint)
103 );
104 if(class_exists($endpoint_class)) {
105 $this->_request_endpoint_class = $endpoint_class;
106 break;
107 }
108 }
109 $this->_request_data = isset($data['data'])
110 ? stripslashes_deep($data['data'])
111 : array();
112
113 // remove reserved keywords from data
114 if(is_array($this->_request_data) && !empty($this->_request_data)) {
115 // filter out reserved keywords from data
116 $reserved_keywords = array(
117 'token',
118 'endpoint',
119 'method',
120 'api_version',
121 'mailpoet_method', // alias of 'method'
122 'mailpoet_redirect'
123 );
124 $this->_request_data = array_diff_key(
125 $this->_request_data,
126 array_flip($reserved_keywords)
127 );
128 }
129 }
130 }
131
132 function processRoute() {
133 try {
134 if(empty($this->_request_endpoint_class)) {
135 throw new \Exception(__('Invalid API endpoint.', 'mailpoet'));
136 }
137
138 $endpoint = new $this->_request_endpoint_class();
139
140 if(!method_exists($endpoint, $this->_request_method)) {
141 throw new \Exception(__('Invalid API endpoint method.', 'mailpoet'));
142 }
143
144 // check the accessibility of the requested endpoint's action
145 // by default, an endpoint's action is considered "private"
146 if(!$this->validatePermissions($this->_request_method, $endpoint->permissions)) {
147 $error_message = __('You do not have the required permissions.', 'mailpoet');
148 $error_response = $this->createErrorResponse(Error::FORBIDDEN, $error_message, Response::STATUS_FORBIDDEN);
149 return $error_response;
150 }
151 $response = $endpoint->{$this->_request_method}($this->_request_data);
152 return $response;
153 } catch(\Exception $e) {
154 $error_message = $e->getMessage();
155 $error_response = $this->createErrorResponse(Error::BAD_REQUEST, $error_message, Response::STATUS_BAD_REQUEST);
156 return $error_response;
157 }
158 }
159
160 function validatePermissions($request_method, $permissions) {
161 // validate method permission if defined, otherwise validate global permission
162 return(!empty($permissions['methods'][$request_method])) ?
163 $this->access_control->validatePermission($permissions['methods'][$request_method]) :
164 $this->access_control->validatePermission($permissions['global']);
165 }
166
167 function checkToken() {
168 return wp_verify_nonce($this->_request_token, 'mailpoet_token');
169 }
170
171 function setTokenAndAPIVersion() {
172 $global = '<script type="text/javascript">';
173 $global .= 'var mailpoet_token = "%s";';
174 $global .= 'var mailpoet_api_version = "%s";';
175 $global .= '</script>';
176 echo sprintf(
177 $global,
178 Security::generateToken(),
179 self::CURRENT_VERSION
180 );
181 }
182
183 function addEndpointNamespace($namespace, $version) {
184 if(!empty($this->_endpoint_namespaces[$version][$namespace])) return;
185 $this->_endpoint_namespaces[$version][] = $namespace;
186 }
187
188 function getEndpointNamespaces() {
189 return $this->_endpoint_namespaces;
190 }
191
192 function getRequestedEndpointClass() {
193 return $this->_request_endpoint_class;
194 }
195
196 function getRequestedAPIVersion() {
197 return $this->_request_api_version;
198 }
199
200 function createErrorResponse($error_type, $error_message, $response_status) {
201 $error_response = new ErrorResponse(
202 array(
203 $error_type => $error_message
204 ),
205 array(),
206 $response_status
207 );
208 return $error_response;
209 }
210 }
211