folding Persistance\ServerSalt into Data\Filesystem

pull/810/head
El RIDO 2021-06-08 22:01:29 +02:00
parent b5a6ce323e
commit 7901ec74a7
No known key found for this signature in database
GPG Key ID: 0F5C940A6BD81F92
12 changed files with 80 additions and 196 deletions

View File

@ -197,6 +197,7 @@ class Controller
{
try {
// Ensure last paste from visitors IP address was more than configured amount of seconds ago.
ServerSalt::setStore($this->_model->getStore());
TrafficLimiter::setConfiguration($this->_conf);
TrafficLimiter::setStore($this->_model->getStore());
if (!TrafficLimiter::canPass()) {

View File

@ -287,17 +287,17 @@ class Filesystem extends AbstractData
self::$_path . DIRECTORY_SEPARATOR . 'purge_limiter.php',
'<?php' . PHP_EOL . '$GLOBALS[\'purge_limiter\'] = ' . $value . ';'
);
break;
case 'salt':
;
break;
return self::_storeString(
self::$_path . DIRECTORY_SEPARATOR . 'salt.php',
'<?php # |' . $value . '|'
);
case 'traffic_limiter':
self::$_traffic_limiter_cache[$key] = $value;
return self::_storeString(
self::$_path . DIRECTORY_SEPARATOR . 'traffic_limiter.php',
'<?php' . PHP_EOL . '$GLOBALS[\'purge_limiter\'] = ' . var_export(self::$_traffic_limiter_cache, true) . ';'
'<?php' . PHP_EOL . '$GLOBALS[\'traffic_limiter\'] = ' . var_export(self::$_traffic_limiter_cache, true) . ';'
);
break;
}
return false;
}
@ -315,17 +315,23 @@ class Filesystem extends AbstractData
switch ($namespace) {
case 'purge_limiter':
$file = self::$_path . DIRECTORY_SEPARATOR . 'purge_limiter.php';
if (is_file($file)) {
if (is_readable($file)) {
require $file;
return $GLOBALS['purge_limiter'];
}
break;
case 'salt':
;
$file = self::$_path . DIRECTORY_SEPARATOR . 'salt.php';
if (is_readable($file)) {
$items = explode('|', file_get_contents($file));
if (is_array($items) && count($items) == 3) {
return $items[1];
}
}
break;
case 'traffic_limiter':
$file = self::$_path . DIRECTORY_SEPARATOR . 'traffic_limiter.php';
if (is_file($file)) {
if (is_readable($file)) {
require $file;
self::$_traffic_limiter_cache = $GLOBALS['traffic_limiter'];
if (array_key_exists($key, self::$_traffic_limiter_cache)) {

View File

@ -93,7 +93,7 @@ class Paste extends AbstractModel
}
$this->_data['meta']['created'] = time();
$this->_data['meta']['salt'] = serversalt::generate();
$this->_data['meta']['salt'] = ServerSalt::generate();
// store paste
if (

View File

@ -12,7 +12,6 @@
namespace PrivateBin\Persistence;
use Exception;
use PrivateBin\Data\AbstractData;
/**
@ -22,15 +21,6 @@ use PrivateBin\Data\AbstractData;
*/
abstract class AbstractPersistence
{
/**
* path in which to persist something
*
* @access private
* @static
* @var string
*/
private static $_path = 'data';
/**
* data storage to use to persist something
*
@ -40,18 +30,6 @@ abstract class AbstractPersistence
*/
protected static $_store;
/**
* set the path
*
* @access public
* @static
* @param string $path
*/
public static function setPath($path)
{
self::$_path = $path;
}
/**
* set the path
*
@ -63,95 +41,4 @@ abstract class AbstractPersistence
{
self::$_store = $store;
}
/**
* get the path
*
* @access public
* @static
* @param string $filename
* @return string
*/
public static function getPath($filename = null)
{
if (strlen($filename)) {
return self::$_path . DIRECTORY_SEPARATOR . $filename;
} else {
return self::$_path;
}
}
/**
* checks if the file exists
*
* @access protected
* @static
* @param string $filename
* @return bool
*/
protected static function _exists($filename)
{
self::_initialize();
return is_file(self::$_path . DIRECTORY_SEPARATOR . $filename);
}
/**
* prepares path for storage
*
* @access protected
* @static
* @throws Exception
*/
protected static function _initialize()
{
// Create storage directory if it does not exist.
if (!is_dir(self::$_path)) {
if (!@mkdir(self::$_path, 0700)) {
throw new Exception('unable to create directory ' . self::$_path, 10);
}
}
$file = self::$_path . DIRECTORY_SEPARATOR . '.htaccess';
if (!is_file($file)) {
$writtenBytes = 0;
if ($fileCreated = @touch($file)) {
$writtenBytes = @file_put_contents(
$file,
'Require all denied' . PHP_EOL,
LOCK_EX
);
}
if ($fileCreated === false || $writtenBytes === false || $writtenBytes < 19) {
throw new Exception('unable to write to file ' . $file, 11);
}
}
}
/**
* store the data
*
* @access protected
* @static
* @param string $filename
* @param string $data
* @throws Exception
* @return string
*/
protected static function _store($filename, $data)
{
self::_initialize();
$file = self::$_path . DIRECTORY_SEPARATOR . $filename;
$fileCreated = true;
$writtenBytes = 0;
if (!is_file($file)) {
$fileCreated = @touch($file);
}
if ($fileCreated) {
$writtenBytes = @file_put_contents($file, $data, LOCK_EX);
}
if ($fileCreated === false || $writtenBytes === false || $writtenBytes < strlen($data)) {
throw new Exception('unable to write to file ' . $file, 13);
}
@chmod($file, 0640); // protect file access
return $file;
}
}

View File

@ -13,6 +13,7 @@
namespace PrivateBin\Persistence;
use Exception;
use PrivateBin\Data\AbstractData;
/**
* ServerSalt
@ -71,20 +72,12 @@ class ServerSalt extends AbstractPersistence
return self::$_salt;
}
if (self::_exists(self::$_file)) {
if (is_readable(self::getPath(self::$_file))) {
$items = explode('|', file_get_contents(self::getPath(self::$_file)));
}
if (!isset($items) || !is_array($items) || count($items) != 3) {
throw new Exception('unable to read file ' . self::getPath(self::$_file), 20);
}
self::$_salt = $items[1];
$salt = self::$_store->getValue('salt');
if ($salt) {
self::$_salt = $salt;
} else {
self::$_salt = self::generate();
self::_store(
self::$_file,
'<?php # |' . self::$_salt . '|'
);
self::$_store->setValue(self::$_salt, 'salt');
}
return self::$_salt;
}
@ -94,11 +87,11 @@ class ServerSalt extends AbstractPersistence
*
* @access public
* @static
* @param string $path
* @param AbstractData $store
*/
public static function setPath($path)
public static function setStore(AbstractData $store)
{
self::$_salt = '';
parent::setPath($path);
parent::setStore($store);
}
}

View File

@ -172,7 +172,7 @@ class TrafficLimiter extends AbstractPersistence
// this hash is used as an array key, hence a shorter algo is used
$hash = self::getHash('sha256');
$now = time();
$tl = self::$_store->getValue('traffic_limiter', $hash);
$tl = (int) self::$_store->getValue('traffic_limiter', $hash);
self::$_store->purgeValues('traffic_limiter', $now - self::$_limit);
if ($tl > 0 && ($tl + self::$_limit >= $now)) {
$result = false;
@ -180,7 +180,7 @@ class TrafficLimiter extends AbstractPersistence
$tl = time();
$result = true;
}
self::$_store->setValue((string) $tl, 'traffic_limiter');
self::$_store->setValue((string) $tl, 'traffic_limiter', $hash);
return $result;
}
}

View File

@ -125,28 +125,6 @@ class ControllerTest extends PHPUnit_Framework_TestCase
);
}
/**
* @runInSeparateProcess
*/
public function testHtaccess()
{
$htaccess = $this->_path . DIRECTORY_SEPARATOR . '.htaccess';
@unlink($htaccess);
$paste = Helper::getPasteJson();
$file = tempnam(sys_get_temp_dir(), 'FOO');
file_put_contents($file, $paste);
Request::setInputStream($file);
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new Controller;
ob_end_clean();
$this->assertFileExists($htaccess, 'htaccess recreated');
}
/**
* @expectedException Exception
* @expectedExceptionCode 2

View File

@ -16,7 +16,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
/* Setup Routine */
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
$this->_model = Filesystem::getInstance(array('dir' => $this->_path));
ServerSalt::setPath($this->_path);
ServerSalt::setStore($this->_model);
$_POST = array();
$_GET = array();

