shell bypass 403
<?php
namespace Srmklive\Dropbox\Client;
use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\Exception\ClientException as HttpClientException;
use GuzzleHttp\Psr7\StreamWrapper;
use Srmklive\Dropbox\Exceptions\BadRequest;
use Srmklive\Dropbox\UploadContent;
class DropboxClient
{
use UploadContent;
const THUMBNAIL_FORMAT_JPEG = 'jpeg';
const THUMBNAIL_FORMAT_PNG = 'png';
const THUMBNAIL_SIZE_XS = 'w32h32';
const THUMBNAIL_SIZE_S = 'w64h64';
const THUMBNAIL_SIZE_M = 'w128h128';
const THUMBNAIL_SIZE_L = 'w640h480';
const THUMBNAIL_SIZE_XL = 'w1024h768';
const MAX_CHUNK_SIZE = 157286400;
/** @var \GuzzleHttp\Client */
protected $client;
/**
* Dropbox OAuth access token.
*
* @var string
*/
protected $accessToken;
/**
* Dropbox API v2 Url.
*
* @var string
*/
protected $apiUrl;
/**
* Dropbox content API v2 url for uploading content.
*
* @var string
*/
protected $apiContentUrl;
/**
* Dropbox API v2 endpoint.
*
* @var string
*/
protected $apiEndpoint;
/**
* @var mixed
*/
protected $content;
/**
* Dropbox API request data.
*
* @var array
*/
protected $request;
/**
* @var int
*/
protected $maxChunkSize;
/**
* DropboxClient constructor.
*
* @param string $token
* @param \GuzzleHttp\Client $client
* @param int $maxChunkSize
*/
public function __construct($token, HttpClient $client = null, $maxChunkSize = self::MAX_CHUNK_SIZE)
{
$this->setAccessToken($token);
$this->setClient($client);
$this->apiUrl = 'https://api.dropboxapi.com/2/';
$this->apiContentUrl = 'https://content.dropboxapi.com/2/';
$this->maxChunkSize = ($maxChunkSize < self::MAX_CHUNK_SIZE ?
($maxChunkSize > 1 ? $maxChunkSize : 1) : self::MAX_CHUNK_SIZE);
}
/**
* Set Http Client.
*
* @param \GuzzleHttp\Client $client
*/
protected function setClient(HttpClient $client = null)
{
if ($client instanceof HttpClient) {
$this->client = $client;
} else {
$this->client = new HttpClient([
'headers' => [
'Authorization' => "Bearer {$this->accessToken}",
],
]);
}
}
/**
* Set Dropbox OAuth access token.
*
* @param string $token
*/
protected function setAccessToken($token)
{
$this->accessToken = $token;
}
/**
* Copy a file or folder to a different location in the user's Dropbox.
*
* If the source path is a folder all its contents will be copied.
*
* @param string $fromPath
* @param string $toPath
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-copy
*/
public function copy($fromPath, $toPath)
{
$this->setupRequest([
'from_path' => $this->normalizePath($fromPath),
'to_path' => $this->normalizePath($toPath),
]);
$this->apiEndpoint = 'files/copy';
return $this->doDropboxApiRequest();
}
/**
* Create a folder at a given path.
*
* @param string $path
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-create_folder
*/
public function createFolder($path)
{
$this->setupRequest([
'path' => $this->normalizePath($path),
]);
$this->apiEndpoint = 'files/create_folder';
$response = $this->doDropboxApiRequest();
$response['.tag'] = 'folder';
return $response;
}
/**
* Delete the file or folder at a given path.
*
* If the path is a folder, all its contents will be deleted too.
* A successful response indicates that the file or folder was deleted.
*
* @param string $path
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-delete
*/
public function delete($path)
{
$this->setupRequest([
'path' => $this->normalizePath($path),
]);
$this->apiEndpoint = 'files/delete';
return $this->doDropboxApiRequest();
}
/**
* Download a file from a user's Dropbox.
*
* @param string $path
*
* @throws \Exception
*
* @return resource
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-download
*/
public function download($path)
{
$this->setupRequest([
'path' => $this->normalizePath($path),
]);
$this->apiEndpoint = 'files/download';
$this->content = null;
$response = $this->doDropboxApiContentRequest();
return StreamWrapper::getResource($response->getBody());
}
/**
* Returns the metadata for a file or folder.
*
* Note: Metadata for the root folder is unsupported.
*
* @param string $path
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_metadata
*/
public function getMetaData($path)
{
$this->setupRequest([
'path' => $this->normalizePath($path),
]);
$this->apiEndpoint = 'files/get_metadata';
return $this->doDropboxApiRequest();
}
/**
* Get a temporary link to stream content of a file.
*
* This link will expire in four hours and afterwards you will get 410 Gone.
* Content-Type of the link is determined automatically by the file's mime type.
*
* @param string $path
*
* @throws \Exception
*
* @return string
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_temporary_link
*/
public function getTemporaryLink($path)
{
$this->setupRequest([
'path' => $this->normalizePath($path),
]);
$this->apiEndpoint = 'files/get_temporary_link';
$response = $this->doDropboxApiRequest();
return $response['link'];
}
/**
* Get a thumbnail for an image.
*
* This method currently supports files with the following file extensions:
* jpg, jpeg, png, tiff, tif, gif and bmp.
*
* Photos that are larger than 20MB in size won't be converted to a thumbnail.
*
* @param string $path
* @param string $format
* @param string $size
*
* @throws \Exception
*
* @return string
*/
public function getThumbnail($path, $format = 'jpeg', $size = 'w64h64')
{
$this->setupRequest([
'path' => $this->normalizePath($path),
'format' => $format,
'size' => $size,
]);
$this->apiEndpoint = 'files/get_thumbnail';
$this->content = null;
$response = $this->doDropboxApiContentRequest();
return (string) $response->getBody();
}
/**
* Starts returning the contents of a folder.
*
* If the result's ListFolderResult.has_more field is true, call
* list_folder/continue with the returned ListFolderResult.cursor to retrieve more entries.
*
* Note: auth.RateLimitError may be returned if multiple list_folder or list_folder/continue calls
* with same parameters are made simultaneously by same API app for same user. If your app implements
* retry logic, please hold off the retry until the previous request finishes.
*
* @param string $path
* @param bool $recursive
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder
*/
public function listFolder($path = '', $recursive = false)
{
$this->setupRequest([
'path' => $this->normalizePath($path),
'recursive' => $recursive,
]);
$this->apiEndpoint = 'files/list_folder';
return $this->doDropboxApiRequest();
}
/**
* Once a cursor has been retrieved from list_folder, use this to paginate through all files and
* retrieve updates to the folder, following the same rules as documented for list_folder.
*
* @param string $cursor
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder-continue
*/
public function listFolderContinue($cursor = '')
{
$this->setupRequest([
'cursor' => $cursor,
]);
$this->apiEndpoint = 'files/list_folder/continue';
return $this->doDropboxApiRequest();
}
/**
* Move a file or folder to a different location in the user's Dropbox.
*
* If the source path is a folder all its contents will be moved.
*
* @param string $fromPath
* @param string $toPath
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-move
*/
public function move($fromPath, $toPath)
{
$this->setupRequest([
'from_path' => $this->normalizePath($fromPath),
'to_path' => $this->normalizePath($toPath),
]);
$this->apiEndpoint = 'files/move_v2';
return $this->doDropboxApiRequest();
}
/**
* Create a new file with the contents provided in the request.
*
* Do not use this to upload a file larger than 150 MB. Instead, create an upload session with upload_session/start.
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload
*
* @param string $path
* @param string|resource $contents
* @param string|array $mode
*
* @throws \Exception
*
* @return array
*/
public function upload($path, $contents, $mode = 'add')
{
if ($this->shouldUploadChunk($contents)) {
return $this->uploadChunk($path, $contents, $mode);
}
$this->setupRequest([
'path' => $this->normalizePath($path),
'mode' => $mode,
]);
$this->content = $contents;
$this->apiEndpoint = 'files/upload';
$response = $this->doDropboxApiContentRequest();
$metadata = json_decode($response->getBody(), true);
$metadata['.tag'] = 'file';
return $metadata;
}
/**
* Get Account Info for current authenticated user.
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function getAccountInfo()
{
$this->apiEndpoint = 'users/get_current_account';
return $this->doDropboxApiRequest();
}
/**
* Revoke current access token.
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#auth-token-revoke
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function revokeToken()
{
$this->apiEndpoint = 'auth/token/revoke';
return $this->doDropboxApiRequest();
}
/**
* Set Dropbox API request data.
*
* @param array $request
*/
protected function setupRequest($request)
{
$this->request = $request;
}
/**
* Perform Dropbox API v2 request.
*
* @param $endpoint
* @param $payload
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function performApiRequest($endpoint, $payload)
{
$this->setupRequest($payload);
$this->apiEndpoint = $endpoint;
return $this->doDropboxApiRequest();
}
/**
* Perform Dropbox API v2 content request.
*
* @param $endpoint
* @param $payload
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function performContentApiRequest($endpoint, $payload)
{
$this->setupRequest($payload);
$this->apiEndpoint = $endpoint;
return $this->doDropboxApiContentRequest();
}
/**
* Perform Dropbox API request.
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*/
protected function doDropboxApiRequest()
{
$request = empty($this->request) ? [] : ['json' => $this->request];
try {
$response = $this->client->post("{$this->apiUrl}{$this->apiEndpoint}", $request);
} catch (HttpClientException $exception) {
throw $this->determineException($exception);
}
return json_decode($response->getBody(), true);
}
/**
* Setup headers for Dropbox API request.
*
* @return array
*/
protected function setupDropboxHeaders()
{
$headers = [
'Dropbox-API-Arg' => json_encode(
$this->request
),
];
if (!empty($this->content) ||
$this->apiEndpoint == 'files/upload_session/finish') {
// The upload_session/finish API requires a Content-Type, always
$headers['Content-Type'] = 'application/octet-stream';
}
return $headers;
}
/**
* Perform Dropbox API request.
*
* @throws \Exception
*
* @return \Psr\Http\Message\ResponseInterface
*/
protected function doDropboxApiContentRequest()
{
try {
$response = $this->client->post("{$this->apiContentUrl}{$this->apiEndpoint}", [
'headers' => $this->setupDropboxHeaders(),
'body' => !empty($this->content) ? $this->content : '',
]);
} catch (HttpClientException $exception) {
throw $this->determineException($exception);
}
return $response;
}
/**
* Normalize path.
*
* @param string $path
*
* @return string
*/
protected function normalizePath($path)
{
if (preg_match("/^id:.*|^rev:.*|^(ns:[0-9]+(\/.*)?)/", $path) === 1) {
return $path;
}
$path = (trim($path, '/') === '') ? '' : '/'.$path;
return str_replace('//', '/', $path);
}
/**
* Catch Dropbox API request exception.
*
* @param HttpClientException $exception
*
* @return \Exception
*/
protected function determineException(HttpClientException $exception)
{
if (!empty($exception->getResponse()) && in_array($exception->getResponse()->getStatusCode(), [400, 409])) {
return new BadRequest($exception->getResponse());
}
return $exception;
}
}