Added default values and soem network related helpers
This commit is contained in:
parent
f5a781d416
commit
d651feb33d
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"com.thorlaksson.phpcs.runOnChange" : "onSave",
|
"com.thorlaksson.phpcs.runOnChange" : "onSave",
|
||||||
"com.thorlaksson.phpcs.standard" : "\/Volumes\/Alyx\/Users\/max\/Dev\/Pnut\/Untitled\/phpcs.xml",
|
"com.thorlaksson.phpcs.standard" : "\/Volumes\/Alyx\/System\/Volumes\/Update\/mnt1\/Users\/max\/Dev\/Pnut\/APnutI\/phpcs.xml",
|
||||||
"editor.default_syntax" : "php",
|
"editor.default_syntax" : "php",
|
||||||
"php.validate" : "onSave",
|
"php.validate" : "onSave",
|
||||||
"workspace.color" : 1,
|
"workspace.color" : 1,
|
||||||
|
236
src/APnutI.php
236
src/APnutI.php
@ -4,6 +4,11 @@ namespace APnutI;
|
|||||||
|
|
||||||
use APnutI\Entities\Post;
|
use APnutI\Entities\Post;
|
||||||
use APnutI\Entities\User;
|
use APnutI\Entities\User;
|
||||||
|
use APnutI\Exceptions\PnutException;
|
||||||
|
use APnutI\Exceptions\NotFoundException;
|
||||||
|
use APnutI\Exceptions\NotAuthorizedException;
|
||||||
|
use APnutI\Exceptions\HttpPnutException;
|
||||||
|
use APnutI\Exceptions\HttpPnutRedirectException;
|
||||||
use APnutI\Meta;
|
use APnutI\Meta;
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
use Monolog\Handler\RotatingFileHandler;
|
use Monolog\Handler\RotatingFileHandler;
|
||||||
@ -16,12 +21,12 @@ class APnutI
|
|||||||
protected string $auth_url = 'https://pnut.io/oauth/authenticate';
|
protected string $auth_url = 'https://pnut.io/oauth/authenticate';
|
||||||
protected string $client_secret;
|
protected string $client_secret;
|
||||||
protected string $client_id;
|
protected string $client_id;
|
||||||
protected string $scope;
|
protected string $scope = "";
|
||||||
protected string $redirect_uri;
|
protected string $redirect_uri;
|
||||||
protected $rate_limit = null;
|
protected int $rate_limit = 40;
|
||||||
protected $rate_limit_remaining = null;
|
protected int $rate_limit_remaining = 40;
|
||||||
protected $rate_limit_rset = null;
|
protected int $rate_limit_reset = 60;
|
||||||
protected $scopes;
|
protected array $scopes = [];
|
||||||
protected ?string $needed_scope;
|
protected ?string $needed_scope;
|
||||||
protected ?string $redirect_target = null;
|
protected ?string $redirect_target = null;
|
||||||
protected array $headers = [];
|
protected array $headers = [];
|
||||||
@ -74,4 +79,225 @@ class APnutI
|
|||||||
$this->logger->debug('No access token in session');
|
$this->logger->debug('No access token in session');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function, parses out important information pnut.io adds
|
||||||
|
* to the headers. Mostly taken from PHPnut
|
||||||
|
*/
|
||||||
|
protected function parseHeaders(string $response): string
|
||||||
|
{
|
||||||
|
// take out the headers
|
||||||
|
// set internal variables
|
||||||
|
// return the body/content
|
||||||
|
$this->rate_limit = null;
|
||||||
|
$this->rate_limit_remaining = null;
|
||||||
|
$this->rate_limit_reset = null;
|
||||||
|
$this->scope = [];
|
||||||
|
$response = explode("\r\n\r\n", $response, 2);
|
||||||
|
$headers = $response[0];
|
||||||
|
if ($headers === 'HTTP/1.1 100 Continue') {
|
||||||
|
$response = explode("\r\n\r\n", $response[1], 2);
|
||||||
|
$headers = $response[0];
|
||||||
|
}
|
||||||
|
if (isset($response[1])) {
|
||||||
|
$content = $response[1];
|
||||||
|
} else {
|
||||||
|
$content = '';
|
||||||
|
}
|
||||||
|
// this is not a good way to parse http headers
|
||||||
|
// it will not (for example) take into account multiline headers
|
||||||
|
// but what we're looking for is pretty basic, so we can ignore those shortcomings
|
||||||
|
$this->headers = explode("\r\n", $headers);
|
||||||
|
foreach ($this->headers as $header) {
|
||||||
|
$header = explode(': ', $header, 2);
|
||||||
|
if (count($header) < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
list($k,$v) = $header;
|
||||||
|
switch ($k) {
|
||||||
|
case 'X-RateLimit-Remaining':
|
||||||
|
$this->rate_limit_remaining = (int)$v;
|
||||||
|
break;
|
||||||
|
case 'X-RateLimit-Limit':
|
||||||
|
$this->rate_limit = (int)$v;
|
||||||
|
break;
|
||||||
|
case 'X-RateLimit-Reset':
|
||||||
|
$this->rate_limit_reset = (int)$v;
|
||||||
|
break;
|
||||||
|
case 'X-OAuth-Scopes':
|
||||||
|
$this->scope = (int)$v;
|
||||||
|
$this->scopes = explode(',', (int)$v);
|
||||||
|
break;
|
||||||
|
case 'location':
|
||||||
|
case 'Location':
|
||||||
|
$this->redirectTarget = (int)$v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function makeRequest(
|
||||||
|
string $method,
|
||||||
|
string $end_point,
|
||||||
|
array $parameters,
|
||||||
|
string $content_type = 'application/x-www-form-urlencoded'
|
||||||
|
): string {
|
||||||
|
|
||||||
|
$this->redirect_target = null;
|
||||||
|
$this->meta = null;
|
||||||
|
$method = strtoupper($method);
|
||||||
|
$url = $this->api_url.$end_point;
|
||||||
|
$this->logger->info("{$method} Request to {$url}");
|
||||||
|
$ch = curl_init($url);
|
||||||
|
$headers = [];
|
||||||
|
$use_server_token = false;
|
||||||
|
if ($method !== 'GET') {
|
||||||
|
// if they passed an array, build a list of parameters from it
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
if (is_array($parameters) && $method !== 'POST-RAW') {
|
||||||
|
$parameters = http_build_query($parameters);
|
||||||
|
}
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters);
|
||||||
|
$headers[] = "Content-Type: ".$content_type;
|
||||||
|
}
|
||||||
|
if ($method !== 'POST' && $method !== 'POST-RAW') {
|
||||||
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||||
|
}
|
||||||
|
if ($method === 'GET' && isset($parameters['access_token'])) {
|
||||||
|
$headers[] = 'Authorization: Bearer '.$params['access_token'];
|
||||||
|
} elseif (!empty($this->access_token)) {
|
||||||
|
$headers[] = 'Authorization: Bearer '.$this->access_token;
|
||||||
|
} elseif (!empty($this->server_token)) {
|
||||||
|
$use_server_token = true;
|
||||||
|
$this->logger->info("Using server token for auth");
|
||||||
|
$headers[] = 'Authorization: Bearer '.$this->server_token;
|
||||||
|
}
|
||||||
|
#$this->logger->info("Access token: ".$this->access_token);
|
||||||
|
#$this->logger->info("Headers: ".json_encode($headers));
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
|
||||||
|
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$request = curl_getinfo($ch, CURLINFO_HEADER_OUT);
|
||||||
|
$http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$effectiveURL = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
|
||||||
|
curl_close($ch);
|
||||||
|
if ($http_status === 0) {
|
||||||
|
throw new Exception('Unable to connect to Pnut ' . $url);
|
||||||
|
}
|
||||||
|
if ($request === false) {
|
||||||
|
if (!curl_getinfo($ch, CURLINFO_SSL_VERIFYRESULT)) {
|
||||||
|
throw new Exception('SSL verification failed, connection terminated: ' . $url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($response)) {
|
||||||
|
$response = $this->parseHeaders($response);
|
||||||
|
if (!empty($response)) {
|
||||||
|
$response = json_decode($response, true);
|
||||||
|
try {
|
||||||
|
$this->meta = new Meta($response);
|
||||||
|
} catch (NotAuthorizedException $nae) {
|
||||||
|
$headers_string = print_r($this->headers, true);
|
||||||
|
$this->logger->error("Error, not authorized: {$nae->getMessage()}");
|
||||||
|
$this->logger->error("Headers: {$headers_string}");
|
||||||
|
# Force re-auth
|
||||||
|
if (!$use_server_token) {
|
||||||
|
$this->logout();
|
||||||
|
}
|
||||||
|
throw $nae;
|
||||||
|
} catch (PnutException $pe) {
|
||||||
|
$response_headers_string = print_r($this->headers, true);
|
||||||
|
$request_headers_string = print_r($headers, true);
|
||||||
|
$parameters_string = print_r($parameters, true);
|
||||||
|
$this->logger->error("Error, no authorized: {$pe->getMessage()}");
|
||||||
|
$this->logger->error("Method: {$method}");
|
||||||
|
$this->logger->error("Parameters: {$parameters_string}");
|
||||||
|
$this->logger->error("Request headers: {$request_headers_string}");
|
||||||
|
$this->logger->error("Response headers: {$response_headers_string}");
|
||||||
|
throw $pe;
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for errors
|
||||||
|
if (isset($response['error'])) {
|
||||||
|
if (is_array($response['error'])) {
|
||||||
|
throw new PnutException($response['error']['message'], $response['error']['code']);
|
||||||
|
} else {
|
||||||
|
throw new PnutException($response['error']);
|
||||||
|
}
|
||||||
|
// look for response migration errors
|
||||||
|
} elseif (isset($response['meta'], $response['meta']['error_message'])) {
|
||||||
|
throw new PnutException($response['meta']['error_message'], $response['meta']['code']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($http_status < 200 || $http_status >= 300) {
|
||||||
|
if ($http_status == 302) {
|
||||||
|
#echo json_encode(preg_match_all('/^Location:(.*)$/mi', $response, $matches));
|
||||||
|
throw new HttpPnutRedirectException($response);
|
||||||
|
} else {
|
||||||
|
throw new HttpPnutException('HTTP error '.$http_status);
|
||||||
|
}
|
||||||
|
} elseif (isset($response['meta'], $response['data'])) {
|
||||||
|
return $response['data'];
|
||||||
|
} elseif (isset($response['access_token'])) {
|
||||||
|
return $response;
|
||||||
|
} elseif (!empty($this->redirect_target)) {
|
||||||
|
return $this->redirect_target;
|
||||||
|
} else {
|
||||||
|
throw new PnutException("No response ".json_encode($response).", http status: ${http_status}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function post(
|
||||||
|
string $end_point,
|
||||||
|
array $parameters,
|
||||||
|
string $content_type = 'application/x-www-form-urlencoded'
|
||||||
|
): string {
|
||||||
|
$method = $content_type === 'multipart/form-data' ? 'POST-RAW' : 'POST';
|
||||||
|
return $this->make_request($method, $end_point, $parameters, $content_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(
|
||||||
|
string $end_point,
|
||||||
|
array $parameters = [],
|
||||||
|
string $content_type = 'application/json'
|
||||||
|
): string {
|
||||||
|
if (!empty($parameters)) {
|
||||||
|
$end_point .= '?'.http_build_query($parameters);
|
||||||
|
$parameters = [];
|
||||||
|
}
|
||||||
|
return $this->make_request('get', $end_point, $parameters, $content_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthURL()
|
||||||
|
{
|
||||||
|
$url = $this->auth_url
|
||||||
|
. '?client_id='
|
||||||
|
. $this->client_id
|
||||||
|
. '&redirect_uri='
|
||||||
|
. urlencode($this->redirect_uri)
|
||||||
|
. '&scope='.$this->needed_scope
|
||||||
|
. '&response_type=code';
|
||||||
|
$this->logger->debug('Auth URL: ' . $url);
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Ping server and validate token
|
||||||
|
public function isAuthenticated(bool $allow_server_token = false): bool
|
||||||
|
{
|
||||||
|
$is_authenticated = ($allow_server_token && !empty($this->server_token))
|
||||||
|
|| isset($this->access_token);
|
||||||
|
$log_str = $is_authenticated
|
||||||
|
? 'Authenticated'
|
||||||
|
: 'Not authenticated';
|
||||||
|
$this->logger->info(
|
||||||
|
"Checking auth status for app: {$this->app_name}: {$log_str}"
|
||||||
|
);
|
||||||
|
$this->logger->info('Referrer: '.($_SERVER['HTTP_REFERER'] ?? 'Unknown'));
|
||||||
|
$_SESSION['redirect_after_auth'] = $_SERVER['HTTP_REFERER'];
|
||||||
|
return $is_authenticated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user