improved implementation of GoogleStorageBucket

This commit is contained in:
Mark van Holsteijn 2021-06-10 21:39:15 +02:00
parent 5af069b4f0
commit 1b88eef356
2 changed files with 71 additions and 27 deletions

View file

@ -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();
try { if (key_exists('metadata', $info) && key_exists('value', $info['metadata'])) {
$object->delete(); $value = $info['metadata']['value'];
} catch (NotFoundException $e) { if (is_numeric($value) && intval($value) < $time) {
// deleted by another instance. try {
} $object->delete();
} else { } catch (NotFoundException $e) {
if (!$timeCreated) { // deleted by another instance.
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 = '')
{ {
$key = 'config/' . $namespace . '/' . $key; if ($key === '') {
$key = 'config/' . $namespace;
} else {
$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 = '')
{ {
$key = 'config/' . $namespace . '/' . $key; if ($key === '') {
$key = 'config/' . $namespace;
} else {
$key = 'config/' . $namespace . '/' . $key;
}
try { try {
$o = $this->_bucket->object($key); $o = $this->_bucket->object($key);
$data = $o->downloadAsString(); $data = $o->downloadAsString();

View file

@ -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));
}
} }
/** /**