diff --git a/cfg/conf.ini.sample b/cfg/conf.ini.sample index 8e1204f..adf2e06 100644 --- a/cfg/conf.ini.sample +++ b/cfg/conf.ini.sample @@ -107,8 +107,7 @@ dir = PATH "data" [purge] ; minimum time limit between two purgings of expired pastes, it is only ; triggered when pastes are created -; Set this to 0 to disable purging. Set it to run more frequently, if you are -; running a large site. +; Set this to 0 to run a purge every time a paste is created. limit = 300 ; maximum amount of expired pastes to delete in one purge diff --git a/lib/privatebin/data.php b/lib/privatebin/data.php index 55f27c6..285c538 100644 --- a/lib/privatebin/data.php +++ b/lib/privatebin/data.php @@ -243,7 +243,8 @@ class privatebin_data extends privatebin_abstract } $secondKey = array_rand($secondLevel); - $path = self::$_dir . $firstLevel[$firstKey] . '/' . $secondLevel[$secondKey]; + $path = self::$_dir . $firstLevel[$firstKey] . + DIRECTORY_SEPARATOR . $secondLevel[$secondKey]; if (!is_dir($path)) continue; $thirdLevel = array_filter( scandir($path), @@ -310,7 +311,8 @@ class privatebin_data extends privatebin_abstract */ private static function _dataid2path($dataid) { - return self::$_dir . substr($dataid,0,2) . '/' . substr($dataid,2,2) . '/'; + return self::$_dir . substr($dataid,0,2) . DIRECTORY_SEPARATOR . + substr($dataid,2,2) . DIRECTORY_SEPARATOR; } /** @@ -325,7 +327,8 @@ class privatebin_data extends privatebin_abstract */ private static function _dataid2discussionpath($dataid) { - return self::_dataid2path($dataid) . $dataid . '.discussion/'; + return self::_dataid2path($dataid) . $dataid . + '.discussion' . DIRECTORY_SEPARATOR; } /** @@ -338,7 +341,8 @@ class privatebin_data extends privatebin_abstract */ private static function _isFirstLevelDir($element) { - return self::_isSecondLevelDir($element) && is_dir(self::$_dir . '/' . $element); + return self::_isSecondLevelDir($element) && + is_dir(self::$_dir . DIRECTORY_SEPARATOR . $element); } /** diff --git a/lib/privatebin/db.php b/lib/privatebin/db.php index 08b495e..8835b4b 100644 --- a/lib/privatebin/db.php +++ b/lib/privatebin/db.php @@ -607,8 +607,8 @@ class privatebin_db extends privatebin_abstract "postdate INT$after_key );" ); self::$_db->exec( - 'CREATE INDEX parent ON ' . self::_sanitizeIdentifier('comment') . - '(pasteid);' + 'CREATE INDEX IF NOT EXISTS comment_parent ON ' . + self::_sanitizeIdentifier('comment') . '(pasteid);' ); } @@ -689,14 +689,17 @@ class privatebin_db extends privatebin_abstract else { self::$_db->exec( - 'CREATE UNIQUE INDEX primary ON ' . self::_sanitizeIdentifier('paste') . '(dataid);' + 'CREATE UNIQUE INDEX IF NOT EXISTS paste_dataid ON ' . + self::_sanitizeIdentifier('paste') . '(dataid);' ); self::$_db->exec( - 'CREATE UNIQUE INDEX primary ON ' . self::_sanitizeIdentifier('comment') . '(dataid);' + 'CREATE UNIQUE INDEX IF NOT EXISTS comment_dataid ON ' . + self::_sanitizeIdentifier('comment') . '(dataid);' ); } self::$_db->exec( - 'CREATE INDEX parent ON ' . self::_sanitizeIdentifier('comment') . '(pasteid);' + 'CREATE INDEX IF NOT EXISTS comment_parent ON ' . + self::_sanitizeIdentifier('comment') . '(pasteid);' ); } } diff --git a/tst/model.php b/tst/model.php index 92f8b65..42fbf52 100644 --- a/tst/model.php +++ b/tst/model.php @@ -8,7 +8,9 @@ class modelTest extends PHPUnit_Framework_TestCase public function setUp() { /* Setup Routine */ + helper::confRestore(); $options = parse_ini_file(CONF, true); + $options['purge']['limit'] = 0; $options['model'] = array( 'class' => 'privatebin_db', ); @@ -209,6 +211,45 @@ class modelTest extends PHPUnit_Framework_TestCase $paste->getComment(helper::getPasteId())->delete(); } + public function testPurge() + { + $conf = new configuration; + $store = privatebin_db::getInstance($conf->getSection('model_options')); + $store->delete(helper::getPasteId()); + $expired = helper::getPaste(array('expire_date' => 1344803344)); + $paste = helper::getPaste(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); + $store->delete($ids[$key]); + $this->assertFalse($store->exists($ids[$key]), "paste $key does not yet exist"); + if (in_array($key, array('x', 'y', 'z'))) + { + $this->assertTrue($store->create($ids[$key], $paste), "store $key paste"); + } + else + { + $this->assertTrue($store->create($ids[$key], $expired), "store $key paste"); + } + $this->assertTrue($store->exists($ids[$key]), "paste $key exists after storing it"); + } + $this->_model->purge(10); + foreach ($ids as $key => $id) + { + if (in_array($key, array('x', 'y', 'z'))) + { + $this->assertTrue($this->_model->getPaste($ids[$key])->exists(), "paste $key exists after purge"); + $this->_model->getPaste($ids[$key])->delete(); + } + else + { + $this->assertFalse($this->_model->getPaste($ids[$key])->exists(), "paste $key was purged"); + } + } + } + public function testCommentWithDisabledVizhash() { $options = parse_ini_file(CONF, true); diff --git a/tst/privatebin.php b/tst/privatebin.php index bf2ccc0..5086207 100644 --- a/tst/privatebin.php +++ b/tst/privatebin.php @@ -7,7 +7,6 @@ class privatebinTest extends PHPUnit_Framework_TestCase { /* Setup Routine */ $this->_model = privatebin_data::getInstance(array('dir' => PATH . 'data')); - serversalt::setPath(PATH . 'data'); $this->reset(); } @@ -456,6 +455,28 @@ class privatebinTest extends PHPUnit_Framework_TestCase ); } + /** + * @runInSeparateProcess + */ + public function testCreateTooSoon() + { + $this->reset(); + $_POST = helper::getPaste(); + $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_SERVER['REMOTE_ADDR'] = '::1'; + ob_start(); + new privatebin; + ob_end_clean(); + $this->_model->delete(helper::getPasteId()); + ob_start(); + new privatebin; + $content = ob_get_contents(); + $response = json_decode($content, true); + $this->assertEquals(1, $response['status'], 'outputs error status'); + $this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste exists after posting data'); + } + /** * @runInSeparateProcess */ diff --git a/tst/privatebin/data.php b/tst/privatebin/data.php index 0372b5a..6184b37 100644 --- a/tst/privatebin/data.php +++ b/tst/privatebin/data.php @@ -65,6 +65,7 @@ class privatebin_dataTest extends PHPUnit_Framework_TestCase public function testPurge() { + mkdir($this->_path . DIRECTORY_SEPARATOR . '00', 0777, true); $expired = helper::getPaste(array('expire_date' => 1344803344)); $paste = helper::getPaste(array('expire_date' => time() + 3600)); $keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'x', 'y', 'z'); diff --git a/tst/privatebin/db.php b/tst/privatebin/db.php index 2c8d3b5..0cbf2c1 100644 --- a/tst/privatebin/db.php +++ b/tst/privatebin/db.php @@ -78,6 +78,7 @@ class privatebin_dbTest extends PHPUnit_Framework_TestCase foreach ($keys as $key) { $ids[$key] = substr(md5($key), 0, 16); + $this->_model->delete($ids[$key]); $this->assertFalse($this->_model->exists($ids[$key]), "paste $key does not yet exist"); if (in_array($key, array('x', 'y', 'z'))) { @@ -95,6 +96,7 @@ class privatebin_dbTest extends PHPUnit_Framework_TestCase if (in_array($key, array('x', 'y', 'z'))) { $this->assertTrue($this->_model->exists($ids[$key]), "paste $key exists after purge"); + $this->_model->delete($ids[$key]); } else { @@ -224,10 +226,53 @@ class privatebin_dbTest extends PHPUnit_Framework_TestCase privatebin_db::getInstance($options); } + public function testOldAttachments() + { + mkdir(PATH . 'data'); + $path = PATH . 'data' . DIRECTORY_SEPARATOR . 'attachement-test.sq3'; + @unlink($path); + $this->_options['dsn'] = 'sqlite:' . $path; + $this->_options['tbl'] = 'bar_'; + $model = privatebin_db::getInstance($this->_options); + + $original = $paste = helper::getPasteWithAttachment(array('expire_date' => 1344803344)); + $paste['meta']['attachment'] = $paste['attachment']; + $paste['meta']['attachmentname'] = $paste['attachmentname']; + unset($paste['attachment'], $paste['attachmentname']); + $meta = $paste['meta']; + + $db = new PDO( + $this->_options['dsn'], + $this->_options['usr'], + $this->_options['pwd'], + $this->_options['opt'] + ); + $statement = $db->prepare('INSERT INTO bar_paste VALUES(?,?,?,?,?,?,?,?,?)'); + $statement->execute( + array( + helper::getPasteId(), + $paste['data'], + $paste['meta']['postdate'], + 1344803344, + 0, + 0, + json_encode($meta), + null, + null, + ) + ); + $statement->closeCursor(); + + $this->assertTrue($model->exists(helper::getPasteId()), 'paste exists after storing it'); + $this->assertEquals(json_decode(json_encode($original)), $model->read(helper::getPasteId())); + + helper::rmdir(PATH . 'data'); + } + public function testTableUpgrade() { mkdir(PATH . 'data'); - $path = PATH . 'data/db-test.sq3'; + $path = PATH . 'data' . DIRECTORY_SEPARATOR . 'db-test.sq3'; @unlink($path); $this->_options['dsn'] = 'sqlite:' . $path; $this->_options['tbl'] = 'foo_'; @@ -246,7 +291,17 @@ class privatebin_dbTest extends PHPUnit_Framework_TestCase 'opendiscussion INT, ' . 'burnafterreading INT );' ); + $db->exec( + 'CREATE TABLE foo_comment ( ' . + "dataid CHAR(16) NOT NULL, " . + 'pasteid CHAR(16), ' . + 'parentid CHAR(16), ' . + 'data BLOB, ' . + 'nickname BLOB, ' . + 'vizhash BLOB, ' . + "postdate INT );" + ); privatebin_db::getInstance($this->_options); - @unlink($path); + helper::rmdir(PATH . 'data'); } } diff --git a/tst/privatebinWithDb.php b/tst/privatebinWithDb.php index bd2d85a..a8a8dec 100644 --- a/tst/privatebinWithDb.php +++ b/tst/privatebinWithDb.php @@ -19,7 +19,7 @@ class privatebinWithDbTest extends privatebinTest /* Setup Routine */ $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data'; if(!is_dir($this->_path)) mkdir($this->_path); - $this->_options['dsn'] = 'sqlite:' . $this->_path . '/tst.sq3'; + $this->_options['dsn'] = 'sqlite:' . $this->_path . DIRECTORY_SEPARATOR . 'tst.sq3'; $this->_model = privatebin_db::getInstance($this->_options); $this->reset(); }