diff --git a/lib/trafficlimiter.php b/lib/trafficlimiter.php index 0734370..4b7b4e2 100644 --- a/lib/trafficlimiter.php +++ b/lib/trafficlimiter.php @@ -26,6 +26,15 @@ class trafficlimiter extends persistence */ private static $_limit = 10; + /** + * key to fetch IP address + * + * @access private + * @static + * @var string + */ + private static $_ipKey = 'REMOTE_ADDR'; + /** * set the time limit in seconds * @@ -39,6 +48,40 @@ class trafficlimiter extends persistence self::$_limit = $limit; } + /** + * set configuration options of the traffic limiter + * + * @access public + * @static + * @param configuration $conf + * @return void + */ + public static function setConfiguration(configuration $conf) + { + self::setLimit($conf->getKey('limit', 'traffic')); + self::setPath($conf->getKey('dir', 'traffic')); + if (($option = $conf->getKey('header', 'traffic')) !== null) + { + $httpHeader = 'HTTP_' . $option; + if (array_key_exists($httpHeader, $_SERVER) && !empty($_SERVER[$httpHeader])) + { + self::$_ipKey = $httpHeader; + } + } + } + + /** + * get the current visitors IP address + * + * @access public + * @static + * @return string + */ + public static function getIp() + { + return $_SERVER[self::$_ipKey]; + } + /** * traffic limiter * @@ -46,14 +89,15 @@ class trafficlimiter extends persistence * * @access public * @static - * @param string $ip * @throws Exception * @return bool */ - public static function canPass($ip) + public static function canPass() { - // disable limits if set to less then 1 - if (self::$_limit < 1) return true; + $ip = self::getIp(); + + // disable limits if set to less then 1 + if (self::$_limit < 1) return true; $file = 'traffic_limiter.php'; if (!self::_exists($file)) diff --git a/lib/zerobin.php b/lib/zerobin.php index 5a4b6fd..f0c6897 100644 --- a/lib/zerobin.php +++ b/lib/zerobin.php @@ -215,18 +215,8 @@ class zerobin $attachmentname = $has_attachmentname ? $_POST['attachmentname'] : ''; // Make sure last paste from the IP address was more than X seconds ago. - trafficlimiter::setLimit($this->_conf->getKey('limit', 'traffic')); - trafficlimiter::setPath($this->_conf->getKey('dir', 'traffic')); - $ipKey = 'REMOTE_ADDR'; - if (($option = $this->_conf->getKey('header', 'traffic')) !== null) - { - $header = 'HTTP_' . $option; - if (array_key_exists($header, $_SERVER) && !empty($_SERVER[$header])) - { - $ipKey = $header; - } - } - if (!trafficlimiter::canPass($_SERVER[$ipKey])) return $this->_return_message( + trafficlimiter::setConfiguration($this->_conf); + if (!trafficlimiter::canPass()) return $this->_return_message( 1, i18n::_( 'Please wait %d seconds between each post.', @@ -334,7 +324,7 @@ class zerobin { $meta['nickname'] = $nick; $vz = new vizhash16x16(); - $pngdata = $vz->generate($_SERVER['REMOTE_ADDR']); + $pngdata = $vz->generate(trafficlimiter::getIp()); if ($pngdata != '') { $meta['vizhash'] = 'data:image/png;base64,' . base64_encode($pngdata); diff --git a/tst/model.php b/tst/model.php new file mode 100644 index 0000000..8a270d6 --- /dev/null +++ b/tst/model.php @@ -0,0 +1,154 @@ + 'zerobin_db', + ); + $options['model_options'] = array( + 'dsn' => 'sqlite::memory:', + 'usr' => null, + 'pwd' => null, + 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION), + ); + helper::confBackup(); + helper::createIniFile(CONF, $options); + $this->_conf = new configuration; + $this->_model = new model($this->_conf); + } + + public function tearDown() + { + /* Tear Down Routine */ + } + + public function testBasicWorkflow() + { + // storing pastes + $pasteData = helper::getPaste(); + $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['data']); + $paste->setOpendiscussion(); + $paste->setFormatter($pasteData['meta']['formatter']); + $paste->store(); + + $paste = $this->_model->getPaste(helper::getPasteId()); + $this->assertTrue($paste->exists(), 'paste exists after storing it'); + $paste = $paste->get(); + foreach (array('data', 'opendiscussion', 'formatter') as $key) { + $this->assertEquals($pasteData[$key], $paste->$key); + } + + // storing comments + $commentData = helper::getComment(); + $comment = $paste->getComment(helper::getPasteId(), helper::getCommentId()); + $this->assertFalse($comment->exists(), 'comment does not yet exist'); + + $comment = $paste->getComment(helper::getPasteId()); + $comment->setData($commentData['data']); + $comment->setNickname($commentData['meta']['nickname']); + $comment->store(); + + $comment = $paste->getComment(helper::getPasteId(), helper::getCommentId()); + $this->assertTrue($comment->exists(), 'comment exists after storing it'); + $comment = $comment->get(); + $this->assertEquals($commentData['data'], $comment->data); + $this->assertEquals($commentData['meta']['nickname'], $comment->meta->nickname); + + // deleting pastes + $this->_model->getPaste(helper::getPasteId())->delete(); + $paste = $this->_model->getPaste(helper::getPasteId()); + $this->assertFalse($paste->exists(), 'paste successfully deleted'); + $this->assertEquals(array(), $paste->getComments(), 'comment was deleted with paste'); + } + + /** + * @expectedException Exception + * @expectedExceptionCode 60 + */ + public function testPasteDuplicate() + { + $pasteData = helper::getPaste(); + + $this->_model->getPaste(helper::getPasteId())->delete(); + $paste = $this->_model->getPaste(); + $paste->setData($pasteData['data']); + $paste->setOpendiscussion(); + $paste->setFormatter($pasteData['meta']['formatter']); + $paste->store(); + + $paste = $this->_model->getPaste(); + $paste->setData($pasteData['data']); + $paste->setOpendiscussion(); + $paste->setFormatter($pasteData['meta']['formatter']); + $paste->store(); + } + + /** + * @expectedException Exception + * @expectedExceptionCode 60 + */ + public function testCommentDuplicate() + { + $pasteData = helper::getPaste(); + $commentData = helper::getComment(); + $this->_model->getPaste(helper::getPasteId())->delete(); + + $paste = $this->_model->getPaste(); + $paste->setData($pasteData['data']); + $paste->setOpendiscussion(); + $paste->setFormatter($pasteData['meta']['formatter']); + $paste->store(); + + $comment = $paste->getComment(helper::getPasteId()); + $comment->setData($commentData['data']); + $comment->setNickname($commentData['meta']['nickname']); + $comment->store(); + + $comment = $paste->getComment(helper::getPasteId()); + $comment->setData($commentData['data']); + $comment->setNickname($commentData['meta']['nickname']); + $comment->store(); + } + + public function testImplicitDefaults() + { + $pasteData = helper::getPaste(); + $commentData = helper::getComment(); + $this->_model->getPaste(helper::getPasteId())->delete(); + + $paste = $this->_model->getPaste(); + $paste->setData($pasteData['data']); + $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, $paste->meta->burnafterreading, 'burn after reading takes precedence'); + $this->assertEquals(false, $paste->meta->opendiscussion, 'opendiscussion is overiden'); + $this->assertEquals($this->_conf->getKey('defaultformatter'), $paste->meta->formatter, 'default formatter is set'); + + $_SERVER['REMOTE_ADDR'] = '::1'; + $vz = new vizhash16x16(); + $pngdata = 'data:image/png;base64,' . base64_encode($vz->generate($_SERVER['REMOTE_ADDR'])); + $comment = $this->_model->getPaste(helper::getPasteId())->getComment(helper::getPasteId()); + $comment->setData($commentData['data']); + $comment->setNickname($commentData['meta']['nickname']); + $comment->store(); + + $comment = $paste->getComment(helper::getPasteId(), helper::getCommentId()); + $this->assertEquals($pngdata, $comment->meta->vizhash, 'nickname triggers vizhash to be set'); + } +} \ No newline at end of file diff --git a/tst/trafficlimiter.php b/tst/trafficlimiter.php index 97b8655..94c41e6 100644 --- a/tst/trafficlimiter.php +++ b/tst/trafficlimiter.php @@ -22,12 +22,15 @@ class trafficlimiterTest extends PHPUnit_Framework_TestCase $file = 'baz'; $this->assertEquals($this->_path . DIRECTORY_SEPARATOR . $file, trafficlimiter::getPath($file)); trafficlimiter::setLimit(4); - $this->assertTrue(trafficlimiter::canPass('127.0.0.1'), 'first request may pass'); + $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; + $this->assertTrue(trafficlimiter::canPass(), 'first request may pass'); sleep(2); - $this->assertFalse(trafficlimiter::canPass('127.0.0.1'), 'second request is to fast, may not pass'); + $this->assertFalse(trafficlimiter::canPass(), 'second request is to fast, may not pass'); sleep(3); - $this->assertTrue(trafficlimiter::canPass('127.0.0.1'), 'third request waited long enough and may pass'); - $this->assertTrue(trafficlimiter::canPass('2001:1620:2057:dead:beef::cafe:babe'), 'fourth request has different ip and may pass'); - $this->assertFalse(trafficlimiter::canPass('127.0.0.1'), 'fifth request is to fast, may not pass'); + $this->assertTrue(trafficlimiter::canPass(), 'third request waited long enough and may pass'); + $_SERVER['REMOTE_ADDR'] = '2001:1620:2057:dead:beef::cafe:babe'; + $this->assertTrue(trafficlimiter::canPass(), 'fourth request has different ip and may pass'); + $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; + $this->assertFalse(trafficlimiter::canPass(), 'fifth request is to fast, may not pass'); } }