mirror of https://github.com/MISP/MISP
Merge pull request #9479 from JakubOnderka/cleanup
new: [CLI] AdminShell isEncryptionKeyValid commandpull/9492/head
commit
4c4e3f2d8b
|
@ -85,6 +85,14 @@ class AdminShell extends AppShell
|
|||
],
|
||||
],
|
||||
]);
|
||||
$parser->addSubcommand('isEncryptionKeyValid', [
|
||||
'help' => __('Check if current encryption key is valid.'),
|
||||
'parser' => [
|
||||
'options' => [
|
||||
'encryptionKey' => ['help' => __('Current encryption key. If not provided, current key will be used.')],
|
||||
],
|
||||
],
|
||||
]);
|
||||
$parser->addSubcommand('dumpCurrentDatabaseSchema', [
|
||||
'help' => __('Dump current database schema to JSON file.'),
|
||||
]);
|
||||
|
@ -662,6 +670,8 @@ class AdminShell extends AppShell
|
|||
*/
|
||||
public function change_authkey()
|
||||
{
|
||||
$this->deprecated('cake user change_authkey [user_id]');
|
||||
|
||||
if (empty($this->args[0])) {
|
||||
echo 'MISP apikey command line tool' . PHP_EOL . 'To assign a new random API key for a user: ' . APP . 'Console/cake Admin change_authkey [user_email]' . PHP_EOL . 'To assign a fixed API key: ' . APP . 'Console/cake Admin change_authkey [user_email] [authkey]' . PHP_EOL;
|
||||
die();
|
||||
|
@ -801,6 +811,8 @@ class AdminShell extends AppShell
|
|||
*/
|
||||
public function UserIP()
|
||||
{
|
||||
$this->deprecated('cake user user_ips [user_id]');
|
||||
|
||||
if (empty($this->args[0])) {
|
||||
die('Usage: ' . $this->Server->command_line_functions['console_admin_tasks']['data']['Get IPs for user ID'] . PHP_EOL);
|
||||
}
|
||||
|
@ -828,6 +840,8 @@ class AdminShell extends AppShell
|
|||
*/
|
||||
public function IPUser()
|
||||
{
|
||||
$this->deprecated('cake user ip_user [ip]');
|
||||
|
||||
if (empty($this->args[0])) {
|
||||
die('Usage: ' . $this->Server->command_line_functions['console_admin_tasks']['data']['Get user ID for user IP'] . PHP_EOL);
|
||||
}
|
||||
|
@ -1045,6 +1059,23 @@ class AdminShell extends AppShell
|
|||
$this->out(__('New encryption key "%s" saved into config file.', $new));
|
||||
}
|
||||
|
||||
public function isEncryptionKeyValid()
|
||||
{
|
||||
$encryptionKey = $this->params['encryptionKey'] ?? null;
|
||||
if ($encryptionKey === null) {
|
||||
$encryptionKey = Configure::read('Security.encryption_key');
|
||||
}
|
||||
if (!$encryptionKey) {
|
||||
$this->error('No encryption key provided');
|
||||
}
|
||||
|
||||
/** @var SystemSetting $systemSetting */
|
||||
$systemSetting = ClassRegistry::init('SystemSetting');
|
||||
$systemSetting->isEncryptionKeyValid($encryptionKey);
|
||||
|
||||
$this->Server->isEncryptionKeyValid($encryptionKey);
|
||||
}
|
||||
|
||||
public function redisMemoryUsage()
|
||||
{
|
||||
$redis = RedisTool::init();
|
||||
|
|
|
@ -84,6 +84,15 @@ abstract class AppShell extends Shell
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $newCommand
|
||||
* @return void
|
||||
*/
|
||||
protected function deprecated($newCommand)
|
||||
{
|
||||
$this->err("<warning>This method is deprecated. Next time please use `$newCommand`.</warning>");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BackgroundJobsTool
|
||||
* @throws Exception
|
||||
|
|
|
@ -12,7 +12,7 @@ class AuthkeyShell extends AppShell {
|
|||
|
||||
public function main()
|
||||
{
|
||||
$this->err('This method is deprecated. Next time please use `cake user change_authkey [user] [authkey]` command.');
|
||||
$this->deprecated('cake user change_authkey [user] [authkey]');
|
||||
|
||||
if (!isset($this->args[0]) || empty($this->args[0])) echo 'MISP authkey reset command line tool.' . PHP_EOL . 'To assign a new authkey for a user:' . PHP_EOL . APP . 'Console/cake Authkey [email] [auth_key | optional]' . PHP_EOL;
|
||||
else {
|
||||
|
|
|
@ -11,7 +11,7 @@ class BaseurlShell extends AppShell {
|
|||
|
||||
public function main()
|
||||
{
|
||||
$this->err('This method is deprecated. Next time please use `cake admin setSetting MISP.baseurl [baseurl]` command.');
|
||||
$this->deprecated('cake admin setSetting MISP.baseurl [baseurl]');
|
||||
|
||||
$baseurl = $this->args[0];
|
||||
$result = $this->Server->testBaseURL($baseurl);
|
||||
|
|
|
@ -11,6 +11,8 @@ class LiveShell extends AppShell {
|
|||
|
||||
public function main()
|
||||
{
|
||||
$this->deprecated('cake admin live [0|1]');
|
||||
|
||||
$live = $this->args[0];
|
||||
if ($live != 0 && $live != 1) {
|
||||
echo 'Invalid parameters. Usage: /var/www/MISP/app/Console/cake Live [0|1]';
|
||||
|
|
|
@ -12,7 +12,7 @@ class PasswordShell extends AppShell {
|
|||
|
||||
public function main()
|
||||
{
|
||||
$this->err('This method is deprecated. Next time please use `cake user change_pw [user] [password]` command.');
|
||||
$this->deprecated('cake user change_pw [user] [password]');
|
||||
|
||||
if (!isset($this->args[0]) || empty($this->args[0]) || !isset($this->args[1]) || empty($this->args[1])) echo 'MISP password reset command line tool.' . PHP_EOL . 'To assign a new password for a user:' . PHP_EOL . APP . 'Console/cake Password [email] [password]' . PHP_EOL;
|
||||
else {
|
||||
|
|
|
@ -83,7 +83,7 @@ class StartWorkerShell extends AppShell
|
|||
|
||||
$start = microtime(true);
|
||||
$job->run(function (array $status) use ($job) {
|
||||
$this->getBackgroundJobsTool()->markAsRunning($this->worker, $job);
|
||||
$this->getBackgroundJobsTool()->markAsRunning($this->worker, $job, $status['pid']);
|
||||
});
|
||||
$duration = number_format(microtime(true) - $start, 3, '.', '');
|
||||
|
||||
|
|
|
@ -34,13 +34,20 @@ class WorkerShell extends AppShell
|
|||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RedisException
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function showQueues()
|
||||
{
|
||||
$tool = $this->getBackgroundJobsTool();
|
||||
$runningJobs = $tool->runningJobs();
|
||||
|
||||
foreach (BackgroundJobsTool::VALID_QUEUES as $queue) {
|
||||
$this->out("{$queue}:\t{$tool->getQueueSize($queue)}");
|
||||
foreach ($tool->runningJobs($queue) as $jobId) {
|
||||
$this->out(" - $jobId");
|
||||
$queueJobs = $runningJobs[$queue] ?? [];
|
||||
foreach ($queueJobs as $jobId => $data) {
|
||||
$this->out(" - $jobId (" . JsonTool::encode($data) .")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,6 +113,14 @@ class BackgroundJob implements JsonSerializable
|
|||
$this->output = '';
|
||||
$this->error = '';
|
||||
|
||||
if ($runningCallback) {
|
||||
$status = proc_get_status($process);
|
||||
if ($status === false) {
|
||||
throw new RuntimeException("Could not get process status");
|
||||
}
|
||||
$runningCallback($status);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
$read = [$pipes[1], $pipes[2]];
|
||||
$write = null;
|
||||
|
|
|
@ -281,13 +281,17 @@ class BackgroundJobsTool
|
|||
/**
|
||||
* @param Worker $worker
|
||||
* @param BackgroundJob $job
|
||||
* @param int|null $pid
|
||||
* @return void
|
||||
* @throws RedisException
|
||||
*/
|
||||
public function markAsRunning(Worker $worker, BackgroundJob $job)
|
||||
public function markAsRunning(Worker $worker, BackgroundJob $job, $pid = null)
|
||||
{
|
||||
$key = self::RUNNING_JOB_PREFIX . ':' . $worker->queue() . ':' . $job->id();
|
||||
$this->RedisConnection->setex($key, 60, $worker->pid());
|
||||
$this->RedisConnection->setex($key, 60, [
|
||||
'worker_pid' => $worker->pid(),
|
||||
'process_pid' => $pid,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -304,19 +308,20 @@ class BackgroundJobsTool
|
|||
|
||||
/**
|
||||
* Return current running jobs
|
||||
* @param string $queue
|
||||
* @return string[] Background jobs IDs
|
||||
* @return array
|
||||
* @throws RedisException
|
||||
*/
|
||||
public function runningJobs(string $queue): array
|
||||
public function runningJobs(): array
|
||||
{
|
||||
$pattern = $this->RedisConnection->_prefix(self::RUNNING_JOB_PREFIX . ':' . $queue . ':*');
|
||||
$pattern = $this->RedisConnection->_prefix(self::RUNNING_JOB_PREFIX . ':*');
|
||||
$keys = RedisTool::keysByPattern($this->RedisConnection, $pattern);
|
||||
|
||||
$jobIds = [];
|
||||
foreach ($keys as $key) {
|
||||
$parts = explode(':', $key);
|
||||
$jobIds[] = end($parts);
|
||||
$queue = $parts[2];
|
||||
$jobId = $parts[3];
|
||||
$jobIds[$queue][$jobId] = $this->RedisConnection->get(self::RUNNING_JOB_PREFIX . ":$queue:$jobId");
|
||||
}
|
||||
return $jobIds;
|
||||
}
|
||||
|
|
|
@ -187,7 +187,7 @@ class CurlClient extends HttpSocketExtended
|
|||
// Share handle between requests to allow keep connection alive between requests
|
||||
$this->ch = curl_init();
|
||||
if (!$this->ch) {
|
||||
throw new \RuntimeException("Could not initialize cURL");
|
||||
throw new \RuntimeException("Could not initialize curl");
|
||||
}
|
||||
} else {
|
||||
// Reset options, so we can do another request
|
||||
|
@ -237,18 +237,19 @@ class CurlClient extends HttpSocketExtended
|
|||
};
|
||||
|
||||
if (!curl_setopt_array($this->ch, $options)) {
|
||||
throw new \RuntimeException('cURL error: Could not set options');
|
||||
throw new \RuntimeException('curl error: Could not set options');
|
||||
}
|
||||
|
||||
// Download the given URL, and return output
|
||||
$output = curl_exec($this->ch);
|
||||
|
||||
if ($output === false) {
|
||||
$errorCode = curl_errno($this->ch);
|
||||
$errorMessage = curl_error($this->ch);
|
||||
if (!empty($errorMessage)) {
|
||||
$errorMessage = ": $errorMessage";
|
||||
}
|
||||
throw new SocketException('cURL error ' . curl_strerror(curl_errno($this->ch)) . $errorMessage);
|
||||
throw new SocketException("curl error $errorCode '" . curl_strerror($errorCode) . "'" . $errorMessage);
|
||||
}
|
||||
|
||||
$code = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
|
||||
|
|
|
@ -18,10 +18,15 @@ class HttpSocketHttpException extends Exception
|
|||
{
|
||||
$this->response = $response;
|
||||
$this->url = $url;
|
||||
|
||||
$message = "Remote server returns HTTP error code $response->code";
|
||||
if ($url) {
|
||||
$message .= " for URL $url";
|
||||
}
|
||||
if ($response->body) {
|
||||
$message .= ': ' . substr($response->body, 0, 100);
|
||||
}
|
||||
|
||||
parent::__construct($message, (int)$response->code);
|
||||
}
|
||||
|
||||
|
|
|
@ -355,6 +355,14 @@ class ServerSyncTool
|
|||
return $this->server['Server']['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function serverName()
|
||||
{
|
||||
return $this->server['Server']['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
|
|
|
@ -2062,6 +2062,7 @@ class Feed extends AppModel
|
|||
$contentType = $response->getHeader('content-type');
|
||||
if ($contentType === 'application/zip') {
|
||||
$zipFilePath = FileAccessTool::writeToTempFile($response->body);
|
||||
unset($response->body); // cleanup variable to reduce memory usage
|
||||
|
||||
try {
|
||||
$response->body = $this->unzipFirstFile($zipFilePath);
|
||||
|
@ -2198,7 +2199,7 @@ class Feed extends AppModel
|
|||
ZipArchive::ER_READ => 'read error',
|
||||
ZipArchive::ER_SEEK => 'seek error',
|
||||
];
|
||||
$message = isset($errorCodes[$result]) ? $errorCodes[$result] : 'error ' . $result;
|
||||
$message = $errorCodes[$result] ?? 'error ' . $result;
|
||||
throw new Exception("Remote server returns ZIP file, that cannot be open ($message)");
|
||||
}
|
||||
|
||||
|
|
|
@ -566,7 +566,7 @@ class Server extends AppModel
|
|||
$response = $serverSync->fetchEvent($eventId, $params);
|
||||
$event = $response->json();
|
||||
} catch (Exception $e) {
|
||||
$this->logException("Failed downloading the event $eventId from remote server {$serverSync->serverId()}", $e);
|
||||
$this->logException("Failed to download the event $eventId from remote server {$serverSync->serverId()} '{$serverSync->serverName()}'", $e);
|
||||
$fails[$eventId] = __('failed downloading the event');
|
||||
return false;
|
||||
}
|
||||
|
@ -4947,6 +4947,28 @@ class Server extends AppModel
|
|||
return $this->saveMany($toSave, ['validate' => false, 'fields' => ['authkey']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encryptionKey
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function isEncryptionKeyValid($encryptionKey)
|
||||
{
|
||||
$servers = $this->find('list', [
|
||||
'fields' => ['Server.id', 'Server.authkey'],
|
||||
]);
|
||||
foreach ($servers as $id => $authkey) {
|
||||
if (EncryptedValue::isEncrypted($authkey)) {
|
||||
try {
|
||||
BetterSecurity::decrypt(substr($authkey, 2), $encryptionKey);
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("Could not decrypt auth key for server #$id", 0, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all Attribute and Object types
|
||||
*/
|
||||
|
|
|
@ -1017,16 +1017,16 @@ class Sighting extends AppModel
|
|||
* @return TmpFileTool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function restSearch(array $user, $returnFormat, $filters)
|
||||
public function restSearch(array $user, $returnFormat, array $filters)
|
||||
{
|
||||
$allowedContext = array('event', 'attribute');
|
||||
// validate context
|
||||
if (isset($filters['context']) && !in_array($filters['context'], $allowedContext, true)) {
|
||||
throw new MethodNotAllowedException(__('Invalid context %s.', $filters['context']));
|
||||
throw new BadRequestException(__('Invalid context %s.', $filters['context']));
|
||||
}
|
||||
// ensure that an id or uuid is provided if context is set
|
||||
if (!empty($filters['context']) && !(isset($filters['id']) || isset($filters['uuid'])) ) {
|
||||
throw new MethodNotAllowedException(__('An ID or UUID must be provided if the context is set.'));
|
||||
throw new BadRequestException(__('An ID or UUID must be provided if the context is set.'));
|
||||
}
|
||||
|
||||
if (!isset($this->validFormats[$returnFormat][1])) {
|
||||
|
@ -1396,7 +1396,7 @@ class Sighting extends AppModel
|
|||
try {
|
||||
$sightings = $serverSync->fetchSightingsForEvents($chunk);
|
||||
} catch (Exception $e) {
|
||||
$this->logException("Failed downloading the sightings from {$serverSync->server()['Server']['name']}.", $e);
|
||||
$this->logException("Failed to download sightings from {$serverSync->server()['Server']['name']}.", $e);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -154,6 +154,32 @@ class SystemSetting extends AppModel
|
|||
return $this->saveMany($toSave);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if provided encryption key is valid for all encrypted settings
|
||||
* @param string $encryptionKey
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function isEncryptionKeyValid($encryptionKey)
|
||||
{
|
||||
$settings = $this->find('list', [
|
||||
'fields' => ['SystemSetting.setting', 'SystemSetting.value'],
|
||||
]);
|
||||
foreach ($settings as $setting => $value) {
|
||||
if (!self::isSensitive($setting)) {
|
||||
continue;
|
||||
}
|
||||
if (EncryptedValue::isEncrypted($value)) {
|
||||
try {
|
||||
BetterSecurity::decrypt(substr($value, 2), $encryptionKey);
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("Could not decrypt `$setting` setting.", 0, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sensitive setting are passwords or api keys.
|
||||
* @param string $setting Setting name
|
||||
|
|
Loading…
Reference in New Issue