improving code coverage

This commit is contained in:
El RIDO 2021-06-13 10:44:26 +02:00
parent e294145a2b
commit 93135e0abf
No known key found for this signature in database
GPG Key ID: 0F5C940A6BD81F92
14 changed files with 949 additions and 660 deletions

View File

@ -195,22 +195,17 @@ class Controller
*/ */
private function _create() private function _create()
{ {
try { // Ensure last paste from visitors IP address was more than configured amount of seconds ago.
// Ensure last paste from visitors IP address was more than configured amount of seconds ago. ServerSalt::setStore($this->_model->getStore());
ServerSalt::setStore($this->_model->getStore()); TrafficLimiter::setConfiguration($this->_conf);
TrafficLimiter::setConfiguration($this->_conf); TrafficLimiter::setStore($this->_model->getStore());
TrafficLimiter::setStore($this->_model->getStore()); if (!TrafficLimiter::canPass()) {
if (!TrafficLimiter::canPass()) { $this->_return_message(
$this->_return_message( 1, I18n::_(
1, I18n::_( 'Please wait %d seconds between each post.',
'Please wait %d seconds between each post.', $this->_conf->getKey('limit', 'traffic')
$this->_conf->getKey('limit', 'traffic') )
) );
);
return;
}
} catch (Exception $e) {
$this->_return_message(1, I18n::_($e->getMessage()));
return; return;
} }

View File

@ -198,21 +198,25 @@ class Database extends AbstractData
$opendiscussion = $paste['adata'][2]; $opendiscussion = $paste['adata'][2];
$burnafterreading = $paste['adata'][3]; $burnafterreading = $paste['adata'][3];
} }
return self::_exec( try {
'INSERT INTO ' . self::_sanitizeIdentifier('paste') . return self::_exec(
' VALUES(?,?,?,?,?,?,?,?,?)', 'INSERT INTO ' . self::_sanitizeIdentifier('paste') .
array( ' VALUES(?,?,?,?,?,?,?,?,?)',
$pasteid, array(
$isVersion1 ? $paste['data'] : Json::encode($paste), $pasteid,
$created, $isVersion1 ? $paste['data'] : Json::encode($paste),
$expire_date, $created,
(int) $opendiscussion, $expire_date,
(int) $burnafterreading, (int) $opendiscussion,
Json::encode($meta), (int) $burnafterreading,
$attachment, Json::encode($meta),
$attachmentname, $attachment,
) $attachmentname,
); )
);
} catch (Exception $e) {
return false;
}
} }
/** /**
@ -348,19 +352,23 @@ class Database extends AbstractData
$meta[$key] = null; $meta[$key] = null;
} }
} }
return self::_exec( try {
'INSERT INTO ' . self::_sanitizeIdentifier('comment') . return self::_exec(
' VALUES(?,?,?,?,?,?,?)', 'INSERT INTO ' . self::_sanitizeIdentifier('comment') .
array( ' VALUES(?,?,?,?,?,?,?)',
$commentid, array(
$pasteid, $commentid,
$parentid, $pasteid,
$data, $parentid,
$meta['nickname'], $data,
$meta[$iconKey], $meta['nickname'],
$meta[$createdKey], $meta[$iconKey],
) $meta[$createdKey],
); )
);
} catch (Exception $e) {
return false;
}
} }
/** /**
@ -416,11 +424,15 @@ class Database extends AbstractData
*/ */
public function existsComment($pasteid, $parentid, $commentid) public function existsComment($pasteid, $parentid, $commentid)
{ {
return (bool) self::_select( try {
'SELECT dataid FROM ' . self::_sanitizeIdentifier('comment') . return (bool) self::_select(
' WHERE pasteid = ? AND parentid = ? AND dataid = ?', 'SELECT dataid FROM ' . self::_sanitizeIdentifier('comment') .
array($pasteid, $parentid, $commentid), true ' WHERE pasteid = ? AND parentid = ? AND dataid = ?',
); array($pasteid, $parentid, $commentid), true
);
} catch (Exception $e) {
return false;
}
} }
/** /**

View File

@ -34,12 +34,9 @@ class GoogleCloudStorage extends AbstractData
if (is_array($options) && array_key_exists('prefix', $options)) { if (is_array($options) && array_key_exists('prefix', $options)) {
$prefix = $options['prefix']; $prefix = $options['prefix'];
} }
if (is_array($options) && array_key_exists('client', $options)) {
$client = $options['client'];
}
if (!(self::$_instance instanceof self)) { if (!(self::$_instance instanceof self)) {
self::$_instance = new self($bucket, $prefix, $client); self::$_instance = new self($bucket, $prefix);
} }
return self::$_instance; return self::$_instance;
} }
@ -48,16 +45,12 @@ class GoogleCloudStorage extends AbstractData
protected $_bucket = null; protected $_bucket = null;
protected $_prefix = 'pastes'; protected $_prefix = 'pastes';
public function __construct($bucket, $prefix, $client = null) public function __construct($bucket, $prefix)
{ {
parent::__construct(); parent::__construct();
if ($client == null) { $this->_client = class_exists('StorageClientStub', false) ?
$this->_client = new StorageClient(array('suppressKeyFileNotice' => true)); new \StorageClientStub(array()) :
} else { new StorageClient(array('suppressKeyFileNotice' => true));
// use given client for test purposes
$this->_client = $client;
}
$this->_bucket = $this->_client->bucket($bucket); $this->_bucket = $this->_client->bucket($bucket);
if ($prefix != null) { if ($prefix != null) {
$this->_prefix = $prefix; $this->_prefix = $prefix;

View File

@ -52,6 +52,11 @@ class FormatV2
} }
} }
// Make sure adata is an array.
if (!is_array($message['adata'])) {
return false;
}
$cipherParams = $isComment ? $message['adata'] : $message['adata'][0]; $cipherParams = $isComment ? $message['adata'] : $message['adata'][0];
// Make sure some fields are base64 data: // Make sure some fields are base64 data:

View File

@ -59,7 +59,6 @@ class PurgeLimiter extends AbstractPersistence
* *
* @access public * @access public
* @static * @static
* @throws \Exception
* @return bool * @return bool
*/ */
public static function canPurge() public static function canPurge()

