updated .htaccess format, refactored .htaccess creation logic and improving code coverage, fixes #194

This commit is contained in:
El RIDO 2017-03-24 21:30:08 +01:00
parent 88b02d866e
commit ce92bfa934
No known key found for this signature in database
GPG key ID: 0F5C940A6BD81F92
10 changed files with 119 additions and 44 deletions

1
.gitignore vendored
View file

@ -31,6 +31,7 @@ vendor/**/build_phar.php
# Ignore local node modules, unit testing logs, api docs and eclipse project files # Ignore local node modules, unit testing logs, api docs and eclipse project files
js/node_modules/ js/node_modules/
tst/log/ tst/log/
tst/ConfigurationCombinationsTest.php
.settings .settings
.buildpath .buildpath
.project .project

View file

@ -12,6 +12,7 @@
namespace PrivateBin\Data; namespace PrivateBin\Data;
use Exception;
use PrivateBin\Json; use PrivateBin\Json;
use PrivateBin\Model\Paste; use PrivateBin\Model\Paste;
@ -41,16 +42,16 @@ class Filesystem extends AbstractData
*/ */
public static function getInstance($options = null) public static function getInstance($options = null)
{ {
// if needed initialize the singleton
if (!(self::$_instance instanceof self)) {
self::$_instance = new self;
}
// if given update the data directory // if given update the data directory
if ( if (
is_array($options) && is_array($options) &&
array_key_exists('dir', $options) array_key_exists('dir', $options)
) { ) {
self::$_dir = $options['dir'] . DIRECTORY_SEPARATOR; self::$_dir = $options['dir'] . DIRECTORY_SEPARATOR;
}
// if needed initialize the singleton
if (!(self::$_instance instanceof self)) {
self::$_instance = new self;
self::_init(); self::_init();
} }
return self::$_instance; return self::$_instance;
@ -293,7 +294,7 @@ class Filesystem extends AbstractData
} }
/** /**
* initialize privatebin * Initialize data store
* *
* @access private * @access private
* @static * @static
@ -303,15 +304,20 @@ class Filesystem extends AbstractData
{ {
// Create storage directory if it does not exist. // Create storage directory if it does not exist.
if (!is_dir(self::$_dir)) { if (!is_dir(self::$_dir)) {
mkdir(self::$_dir, 0700); if (!@mkdir(self::$_dir, 0700)) {
throw new Exception('unable to create directory ' . self::$_dir, 10);
} }
// Create .htaccess file if it does not exist. }
if (!is_file(self::$_dir . '.htaccess')) { $file = self::$_dir . DIRECTORY_SEPARATOR . '.htaccess';
file_put_contents( if (!is_file($file)) {
self::$_dir . '.htaccess', $writtenBytes = @file_put_contents(
'Allow from none' . PHP_EOL . $file,
'Deny from all' . PHP_EOL 'Require all denied' . PHP_EOL,
LOCK_EX
); );
if ($writtenBytes === false || $writtenBytes < 19) {
throw new Exception('unable to write to file ' . $file, 11);
}
} }
} }

View file

@ -86,21 +86,18 @@ abstract class AbstractPersistence
{ {
// Create storage directory if it does not exist. // Create storage directory if it does not exist.
if (!is_dir(self::$_path)) { if (!is_dir(self::$_path)) {
if (!@mkdir(self::$_path)) { if (!@mkdir(self::$_path, 0700)) {
throw new Exception('unable to create directory ' . self::$_path, 10); throw new Exception('unable to create directory ' . self::$_path, 10);
} }
} }
// Create .htaccess file if it does not exist.
$file = self::$_path . DIRECTORY_SEPARATOR . '.htaccess'; $file = self::$_path . DIRECTORY_SEPARATOR . '.htaccess';
if (!is_file($file)) { if (!is_file($file)) {
$writtenBytes = @file_put_contents( $writtenBytes = @file_put_contents(
$file, $file,
'Allow from none' . PHP_EOL . 'Require all denied' . PHP_EOL,
'Deny from all' . PHP_EOL,
LOCK_EX LOCK_EX
); );
if ($writtenBytes === false || $writtenBytes < 30) { if ($writtenBytes === false || $writtenBytes < 19) {
throw new Exception('unable to write to file ' . $file, 11); throw new Exception('unable to write to file ' . $file, 11);
} }
} }

View file

@ -175,17 +175,6 @@ class PrivateBin
*/ */
private function _init() private function _init()
{ {
foreach (array('cfg', 'lib') as $dir) {
if (!is_file(PATH . $dir . DIRECTORY_SEPARATOR . '.htaccess')) {
file_put_contents(
PATH . $dir . DIRECTORY_SEPARATOR . '.htaccess',
'Allow from none' . PHP_EOL .
'Deny from all' . PHP_EOL,
LOCK_EX
);
}
}
$this->_conf = new Configuration; $this->_conf = new Configuration;
$this->_model = new Model($this->_conf); $this->_model = new Model($this->_conf);
$this->_request = new Request; $this->_request = new Request;

1
tst/.gitignore vendored
View file

@ -1 +0,0 @@
/ConfigurationCombinationsTest.php

View file

@ -1,2 +0,0 @@
Allow from none
Deny from all

View file

@ -8,16 +8,26 @@ class FilesystemTest extends PHPUnit_Framework_TestCase
private $_path; private $_path;
private $_invalidPath;
public function setUp() public function setUp()
{ {
/* Setup Routine */ /* Setup Routine */
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data'; $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
$this->_invalidPath = $this->_path . DIRECTORY_SEPARATOR . 'bar';
$this->_model = Filesystem::getInstance(array('dir' => $this->_path)); $this->_model = Filesystem::getInstance(array('dir' => $this->_path));
if (!is_dir($this->_path)) {
mkdir($this->_path);
}
if (!is_dir($this->_invalidPath)) {
mkdir($this->_invalidPath);
}
} }
public function tearDown() public function tearDown()
{ {
/* Tear Down Routine */ /* Tear Down Routine */
chmod($this->_invalidPath, 0700);
Helper::rmDir($this->_path); Helper::rmDir($this->_path);
} }
@ -37,6 +47,7 @@ class FilesystemTest extends PHPUnit_Framework_TestCase
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist'); $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist');
$this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()), 'store comment'); $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()), 'store comment');
$this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment exists after storing it'); $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment exists after storing it');
$this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()), 'unable to store the same comment twice');
$comment = json_decode(json_encode(Helper::getComment())); $comment = json_decode(json_encode(Helper::getComment()));
$comment->id = Helper::getCommentId(); $comment->id = Helper::getCommentId();
$comment->parentid = Helper::getPasteId(); $comment->parentid = Helper::getPasteId();
@ -127,4 +138,26 @@ class FilesystemTest extends PHPUnit_Framework_TestCase
$this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment'); $this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment');
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does still not exist'); $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does still not exist');
} }
/**
* @expectedException Exception
* @expectedExceptionCode 10
*/
public function testPermissionShenanigans()
{
// try creating an invalid path
chmod($this->_invalidPath, 0000);
Filesystem::getInstance(array('dir' => $this->_invalidPath . DIRECTORY_SEPARATOR . 'baz'));
}
/**
* @expectedException Exception
* @expectedExceptionCode 11
*/
public function testPathShenanigans()
{
// try setting an invalid path
chmod($this->_invalidPath, 0000);
Filesystem::getInstance(array('dir' => $this->_invalidPath));
}
} }

