PluginProbe
PowerPress Podcasting plugin by Blubrry / trunk
PowerPress Podcasting plugin by Blubrry vtrunk
11.17.9 11.17.8 11.17.7 11.17.6 11.17.4 11.17.3 11.17.2 11.17.1 11.17 11.16.11 11.16.10 11.16.9 11.16.8 11.16.7 11.16.6 11.16.5 11.16.4 11.16.3 11.16.2 11.16.1 11.9.13 11.9.14 11.9.15 11.9.16 11.9.17 All 383 releases
powerpress / powerpressadmin-auth.class.php

powerpressadmin-auth.class.php in PowerPress Podcasting plugin by Blubrry trunk, at powerpressadmin-auth.class.php

391 lines 15.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 PowerPressAuth library for WordPress (copied & pasted from Network plugin)
4
5 If curl is enabled, the WordPress functions are not used, allowing this class to work without WordPress
6 */
7
8
9 class PowerPressAuth {
10
11 // Error handling
12 var $error = '';
13 var $errorCode = 0;
14
15 // API call URLs, can loop through for failures
16 var $apiUrl = array('https://api.blubrry.com/');
17 var $apiUrlIndex = 0;
18
19 function __construct() {
20
21 if( defined('POWERPRESS_BLUBRRY_API_URL') ) {
22 if( strstr(POWERPRESS_BLUBRRY_API_URL, 'http://api.blubrry.com') == false ) // If not the default
23 {
24 $this->apiUrl = explode(';', POWERPRESS_BLUBRRY_API_URL);
25 }
26 else
27 {
28 $this->apiUrl[] = 'https://api.blubrry.com/'; // Use secure URL first when possible
29 $this->apiUrl[] = 'http://api.blubrry.net/';
30 $this->apiUrl[] = 'http://api.blubrry.com/';
31 }
32 }
33 }
34
35 function getApiUrl()
36 {
37 return $this->apiUrl[ $this->apiUrlIndex ];
38 }
39
40 function getDebugInfo() {
41 $str = '';
42 $str .= "API URLs:<br>\n";
43 $str .= "<pre>". print_r($this->apiUrl, true) . "</pre>\n";
44 return $str;
45 }
46
47 function getLastError() {
48 return $this->error;
49 }
50
51 function getLastErrorCode() {
52 return $this->errorCode;
53 }
54
55 function setApiUrl($url) {
56 $this->apiUrlIndex = 0;
57 $this->apiUrl = array($url);
58 }
59
60
61 function getTemporaryCredentials()
62 {
63 $requestUrl = $this->apiUrl[ $this->apiUrlIndex ] . "client/temporary?cache=" . md5( rand(0, 999) . time() );
64 $return = $this->_makeApiCall($requestUrl);
65 while( $return === false && $this->_retryApiUrl() ) {
66 $requestUrl = $this->apiUrl[ $this->apiUrlIndex ] . "client/temporary?cache=" . md5( rand(0, 999) . time() );
67 $return = $this->_makeApiCall($requestUrl);
68 }
69 return $return;
70 }
71
72 function issueClient($code, $clientId, $clientSecret, $redirectUri = '')
73 {
74 $requestUrl = $this->apiUrl[ $this->apiUrlIndex ] . 'client/issue?client_id=' . urlencode($clientId) . '&client_secret=' . urlencode($clientSecret) . '&code=' . urlencode($code) . '&redirect_uri='. urlencode($redirectUri);
75 $return = $this->_makeApiCall($requestUrl);
76 while( $return === false && $this->_retryApiUrl() ) {
77 $requestUrl = $this->apiUrl[ $this->apiUrlIndex ] . 'client/issue?client_id=' . urlencode($clientId) . '&client_secret=' . urlencode($clientSecret) . '&code=' . urlencode($code) . '&redirect_uri='. urlencode($redirectUri);
78 $return = $this->_makeApiCall($requestUrl);
79 }
80 return $return;
81 }
82
83 function getAccessTokenFromCode($code, $clientId, $clientSecret, $redirectUri ='')
84 {
85 $clientAuth = base64_encode("$clientId:$clientSecret");
86 $requestUrl = $this->apiUrl[ $this->apiUrlIndex ] . 'oauth2/token';
87 $post = array();
88 $post['grant_type'] = 'authorization_code';
89 $post['code'] = $code;
90 $post['redirect_uri'] = urlencode($redirectUri);
91 $return = $this->_makeApiCall($requestUrl, $post, $clientAuth);
92 while( $return === false && $this->_retryApiUrl() ) {
93 $requestUrl = $this->apiUrl[ $this->apiUrlIndex ] . 'oauth2/token';
94 $return = $this->_makeApiCall($requestUrl, $post, $clientAuth);
95 }
96 return $return;
97 }
98
99 function getAccessTokenFromRefreshToken($refreshToken, $clientId, $clientSecret, $redirectUri ='')
100 {
101 $clientAuth = base64_encode("$clientId:$clientSecret");
102 $post['grant_type'] = 'refresh_token';
103 $post['refresh_token'] = $refreshToken;
104 $post['redirect_uri'] = $redirectUri;
105 $requestUrl = $this->apiUrl[ $this->apiUrlIndex ] . 'oauth2/token';
106 $return = $this->_makeApiCall($requestUrl, $post, $clientAuth);
107 while( $return === false && $this->_retryApiUrl() ) {
108 $requestUrl = $this->apiUrl[ $this->apiUrlIndex ] . 'oauth2/token';
109 $return = $this->_makeApiCall($requestUrl, $post, $clientAuth);
110 }
111 return $return;
112 }
113
114 function reSendVerifyEmail() {
115 $creds = get_option('powerpress_creds');
116 $path = '/account/create-status?client_id=' . urlencode($creds['client_id']) . '&email=true';
117 return $this->api('', $path);
118 }
119
120 function checkAccountVerified() {
121 $creds = get_option('powerpress_creds');
122 $accessToken = !empty($creds['access_token']) ? $creds['access_token'] : '';
123 $path = '/account/create-status?cache=' . md5( rand(0, 999) . time() ) . '&client_id=' . urlencode($creds['client_id']);
124 return $this->api($accessToken, $path);
125 }
126
127 function revokeClient($accessToken, $clientID, $clientSecret) {
128 $path = '/client/revoke?client_id=' . urlencode($clientID) . '&client_secret=' . urlencode($clientSecret);
129 return $this->api($accessToken, $path, array('client_id' => $clientID, 'client_secret' => $clientSecret));
130 }
131
132 function api($accessToken, $path, $post = false, $custom_request = false, $timeout = 15, $decode_json = true, $encode_json = false )
133 {
134 $requestUrl = $this->apiUrl[ $this->apiUrlIndex ] . ltrim($path, '/'); // Make sure prefix slash is removed
135 $return = $this->_makeApiCall($requestUrl, $post, false, $accessToken, $custom_request, $timeout, $decode_json, $encode_json);
136 while( $return === false && $this->_retryApiUrl() ) {
137 $requestUrl = $this->apiUrl[ $this->apiUrlIndex ] . ltrim($path, '/'); // Make sure prefix slash is removed
138 $return = $this->_makeApiCall($requestUrl, $post, false, $accessToken, $custom_request, $timeout, $decode_json, $encode_json);
139 }
140 return $return;
141 }
142
143 /*
144 * Allows us to somewhat cleanly send multi-dimensional arrays over curl (still takes some parsing API-side)
145 * https://stackoverflow.com/questions/3772096/posting-multidimensional-array-with-php-and-curl
146 */
147 function http_build_query_for_curl( $arrays, &$new = array(), $prefix = null ) {
148
149 if ( is_object( $arrays ) ) {
150 $arrays = get_object_vars( $arrays );
151 }
152
153 foreach ( $arrays AS $key => $value ) {
154 $k = isset( $prefix ) ? $prefix . '[' . $key . ']' : $key;
155 if ( is_array( $value ) OR is_object( $value ) ) {
156 $this->http_build_query_for_curl( $value, $new, $k );
157 } else {
158 $new[$k] = $value;
159 }
160 }
161 }
162
163 private function _makeApiCallCurl($url, $post = false, $clientCredsBase64 = false, $bearerValue = '', $custom_request = false, $timeout = 15, $decode_json = true, $encode_json = false ) {
164
165 $curl = curl_init();
166 if ( version_compare( PHP_VERSION, '5.5.0') > 0 )
167 curl_reset($curl);
168 curl_setopt($curl, CURLOPT_URL, $url);
169 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
170 curl_setopt($curl, CURLOPT_HEADER, 0);
171 curl_setopt( $curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1 );
172
173 if ( version_compare( PHP_VERSION, '5.3.0') < 0 )
174 {
175 curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // Follow location redirection
176 curl_setopt($curl, CURLOPT_MAXREDIRS, 12); // Location redirection limit
177 }
178 else if ( !ini_get('open_basedir') )
179 {
180 curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // Follow location redirection
181 curl_setopt($curl, CURLOPT_MAXREDIRS, 12); // Location redirection limit
182 }
183 else // open_basedir is set, bummer
184 {
185 curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
186 curl_setopt($curl, CURLOPT_MAXREDIRS, 0 );
187 }
188
189 curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 2 ); // Connect time out
190 curl_setopt($curl, CURLOPT_TIMEOUT, $timeout); // The maximum number of seconds to execute.
191 curl_setopt($curl, CURLOPT_USERAGENT, 'Blubrry PowerPress/'.POWERPRESS_VERSION);
192 curl_setopt($curl, CURLOPT_FAILONERROR, false);
193 if( preg_match('/^https:\/\//i', $url) != 0 )
194 {
195 if( file_exists(ABSPATH . WPINC . '/certificates/ca-bundle.crt') ) {
196 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2 );
197 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true );
198 curl_setopt($curl, CURLOPT_CAINFO, ABSPATH . WPINC . '/certificates/ca-bundle.crt');
199 } else {
200 // Trust the SSL certs, not ideal but we don't have the bundle
201 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
202 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
203 }
204 }
205 // HTTP Authentication
206 if( !empty($clientCredsBase64) )
207 {
208 curl_setopt( $curl, CURLOPT_HTTPHEADER, array('Authorization: Basic '.$clientCredsBase64) );
209 } else if( !empty($bearerValue) ) {
210 curl_setopt( $curl, CURLOPT_HTTPHEADER, array('Authorization: Bearer '.$bearerValue) );
211 }
212
213 // Handle post data
214 if ($encode_json && is_array($post)) {
215 $post_query = array();
216 $this->http_build_query_for_curl($post, $post_query);
217 curl_setopt($curl, CURLOPT_POST, 1);
218 curl_setopt($curl, CURLOPT_POSTFIELDS, $post_query);
219 } elseif( is_array($post) && count($post) > 0 )
220 {
221 $post_query = '';
222 foreach( $post as $name => $value )
223 {
224 if( $post_query != '' )
225 $post_query .= '&';
226 $post_query .= $name;
227 $post_query .= '=';
228 $post_query .= urlencode($value);
229 }
230 curl_setopt($curl, CURLOPT_POST, 1);
231 curl_setopt($curl, CURLOPT_POSTFIELDS, $post_query);
232 }
233 else if( $custom_request )
234 {
235 curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $custom_request);
236 }
237
238 $returnedBody = curl_exec($curl);
239 $error = curl_errno($curl);
240 $error_msg = curl_error($curl);
241 $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
242 if (version_compare(PHP_VERSION, '8.0', '<')) {
243 curl_close($curl);
244 } else {
245 unset($curl);
246 }
247
248 if( $error ) // Curl level error, lets deal with it...
249 {
250 $this->error = $error_msg;
251 $this->errorCode = $error;
252 return false;
253 }
254 else if( $http_code > 399 ) // HTTP level error, lets record it and see if the response is what we want to use...
255 {
256 $this->error = "HTTP $http_code";
257 $this->errorCode = $http_code;
258 switch( $http_code )
259 {
260 case 400: $this->error .= ' '. __("Bad Request", 'powerpress'); break;
261 case 401: $this->error .= ' '. __("Unauthorized (Check that your username and password are correct)", 'powerpress'); break;
262 case 402: $this->error .= ' '. __("Payment Required", 'powerpress'); break;
263 case 403: $this->error .= ' '. __("Forbidden", 'powerpress'); break;
264 case 404: $this->error .= ' '. __("Not Found", 'powerpress'); break;
265 }
266 }
267
268 if( !empty($returnedBody) ) {
269 if ($decode_json) {
270 $decoded = @json_decode($returnedBody, true);
271 // json decode
272 if ($decoded !== false && json_last_error() === JSON_ERROR_NONE)
273 return $decoded;
274 } else {
275 return $returnedBody;
276 }
277
278 // json decode returned empty/null, capture raw body as error context
279 $preview = substr(trim($returnedBody), 0, 200);
280 $this->error = $this->errorCode != 0
281 ? 'Unable to decode response.'
282 : "Unexpected API response: {$preview}";
283 $this->errorCode = -1;
284 return false;
285 }
286
287 $this->error = 'Empty response from API.';
288 $this->errorCode = -1;
289 return false;
290 }
291
292 private function _makeApiCall($url, $post = false, $clientCredsBase64 = false, $bearerValue = '', $custom_request = false, $timeout = 15, $decode_json = true, $encode_json = false) {
293
294 // Reset the errors
295 $this->error = '';
296 $this->errorCode = 0;
297 if( function_exists('curl_init') ) // If using CURL, better handling of errors
298 return $this->_makeApiCallCurl($url, $post, $clientCredsBase64, $bearerValue, $custom_request, $timeout, $decode_json, $encode_json);
299
300 if( !function_exists('wp_remote_post') ) {
301 $this->error = 'WordPress or curl library required.';
302 $this->errorCode = -1;
303 return false;
304 }
305
306 $options = array();
307 $options['timeout'] = $timeout;
308 $options['user-agent'] = 'Blubrry PowerPress/'.POWERPRESS_VERSION;
309 if( !empty($clientCredsBase64) )
310 $options['headers']['Authorization'] = 'Basic '.$clientCredsBase64;
311 else if( !empty($bearerValue) )
312 $options['headers']['Authorization'] = 'Bearer '.$bearerValue;
313
314 if( !empty($post) ) {
315 if ($encode_json) {
316 $options['body'] = json_encode($post);
317 } else {
318 $options['body'] = $post;
319 }
320 $response = wp_remote_post( $url, $options );
321 } else if($custom_request) {
322 $options['method'] = $custom_request;
323 $response = wp_remote_request($url,$options);
324 } else
325 {
326 $response = wp_remote_get( $url, $options );
327 }
328
329 if ( is_wp_error( $response ) )
330 {
331 $this->errorCode = $response->get_error_code();
332 $this->error = $response->get_error_message();
333 return false;
334 }
335
336 if( !empty($response['body']) )
337 $returnedBody = $response['body'];
338 else
339 $returnedBody = '';
340
341 if( isset($response['response']['code']) && $response['response']['code'] > 399 )
342 {
343 $this->error = "HTTP ".$response['response']['code'];
344 $this->errorCode = $response['response']['code'];
345 switch( $response['response']['code'] )
346 {
347 case 400: $this->error .= ' '. __("Bad Request", 'powerpress'); break;
348 case 401: $this->error .= ' '. __("Unauthorized (Check that your username and password are correct)", 'powerpress'); break;
349 case 402: $this->error .= ' '. __("Payment Required", 'powerpress'); break;
350 case 403: $this->error .= ' '. __("Forbidden", 'powerpress'); break;
351 case 404: $this->error .= ' '. __("Not Found", 'powerpress'); break;
352 default: $this->error .= ' '.$response['response']['message'];
353 }
354 }
355
356 if( !empty($returnedBody) ) {
357 if ($decode_json) {
358 $decoded = @json_decode($returnedBody, true);
359 if ($decoded !== false) {
360 return $decoded;
361 }
362 } else {
363 return $returnedBody;
364 }
365
366 if( $this->errorCode != 0 ) {
367 $this->error = 'Unable to decode response.';
368 $this->errorCode = -1;
369 }
370 return false;
371 }
372
373 if( !empty($returnedBody) )
374 $this->error = $returnedBody;
375 else
376 $this->error = 'Unknown error occurred.';
377 $this->errorCode = -1;
378 return false;
379 }
380
381 private function _retryApiUrl() {
382 if( ($this->apiUrlIndex+1) < count($this->apiUrl) ) {
383 // Retry using the next indexed API url
384 $this->apiUrlIndex++;
385 return true;
386 }
387 return false;
388 }
389 } // end of class
390
391 // eof