View File

@ -12,7 +12,6 @@
namespace PrivateBin\Persistence; namespace PrivateBin\Persistence;
use Exception;
use PrivateBin\Data\AbstractData; use PrivateBin\Data\AbstractData;
/** /**
@ -54,8 +53,7 @@ class ServerSalt extends AbstractPersistence
*/ */
public static function generate() public static function generate()
{ {
$randomSalt = bin2hex(random_bytes(256)); return bin2hex(random_bytes(256));
return $randomSalt;
} }
/** /**
@ -63,7 +61,6 @@ class ServerSalt extends AbstractPersistence
* *
* @access public * @access public
* @static * @static
* @throws Exception
* @return string * @return string
*/ */
public static function get() public static function get()

View File

@ -108,6 +108,8 @@ class Request
case 'DELETE': case 'DELETE':
case 'PUT': case 'PUT':
case 'POST': case 'POST':
// it might be a creation or a deletion, the latter is detected below
$this->_operation = 'create';
$this->_params = Json::decode( $this->_params = Json::decode(
file_get_contents(self::$_inputStream) file_get_contents(self::$_inputStream)
); );
@ -125,15 +127,10 @@ class Request
} }
// prepare operation, depending on current parameters // prepare operation, depending on current parameters
if ( if (array_key_exists('pasteid', $this->_params) && !empty($this->_params['pasteid'])) {
array_key_exists('ct', $this->_params) &&
!empty($this->_params['ct'])
) {
$this->_operation = 'create';
} elseif (array_key_exists('pasteid', $this->_params) && !empty($this->_params['pasteid'])) {
if (array_key_exists('deletetoken', $this->_params) && !empty($this->_params['deletetoken'])) { if (array_key_exists('deletetoken', $this->_params) && !empty($this->_params['deletetoken'])) {
$this->_operation = 'delete'; $this->_operation = 'delete';
} else { } else if ($this->_operation != 'create') {
$this->_operation = 'read'; $this->_operation = 'read';
} }
} elseif (array_key_exists('jsonld', $this->_params) && !empty($this->_params['jsonld'])) { } elseif (array_key_exists('jsonld', $this->_params) && !empty($this->_params['jsonld'])) {
@ -172,7 +169,7 @@ class Request
$data['meta'] = $meta; $data['meta'] = $meta;
} }
foreach ($required_keys as $key) { foreach ($required_keys as $key) {
$data[$key] = $this->getParam($key); $data[$key] = $this->getParam($key, $key == 'v' ? 1 : '');
} }
// forcing a cast to int or float // forcing a cast to int or float
$data['v'] = $data['v'] + 0; $data['v'] = $data['v'] + 0;

View File