View File

@ -25,7 +25,6 @@ class ModelTest extends PHPUnit_Framework_TestCase
if (!is_dir($this->_path)) {
mkdir($this->_path);
}
ServerSalt::setPath($this->_path);
$options = parse_ini_file(CONF_SAMPLE, true);
$options['purge']['limit'] = 0;
$options['model'] = array(
@ -39,6 +38,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
);
Helper::confBackup();
Helper::createIniFile(CONF, $options);
ServerSalt::setStore(Database::getInstance($options['model_options']));
$this->_conf = new Configuration;
$this->_model = new Model($this->_conf);
$_SERVER['REMOTE_ADDR'] = '::1';

View File

@ -1,5 +1,6 @@
<?php
use PrivateBin\Data\Filesystem;
use PrivateBin\Persistence\ServerSalt;
class ServerSaltTest extends PHPUnit_Framework_TestCase
@ -19,7 +20,9 @@ class ServerSaltTest extends PHPUnit_Framework_TestCase
if (!is_dir($this->_path)) {
mkdir($this->_path);
}
ServerSalt::setPath($this->_path);
ServerSalt::setStore(
Filesystem::getInstance(array('dir' => $this->_path))
);
$this->_otherPath = $this->_path . DIRECTORY_SEPARATOR . 'foo';
@ -40,46 +43,46 @@ class ServerSaltTest extends PHPUnit_Framework_TestCase
public function testGeneration()
{
// generating new salt
ServerSalt::setPath($this->_path);
ServerSalt::setStore(
Filesystem::getInstance(array('dir' => $this->_path))
);
$salt = ServerSalt::get();
// try setting a different path and resetting it
ServerSalt::setPath($this->_otherPath);
ServerSalt::setStore(
Filesystem::getInstance(array('dir' => $this->_otherPath))
);
$this->assertNotEquals($salt, ServerSalt::get());
ServerSalt::setPath($this->_path);
ServerSalt::setStore(
Filesystem::getInstance(array('dir' => $this->_path))
);
$this->assertEquals($salt, ServerSalt::get());
}
/**
* @expectedException Exception
* @expectedExceptionCode 11
*/
public function testPathShenanigans()
{
// try setting an invalid path
chmod($this->_invalidPath, 0000);
ServerSalt::setPath($this->_invalidPath);
ServerSalt::get();
$store = Filesystem::getInstance(array('dir' => $this->_invalidPath));
ServerSalt::setStore($store);
$salt = ServerSalt::get();
ServerSalt::setStore($store);
$this->assertNotEquals($salt, ServerSalt::get());
}
/**
* @expectedException Exception
* @expectedExceptionCode 20
*/
public function testFileRead()
{
// try setting an invalid file
chmod($this->_invalidPath, 0700);
file_put_contents($this->_invalidFile, '');
chmod($this->_invalidFile, 0000);
ServerSalt::setPath($this->_invalidPath);
ServerSalt::get();
$store = Filesystem::getInstance(array('dir' => $this->_invalidPath));
ServerSalt::setStore($store);
$salt = ServerSalt::get();
ServerSalt::setStore($store);
$this->assertNotEquals($salt, ServerSalt::get());
}
/**
* @expectedException Exception
* @expectedExceptionCode 13
*/
public function testFileWrite()
{
// try setting an invalid file
@ -90,19 +93,24 @@ class ServerSaltTest extends PHPUnit_Framework_TestCase
}
file_put_contents($this->_invalidPath . DIRECTORY_SEPARATOR . '.htaccess', '');
chmod($this->_invalidPath, 0500);
ServerSalt::setPath($this->_invalidPath);
ServerSalt::get();
$store = Filesystem::getInstance(array('dir' => $this->_invalidPath));
ServerSalt::setStore($store);
$salt = ServerSalt::get();
ServerSalt::setStore($store);
$this->assertNotEquals($salt, ServerSalt::get());
}
/**
* @expectedException Exception
* @expectedExceptionCode 10
*/
public function testPermissionShenanigans()
{
// try creating an invalid path
chmod($this->_invalidPath, 0000);
ServerSalt::setPath($this->_invalidPath . DIRECTORY_SEPARATOR . 'baz');
ServerSalt::get();
ServerSalt::setStore(
Filesystem::getInstance(array('dir' => $this->_invalidPath . DIRECTORY_SEPARATOR . 'baz'))
);
$store = Filesystem::getInstance(array('dir' => $this->_invalidPath));
ServerSalt::setStore($store);
$salt = ServerSalt::get();
ServerSalt::setStore($store);
$this->assertNotEquals($salt, ServerSalt::get());
}
}

