diff --git a/lib/FormatV2.php b/lib/FormatV2.php index ea0c78ff..7835e817 100644 --- a/lib/FormatV2.php +++ b/lib/FormatV2.php @@ -32,10 +32,12 @@ class FormatV2 */ public static function isValid($message, $isComment = false) { - $required_keys = array('adata', 'meta', 'v', 'ct'); + $required_keys = array('adata', 'v', 'ct'); if ($isComment) { $required_keys[] = 'pasteid'; $required_keys[] = 'parentid'; + } else { + $required_keys[] = 'meta'; } // Make sure no additionnal keys were added. @@ -109,6 +111,15 @@ class FormatV2 return false; } + // require only the key 'expire' in the metadata of pastes + if (!$isComment && ( + count($message['meta']) === 0 || + !array_key_exists('expire', $message['meta']) || + count($message['meta']) > 1 + )) { + return false; + } + return true; } } diff --git a/lib/Model/AbstractModel.php b/lib/Model/AbstractModel.php index 24559b99..ac17ee2f 100644 --- a/lib/Model/AbstractModel.php +++ b/lib/Model/AbstractModel.php @@ -16,7 +16,6 @@ use Exception; use PrivateBin\Configuration; use PrivateBin\Data\AbstractData; use PrivateBin\FormatV2; -use stdClass; /** * AbstractModel @@ -37,9 +36,9 @@ abstract class AbstractModel * Instance data. * * @access protected - * @var stdClass + * @var array */ - protected $_data; + protected $_data = array('meta' => array()); /** * Configuration. @@ -68,8 +67,6 @@ abstract class AbstractModel { $this->_conf = $configuration; $this->_store = $storage; - $this->_data = new stdClass; - $this->_data->meta = new stdClass; } /** @@ -90,7 +87,7 @@ abstract class AbstractModel * @param string $id * @throws Exception */ - public function setId($id) + public function setId(string $id) { if (!self::isValidId($id)) { throw new Exception('Invalid paste ID.', 60); @@ -102,15 +99,17 @@ abstract class AbstractModel * Set data and recalculate ID. * * @access public - * @param string $data + * @param array $data * @throws Exception */ - public function setData($data) + public function setData(array $data) { - if (!FormatV2::isValid($data)) { + if (!FormatV2::isValid($data, $this instanceof Comment)) { throw new Exception('Invalid data.', 61); } - $this->_data->data = $data; + $data = $this->_sanitize($data); + $this->_validate($data); + $this->_data = $data; // calculate a 64 bit checksum to avoid collisions $this->setId(hash('fnv1a64', $data['ct'])); @@ -120,9 +119,12 @@ abstract class AbstractModel * Get instance data. * * @access public - * @return stdClass + * @return array */ - abstract public function get(); + public function get() + { + return $this->_data; + } /** * Store the instance's data. @@ -156,8 +158,29 @@ abstract class AbstractModel * @param string $id * @return bool */ - public static function isValidId($id) + public static function isValidId(string $id) { return (bool) preg_match('#\A[a-f\d]{16}\z#', (string) $id); } + + /** + * Sanitizes data to conform with current configuration. + * + * @access protected + * @param array $data + * @return array + */ + abstract protected function _sanitize(array $data); + + /** + * Validate data. + * + * @access protected + * @param array $data + * @throws Exception + */ + protected function _validate(array $data) + { + return; + } } diff --git a/lib/Model/Comment.php b/lib/Model/Comment.php index 5fbc502d..5737086e 100644 --- a/lib/Model/Comment.php +++ b/lib/Model/Comment.php @@ -15,7 +15,6 @@ namespace PrivateBin\Model; use Exception; use Identicon\Identicon; use PrivateBin\Persistence\TrafficLimiter; -use PrivateBin\FormatV2; use PrivateBin\Vizhash16x16; /** @@ -33,29 +32,6 @@ class Comment extends AbstractModel */ private $_paste; - /** - * Get comment data. - * - * @access public - * @throws Exception - * @return \stdClass - */ - public function get() - { - // @todo add support to read specific comment - $comments = $this->_store->readComments($this->getPaste()->getId()); - foreach ($comments as $comment) { - if ( - $comment->parentid == $this->getParentId() && - $comment->id == $this->getId() - ) { - $this->_data = $comment; - break; - } - } - return $this->_data; - } - /** * Store the comment's data. * @@ -80,7 +56,7 @@ class Comment extends AbstractModel throw new Exception('You are unlucky. Try again.', 69); } - $this->_data->meta->postdate = time(); + $this->_data['meta']['created'] = time(); // store comment if ( @@ -88,7 +64,7 @@ class Comment extends AbstractModel $pasteid, $this->getParentId(), $this->getId(), - json_decode(json_encode($this->_data), true) + $this->_data ) === false ) { throw new Exception('Error saving comment. Sorry.', 70); @@ -130,8 +106,8 @@ class Comment extends AbstractModel */ public function setPaste(Paste $paste) { - $this->_paste = $paste; - $this->_data->meta->pasteid = $paste->getId(); + $this->_paste = $paste; + $this->_data['pasteid'] = $paste->getId(); } /** @@ -157,7 +133,7 @@ class Comment extends AbstractModel if (!self::isValidId($id)) { throw new Exception('Invalid paste ID.', 65); } - $this->_data->meta->parentid = $id; + $this->_data['parentid'] = $id; } /** @@ -168,29 +144,22 @@ class Comment extends AbstractModel */ public function getParentId() { - if (!property_exists($this->_data->meta, 'parentid')) { - $this->_data->meta->parentid = ''; + if (!array_key_exists('parentid', $this->_data)) { + $this->_data['parentid'] = ''; } - return $this->_data->meta->parentid; + return $this->_data['parentid']; } /** - * Set nickname. + * Sanitizes data to conform with current configuration. * - * @access public - * @param string $nickname - * @throws Exception + * @access protected + * @param array $data + * @return array */ - public function setNickname($nickname) + protected function _sanitize(array $data) { - if (!FormatV2::isValid($nickname)) { - throw new Exception('Invalid data.', 66); - } - $this->_data->meta->nickname = $nickname; - - // If a nickname is provided, we generate an icon based on a SHA512 HMAC - // of the users IP. (We assume that if the user did not enter a nickname, - // the user wants to be anonymous and we will not generate an icon.) + // we generate an icon based on a SHA512 HMAC of the users IP, if configured $icon = $this->_conf->getKey('icon'); if ($icon != 'none') { $pngdata = ''; @@ -205,9 +174,12 @@ class Comment extends AbstractModel ); } if ($pngdata != '') { - $this->_data->meta->vizhash = $pngdata; + if (!array_key_exists('meta', $data)) { + $data['meta'] = array(); + } + $data['meta']['icon'] = $pngdata; } } - // Once the icon is generated, we do not keep the IP address hash. + return $data; } } diff --git a/lib/Model/Paste.php b/lib/Model/Paste.php index f68e8e61..cb364eb0 100644 --- a/lib/Model/Paste.php +++ b/lib/Model/Paste.php @@ -15,7 +15,6 @@ namespace PrivateBin\Model; use Exception; use PrivateBin\Controller; use PrivateBin\Persistence\ServerSalt; -use PrivateBin\FormatV2; /** * Paste @@ -28,8 +27,8 @@ class Paste extends AbstractModel * Get paste data. * * @access public - * @throws \Exception - * @return \stdClass + * @throws Exception + * @return array */ public function get() { @@ -39,44 +38,42 @@ class Paste extends AbstractModel } // check if paste has expired and delete it if neccessary. - if (property_exists($data->meta, 'expire_date')) { - if ($data->meta->expire_date < time()) { + if (array_key_exists('expire_date', $data['meta'])) { + if ($data['meta']['expire_date'] < time()) { $this->delete(); throw new Exception(Controller::GENERIC_ERROR, 63); } // We kindly provide the remaining time before expiration (in seconds) - $data->meta->remaining_time = $data->meta->expire_date - time(); + $data['meta']['time_to_live'] = $data['meta']['expire_date'] - time(); } // check if non-expired burn after reading paste needs to be deleted - if (property_exists($data->meta, 'burnafterreading') && $data->meta->burnafterreading) { + if ( + (array_key_exists('adata', $data) && $data['adata'][3] === 1) || + (array_key_exists('burnafterreading', $data['meta']) && $data['meta']['burnafterreading']) + ) { $this->delete(); } - // set formatter for for the view. - if (!property_exists($data->meta, 'formatter')) { + // set formatter for the view in version 1 pastes. + if (array_key_exists('data', $data) && !array_key_exists('formatter', $data['meta'])) { // support < 0.21 syntax highlighting - if (property_exists($data->meta, 'syntaxcoloring') && $data->meta->syntaxcoloring === true) { - $data->meta->formatter = 'syntaxhighlighting'; + if (array_key_exists('syntaxcoloring', $data['meta']) && $data['meta']['syntaxcoloring'] === true) { + $data['meta']['formatter'] = 'syntaxhighlighting'; } else { - $data->meta->formatter = $this->_conf->getKey('defaultformatter'); + $data['meta']['formatter'] = $this->_conf->getKey('defaultformatter'); } } // support old paste format with server wide salt - if (!property_exists($data->meta, 'salt')) { - $data->meta->salt = ServerSalt::get(); - } - $data->comments = array_values($this->getComments()); - $data->comment_count = count($data->comments); - $data->comment_offset = 0; - $data->{'@context'} = 'js/paste.jsonld'; - $this->_data = $data; - - // If the paste was meant to be read only once, delete it. - if ($this->isBurnafterreading()) { - $this->delete(); + if (!array_key_exists('salt', $data['meta'])) { + $data['meta']['salt'] = ServerSalt::get(); } + $data['comments'] = array_values($this->getComments()); + $data['comment_count'] = count($data['comments']); + $data['comment_offset'] = 0; + $data['@context'] = 'js/paste.jsonld'; + $this->_data = $data; return $this->_data; } @@ -94,8 +91,8 @@ class Paste extends AbstractModel throw new Exception('You are unlucky. Try again.', 75); } - $this->_data->meta->postdate = time(); - $this->_data->meta->salt = serversalt::generate(); + $this->_data['meta']['created'] = time(); + $this->_data['meta']['salt'] = serversalt::generate(); // store paste if ( @@ -139,7 +136,7 @@ class Paste extends AbstractModel * @throws Exception * @return Comment */ - public function getComment($parentId, $commentId = null) + public function getComment(string $parentId, string $commentId = '') { if (!$this->exists()) { throw new Exception('Invalid data.', 62); @@ -147,7 +144,7 @@ class Paste extends AbstractModel $comment = new Comment($this->_conf, $this->_store); $comment->setPaste($this); $comment->setParentId($parentId); - if ($commentId !== null) { + if ($commentId !== '') { $comment->setId($commentId); } return $comment; @@ -186,130 +183,6 @@ class Paste extends AbstractModel ); } - /** - * Set paste's attachment. - * - * @access public - * @param string $attachment - * @throws Exception - */ - public function setAttachment($attachment) - { - if (!$this->_conf->getKey('fileupload') || !FormatV2::isValid($attachment)) { - throw new Exception('Invalid attachment.', 71); - } - $this->_data->meta->attachment = $attachment; - } - - /** - * Set paste's attachment name. - * - * @access public - * @param string $attachmentname - * @throws Exception - */ - public function setAttachmentName($attachmentname) - { - if (!$this->_conf->getKey('fileupload') || !FormatV2::isValid($attachmentname)) { - throw new Exception('Invalid attachment.', 72); - } - $this->_data->meta->attachmentname = $attachmentname; - } - - /** - * Set paste expiration. - * - * @access public - * @param string $expiration - */ - public function setExpiration($expiration) - { - $expire_options = $this->_conf->getSection('expire_options'); - if (array_key_exists($expiration, $expire_options)) { - $expire = $expire_options[$expiration]; - } else { - // using getKey() to ensure a default value is present - $expire = $this->_conf->getKey($this->_conf->getKey('default', 'expire'), 'expire_options'); - } - if ($expire > 0) { - $this->_data->meta->expire_date = time() + $expire; - } - } - - /** - * Set paste's burn-after-reading type. - * - * @access public - * @param string $burnafterreading - * @throws Exception - */ - public function setBurnafterreading($burnafterreading = '1') - { - if ($burnafterreading === '0') { - $this->_data->meta->burnafterreading = false; - } else { - if ($burnafterreading !== '1') { - throw new Exception('Invalid data.', 73); - } - $this->_data->meta->burnafterreading = true; - $this->_data->meta->opendiscussion = false; - } - } - - /** - * Set paste's discussion state. - * - * @access public - * @param string $opendiscussion - * @throws Exception - */ - public function setOpendiscussion($opendiscussion = '1') - { - if ( - !$this->_conf->getKey('discussion') || - $this->isBurnafterreading() || - $opendiscussion === '0' - ) { - $this->_data->meta->opendiscussion = false; - } else { - if ($opendiscussion !== '1') { - throw new Exception('Invalid data.', 74); - } - $this->_data->meta->opendiscussion = true; - } - } - - /** - * Set paste's format. - * - * @access public - * @param string $format - * @throws Exception - */ - public function setFormatter($format) - { - if (!array_key_exists($format, $this->_conf->getSection('formatter_options'))) { - $format = $this->_conf->getKey('defaultformatter'); - } - $this->_data->meta->formatter = $format; - } - - /** - * Check if paste is of burn-after-reading type. - * - * @access public - * @throws Exception - * @return bool - */ - public function isBurnafterreading() - { - if (!property_exists($this->_data, 'data')) { - $this->get(); - } - return property_exists($this->_data->meta, 'burnafterreading') && - $this->_data->meta->burnafterreading === true; - } - /** * Check if paste has discussions enabled. * @@ -319,10 +192,67 @@ class Paste extends AbstractModel */ public function isOpendiscussion() { - if (!property_exists($this->_data, 'data')) { + if (!array_key_exists('adata', $this->_data) && !array_key_exists('data', $this->_data)) { $this->get(); } - return property_exists($this->_data->meta, 'opendiscussion') && - $this->_data->meta->opendiscussion === true; + return ( + (array_key_exists('adata', $this->_data) && $this->_data['adata'][2] === 1) || + (array_key_exists('opendiscussion', $this->_data['meta']) && $this->_data['meta']['opendiscussion']) + ); + } + + /** + * Sanitizes data to conform with current configuration. + * + * @access protected + * @param array $data + * @return array + */ + protected function _sanitize(array $data) + { + $expiration = $data['meta']['expire']; + unset($data['meta']['expire']); + $expire_options = $this->_conf->getSection('expire_options'); + if (array_key_exists($expiration, $expire_options)) { + $expire = $expire_options[$expiration]; + } else { + // using getKey() to ensure a default value is present + $expire = $this->_conf->getKey($this->_conf->getKey('default', 'expire'), 'expire_options'); + } + if ($expire > 0) { + $data['meta']['expire_date'] = time() + $expire; + } + return $data; + } + + /** + * Validate data. + * + * @access protected + * @param array $data + * @throws Exception + */ + protected function _validate(array $data) + { + // reject invalid or disabled formatters + if (!array_key_exists($data['adata'][1], $this->_conf->getSection('formatter_options'))) { + throw new Exception('Invalid data.', 75); + } + + // discussion requested, but disabled in config or burn after reading requested as well, or invalid integer + if ( + ($data['adata'][2] === 1 && ( // open discussion flag + !$this->_conf->getKey('discussion') || + $data['adata'][3] === 1 // burn after reading flag + )) || + ($data['adata'][2] !== 0 && $data['adata'][2] !== 1) + ) { + throw new Exception('Invalid data.', 74); + } + + // reject invalid burn after reading + if ($data['adata'][3] !== 0 && $data['adata'][3] !== 1) { + throw new Exception('Invalid data.', 73); + } } } diff --git a/tst/Bootstrap.php b/tst/Bootstrap.php index d8aa025e..c9f7e96a 100644 --- a/tst/Bootstrap.php +++ b/tst/Bootstrap.php @@ -167,6 +167,19 @@ class Helper return json_encode($example); } + /** + * get example paste, as received via POST by user + * + * @param int $version + * @return array + */ + public static function getPastePost() + { + $example = self::getPaste(); + $example['meta'] = array('expire' => $example['meta']['expire']); + return $example; + } + /** * get example paste ID * @@ -203,15 +216,10 @@ class Helper * @param int $version * @return array */ - public static function getCommentPost(int $version = 2) + public static function getCommentPost() { - $example = self::getComment($version); - if ($version === 1) { - $example['nickname'] = $example['meta']['nickname']; - unset($example['meta']['nickname']); - } else { - unset($example['meta']); - } + $example = self::getComment(); + unset($example['meta']); return $example; } diff --git a/tst/Data/FilesystemTest.php b/tst/Data/FilesystemTest.php index 0a122f0b..5e56b5f0 100644 --- a/tst/Data/FilesystemTest.php +++ b/tst/Data/FilesystemTest.php @@ -88,7 +88,7 @@ class FilesystemTest extends PHPUnit_Framework_TestCase $keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'); $ids = array(); foreach ($keys as $key) { - $ids[$key] = substr(md5($key), 0, 16); + $ids[$key] = hash('fnv1a64', $key); $this->assertFalse($this->_model->exists($ids[$key]), "paste $key does not yet exist"); if (in_array($key, array('x', 'y', 'z'))) { $this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste"); diff --git a/tst/ModelTest.php b/tst/ModelTest.php index 8e258f9f..4f02bb4f 100644 --- a/tst/ModelTest.php +++ b/tst/ModelTest.php @@ -54,42 +54,46 @@ class ModelTest extends PHPUnit_Framework_TestCase public function testBasicWorkflow() { // storing pastes - $pasteData = Helper::getPaste(); + $pasteData = Helper::getPastePost(); + unset($pasteData['meta']['created'], $pasteData['meta']['salt']); $this->_model->getPaste(Helper::getPasteId())->delete(); $paste = $this->_model->getPaste(Helper::getPasteId()); $this->assertFalse($paste->exists(), 'paste does not yet exist'); $paste = $this->_model->getPaste(); $paste->setData($pasteData); - $paste->setOpendiscussion(); - $paste->setFormatter($pasteData['adata'][1]); $paste->store(); $paste = $this->_model->getPaste(Helper::getPasteId()); $this->assertTrue($paste->exists(), 'paste exists after storing it'); $paste = $paste->get(); - $this->assertEquals($pasteData, $paste->data); - foreach (array('opendiscussion', 'formatter') as $key) { - $this->assertEquals($pasteData['meta'][$key], $paste->meta->$key); - } + unset( + $pasteData['meta'], + $paste['meta'], + $paste['comments'], + $paste['comment_count'], + $paste['comment_offset'], + $paste['@context'] + ); + $this->assertEquals($pasteData, $paste); // storing comments - $commentData = Helper::getComment(); + $commentData = Helper::getCommentPost(); $paste = $this->_model->getPaste(Helper::getPasteId()); $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId()); $this->assertFalse($comment->exists(), 'comment does not yet exist'); $comment = $paste->getComment(Helper::getPasteId()); $comment->setData($commentData); - $comment->setNickname($commentData['meta']['nickname']); - $comment->getParentId(); + //$comment->getParentId(); $comment->store(); - $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId()); - $this->assertTrue($comment->exists(), 'comment exists after storing it'); - $comment = $comment->get(); - $this->assertEquals($commentData, $comment->data); - $this->assertEquals($commentData['meta']['nickname'], $comment->meta->nickname); + $comments = $this->_model->getPaste(Helper::getPasteId())->get()['comments']; + $this->assertTrue(count($comments) === 1, 'comment exists after storing it'); + $commentData['id'] = Helper::getPasteId(); + $commentData['meta']['created'] = current($comments)['meta']['created']; + $commentData['meta']['icon'] = current($comments)['meta']['icon']; + $this->assertEquals($commentData, current($comments)); // deleting pastes $this->_model->getPaste(Helper::getPasteId())->delete(); @@ -104,19 +108,15 @@ class ModelTest extends PHPUnit_Framework_TestCase */ public function testPasteDuplicate() { - $pasteData = Helper::getPaste(); + $pasteData = Helper::getPastePost(); $this->_model->getPaste(Helper::getPasteId())->delete(); $paste = $this->_model->getPaste(); $paste->setData($pasteData); - $paste->setOpendiscussion(); - $paste->setFormatter($pasteData['adata'][1]); $paste->store(); $paste = $this->_model->getPaste(); $paste->setData($pasteData); - $paste->setOpendiscussion(); - $paste->setFormatter($pasteData['adata'][1]); $paste->store(); } @@ -126,61 +126,42 @@ class ModelTest extends PHPUnit_Framework_TestCase */ public function testCommentDuplicate() { - $pasteData = Helper::getPaste(); - $commentData = Helper::getComment(); + $pasteData = Helper::getPastePost(); + $commentData = Helper::getCommentPost(); $this->_model->getPaste(Helper::getPasteId())->delete(); $paste = $this->_model->getPaste(); $paste->setData($pasteData); - $paste->setOpendiscussion(); - $paste->setFormatter($pasteData['adata'][1]); $paste->store(); $comment = $paste->getComment(Helper::getPasteId()); $comment->setData($commentData); - $comment->setNickname($commentData['meta']['nickname']); $comment->store(); $comment = $paste->getComment(Helper::getPasteId()); $comment->setData($commentData); - $comment->setNickname($commentData['meta']['nickname']); $comment->store(); } public function testImplicitDefaults() { - $pasteData = Helper::getPaste(); - $commentData = Helper::getComment(); + $pasteData = Helper::getPastePost(); + $commentData = Helper::getCommentPost(); $this->_model->getPaste(Helper::getPasteId())->delete(); $paste = $this->_model->getPaste(); $paste->setData($pasteData); - $paste->setBurnafterreading(); - $paste->setOpendiscussion(); - // not setting a formatter, should use default one - $paste->store(); - - $paste = $this->_model->getPaste(Helper::getPasteId())->get(); // ID was set based on data - $this->assertEquals(true, property_exists($paste->meta, 'burnafterreading') && $paste->meta->burnafterreading, 'burn after reading takes precendence'); - $this->assertEquals(false, property_exists($paste->meta, 'opendiscussion') && $paste->meta->opendiscussion, 'opendiscussion is disabled'); - $this->assertEquals($this->_conf->getKey('defaultformatter'), $paste->meta->formatter, 'default formatter is set'); - - $this->_model->getPaste(Helper::getPasteId())->delete(); - $paste = $this->_model->getPaste(); - $paste->setData($pasteData); - $paste->setBurnafterreading('0'); - $paste->setOpendiscussion(); $paste->store(); $comment = $paste->getComment(Helper::getPasteId()); $comment->setData($commentData); - $comment->setNickname($commentData['meta']['nickname']); + $comment->get(); $comment->store(); $identicon = new Identicon(); $pngdata = $identicon->getImageDataUri(TrafficLimiter::getHash(), 16); - $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId())->get(); - $this->assertEquals($pngdata, $comment->meta->vizhash, 'nickname triggers vizhash to be set'); + $comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']); + $this->assertEquals($pngdata, $comment['meta']['icon'], 'icon gets set'); } public function testPasteIdValidation() @@ -201,6 +182,15 @@ class ModelTest extends PHPUnit_Framework_TestCase $paste->get(); } + /** + * @expectedException Exception + * @expectedExceptionCode 60 + */ + public function testInvalidPasteId() + { + $this->_model->getPaste(''); + } + /** * @expectedException Exception * @expectedExceptionCode 61 @@ -227,7 +217,7 @@ class ModelTest extends PHPUnit_Framework_TestCase */ public function testInvalidCommentDeletedPaste() { - $pasteData = Helper::getPaste(); + $pasteData = Helper::getPastePost(); $paste = $this->_model->getPaste(Helper::getPasteId()); $paste->setData($pasteData); $paste->store(); @@ -243,7 +233,8 @@ class ModelTest extends PHPUnit_Framework_TestCase */ public function testInvalidCommentData() { - $pasteData = Helper::getPaste(); + $pasteData = Helper::getPastePost(); + $pasteData['adata'][2] = 0; $paste = $this->_model->getPaste(Helper::getPasteId()); $paste->setData($pasteData); $paste->store(); @@ -252,20 +243,30 @@ class ModelTest extends PHPUnit_Framework_TestCase $comment->store(); } + /** + * @expectedException Exception + * @expectedExceptionCode 65 + */ + public function testInvalidCommentParent() + { + $paste = $this->_model->getPaste(Helper::getPasteId()); + $comment = $paste->getComment(''); + $comment->store(); + } + public function testExpiration() { - $pasteData = Helper::getPaste(); + $pasteData = Helper::getPastePost(); $this->_model->getPaste(Helper::getPasteId())->delete(); $paste = $this->_model->getPaste(Helper::getPasteId()); $this->assertFalse($paste->exists(), 'paste does not yet exist'); $paste = $this->_model->getPaste(); $paste->setData($pasteData); - $paste->setExpiration('5min'); // = 300 seconds $paste->store(); $paste = $paste->get(); - $this->assertEquals(300, $paste->meta->remaining_time, 'remaining time is set correctly'); + $this->assertEquals((float) 300, (float) $paste['meta']['time_to_live'], 'remaining time is set correctly', 1.0); } /** @@ -274,7 +275,7 @@ class ModelTest extends PHPUnit_Framework_TestCase */ public function testCommentDeletion() { - $pasteData = Helper::getPaste(); + $pasteData = Helper::getPastePost(); $this->_model->getPaste(Helper::getPasteId())->delete(); $paste = $this->_model->getPaste(); @@ -288,12 +289,12 @@ class ModelTest extends PHPUnit_Framework_TestCase $conf = new Configuration; $store = Database::getInstance($conf->getSection('model_options')); $store->delete(Helper::getPasteId()); - $expired = Helper::getPaste(array('expire_date' => 1344803344)); - $paste = Helper::getPaste(array('expire_date' => time() + 3600)); + $expired = Helper::getPaste(2, array('expire_date' => 1344803344)); + $paste = Helper::getPaste(2, array('expire_date' => time() + 3600)); $keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'x', 'y', 'z'); $ids = array(); foreach ($keys as $key) { - $ids[$key] = substr(md5($key), 0, 16); + $ids[$key] = hash('fnv1a64', $key); $store->delete($ids[$key]); $this->assertFalse($store->exists($ids[$key]), "paste $key does not yet exist"); if (in_array($key, array('x', 'y', 'z'))) { @@ -330,79 +331,34 @@ class ModelTest extends PHPUnit_Framework_TestCase Helper::createIniFile(CONF, $options); $model = new Model(new Configuration); - $pasteData = Helper::getPaste(); + $pasteData = Helper::getPastePost(); $this->_model->getPaste(Helper::getPasteId())->delete(); $paste = $model->getPaste(Helper::getPasteId()); $this->assertFalse($paste->exists(), 'paste does not yet exist'); $paste = $model->getPaste(); $paste->setData($pasteData); - $paste->setOpendiscussion(); - $paste->setFormatter($pasteData['adata'][1]); $paste->store(); $paste = $model->getPaste(Helper::getPasteId()); $this->assertTrue($paste->exists(), 'paste exists after storing it'); - $paste = $paste->get(); - $this->assertEquals($pasteData, $paste->data); - foreach (array('opendiscussion', 'formatter') as $key) { - $this->assertEquals($pasteData['meta'][$key], $paste->meta->$key); - } // storing comments - $commentData = Helper::getComment(); + $commentData = Helper::getCommentPost(); + unset($commentData['meta']['icon']); $paste = $model->getPaste(Helper::getPasteId()); - $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId()); + $comment = $paste->getComment(Helper::getPasteId(), Helper::getPasteId()); $this->assertFalse($comment->exists(), 'comment does not yet exist'); $comment = $paste->getComment(Helper::getPasteId()); $comment->setData($commentData); - $comment->setNickname($commentData['meta']['nickname']); $comment->store(); - $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId()); + $comment = $paste->getComment(Helper::getPasteId(), Helper::getPasteId()); $this->assertTrue($comment->exists(), 'comment exists after storing it'); - $comment = $comment->get(); - $this->assertEquals($commentData, $comment->data); - $this->assertEquals($commentData['meta']['nickname'], $comment->meta->nickname); - $this->assertFalse(property_exists($comment->meta, 'vizhash'), 'vizhash was not generated'); - } - public function testCommentIdenticon() - { - $options = parse_ini_file(CONF, true); - $options['main']['icon'] = 'identicon'; - $options['model'] = array( - 'class' => 'Database', - ); - $options['model_options'] = array( - 'dsn' => 'sqlite::memory:', - 'usr' => null, - 'pwd' => null, - 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION), - ); - Helper::createIniFile(CONF, $options); - $model = new Model(new Configuration); - - $pasteData = Helper::getPaste(); - $commentData = Helper::getComment(); - $model->getPaste(Helper::getPasteId())->delete(); - - $paste = $model->getPaste(); - $paste->setData($pasteData); - $paste->setOpendiscussion(); - $paste->setFormatter($pasteData['adata'][1]); - $paste->store(); - - $comment = $paste->getComment(Helper::getPasteId()); - $comment->setData($commentData); - $comment->setNickname($commentData['meta']['nickname']); - $comment->store(); - - $identicon = new Identicon(); - $pngdata = $identicon->getImageDataUri(TrafficLimiter::getHash(), 16); - $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId())->get(); - $this->assertEquals($pngdata, $comment->meta->vizhash, 'nickname triggers vizhash to be set'); + $comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']); + $this->assertFalse(array_key_exists('icon', $comment['meta']), 'icon was not generated'); } public function testCommentVizhash() @@ -421,24 +377,21 @@ class ModelTest extends PHPUnit_Framework_TestCase Helper::createIniFile(CONF, $options); $model = new Model(new Configuration); - $pasteData = Helper::getPaste(); - $commentData = Helper::getComment(); + $pasteData = Helper::getPastePost(); + $commentData = Helper::getCommentPost(); $model->getPaste(Helper::getPasteId())->delete(); $paste = $model->getPaste(); $paste->setData($pasteData); - $paste->setOpendiscussion(); - $paste->setFormatter($pasteData['adata'][1]); $paste->store(); $comment = $paste->getComment(Helper::getPasteId()); $comment->setData($commentData); - $comment->setNickname($commentData['meta']['nickname']); $comment->store(); $vz = new Vizhash16x16(); $pngdata = 'data:image/png;base64,' . base64_encode($vz->generate(TrafficLimiter::getHash())); - $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId())->get(); - $this->assertEquals($pngdata, $comment->meta->vizhash, 'nickname triggers vizhash to be set'); + $comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']); + $this->assertEquals($pngdata, $comment['meta']['icon'], 'nickname triggers vizhash to be set'); } }