Procházet zdrojové kódy

Merge pull request #812 from binxio/persistence-into-data

improved implementation
El RIDO před 5 roky
rodič
revize
cc6fb1c0c3
2 změnil soubory, kde provedl 71 přidání a 27 odebrání
  1. 32 23
      lib/Data/GoogleCloudStorage.php
  2. 39 4
      tst/Data/GoogleCloudStorageTest.php

+ 32 - 23
lib/Data/GoogleCloudStorage.php

@@ -2,7 +2,6 @@
 
 namespace PrivateBin\Data;
 
-use DateTime;
 use Exception;
 use Google\Cloud\Core\Exception\NotFoundException;
 use Google\Cloud\Storage\StorageClient;
@@ -225,23 +224,22 @@ class GoogleCloudStorage extends AbstractData
      */
     public function purgeValues($namespace, $time)
     {
-        $prefix = 'config/' . $namespace . '/';
+        $path = 'config/' . $namespace;
         try {
-            foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $object) {
-                $info        = $object->info();
-                $timeCreated = false;
-                if (key_exists('timeCreated', $info)) {
-                    $timeCreated = DateTime::createFromFormat(GoogleCloudStorage::DATETIME_FORMAT, $info['timeCreated']);
+            foreach ($this->_bucket->objects(array('prefix' => $path)) as $object) {
+                $name = $object->name();
+                if (strlen($name) > strlen($path) && substr($name, strlen($path), 1) !== '/') {
+                    continue;
                 }
-                if ($timeCreated && ($timeCreated->getTimestamp() < $time)) {
-                    try {
-                        $object->delete();
-                    } catch (NotFoundException $e) {
-                        // deleted by another instance.
-                    }
-                } else {
-                    if (!$timeCreated) {
-                        error_log('failed to parse create timestamp ' . $info['timeCreated'] . ' of object ' . $object->name());
+                $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 {
+                            $object->delete();
+                        } catch (NotFoundException $e) {
+                            // deleted by another instance.
+                        }
                     }
                 }
             }
@@ -251,15 +249,24 @@ class GoogleCloudStorage extends AbstractData
     }
 
     /**
-     * This is the simplest thing that could possibly work.
-     * will be to tested for runtime performance.
+     * For GoogleCloudStorage, the value will also be stored in the metadata for the
+     * namespaces traffic_limiter and purge_limiter.
      * @inheritDoc
      */
     public function setValue($value, $namespace, $key = '')
     {
-        $key  = 'config/' . $namespace . '/' . $key;
+        if ($key === '') {
+            $key = 'config/' . $namespace;
+        } else {
+            $key = 'config/' . $namespace . '/' . $key;
+        }
+
         $data = Json::encode($value);
 
+        $metadata = array('namespace' => $namespace);
+        if ($namespace != 'salt') {
+            $metadata['value'] = strval($value);
+        }
         try {
             $this->_bucket->upload($data, array(
                 'name'          => $key,
@@ -267,7 +274,7 @@ class GoogleCloudStorage extends AbstractData
                 'predefinedAcl' => 'private',
                 'metadata'      => array(
                     'content-type' => 'application/json',
-                    'metadata'     => array('namespace' => $namespace),
+                    'metadata'     => $metadata,
                 ),
             ));
         } 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
      */
     public function getValue($namespace, $key = '')
     {
-        $key = 'config/' . $namespace . '/' . $key;
+        if ($key === '') {
+            $key = 'config/' . $namespace;
+        } else {
+            $key = 'config/' . $namespace . '/' . $key;
+        }
         try {
             $o    = $this->_bucket->object($key);
             $data = $o->downloadAsString();

+ 39 - 4
tst/Data/GoogleCloudStorageTest.php

@@ -141,8 +141,8 @@ class GoogleCloudStorageTest extends PHPUnit_Framework_TestCase
     public function testKeyValueStore()
     {
         $salt = bin2hex(random_bytes(256));
-        $this->_model->setValue($salt, 'salt', 'master');
-        $storedSalt = $this->_model->getValue('salt', 'master');
+        $this->_model->setValue($salt, 'salt', '');
+        $storedSalt = $this->_model->getValue('salt', '');
         $this->assertEquals($salt, $storedSalt);
         $this->_model->purgeValues('salt', time() + 60);
         $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));
 
         $purgeAt = $expire + (15 * 60);
-        $this->_model->setValue($purgeAt, 'purge_limiter', 'at');
-        $storedPurgedAt = $this->_model->getValue('purge_limiter', 'at');
+        $this->_model->setValue($purgeAt, 'purge_limiter', '');
+        $storedPurgedAt = $this->_model->getValue('purge_limiter', '');
         $this->assertEquals($purgeAt, $storedPurgedAt);
         $this->_model->purgeValues('purge_limiter', time() + 60);
         $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));
+    }
 }
 
 /**