@ -1,5 +1,14 @@
<?php <?php
use Google\Auth\HttpHandler\HttpHandlerFactory;
use Google\Cloud\Core\Exception\BadRequestException;
use Google\Cloud\Core\Exception\NotFoundException;
use Google\Cloud\Storage\Bucket;
use Google\Cloud\Storage\Connection\ConnectionInterface;
use Google\Cloud\Storage\StorageClient;
use Google\Cloud\Storage\StorageObject;
use GuzzleHttp\Client;
use PrivateBin\Data\GoogleCloudStorage;
use PrivateBin\Persistence\ServerSalt; use PrivateBin\Persistence\ServerSalt;
error_reporting(E_ALL | E_STRICT); error_reporting(E_ALL | E_STRICT);
@ -21,6 +30,586 @@ if (!defined('CONF_SAMPLE')) {
require PATH . 'vendor/autoload.php'; require PATH . 'vendor/autoload.php';
Helper::updateSubresourceIntegrity(); Helper::updateSubresourceIntegrity();
/**
* Class StorageClientStub provides a limited stub for performing the unit test
*/
class StorageClientStub extends StorageClient
{
private $_config = null;
private $_connection = null;
private $_buckets = array();
public function __construct(array $config = array())
{
$this->_config = $config;
$this->_connection = new ConnectionInterfaceStub();
}
public function bucket($name, $userProject = false)
{
if (!key_exists($name, $this->_buckets)) {
$b = new BucketStub($this->_connection, $name, array(), $this);
$this->_buckets[$name] = $b;
}
return $this->_buckets[$name];
}
/**
* @throws \Google\Cloud\Core\Exception\NotFoundException
*/
public function deleteBucket($name)
{
if (key_exists($name, $this->_buckets)) {
unset($this->_buckets[$name]);
} else {
throw new NotFoundException();
}
}
public function buckets(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function registerStreamWrapper($protocol = null)
{
throw new BadMethodCallException('not supported by this stub');
}
public function unregisterStreamWrapper($protocol = null)
{
throw new BadMethodCallException('not supported by this stub');
}
public function signedUrlUploader($uri, $data, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function timestamp(\DateTimeInterface $timestamp, $nanoSeconds = null)
{
throw new BadMethodCallException('not supported by this stub');
}
public function getServiceAccount(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function hmacKeys(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function hmacKey($accessId, $projectId = null, array $metadata = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function createHmacKey($serviceAccountEmail, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function createBucket($name, array $options = array())
{
if (key_exists($name, $this->_buckets)) {
throw new BadRequestException('already exists');
}
$b = new BucketStub($this->_connection, $name, array(), $this);
$this->_buckets[$name] = $b;
return $b;
}
}
/**
* Class BucketStub stubs a GCS bucket.
*/
class BucketStub extends Bucket
{
public $_objects;
private $_name;
private $_info;
private $_connection;
private $_client;
public function __construct(ConnectionInterface $connection, $name, array $info = array(), $client = null)
{
$this->_name = $name;
$this->_info = $info;
$this->_connection = $connection;
$this->_objects = array();
$this->_client = $client;
}
public function acl()
{
throw new BadMethodCallException('not supported by this stub');
}
public function defaultAcl()
{
throw new BadMethodCallException('not supported by this stub');
}
public function exists()
{
return true;
}
public function upload($data, array $options = array())
{
if (!is_string($data) || !key_exists('name', $options)) {
throw new BadMethodCallException('not supported by this stub');
}
$name = $options['name'];
$generation = '1';
$o = new StorageObjectStub($this->_connection, $name, $this, $generation, $options);
$this->_objects[$options['name']] = $o;
$o->setData($data);
}
public function uploadAsync($data, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getResumableUploader($data, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getStreamableUploader($data, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function object($name, array $options = array())
{
if (key_exists($name, $this->_objects)) {
return $this->_objects[$name];
} else {
return new StorageObjectStub($this->_connection, $name, $this, null, $options);
}
}
public function objects(array $options = array())
{
$prefix = key_exists('prefix', $options) ? $options['prefix'] : '';
return new CallbackFilterIterator(
new ArrayIterator($this->_objects),
function ($current, $key, $iterator) use ($prefix) {
return substr($key, 0, strlen($prefix)) == $prefix;
}
);
}
public function createNotification($topic, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function notification($id)
{
throw new BadMethodCallException('not supported by this stub');
}
public function notifications(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function delete(array $options = array())
{
$this->_client->deleteBucket($this->_name);
}
public function update(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function compose(array $sourceObjects, $name, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function info(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function reload(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function name()
{
return $this->_name;
}
public static function lifecycle(array $lifecycle = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function currentLifecycle(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function isWritable($file = null)
{
throw new BadMethodCallException('not supported by this stub');
}
public function iam()
{
throw new BadMethodCallException('not supported by this stub');
}
public function lockRetentionPolicy(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function signedUrl($expires, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function generateSignedPostPolicyV4($objectName, $expires, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
}
/**
* Class StorageObjectStub stubs a GCS storage object.
*/
class StorageObjectStub extends StorageObject
{
private $_name;
private $_data;
private $_info;
private $_bucket;
private $_generation;
private $_exists = false;
private $_connection;
public function __construct(ConnectionInterface $connection, $name, $bucket, $generation = null, array $info = array(), $encryptionKey = null, $encryptionKeySHA256 = null)
{
$this->_name = $name;
$this->_bucket = $bucket;
$this->_generation = $generation;
$this->_info = $info;
$this->_connection = $connection;
$timeCreated = new Datetime();
$this->_info['metadata']['timeCreated'] = $timeCreated->format(GoogleCloudStorage::DATETIME_FORMAT);
}
public function acl()
{
throw new BadMethodCallException('not supported by this stub');
}
public function exists(array $options = array())
{
return key_exists($this->_name, $this->_bucket->_objects);
}
/**
* @throws NotFoundException
*/
public function delete(array $options = array())
{
if (key_exists($this->_name, $this->_bucket->_objects)) {
unset($this->_bucket->_objects[$this->_name]);
} else {
throw new NotFoundException('key ' . $this->_name . ' not found.');
}
}
/**
* @throws NotFoundException
*/
public function update(array $metadata, array $options = array())
{
if (!$this->_exists) {
throw new NotFoundException('key ' . $this->_name . ' not found.');
}
$this->_info = $metadata;
}
public function copy($destination, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function rewrite($destination, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function rename($name, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
/**
* @throws NotFoundException
*/
public function downloadAsString(array $options = array())
{
if (!$this->_exists) {
throw new NotFoundException('key ' . $this->_name . ' not found.');
}
return $this->_data;
}
public function downloadToFile($path, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function downloadAsStream(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function downloadAsStreamAsync(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function signedUrl($expires, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function signedUploadUrl($expires, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function beginSignedUploadSession(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function info(array $options = array())
{
return key_exists('metadata',$this->_info) ? $this->_info['metadata'] : array();
}
public function reload(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function name()
{
return $this->_name;
}
public function identity()
{
throw new BadMethodCallException('not supported by this stub');
}
public function gcsUri()
{
return sprintf(
'gs://%s/%s',
$this->_bucket->name(),
$this->_name
);
}
public function setData($data)
{
$this->_data = $data;
$this->_exists = true;
}
}
/**
* Class ConnectionInterfaceStub required for the stubs.
*/
class ConnectionInterfaceStub implements ConnectionInterface
{
public function deleteAcl(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getAcl(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function listAcl(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function insertAcl(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function patchAcl(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function deleteBucket(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getBucket(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function listBuckets(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function insertBucket(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getBucketIamPolicy(array $args)
{
throw new BadMethodCallException('not supported by this stub');
}
public function setBucketIamPolicy(array $args)
{
throw new BadMethodCallException('not supported by this stub');
}
public function testBucketIamPermissions(array $args)
{
throw new BadMethodCallException('not supported by this stub');
}
public function patchBucket(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function deleteObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function copyObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function rewriteObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function composeObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function listObjects(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function patchObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function downloadObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function insertObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getNotification(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function deleteNotification(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function insertNotification(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function listNotifications(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getServiceAccount(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function lockRetentionPolicy(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function createHmacKey(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function deleteHmacKey(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getHmacKey(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function updateHmacKey(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function listHmacKeys(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
}
/**
* Class Helper provides unit tests pastes and comments of various formats
*/
class Helper class Helper
{ {
/** /**
@ -155,7 +744,11 @@ class Helper
public static function getPastePost($version = 2, array $meta = array()) public static function getPastePost($version = 2, array $meta = array())
{ {
$example = self::getPaste($version, $meta); $example = self::getPaste($version, $meta);
$example['meta'] = array('expire' => $example['meta']['expire']); if ($version == 2) {
$example['meta'] = array('expire' => $example['meta']['expire']);
} else {
unset($example['meta']['postdate']);
}
return $example; return $example;
} }

View File

@ -48,6 +48,8 @@ class ControllerTest extends PHPUnit_Framework_TestCase
*/ */
public function testView() public function testView()
{ {
$_SERVER['QUERY_STRING'] = Helper::getPasteId();
$_GET[Helper::getPasteId()] = '';
ob_start(); ob_start();
new Controller; new Controller;
$content = ob_get_contents(); $content = ob_get_contents();
@ -470,6 +472,29 @@ class ControllerTest extends PHPUnit_Framework_TestCase
$this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data'); $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data');
} }
/**
* @runInSeparateProcess
*/
public function testCreateInvalidFormat()
{
$options = parse_ini_file(CONF, true);
$options['traffic']['limit'] = 0;
Helper::createIniFile(CONF, $options);
$file = tempnam(sys_get_temp_dir(), 'FOO');
file_put_contents($file, Helper::getPasteJson(1));
Request::setInputStream($file);
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data');
}
/** /**
* @runInSeparateProcess * @runInSeparateProcess
*/ */
@ -518,7 +543,7 @@ class ControllerTest extends PHPUnit_Framework_TestCase
ob_end_clean(); ob_end_clean();
$response = json_decode($content, true); $response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status'); $this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertFalse($this->_data->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'paste exists after posting data'); $this->assertFalse($this->_data->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment exists after posting data');
} }
/** /**

View File

@ -0,0 +1,59 @@
<?php
use Google\Auth\HttpHandler\HttpHandlerFactory;
use GuzzleHttp\Client;
use PrivateBin\Data\GoogleCloudStorage;
use PrivateBin\Persistence\ServerSalt;
use PrivateBin\Persistence\TrafficLimiter;
require_once 'ControllerTest.php';
class ControllerWithGcsTest extends ControllerTest
{
private static $_client;
private static $_bucket;
private $_options = array();
public static function setUpBeforeClass()
{
$httpClient = new Client(array('debug'=>false));
$handler = HttpHandlerFactory::build($httpClient);
$name = 'pb-';
$alphabet = 'abcdefghijklmnopqrstuvwxyz';
for ($i = 0; $i < 29; ++$i) {
$name .= $alphabet[rand(0, strlen($alphabet) - 1)];
}
self::$_client = new StorageClientStub(array());
self::$_bucket = self::$_client->createBucket($name);
}
public function setUp()
{
/* Setup Routine */
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
if (!is_dir($this->_path)) {
mkdir($this->_path);
}
$this->_options = array(
'bucket' => self::$_bucket->name(),
'prefix' => 'pastes',
);
$this->_data = GoogleCloudStorage::getInstance($this->_options);
ServerSalt::setStore($this->_data);
TrafficLimiter::setStore($this->_data);
$this->reset();
}
public function reset()
{
parent::reset();
// but then inject a db config
$options = parse_ini_file(CONF, true);
$options['model'] = array(
'class' => 'GoogleCloudStorage',
);
$options['model_options'] = $this->_options;
Helper::createIniFile(CONF, $options);
}
}

View File

@ -302,6 +302,48 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
Helper::rmDir($this->_path); Helper::rmDir($this->_path);
} }
public function testCorruptMeta()
{
mkdir($this->_path);
$path = $this->_path . DIRECTORY_SEPARATOR . 'meta-test.sq3';
if (is_file($path)) {
unlink($path);
}
$this->_options['dsn'] = 'sqlite:' . $path;
$this->_options['tbl'] = 'baz_';
$model = Database::getInstance($this->_options);
$paste = Helper::getPaste(1, array('expire_date' => 1344803344));
unset($paste['meta']['formatter'], $paste['meta']['opendiscussion'], $paste['meta']['salt']);
$model->delete(Helper::getPasteId());
$db = new PDO(
$this->_options['dsn'],
$this->_options['usr'],
$this->_options['pwd'],
$this->_options['opt']
);
$statement = $db->prepare('INSERT INTO baz_paste VALUES(?,?,?,?,?,?,?,?,?)');
$statement->execute(
array(
Helper::getPasteId(),
$paste['data'],
$paste['meta']['postdate'],
$paste['meta']['expire_date'],
0,
0,
'{',
null,
null,
)
);
$statement->closeCursor();
$this->assertTrue($model->exists(Helper::getPasteId()), 'paste exists after storing it');
$this->assertEquals($paste, $model->read(Helper::getPasteId()));
Helper::rmDir($this->_path);
}
public function testTableUpgrade() public function testTableUpgrade()
{ {
mkdir($this->_path); mkdir($this->_path);

View File

@ -117,6 +117,7 @@ class FilesystemTest extends PHPUnit_Framework_TestCase
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
$this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste'); $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist'); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
$this->assertFalse($this->_model->setValue('foo', 'non existing namespace'), 'rejects setting value in non existing namespace');
} }
public function testCommentErrorDetection() public function testCommentErrorDetection()

View File

@ -1,12 +1,6 @@
<?php <?php
use Google\Auth\HttpHandler\HttpHandlerFactory; use Google\Auth\HttpHandler\HttpHandlerFactory;
use Google\Cloud\Core\Exception\BadRequestException;
use Google\Cloud\Core\Exception\NotFoundException;
use Google\Cloud\Storage\Bucket;
use Google\Cloud\Storage\Connection\ConnectionInterface;
use Google\Cloud\Storage\StorageClient;
use Google\Cloud\Storage\StorageObject;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use PrivateBin\Data\GoogleCloudStorage; use PrivateBin\Data\GoogleCloudStorage;
@ -35,7 +29,7 @@ class GoogleCloudStorageTest extends PHPUnit_Framework_TestCase
$this->_model = GoogleCloudStorage::getInstance(array( $this->_model = GoogleCloudStorage::getInstance(array(
'bucket' => self::$_bucket->name(), 'bucket' => self::$_bucket->name(),
'prefix' => 'pastes', 'prefix' => 'pastes',
'client' => self::$_client, )); ));
} }
public function tearDown() public function tearDown()
@ -201,580 +195,3 @@ class GoogleCloudStorageTest extends PHPUnit_Framework_TestCase
$this->assertFalse($this->_model->getValue('traffic_limiter', $client)); $this->assertFalse($this->_model->getValue('traffic_limiter', $client));
} }
} }
/**
* Class StorageClientStub provides a limited stub for performing the unit test
*/
class StorageClientStub extends StorageClient
{
private $_config = null;
private $_connection = null;
private $_buckets = array();
public function __construct(array $config = array())
{
$this->_config = $config;
$this->_connection = new ConnectionInterfaceStub();
}
public function bucket($name, $userProject = false)
{
if (!key_exists($name, $this->_buckets)) {
$b = new BucketStub($this->_connection, $name, array(), $this);
$this->_buckets[$name] = $b;
}
return $this->_buckets[$name];
}
/**
* @throws \Google\Cloud\Core\Exception\NotFoundException
*/
public function deleteBucket($name)
{
if (key_exists($name, $this->_buckets)) {
unset($this->_buckets[$name]);
} else {
throw new NotFoundException();
}
}
public function buckets(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function registerStreamWrapper($protocol = null)
{
throw new BadMethodCallException('not supported by this stub');
}
public function unregisterStreamWrapper($protocol = null)
{
throw new BadMethodCallException('not supported by this stub');
}
public function signedUrlUploader($uri, $data, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function timestamp(\DateTimeInterface $timestamp, $nanoSeconds = null)
{
throw new BadMethodCallException('not supported by this stub');
}
public function getServiceAccount(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function hmacKeys(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function hmacKey($accessId, $projectId = null, array $metadata = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function createHmacKey($serviceAccountEmail, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function createBucket($name, array $options = array())
{
if (key_exists($name, $this->_buckets)) {
throw new BadRequestException('already exists');
}
$b = new BucketStub($this->_connection, $name, array(), $this);
$this->_buckets[$name] = $b;
return $b;
}
}
/**
* Class BucketStub stubs a GCS bucket.
*/
class BucketStub extends Bucket
{
public $_objects;
private $_name;
private $_info;
private $_connection;
private $_client;
public function __construct(ConnectionInterface $connection, $name, array $info = array(), $client = null)
{
$this->_name = $name;
$this->_info = $info;
$this->_connection = $connection;
$this->_objects = array();
$this->_client = $client;
}
public function acl()
{
throw new BadMethodCallException('not supported by this stub');
}
public function defaultAcl()
{
throw new BadMethodCallException('not supported by this stub');
}
public function exists()
{
return true;
}
public function upload($data, array $options = array())
{
if (!is_string($data) || !key_exists('name', $options)) {
throw new BadMethodCallException('not supported by this stub');
}
$name = $options['name'];
$generation = '1';
$o = new StorageObjectStub($this->_connection, $name, $this, $generation, $options);
$this->_objects[$options['name']] = $o;
$o->setData($data);
}
public function uploadAsync($data, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getResumableUploader($data, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getStreamableUploader($data, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function object($name, array $options = array())
{
if (key_exists($name, $this->_objects)) {
return $this->_objects[$name];
} else {
return new StorageObjectStub($this->_connection, $name, $this, null, $options);
}
}
public function objects(array $options = array())
{
$prefix = key_exists('prefix', $options) ? $options['prefix'] : '';
return new CallbackFilterIterator(
new ArrayIterator($this->_objects),
function ($current, $key, $iterator) use ($prefix) {
return substr($key, 0, strlen($prefix)) == $prefix;
}
);
}
public function createNotification($topic, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function notification($id)
{
throw new BadMethodCallException('not supported by this stub');
}
public function notifications(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function delete(array $options = array())
{
$this->_client->deleteBucket($this->_name);
}
public function update(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function compose(array $sourceObjects, $name, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function info(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function reload(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function name()
{
return $this->_name;
}
public static function lifecycle(array $lifecycle = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function currentLifecycle(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function isWritable($file = null)
{
throw new BadMethodCallException('not supported by this stub');
}
public function iam()
{
throw new BadMethodCallException('not supported by this stub');
}
public function lockRetentionPolicy(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function signedUrl($expires, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function generateSignedPostPolicyV4($objectName, $expires, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
}
/**
* Class StorageObjectStub stubs a GCS storage object.
*/
class StorageObjectStub extends StorageObject
{
private $_name;
private $_data;
private $_info;
private $_bucket;
private $_generation;
private $_exists = false;
private $_connection;
public function __construct(ConnectionInterface $connection, $name, $bucket, $generation = null, array $info = array(), $encryptionKey = null, $encryptionKeySHA256 = null)
{
$this->_name = $name;
$this->_bucket = $bucket;
$this->_generation = $generation;
$this->_info = $info;
$this->_connection = $connection;
$timeCreated = new Datetime();
$this->_info['metadata']['timeCreated'] = $timeCreated->format(GoogleCloudStorage::DATETIME_FORMAT);
}
public function acl()
{
throw new BadMethodCallException('not supported by this stub');
}
public function exists(array $options = array())
{
return key_exists($this->_name, $this->_bucket->_objects);
}
/**
* @throws NotFoundException
*/
public function delete(array $options = array())
{
if (key_exists($this->_name, $this->_bucket->_objects)) {
unset($this->_bucket->_objects[$this->_name]);
} else {
throw new NotFoundException('key ' . $this->_name . ' not found.');
}
}
/**
* @throws NotFoundException
*/
public function update(array $metadata, array $options = array())
{
if (!$this->_exists) {
throw new NotFoundException('key ' . $this->_name . ' not found.');
}
$this->_info = $metadata;
}
public function copy($destination, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function rewrite($destination, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function rename($name, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
/**
* @throws NotFoundException
*/
public function downloadAsString(array $options = array())
{
if (!$this->_exists) {
throw new NotFoundException('key ' . $this->_name . ' not found.');
}
return $this->_data;
}
public function downloadToFile($path, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function downloadAsStream(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function downloadAsStreamAsync(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function signedUrl($expires, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function signedUploadUrl($expires, array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function beginSignedUploadSession(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function info(array $options = array())
{
return key_exists('metadata',$this->_info) ? $this->_info['metadata'] : array();
}
public function reload(array $options = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function name()
{
return $this->_name;
}
public function identity()
{
throw new BadMethodCallException('not supported by this stub');
}
public function gcsUri()
{
return sprintf(
'gs://%s/%s',
$this->_bucket->name(),
$this->_name
);
}
public function setData($data)
{
$this->_data = $data;
$this->_exists = true;
}
}
/**
* Class ConnectionInterfaceStub required for the stubs.
*/
class ConnectionInterfaceStub implements ConnectionInterface
{
public function deleteAcl(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getAcl(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function listAcl(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function insertAcl(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function patchAcl(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function deleteBucket(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getBucket(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function listBuckets(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function insertBucket(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getBucketIamPolicy(array $args)
{
throw new BadMethodCallException('not supported by this stub');
}
public function setBucketIamPolicy(array $args)
{
throw new BadMethodCallException('not supported by this stub');
}
public function testBucketIamPermissions(array $args)
{
throw new BadMethodCallException('not supported by this stub');
}
public function patchBucket(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function deleteObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function copyObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function rewriteObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function composeObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function listObjects(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function patchObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function downloadObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function insertObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getNotification(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function deleteNotification(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function insertNotification(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function listNotifications(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getServiceAccount(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function lockRetentionPolicy(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function createHmacKey(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function deleteHmacKey(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function getHmacKey(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function updateHmacKey(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function listHmacKeys(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
}

View File

@ -102,6 +102,58 @@ class ModelTest extends PHPUnit_Framework_TestCase
$this->assertEquals(array(), $paste->getComments(), 'comment was deleted with paste'); $this->assertEquals(array(), $paste->getComments(), 'comment was deleted with paste');
} }
public function testPasteV1()
{
$pasteData = Helper::getPaste(1);
unset($pasteData['meta']['formatter']);
$path = $this->_path . DIRECTORY_SEPARATOR . 'v1-test.sq3';
if (is_file($path)) {
unlink($path);
}
$options = parse_ini_file(CONF_SAMPLE, true);
$options['purge']['limit'] = 0;
$options['model'] = array(
'class' => 'Database',
);
$options['model_options'] = array(
'dsn' => 'sqlite:' . $path,
'usr' => null,
'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
);
Helper::createIniFile(CONF, $options);
$model = new Model(new Configuration);
$model->getPaste('0000000000000000')->exists(); // triggers database table creation
$model->getPaste(Helper::getPasteId())->delete(); // deletes the cache
$db = new PDO(
$options['model_options']['dsn'],
$options['model_options']['usr'],
$options['model_options']['pwd'],
$options['model_options']['opt']
);
$statement = $db->prepare('INSERT INTO paste VALUES(?,?,?,?,?,?,?,?,?)');
$statement->execute(
array(
Helper::getPasteId(),
$pasteData['data'],
$pasteData['meta']['postdate'],
0,
0,
0,
json_encode($pasteData['meta']),
null,
null,
)
);
$statement->closeCursor();
$paste = $model->getPaste(Helper::getPasteId());
$paste->getDeleteToken();
$this->assertEquals('plaintext', $paste->get()['meta']['formatter'], 'paste got created with default formatter');
}
public function testCommentDefaults() public function testCommentDefaults()
{ {
$comment = new Comment( $comment = new Comment(
@ -133,6 +185,96 @@ class ModelTest extends PHPUnit_Framework_TestCase
$paste->store(); $paste->store();
} }
/**
* @expectedException Exception
* @expectedExceptionCode 76
*/
public function testStoreFail()
{
$path = $this->_path . DIRECTORY_SEPARATOR . 'model-store-test.sq3';
if (is_file($path)) {
unlink($path);
}
$options = parse_ini_file(CONF_SAMPLE, true);
$options['purge']['limit'] = 0;
$options['model'] = array(
'class' => 'Database',
);
$options['model_options'] = array(
'dsn' => 'sqlite:' . $path,
'usr' => null,
'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
);
Helper::createIniFile(CONF, $options);
$model = new Model(new Configuration);
$pasteData = Helper::getPastePost();
$model->getPaste(Helper::getPasteId())->delete();
$model->getPaste(Helper::getPasteId())->exists();
$db = new PDO(
$options['model_options']['dsn'],
$options['model_options']['usr'],
$options['model_options']['pwd'],
$options['model_options']['opt']
);
$statement = $db->prepare('DROP TABLE paste');
$statement->execute();
$statement->closeCursor();
$paste = $model->getPaste();
$paste->setData($pasteData);
$paste->store();
}
/**
* @expectedException Exception
* @expectedExceptionCode 70
*/
public function testCommentStoreFail()
{
$path = $this->_path . DIRECTORY_SEPARATOR . 'model-test.sq3';
if (is_file($path)) {
unlink($path);
}
$options = parse_ini_file(CONF_SAMPLE, true);
$options['purge']['limit'] = 0;
$options['model'] = array(
'class' => 'Database',
);
$options['model_options'] = array(
'dsn' => 'sqlite:' . $path,
'usr' => null,
'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
);
Helper::createIniFile(CONF, $options);
$model = new Model(new Configuration);
$pasteData = Helper::getPastePost();
$commentData = Helper::getCommentPost();
$model->getPaste(Helper::getPasteId())->delete();
$paste = $model->getPaste();
$paste->setData($pasteData);
$paste->store();
$db = new PDO(
$options['model_options']['dsn'],
$options['model_options']['usr'],
$options['model_options']['pwd'],
$options['model_options']['opt']
);
$statement = $db->prepare('DROP TABLE comment');
$statement->execute();
$statement->closeCursor();
$comment = $paste->getComment(Helper::getPasteId());
$comment->setData($commentData);
$comment->store();
}
/** /**
* @expectedException Exception * @expectedException Exception
* @expectedExceptionCode 69 * @expectedExceptionCode 69
@ -195,6 +337,18 @@ class ModelTest extends PHPUnit_Framework_TestCase
$paste->get(); $paste->get();
} }
/**
* @expectedException Exception
* @expectedExceptionCode 75
*/
public function testInvalidPasteFormat()
{
$pasteData = Helper::getPastePost();
$pasteData['adata'][1] = 'format does not exist';
$paste = $this->_model->getPaste();
$paste->setData($pasteData);
}
/** /**
* @expectedException Exception * @expectedException Exception
* @expectedExceptionCode 60 * @expectedExceptionCode 60