View File

@ -1,5 +1,7 @@
<?php
use PrivateBin\Data\Filesystem;
use PrivateBin\Persistence\ServerSalt;
use PrivateBin\Persistence\TrafficLimiter;
class TrafficLimiterTest extends PHPUnit_Framework_TestCase
@ -10,7 +12,9 @@ class TrafficLimiterTest extends PHPUnit_Framework_TestCase
{
/* Setup Routine */
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'trafficlimit';
TrafficLimiter::setPath($this->_path);
$store = Filesystem::getInstance(array('dir' => $this->_path));
ServerSalt::setStore($store);
TrafficLimiter::setStore($store);
}
public function tearDown()
@ -19,11 +23,17 @@ class TrafficLimiterTest extends PHPUnit_Framework_TestCase
Helper::rmDir($this->_path . DIRECTORY_SEPARATOR);
}
public function testHtaccess()
{
$htaccess = $this->_path . DIRECTORY_SEPARATOR . '.htaccess';
@unlink($htaccess);
$_SERVER['REMOTE_ADDR'] = 'foobar';
TrafficLimiter::canPass();
$this->assertFileExists($htaccess, 'htaccess recreated');
}
public function testTrafficGetsLimited()
{
$this->assertEquals($this->_path, TrafficLimiter::getPath());
$file = 'baz';
$this->assertEquals($this->_path . DIRECTORY_SEPARATOR . $file, TrafficLimiter::getPath($file));
TrafficLimiter::setLimit(4);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$this->assertTrue(TrafficLimiter::canPass(), 'first request may pass');

View File

@ -1,5 +1,6 @@
<?php
use PrivateBin\Data\Filesystem;
use PrivateBin\Persistence\ServerSalt;
use PrivateBin\Vizhash16x16;
@ -17,7 +18,7 @@ class Vizhash16x16Test extends PHPUnit_Framework_TestCase
mkdir($this->_path);
}
$this->_file = $this->_path . DIRECTORY_SEPARATOR . 'vizhash.png';
ServerSalt::setPath($this->_path);
ServerSalt::setStore(Filesystem::getInstance(array('dir' => $this->_path)));
}
public function tearDown()