shell bypass 403
<?php
namespace Srmklive\Dropbox\Test;
use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\Exception\ClientException;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Srmklive\Dropbox\Client\DropboxClient as Client;
use Srmklive\Dropbox\DropboxUploadCounter as UploadSessionCursor;
use Srmklive\Dropbox\Exceptions\BadRequest;
class ClientTest extends TestCase
{
/** @test */
public function it_can_be_instantiated()
{
$client = new Client('test_token');
$this->assertInstanceOf(Client::class, $client);
}
/** @test */
public function it_can_copy_a_file()
{
$expectedResponse = [
'.tag' => 'file',
'name' => 'Prime_Numbers.txt',
];
$mockHttpClient = $this->mock_http_request(
json_encode($expectedResponse),
'https://api.dropboxapi.com/2/files/copy',
[
'json' => [
'from_path' => '/from/path/file.txt',
'to_path' => '/to/path/file.txt',
],
]
);
$client = new Client('test_token', $mockHttpClient);
$this->assertEquals($expectedResponse, $client->copy('from/path/file.txt', 'to/path/file.txt'));
}
/** @test */
public function it_can_create_a_folder()
{
$mockHttpClient = $this->mock_http_request(
json_encode(['name' => 'math']),
'https://api.dropboxapi.com/2/files/create_folder',
[
'json' => [
'path' => '/Homework/math',
],
]
);
$client = new Client('test_token', $mockHttpClient);
$this->assertEquals(['.tag' => 'folder', 'name' => 'math'], $client->createFolder('Homework/math'));
}
/** @test */
public function it_can_delete_a_folder()
{
$mockHttpClient = $this->mock_http_request(
json_encode(['name' => 'math']),
'https://api.dropboxapi.com/2/files/delete',
[
'json' => [
'path' => '/Homework/math',
],
]
);
$client = new Client('test_token', $mockHttpClient);
$this->assertEquals(['name' => 'math'], $client->delete('Homework/math'));
}
/** @test */
public function it_can_download_a_file()
{
$expectedResponse = $this->getMockBuilder(StreamInterface::class)
->getMock();
$expectedResponse->expects($this->once())
->method('isReadable')
->willReturn(true);
$mockHttpClient = $this->mock_http_request(
$expectedResponse,
'https://content.dropboxapi.com/2/files/download',
[
'headers' => [
'Dropbox-API-Arg' => json_encode(['path' => '/Homework/math/answers.txt']),
],
'body' => '',
]
);
$client = new Client('test_token', $mockHttpClient);
$this->assertTrue(is_resource($client->download('Homework/math/answers.txt')));
}
/** @test */
public function it_can_retrieve_metadata()
{
$mockHttpClient = $this->mock_http_request(
json_encode(['name' => 'math']),
'https://api.dropboxapi.com/2/files/get_metadata',
[
'json' => [
'path' => '/Homework/math',
],
]
);
$client = new Client('test_token', $mockHttpClient);
$this->assertEquals(['name' => 'math'], $client->getMetaData('Homework/math'));
}
/** @test */
public function it_can_get_a_temporary_link()
{
$mockHttpClient = $this->mock_http_request(
json_encode([
'name' => 'math',
'link' => 'https://dl.dropboxusercontent.com/apitl/1/YXNkZmFzZGcyMzQyMzI0NjU2NDU2NDU2',
]),
'https://api.dropboxapi.com/2/files/get_temporary_link',
[
'json' => [
'path' => '/Homework/math',
],
]
);
$client = new Client('test_token', $mockHttpClient);
$this->assertEquals(
'https://dl.dropboxusercontent.com/apitl/1/YXNkZmFzZGcyMzQyMzI0NjU2NDU2NDU2',
$client->getTemporaryLink('Homework/math')
);
}
/** @test */
public function it_can_get_a_thumbnail()
{
$expectedResponse = $this->getMockBuilder(StreamInterface::class)
->getMock();
$mockHttpClient = $this->mock_http_request(
$expectedResponse,
'https://content.dropboxapi.com/2/files/get_thumbnail',
[
'headers' => [
'Dropbox-API-Arg' => json_encode(
[
'path' => '/Homework/math/answers.jpg',
'format' => 'jpeg',
'size' => 'w64h64',
]
),
],
'body' => '',
]
);
$client = new Client('test_token', $mockHttpClient);
$this->assertTrue(is_string($client->getThumbnail('Homework/math/answers.jpg')));
}
/** @test */
public function it_can_list_a_folder()
{
$mockHttpClient = $this->mock_http_request(
json_encode(['name' => 'math']),
'https://api.dropboxapi.com/2/files/list_folder',
[
'json' => [
'path' => '/Homework/math',
'recursive' => true,
],
]
);
$client = new Client('test_token', $mockHttpClient);
$this->assertEquals(['name' => 'math'], $client->listFolder('Homework/math', true));
}
/** @test */
public function it_can_continue_to_list_a_folder()
{
$mockHttpClient = $this->mock_http_request(
json_encode(['name' => 'math']),
'https://api.dropboxapi.com/2/files/list_folder/continue',
[
'json' => [
'cursor' => 'ZtkX9_EHj3x7PMkVuFIhwKYXEpwpLwyxp9vMKomUhllil9q7eWiAu',
],
]
);
$client = new Client('test_token', $mockHttpClient);
$this->assertEquals(
['name' => 'math'],
$client->listFolderContinue('ZtkX9_EHj3x7PMkVuFIhwKYXEpwpLwyxp9vMKomUhllil9q7eWiAu')
);
}
/** @test */
public function it_can_move_a_file()
{
$expectedResponse = [
'.tag' => 'file',
'name' => 'Prime_Numbers.txt',
];
$mockHttpClient = $this->mock_http_request(
json_encode($expectedResponse),
'https://api.dropboxapi.com/2/files/move_v2',
[
'json' => [
'from_path' => '/from/path/file.txt',
'to_path' => '',
],
]
);
$client = new Client('test_token', $mockHttpClient);
$this->assertEquals($expectedResponse, $client->move('/from/path/file.txt', ''));
}
/** @test */
public function it_can_upload_a_file()
{
$mockHttpClient = $this->mock_http_request(
json_encode(['name' => 'answers.txt']),
'https://content.dropboxapi.com/2/files/upload',
[
'headers' => [
'Dropbox-API-Arg' => json_encode(
[
'path' => '/Homework/math/answers.txt',
'mode' => 'add',
]
),
'Content-Type' => 'application/octet-stream',
],
'body' => 'testing text upload',
]
);
$client = new Client('test_token', $mockHttpClient);
$this->assertEquals(
['.tag' => 'file', 'name' => 'answers.txt'],
$client->upload('Homework/math/answers.txt', 'testing text upload')
);
}
/** @test */
public function it_can_start_upload_session()
{
$mockGuzzle = $this->mock_http_request(
json_encode(['session_id' => 'mockedUploadSessionId']),
'https://content.dropboxapi.com/2/files/upload_session/start',
[
'headers' => [
'Dropbox-API-Arg' => json_encode(
[
'close' => false,
]
),
'Content-Type' => 'application/octet-stream',
],
'body' => 'this text have 23 bytes',
]
);
$client = new Client('test_token', $mockGuzzle);
$uploadSessionCursor = $client->startUploadSession('this text have 23 bytes');
$this->assertInstanceOf(UploadSessionCursor::class, $uploadSessionCursor);
$this->assertEquals('mockedUploadSessionId', $uploadSessionCursor->session_id);
$this->assertEquals(23, $uploadSessionCursor->offset);
}
/** @test */
public function it_can_append_to_upload_session()
{
$mockGuzzle = $this->mock_http_request(
null,
'https://content.dropboxapi.com/2/files/upload_session/append_v2',
[
'headers' => [
'Dropbox-API-Arg' => json_encode(
[
'cursor' => [
'session_id' => 'mockedUploadSessionId',
'offset' => 10,
],
'close' => false,
]
),
'Content-Type' => 'application/octet-stream',
],
'body' => 'this text has 32 bytes',
]
);
$client = new Client('test_token', $mockGuzzle);
$oldUploadSessionCursor = new UploadSessionCursor('mockedUploadSessionId', 10);
$uploadSessionCursor = $client->appendContentToUploadSession('this text has 32 bytes', $oldUploadSessionCursor);
$this->assertInstanceOf(UploadSessionCursor::class, $uploadSessionCursor);
$this->assertEquals('mockedUploadSessionId', $uploadSessionCursor->session_id);
$this->assertEquals(32, $uploadSessionCursor->offset);
}
/** @test */
public function it_can_upload_a_file_string_chunk()
{
$content = 'chunk0chunk1chunk2rest';
$mockClient = $this->mock_chunk_upload_client($content, 6);
$this->assertEquals(
['name' => 'answers.txt'],
$mockClient->uploadChunk('Homework/math/answers.txt', $content, 'add', 6)
);
}
/** @test */
public function it_can_upload_a_file_resource_chunk()
{
$content = 'chunk0chunk1chunk2rest';
$resource = fopen('php://memory', 'r+');
fwrite($resource, $content);
rewind($resource);
$mockClient = $this->mock_chunk_upload_client($content, 6);
$this->assertEquals(
['name' => 'answers.txt'],
$mockClient->uploadChunk('Homework/math/answers.txt', $resource, 'add', 6)
);
}
/** @test */
public function it_can_upload_a_tiny_file_chunk()
{
$content = 'smallerThenChunkSize';
$resource = fopen('php://memory', 'r+');
fwrite($resource, $content);
rewind($resource);
$mockClient = $this->mock_chunk_upload_client($content, 21);
$this->assertEquals(
['name' => 'answers.txt'],
$mockClient->uploadChunk('Homework/math/answers.txt', $resource, 'add', 21)
);
}
/** @test */
public function it_can_finish_an_upload_session()
{
$mockGuzzle = $this->mock_http_request(
json_encode([
'name' => 'answers.txt',
]),
'https://content.dropboxapi.com/2/files/upload_session/finish',
[
'headers' => [
'Dropbox-API-Arg' => json_encode([
'cursor' => [
'session_id' => 'mockedUploadSessionId',
'offset' => 10,
],
'commit' => [
'path' => 'Homework/math/answers.txt',
'mode' => 'add',
'autorename' => false,
'mute' => false,
],
]),
'Content-Type' => 'application/octet-stream',
],
'body' => 'this text has 32 bytes',
]
);
$client = new Client('test_token', $mockGuzzle);
$oldUploadSessionCursor = new UploadSessionCursor('mockedUploadSessionId', 10);
$response = $client->finishUploadSession(
'this text has 32 bytes',
$oldUploadSessionCursor,
'Homework/math/answers.txt'
);
$this->assertEquals([
'.tag' => 'file',
'name' => 'answers.txt',
], $response);
}
/** @test */
public function it_can_get_account_info()
{
$expectedResponse = [
'account_id' => 'dbid:AAH4f99T0taONIb-OurWxbNQ6ywGRopQngc',
'name' => [
'given_name' => 'Franz',
'surname' => 'Ferdinand',
'familiar_name' => 'Franz',
'display_name' => 'Franz Ferdinand (Personal)',
'abbreviated_name' => 'FF',
],
'email' => 'franz@gmail.com',
'email_verified' => false,
'disabled' => false,
'locale' => 'en',
'referral_link' => 'https://db.tt/ZITNuhtI',
'is_paired' => false,
'account_type' => [
'.tag' => 'basic',
],
'profile_photo_url' => 'https://dl-web.dropbox.com/account_photo/get/dbid%3AAAH4f99T0taONIb-OurWxbNQ6ywGRopQngc?vers=1453416673259&size=128x128',
'country' => 'US',
];
$mockGuzzle = $this->mock_http_request(
json_encode($expectedResponse),
'https://api.dropboxapi.com/2/users/get_current_account',
[]
);
$client = new Client('test_token', $mockGuzzle);
$this->assertEquals($expectedResponse, $client->getAccountInfo());
}
/** @test */
public function it_can_revoke_token()
{
$mockGuzzle = $this->mock_http_request(
null,
'https://api.dropboxapi.com/2/auth/token/revoke',
[]
);
$client = new Client('test_token', $mockGuzzle);
$client->revokeToken();
}
/** @test */
public function content_endpoint_request_can_throw_exception()
{
$mockGuzzle = $this->getMockBuilder(HttpClient::class)
->setMethods(['post'])
->getMock();
$mockGuzzle->expects($this->once())
->method('post')
->willThrowException(
new ClientException(
'there was an error',
$this->getMockBuilder(RequestInterface::class)->getMock(),
$this->getMockBuilder(ResponseInterface::class)->getMock()
)
);
$client = new Client('test_token', $mockGuzzle);
$this->expectException(ClientException::class);
$client->performContentApiRequest('testing/endpoint', []);
}
/** @test */
public function rpc_endpoint_request_can_throw_exception_with_400_status_code()
{
$mockResponse = $this->getMockBuilder(ResponseInterface::class)
->getMock();
$mockResponse->expects($this->any())
->method('getStatusCode')
->willReturn(400);
$mockGuzzle = $this->getMockBuilder(HttpClient::class)
->setMethods(['post'])
->getMock();
$mockGuzzle->expects($this->once())
->method('post')
->willThrowException(
new ClientException(
'there was an error',
$this->getMockBuilder(RequestInterface::class)->getMock(),
$mockResponse
)
);
$client = new Client('test_token', $mockGuzzle);
$this->expectException(BadRequest::class);
$client->performApiRequest('testing/endpoint', []);
}
/** @test */
public function rpc_endpoint_request_can_throw_exception_with_409_status_code()
{
$body = [
'error' => [
'.tag' => 'machine_readable_error_code',
],
'error_summary' => 'Human readable error code',
];
$mockResponse = $this->getMockBuilder(ResponseInterface::class)
->getMock();
$mockResponse->expects($this->any())
->method('getStatusCode')
->willReturn(409);
$mockResponse->expects($this->any())
->method('getBody')
->willReturn(json_encode($body));
$mockGuzzle = $this->getMockBuilder(HttpClient::class)
->setMethods(['post'])
->getMock();
$mockGuzzle->expects($this->once())
->method('post')
->willThrowException(
new ClientException(
'there was an error',
$this->getMockBuilder(RequestInterface::class)->getMock(),
$mockResponse
)
);
$client = new Client('test_token', $mockGuzzle);
$this->expectException(BadRequest::class);
$client->performApiRequest('testing/endpoint', []);
}
/** @test */
public function it_can_normalize_paths()
{
$normalizeFunction = self::getMethod('normalizePath');
$client = new Client('test_token');
//Default functionality of client to prepend slash for file paths requested
$this->assertEquals($normalizeFunction->invokeArgs($client, ['/test/file/path']), '/test/file/path');
$this->assertEquals($normalizeFunction->invokeArgs($client, ['testurl']), '/testurl');
$this->assertEquals($normalizeFunction->invokeArgs($client, ['']), '');
$this->assertEquals($normalizeFunction->invokeArgs($client, ['file:1234567890']), '/file:1234567890');
//If supplied with a direct id/ns/rev normalization should not prepend slash
$this->assertEquals($normalizeFunction->invokeArgs($client, ['id:1234567890']), 'id:1234567890');
$this->assertEquals($normalizeFunction->invokeArgs($client, ['ns:1234567890']), 'ns:1234567890');
$this->assertEquals($normalizeFunction->invokeArgs($client, ['rev:1234567890']), 'rev:1234567890');
}
private function mock_http_request($expectedResponse, $expectedEndpoint, $expectedParams)
{
$mockResponse = $this->getMockBuilder(ResponseInterface::class)
->getMock();
$mockResponse->expects($this->once())
->method('getBody')
->willReturn($expectedResponse);
$mockHttpClient = $this->getMockBuilder(HttpClient::class)
->setMethods(['post'])
->getMock();
$mockHttpClient->expects($this->once())
->method('post')
->with($expectedEndpoint, $expectedParams)
->willReturn($mockResponse);
return $mockHttpClient;
}
private function mock_chunk_upload_client($content, $chunkSize)
{
$chunks = str_split($content, $chunkSize);
$mockClient = $this->getMockBuilder(Client::class)
->setConstructorArgs(['test_token'])
->setMethodsExcept(['uploadChunk', 'upload'])
->getMock();
$mockClient->expects($this->once())
->method('startUploadSession')
->with(array_shift($chunks))
->willReturn(new UploadSessionCursor('mockedSessionId', $chunkSize));
$mockClient->expects($this->once())
->method('finishUploadSession')
->with(array_pop($chunks), $this->anything(), 'Homework/math/answers.txt', 'add')
->willReturn(['name' => 'answers.txt']);
$remainingChunks = count($chunks);
$offset = $chunkSize;
if ($remainingChunks) {
$withs = [];
$returns = [];
foreach ($chunks as $chunk) {
$offset += $chunkSize;
$withs[] = [$chunk, $this->anything()];
$returns[] = new UploadSessionCursor('mockedSessionId', $offset);
}
$mockClient->expects($this->exactly($remainingChunks))
->method('appendContentToUploadSession')
->withConsecutive(...$withs)
->willReturn(...$returns);
}
return $mockClient;
}
protected static function getMethod($name)
{
$class = new \ReflectionClass(Client::class);
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method;
}
}