View file

@ -82,6 +82,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
$comment = $paste->getComment(Helper::getPasteId()); $comment = $paste->getComment(Helper::getPasteId());
$comment->setData($commentData['data']); $comment->setData($commentData['data']);
$comment->setNickname($commentData['meta']['nickname']); $comment->setNickname($commentData['meta']['nickname']);
$comment->getParentId();
$comment->store(); $comment->store();
$comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId()); $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId());
@ -189,6 +190,27 @@ class ModelTest extends PHPUnit_Framework_TestCase
$this->assertFalse(Paste::isValidId('../bar/baz'), 'path attack'); $this->assertFalse(Paste::isValidId('../bar/baz'), 'path attack');
} }
/**
* @expectedException Exception
* @expectedExceptionCode 64
*/
public function testInvalidPaste()
{
$this->_model->getPaste(Helper::getPasteId())->delete();
$paste = $this->_model->getPaste(Helper::getPasteId());
$paste->get();
}
/**
* @expectedException Exception
* @expectedExceptionCode 61
*/
public function testInvalidData()
{
$paste = $this->_model->getPaste();
$paste->setData('');
}
/** /**
* @expectedException Exception * @expectedException Exception
* @expectedExceptionCode 62 * @expectedExceptionCode 62
@ -199,6 +221,37 @@ class ModelTest extends PHPUnit_Framework_TestCase
$paste->getComment(Helper::getPasteId()); $paste->getComment(Helper::getPasteId());
} }
/**
* @expectedException Exception
* @expectedExceptionCode 67
*/
public function testInvalidCommentDeletedPaste()
{
$pasteData = Helper::getPaste();
$paste = $this->_model->getPaste(Helper::getPasteId());
$paste->setData($pasteData['data']);
$paste->store();
$comment = $paste->getComment(Helper::getPasteId());
$paste->delete();
$comment->store();
}
/**
* @expectedException Exception
* @expectedExceptionCode 68
*/
public function testInvalidCommentData()
{
$pasteData = Helper::getPaste();
$paste = $this->_model->getPaste(Helper::getPasteId());
$paste->setData($pasteData['data']);
$paste->store();
$comment = $paste->getComment(Helper::getPasteId());
$comment->store();
}
public function testExpiration() public function testExpiration()
{ {
$pasteData = Helper::getPaste(); $pasteData = Helper::getPaste();

View file

@ -140,21 +140,18 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
public function testHtaccess() public function testHtaccess()
{ {
$this->reset(); $this->reset();
$dirs = array('cfg', 'lib'); $file = $this->_path . DIRECTORY_SEPARATOR . '.htaccess';
foreach ($dirs as $dir) {
$file = PATH . $dir . DIRECTORY_SEPARATOR . '.htaccess';
@unlink($file); @unlink($file);
}
$_POST = Helper::getPaste();
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start(); ob_start();
new PrivateBin; new PrivateBin;
ob_end_clean(); ob_end_clean();
foreach ($dirs as $dir) {
$file = PATH . $dir . DIRECTORY_SEPARATOR . '.htaccess'; $this->assertFileExists($file, 'htaccess recreated');
$this->assertFileExists(
$file,
"$dir htaccess recreated"
);
}
} }
/** /**

View file

@ -1,11 +1,13 @@
<?php <?php
use PrivateBin\Persistence\ServerSalt;
use PrivateBin\Sjcl; use PrivateBin\Sjcl;
class SjclTest extends PHPUnit_Framework_TestCase class SjclTest extends PHPUnit_Framework_TestCase
{ {
public function testSjclValidatorValidatesCorrectly() public function testSjclValidatorValidatesCorrectly()
{ {
ServerSalt::setPath(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data');
$paste = Helper::getPasteWithAttachment(); $paste = Helper::getPasteWithAttachment();
$this->assertTrue(Sjcl::isValid($paste['data']), 'valid sjcl'); $this->assertTrue(Sjcl::isValid($paste['data']), 'valid sjcl');
$this->assertTrue(Sjcl::isValid($paste['attachment']), 'valid sjcl'); $this->assertTrue(Sjcl::isValid($paste['attachment']), 'valid sjcl');