new: [sighting/api] trying to follow the new API architecture. JSON

export is broken but CSV is working. WIP...
pull/3789/head
Sami Mokaddem 2018-10-23 11:24:03 +02:00
parent 41d2de90db
commit 99e5f560a8
4 changed files with 130 additions and 12 deletions

View File

@ -181,13 +181,14 @@ class RestResponseComponent extends Component
'mandatory' => array('OR' => array('values', 'id')),
'optional' => array('type', 'source', 'timestamp', 'date', 'time')
),
'get' => array(
'restSearch' => array(
'description' => "Search MISP using a list of filter parameters and return the data in the JSON format.
The search is available on an event, attribute or instace level,
just select the scope via the URL (/sighting/get/event vs /sighting/get/).",
'mandatory' => array('context'),
just select the scope via the URL (/sighting/get/event vs /sighting/get/).
id MUST be provided is context is set.",
'mandatory' => array('returnFormat'),
'optional' => array('id', 'type', 'from', 'to', 'last', 'org_id', 'includeAttribute', 'includeEvent'),
'params' => array()
'params' => array('context')
),
),
'SharingGroup' => array(
@ -454,14 +455,15 @@ class RestResponseComponent extends Component
private function __setup() {
if (!$this->__setup) {
$scopes = array('Event', 'Attribute');
$scopes = array('Event', 'Attribute', 'Sighting');
foreach ($scopes as $scope) {
$this->{$scope} = ClassRegistry::init($scope);
$this->__descriptions[$scope]['restSearch'] = array(
'description' => $this->__descriptions[$scope]['restSearch']['description'],
'returnFormat' => array_keys($this->{$scope}->validFormats),
'mandatory' => $this->__descriptions[$scope]['restSearch']['mandatory'],
'optional' => $this->__descriptions[$scope]['restSearch']['optional']
'optional' => $this->__descriptions[$scope]['restSearch']['optional'],
'params' => $this->__descriptions[$scope]['restSearch']['params']
);
}
}

View File

@ -220,9 +220,9 @@ class SightingsController extends AppController
return $this->RestResponse->viewData($sightings);
}
public function get($context = false)
public function restSearch($context = false)
{
$paramArray = array('id', 'type', 'from', 'to', 'last', 'org_id');
$paramArray = array('returnFormat', 'id', 'type', 'from', 'to', 'last', 'org_id', 'includeAttribute', 'includeEvent');
$filterData = array(
'request' => $this->request,
'named_params' => $this->params['named'],
@ -232,13 +232,24 @@ class SightingsController extends AppController
$filters = $this->_harvestParameters($filterData, $exception);
$filters['context'] = $context;
if (isset($filters['returnFormat'])) {
$returnFormat = $filters['returnFormat'];
}
if ($returnFormat === 'download') {
$returnFormat = 'json';
}
// ensure that an id is provided if context is set
if ($context !== false && !isset($filters['id'])) {
throw new MethodNotAllowedException(_('An id must be provided if the context is set.'));
}
$sightings = $this->Sighting->getSightingsForTime($this->Auth->user(), $filters);
return $this->RestResponse->viewData($sightings);
$sightings = $this->Sighting->getSightingsForTime($this->Auth->user(), $returnFormat, $filters);
$validFormats = $this->Sighting->validFormats;
$responseType = $validFormats[$returnFormat][0];
return $this->RestResponse->viewData($sightings, $responseType, false, true);
//return $this->RestResponse->viewData($sightings);
}
public function listSightings($id, $context = 'attribute', $org_id = false)

View File

@ -14,6 +14,8 @@ class CsvExport
$lines = $this->__attributesHandler($data, $options);
} else if($options['scope'] === 'Event') {
$lines = $this->__eventsHandler($data, $options);
} else if($options['scope'] === 'Sighting') {
$lines = $this->__sightingsHandler($data, $options);
}
return $lines;
}
@ -46,6 +48,32 @@ class CsvExport
return $this->__addLine($attribute, $options);
}
private function __sightingsHandler($sighting, $options)
{
$lines = '';
if (isset($sighting['Sighting']['Event'])) {
foreach($sighting['Sighting']['Event'] as $k => $event_val) {
$new_key = 'event_' . $k;
// in case we have an array, e.g. orc => name
if (is_array($event_val)) {
$v2 = reset($event_val);
$k2 = key($event_val);
$new_key .= '_' . $k2;
$event_val = $v2;
}
$sighting['Sighting'][$new_key] = $event_val;
}
}
if (isset($sighting['Sighting']['Attribute'])) {
foreach($sighting['Sighting']['Attribute'] as $k => $attribute_val) {
$new_key = 'attribute_' . $k;
$sighting['Sighting'][$new_key] = $attribute_val;
}
}
$lines .= $this->__addLine($sighting['Sighting'], $options);
return $lines;
}
private function __eventsHandler($event, $options)
{
$lines = '';

View File

@ -38,6 +38,20 @@ class Sighting extends AppModel
2 => 'expiration'
);
public $validFormats = array(
'json' => array('json', 'JsonExport', 'json'),
//'openioc' => array('xml', 'OpeniocExport', 'ioc'),
//'xml' => array('xml', 'XmlExport', 'xml'),
//'suricata' => array('txt', 'NidsSuricataExport', 'rules'),
//'snort' => array('txt', 'NidsSnortExport', 'rules'),
//'rpz' => array('rpz', 'RPZExport', 'rpz'),
//'text' => array('text', 'TextExport', 'txt'),
'csv' => array('csv', 'CsvExport', 'csv'),
//'stix' => array('xml', 'Stix1Export', 'xml'),
//'stix2' => array('json', 'Stix2Export', 'json'),
//'cache' => array('txt', 'CacheExport', 'cache')
);
public function beforeValidate($options = array())
{
parent::beforeValidate();
@ -449,8 +463,13 @@ class Sighting extends AppModel
return $sightingsRearranged;
}
public function getSightingsForTime($user, $filters)
public function getSightingsForTime($user, $returnFormat, $filters)
{
if (!isset($this->validFormats[$returnFormat][1])) {
throw new NotFoundException('Invalid output format.');
}
App::uses($this->validFormats[$returnFormat][1], 'Export');
$exportTool = new $this->validFormats[$returnFormat][1]();
// fetch sightings matching the query
if (isset($filters['from']) && isset($filters['to'])) {
@ -490,21 +509,79 @@ class Sighting extends AppModel
));
$sightings = array_values($sightings);
$filters['requested_attributes'] = array('id', 'attribute_id', 'event_id', 'org_id', 'date_sighting', 'uuid', 'source', 'type');
// apply ACL and sightings policies
$allowedSightings = array();
$additional_attribute_added = false;
$additional_event_added = false;
foreach($sightings as $sid) {
$sight = $this->getSighting($sid, $user);
// by default, do not include event and attribute
if (!isset($filters['includeAttribute']) || !$filters['includeAttribute']) {
unset($sight["Sighting"]["Attribute"]);
} else if (!$additional_attribute_added) {
$filters['requested_attributes'] = array_merge($filters['requested_attributes'], array('attribute_uuid', 'attribute_type', 'attribute_category', 'attribute_to_ids', 'attribute_value'));
$additional_attribute_added = true;
}
if (!isset($filters['includeEvent']) || !$filters['includeEvent']) {
unset($sight["Sighting"]["Event"]);
} else if (!$additional_event_added) {
$filters['requested_attributes'] = array_merge($filters['requested_attributes'], array('event_uuid', 'event_orgc_id', 'event_org_id', 'event_info', 'event_Orgc_name'));
$additional_event_added = true;
}
if (!empty($sight)) {
array_push($allowedSightings, $sight);
}
}
return $allowedSightings;
$params = array(
'conditions' => array(), //result already filtered
);
if (!isset($this->validFormats[$returnFormat])) {
// this is where the new code path for the export modules will go
throw new MethodNotFoundException('Invalid export format.');
}
if (method_exists($exportTool, 'modify_params')) {
//$params = $exportTool->modify_params($user, $params);
}
$exportToolParams = array(
'user' => $user,
'params' => $params,
'returnFormat' => $returnFormat,
'scope' => 'Sighting',
'filters' => $filters
);
if (!empty($exportTool->additional_params)) {
//$params = array_merge($params, $exportTool->additional_params);
}
$tmpfile = tmpfile();
fwrite($tmpfile, $exportTool->header($exportToolParams));
$temp = '';
$i = 0;
foreach ($allowedSightings as $sighting) {
$temp .= $exportTool->handler($sighting, $exportToolParams);
if ($temp !== '') {
if ($i != count($allowedSightings) -1) {
$temp .= $exportTool->separator($exportToolParams);
}
}
$i++;
}
fwrite($tmpfile, $temp);
fwrite($tmpfile, $exportTool->footer($exportToolParams));
fseek($tmpfile, 0);
$final = fread($tmpfile, fstat($tmpfile)['size']);
fclose($tmpfile);
return $final;
//return $allowedSightings;
}
}