new: [internal] RedisTool

pull/8489/head
Jakub Onderka 2022-07-10 17:11:16 +02:00
parent 36addef808
commit 17981be04d
5 changed files with 97 additions and 41 deletions

View File

@ -0,0 +1,84 @@
<?php
class RedisTool
{
/** @var Redis|null */
private static $connection;
/** @var string */
private static $serializer;
/**
* @return Redis
* @throws Exception
*/
public static function init()
{
if (self::$connection) {
return self::$connection;
}
if (!class_exists('Redis')) {
throw new Exception("Class Redis doesn't exists. Please install redis extension for PHP.");
}
$host = Configure::read('MISP.redis_host') ?: '127.0.0.1';
$port = Configure::read('MISP.redis_port') ?: 6379;
$database = Configure::read('MISP.redis_database') ?: 13;
$pass = Configure::read('MISP.redis_password');
$redis = new Redis();
if (!$redis->connect($host, (int) $port)) {
throw new Exception("Could not connect to Redis: {$redis->getLastError()}");
}
if (!empty($pass)) {
if (!$redis->auth($pass)) {
throw new Exception("Could not authenticate to Redis: {$redis->getLastError()}");
}
}
if (!$redis->select($database)) {
throw new Exception("Could not select Redis database $database: {$redis->getLastError()}");
}
self::$connection = $redis;
return $redis;
}
/**
* @param mixed $data
* @return string
* @throws JsonException
*/
public static function serialize($data)
{
if (self::$serializer === null) {
self::$serializer = Configure::read('MISP.redis_serializer') ?: false;
}
if (self::$serializer === 'igbinary') {
return igbinary_serialize($data);
} else {
return JsonTool::encode($data);
}
}
/**
* @param string $string
* @return mixed
* @throws JsonException
*/
public static function deserialize($string)
{
if ($string === false) {
return false;
}
if (self::$serializer === null) {
self::$serializer = Configure::read('MISP.redis_serializer') ?: false;
}
if (self::$serializer === 'igbinary') {
return igbinary_unserialize($string);
} else {
return JsonTool::decode($string);
}
}
}

View File

@ -25,6 +25,7 @@ App::uses('LogableBehavior', 'Assets.models/behaviors');
App::uses('RandomTool', 'Tools');
App::uses('FileAccessTool', 'Tools');
App::uses('JsonTool', 'Tools');
App::uses('RedisTool', 'Tools');
App::uses('BetterCakeEventManager', 'Tools');
class AppModel extends Model
@ -38,9 +39,6 @@ class AppModel extends Model
/** @var BackgroundJobsTool */
private static $loadedBackgroundJobsTool;
/** @var null|Redis */
private static $__redisConnection;
private $__profiler = array();
public $elasticSearchClient;
@ -2885,37 +2883,11 @@ class AppModel extends Model
* Similar method as `setupRedis`, but this method throw exception if Redis cannot be reached.
* @return Redis
* @throws Exception
* @deprecated
*/
public function setupRedisWithException()
{
if (self::$__redisConnection) {
return self::$__redisConnection;
}
if (!class_exists('Redis')) {
throw new Exception("Class Redis doesn't exists. Please install redis extension for PHP.");
}
$host = Configure::read('MISP.redis_host') ?: '127.0.0.1';
$port = Configure::read('MISP.redis_port') ?: 6379;
$database = Configure::read('MISP.redis_database') ?: 13;
$pass = Configure::read('MISP.redis_password');
$redis = new Redis();
if (!$redis->connect($host, (int) $port)) {
throw new Exception("Could not connect to Redis: {$redis->getLastError()}");
}
if (!empty($pass)) {
if (!$redis->auth($pass)) {
throw new Exception("Could not authenticate to Redis: {$redis->getLastError()}");
}
}
if (!$redis->select($database)) {
throw new Exception("Could not select Redis database $database: {$redis->getLastError()}");
}
self::$__redisConnection = $redis;
return $redis;
return RedisTool::init();
}
/**
@ -2927,7 +2899,7 @@ class AppModel extends Model
public function setupRedis()
{
try {
return $this->setupRedisWithException();
return RedisTool::init();
} catch (Exception $e) {
return false;
}

View File

@ -812,10 +812,10 @@ class Server extends AppModel
$filterRules['published'] = 1;
// Fetch event index from cache if exists and is not modified
$redis = $this->setupRedisWithException();
$redis = RedisTool::init();
$indexFromCache = $redis->get("misp:event_index:{$serverSync->serverId()}");
if ($indexFromCache) {
list($etag, $eventIndex) = JsonTool::decode($indexFromCache);
list($etag, $eventIndex) = RedisTool::deserialize($indexFromCache);
} else {
$etag = '""'; // Provide empty ETag, so MISP will compute ETag for returned data
}
@ -835,7 +835,7 @@ class Server extends AppModel
// Save to cache for 24 hours if ETag provided
if (isset($response->headers["ETag"])) {
$data = JsonTool::encode([$response->headers["ETag"], $eventIndex]);
$data = RedisTool::serialize([$response->headers["ETag"], $eventIndex]);
$redis->setex("misp:event_index:{$serverSync->serverId()}", 3600 * 24, $data);
} else if ($indexFromCache) {
$redis->del("misp:event_index:{$serverSync->serverId()}");

View File

@ -589,9 +589,9 @@ class Taxonomy extends AppModel
return false; // not taxonomy tag
}
$key = 'taxonomies_cache:tagName=' . $tagName . "&" . "metaOnly=$metaOnly" . "&" . "fullTaxonomy=$fullTaxonomy";
$key = "taxonomies_cache:tagName=$tagName&metaOnly=$metaOnly&fullTaxonomy=$fullTaxonomy";
$redis = $this->setupRedis();
$taxonomy = $redis ? json_decode($redis->get($key), true) : null;
$taxonomy = $redis ? RedisTool::deserialize($redis->get($key)) : null;
if (!$taxonomy) {
if (isset($splits['value'])) {
@ -634,7 +634,7 @@ class Taxonomy extends AppModel
}
if ($redis) {
$redis->setex($key, 1800, json_encode($taxonomy));
$redis->setex($key, 1800, RedisTool::serialize($taxonomy));
}
}

View File

@ -115,7 +115,7 @@ class Warninglist extends AppModel
}
try {
$redis = $this->setupRedisWithException();
$redis = RedisTool::init();
} catch (Exception $e) {
// fallback to default implementation when redis is not available
$eventWarnings = [];
@ -182,10 +182,10 @@ class Warninglist extends AppModel
}
$attributeKey = $keysToGet[$pos];
$saveToCache[$attributeKey] = empty($store) ? '' : json_encode($store);
$saveToCache[$attributeKey] = empty($store) ? '' : RedisTool::serialize($store);
} elseif (!empty($result)) { // skip empty string that means no warning list match
$matchedWarningList = json_decode($result, true);
$matchedWarningList = RedisTool::deserialize($result);
foreach ($matchedWarningList as $warninglistId => $matched) {
$attributes[$redisResultToAttributePos[$pos]]['warnings'][] = [
'value' => $matched[0],