Merge pull request #812 from binxio/persistence-into-data
improved implementation
This commit is contained in:
commit
cc6fb1c0c3
2 changed files with 71 additions and 27 deletions
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace PrivateBin\Data;
|
namespace PrivateBin\Data;
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Google\Cloud\Core\Exception\NotFoundException;
|
use Google\Cloud\Core\Exception\NotFoundException;
|
||||||
use Google\Cloud\Storage\StorageClient;
|
use Google\Cloud\Storage\StorageClient;
|
||||||
|
@ -225,23 +224,22 @@ class GoogleCloudStorage extends AbstractData
|
||||||
*/
|
*/
|
||||||
public function purgeValues($namespace, $time)
|
public function purgeValues($namespace, $time)
|
||||||
{
|
{
|
||||||
$prefix = 'config/' . $namespace . '/';
|
$path = 'config/' . $namespace;
|
||||||
try {
|
try {
|
||||||
foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $object) {
|
foreach ($this->_bucket->objects(array('prefix' => $path)) as $object) {
|
||||||
$info = $object->info();
|
$name = $object->name();
|
||||||
$timeCreated = false;
|
if (strlen($name) > strlen($path) && substr($name, strlen($path), 1) !== '/') {
|
||||||
if (key_exists('timeCreated', $info)) {
|
continue;
|
||||||
$timeCreated = DateTime::createFromFormat(GoogleCloudStorage::DATETIME_FORMAT, $info['timeCreated']);
|
|
||||||
}
|
}
|
||||||
if ($timeCreated && ($timeCreated->getTimestamp() < $time)) {
|
$info = $object->info();
|
||||||
|
if (key_exists('metadata', $info) && key_exists('value', $info['metadata'])) {
|
||||||
|
$value = $info['metadata']['value'];
|
||||||
|
if (is_numeric($value) && intval($value) < $time) {
|
||||||
try {
|
try {
|
||||||
$object->delete();
|
$object->delete();
|
||||||
} catch (NotFoundException $e) {
|
} catch (NotFoundException $e) {
|
||||||
// deleted by another instance.
|
// deleted by another instance.
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (!$timeCreated) {
|
|
||||||
error_log('failed to parse create timestamp ' . $info['timeCreated'] . ' of object ' . $object->name());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,15 +249,24 @@ class GoogleCloudStorage extends AbstractData
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the simplest thing that could possibly work.
|
* For GoogleCloudStorage, the value will also be stored in the metadata for the
|
||||||
* will be to tested for runtime performance.
|
* namespaces traffic_limiter and purge_limiter.
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function setValue($value, $namespace, $key = '')
|
public function setValue($value, $namespace, $key = '')
|
||||||
{
|
{
|
||||||
|
if ($key === '') {
|
||||||
|
$key = 'config/' . $namespace;
|
||||||
|
} else {
|
||||||
$key = 'config/' . $namespace . '/' . $key;
|
$key = 'config/' . $namespace . '/' . $key;
|
||||||
|
}
|
||||||
|
|
||||||
$data = Json::encode($value);
|
$data = Json::encode($value);
|
||||||
|
|
||||||
|
$metadata = array('namespace' => $namespace);
|
||||||
|
if ($namespace != 'salt') {
|
||||||
|
$metadata['value'] = strval($value);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
$this->_bucket->upload($data, array(
|
$this->_bucket->upload($data, array(
|
||||||
'name' => $key,
|
'name' => $key,
|
||||||
|
@ -267,7 +274,7 @@ class GoogleCloudStorage extends AbstractData
|
||||||
'predefinedAcl' => 'private',
|
'predefinedAcl' => 'private',
|
||||||
'metadata' => array(
|
'metadata' => array(
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
'metadata' => array('namespace' => $namespace),
|
'metadata' => $metadata,
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
@ -279,13 +286,15 @@ class GoogleCloudStorage extends AbstractData
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the simplest thing that could possibly work.
|
|
||||||
* will be to tested for runtime performance.
|
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function getValue($namespace, $key = '')
|
public function getValue($namespace, $key = '')
|
||||||
{
|
{
|
||||||
|
if ($key === '') {
|
||||||
|
$key = 'config/' . $namespace;
|
||||||
|
} else {
|
||||||
$key = 'config/' . $namespace . '/' . $key;
|
$key = 'config/' . $namespace . '/' . $key;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
$o = $this->_bucket->object($key);
|
$o = $this->_bucket->object($key);
|
||||||
$data = $o->downloadAsString();
|
$data = $o->downloadAsString();
|
||||||
|
|
|
@ -141,8 +141,8 @@ class GoogleCloudStorageTest extends PHPUnit_Framework_TestCase
|
||||||
public function testKeyValueStore()
|
public function testKeyValueStore()
|
||||||
{
|
{
|
||||||
$salt = bin2hex(random_bytes(256));
|
$salt = bin2hex(random_bytes(256));
|
||||||
$this->_model->setValue($salt, 'salt', 'master');
|
$this->_model->setValue($salt, 'salt', '');
|
||||||
$storedSalt = $this->_model->getValue('salt', 'master');
|
$storedSalt = $this->_model->getValue('salt', '');
|
||||||
$this->assertEquals($salt, $storedSalt);
|
$this->assertEquals($salt, $storedSalt);
|
||||||
$this->_model->purgeValues('salt', time() + 60);
|
$this->_model->purgeValues('salt', time() + 60);
|
||||||
$this->assertFalse($this->_model->getValue('salt', 'master'));
|
$this->assertFalse($this->_model->getValue('salt', 'master'));
|
||||||
|
@ -159,12 +159,47 @@ class GoogleCloudStorageTest extends PHPUnit_Framework_TestCase
|
||||||
$this->assertFalse($this->_model->getValue('traffic_limiter', $client));
|
$this->assertFalse($this->_model->getValue('traffic_limiter', $client));
|
||||||
|
|
||||||
$purgeAt = $expire + (15 * 60);
|
$purgeAt = $expire + (15 * 60);
|
||||||
$this->_model->setValue($purgeAt, 'purge_limiter', 'at');
|
$this->_model->setValue($purgeAt, 'purge_limiter', '');
|
||||||
$storedPurgedAt = $this->_model->getValue('purge_limiter', 'at');
|
$storedPurgedAt = $this->_model->getValue('purge_limiter', '');
|
||||||
$this->assertEquals($purgeAt, $storedPurgedAt);
|
$this->assertEquals($purgeAt, $storedPurgedAt);
|
||||||
$this->_model->purgeValues('purge_limiter', time() + 60);
|
$this->_model->purgeValues('purge_limiter', time() + 60);
|
||||||
$this->assertFalse($this->_model->getValue('purge_limiter', 'at'));
|
$this->assertFalse($this->_model->getValue('purge_limiter', 'at'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function testKeyValuePurgeTrafficLimiter()
|
||||||
|
{
|
||||||
|
$salt = bin2hex(random_bytes(256));
|
||||||
|
$client = hash_hmac('sha512', '127.0.0.1', $salt);
|
||||||
|
$expire = time();
|
||||||
|
$this->_model->setValue($expire, 'traffic_limiter', $client);
|
||||||
|
$storedExpired = $this->_model->getValue('traffic_limiter', $client);
|
||||||
|
$this->assertEquals($expire, $storedExpired);
|
||||||
|
|
||||||
|
$this->_model->purgeValues('traffic_limiter', time() - 60);
|
||||||
|
$this->assertEquals($storedExpired, $this->_model->getValue('traffic_limiter', $client));
|
||||||
|
|
||||||
|
$this->_model->purgeValues('traffic_limiter', time() + 60);
|
||||||
|
$this->assertFalse($this->_model->getValue('traffic_limiter', $client));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testKeyValuePurgeTrafficLimiterWithKey()
|
||||||
|
{
|
||||||
|
$salt = bin2hex(random_bytes(256));
|
||||||
|
$client = hash_hmac('sha512', '127.0.0.1', $salt);
|
||||||
|
$expire = time();
|
||||||
|
$this->_model->setValue($expire, 'traffic_limiter', $client);
|
||||||
|
$storedExpired = $this->_model->getValue('traffic_limiter', $client);
|
||||||
|
$this->assertEquals($expire, $storedExpired);
|
||||||
|
|
||||||
|
$this->_model->purgeValues('traffic_limiter', time() - 60);
|
||||||
|
$this->assertEquals($storedExpired, $this->_model->getValue('traffic_limiter', $client));
|
||||||
|
|
||||||
|
$this->_model->purgeValues('traffic_limiter', time() + 60);
|
||||||
|
$this->assertFalse($this->_model->getValue('traffic_limiter', $client));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue