mirror of https://github.com/MISP/MISP
Merge pull request #6779 from JakubOnderka/event-report-extract-fix
Event report extract fixpull/6782/head
commit
ba624b303c
|
@ -209,31 +209,30 @@ class EventReportsController extends AppController
|
|||
{
|
||||
if (!$this->request->is('ajax')) {
|
||||
throw new MethodNotAllowedException(__('This function can only be reached via AJAX.'));
|
||||
} else {
|
||||
if ($this->request->is('post')) {
|
||||
$report = $this->EventReport->fetchIfAuthorized($this->Auth->user(), $reportId, 'edit', $throwErrors=true, $full=false);
|
||||
$results = $this->EventReport->getComplexTypeToolResultWithReplacements($this->Auth->user(), $report);
|
||||
$report['EventReport']['content'] = $results['replacementResult']['contentWithReplacements'];
|
||||
$contextResults = $this->EventReport->extractWithReplacements($this->Auth->user(), $report, ['replace' => true]);
|
||||
$suggestionResult = $this->EventReport->transformFreeTextIntoSuggestion($contextResults['contentWithReplacements'], $results['complexTypeToolResult']);
|
||||
$errors = $this->EventReport->applySuggestions($this->Auth->user(), $report, $suggestionResult['contentWithSuggestions'], $suggestionResult['suggestionsMapping']);
|
||||
if (empty($errors)) {
|
||||
if (!empty($this->data['EventReport']['tag_event'])) {
|
||||
$this->EventReport->attachTagsAfterReplacements($this->Auth->User(), $contextResults['replacedContext'], $report['EventReport']['event_id']);
|
||||
}
|
||||
$report = $this->EventReport->simpleFetchById($this->Auth->user(), $reportId);
|
||||
$data = [ 'report' => $report ];
|
||||
$successMessage = __('Automatic extraction applied to Event Report %s', $reportId);
|
||||
return $this->__getSuccessResponseBasedOnContext($successMessage, $data, 'applySuggestions', $reportId);
|
||||
} else {
|
||||
$errorMessage = __('Automatic extraction could not be applied to Event Report %s.%sReasons: %s', $reportId, PHP_EOL, json_encode($errors));
|
||||
return $this->__getFailResponseBasedOnContext($errorMessage, array(), 'applySuggestions', $reportId);
|
||||
}
|
||||
}
|
||||
$this->layout = 'ajax';
|
||||
$this->set('reportId', $reportId);
|
||||
$this->render('ajax/extractAllFromReport');
|
||||
}
|
||||
if ($this->request->is('post')) {
|
||||
$report = $this->EventReport->fetchIfAuthorized($this->Auth->user(), $reportId, 'edit', $throwErrors=true, $full=false);
|
||||
$results = $this->EventReport->getComplexTypeToolResultWithReplacements($this->Auth->user(), $report);
|
||||
$report['EventReport']['content'] = $results['replacementResult']['contentWithReplacements'];
|
||||
$contextResults = $this->EventReport->extractWithReplacements($this->Auth->user(), $report, ['replace' => true]);
|
||||
$suggestionResult = $this->EventReport->transformFreeTextIntoSuggestion($contextResults['contentWithReplacements'], $results['complexTypeToolResult']);
|
||||
$errors = $this->EventReport->applySuggestions($this->Auth->user(), $report, $suggestionResult['contentWithSuggestions'], $suggestionResult['suggestionsMapping']);
|
||||
if (empty($errors)) {
|
||||
if (!empty($this->data['EventReport']['tag_event'])) {
|
||||
$this->EventReport->attachTagsAfterReplacements($this->Auth->User(), $contextResults['replacedContext'], $report['EventReport']['event_id']);
|
||||
}
|
||||
$report = $this->EventReport->simpleFetchById($this->Auth->user(), $reportId);
|
||||
$data = [ 'report' => $report ];
|
||||
$successMessage = __('Automatic extraction applied to Event Report %s', $reportId);
|
||||
return $this->__getSuccessResponseBasedOnContext($successMessage, $data, 'applySuggestions', $reportId);
|
||||
} else {
|
||||
$errorMessage = __('Automatic extraction could not be applied to Event Report %s.%sReasons: %s', $reportId, PHP_EOL, json_encode($errors));
|
||||
return $this->__getFailResponseBasedOnContext($errorMessage, array(), 'applySuggestions', $reportId);
|
||||
}
|
||||
}
|
||||
$this->layout = 'ajax';
|
||||
$this->set('reportId', $reportId);
|
||||
$this->render('ajax/extractAllFromReport');
|
||||
}
|
||||
|
||||
public function extractFromReport($reportId)
|
||||
|
|
|
@ -1116,10 +1116,13 @@ class TagsController extends AppController
|
|||
'conditions' => $conditions,
|
||||
'recursive' => -1
|
||||
));
|
||||
if (!$searchIfTagExists && empty($tags)) {
|
||||
$tags = [];
|
||||
foreach ($tag as $i => $tagName) {
|
||||
$tags[] = ['Tag' => ['name' => $tagName], 'simulatedTag' => true];
|
||||
if (!$searchIfTagExists) {
|
||||
$foundTagNames = Hash::extract($tags, "{n}.Tag.name");
|
||||
foreach ($tag as $tagName) {
|
||||
if (!in_array($tagName, $foundTagNames, true)) {
|
||||
// Tag not found, insert simulated tag
|
||||
$tags[] = ['Tag' => ['name' => $tagName], 'simulatedTag' => true];
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->loadModel('Taxonomy');
|
||||
|
|
|
@ -234,6 +234,7 @@ class ComplexTypeTool
|
|||
if (isset($resultArray[$typeArray['value']])) {
|
||||
continue;
|
||||
}
|
||||
$typeArray['original_value'] = $ioc;
|
||||
$resultArray[$typeArray['value']] = $typeArray;
|
||||
}
|
||||
return array_values($resultArray);
|
||||
|
|
|
@ -521,7 +521,8 @@ class EventReport extends AppModel
|
|||
return $errors;
|
||||
}
|
||||
|
||||
public function applySuggestions($user, $report, $contentWithSuggestions, $suggestionsMapping) {
|
||||
public function applySuggestions(array $user, array $report, $contentWithSuggestions, array $suggestionsMapping)
|
||||
{
|
||||
$errors = [];
|
||||
$replacedContent = $contentWithSuggestions;
|
||||
$success = 0;
|
||||
|
@ -546,10 +547,10 @@ class EventReport extends AppModel
|
|||
return $errors;
|
||||
}
|
||||
|
||||
public function applySuggestionsInText($contentWithSuggestions, $attribute, $value)
|
||||
public function applySuggestionsInText($contentWithSuggestions, array $attribute, $value)
|
||||
{
|
||||
$textToBeReplaced = sprintf('@[suggestion](%s)', $value);
|
||||
$textToInject = sprintf('@[attribute](%s)', $attribute['Attribute']['uuid']);
|
||||
$textToBeReplaced = "@[suggestion]($value)";
|
||||
$textToInject = "@[attribute]({$attribute['Attribute']['uuid']})";
|
||||
$replacedContent = str_replace($textToBeReplaced, $textToInject, $contentWithSuggestions);
|
||||
return $replacedContent;
|
||||
}
|
||||
|
@ -642,25 +643,36 @@ class EventReport extends AppModel
|
|||
];
|
||||
}
|
||||
|
||||
public function transformFreeTextIntoSuggestion($content, $complexTypeToolResult)
|
||||
public function transformFreeTextIntoSuggestion($content, array $complexTypeToolResult)
|
||||
{
|
||||
$replacedContent = $content;
|
||||
$suggestionsMapping = [];
|
||||
$typeToCategoryMapping = $this->Event->Attribute->typeToCategoryMapping();
|
||||
foreach ($complexTypeToolResult as $i => $complexTypeToolEntry) {
|
||||
|
||||
// Sort by original value string length, longest values first
|
||||
usort($complexTypeToolResult, function ($a, $b) {
|
||||
$strlenA = strlen($a['original_value']);
|
||||
$strlenB = strlen($b['original_value']);
|
||||
if ($strlenA === $strlenB) {
|
||||
return 0;
|
||||
}
|
||||
return ($strlenA < $strlenB) ? 1 : -1;
|
||||
});
|
||||
|
||||
$suggestionsMapping = [];
|
||||
foreach ($complexTypeToolResult as $complexTypeToolEntry) {
|
||||
$textToBeReplaced = $complexTypeToolEntry['value'];
|
||||
$textToInject = sprintf('@[suggestion](%s)', $textToBeReplaced);
|
||||
$textToInject = "@[suggestion]($textToBeReplaced)";
|
||||
$suggestionsMapping[$textToBeReplaced] = [
|
||||
'category' => $typeToCategoryMapping[$complexTypeToolEntry['default_type']][0],
|
||||
'type' => $complexTypeToolEntry['default_type'],
|
||||
'value' => $textToBeReplaced,
|
||||
'to_ids' => $complexTypeToolEntry['to_ids'],
|
||||
];
|
||||
$replacedContent = str_replace($textToBeReplaced, $textToInject, $replacedContent);
|
||||
$replacedContent = str_replace($complexTypeToolEntry['original_value'], $textToInject, $replacedContent);
|
||||
}
|
||||
return [
|
||||
'contentWithSuggestions' => $replacedContent,
|
||||
'suggestionsMapping' => $suggestionsMapping
|
||||
'suggestionsMapping' => $suggestionsMapping,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -674,21 +686,17 @@ class EventReport extends AppModel
|
|||
return $complexTypeToolResult;
|
||||
}
|
||||
|
||||
public function getComplexTypeToolResultFromReport($content)
|
||||
public function getComplexTypeToolResultWithReplacements(array $user, array $report)
|
||||
{
|
||||
App::uses('ComplexTypeTool', 'Tools');
|
||||
$complexTypeTool = new ComplexTypeTool();
|
||||
$this->Warninglist = ClassRegistry::init('Warninglist');
|
||||
$complexTypeTool->setTLDs($this->Warninglist->fetchTLDLists());
|
||||
$complexTypeToolResult = $complexTypeTool->checkComplexRouter($content, 'freetext');
|
||||
return $complexTypeToolResult;
|
||||
}
|
||||
|
||||
public function getComplexTypeToolResultWithReplacements($user, $report)
|
||||
{
|
||||
$complexTypeToolResult = $this->getComplexTypeToolResultFromReport($report['EventReport']['content']);
|
||||
$complexTypeToolResult = $complexTypeTool->checkFreeText($report['EventReport']['content']);
|
||||
$replacementResult = $this->transformFreeTextIntoReplacement($user, $report, $complexTypeToolResult);
|
||||
$complexTypeToolResult = $this->getComplexTypeToolResultFromReport($replacementResult['contentWithReplacements']);
|
||||
$complexTypeToolResult = $complexTypeTool->checkFreeText($replacementResult['contentWithReplacements']);
|
||||
|
||||
return [
|
||||
'complexTypeToolResult' => $complexTypeToolResult,
|
||||
'replacementResult' => $replacementResult,
|
||||
|
@ -700,6 +708,7 @@ class EventReport extends AppModel
|
|||
*
|
||||
* @param array $user
|
||||
* @param array $report
|
||||
* @param array $options
|
||||
* @return array
|
||||
*/
|
||||
public function extractWithReplacements(array $user, array $report, array $options = [])
|
||||
|
@ -713,7 +722,6 @@ class EventReport extends AppModel
|
|||
'attack' => true,
|
||||
];
|
||||
$options = array_merge($baseOptions, $options);
|
||||
$originalContent = $report['EventReport']['content'];
|
||||
$this->GalaxyCluster = ClassRegistry::init('GalaxyCluster');
|
||||
$mitreAttackGalaxyId = $this->GalaxyCluster->Galaxy->getMitreAttackGalaxyId();
|
||||
$clusterContain = ['Tag'];
|
||||
|
@ -734,17 +742,21 @@ class EventReport extends AppModel
|
|||
'contain' => $clusterContain
|
||||
]);
|
||||
|
||||
$originalContent = $report['EventReport']['content'];
|
||||
// Remove all existing event report markers
|
||||
$content = preg_replace("/@\[(attribute|tag|galaxymatrix)]\([^)]*\)/", '', $originalContent);
|
||||
|
||||
if ($options['tags']) {
|
||||
$this->Tag = ClassRegistry::init('Tag');
|
||||
$tags = $this->Tag->fetchUsableTags($user);
|
||||
foreach ($tags as $i => $tag) {
|
||||
foreach ($tags as $tag) {
|
||||
$tagName = $tag['Tag']['name'];
|
||||
$found = $this->isValidReplacementTag($originalContent, $tagName);
|
||||
$found = $this->isValidReplacementTag($content, $tagName);
|
||||
if ($found) {
|
||||
$replacedContext[$tagName][$tagName] = $tag['Tag'];
|
||||
} else {
|
||||
$tagNameUpper = strtoupper($tagName);
|
||||
$found = $this->isValidReplacementTag($originalContent, $tagNameUpper);
|
||||
$found = $this->isValidReplacementTag($content, $tagNameUpper);
|
||||
if ($found) {
|
||||
$replacedContext[$tagNameUpper][$tagName] = $tag['Tag'];
|
||||
}
|
||||
|
@ -752,10 +764,10 @@ class EventReport extends AppModel
|
|||
}
|
||||
}
|
||||
|
||||
foreach ($clusters as $i => $cluster) {
|
||||
foreach ($clusters as $cluster) {
|
||||
$cluster['GalaxyCluster']['colour'] = '#0088cc';
|
||||
$tagName = $cluster['GalaxyCluster']['tag_name'];
|
||||
$found = $this->isValidReplacementTag($originalContent, $tagName);
|
||||
$found = $this->isValidReplacementTag($content, $tagName);
|
||||
if ($found) {
|
||||
$replacedContext[$tagName][$tagName] = $cluster['GalaxyCluster'];
|
||||
}
|
||||
|
@ -765,10 +777,10 @@ class EventReport extends AppModel
|
|||
$replacedContext[$cluster['GalaxyCluster']['value']][$tagName] = $cluster['GalaxyCluster'];
|
||||
}
|
||||
if ($options['synonyms']) {
|
||||
foreach ($cluster['GalaxyElement'] as $j => $element) {
|
||||
foreach ($cluster['GalaxyElement'] as $element) {
|
||||
if (strlen($element['value']) >= $options['synonyms_min_characters']) {
|
||||
$toSearch = ' ' . $element['value'] . ' ';
|
||||
$found = strpos($originalContent, $toSearch) !== false;
|
||||
$found = strpos($content, $toSearch) !== false;
|
||||
if ($found) {
|
||||
$replacedContext[$element['value']][$tagName] = $cluster['GalaxyCluster'];
|
||||
}
|
||||
|
@ -783,22 +795,22 @@ class EventReport extends AppModel
|
|||
'conditions' => ['GalaxyCluster.galaxy_id' => $mitreAttackGalaxyId],
|
||||
'contain' => $clusterContain
|
||||
]);
|
||||
foreach ($attackClusters as $i => $cluster) {
|
||||
foreach ($attackClusters as $cluster) {
|
||||
$cluster['GalaxyCluster']['colour'] = '#0088cc';
|
||||
$tagName = $cluster['GalaxyCluster']['tag_name'];
|
||||
$toSearch = ' ' . $cluster['GalaxyCluster']['value'] . ' ';
|
||||
$found = strpos($originalContent, $toSearch) !== false;
|
||||
$found = strpos($content, $toSearch) !== false;
|
||||
if ($found) {
|
||||
$replacedContext[$cluster['GalaxyCluster']['value']][$tagName] = $cluster['GalaxyCluster'];
|
||||
} else {
|
||||
$clusterParts = explode(' - ', $cluster['GalaxyCluster']['value'], 2);
|
||||
$toSearch = ' ' . $clusterParts[0] . ' ';
|
||||
$found = strpos($originalContent, $toSearch) !== false;
|
||||
$found = strpos($content, $toSearch) !== false;
|
||||
if ($found) {
|
||||
$replacedContext[$clusterParts[0]][$tagName] = $cluster['GalaxyCluster'];
|
||||
} else {
|
||||
} else if (isset($clusterParts[1])) {
|
||||
$toSearch = ' ' . $clusterParts[1] . ' ';
|
||||
$found = strpos($originalContent, $toSearch) !== false;
|
||||
$found = strpos($content, $toSearch) !== false;
|
||||
if ($found) {
|
||||
$replacedContext[$clusterParts[1]][$tagName] = $cluster['GalaxyCluster'];
|
||||
}
|
||||
|
@ -810,14 +822,32 @@ class EventReport extends AppModel
|
|||
'replacedContext' => $replacedContext
|
||||
];
|
||||
if ($options['replace']) {
|
||||
// Sort by original value string length, longest values first
|
||||
uksort($replacedContext, function ($a, $b) {
|
||||
$strlenA = strlen($a);
|
||||
$strlenB = strlen($b);
|
||||
if ($strlenA === $strlenB) {
|
||||
return 0;
|
||||
}
|
||||
return ($strlenA < $strlenB) ? 1 : -1;
|
||||
});
|
||||
|
||||
$content = $originalContent;
|
||||
$secondPassReplace = [];
|
||||
// Replace in two pass to prevent double replace
|
||||
$id = 0;
|
||||
foreach ($replacedContext as $rawText => $replacements) {
|
||||
// Replace with first one until a better strategy is found
|
||||
reset($replacements);
|
||||
$replacement = key($replacements);
|
||||
$textToInject = sprintf('@[tag](%s)', $replacement);
|
||||
$content = str_replace($rawText, $textToInject, $content);
|
||||
++$id;
|
||||
$content = str_replace($rawText, "@[mark]($id)", $content);
|
||||
$secondPassReplace[$id] = "@[tag]($replacement)";
|
||||
}
|
||||
|
||||
$content = preg_replace_callback("/@\[mark]\(([^)]*)\)/", function ($matches) use ($secondPassReplace) {
|
||||
return $secondPassReplace[$matches[1]];
|
||||
}, $content);
|
||||
$toReturn['contentWithReplacements'] = $content;
|
||||
}
|
||||
return $toReturn;
|
||||
|
@ -835,7 +865,6 @@ class EventReport extends AppModel
|
|||
'event_id' => $event_id,
|
||||
'url' => $url
|
||||
];
|
||||
$module = $this->isFetchURLModuleEnabled();
|
||||
if (!empty($module)) {
|
||||
$result = $this->Module->queryModuleServer($modulePayload, false);
|
||||
if (empty($result['results'][0]['values'][0])) {
|
||||
|
@ -853,7 +882,7 @@ class EventReport extends AppModel
|
|||
}
|
||||
|
||||
/**
|
||||
* findValidReplacementTag Search if tagName is in content and is not wrapped in a tag reference
|
||||
* findValidReplacementTag Search if tagName is in content
|
||||
*
|
||||
* @param string $content
|
||||
* @param string $tagName
|
||||
|
@ -861,25 +890,8 @@ class EventReport extends AppModel
|
|||
*/
|
||||
private function isValidReplacementTag($content, $tagName)
|
||||
{
|
||||
$lastIndex = 0;
|
||||
$allIndices = [];
|
||||
$toSearch = strpos($tagName, ':') === false ? ' ' . $tagName . ' ' : $tagName;
|
||||
while (($lastIndex = strpos($content, $toSearch, $lastIndex)) !== false) {
|
||||
$allIndices[] = $lastIndex;
|
||||
$lastIndex = $lastIndex + strlen($toSearch);
|
||||
}
|
||||
if (empty($allIndices)) {
|
||||
return false;
|
||||
} else {
|
||||
$wrapper = '@[tag](';
|
||||
foreach ($allIndices as $i => $index) {
|
||||
$stringBeforeTag = substr($content, $index - strlen($wrapper), strlen($wrapper));
|
||||
if ($stringBeforeTag != $wrapper) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return strpos($content, $toSearch) !== false;
|
||||
}
|
||||
|
||||
public function attachTagsAfterReplacements($user, $replacedContext, $eventId)
|
||||
|
|
|
@ -509,7 +509,7 @@ function renderMISPElement(scope, elementID, indexes) {
|
|||
type: suggestion.complexTypeToolResult.picked_type,
|
||||
origValue: elementID,
|
||||
value: suggestion.complexTypeToolResult.value,
|
||||
'indexStart': indexes.start,
|
||||
indexStart: indexes.start,
|
||||
suggestionkey: suggestionKey,
|
||||
checked: suggestion.checked
|
||||
})
|
||||
|
@ -651,23 +651,34 @@ function attachRemoteMISPElements() {
|
|||
$div.html(cache_matrix[cacheKey])
|
||||
}
|
||||
})
|
||||
|
||||
var tagNamesToLoad = [];
|
||||
var tagsLoading = [];
|
||||
$('.embeddedTag[data-scope="tag"]').each(function() {
|
||||
var $div = $(this)
|
||||
$div.append($('<span/>').append(loadingSpanAnimation))
|
||||
var eventID = $div.data('eventid')
|
||||
var elementID = $div.data('elementid')
|
||||
var cacheKey = eventid + '-' + elementID
|
||||
clearTimeout(tagTimers[cacheKey]);
|
||||
if (cache_tag[cacheKey] === undefined) {
|
||||
tagTimers[cacheKey] = setTimeout(function() {
|
||||
fetchTagInfo(eventID, elementID, function() {
|
||||
attachTagInfo($div, eventID, elementID, true)
|
||||
})
|
||||
}, firstCustomPostRenderCall ? 0 : slowDebounceDelay);
|
||||
var $div = $(this);
|
||||
var elementID = $div.data('elementid');
|
||||
if (!(elementID in cache_tag)) {
|
||||
$div.append($('<span/>').append(loadingSpanAnimation));
|
||||
tagNamesToLoad.push(elementID);
|
||||
tagsLoading.push($div);
|
||||
} else {
|
||||
$div.html(cache_tag[cacheKey])
|
||||
$div.html(cache_tag[elementID]);
|
||||
}
|
||||
})
|
||||
}).promise().done(function() {
|
||||
if (tagNamesToLoad.length === 0) {
|
||||
return;
|
||||
}
|
||||
fetchTagInfo(tagNamesToLoad, function() {
|
||||
$.each(tagsLoading, function() {
|
||||
var $div = $(this);
|
||||
var elementID = $div.data('elementid');
|
||||
if (elementID in cache_tag) {
|
||||
$div.html(cache_tag[elementID]);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (firstCustomPostRenderCall) {
|
||||
// Wait, because .each calls are asynchronous
|
||||
setTimeout(function() {
|
||||
|
@ -720,56 +731,53 @@ function attachGalaxyMatrix($elem, eventid, elementID) {
|
|||
})
|
||||
}
|
||||
|
||||
function attachTagInfo($elem, eventid, elementID, all) {
|
||||
var cacheKey = eventid + '-' + elementID
|
||||
$elem.html(cache_tag[cacheKey])
|
||||
if (all === true) {
|
||||
$('.embeddedTag[data-scope="tag"]').filter(function() {
|
||||
return $(this).data('eventid') == eventid && $(this).data('elementid') == elementID
|
||||
}).html(cache_tag[cacheKey])
|
||||
}
|
||||
}
|
||||
|
||||
function fetchTagInfo(eventid, tagName, callback) {
|
||||
function fetchTagInfo(tagNames, callback) {
|
||||
$.ajax({
|
||||
data: {
|
||||
"tag": tagName,
|
||||
"tag": tagNames,
|
||||
},
|
||||
success:function(data, textStatus) {
|
||||
var $tag
|
||||
success: function (data) {
|
||||
var $tag, tagName;
|
||||
data = $.parseJSON(data)
|
||||
var tagData;
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var tag = data[i];
|
||||
if (tag.Tag.name == tagName) {
|
||||
tagData = data[i]
|
||||
break
|
||||
tagName = tag.Tag.name;
|
||||
|
||||
proxyMISPElements['tag'][tagName] = tag;
|
||||
|
||||
$tag = getTagReprensentation(tag);
|
||||
cache_tag[tagName] = $tag[0].outerHTML;
|
||||
}
|
||||
|
||||
// If tag name doesn't exists, construct empty placeholder
|
||||
for (i = 0; i < tagNames.length; i++) {
|
||||
tagName = tagNames[i];
|
||||
if (!(tagName in cache_tag)) {
|
||||
$tag = constructTagHtml(tagName, '#ffffff', {'border': '1px solid #000'});
|
||||
cache_tag[tagName] = $tag[0].outerHTML;
|
||||
}
|
||||
}
|
||||
if (tagData === undefined) {
|
||||
tagData = {}
|
||||
$tag = constructTagHtml(tagName, '#ffffff', {'border': '1px solid #000'})
|
||||
} else {
|
||||
$tag = getTagReprensentation(tagData)
|
||||
proxyMISPElements['tag'][tagName] = tagData
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
// Query failed, fill cache with placeholder
|
||||
var tagName, templateVariables;
|
||||
for (var i = 0; i < tagNames.length; i++) {
|
||||
tagName = tagNames[i];
|
||||
if (!(tagName in cache_tag)) {
|
||||
templateVariables = sanitizeObject({
|
||||
scope: 'Error while fetching tag',
|
||||
id: tagName
|
||||
});
|
||||
cache_tag[tagName] = dotTemplateInvalid(templateVariables);
|
||||
}
|
||||
}
|
||||
var cacheKey = eventid + '-' + tagName
|
||||
cache_tag[cacheKey] = $tag[0].outerHTML;
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
var templateVariables = sanitizeObject({
|
||||
scope: 'Error while fetching tag',
|
||||
id: tagName
|
||||
})
|
||||
var placeholder = dotTemplateInvalid(templateVariables)
|
||||
cache_tag[cacheKey] = placeholder;
|
||||
},
|
||||
complete: function() {
|
||||
complete: function () {
|
||||
if (callback !== undefined) {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
type:"post",
|
||||
type: "post",
|
||||
url: baseurl + "/tags/search/0/1/0"
|
||||
})
|
||||
}
|
||||
|
@ -947,7 +955,14 @@ function highlightPickedReplacementInReport() {
|
|||
|
||||
function convertEntityIntoSuggestion(content, entity) {
|
||||
var converted = ''
|
||||
var entityValue = entity.importRegexMatch ? entity.importRegexMatch : entity.value
|
||||
var entityValue;
|
||||
if (entity.importRegexMatch) {
|
||||
entityValue = entity.importRegexMatch;
|
||||
} else if (entity.original_value) {
|
||||
entityValue = entity.original_value;
|
||||
} else {
|
||||
entityValue = entity.value;
|
||||
}
|
||||
var splittedContent = content.split(entityValue)
|
||||
splittedContent.forEach(function(text, i) {
|
||||
converted += text
|
||||
|
@ -1007,7 +1022,7 @@ function constructSuggestionMapping(entity, indicesInCM) {
|
|||
function injectNumberOfOccurrencesInReport(entities) {
|
||||
var content = getEditorData()
|
||||
entities.forEach(function(entity, i) {
|
||||
entities[i].occurrences = getAllIndicesOf(content, entity.value, false, false).length
|
||||
entities[i].occurrences = getAllIndicesOf(content, entity.original_value, false, false).length
|
||||
})
|
||||
return entities
|
||||
}
|
||||
|
@ -1089,7 +1104,7 @@ function pickSuggestionColumn(index, tableID, force) {
|
|||
tr: $tr,
|
||||
index: index
|
||||
}
|
||||
if (tableID == 'replacementTable') {
|
||||
if (tableID === 'replacementTable') {
|
||||
var uuid = $tr.find('select.attribute-replacement').val()
|
||||
pickedSuggestion['entity'] = {
|
||||
value: $tr.data('attributeValue'),
|
||||
|
@ -1100,7 +1115,7 @@ function pickSuggestionColumn(index, tableID, force) {
|
|||
pickedSuggestion['entity']['importRegexMatch'] = proxyMISPElements['attribute'][uuid].importRegexValue
|
||||
}
|
||||
highlightPickedReplacementInReport()
|
||||
} else if (tableID == 'contextReplacementTable') {
|
||||
} else if (tableID === 'contextReplacementTable') {
|
||||
pickedSuggestion['entity'] = {
|
||||
value: $tr.data('contextValue'),
|
||||
picked_type: 'tag',
|
||||
|
@ -1211,7 +1226,11 @@ function submitExtractionSuggestion() {
|
|||
}
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
showMessage('fail', saveFailedMessage + ': ' + errorThrown);
|
||||
if (jqXHR.responseJSON) {
|
||||
showMessage('fail', jqXHR.responseJSON.errors);
|
||||
} else {
|
||||
showMessage('fail', saveFailedMessage + ': ' + errorThrown);
|
||||
}
|
||||
},
|
||||
complete:function() {
|
||||
$('#temp').remove();
|
||||
|
@ -1412,10 +1431,11 @@ function constructTag(tagName) {
|
|||
|
||||
function getTagReprensentation(tagData) {
|
||||
var $tag
|
||||
if(tagData.GalaxyCluster !== undefined) {
|
||||
if (tagData.GalaxyCluster !== undefined) {
|
||||
$tag = constructClusterTagHtml(tagData)
|
||||
} else {
|
||||
$tag = constructTagHtml(tagData.Tag.name, tagData.Tag.colour)
|
||||
var color = tagData.Tag.colour ? tagData.Tag.colour : tagData.TaxonomyPredicate.colour;
|
||||
$tag = constructTagHtml(tagData.Tag.name, color)
|
||||
}
|
||||
return $tag
|
||||
}
|
||||
|
@ -1480,8 +1500,7 @@ function constructTaxonomyInfo(tagData) {
|
|||
}
|
||||
|
||||
function constructGalaxyInfo(tagData) {
|
||||
var cacheKey = eventid + '-' + tagData.Tag.name
|
||||
var tagHTML = cache_tag[cacheKey]
|
||||
var tagHTML = cache_tag[tagData.Tag.name]
|
||||
var $tag = $(tagHTML)
|
||||
var $cluster = $('<div/>').append(
|
||||
$('<span/>').append($tag),
|
||||
|
@ -2011,16 +2030,14 @@ function isDoubleExtraction(content) {
|
|||
|
||||
function getAllIndicesOf(haystack, needle, caseSensitive, requestLineNum) {
|
||||
var indices = []
|
||||
if (needle.length == 0) {
|
||||
if (needle.length === 0) {
|
||||
return indices
|
||||
}
|
||||
var startIndex = 0, index, indices = [];
|
||||
var startIndex = 0, index = 0;
|
||||
if (!caseSensitive) {
|
||||
needle = needle.toLowerCase();
|
||||
haystack = haystack.toLowerCase();
|
||||
}
|
||||
var startIndex = 0
|
||||
var index = 0
|
||||
while (true) {
|
||||
index = haystack.indexOf(needle, startIndex)
|
||||
if (index === -1) {
|
||||
|
|
|
@ -633,14 +633,16 @@ function createRulesMenuItem(itemName, icon, ruleScope, ruleName) {
|
|||
|
||||
function createMenuItem(itemName, icon, clickHandler) {
|
||||
return $('<li/>').append(
|
||||
$('<a/>').attr('tabindex', '-1').attr('href', '#').click(clickHandler).append(
|
||||
$('<a/>').attr('tabindex', '-1').attr('href', '#').click(function (event) {
|
||||
event.preventDefault();
|
||||
clickHandler();
|
||||
}).append(
|
||||
$('<span/>').addClass('icon').append(
|
||||
icon instanceof jQuery ? icon : $('<i/>').addClass(icon)
|
||||
),
|
||||
$('<span/>').text(' ' + itemName)
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
function createSubMenu(submenuConfig) {
|
||||
|
@ -805,4 +807,4 @@ var syncSrcScroll = function () {
|
|||
break;
|
||||
}
|
||||
cm.scrollTo(0, line*cm.defaultTextHeight())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue